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
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
import { FuseDB, FileAdapter } from "fusedb"
FuseDB.setup({ adapter :
FileAdapter({ path: "/path/to/folder/", database: "test" }) });Install mongo module first
npm install mongodb --saveimport { FuseDB, MongoAdapter } from "fusedb";
FuseDB.setup({
adapter: MongoAdapter({
url : "mongodb://localhost:27017/fusedb",
dbName : "myProject"
})
});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:
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 has a few properties you might find useful
hidden
Hiding your field when sending to view
@Field({ hidden : true })
public password: string;Define custom serialiser when sending to view
@Field({
toJSON : value => moment(value).format("LLLL")
})
public date: Date;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();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()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 groupconst authors
= await Author.find<Author>({active : true})
.sort("name", "desc")
.limit(4)
.skip(2)
.all()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();const author = new Author();
author.name = "john"
await autor.save() const author = await Author.find({name : "john"});
await author.remove()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 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}})class FooBarMin extends Model<FooBarMin> {
@Field() @Validate({min : 3})
public name: string;
}class FooBarMax extends Model<FooBarMax> {
@Field() @Validate({max : 3})
public name: string;
}class FooBarEmail extends Model<FooBarEmail> {
@Field() @Validate({email : true})
public name: string;
}class FooBarRegExp extends Model<FooBarRegExp> {
@Field() @Validate({regExp : /\d{2}/})
public name: string;
}const seasons = {
SUMMER: 'summer',
WINTER: 'winter',
SPRING: 'spring'
}class FooBarEnum extends Model<FooBarEnum> {
@Field() @Validate({enum : seasons})
public season: string;
}class FooBarCustom extends Model<FooBarCustom> {
@Field()
@Validate({fn : value => {
if( value !== "foo") throw new Error("Value should be foo only")
}})
public name: string;
}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;
}