FireORM for Web - is a tiny wrapper on top of web firebase package, based on fireorm codebase that makes life easier when dealing with a Firestore database. FireORM-Web tries to ease the development of apps that rely on Firestore at the database layer by abstracting the access layer providing a familiar repository pattern. It basically helps us not worry about Firestore details and focus on what matters: adding cool new features!
- Installation
- Usage
- Reading Data
- Manage Data
- SubCollections
- Transactions
- Batches
- Custom Repositories
- Validation
- Transformer
- Utils
- Development
- Contributing
- License
- Install the npm package:
npm install fireorm-web --save`
- You need to install
reflect-metadata
shim:
npm install reflect-metadata --save
and import it somewhere in the global place of your app (for example in app.ts
):
import "reflect-metadata";
- TypeScript configuration
Also, make sure you are using TypeScript version 4.5 or higher,
and you have enabled the following settings in tsconfig.json
:
{
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
- Initialize your Firestore application:
import {initializeApp} from 'firebase/app';
import {getFirestore} from 'firebase/firestore';
import {initialize} from 'fireorm-web';
const firebaseConfig = {
apiKey: process.env.API_KEY,
authDomain: process.env.AUTH_DOMAIN,
projectId: process.env.PROJECT_ID,
storageBucket: process.env.STORAGE_BUCKET,
messagingSenderId: process.env.SENDER_ID,
appId: process.env.APP_ID,
};
// - or -
// const firebaseConfig = require('/path_to_json/firestore.creds.json');
const firebaseApp = initializeApp(firebaseConfig);
const firebaseFirestore = getFirestore(firebaseApp);
initialize(firebaseFirestore);
- Create your Firestore models
import { Collection } from 'fireorm-web';
@Collection()
class Todo {
public _id: string;
public text: string;
public done: Boolean;
}
- And your domain logic looks like this
import { getRepository } from 'fireorm-web';
const todoRepository = getRepository(Todo);
const todo = new Todo();
todo.text = "Check FireORM-Web GitHub repository";
todo.done = false;
// Create record
const todoDocument = await todoRepository.create(todo);
// Read record
const mySuperTodoDocument = await todoRepository.findById(todoDocument._id);
// Update record
await todoRepository.update(mySuperTodoDocument);
// Delete record
await todoRepository.delete(mySuperTodoDocument._id);
Firestore has support for complex data types such as GeoPoint and Reference. Full handling of complex data types is being handled in this issue in fireorm. Temporarily, fireorm and fireorm-web will export Class Transformer's @Type decorator. It receives a lamda where you return the type you want to cast to.
FireORM-Web is just a library to simplify the way we communicate with web firestore. It does not implement the underlying communication with the database (it resorts to official sdk's for that, such as firebase).
According to it's homepage, Firestore is a fast, fully managed, serverless, cloud-native NoSQL document database that simplifies storing, syncing, and querying data for your mobile, web, and IoT apps at global scale.
In Firestore, data is stored in Documents which are organized into Collections that may also contain SubCollections.
To take full advantage of what fireorm-web have to offer, is recommended that you are familiarized with Firestore Data Model.
Models in fireorm-web are just a way to specify the shape that our data (or Documents) will have. Models are represented with JavaScript Classes!
For example, let's pretend that we want to store information about Rock Bands:the band name, formation year and array of genres. Our Model would look like this:
class Band {
public _id: string;
public name: string;
public formationYear: number;
public genres: string[];
}
Wait, I only mentioned name, formationYear and genres in my original specification, so why does the model have a string property called _id
? Because of the way the data is stored in Firestore, it's required that every model contain a string property called _id. If you create a model without the _id
property (or with another data type such as Number or Symbol) fireorm-web won't work correctly.
Great, we have a model, but how can we ‘take’ our model and ‘store’ it the database? In Firestore we store data in Documents and they are organized into Collections. To represent a Collection in our code, we'll use a fairly new JavaScript feature which Typescript lets us use super easy: Decorators.
To declare Collections we can just decorate our model class with fireorm-web Collection
decorator and each instance of the model would act as a Firestore Document.
import { Collection } from 'fireorm-web';
@Collection()
class Band {
public _id: string;
public name: string;
public formationYear: number;
public genres: string[];
}
See how we're importing the Collection
decorator from fireorm-web and we're decorating our Band class with it. Internally, fireorm-web will treat each instance of Band as a Firestore Document.
Wait, Firestore Collections must have a name. What will be the name of that collection? By default, fireorm-web will name the collections with the plural form of the Model name in lower case, in this case bands
. If you want you use your own name, you can pass a string as the first parameter of the Decorator.
@Collection('RockBands')
One of my goals when developing this library was to create a way to use the Repository Pattern with Firestore as easily as possible. We have our models, we have our collections, but how are we supposed to make CRUD operations? That’s what Repositories are for.
In general, repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer (source).
Repositories provide the necessary methods to create, retrieve, update and delete documents from our Firestore collections. To create a repository from a collection we can just call getRepository
method.
import { Collection, getRepository } from 'fireorm-web';
@Collection()
class Band {
public _id: string;
public name: string;
public formationYear: number;
public genres: string[];
}
const bandRepository = getRepository(Band);
The variable bandRepository
contains all the methods to interact with our band
. You can retrieve, create, update, delete and do complex queries over our Bands collection!
This is where fun starts! Once we have initialized fireorm-web in our application we can start using it.
We'll continue working with the Band's collection we defined in Core Concept's section.
FireORM-Web Repositories have the method findById
which you can use to retrieve documents by its id.
Let's imagine we have a Document in our Bands Collection in firestore with an id red-hot-chilli-peppers
. To retrieve it we only have to use the handy findById method in our repository.
import { Collection, getRepository } from 'fireorm-web';
@Collection()
class Band {
public _id: string;
public name: string;
public formationYear: number;
public genres: string[];
}
const bandRepository = getRepository(Band);
const band = await bandRepository.findById('red-hot-chilli-peppers');
Now the variable band is an instance of our Band model that contains the information about the band.
If you need to listen for updates document in realtime, you can use the "findByIdAndListen" method of the repository. In the arguments, you can specify callback functions that will be called when a data change detect or error.
function renderBandIten(band) {
// ... some render logic
}
// find document and start listen
const unsubscribe = getRepository(Band)
.findByIdAndListen('red-hot-chilli-peppers', renderBandIten, console.error);
// stop listen
unsubscribe();
This approach will be convenient when used in a single page application.
Only being able to find documents by id is a bit limiting, that's why fireorm-web repositories provide a lot of helper functions to ease the filtering of data in queries. These are whereEqualTo
, whereGreaterThan
, whereGreaterOrEqualTha
, whereLessThan
, whereLessOrEqualThan
, whereArrayContains
, whereIn
and whereArrayContainsAny
methods. We can pipe as many methods as we need to perform complex queries, as long as we don’t forget to call the find
method at the end.
// Bands formed from 1990 onwards
await bandRepository
.whereGreaterOrEqualThan('formationYear', 1990)
.find();
// Bands whose name is Porcupine Tree
await bandRepository
.whereEqualTo('name', 'Porcupine Tree')
.find();
// Bands formed after 1985 and that play Progressive Rock
await bandRepository
.whereGreaterThan('formationYear', 1985)
.whereArrayContains('genres', 'progressive-rock')
.find();
All the *Where methods have a similar api, where the first parameter is a string that represents the field that we want to search for and the second one is the value that we want to compare to (which can be any JavaScript primitive type). FireORM-Web also provide an alternative API to make it more type safe; the first parameter can also accept a lamda function where it's first parameter is the type of the model of the repository.
// This example is exactly the same than the last one, but using the alternative API.
// Bands formed from 1990 onwards
await bandRepository
.whereGreaterOrEqualThan((band) => band.formationYear, 1990)
.find();
// Bands whose name is Porcupine Tree
await bandRepository
.whereEqualTo((band) => band.name, 'Porcupine Tree')
.find();
// Bands formed after 1985 and that play Progressive Rock
await bandRepository
.whereGreaterThan((band) => band.formationYear, 1985)
.whereArrayContains((band) => band.genres, 'progressive-rock')
.find();
Similar to findByIdAndListen
, you can get data and listen for changes in real time. To do this, use the findAndListen
method.
function renderBandList(bands) {
// ... some render logic
}
// run querie and start listin
const unsubscribe = bandRepository.findAndListen(renderBandList, console.error);
// stop listen
unsubscribe();
Sometimes it is convenient to automatically process the received data. You can use the pipe
method for this, passing any number of callbacks to it as arguments. This way you can transfer the filter, map and other data processing to the client side.
function filterBandsByYear(from: number, to: number) {
return (items) => items.filter((item) => item.formationYear > from && item.formationYear < to);
}
function mapNameToLowerCase() {
return (items) => items.map((item) => {
item.name = item.name.toLowerCase();
return item;
});
}
await bandRepository
.pipe(
filterBandsByYear(1985, 1990),
mapNameToLowerCase(),
)
.find();
We can use the document reference as the value in any of the helpers function described above.
// Fake DocumentReference
class FirestoreDocumentReference {
public _id: string;
public _path: string;
}
@Collection()
class BandWithReference {
public _id: string;
public name: string;
public formationYear: number;
public genres: string[];
@Type(() => FirestoreDocumentReference)
public relatedBand?: FirestoreDocumentReference;
}
const pt = new Band();
pt._id = 'porcupine-tree';
pt.name = 'Porcupine Tree';
pt.formationYear = 1987;
pt.genres = ['psychedelic-rock', 'progressive-rock', 'progressive-metal'];
await bandRepository.create(pt);
// Filter documents by a doc reference
const band1 = await bandRepository.whereEqualTo((item) => item.relatedBand, ptRef).find();
// Can also use the string api of the complex query
await band2 = bandRepository.whereEqualTo('relatedBand', ptRef).find();
FireORM-Web repositories also provide functions to order documents and limit the quantity of documents that we will retrieve. These are orderByAscending
, orderByDescending
, limit
and offset
. Please be aware that you can only use one orderBy, one offset and one limit per query.
// Bands formed from 1990 onwards or
await bandRepository
.whereGreaterOrEqualThan((band) => band.formationYear, 1990)
.orderByAscending('name')
.find();
// Top 10 bands whose formationYear is 1987 in ascending order by formationYear (using the alternative api)
await bandRepository
.whereEqualTo((band) => band.formationYear, 1987)
.orderByAscending((band) => band.formationYear)
.limit(10)
.find();
// Top 3 bands formed after 1985 and that play Progressive Rock, skip first
await bandRepository
.whereGreaterThan((band) => band.formationYear, 1985)
.whereArrayContains((band) => band.genres, 'progressive-rock')
.offset(1)
.limit(3)
.find();
Be careful offset - not recommended to google
Please be aware that fireorm-web cannot circumvent Firestore query limitations, we still have to create indexes if we want to create queries that involve more than one field.
Now that we know how to retrieve documents from Firestore, it's time to finish the rest of our CRUD operations.
FireORM-Web repositories provide a create
method to save new documents into Firestore. If at the moment of calling the create
method you don't provide an _id
, an autogenerated id will be used.
import { Collection, getRepository } from 'fireorm-web';
import Band from './wherever-our-models-are';
const bandRepository = getRepository(Band);
const rush = new Band();
rush.name = 'Rush';
rush.formationYear = 1968;
rush.genres = ['progressive-rock', 'hard-rock', 'heavy-metal'];
await bandRepository.create(rush);
Not all information we store in Firestore will remain unedited forever, so we need a way to edit the data we already have. No worries, FireORM-Web repositories provide an update
method to update the data we already have stored in our documents.
import { Collection, getRepository } from 'fireorm-web';
import Band from './wherever-our-models-are';
const bandRepository = getRepository(Band);
const rush = await bandRepository.findById('rush');
rush.name = 'rush';
await bandRepository.update(rush);
You can also specify a strategy for updating documents by passing options as the second argument.
await bandRepository.update(rush, {merge: true});
By now you know the drill. FireORM-Web repositories provide an delete
method to delete documents.
import { Collection, getRepository } from 'fireorm-web';
import Band from './wherever-our-models-are';
const bandRepository = getRepository(Band);
const rush = await bandRepository.findById('rush');
await bandRepository.delete(rush);
In the core concepts we learned that in Firestore we store data in Documents and they are organized into Collections. But in Firestore you can also add collections inside documents, they are called Subcollections.
To represent a SubCollection in our code, we'll make use of fireorm-web SubCollection
decorator.
For example, let’s create an Albums model and add it as a Subcollection of Band
import { Collection, SubCollection, Repository } from 'fireorm-web';
class Album {
public _id: string;
public name: string;
public year: number;
}
@Collection()
class Band {
public _id: string;
public name: string;
public formationYear: number;
public genres: string[];
@SubCollection(Album)
public albums?: Repository<Album>;
}
In this case we created a model called Album to store each album information: a unique id (remember, models must have an id by design!), name and year. Once the model is created, we add a albums property to the existing Band model and decorate it using fireorm-web SubCollection
decorator passing Album model as the first parameter.
Notice how we didn't add the Collection
Decorator to the Album class (we wanted it to be a SubCollection, not a Collection!) but added the SubCollection
inside Band model.
By default, fireorm-web will name the SubCollections with the plural form of the model name that was passed as first parameter (in this case, it will be named Albums
). If you want you use your own name, you can pass an string as the second parameter of the SubCollection Decorator.
@SubCollection(Album, 'TheAlbums')
FireORM-Web has support for nested subcollections (subcollections inside subcollections). To represent a nested subcollection we only have to use the SubCollection
decorator inside a model that is itself a subcollection of another model.
import { Collection, SubCollection, Repository } from 'fireorm-web';
class Image {
public _id: string;
public url: string;
}
class Album {
public _id: string;
public name: string;
public year: number;
@SubCollection(Image)
public images?: Repository<Image>;
}
@Collection()
class Band {
public _id: string;
public name: string;
public formationYear: number;
public genres: Array<string>;
@SubCollection(Album)
public albums?: Repository<Album>;
}
In this example we have a Band model that has a field called albums
that represents the Albums subcollection that itself has a field called images
that represents the Images subcollection (Band -> Album -> Image).
Please note that firestore supports up to 100 nested subcollections.
FireORM-Web also has support for Firestore Transactions inside a single repository and between multiple repositories.
FireORM-Web repositories have a runTransaction
method. It receives a lamda function where the first parameter corresponds to a FirestoreTransactionRepository
. The FirestoreTransactionRepository
is an special type of repository that has methods to create, retrieve, update and delete documents inside a transaction.
import { getRepository, Collection } from 'fireorm-web';
import Band from './wherever-our-models-are';
const bandRepository = getRepository(Band);
const dt = new Band();
dt._id = 'dream-theater';
dt.name = 'DreamTheater';
dt.formationYear = 1985;
bandRepository.runTransaction(async (tran) => {
await tran.create(dt);
});
FireORM-Web exports a runTransaction
method that can be used to create transactions with one or multiple repositories. It receives a lamda function where the first parameter corresponds to a FirestoreTransactionRepository
class. This class exposes a getRepository
method that receives an Model class and returns a FirestoreTransactionRepository
of the given entity and can be used to create, retrieve, update and delete documents inside a transaction.
import { runTransaction } from 'fireorm-web';
import { Band, Album } from './wherever-our-models-are';
const band = new Band();
band._id = 'dream-theater';
band.name = 'DreamTheater';
band.formationYear = 1985;
const album1 = new Album();
album1.name = 'When Dream and Day Unite';
album1.releaseDate = new Date('1989-03-06T00:00:00.000Z');
album1.bandId = band._id;
const album2 = new Album();
album2.name = 'Images and Words';
album2.releaseDate = new Date('1992-07-07T00:00:00.000Z');
album2.bandId = band._id;
await runTransaction(async (tran) => {
const bandTranRepository = tran.getRepository(Band);
const albumTranRepository = tran.getRepository(Album);
await bandTranRepository.create(band);
await albumTranRepository.create(album1);
await albumTranRepository.create(album2);
});
If you need to return data from transactions, runTransaction
receives a type parameter of the output value of your transaction.
import { runTransaction } from 'fireorm-web';
import { Band } from './wherever-our-models-are';
const band = new Band();
band.id = 'dream-theater';
band.name = 'DreamTheater';
band.formationYear = 1985;
await runTransaction<Band>(async (tran) => {
const bandTranRepository = tran.getRepository(Band);
const albumTranRepository = tran.getRepository(Album);
return bandTranRepository.create(band);
});
If we create an entity inside a transactions, all of its subcollections will be automatically be a FirestoreTransactionRepository
that means that all of the operations done to subcollections will also be done inside transactions. Once the transaction is finished fireorm-web will automatically change the FirestoreTransactionRepository
for a normal FirestoreRepository
in case you need to reuse the entity.
import { runTransaction } from 'fireorm-web';
import { Band, Album } from './wherever-our-models-are';
const band = new Band();
band._id = 'tame-impala';
band.name = 'Tame Impala';
band.formationYear = 2007;
const albums = [
{
_id: 'currents',
name: 'Currents',
releaseDate: new Date('2015-07-17T00:00:00.000Z'),
},
{
_id: 'slow-rush',
name: 'The Slow Rush',
releaseDate: new Date('2020-02-14T00:00:00.000Z'),
},
];
await runTransaction<Band>(async (tran) => {
const bandTranRepository = tran.getRepository(Band);
// Create the band inside transaction.
// Band contains a subcollection of Albums in the field albums, so when the band is created it will contain an albums field with FirestoreTransactionRepository<Album> type.
const createdBand = await bandTranRepository.create(band);
// Once the band is created, save the albums
for (const album of albums) {
await createdBand.albums.create(album);
}
// Outside of the transaction, albums will be a FirestoreRepository<Album>
return createdBand;
});
Please be aware that Firestore has many limitations when working with transactions. You can learn more here. The most notable ones are that inside Transactions all the read operations must be done first (i.e. if you need to fetch some documents from firestore and edit it inside a transaction, you must fetch everything you need before doing creating/updating/deleting any document). Also, transactions cannot contain any limit
, offset
or orderBy
clauses.
FireORM-Web also has support for Firestore's Batched Writes.
FireORM-Web repositories have a createBatch
method that returns a FirestoreBatchRepository
. The FirestoreBatchRepository
is an special type of repository that has methods to create, update and delete documents inside a batch. After adding all the operations that we want to run to the batch, we have to call the commit
method to execute them.
import { getRepository, Collection } from 'fireorm-web';
import Band from './wherever-our-models-are';
const bandRepository = getRepository(Band);
const dt = new Band();
dt._id = 'dream-theater';
dt.name = 'DreamTheater';
dt.formationYear = 1985;
const batch = bandRepository.createBatch();
batch.create(dt);
await batch.commit();
FireORM-Web exports a createBatch
method that can be used to create batches with one or multiple repositories. It receives a lamda function where the first parameter corresponds to a FirestoreBatchStorage
class. This class exposes a getRepository
method that receives an Model class and returns a FirestoreBatchRepository
of the given entity and can be used to create, update and delete documents. Once all operations are defined, we have to call the commit
method of our FirestoreBatchRepository
to commit all the operations.
import { createBatch } from 'fireorm-web';
import { Band, Album } from './wherever-our-models-are';
const band = new Band();
band._id = 'dream-theater';
band.name = 'DreamTheater';
band.formationYear = 1985;
const album1 = new Album();
album1.name = 'When Dream and Day Unite';
album1.releaseDate = new Date('1989-03-06T00:00:00.000Z');
album1.bandId = band._id;
const album2 = new Album();
album2.name = 'Images and Words';
album2.releaseDate = new Date('1992-07-07T00:00:00.000Z');
album2.bandId = band._id;
const batch = createBatch();
const bandBatchRepository = batch.getRepository(Band);
const albumBatchRepository = batch.getRepository(Album);
bandBatchRepository.create(band);
albumBatchRepository.create(album1);
albumBatchRepository.create(album2);
await batch.commit();
FireORM-Web exports a createBatch
method that can be used to create batches with one or multiple repositories. It receives a lamda function where the first parameter corresponds to a FirestoreBatchStorage
class. This class exposes a getRepository
method that receives an Model class and returns a FirestoreBatchRepository
of the given entity and can be used to create, update and delete documents. Once all operations are defined, we have to call the commit
method of our FirestoreBatchRepository
to commit all the operations.
import Band from './wherever-our-models-are';
import Album from './wherever-our-models-are';
const bandRepository = getRepository(Band);
const band = bandRepository.findById('opeth');
// Initialize subcollection documents
const firstAlbum = new Album();
firstAlbum._id = 'blackwater-park';
firstAlbum.name = 'Blackwater Park';
firstAlbum.releaseDate = new Date('2001-12-03T00:00:00.000Z');
const secondAlbum = new Album();
secondAlbum._id = 'deliverance';
secondAlbum.name = 'Deliverance';
secondAlbum.releaseDate = new Date('2002-11-12T00:00:00.000Z');
// Create a batch for the subcollection
const albumsBatch = band.albums.createBatch();
// Add the subcollection entities
albumsBatch.create(firstAlbum);
albumsBatch.create(secondAlbum);
// Commit transaction
await albumsBatch.commit();
Please be aware that Firestore has many limitations when working with BatchedWrites. You can learn more here.
By default, fireorm-web repositories have methods to create, read, update and delete documents, but what if we want to add extra data access logic? FireORM-Web supports Custom Repositories. A Custom Repository is a class that extends FirestoreRepository(where T is a model) and is decorated with fireorm-web CustomRepository
decorator.
import { FirestoreRepository, CustomRepository, getRepository } from 'fireorm-web';
import Band from './wherever-our-models-are';
@CustomRepository(Band)
class CustomBandRepository extends FirestoreRepository<Band> {
async getProgressiveRockBands(): Promise<Band[]> {
return this.whereArrayContains('genres', 'progressive-rock').find();
}
}
const bandRepository = getRepository(Band) as CustomBandRepository;
const bands = await bandRepository.getProgressiveRockBands();
Now, getRepository(Band)
will return the custom repository for Band with the getProgressiveRockBands method. If a model doesn’t have a custom repository, the base repository will be returned. FireORM-Web also provides getCustomRepository
and getBaseRepository
helpers if we don’t want the default behavior.
As you could see in the previous example, we had to cast the repository returned by the getRepository
as the custom repository we wanted to use (CustomBandRepository).
FireORM-Web supports class-validator validation decorators in any collection.
FireORM-Web depend on it explicitly. Enable model validation and config it, you may in initialize
method call.
initialize(
firebaseFirestore,
{
validateModels: true,
validatorOptions: {
skipNullProperties: true,
},
},
);
and add validator
import { Collection } from 'fireorm-web';
import { IsEmail } from 'class-validator';
@Collection()
class Band {
@IsEmail()
public contactEmail: string;
}
Use this in the same way that you would your other collections and it will validate whenever a document is saved or updated.
FireORM-Web supports class-transformer transform decorators in any collection.
FireORM-Web depend on it explicitly. Transformer is always applied and cannot be disabled. Config it, you may in initialize
method call.
initialize(
firebaseFirestore,
{
transformOptions: {
exposeDefaultValues: false,
},
},
);
add class-transformer decorator
import { Collection } from 'fireorm-web';
import { Exclude, Transform, Type } from 'class-transformer';
@Collection()
class User {
@Exclude({toClassOnly: true})
public password: string;
}
Class transformer will be applied when you read or write data. Getters from the model do not get into the handler
You can ask the fireorm-web to ignore the field when reading or writing data. Simply applying a decorator to it.
import { Collection, Ignore } from 'fireorm-web';
@Collection()
class Band {
public _id: string;
@Ignore()
public name: string;
}
Or allows for serialization of properties.
import { Collection, Serialize } from 'fireorm-web';
class Website {
public url: string;
}
@Collection()
class Band {
public _id: string;
@Serialize(Website)
public website: Website;
}
Often you need to be able to quickly search for a record across various text fields or filter by an exact value. To do this, the fireorm-web has Search
and Filter
decorators, as well as special methods searchInData
and filterDataByParams
for processing the collection after it is loaded on the client. Each of the decorators supports a custom handler function.
import { Collection, Search, Filter, searchInData, filterDataByParams, getRepository } from 'fireorm-web';
@Collection()
class User {
public _id: string;
@Search()
public name: string;
@Search()
public address: string;
@Search((search: string | undefined, data: string): boolean => data.indexOf(`+${search}`) !== 1)
public phone: string;
@Filter()
public active: boolean;
}
const users1 = await getRepository(User)
.find()
.filter((item) => searchInData('some_text', item))
.filter((item) => filterDataByParams({field: 'active', value: true}, item));
// or use in pipe
const users2 = await getRepository(User)
.pipe(
(items) => items.filter((item) => searchInData('some_text', item)),
(items) => items.filter((item) => filterDataByParams({field: 'active', value: true}, item)),
)
.find();
Search
and Filter
also supports SubCollections and nested data.
- Clone the project from github:
git clone git@github.com:BoastfulCat/fireorm-web.git
- Install the dependencies:
npm install
This repo uses Conventional Commits as the commit messages convention.
This repo uses Semantic Release to automatically release new versions as soon as they land on master.
Commits must follow Angular's Git Commit Guidelines.
Supported commit types (taken from here):
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing or correcting existing tests
- chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
Have a bug or a feature request? Please search the issues to prevent duplication. If you couldn't find what you were looking for, proceed to open a new one. Pull requests are welcome!
MIT © BoastfulCat. See LICENSE for details.