{"id":18465148,"url":"https://github.com/natario1/firestore","last_synced_at":"2025-08-01T08:14:40.947Z","repository":{"id":99104473,"uuid":"142636423","full_name":"natario1/Firestore","owner":"natario1","description":"The lightweight, efficient Android wrapper for Google's Firestore model data.","archived":false,"fork":false,"pushed_at":"2020-09-25T12:02:02.000Z","size":219,"stargazers_count":33,"open_issues_count":4,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-23T09:24:38.580Z","etag":null,"topics":["android","databinding","firebase","firebase-firestore","firebase-object","firestore","model","parcelable"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/natario1.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["natario1"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2018-07-28T01:16:30.000Z","updated_at":"2024-03-18T08:01:13.000Z","dependencies_parsed_at":"2023-06-03T20:30:30.217Z","dependency_job_id":null,"html_url":"https://github.com/natario1/Firestore","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FFirestore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FFirestore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FFirestore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/natario1%2FFirestore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/natario1","download_url":"https://codeload.github.com/natario1/Firestore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247804544,"owners_count":20999010,"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":["android","databinding","firebase","firebase-firestore","firebase-object","firestore","model","parcelable"],"created_at":"2024-11-06T09:12:07.393Z","updated_at":"2025-04-08T08:31:46.313Z","avatar_url":"https://github.com/natario1.png","language":"Kotlin","funding_links":["https://github.com/sponsors/natario1","https://github.com/sponsors/natario1)!"],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://github.com/natario1/Firestore/workflows/Build/badge.svg?event=push)](https://github.com/natario1/Firestore/actions)\n[![Release](https://img.shields.io/github/release/natario1/Firestore.svg)](https://github.com/natario1/Firestore/releases)\n[![Issues](https://img.shields.io/github/issues-raw/natario1/Firestore.svg)](https://github.com/natario1/Firestore/issues)\n\n*Need support, consulting, or have any other business-related question? Feel free to \u003ca href=\"mailto:mat.iavarone@gmail.com\"\u003eget in touch\u003c/a\u003e.*\n\n*Like the project, make profit from it, or simply want to thank back? Please consider [sponsoring me](https://github.com/sponsors/natario1)!*\n\n# Firestore\n\nThe lightweight, efficient wrapper for Firestore model data, written in Kotlin, with data-binding and Parcelable support.\n\n```groovy\nimplementation 'com.otaliastudios:firestore:0.7.0'\nkapt 'com.otaliastudios:firestore-compiler:0.7.0'\n```\n\n- Efficient and lightweight\n- Compiler to avoid reflection\n- Built-in Parcelable implementation\n- Built-in Data binding support\n- Built-in equals \u0026 hashcode\n- Written in Kotlin using map / list delegation\n- Full replacement for `data class` and `Parcelize`\n\n# We know about your schema\n\nThe key classes here are `FirestoreDocument` (for documents), `FirestoreMap` and `FirestoreList` (for inner maps and lists).\nThey use Kotlin delegation so you can declare expected fields using the `by this` syntax:\n\n```kotlin\n@FirestoreClass\nclass User : FirestoreDocument() {\n    var type: Int by this\n    var imageUrl: String? by this\n    var messages: Messages by this\n    \n    @FirestoreClass\n    class Messages : FirestoreList\u003cMessage\u003e()\n    \n    @FirestoreClass\n    class Message : FirestoreMap\u003cAny?\u003e() {\n        var from: String by this\n        var to: String by this\n        var text: String? by this\n    }\n}\n```\n\nThe compiler will inspect your hierarchy and at runtime, it will know how to instantiate fields\nand inner maps or lists, as long as you provide a no arguments constructor for them. This is valid:\n\n```kotlin\nval user = User()\nval message = Message()\nuser.messages.add(message) // We didn't have to instantiate Messages()\n```\n\nFiels are instantiated automatically and **lazily**, when requested. \nThe map and list implementations parsed by the compiler are also used when retrieving the document\nfrom the network, which makes it much more efficient than using reflection to find setters.\n\n```kotlin\nval user: User = documentSnapshot.toFirestoreDocument()\nval lastMessage = user.messages.last()\n```\n\n## Specify default values\n\nThe fields that are marked as not nullable, will be instantiated using their no arguments constructor.\nThis means that, for example, `Int` defaults to `0`. To specify different defaults, simply use an init block:\n\n```kotlin\n@FirestoreClass\nclass User : FirestoreDocument() {\n    var type: Int by this\n    \n    init {\n        type = UserType.ADMIN\n    }\n}\n```\n\n# We cache your documents\n\nSimilar to what Firestore-UI does, we keep a static `LruCache` of your documents based on their path.\nThis means that if you run a query for 50 documents and 20 were already cached, we will reuse their \ninstance instead of creating new ones.\n\n```kotlin\nval user1: User = documentSnapshot.toFirestoreDocument()\nval user2: User = documentSnapshot.toFirestoreDocument()\nassert(user1 === user2)\n```\n\nOf course, the fields will be updated to reflect the new network data.\n\n# We keep some basic fields\n\nEach object will keep (and save to network) some extra fields that are commonly used, plus have\nuseful functions to inspect their state with respect to the database.\n\n```kotlin\nval isNew: Boolean = user.isNew() // Whether this object was saved to / comes from network\nval createdAt: Timestamp? = user.createdAt // When this object was saved to network for the first time. Null if new\nval updatedAt: Timestamp? = user.updatedAt // When this object was saved to network for the last time. Null if new\nval reference: DocumentReference = user.getReference() // Throws if new\n```\n\nWe also have built-in reliable implementations for `equals()` and `hashcode()`.\n\n# We know your dirty values\n\nWhen you update some fields, either some declared field (`user.imageUrl = \"url\"`) or using the backing\nmap implementation (`user[\"imageUrl\"] = \"url\"`), the document will remember that this specific field was changed\nwith respect to the original values.\n\nNext call to `user.save()` will internally use something like `reference.update(mapOf(\"imageUrl\" to \"url\"))`,\ninstead of saving the whole object to the database. This is managed automatically and you don't have to worry about it.\n\nThis even works with inner fields and maps!\n\n```kotlin\nuser.family.father.name = \"John\"\nuser.save()\n\n// This will not send the whole User, not the whole Family and not even the whole Father.\n// It will call reference.update(\"user.family.father.name\", \"John\") as it should.\n```\n\n# Built-in Data Binding support\n\nThe `FirestoreDocument` and `FirestoreMap` classes extend the `BaseObservable` class from the official data binding lib.\nThanks to the compiler, all declared fields will automatically call `notifyPropertyChanged()` for you,\nwhich hugely reduce the work needed to implement databinding and two-way databinding.\n\n\nIn fact, all you have to do is add `@get:Bindable` to your fields:\n\n```kotlin\n@FirestoreClass\nclass Message : FirestoreDocument() {\n    @get:Bindable var text: String by this\n    @get:Bindable var comment: String by this\n}\n```\n\nYou can now use `message.text` and `message.comment` in XML layouts and they will be updated\nwhen the data model changes.\n\n# We know how to `Parcel`\n\nDocuments, maps and lists implement the `Parcelable` interface.\n\n## Local metadata\n\nIf your object holds metadata that should not by saved to network (for instance, fields that are not marked with `by this`),\nthey can be saved and restored to the `Parcel` overriding the class callbacks:\n\n```kotlin\n@FirestoreClass\nclass Message : FirestoreDocument() {\n    var text: String by this\n    var comment: String by this\n    \n    var hasBeenRead = false\n    \n    override fun onWriteToBundle(bundle: Bundle) {\n        bundle.putBoolean(\"hasBeenRead\", hasBeenRead)\n    }\n    \n    override fun onReadFromBundle(bundle: Bundle) {\n        hasBeenRead = bundle.getBoolean(\"hasBeenRead\")\n    }\n}\n```\n\n## Special types\n\nWe offer built in parcelers for `DocumentReference`, `Timestamp` and `FieldValue` types.\nIf your types do not implement parcelable directly, either have them implement it or register\na parceler using `FirestoreDocument.registerParceler()`:\n\n```kotlin\nclass App : Application() {\n\n    override fun onCreate() {\n        registerParceler(GeoPointParceler)\n        registerParceler(WhateverParceler)\n    }\n    \n    object GeoPointParceler : FirestoreDocument.Parceler\u003cGeoPoint\u003e() {\n        // ...\n    }\n    \n    object WhateverParceler : FirestoreDocument.Parceler\u003cWhatever\u003e() {\n        // ...\n    }\n}\n```\n\n# Finally, we know how to update \n\nThe document class exposes `delete()`, `save()` and `trySave()` methods. They all return a `Task\u003c?\u003e` object\nfrom the Google gms library, which you should be used to. This lets you add success and failure callbacks,\nas well as chain operations with complex dependencies.\n\n## Delete\n\n```kotlin\nuser.delete().addOnSuccessListener { \n    // User was deleted!               \n}.addOnFailureListener {\n    // Something went wrong\n}\n```\n\nThe delete operation will throw an exception is the object `isNew()`.\n\n## Save\n\nThe `save()` method will check if the object is new or comes from server.\n\n- For a new object, internally this will call `reference.set()` to create your object\n- For a backend object, this will call `reference.update()`. As stated above in the dirty fields chapter,\n  we only update exactly what was changed programmatically.\n  \n```kotlin\nuser.family.father = John()\nuser.type = User.TYPE_CHILD\nuser.save().addOnSuccessListener { \n    // User was saved!               \n}.addOnFailureListener {\n    // Something went wrong\n}\n```\n\n## Try Save\n\nThe `trySave()` method follows an opposite procedure.\nIt will first try to update the fields you specify to network, and if the call succeeds, it will update\nthe data document too.\n  \n```kotlin\nuser.family.father = null\nuser.trySave(\n    \"family.father\" to John(),\n    \"type\" to User.TYPE_CHILD\n).addOnSuccessListener {\n    // User was saved!\n    assert(user.family.father is John)\n}.addOnFailureListener {\n    // Something went wrong.\n    assert(user.family.father == null)\n}\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnatario1%2Ffirestore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnatario1%2Ffirestore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnatario1%2Ffirestore/lists"}