Flamev0.7.0

Getting Started

About

Flame is a data model and query library for Firestore.

Firestore is a fully managed, internet scale document database offered by Google. Flame was designed to improve clarity and accuracy of Firestore related data model and query code.

Among other features, Flame makes it easy to define models, write queries and transactions, and page data with cursor based paging. As a bonus, (compared to using firestore-admin directly) using Flame will greatly reduce the amount code in API endpoints and Lambda functions that interact with Firestore.

If you have any ± feedback, feature requests, or bug reports, please open an issue on Github.

Install

Install flame-odm using yarn or npm.

At this time, Flame targets node.js and will not work in the browser.

Note: Flame works alongside existing installations of firebase-admin in your project.

Connect to Firestore

The connection to Firestore is defined as part of an Adapter. If you are using Firebase Functions, Flame's default Adapter will connect automatically. The following example shows how to define the connection manually using a service account.

Note: Flame doesn't immediately create a database connection. When queries are run, the Adapter lazily connects to Firestore as needed.

Define a Model

Let's create our first Model using the Adapter we just defined.

Create a Record

Now, we can use our User Model to create a Record.

Save a Document

Then, we can save the Record we just created as a document to Firestore.

Run a Query

Finally, we can execute a Query to retrieve the document saved in Firestore.

API Reference

Access

new Access(mask)

Create an Access that can be used to screen Objects using a role-basd mask.

Parameters
mask (Object)
An Object that mirrors defaults on the target Model, where the value of each field is an Array of roles allowed to access the given field.
Returns
value (Access)
Returns the new Access.
Example

Access.fields(roles)

List the fields allowed by an Access, given one or more roles.

Parameters
roles (Array)
The roles used to determine allowed fields.
Returns
value (Array)
Returns an array of allowed fields.
Example

Access.screen(obj, roles)

Creates a copy of obj including only role-allowed fields.

Parameters
obj (Object)
The object to be screened.
roles (Array)
The roles used to determine allowed fields.
Returns
value (Object)
Returns the new, screened object.
Example

Adapter

new Adapter(service_account, app_name)

Create an Adapter which can be used as a mixin when creating a Model or Record.

Parameters
service_account (Function|Object|String) Optional

When service_account is 'firebase-function' or 'google-cloud' the service account will be retrieved automatically from the respective platform.

When service_account is 'process-env' Flame will look for the service account as a JSON string stored at process.env.FB_SERVICE_ACCOUNT.

When service_account is an Object, Flame assumes the Object is the service account.

When service_account is a Function, Flame will invoke service_account(), which should return a Promise that resolves to a service account Object.

When unspecified, Flame will default to using 'firebase-function'.

Note: If you are using Flame in a Firebase Function, you do not need to define or use an Adapter. Flame will automatically use the default Adapter and connect as needed.

app_name (String) Optional

Create multiple Adapters with different app_names to connect to multiple Firestore databases.

If service_account is: 'google-cloud', 'firebase-function', or null then app_name is ignored.

Returns
value (Adapter)
Returns the new Adapter.
Example

Adapter.connect()

Avoid calling Adapter.connect() directly, it is invoked automatically by Adapter, Model, and Record methods as needed.

Connect to Firestore.

Returns
value (Promise → Nothing)
Returns a Promise that resolves empty.
Example

Adapter.transact(fn)

Executes a set of database operations as a transaction.

The argument fn is a Function invoked with one argument: T (Transaction) which may be passed to any read or write methods carried out within the context of Adatper.transact.

Parameters
fn (Function)
The Function that wraps the read/write operations to be handled as a transaction.
Returns
value (Promise → Any)
Returns the return value of fn.
Example

Config

new Config(obj)

Create a Config which is used to store and pass configuration options to other constructors.

Parameters
obj (Object)
An Object of { field: value, ...} entries allowed by the constructor or method that will recieve Config.
Returns
value (Config)
Returns the new Config.
Example

Model

new Model(type, defaults, mixins...)

Create a Model. A Model defines the structure of the documents to be stored in Firestore.

Parameters
type (String)

This Model's type.

By default, type will be the collection in Firestore for documents saved by Records created from this Model. However, the collection can be overriden with a custom Config.

defaults (Object)

The structure of your Model defined by an Object of {field: value, ...} entries, where value can be any of: Array, Boolean, Number, Null, Object, String, or Function.

When value is a Function, it will be invoked with two arguments: type and values where type is the Model's type and values is a clone of defaults.

mixins... (Adapter|Config|Serializer|Validator) Optional
For each additional argument passed to the Model's constructor of (Type), the Model's corresponding default (Type) will be overridden.
Returns
value (Model)
Returns the new Model.
Example

Model.count(query)

Count the number of documents in a collection that satisfy query.

Parameters
query Optional
The Query that determines what to count. If query is not specified, all documents in the collection are counted.
Returns
value (Promise → Integer|Null)
Returns a Promise that resolves to the Integer number of documents in the collection that satisfy query, or Null if Model.count() fails.
Example

Model.create(values, mixins...)

Create a new Record.

Parameters
values (Object)
An Object of the values for Record. values will be merged with the Model's defaults.
mixins... (Adapter|Config|Serializer|Validator) Optional
For each additional argument passed to Model.create() of (Type), the created Record's corresponding default (Type) will be overridden.
Returns
value (Record)
Returns the new Record.
Example

Model.extend(type, defaults, mixins...)

Extend a Model.

Parameters
type (String)

This Model's type.

By default type will be the collection used in Firestore when saving a Record. However, the collection can be overriden with a custom Config.

defaults (Object)

The structure of your Model defined by an Object of {field: value, ...} entries, where value can be any of: Array, Boolean, Number, Null, Object, String, or Function. defaults will be merged with the extended Model's defaults.

When value is a Function, it will be invoked with two arguments: type and values where type is the Model's type and values is a clone of defaults.

mixins... (Adapter|Config|Serializer|Validator) Optional
For each additional argument passed to the Model's constructor of (Type), the Model's corresponding default (Type) will be overridden.
Returns
value (Model)
Returns the new Model.
Example

Model.find(query, T)

Retrieve the first document in a collection that satisfies query.

Parameters
query Optional
The Query that determines what documents are elliglbe. If query is not specified, the first document in the collection is returned
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Model.find() within the context of Adapter.transact().
Returns
value (Promise → Object|Null)
Returns the return the document Object, or Null if there is no match.
Example

Model.findAll(query, T)

Retrieve all documents in a collection that satisfy query.

Parameters
query Optional
The Query that determines what documents will be included. If query is not specified, all documents in the collection will be included.
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Model.findAll() within the context of Adapter.transact().
Returns
value (Promise → Array|Null)
Returns an array of matching document Objects, or Null if there are no matches.
Example

Model.fragment(id, values, mixins...)

Create a partial Record using an existing document ID.

Parameters
id (String)
The the document ID
values (Object)
An Object of the values for Record. values will be merged with the Model's defaults.
mixins... (Adapter|Config|Serializer|Validator) Optional
For each additional argument passed to Model.fragment() of (Type), the created Record's corresponding default (Type) will be overridden.
Returns
value (Record)
Returns the new Record.
Example

Model.get(id, T)

Retrieve a single document from a collection.

Parameters
id (String)
The document ID.
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Model.get() within the context of Adapter.transact().
Returns
value (Promise → Object|Null)
Returns the Record Object, or Null if there is no document with the given id.
Example

Model.getAll(ids, T)

Retreive multiple documents from a collection.

Parameters
ids (Array<String>)
The document IDs of the documents to retrieve.
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Model.getAll() within the context of Adapter.transact().
Returns
value (Promise → Array<Object>|Null)
Returns an Array of the document Objects, or Null if any of the provided ids do not correspond to a document in Firestore.
Example

Model.page(pager, cursor, fields, T)

Retrieve a page of documents from a collection.

Parameters
pager (Pager)
The Pager to use.
cursor (Object) Optional

An Object that defines the current cursor and it's position.

When unspecified or Null, cursor defaults to the first document in the collection that satisfies pager.

fields (Array<String>) Optional
The fields that should be included in the returned documents.
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Model.getAll() within the context of Adapter.transact().
Returns
value (Promise → Object|Null)
Returns a page Object, or Null if there are no documents that satisfy the supplied pager and cursor.
Example

Model.traverse(pager, fn, fields)

Traverse all documents in a collection that satisify the constraints of pager. fn is invoked once with each record as its first argument.

Parameters
pager (Pager)

The Pager to use. When Pager is initalized with { size: 1 }, each invocation of fn will be in serial. Otherwise, fn will be invoked on all records in a given page in parallel.

Use size as a rate-limiter to ensure Model.traverse() doesn't exceed read or write limits.

fn (Function)

An Object that defines the current cursor and it's position.

When unspecified or Null, the cursor defaults to the first document in the collection that satisfies pager.

fields (Array<String>) Optional
The fields that should be included in the returned documents.
Returns
value (Promise → Object|Null)
Returns a page Object, or Null if there are no documents that satisfy the supplied pager.
Example

Pager

new Pager(q, opts)

Creates a Pager that can be used to in combination with Model.page() to retrieve cursor-based pages from a collection in Firestore.

Parameters
q (Array<Array>)

An Array of constraint tuples that defines what documents are included when retrieving a page using this Pager in combination with Model.page(). Each constraint tuple is represented using an Array in the form [constraint, field, value(s)].

The allowed constraint tuples are:

Constraint Tuples
'eq'field (String)value  (Array|Boolean|Number|Null|Object|String)
'eq-any'field (String)values (Array<Array|Boolean|Number|Null|Object|String>)
'gt'field (String)value  (Array|Boolean|Number|Null|Object|String)
'gte'field (String)value  (Array|Boolean|Number|Null|Object|String)
'includes'field (String)value  (Array|Boolean|Number|Null|Object|String)
'includes-any'field (String)values (Array<Array|Boolean|Number|Null|Object|String>)
'lt'field (String)value  (Array|Boolean|Number|Null|Object|String)
'lte'field (String)value  (Array|Boolean|Number|Null|Object|String)
'not-eq'field (String)value  (Array|Boolean|Number|Null|Object|String)
'not-eq-any'field (String)values (Array<Array|Boolean|Number|Null|Object|String>)
'order-by'field (String)values (Array<String>)
opts (Object)
An Object of the form { size: value (Integer) } where value is the number of documents per page.
Returns
value (Pager)
Returns the new Pager.
Example

Query

new Query(q, serializer)

Create a Query that can be used with Model.count(), Model.find(), and Model.findAll() to count and retrieve documents from Firestore.

Parameters
q (Array<Array>)

An Array of constraint tuples that defines what documents are included when using this Query in combination with Model.count(), Model.find(), or Model.findAll(). Each constraint tuple is represented using an Array in the form [constraint, field, value(s)] or [constraint, value(s)].

The allowed constraint tuples are:

Constraint Tuples
'eq'field (String)value  (Array|Boolean|Number|Null|Object|String)
'eq-any'field (String)values (Array<Array|Boolean|Number|Null|Object|String>)
'gt'field (String)value  (Array|Boolean|Number|Null|Object|String)
'gte'field (String)value  (Array|Boolean|Number|Null|Object|String)
'includes'field (String)value  (Array|Boolean|Number|Null|Object|String)
'includes-any'field (String)values (Array<Array|Boolean|Number|Null|Object|String>)
'limit'value (Integer)
'lt'field (String)value  (Array|Boolean|Number|Null|Object|String)
'lte'field (String)value  (Array|Boolean|Number|Null|Object|String)
'not-eq'field (String)value  (Array|Boolean|Number|Null|Object|String)
'not-eq-any'field (String)values (Array<Array|Boolean|Number|Null|Object|String>)
'order-by'field (String)values (Array<String>)
'start-at'value (Array<Strings>)
Returns
value (Query)
Returns the new Query.
Example

Record

Record.destroy(T)

Permanently removes the document represented by this Record from Firestore.

Parameters
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Record.destroy() within the context of Adapter.transact().
Returns
value (Promise → Boolean|Null)
Returns the true if successful, otherwise false.
Example

Record.errors(fields)

Produces an Object of the Record's fields that are not valid.

Parameters
fields (Array) Optional
An Array of fields to validate. When unspecified or Null, all fields are validated.
Returns
value (Object)
An Object in the form of { field: value (Boolean), ... } where each field is a field in the Record, and each value is true if the field fails this Record's corresponding Validator function.
Example

Record.obj()

Produces the Object representation of this Record's fields and values.

Returns
value (Object)
Returns the Record's as an Object.
Example

Record.ok(fields)

Check if all fields of the Record are valid.

Parameters
fields (Array<String>)
The fields to check, if unspecified or Null all fields are checked.
Returns
value (Boolean)
Returns true if all fields are valid, otherwise false.
Example

Record.save(T)

Save this Record to Firestore as a document.

Parameters
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Record.save() within the context of Adapter.transact().
Returns
value (Promise → Boolean)
Returns true when successful, otherwise false.
Example

Record.update(fields, T)

Update this Record's corresponding document in Firestore.

Parameters
fields (Object)
The fields to update in this Record's document in Firestore.
T (Transaction) Optional
A Firestore transaction Object. Use when invoking Record.update() within the context of Adapter.transact().
Returns
value (Promise → Boolean)
Returns true when successful, otherwise false.
Example

Serializer

new Serializer(opts)

Create a Serializer that can be used to transform Record Object format into a Firestore document Object format, and vice-a-versa.

Parameters
opts (Object)

opts is an Object with three allowed fields: prefixes, separator, and fmt.

prefixes is an Array of prefixes that can be used to create 2-level Records that will be automatically flattened by Flame as they are written to Firestore, and documents retrieved from Firestore will automatically be expanded back into 2-level Objects.

separator is used as field concatenator between the prefixes and the 2nd-level field names for 2-level Records stored in Firestore.

fmt normalizes the casing for field names when in Firestore, and as Objects. Snake, kebabk, pascal, and camel cases are supported.

Returns
value (Serializer)
Returns the new Serializer.
Example

Validator

new Validator(v)

Create a Validator that can be used to check if a Record's fields are valid.

Parameters
v (Object)

An Object of the form { field: validator } that mirrors the structure of the target Model, where the validator of each field is a Function.

Each validator is invoked with two arguments, value and object. value is the Record's corresponding field value, and object is the full Object representation of the Record.

Each validator should evaluate true if valid, false otherwise.

Returns
value (Validator)
Returns the new Validator.
Example