fusedb
fusedb copied to clipboard
FuseDB - blazing fast ORM with simplicity in mind with love from FuseBox
FuseDB
FuseDB is an ORM with traditional ActiveRecord approach, that provides a simple yet powerful API. FuseDB stores data in the filesystem (nedb) or MongoDB. You write your own adapter and implement a different database suppport.
It's perfectly suitable for medium scale databases or Electron apps and takes 5 minutes to dive in.
Checkout this example
Setting up a connection
Everything works by default, and the files will be stored in your home folder e.g /home/user/.fusedb on linux or /Users/user/.fusedb on mac. In order to customise it, do the following
File database
import { FuseDB, FileAdapter } from "fusedb"
FuseDB.setup({ adapter :
FileAdapter({ path: "/path/to/folder/", database: "test" }) });
MongoDB database
Install mongo module first
npm install mongodb --save
import { FuseDB, MongoAdapter } from "fusedb";
FuseDB.setup({
adapter: MongoAdapter({
url : "mongodb://localhost:27017/fusedb",
dbName : "myProject"
})
});
Models
Models contain essential methods to talk to the database, methods like save, find, remove are reserved. Therefore we don't need any "repositories" and connection pools as everything is handled internally
import { Field, Model } from "fusedb";
class Author extends Model<Author> {
@Field()
public name: string;
@Field()
public books: Book[];
}
class Book extends Model<Book> {
@Field()
public name: string;
@Field()
public author: Author;
}
Field decorator tells fusedb to serialize the field. There are a few reserved methods:
Creating records
const john = new Author({ name: "John" });
await john.save();
const book1 = new Book({ name: "book1", author: john });
const book2 = new Book({ name: "book2", author: john });
await book1.save();
await book2.save();
john.books = [book1, book2];
await john.save();
FuseDB will save references as ids and it won't store the entire model
Field decorator
Field decorator has a few properties you might find useful
hidden
Hiding your field when sending to view
@Field({ hidden : true })
public password: string;
toJSON
Define custom serialiser when sending to view
@Field({
toJSON : value => moment(value).format("LLLL")
})
public date: Date;
Finding
First record:
const author = await Author.find<Author>({ name: "john" }).first();
All records:
const authors = await Author.find<Author>({
name : {$in : ["a", "b"]}
}).all();
Count:
const num = await Author.find<Author>().count();
Query normalization
ObjectID
You don't need to convert strings to ObjectID When you using MongoAdapter. FuseDB does it for you.
for example:
const record = await Foo.findById<Foo>("5b290c188e9f69ab51c3bd41");
It will be applied for find method recursively for example
await Foo.find<Foo>({
_id : $in : ["5b290c188e9f69ab51c3bd41", "5b290c188e9f69ab51c3bd42"]
}).first()
Passing real objects to query
Instead of extracting IDs you can pass a real FuseDB Model to the query. For example
const group = await Group.find({name : "admin"}).first();
const adminUsers = await Users.find({group : group}).all(); // will fetch all users that belong to admin group
Chaining query
const authors
= await Author.find<Author>({active : true})
.sort("name", "desc")
.limit(4)
.skip(2)
.all()
Joining references
FuseDB can automatically join referenced fields by making optimised requests (collecting all ids and making additional queries to the database) e.g
const books = await Book.find<Book>().with("author", Author).all();
Saving
const author = new Author();
author.name = "john"
await autor.save()
Removing
const author = await Author.find({name : "john"});
await author.remove()
Model event hooks
Defining the following hooks will allow you to intercept model events
export class Foo extends Model<Foo> {
@Field()
public name: string;
// before updating or creating a record
async onBeforeSave() {}
// after creating or updating a record
async onAfterSave() {}
// before updating a record
async onBeforeUpdate() {}
// after creating a record
async onBeforeCreate() {}
}
Validators
Validators in FuseDb are quite easy to use and implement. The framework offers a few default validators, in order to enable them call a function in your entry point (before you start importing your models)
import { enableDefaultDecorators } from "fusedb"
enableDefaultDecorators();
Now you can start using them in your models, like that:
class FooBarMax extends Model<FooBarMin> {
@Field() @Validate({max : 3})
public name: string;
}
Default validators can assert a custom message
@Validate({nameOftheValidator : { message :"Failed", value : 3}})
Min Symbols Validator
class FooBarMin extends Model<FooBarMin> {
@Field() @Validate({min : 3})
public name: string;
}
Max Symbols Validator
class FooBarMax extends Model<FooBarMax> {
@Field() @Validate({max : 3})
public name: string;
}
Email Validator
class FooBarEmail extends Model<FooBarEmail> {
@Field() @Validate({email : true})
public name: string;
}
RegExp Validator
class FooBarRegExp extends Model<FooBarRegExp> {
@Field() @Validate({regExp : /\d{2}/})
public name: string;
}
Enum Validator
const seasons = {
SUMMER: 'summer',
WINTER: 'winter',
SPRING: 'spring'
}
class FooBarEnum extends Model<FooBarEnum> {
@Field() @Validate({enum : seasons})
public season: string;
}
Function validator
class FooBarCustom extends Model<FooBarCustom> {
@Field()
@Validate({fn : value => {
if( value !== "foo") throw new Error("Value should be foo only")
}})
public name: string;
}
Your own validators
Define a class with Validator
import { Validator, FieldValidator } from "fusedb";
@Validator()
export class OopsValidator implements FieldValidator {
validate(field: string, props: any, value: any) {
throw "Somethign wentWrong"
}
}
A validator with name oops has be registered, how you can use it in your models
class Hello extends Model<Hello> {
@Field() @Validate({oops : true})
public name: string;
}