OnFire
OnFire is a library that makes it easier to develop and maintain Firebase apps that have complex data structures, whether they are browser-based or run on Node.js.
Already implemented:
- Schema-driven, live models. Where appropriate, property values are also models, automatically.
- Makes Promises, instead of actually calling you back. 😆
Coming soon:
- Atomic operations that involve multiple models simultaneously.
- Persistence! This is for loading data while offline, or for priming your app for a quick start.
Here are more details.
Contents
Examples
var Person = onfire; // Access an object at a specific location:var person = ref;person ; // A getter/setter is generated for each property specified in the schema.console; // The jobs property is automatically instantiated as a collection model.console // Chainable setters:person; // After setting the values, we need to save the changes:person; // a promise. // or all together:person ; // This will throw an exception, because of the mis-spelt property name.// Schema-driven modules reduce the chances of unintentional errors in your code.person; // Collections can be conveniently manipulated.person ; // Add a new member to a collection.person ; // When a member's ID is predetermined, fetchOrCreate() will fetch it if it already exists, and// create it if it doesn't. This is, of course, performed transactionally.person ;
Documentation
Ref
/** * An analogue of a Firebase reference. * @see https://www.firebase.com/docs/web/api/firebase/constructor.html * * @param {string|!Firebase} urlOrRef A Firebase URL or a Firebase reference instance. * @constructor * @final */onfire {}; /** * Firebase.authAnonymously() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/authanonymously.html * * @param * @return {!Promise<!Firebase.AuthCallbackData,!Error>} A promise which resolves to the authData, * or is rejected with an error. */onfireRefprototype {}; /** * Firebase.authWithCustomToken() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/authwithcustomtoken.html * * @param * @param * @return {!Promise<!Firebase.AuthCallbackData,!Error>} A promise which resolves to the authData, * or is rejected with an error. */onfireRefprototype {}; /** * Firebase.authWithOAuthPopup() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/authwithoauthpopup.html * * @param * @param * @return {!Promise<!Firebase.AuthCallbackData,!Error>} A promise which resolves to the authData, * or is rejected with an error. */onfireRefprototype {}; /** * Firebase.authWithOAuthRedirect() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/authwithoauthredirect.html * * @param * @param * @return {!Promise<null,!Error>} A promise which is rejected with an error if the authentication * fails. */onfireRefprototype {}; /** * Firebase.authWithOAuthToken() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/authwithoauthtoken.html * * @param * @param {string|!Object} credentials * @param * @return {!Promise<!Firebase.AuthCallbackData,!Error>} A promise which resolves to the authData, * or is rejected with an error. */onfireRefprototype {}; /** * Firebase.authWithPassword() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/authwithpassword.html * * @param * @param * @return {!Promise<!Firebase.AuthCallbackData,!Error>} A promise which resolves to the authData, * or is rejected with an error. */onfireRefprototype {}; /** * Firebase.changeEmail() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/changeemail.html * * @param {!{oldEmail:string, password:string, newEmail:string}} credentials * @return {!Promise<null,!Error>} A promise which resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {}; /** * Firebase.changePassword() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/changepassword.html * * @param {!{email:string, oldPassword:string, newPassword:string}} credentials * @return {!Promise<null,!Error>} A promise which resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {}; /** * Firebase.createUser() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/createuser.html * * @param * @return {!Promise<!{uid:string}},!Error>} A promise which resolves to a userData object, or is * rejected with an error. */onfireRefprototype {}; /** * Returns a reference that is relative to the current location. * @see https://www.firebase.com/docs/web/api/firebase/child.html * * @param * @return */onfireRefprototype {}; /** * Generates a push ID. This takes the place of .push() when all we want is a unique ID, via a * synchronous method instead of a promise, which is what .push() returns. * * @return */onfireRefprototype {}; /** * A proxy for Firebase.getAuth(). * @see https://www.firebase.com/docs/web/api/firebase/getauth.html * * @return */onfireRefprototype {}; /** * Returns the key of the current location. * @see https://www.firebase.com/docs/web/api/firebase/key.html * * @return */onfireRefprototype {}; /** * Deregisters a previously registered callback. * @see https://www.firebase.com/docs/web/api/query/off.html * * @param * @param * returned by the .on() method. * @param */onfireRefprototype {}; /** * A proxy for Firebase.offAuth(). * @see https://www.firebase.com/docs/web/api/firebase/offauth.html * * @param {!function(Firebase.AuthCallbackData)} onComplete * @param */onfireRefprototype {}; /** * Deregisters a previously registered .onValue() callback. * * @param {!function(Firebase.Value)} callback This MUST be the *wrapped* callback returned * by .onValue(). * @param */onfireRefprototype {}; /** * Registers a callback for an event of a specified type at the current location. Make sure to keep * the return value for use when turning this off -- see the off() method. * @see https://www.firebase.com/docs/web/api/query/on.html * * @param * @param * @param * @param * @return {!function(!Firebase.DataSnapshot, ?string=)} A handler function that may be needed when * deregistering the callback. */onfireRefprototype {}; /** * A proxy for Firebase.onAuth(). * @see https://www.firebase.com/docs/web/api/firebase/onauth.html * * @param {!function(Firebase.AuthCallbackData)} onComplete * @param */onfireRefprototype {}; /** * Waits for the first event of a specified type at the current location. A promisified analogue * of Firebase's .once() method. * @see https://www.firebase.com/docs/web/api/query/once.html * * @param * @return {!Promise<!Firebase.DataSnapshot,!Error>} A promise that resolves to a Firebase snapshot, * or is rejected with an error. */onfireRefprototype {}; /** * Retrieves the value that is stored at the current location. This is shorthand for calling .once() * for the 'value' event and then extracting the value of the returned snapshot. * * @return {!Promise<Firebase.Value,!Error>} A promise that * resolves to the value stored at the current location, or is rejected with an error. */onfireRefprototype {}; /** * Registers a callback for value changes at the current location. This is shorthand for calling * .on() for the 'value' event and then extracting the value of each returned snapshot. Make sure to * keep the return value for when you want to turn this off. See the .offValue() method. * * @param {!function(Firebase.Value)} callback * @param * @param * @return {!function(!Firebase.DataSnapshot)} */onfireRefprototype {}; /** * Returns a reference to the parent of the current location. * @see https://www.firebase.com/docs/web/api/firebase/parent.html * * @return */onfireRefprototype {}; /** * Returns the path of this reference relative to the root, i.e. not including the firebaseio.com * domain. * * @return */onfireRefprototype {}; /** * Pushes a value under the current location. A promisified analogue of Firebase's .push() method. * @see https://www.firebase.com/docs/web/api/firebase/push.html * * @param * @return {!Promise<!onfire.Ref,!Error>} A promise that resolves to the Ref of the newly pushed * child. */onfireRefprototype {}; /** * Returns an unwrapped Firebase reference to the current location. * * @return */onfireRefprototype {}; /** * Removes the data that is stored at the current location. A promisified analogue of Firebase's * .remove() method. * @see https://www.firebase.com/docs/web/api/firebase/remove.html * * @return {!Promise<null,!Error>} A promise that resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {}; /** * Firebase.removeUser() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/removeuser.html * * @param * @return {!Promise<null,!Error>} A promise which resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {}; /** * Firebase.resetPassword() wrapped in a promise. * @see https://www.firebase.com/docs/web/api/firebase/resetpassword.html * * @param {!{email:string}} credentials * @return {!Promise<null,!Error>} A promise which resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {}; /** * Returns a reference that represents the root of the tree. * @see https://www.firebase.com/docs/web/api/firebase/root.html * * @return */onfireRefprototype {}; /** * Stores a value at the current location. A promisified analogue of Firebase's .set() method. * @see https://www.firebase.com/docs/web/api/firebase/set.html * * @param * @return {!Promise<null,!Error>} A promise that resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {}; /** * Sets a the values stored at the current location, atomically. A promisified analogue of * Firebase's .transaction() method. * @see https://www.firebase.com/docs/web/api/firebase/transaction.html * * @param * @return {!Promise<!{{isCommitted:boolean,snapshot:Firebase.DataSnapshot}},!Error>} A promise that * resolves when the operation is complete, or is rejected with an error. The value provided * when the promise resolves is an object with two properties: * isCommitted: whether the operation actually committed a value to the database. * snapshot: a snapshot of the current data. */onfireRefprototype {}; /** * A proxy for Firebase.unauth(). * @see https://www.firebase.com/docs/web/api/firebase/unauth.html */onfireRefprototype {}; /** * Updates multiple key/value pairs stored at the current location. A promisified analogue of * Firebase's .update() method. * @see https://www.firebase.com/docs/web/api/firebase/update.html * * @param {!Object<string,Firebase.Value>} values An object containing the key/value pairs. * @return {!Promise<null,!Error>} A promise that resolves when the operation is complete, or is * rejected with an error. */onfireRefprototype {};
defineModel
/** * Generates a subclass of onfire.model.Model or onfire.model.Collection with a baked in schema. * * @param * @return {!function(new:onfire.model.Model, !onfire.Ref)} A model constructor. * @throws */onfire {};
Model
/** * Base class to represent objects that live in Firebase. * * @param * @constructor */onfiremodel {}; /** * Releases resources used by the model. Call this when you no longer need the instance. */onfiremodelModelprototype {}; /** * Determines whether the underlying data exists. We may have retrieved a non-existent object, or * it may have subsequently been deleted. * * @return * @throws */onfiremodelModelprototype {}; /** * Synchronously retrieves the value associated with a key. If the value is not a primitive, a model * instance will be returned, in which case .whenLoaded() should be called on the returned model in * order to know when it is ready to use. If the key is already known to represent a model, it is * better to obtain it via the asynchronous .fetch() method. * If the key is specified in the schema, its value, or a model representing its value, will be * returned. If the key represents a primitive but missing value, the return value will be null. * If the key is not specified in the schema, but does have a value in the underlying data, that * value will be returned. Otherwise, an exception will be thrown. * * @param * @return * @throws */onfiremodelModelprototype {}; /** * Synchronously retrieves the primitive value associated with a key. If the value is an object, it * is returned unwrapped, i.e. not as a model instance. * If the key is specified in the schema, its value will be returned. If the key does not have a * value the return value will be null. * If the key is not specified in the schema, but does have a value in the underlying data, that * value will be returned. Otherwise, an exception will be thrown. * * @param * @return * @throws */onfiremodelModelprototype {}; /** * Synchronously retrieves the model instance that represents a non-primitive value that is * associated with a key. Make sure to call .whenLoaded() on the returned model in order to know when * it is ready to use. In many cases it may be more convenient to call the asynchronous .fetch() * method instead. * If the key is not specified in the schema, an exception will be thrown. * * @param * @return * @throws */onfiremodelModelprototype {}; /** * Determines whether there are any unsaved changes on this model. * * @return */onfiremodelModelprototype {}; /** * Returns the key of the model's reference. * * @return */onfiremodelModelprototype {}; /** * Register the callback function that will be called whenever the model is updated. To deregister * an existing callback, just pass null as the callback argument. * * @param {function()|null} callback */onfiremodelModelprototype {}; /** * Asynchronously commits the outstanding changes. * * @return {!Promise<!onfire.model.Model,!Error>} A promise that resolves to this model instance * when the operation completes successfully, or is rejected with an error. * @throws */onfiremodelModelprototype {}; /** * Registers the desire to change the primitive value associated with a key. The value will be * committed only when .save() is called. Returns a reference to the current model to allow * chaining, e.g., * person.set('firstName', 'John').set('lastName', 'Smith').save() * Throws an error if the key is not specified in the schema and does not already have a value in * the underlying data. * * @param * @param * @return * @throws */onfiremodelModelprototype {}; /** * Returns a promise that is resolved to this instance when the data has been loaded. * * @return {!Promise<!onfire.model.Model,!Error>} A promise resolves to this instance when the data * has been loaded. */onfiremodelModelprototype {};
Collection
Offers all the Model properties with the following additions and changes.
/** * Base class for collections that live in Firebase. If collection members are not primitives, they * are lazily loaded -- only when requested. * * @param * @param {!function(new:onfire.model.Model, !onfire.Ref, number=)=} opt_memberCtor The model * constructor to use for instances of collection members. If the members are primitives, * this should not be supplied. * @constructor * @extends */onfiremodel {}; /** * Determines whether the collection already has an entry for the provided key. * * @param * @return * @throws */onfiremodelCollectionprototype {}; /** * Returns the number of values in the collection. * * @return * @throws */onfiremodelCollectionprototype {}; /** * Asynchronously creates a model instance and adds it as a member of the collection, with an * automatically generated key. * * @param {!Object<string,Firebase.Value>=} opt_values An object containing the property/value pairs * to initialize the new object with. * @return {!Promise<!onfire.model.Model,!Error>} A promise that resolves to a model instance, or is * rejected with an error. * @throws */onfiremodelCollectionprototype {}; /** * Asynchronously retrieves a model instance that represents a member of the collection. Throws an * exception if the key does not exist. * * @param * @return {!Promise<!onfire.model.Model,!Error>} A promise that resolves to a model instance, or is * rejected with an error. * @throws */onfiremodelCollectionprototype {}; /** * Asynchronously retrieves an existing item by its key, or creates it if it does not yet exist, and * adds it to the collection. * * @param * @param {!Object<string,Firebase.Value>=} values A set of property/value pairs to assign if * created. If null, don't set any values. The object will come into existence only when a * value is set and committed to the database. * @return {!Promise<!onfire.model.Model,!Error>} A promise that resolves to a model instance, or is * rejected with an error. * @throws */onfiremodelCollectionprototype {}; /** * Calls a callback for each member of the collection. Returns a promise that is resolved once all * the callbacks have been invoked, and any promises returned by callbacks have themselves been * resolved. * The callback function should accept a primitive value or a model instance, according to the type * of members in the collection. It does not need to return anything, but if it returns a promise, * the main return value of this method (a promise) will depend on it. * * @param {!function((!onfire.model.Model|Firebase.Value), string=):(!Promise|undefined)} callback * @return * @throws */onfiremodelCollectionprototype {}; /** * Synchronously retrieves the value associated with a key. If the collection members are not * primitive values, a model instance will be returned, in which case .whenLoaded() should be called * on the returned model in order to know when it is ready to use. Consider using the asynchronous * .fetch() method instead. * Throws an exception if the key does not have a value in the underlying data. * * @override * @param * @return * @throws */onfiremodelCollectionprototype {}; /** * Synchronously retrieves the primitive value associated with a key. If the value is an object, it * is returned unwrapped, i.e. not as a model instance. * Throws an exception if the key does not have a value in the underlying data. * * @param * @return * @throws */onfiremodelCollectionprototype {}; /** * Synchronously retrieves the value associated with a key and wraps it in a model instance. Make * sure to call .whenLoaded() on the returned model in order to know when it is ready to use. * Consider using the asynchronous .fetch() method instead. * Throws an exception if the key does not have a value in the underlying data. * * @param * @return * @throws */onfiremodelCollectionprototype {}; /** * Returns an array of the keys of members in the collection. * * @return * @throws */onfiremodelCollectionprototype {}; /** * Register the callback function that will be called whenever a child is added. To deregister * an existing callback, just pass null as the callback argument. * * @param {function(string)|null} callback A function that will be called with the key of the new * child. */onfiremodelCollectionprototype {}; /** * Register the callback function that will be called whenever a child is removed. To deregister * an existing callback, just pass null as the callback argument. * * @param {function(string)|null} callback A function that will be called with the key of the * removed child. */onfiremodelCollectionprototype {}; /** * Asynchronously removes the specified member of the collection. The promise is not rejected if the * member is not present. * * @param * @return {!Promise<null,!Error>} A promise that resolves when the operation is complete, or is * rejected with an error. * @throws */onfiremodelCollectionprototype {}; /** * Registers the desire to change the primitive value associated with a key. The value will be * committed only when .save() is called. Returns a reference to the current model to allow * chaining, e.g., * person.set('firstName', 'John').set('lastName', 'Smith').save() * Throws an error if the key is not specified in the schema and does not already have a value in * the underlying data. * * @override return type. * @param * @param * @return * @throws */onfiremodelCollectionprototype {};
Error Messages
/** * Thrown when the argument provided to the model constructor is not an onfire.Ref instance. * * @type */onfiremodelErrorINVALID_REF; /** * Thrown when a property or method is accessed before the model has finished loading, and the * result would be incorrect or unavailable. * * @type */onfiremodelErrorNOT_LOADED; /** * Thrown when an attempt is made to get or set the value of a key that is not specified in the * schema and does not exist in the underlying data. * * @type */onfiremodelErrorNO_SUCH_KEY; /** * Thrown when an attempt is made to obtain a model to represent a primitive value, e.g. calling * .getModel('abc') when .abc has an integer value according to the schema or in reality. * Another example is calling a collection's .create(), .fetch() or fetchOrCreate() methods * when the collection is a colection of primitive values and not models. * * @type */onfiremodelErrorNOT_A_MODEL; /** * Thrown when an attempt is made to assign a value to a key that represents a model. Any * changes need to be assigned via the model itself. In order to add a model instance to a * collection use .create() or .fetchOrCreate() instead of .set(). * * @type */onfiremodelErrorNOT_A_PRIMITIVE;
How to use OnFire in your project
Browser based projects
- Load
onfire.min.js
into your project, after the line that references Firebase. For example:
<script src="./bower_components/onfire/dist/onfire.min.js"></script>
- Optional:
bower install --save isabo/onfire
Node.js based projects
npm install --save onfire
var onfire = require('onfire');
How to set up the development environment
This is not needed if you just want to use OnFire in your project.
Pre-requisites
- Java - used by Google Closure Compiler to optimise and minify Javascript.
- NPM - used to manage dependencies. This is usually installed together with Node.js.
Dependencies
- Install the dependencies locally:
npm install
- Update the dependencies to the most recent compatible versions:
npm update
How To Run the Test Suite
npm test
How to Build the Distributables
npm run build