🧩

json→firestore→Serverpod

2023/07/10に公開

とあるアプリからの心臓移植

あるアプリの機能がとても気に入って、自分のアプリに取り込みたいと思ったのだけれど、これがなかなか苦難の道だった。
いや、まだ進行形、苦難の道程だ。
だがともかく、一つ山を越したので、メモっておこうと思う。

もともとはアプリ内の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;

最適解ではないだろうけど

とりあえずこれで前進する。

Flutter大学

Discussion