{"id":13798939,"url":"https://github.com/hukusuke1007/flamingo","last_synced_at":"2025-05-12T18:31:11.309Z","repository":{"id":35509323,"uuid":"217413716","full_name":"hukusuke1007/flamingo","owner":"hukusuke1007","description":"[Flutter Library] Flamingo is a firebase firestore model framework library. 🐤","archived":false,"fork":false,"pushed_at":"2023-02-18T14:15:09.000Z","size":648,"stargazers_count":120,"open_issues_count":5,"forks_count":20,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-01T09:11:09.182Z","etag":null,"topics":["cloud-firestore","firebase-storage","firestore","flamingo","flutter","flutter-package","flutter-plugin"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/flamingo","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hukusuke1007.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":["hukusuke1007"]}},"created_at":"2019-10-24T23:39:45.000Z","updated_at":"2025-02-03T10:25:47.000Z","dependencies_parsed_at":"2024-01-05T20:58:18.300Z","dependency_job_id":"2ad50584-3aed-46e1-8e50-d8bd132339c8","html_url":"https://github.com/hukusuke1007/flamingo","commit_stats":null,"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukusuke1007%2Fflamingo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukusuke1007%2Fflamingo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukusuke1007%2Fflamingo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukusuke1007%2Fflamingo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hukusuke1007","download_url":"https://codeload.github.com/hukusuke1007/flamingo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253797989,"owners_count":21965986,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud-firestore","firebase-storage","firestore","flamingo","flutter","flutter-package","flutter-plugin"],"created_at":"2024-08-04T00:00:56.914Z","updated_at":"2025-05-12T18:31:10.932Z","avatar_url":"https://github.com/hukusuke1007.png","language":"Dart","readme":"# Flamingo\n\nFlamingo is a firebase firestore model framework library.\n\n[https://pub.dev/packages/flamingo](https://pub.dev/packages/flamingo)\n\n[日本語ドキュメント](https://github.com/hukusuke1007/flamingo/blob/master/README_j.md)\n\n## Example code\nSee the example directory for a complete sample app using flamingo.\n\n[example](https://github.com/hukusuke1007/flamingo/tree/master/flamingo/example)\n\n## Installation\n\nAdd this to your package's pubspec.yaml file:\n\n```\ndependencies:\n  flamingo:\n  flamingo_annotation:\n\ndev_dependencies:\n  build_runner:\n  flamingo_generator:\n```\n\n\n## Setup\nPlease check Setup of cloud_firestore.\u003cbr\u003e\n[https://pub.dev/packages/cloud_firestore](https://pub.dev/packages/cloud_firestore#setup)\n\n## Usage\n\nAdding a initializeApp code to main.dart.\n\n### Initialize\n\n```dart\nimport 'package:flamingo/flamingo.dart';\n\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await Flamingo.initializeApp();\n  ...\n}\n```\n\n### Create Model\nCreate class that inherited **Document**. And add json mapping code into override functions.\n\nCan be used flamingo_generator. Automatically create code for mapping JSON.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'user.flamingo.dart';\n\nclass User extends Document\u003cUser\u003e {\n  User({\n    String? id,\n    DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(id: id, snapshot: snapshot, values: values);\n\n  @Field()\n  String? name;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nAnnotation list.\n\n- @Field()\n- @StorageField()\n- @ModelField()\n- @SubCollection()\n\nExecute build runner to generate data mapping JSON.\n\n```\nflutter pub run build_runner build\n```\n\nIt will be generated the following code.\n\n```dart\n// GENERATED CODE - DO NOT MODIFY BY HAND\n\npart of 'user.dart';\n\n// **************************************************************************\n// FieldValueGenerator\n// **************************************************************************\n\n/// Field value key\nenum UserKey {\n  name,\n}\n\nextension UserKeyExtension on UserKey {\n  String get value {\n    switch (this) {\n      case UserKey.name:\n        return 'name';\n      default:\n        throw Exception('Invalid data key.');\n    }\n  }\n}\n\n/// For save data\nMap\u003cString, dynamic\u003e _$toData(User doc) {\n  final data = \u003cString, dynamic\u003e{};\n  Helper.writeNotNull(data, 'name', doc.name);\n\n  return data;\n}\n\n/// For load data\nvoid _$fromData(User doc, Map\u003cString, dynamic\u003e data) {\n  doc.name = Helper.valueFromKey\u003cString\u003e(data, 'name');\n}\n\n```\n\n#### [Option] build.yaml\n\nIf you set build.yaml in the root of the project, the automatic generation will be faster.\n\nhttps://github.com/hukusuke1007/flamingo/blob/master/flamingo/example/build.yaml\n\n\n```yaml\ntargets:\n  $default:\n    builders:\n      flamingo_generator|field_value_generator:\n        generate_for:\n          include:\n            - lib/model/*.dart\n            - lib/model/**/*.dart\n```\n\n### CRUD\n\nCreate instance the following code.\n\n```dart\nfinal user = User();\nprint(user.id); // id: Automatically create document id;\n\nfinal user = User(id: 'userId');\nprint(user.id); // id: 'userId'\n```\n\nUsing DocumentAccessor or Batch or Transaction in order to CRUD.\n\n```dart\nfinal user = User()\n      ..name = 'hoge';\n\nfinal documentAccessor = DocumentAccessor();\n\n// save\nawait documentAccessor.save(user);\n\n// update\nawait documentAccessor.update(user);\n\n// delete\nawait documentAccessor.delete(user);\n\n// Batch\nfinal batch = Batch()\n  ..save(user)\n  ..update(user);\n  ..delete(user);\nawait batch.commit();\n```\n\nIf save a document, please check firestore console.\n\n\u003ca href=\"https://imgur.com/tlmwnrr\"\u003e\u003cimg src=\"https://i.imgur.com/tlmwnrr.png\" width=\"90%\" /\u003e\u003c/a\u003e\n\n\nAnd can be used field value key and save data by specific key.\n\n```dart\nfinal documentAccessor = DocumentAccessor();\nawait documentAccessor.saveRaw(\n  \u003cString, dynamic\u003e{ UserKey.name.value: 'hogehoge' },\n  user.reference,\n);\n```\n\nGet a document.\n\n```dart\nfinal user = await documentAccessor.load\u003cUser\u003e(User(id: 'userId'));\n```\n\nGet a document from cache.\n\n```dart\nfinal user = await documentAccessor.loadCache\u003cUser\u003e(User(id: 'userId'));\n```\n\nGet a document from cache and server.\n\n```dart\nString name = 'Anonymous';\n\nfinal user = await documentAccessor.load\u003cUser\u003e(\n  User(id: 'userId'),\n  fromCache: (cache) {\n    setState(() {\n      // 1. update state from cache\n      if (cache != null) {\n        name = cache.name;\n      }\n    });\n  },\n);\nsetState(() {\n  // 2. update state from serverAndCache\n  if (user != null) {\n    name = user.name;\n  }\n});\n```\n\n### Get Collection Documents \n\n#### CollectionPaging\nCan be used get and paging features of documents by CollectionPaging.\n\nQuery of Collection.\n\n```dart\nfinal collectionPaging = CollectionPaging\u003cUser\u003e(\n  query: User().collectionRef.orderBy('createdAt', descending: true),\n  limit: 20,\n  decode: (snap) =\u003e User(snapshot: snap),\n);\n\n// Load \nList\u003cUser\u003e items = await collectionPaging.load();\n\n// LoadMore\nfinal _items = await collectionPaging.loadMore();\nitems.addAll(_items);\n```\n\nGet a documents from cache and server.\n\n```dart\nList\u003cUser\u003e items = [];\n\nfinal _items = await collectionPaging.load(\n  fromCache: (caches) {\n    setState(() {\n      // 1. update state from cache\n      items = caches;\n    });\n  },\n);\n\n// 2. update state from serverAndCache\nsetState(() {\n  items = _items;\n});\n```\n\n\nQuery of CollectionGroup.\n\n```dart\nfinal collectionPaging = CollectionPaging\u003cUser\u003e(\n  query: firestoreInstance\n    .collectionGroup('user')\n    .orderBy('createdAt', descending: true),\n  limit: 20,\n  decode: (snap) =\u003e User(snapshot: snap),\n);\n```\n\n[sample code](https://github.com/hukusuke1007/flamingo/blob/master/flamingo/example/lib/collection_paging_page.dart)\n\n#### CollectionPagingListener\nCan be used listener and paging features of documents by CollectionPagingListener.\u003cbr\u003e\n\n```dart\nfinal collectionPagingListener = CollectionPagingListener\u003cUser\u003e(\n  query: User().collectionRef.orderBy('updatedAt', descending: true),\n  initialLimit: 20,\n  pagingLimit: 20,\n  decode: (snap) =\u003e User(snapshot: snap),\n);\n\n// Fetch to set listener.\ncollectionPagingListener.fetch();\n\nfinal items = \u003cUser\u003e[];\n\n// Get documents via listener. data is ValueStream.\ncollectionPagingListener.data.listen((event) {\n    setState(() {\n      items = event;\n    });\n  });\n\n// Get document changes status and cache status.\ncollectionPagingListener.docChanges.listen((event) {\n    for (var item in event) {\n      final change = item.docChange;\n      print('id: ${item.doc.id}, changeType: ${change.type}, oldIndex: ${change.oldIndex}, newIndex: ${change.newIndex} cache: ${change.doc.metadata.isFromCache}');\n    }\n  });\n\n// LoadMore. To load next page data.\ncollectionPagingListener.loadMore();\n\n\n// Dispose.\nawait collectionPagingListener.dispose();\n```\n\n[sample code](https://github.com/hukusuke1007/flamingo/blob/master/flamingo/example/lib/collection_paging_listener_page.dart)\n\n#### firestoreInstance\nCan be get documents in collection.\n\n```dart\nfinal path = Document.path\u003cUser\u003e();\nfinal snapshot = await firestoreInstance.collection(path).get();\n\n// from snapshot\nfinal listA = snapshot.docs.map((item) =\u003e User(snapshot: item)).toList()\n  ..forEach((user) {\n    print(user.id); // user model.\n  });\n\n// from values.\nfinal listB = snapshot.docs.map((item) =\u003e User(id: item.documentID, values: item.data)).toList()\n  ..forEach((user) {\n    print(user.id); // user model.\n  });\n```\n\n### Snapshot Listener \n\nListen snapshot of document.\n\n```dart\n// Listen\nfinal user = User(id: '0')\n  ..name = 'hoge';\n\nfinal dispose = user.reference.snapshots().listen((snap) {\n  final user = User(snapshot: snap);\n  print('${user.id}, ${user.name}');\n});\n\n// Save, update, delete\nDocumentAccessor documentAccessor = DocumentAccessor();\nawait documentAccessor.save(user);\n\nuser.name = 'fuga';\nawait documentAccessor.update(user);\n\nawait documentAccessor.delete(user);\n\nawait dispose.cancel();\n```\n\nListen snapshot of collection documents. And can be used also CollectionPagingListener.\n\n\n```dart\n// Listen\nfinal path = Document.path\u003cUser\u003e();\nfinal query = firestoreInstance.collection(path).limit(20);\nfinal dispose = query.snapshots().listen((querySnapshot) {\n  for (var change in querySnapshot.documentChanges) {\n    if (change.type == DocumentChangeType.added ) {\n      print('added ${change.document.documentID}');\n    }\n    if (change.type == DocumentChangeType.modified) {\n      print('modified ${change.document.documentID}');\n    }\n    if (change.type == DocumentChangeType.removed) {\n      print('removed ${change.document.documentID}');\n    }\n  }\n  final _ = querySnapshot.docs.map((item) =\u003e User(snapshot: item)).toList()\n    ..forEach((item) =\u003e print('${item.id}, ${item.name}'));\n});\n\n// Save, update, delete\nfinal user = User(id: '0')\n  ..name = 'hoge';\n\nDocumentAccessor documentAccessor = DocumentAccessor();\nawait documentAccessor.save(user);\n\nuser.name = 'fuga';\nawait documentAccessor.update(user);\n\nawait documentAccessor.delete(user);\n\nawait dispose.cancel();\n```\n\n### Model of map object\n\nExample, Owner's document object is the following json.\n\n```json\n{\n  \"name\": \"owner\",\n  \"address\": {\n    \"postCode\": \"0000\",\n    \"country\": \"japan\"\n  },\n  \"medals\": [\n    {\"name\": \"gold\"},\n    {\"name\": \"silver\"},\n    {\"name\": \"bronze\"}\n  ]\n}\n```\n\nOwner that inherited **Document** has model of map object.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\nimport 'address.dart';\nimport 'medal.dart';\n\npart 'owner.flamingo.dart';\n\nclass Owner extends Document\u003cOwner\u003e {\n  Owner({\n    String? id,\n    DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(id: id, snapshot: snapshot, values: values);\n\n  @Field()\n  String? name;\n\n  @ModelField()\n  Address? address;\n\n  @ModelField()\n  List\u003cMedal\u003e? medals;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nCreate class that inherited **Model**.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'address.flamingo.dart';\n\nclass Address extends Model {\n  Address({\n    this.postCode,\n    this.country,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(values: values);\n\n  @Field()\n  String? postCode;\n\n  @Field()\n  String? country;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'medal.flamingo.dart';\n\nclass Medal extends Model {\n  Medal({\n    this.name,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(values: values);\n\n  @Field()\n  String? name;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nExample of usage.\n\n```dart\n// save\nfinal owner = Owner()\n  ..name = 'owner'\n  ..address = Address(\n    postCode: '0000',\n    country: 'japan',\n  )\n  ..medals = [\n    Medal(name: 'gold',),\n    Medal(name: 'silver',),\n    Medal(name: 'bronze',),\n  ];\n\nawait documentAccessor.save(owner);\n\n// load\nfinal _owner = await documentAccessor.load\u003cOwner\u003e(Owner(id: owner.id));\nprint('id: ${_owner.id}, name: ${_owner.name}');\nprint('address: ${_owner.id} ${_owner.address.postCode} ${_owner.address.country}');\nprint('medals: ${_owner.medals.map((d) =\u003e d.name)}');\n```\n\n\u003ca href=\"https://imgur.com/O9f1LOb\"\u003e\u003cimg src=\"https://i.imgur.com/O9f1LOb.png\" width=\"90%\" /\u003e\u003c/a\u003e\n\n### Sub Collection\n\nFor example, ranking document has count collection.\n\n#### Ranking model\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\nimport 'count.dart';\n\npart 'ranking.flamingo.dart';\n\nclass Ranking extends Document\u003cRanking\u003e {\n  Ranking(\n      {String? id,\n      DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n      Map\u003cString, dynamic\u003e? values,\n      CollectionReference\u003cMap\u003cString, dynamic\u003e\u003e? collectionRef})\n      : super(\n            id: id,\n            snapshot: snapshot,\n            values: values,\n            collectionRef: collectionRef) {\n    count = Collection(this, RankingKey.count.value);\n  }\n\n  @Field()\n  String? title;\n\n  @SubCollection()\n  late Collection\u003cCount\u003e count;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\n#### Count model\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'count.flamingo.dart';\n\nclass Count extends Document\u003cCount\u003e {\n  Count({\n    String? id,\n    DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n    Map\u003cString, dynamic\u003e? values,\n    CollectionReference\u003cMap\u003cString, dynamic\u003e\u003e? collectionRef,\n  }) : super(\n            id: id,\n            snapshot: snapshot,\n            values: values,\n            collectionRef: collectionRef);\n\n  @Field()\n  String? userId;\n\n  @Field()\n  int count = 0;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\n#### Save and Get Sub Collection.\n\n```dart\nfinal ranking = Ranking(id: '20201007')\n  ..title = 'userRanking';\n\n// Save sub collection of ranking document\nfinal countA = Count(collectionRef: ranking.count.ref)\n  ..userId = '0'\n  ..count = 10;\nfinal countB = Count(collectionRef: ranking.count.ref)\n  ..userId = '1'\n  ..count = 100;\nfinal batch = Batch()\n  ..save(ranking)\n  ..save(countA)\n  ..save(countB);\nawait batch.commit();\n\n// Get sub collection\nfinal path = ranking.count.ref.path;\nfinal snapshot = await firestoreInstance.collection(path).get();\nfinal list = snapshot.docs.map((item) =\u003e Count(snapshot: item)).toList()\n  ..forEach((count) {\n    print(count);\n  });\n```\n\n\n### File\nCan operation into Firebase Storage and upload and delete storage file. Using StorageFile and Storage class.\n\nFor example, create post model that have StorageFile.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'post.flamingo.dart';\n\nclass Post extends Document\u003cPost\u003e {\n  Post({String? id}) : super(id: id);\n\n  @StorageField()\n  StorageFile? file;\n\n  @StorageField()\n  List\u003cStorageFile\u003e? files;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nUpload file to Firebase Storage.\n\n```dart\nfinal post = Post();\nfinal storage = Storage();\nfinal file = ... // load image.\n\n// Fetch uploader stream\nstorage.fetch();\n\n// Checking status\nstorage.uploader.listen((data){\n  print('total: ${data.totalBytes} transferred: ${data.bytesTransferred}');\n});\n\n// Upload file into firebase storage and save file metadata into firestore\nfinal path = '${post.documentPath}/${PostKey.file.value}';\npost.file = await storage.save(path, file, mimeType: mimeTypePng, metadata: {'newPost': 'true'}); // 'mimeType' is defined in master/master.dart\nawait documentAccessor.save(post);\n\n// Dispose uploader stream\nstorage.dispose();\n```\n\nDelete storage file.\n\n```dart\n// delete file in firebase storage and delete file metadata in firestore\nawait storage.delete(post.file);\nawait documentAccessor.update(post);\n```\n\nAlternatively, flamingo provide function to operate Cloud Storage and Firestore.\n\n```dart\n// Save storage and document of storage data.\nfinal storageFile = await storage.saveWithDoc(\n    post.reference,\n    PostKey.file.value,\n    file,\n    mimeType: mimeTypePng,\n    metadata: {\n      'newPost': 'true'\n    },\n    additionalData: \u003cString, dynamic\u003e{\n      'key0': 'key',\n      'key1': 10,\n      'key2': 0.123,\n      'key3': true,\n    },\n);\n\n// Delete storage and document of storage data.\nawait storage.deleteWithDoc(post.reference, PostKey.file.value, post.file, isNotNull: true);\n```\n\n### Increment\n\nExample, CreditCard's document has point and score field. Their fields is Increment type.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'credit_card.flamingo.dart';\n\nclass CreditCard extends Document\u003cCreditCard\u003e {\n  CreditCard({\n    String? id,\n    DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(id: id, snapshot: snapshot, values: values);\n\n  @Field()\n  Increment\u003cint\u003e point = Increment\u003cint\u003e();\n\n  @Field()\n  Increment\u003cdouble\u003e score = Increment\u003cdouble\u003e();\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n\n  /// Call after create, update, delete.\n  @override\n  void onCompleted(ExecuteType executeType) {\n    point = point.onRefresh();\n    score = score.onRefresh();\n  }\n}\n```\n\nIncrement and decrement of data.\n\n```dart\n// Increment\nfinal card = CreditCard()\n  ..point.incrementValue = 1\n  ..score.incrementValue = 1.25;\nawait documentAccessor.save(card);\nprint('point ${card.point.value}, score: ${card.score.value}'); // point 1, score 1.25\n\nfinal _card = await documentAccessor.load\u003cCreditCard\u003e(card);\nprint('point ${_card.point.value}, score: ${_card.score.value}'); // point 1, score 1.25\n\n\n// Decrement\ncard\n  ..point.incrementValue = -1\n  ..score.incrementValue = -1.00;\nawait documentAccessor.update(card);\nprint('point ${card.point.value}, score: ${card.score.value}'); // point 0, score 0.25\n\nfinal _card = await documentAccessor.load\u003cCreditCard\u003e(card);\nprint('point ${_card.point.value}, score: ${_card.score.value}'); // point 0, score 0.25\n\n\n// Clear\ncard\n  ..point.isClearValue = true\n  ..score.isClearValue = true;\nawait documentAccessor.update(card);\nprint('point ${card.point.value}, score: ${card.score.value}'); // point 0, score 0.0\n\nfinal _card = await documentAccessor.load\u003cCreditCard\u003e(card);\nprint('point ${_card.point.value}, score: ${_card.score.value}'); // point 0, score 0.0\n```\n\nOr can be use with increment method of DocumentAccessor.\n\n```dart\nfinal card = CreditCard();\nfinal batch = Batch()\n  ..save(card);\nawait batch.commit();\n\n// Increment\ncard\n  ..point = await documentAccessor.increment\u003cint\u003e(card.point, card.reference, fieldName: CreditCardKey.point.value, value: 10)\n  ..score = await documentAccessor.increment\u003cdouble\u003e(card.score, card.reference, fieldName: CreditCardKey.score.value, value: 3.5);\n\n// Decrement\ncard\n  ..point = await documentAccessor.increment\u003cint\u003e(card.point, card.reference, fieldName: CreditCardKey.point.value, value: -5)\n  ..score = await documentAccessor.increment\u003cdouble\u003e(card.score, card.reference, fieldName: CreditCardKey.score.value, value: -2.5);\n\n// Clear\ncard\n  ..point = await documentAccessor.increment\u003cint\u003e(card.point, card.reference, fieldName: CreditCardKey.point.value, isClear: true)\n  ..score = await documentAccessor.increment\u003cdouble\u003e(card.score, card.reference, fieldName: CreditCardKey.score.value, isClear: true);\n```\n\nAttension: \n\nClear process only set 0 to document and update. It not try transaction process. Do not use except to first set doument\n\n### Distributed counter\n\nUsing DistributedCounter and Counter.\n\nFor example, create score model that have Counter.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'score.flamingo.dart';\n\nclass Score extends Document\u003cScore\u003e {\n  Score({\n    String? id,\n  }) : super(id: id) {\n    counter = Counter(this, ScoreKey.counter.value, numShards);\n  }\n\n  @Field()\n  String? userId;\n\n  /// DistributedCounter\n  @SubCollection()\n  late Counter counter;\n\n  int numShards = 10;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nCreate and increment and load.\n\n```dart\n/// Create\nfinal score = Score()\n  ..userId = '0001';\nawait documentAccessor.save(score);\n\nfinal distributedCounter = DistributedCounter();\nawait distributedCounter.create(score.counter);\n\n/// Increment\nfor (var i = 0; i \u003c 10; i++) {\n  await distributedCounter.increment(score.counter, count: 1);\n}\n\n/// Load\nfinal count = await distributedCounter.load(score.counter);\nprint('count $count ${score.counter.count}');\n```\n\n### Transaction\n\nThis api is simply wrap transaction function of Firestore.\n\n```dart\nRunTransaction.scope((transaction) async {\n  final hoge = User()\n    ..name = 'hoge';\n\n  // save\n  await transaction.set(hoge.reference, hoge.toData());\n\n  // update\n  final fuge = User(id: '0')\n    ..name = 'fuge';\n  await transaction.update(fuge.reference, fuge.toData());\n\n  // delete\n  await transaction.delete(User(id: '1').reference);\n});\n```\n\n\n### Objects for model\n\n#### Map objects\n\nCreate the following model class.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'map_sample.flamingo.dart';\n\nclass MapSample extends Document\u003cMapSample\u003e {\n  MapSample({\n    String? id,\n    DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(id: id, snapshot: snapshot, values: values);\n\n  @Field()\n  Map\u003cString, String\u003e? strMap;\n\n  @Field()\n  Map\u003cString, int\u003e? intMap;\n\n  @Field()\n  Map\u003cString, double\u003e? doubleMap;\n\n  @Field()\n  Map\u003cString, bool\u003e? boolMap;\n\n  @Field()\n  List\u003cMap\u003cString, String\u003e\u003e? listStrMap;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nAnd save and load documents. \n\n```dart\nfinal sample1 = MapSample()\n  ..strMap = {'userId1': 'tanaka', 'userId2': 'hanako', 'userId3': 'shohei',}\n  ..intMap = {'userId1': 0, 'userId2': 1, 'userId3': 2,}\n  ..doubleMap = {'userId1': 1.02, 'userId2': 0.14, 'userId3': 0.89,}\n  ..boolMap = {'userId1': true, 'userId2': true, 'userId3': true,}\n  ..listStrMap = [\n    {'userId1': 'tanaka', 'userId2': 'hanako',},\n    {'adminId1': 'shohei', 'adminId2': 'tanigawa',},\n    {'managerId1': 'ueno', 'managerId2': 'yoshikawa',},\n  ];\nawait documentAccessor.save(sample1);\n\nfinal _sample1 = await documentAccessor.load\u003cMapSample\u003e(MapSample(id: sample1.id));\n```\n\n#### List\n\nCreate the following model class.\n\n```dart\nimport 'package:flamingo/flamingo.dart';\nimport 'package:flamingo_annotation/flamingo_annotation.dart';\n\npart 'list_sample.flamingo.dart';\n\nclass ListSample extends Document\u003cListSample\u003e {\n  ListSample({\n    String? id,\n    DocumentSnapshot\u003cMap\u003cString, dynamic\u003e\u003e? snapshot,\n    Map\u003cString, dynamic\u003e? values,\n  }) : super(id: id, snapshot: snapshot, values: values);\n\n  @Field()\n  List\u003cString\u003e? strList;\n\n  @Field()\n  List\u003cint\u003e? intList;\n\n  @Field()\n  List\u003cdouble\u003e? doubleList;\n\n  @Field()\n  List\u003cbool\u003e? boolList;\n\n  @StorageField(isWriteNotNull: false)\n  List\u003cStorageFile\u003e? filesA;\n\n  @StorageField()\n  List\u003cStorageFile\u003e? filesB;\n\n  @override\n  Map\u003cString, dynamic\u003e toData() =\u003e _$toData(this);\n\n  @override\n  void fromData(Map\u003cString, dynamic\u003e data) =\u003e _$fromData(this, data);\n}\n```\n\nAnd save and load documents. \n\n```dart\n/// Save\nfinal sample1 = ListSample()\n  ..strList = ['userId1', 'userId2', 'userId3',]\n  ..intList = [0, 1, 2,]\n  ..doubleList = [0.0, 0.1, 0.2,]\n  ..boolList = [true, false, true,]\n  ..filesA = [\n    StorageFile(\n        name: 'name1', url: 'https://sample1.jpg', mimeType: mimeTypePng),\n    StorageFile(\n        name: 'name2', url: 'https://sample2.jpg', mimeType: mimeTypePng),\n    StorageFile(\n        name: 'name3', url: 'https://sample3.jpg', mimeType: mimeTypePng),\n  ]\n  ..filesB = [\n    StorageFile(\n        name: 'name1', url: 'https://sample1.jpg', mimeType: mimeTypePng),\n    StorageFile(\n        name: 'name2', url: 'https://sample2.jpg', mimeType: mimeTypePng),\n    StorageFile(\n        name: 'name3', url: 'https://sample3.jpg', mimeType: mimeTypePng),\n  ];\nawait documentAccessor.save(sample1);\n\n/// Load\nfinal _sample1 = await documentAccessor.load\u003cListSample\u003e(ListSample(id: sample1.id));\n```\n\n## [WIP] Unit Test\n\n\u003cb\u003e※Under construction\u003c/b\u003e\n\nInstall packages for unit test.\n\n- [test](https://pub.dev/packages/test)\n- [cloud_firestore_mocks](https://pub.dev/packages/cloud_firestore_mocks)\n- [firebase_storage_mocks](https://pub.dev/packages/firebase_storage_mocks)\n\n```\ndev_dependencies:\n  ...\n\n  test: ^1.14.4\n  cloud_firestore_mocks:\n  firebase_storage_mocks:\n```\n\nSet Firestore and Cloud Storage mock instance.\n\n```dart\nimport 'package:cloud_firestore_mocks/cloud_firestore_mocks.dart';\nimport 'package:firebase_storage_mocks/firebase_storage_mocks.dart';\nimport 'package:flamingo/flamingo.dart';\nimport 'package:test/test.dart';\n\nvoid main() async {\n  final firestore = MockFirestoreInstance();\n  final storage = MockFirebaseStorage();\n  await Flamingo.initializeApp(\n      firestore: firestore,\n      storage: storage,\n      root: firestore.document('test/v1'));\n  ...\n}\n```\n\n[sample code](https://github.com/hukusuke1007/flamingo/blob/master/flamingo/example/test/example_test.dart)\n\n\n## Reference\n- [Firebase for Flutter](https://firebase.google.com/docs/flutter/setup)\n- [Ballcap for iOS](https://github.com/1amageek/Ballcap-iOS)\n- [Ballcap for TypeScript](https://github.com/1amageek/ballcap.ts)\n","funding_links":["https://github.com/sponsors/hukusuke1007"],"categories":["모바일"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhukusuke1007%2Fflamingo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhukusuke1007%2Fflamingo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhukusuke1007%2Fflamingo/lists"}