Skip to content

Dynamic API

Dependencies

Add repository URL https://s01.oss.sonatype.org/content/repositories/snapshots/ for SNAPSHOT versions.

plugins {
    kotlin("plugin.serialization")
}

dependencies {
    implementation("io.firestore4k:dynamic-api:$latestVersion")
}

Model

Example

In the sample code below, we will define model for:

/users/{useri-d}/messages/{message-id}

So, we have 2 collections - users and messages, each of the collection have documents under them.

users will be a root collection.
messages will be a sub collection under users.

Entity classes

Define Kotlin data classs for the firestore documents.

Important

Annotate them with @kotlinx.serialization.Serializable

@kotlinx.serialization.Serializable
data class User(
    val name: String,
    val email: String,
)

@kotlinx.serialization.Serializable
data class Message(
    val from: String,
    val to: String,
    val subject: String,
    val body: String,
)

Collections

Define collections - users and messages.

val users = collection("users")
val messages = collection("messages")

Warning

Unlike typed collections, we cannot define hierarchy of collections in dynamic-api.
So an incorrect collection hierarchy will NOT be detected at compile-time.

messages / "message1" / users / "user1"

firestore path expression

DSL to express Firestore collection & document path.

val users = collection("users")
val messages = collection("messages")

// /users
users

// /users/user1
users / "user1"

// /users/user1/message
users / "user1" / messages

// /users/user1/message/message1
users / "user1" / messages / "message1"

Info

dynamic-api only enforces path to be collection / id / collection / id / ....
There are no checks for collection hierarchy.

Warning

Unlike typed Identity value classes (optional), document IDs are String in dynamic-api.
So these incorrect IDs will NOT be detected at compile-time.

users / "message1" / messages / "user1"

CRUD operations

Use collection & document path for operations.

add

// add (ID auto generated by Firestore)
// add(<collection path>, <document object>): <String Id>
val userId: String = add(users, User())

put

// put (create or update)
// put(<document path>, <document object>)
put(users / "user1", User())

get

// get
// get(<document path>): <document object>
val user = get<User>(users / "user1")

Warning

dynamic-api does not check if correct data class is used in generics.
So an incorrect class in generics will NOT be detected at compile-time.

val user = get<Message>(users / "user1")

get all

// get all
// getAll(<collection path>): Collection<document object>
val messages = getAll<Message>(users / "user1" / messages)

Warning

dynamic-api does not check if correct data class is used in generics.
So an incorrect class in generics will NOT be detected at compile-time.

val messages = getAll<User>(users / "user1" / messages)

delete document

// delete document and its child entities
// This can be a document under root collection or sub-collection.

// deleteDocument(<document path>)
deleteDocument(users / "user1")

delete collection

// delete collection and its child entities.
// This can be root collection or sub-collection.

// deleteCollection(<collection path>)
deleteCollection(users)