🧩
json→firestore→Serverpod
とあるアプリからの心臓移植
あるアプリの機能がとても気に入って、自分のアプリに取り込みたいと思ったのだけれど、これがなかなか苦難の道だった。
いや、まだ進行形、苦難の道程だ。
だがともかく、一つ山を越したので、メモっておこうと思う。
もともとはアプリ内のjsonのdataを
Mapに展開して、読み込んでいた。
こんな感じ
Future<List<DistanceEntry>> loadFromBundle(String filename) async {
String data = await rootBundle.loadString(filename);
List jsonEntries = json.decode(data) as List;
List<DistanceEntry> allEntries = [];
_backgroundColors = [];
_tickColors = [];
_headerColors = [];
/// The JSON decode doesn't provide strong typing, so we'll iterate
/// on the dynamic entries in the [jsonEntries] list.
for (dynamic entry in jsonEntries) {
Map map = entry as Map;
/// Sanity check.
if (map != null) {
/// Create the current entry and fill in the current date if it's
/// an `material`, or look for the `start` property if it's a `Position` instead.
/// Some entries will have a `start` element, but not an `end` specified.
DistanceEntry distanceEntry = DistanceEntry();
if (map.containsKey("point")) {
distanceEntry.type = DistanceEntryType.material;
dynamic point = map["point"];
distanceEntry.start = point is int ? point.toDouble() : point;
} else if (map.containsKey("start")) {
distanceEntry.type = DistanceEntryType.position;
dynamic start = map["start"];
distanceEntry.start = start is int ? start.toDouble() : start;
} else {
continue;
}
そこから、firestoreのdataを
検索して、読み込む形に変換した。
Future<List<TimelineEntry>> loadFromFirestore(
String collectionPath, {String? country}) async {
List<TimelineEntry> allEntries = [];
_tickColors = [];
QuerySnapshot querySnapshot = await FirebaseFirestore.instance.collection(collectionPath)
.where("country", isEqualTo: country)
.get();
List<DocumentSnapshot> docSnapshots = querySnapshot.docs;
for (DocumentSnapshot docSnapshot in docSnapshots) {
Map<String, dynamic> map = docSnapshot.data() as Map<String, dynamic>;
/// Sanity check.
if (map != null) {
/// Create the current entry and fill in the current date if it's
/// an `material`, or look for the `start` property if it's a `Position` instead.
/// Some entries will have a `start` element, but not an `end` specified.
TimelineEntry timelineEntry = TimelineEntry();
if (map.containsKey("year")) {
timelineEntry.type = TimelineEntryType.incident;
dynamic year = map["year"];
timelineEntry.start = year is int ? year.toDouble() : year;
} else {
continue;
}
それをさらに、Serverpodに
繋ぎ直した。
この段階で、Map展開するのを止めて、ListからListに、なるべくシンプルに繋いだ。
List<Principal> _principal = [];
Future<List<TimelineEntry>> fetchPrincipal(
{String? country}) async {
_principal = await client.principal.getPrincipal();
List<TimelineEntry> allEntries = [];
_tickColors = [];
for (var principal in _principal){
/// Sanity check.
if (principal != null) {
/// Create the current entry and fill in the current date if it's
/// an `material`, or look for the `start` property if it's a `Position` instead.
/// Some entries will have a `start` element, but not an `end` specified.
TimelineEntry timelineEntry = TimelineEntry();
timelineEntry.type = TimelineEntryType.incident;
dynamic year = principal.annee;
timelineEntry.start = year is int ? year.toDouble() : year;
最適解ではないだろうけど
とりあえずこれで前進する。
Discussion