Skip to content

Latest commit

 

History

History
778 lines (662 loc) · 27.8 KB

API.md

File metadata and controls

778 lines (662 loc) · 27.8 KB

Classes

Collection

The Collection class lays at the heart of firestorter. It represents a collection in Firestore and its queried data. It is observable so that it can be efficiently linked to a React Component using mobx-react's observer pattern.

Collection supports three modes of real-time updating:

  • "auto" (real-time updating is enabled on demand) (default)
  • "on" (real-time updating is permanently turned on)
  • "off" (real-time updating is turned off, use .fetch explicitly)

The "auto" mode ensures that Collection only communicates with the firestore back-end whever the Collection is actually rendered by a Component. This prevents unneccesary background updates and leads to the best possible performance.

When real-time updates are enabled, data is automatically fetched from Firestore whenever it changes in the back-end (using onSnapshot). This enables almost magical instant updates. When data is changed, only those documents are updated that have actually changed. Document objects are re-used where possible, and just their data is updated. The same is true for the docs property. If no documents where added, removed, re-ordered, then the docs property itself will not change.

Alternatively, you can keep real-time updates turned off and fetch manually. This will update the Collection as efficiently as possible. If nothing has changed on the back-end, no new Documents would be created or modified.

Document

Document represents a document stored in the firestore database. Document is observable so that it can be efficiently linked to for instance a React Component using mobx-react's observer pattern. This ensures that a component is only re-rendered when data that is accessed in the render function has changed.

Members

Mode : Mode

Real-time updating mode.

Functions

initFirestorter(config)

Initializes firestorter with the firebase-app.

makeContext()

If you need to use different firestore instances for different collections, or otherwise want to avoid global state, you can instead provide a "context" opton when creating Document and Collection instances.

This function takes the same arguments as initFirestore and returns a context suitable for Document and Collection creation.

mergeUpdateData(data, fields)Object

Helper function which merges data into the source and returns the new object.

isTimestamp(val)Boolean

Checks whether the provided value is a valid Firestore Timestamp or Date.

Use this function in combination with schemas, in order to validate that the field in the document is indeed a timestamp.

Collection

The Collection class lays at the heart of firestorter. It represents a collection in Firestore and its queried data. It is observable so that it can be efficiently linked to a React Component using mobx-react's observer pattern.

Collection supports three modes of real-time updating:

  • "auto" (real-time updating is enabled on demand) (default)
  • "on" (real-time updating is permanently turned on)
  • "off" (real-time updating is turned off, use .fetch explicitly)

The "auto" mode ensures that Collection only communicates with the firestore back-end whever the Collection is actually rendered by a Component. This prevents unneccesary background updates and leads to the best possible performance.

When real-time updates are enabled, data is automatically fetched from Firestore whenever it changes in the back-end (using onSnapshot). This enables almost magical instant updates. When data is changed, only those documents are updated that have actually changed. Document objects are re-used where possible, and just their data is updated. The same is true for the docs property. If no documents where added, removed, re-ordered, then the docs property itself will not change.

Alternatively, you can keep real-time updates turned off and fetch manually. This will update the Collection as efficiently as possible. If nothing has changed on the back-end, no new Documents would be created or modified.

Kind: global class

new Collection([source], [options])

Param Type Description
[source] CollectionSource

String-path, ref or function that returns a path or ref

[options] Object

Configuration options

[options.query] function | Query

See Collection.query

[options.mode] String

See Collection.mode

[options.createDocument] function

Factory function for creating documents (source, options) => new Document(source, options)

[options.minimizeUpdates] boolean

Enables additional algorithms to reduces updates to your app (e.g. when snapshots are received in rapid succession)

[options.debug] boolean

Enables debug logging

[options.debugName] String

Name to use when debug logging is enabled

Example

import {Collection} from 'firestorter';

// Create a collection using path (preferred)
const col = new Collection('artists/Metallica/albums');

// Create a collection using a reference
const col2 = new Collection(firebase.firestore().collection('todos'));

// Create a collection and permanently start real-time updating
const col2 = new Collection('artists', {
  mode: 'on'
});

// Create a collection with a query on it
const col3 = new Collection('artists', {
  query: (ref) => ref.orderBy('name', 'asc')
});

Example

// In manual mode, just call `fetch` explicitely
const col = new Collection('albums', {mode: 'off'});
col.fetch().then((collection) => {
  collection.docs.forEach((doc) => console.log(doc));
});

// Yo can use the `isLoading` property to see whether a fetch
// is in progress
console.log(col.isLoading);

collection.docs : Array

Array of all the documents that have been fetched from firestore.

Kind: instance property of Collection
Example

collection.docs.forEach((doc) => {
  console.log(doc.data);
});

collection.hasDocs : boolean

True whenever the docs array is not empty.

Kind: instance property of Collection

collection.ref : firestore.CollectionReference | function

Firestore collection reference.

Use this property to get or set the collection reference. When set, a fetch to the new collection is performed.

Alternatively, you can also use path to change the reference in more a readable way.

Kind: instance property of Collection
Example

const col = new Collection(firebase.firestore().collection('albums/splinter/tracks'));
...
// Switch to another collection
col.ref = firebase.firestore().collection('albums/americana/tracks');

collection.id : string

Id of the Firestore collection (e.g. 'tracks').

To get the full-path of the collection, use path.

Kind: instance property of Collection

collection.path : string | function

Path of the collection (e.g. 'albums/blackAlbum/tracks').

Use this property to switch to another collection in the back-end. Effectively, it is a more compact and readable way of setting a new ref.

Kind: instance property of Collection
Example

const col = new Collection('artists/Metallica/albums');
...
// Switch to another collection in the back-end
col.path = 'artists/EaglesOfDeathMetal/albums';

collection.query : firestore.Query | function

Use this property to set any order-by, where, limit or start/end criteria. When set, that query is used to retrieve any data. When cleared (undefined), the collection reference is used.

The query can be a Function of the form (firestore.CollectionReference) => firestore.Query | null | undefined. Where returning null will result in an empty collection, and returning undefined will revert to using the collection reference (the entire collection).

If the query function makes use of any observable values then it will be re-run when those values change.

query can be set to a direct Firestore Query object but this is an uncommon usage.

Kind: instance property of Collection
Example

const todos = new Collection('todos');

// Sort the collection
todos.query = (ref) => ref.orderBy('text', 'asc');

// Order, filter & limit
todos.query = (ref) => ref.where('finished', '==', false).orderBy('finished', 'asc').limit(20);

// React to changes in observable and force empty collection when required
todos.query = (ref) => authStore.uid ? ref.where('owner', '==', authStore.uid) : null;

// Clear the query, will cause whole collection to be fetched
todos.query = undefined;

collection.mode : string

Real-time updating mode.

Can be set to any of the following values:

  • "auto" (enables real-time updating when the collection is observed)
  • "off" (no real-time updating, you need to call fetch explicitly)
  • "on" (real-time updating is permanently enabled)

Kind: instance property of Collection

collection.isActive : boolean

Returns true when the Collection is actively listening for changes in the firestore back-end.

Kind: instance property of Collection

collection.isLoading : boolean

True when new data is being loaded.

Fetches are performed in these cases:

  • When real-time updating is started
  • When a different ref or path is set
  • When a query is set or cleared
  • When fetch is explicitely called

Kind: instance property of Collection
Example

const col = new Collection('albums', {mode: 'off'});
console.log(col.isLoading);  // false
col.fetch();                 // start fetch
console.log(col.isLoading);  // true
await col.ready();           // wait for fetch to complete
console.log(col.isLoading);  // false

Example

const col = new Collection('albums');
console.log(col.isLoading);  // false
const dispose = autorun(() => {
  console.log(col.docs);     // start observing collection data
});
console.log(col.isLoading);  // true
...
dispose();                   // stop observing collection data
console.log(col.isLoading);  // false

collection.fetch() ⇒ Promise

Fetches new data from firestore. Use this to manually fetch new data when mode is set to 'off'.

Kind: instance method of Collection
Fulfil: Collection - This collection
Reject: Error - Error describing the cause of the problem
Example

const col = new Collection('albums', 'off');
col.fetch().then(({docs}) => {
  docs.forEach(doc => console.log(doc));
});

collection.ready() ⇒ Promise

Promise that is resolved when the Collection has finished fetching its (initial) documents.

Use this method to for instance wait for the initial snapshot update to complete, or to wait for fresh data after changing the path/ref.

Kind: instance method of Collection
Example

const col = new Collection('albums', {mode: 'on'});
await col.ready();
console.log('albums: ', col.docs);

Example

const col = new Collection('artists/FooFighters/albums', {mode: 'on'});
await col.ready();
...
// Changing the path causes a new snapshot update
col.path = 'artists/TheOffspring/albums';
await col.ready();
console.log('albums: ', col.docs);

collection.add(data) ⇒ Promise

Add a new document to this collection with the specified data, assigning it a document ID automatically.

Kind: instance method of Collection
Fulfil: Document - The newly created document
Reject: Error - Error, e.g. a schema validation error or Firestore error

Param Type Description
data Object

JSON data for the new document

Example

const doc = await collection.add({
  finished: false,
  text: 'New todo',
  options: {
    highPrio: true
  }
});
console.log(doc.id); // print id of new document

Example

// If you want to create a document with a custom Id, then
// use the Document class instead, like this
const docWithCustomId = new Document('todos/mytodoid');
await docWithCustomId.set({
  finished: false,
  text: 'New todo',
});

Document

Document represents a document stored in the firestore database. Document is observable so that it can be efficiently linked to for instance a React Component using mobx-react's observer pattern. This ensures that a component is only re-rendered when data that is accessed in the render function has changed.

Kind: global class

new Document([source], [options])

Param Type Description
[source] DocumentSource

String-path, ref or function that returns a path or ref

[options] Object

Configuration options

[options.mode] String

See Document.mode (default: auto)

[options.schema] function

Superstruct schema for data validation

[options.snapshot] firestore.DocumentSnapshot

Initial document snapshot

[options.snapshotOptions] firestore.SnapshotOptions

Options that configure how data is retrieved from a snapshot

[options.debug] boolean

Enables debug logging

[options.debugName] String

Name to use when debug logging is enabled

document.schema : function

Returns the superstruct schema used to validate the document, or undefined.

Kind: instance property of Document

document.data : Object

Returns the data inside the firestore document.

Kind: instance property of Document
Example

todos.docs.map((doc) => {
  console.log(doc.data);
  // {
  //   finished: false
  //   text: 'Must do this'
  // }
});

document.hasData : boolean

True whenever the document has fetched any data.

Kind: instance property of Document

document.ref : firestore.DocumentReference | function

Firestore document reference.

Use this property to get or set the underlying document reference.

Alternatively, you can also use path to change the reference in more a readable way.

Kind: instance property of Document
Example

const doc = new Document('albums/splinter');

// Get the DocumentReference for `albums/splinter`
const ref = doc.ref;

// Switch to another document
doc.ref = firebase.firestore().doc('albums/americana');

document.id : string

Id of the firestore document.

To get the full-path of the document, use path.

Kind: instance property of Document

document.path : string | function

Path of the document (e.g. 'albums/blackAlbum').

Use this property to switch to another document in the back-end. Effectively, it is a more compact and readable way of setting a new ref.

Kind: instance property of Document
Example

const doc = new Document('artists/Metallica');
...
// Switch to another document in the back-end
doc.path = 'artists/EaglesOfDeathMetal';

// Or, you can use a reactive function to link
// to the contents of another document.
const doc2 = new Document('settings/activeArtist');
doc.path = () => 'artists/' + doc2.data.artistId;

document.mode : string

Real-time updating mode.

Can be set to any of the following values:

  • "auto" (enables real-time updating when the document becomes observed)
  • "off" (no real-time updating, you need to call fetch explicitly)
  • "on" (real-time updating is permanently enabled)

Kind: instance property of Document

document.isActive : boolean

Returns true when the Document is actively listening for changes in the firestore back-end.

Kind: instance property of Document

document.snapshot : firestore.DocumentSnapshot

Underlying firestore snapshot.

Kind: instance property of Document

document.isLoading : boolean

True when new data is being loaded.

Loads are performed in these cases:

  • When real-time updating is started
  • When a different ref or path is set
  • When a query is set or cleared
  • When fetch is explicitely called

Kind: instance property of Document
Example

const doc = new Document('albums/splinter', {mode: 'off'});
console.log(doc.isLoading); 	// false
doc.fetch(); 								// start fetch
console.log(doc.isLoading); 	// true
await doc.ready(); 					// wait for fetch to complete
console.log(doc.isLoading); 	// false

Example

const doc = new Document('albums/splinter');
console.log(doc.isLoading); 	// false
const dispose = autorun(() => {
  console.log(doc.data);			// start observing document data
});
console.log(doc.isLoading); 	// true
...
dispose();										// stop observing document data
console.log(doc.isLoading); 	// false

document.update(fields) ⇒ Promise

Updates one or more fields in the document.

The update will fail if applied to a document that does not exist.

Kind: instance method of Document

Param Type Description
fields Object

Fields to update

Example

await todoDoc.update({
  finished: true,
  text: 'O yeah, checked this one off',
  foo: {
    bar: 10
  }
});

document.set(data, [options]) ⇒ Promise

Writes to the document.

If the document does not exist yet, it will be created. If you pass options, the provided data can be merged into the existing document.

Kind: instance method of Document

Param Type Description
data Object

An object of the fields and values for the document

[options] Object

Set behaviour options

[options.merge] Boolean

Set to true to only replace the values specified in the data argument. Fields omitted will remain untouched.

Example

const todo = new Document('todos/mynewtodo');
await todo.set({
  finished: false,
  text: 'this is awesome'
});

document.delete() ⇒ Promise

Deletes the document in Firestore.

Returns a promise that resolves once the document has been successfully deleted from the backend (Note that it won't resolve while you're offline).

Kind: instance method of Document

document.fetch() ⇒ Promise

Fetches new data from firestore. Use this to manually fetch new data when mode is set to 'off'.

Kind: instance method of Document
Fullfil: Document<T> This document
Example

const doc = new Document('albums/splinter');
await doc.fetch();
console.log('data: ', doc.data);

document.ready() ⇒ Promise

Promise that is resolved when the Document has data ready to be consumed.

Use this function to for instance wait for the initial snapshot update to complete, or to wait for fresh data after changing the path/ref.

Kind: instance method of Document
Example

const doc = new Document('albums/splinter', {mode: 'on'});
await doc.ready();
console.log('data: ', doc.data);

Example

const doc = new Document('albums/splinter', {mode: 'on'});
await doc.ready();
...
// Changing the path causes a new snapshot update
doc.path = 'albums/americana';
await doc.ready();
console.log('data: ', doc.data);

Mode : Mode

Real-time updating mode.

Kind: global variable

initFirestorter(config)

Initializes firestorter with the firebase-app.

Kind: global function

Param Type Description
config Object

Configuration options

config.firebase Firebase

Firebase reference

[config.app] String | FirebaseApp

FirebaseApp to use (when omitted the default app is used)

Example

import firebase from 'firebase';
import 'firebase/firestore';
import {initFirestorter, Collection, Document} from 'firestorter';

// Initialize firebase app
firebase.initializeApp({...});

// Initialize `firestorter`
initFirestorter({firebase: firebase});

// Create collection or document
const albums = new Collection('artists/Metallica/albums');
...
const album = new Document('artists/Metallica/albums/BlackAlbum');
...

makeContext()

If you need to use different firestore instances for different collections, or otherwise want to avoid global state, you can instead provide a "context" opton when creating Document and Collection instances.

This function takes the same arguments as initFirestore and returns a context suitable for Document and Collection creation.

Kind: global function
Example

import firebase from 'firebase';
import 'firebase/firestore'
import * as firetest from '@firebase/testing'
import {makeContext, Collection, Document} from "firestorter"

function makeTestContext(fbtestArgs) {
	 const app = firetest.initializeTestApp(fbtestArgs)
  return makeContext({
    firestore,
    app,
  })
}

// create collection or document without global state
test('collection and document using different apps', () => {
  const context1 = makeTestContext({ projectId: 'foo' })
  const context2 = makeTestContext({ projectId: 'bar' })

  // Create collection or document
  const albums = new Collection('artists/Metallica/albums', {context: context1});
  ...
  const album = new Document('artists/Metallica/albums/BlackAlbum', {context: context2});
  ...
})

mergeUpdateData(data, fields) ⇒ Object

Helper function which merges data into the source and returns the new object.

Kind: global function
Returns: Object -

Result

Param Type Description
data Object

JSON data

fields Object

JSON data that supports field-paths

isTimestamp(val) ⇒ Boolean

Checks whether the provided value is a valid Firestore Timestamp or Date.

Use this function in combination with schemas, in order to validate that the field in the document is indeed a timestamp.

Kind: global function

Param Type Description
val Object

Value to check

Example

import { isTimestamp } from 'firestorter';

const TaskSchema = struct({
 name: 'string',
 startDate: isTimestamp,
 duration: 'number'
});

const doc = new Document('tasks/mytask', {
  schema: TaskSchema
});
await doc.fetch();
console.log('startDate: ', doc.data.startDate.toDate());