firestore-eloquent
v1.6.6
Published
A library for creating eloquent models in firestore.
Downloads
11
Readme
firestore-eloquent
A library for creating eloquent models in firestore inspired heavily by Laravel's Eloquent ORM.
Setup
Installation
npm:
npm install firestore-eloquent
yarn:
yarn add firestore-eloquent
Usage
Note: Firebase must be initialized before using these models.
Example:
const app = firebase.initializeApp({
apiKey: "AIza....",
appId: "1:27992087142:web:ce....",
projectId: "my-firebase-project",
authDomain: "YOUR_APP.firebaseapp.com",
databaseURL: "https://YOUR_APP.firebaseio.com",
storageBucket: "YOUR_APP.appspot.com",
messagingSenderId: "123456789",
measurementId: "G-12345",
});
If you have an already existing firestore instance:
import { setFirestore } from 'firestore-eloquent';
const firestore = app.firestore();
setFirestore(firestore);
You can also get the firestore instance that is being used:
import { getFirestore } from 'firestore-eloquent';
// returns firebase.firestore.Firestore
const firestore = getFirestore();
Making Models:
Using and creating models should be similar to using Laravel Eloquent Models.
Notes:
- The Authenticatable class for user models is still under development.
- It's possible to not override the constructor of the class, the library will try to infer the collection name according to the name of the class (ex: model
Post
will have a collection name ofpost
). But this is not recommended because building a production version of an app that is using this library will most likely rename these classes due to minification of the code from webpack or other module bundlers.
import { Model, ModelData } from 'firestore-eloquent';
// Optional
export interface PostData extends ModelData {
title: string;
description: string;
}
export class Post extends Model<PostData> {
type = Post;
constructor(data?: Partial<PostData>) {
super(data);
// explicitly set collection name
this.name = 'posts';
}
protected fillable() {
return ['title', 'description'];
}
}
CRUD Examples:
import { Post } from 'path/to/models';
const post = new Post({
title: 'My Title',
description: 'My Description',
});
// You can also use fill() or forceFill()
post.fill({
title: 'My Title',
description: 'My Description',
});
// create
await post.create(); /* or */ post.create(data);
// update
await post.update(); /* or */ post.update(data);
// delete
await post.delete();
// save
await post.save(); /* or */ post.save(data);
// fetching
await post.all();
// get one
await post.first();
// find one by id
await post.findOne(id);
// Reading data
// get a specific key
console.log(post.get('title')) // My Title
// get all data
console.log(post.getData()) // { title: 'My Title', description: 'My Description' }
// set data
post.set('title', 'My New Title');
await post.save();
Events
Events are also supported.
Example:
export class Post extends Model<PostData> {
type = Post;
constructor(data?: Partial<PostData>) {
super(data);
this.name = 'posts';
}
protected fillable() {
return ['title', 'description'];
}
// register events here
protected booted() {
this.creating((post) => {});
this.created((post) => {});
this.updating((post) => {});
this.updated((post) => {});
this.deleting((post) => {});
this.deleted((post) => {});
this.saving((post) => {});
this.saved((post) => {});
}
}
Relationships
Currently, only hasOne
, hasMany
and belongsTo
are supported.
Example:
export class Post extends Model<PostData> {
type = Post;
constructor(data?: Partial<PostData>) {
super(data);
this.name = 'posts';
}
protected fillable() {
return ['title', 'description'];
}
comments() {
return this.hasMany(Comment);
}
}
export class Comment extends Model<CommentData> {
type = Comment;
constructor(data?: Partial<CommentData>) {
super(data);
this.name = 'comments';
}
protected fillable() {
return ['body'];
}
post() {
return this.belongsTo(Post);
}
}
const post = new Post(data);
await post.save();
// saving
post.comments().save(new Comment({
body: 'My comment',
}));
// creating
const comment = await post.comments().create(data);
// fetching
const comments = await post.comments().getAll();
// loading
await post.load(['comments']);
Collections
Collections extend the Array
class and has several methods added to it. Model.all()
and hasMany
relationships all return Collections of that model. Some of the methods are overriden to improve their functionality such as collection.includes(model)
and collection.indexOf(model)
.
const posts = await new Post().all(); // Collection<Post>
// call methods from `Array`
const post = posts.pop();
post.set('title', 'Another Title');
// pushes the post if it does not exist, otherwise it replaces with it's index
posts.set(post);
// or do this instead
posts.replace(post)
// find by id
const newPost = posts.get(id);
// load relationships of all posts
await posts.load(['comments']);
const comments = posts.map(post => post.get('comments')); // CommentData[]
// turn into a normal `Array`
const array = posts.toArray();
JSON
Calling JSON.stringify
on models will automatically call getData()
on them, this applies to collections as well.
Observers and Listeners
There are wrapper methods available to make use of firestore's onSnapshot method.
import { listen, addListener, removeListener, clearListeners } from 'firestore-eloquent';
// add a listener
const handle = addListener(Post, (posts) => {
console.log(posts) // Post[]
});
// remove a listener
removeListener(Post, handle);
// tell the library to actually start listening to onSnapshot methods
listen(Post)
// remove all registered listeners
clearListeners(Post)
Example in React
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
const handle = addListener(Post, setPosts);
listen(Post);
return () => {
removeListener(Post, handle);
};
}, []);
Contributing
Contributions are welcome! Just fork the project and make a pull request.
License
This library is open-sourced software licensed under the MIT license.