Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fuse-box/fusedb

FuseDB - blazing fast ORM with simplicity in mind with love from FuseBox
https://github.com/fuse-box/fusedb

Last synced: about 1 month ago
JSON representation

FuseDB - blazing fast ORM with simplicity in mind with love from FuseBox

Awesome Lists containing this project

README

        

[![Build Status](https://travis-ci.org/fuse-box/fusedb.svg?branch=master)](https://travis-ci.org/fuse-box/fusedb)

# FuseDB

FuseDB is an ORM with traditional ActiveRecord approach, that provides a simple yet powerful API. FuseDB stores data in the filesystem ([nedb](https://github.com/louischatriot/nedb)) or MongoDB. You write your own [adapter](https://github.com/fuse-box/fusedb/blob/master/src/adapters/Adapter.ts) 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](https://github.com/fuse-box/fusedb-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
```js
import { FuseDB, FileAdapter } from "fusedb"
FuseDB.setup({ adapter :
FileAdapter({ path: "/path/to/folder/", database: "test" }) });
```

### MongoDB database
Install mongo module first
```bash
npm install mongodb --save
```

```js
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

```js
import { Field, Model } from "fusedb";

class Author extends Model {
@Field()
public name: string;

@Field()
public books: Book[];
}

class Book extends Model {
@Field()
public name: string;

@Field()
public author: Author;
}
```

`Field` decorator tells fusedb to serialize the field. There are a few reserved methods:

### Creating records

```js
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
```ts
@Field({ hidden : true })
public password: string;
```

#### toJSON
Define custom serialiser when sending to view
```ts
@Field({
toJSON : value => moment(value).format("LLLL")
})
public date: Date;
```

### Finding

First record:

```js
const author = await Author.find({ name: "john" }).first();
```

All records:

```js
const authors = await Author.find({
name : {$in : ["a", "b"]}
}).all();
```

Count:

```js
const num = await Author.find().count();
```

### Query normalization

#### ObjectID
You don't need to convert strings to ObjectID When you using MongoAdapter. FuseDB does it for you.

for example:

```ts
const record = await Foo.findById("5b290c188e9f69ab51c3bd41");
```

It will be applied for `find` method recursively for example

```ts
await Foo.find({
_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

```ts
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

```js
const authors
= await Author.find({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

```js
const books = await Book.find().with("author", Author).all();
```

## Saving

```js
const author = new Author();
author.name = "john"
await autor.save()
```

## Removing
```js
const author = await Author.find({name : "john"});
await author.remove()
```

## Model event hooks

Defining the following hooks will allow you to intercept model events

```ts
export class Foo extends Model {
@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)

```js
import { enableDefaultDecorators } from "fusedb"
enableDefaultDecorators();
```

Now you can start using them in your models, like that:

```js
class FooBarMax extends Model {
@Field() @Validate({max : 3})
public name: string;
}
```

Default validators can assert a custom message

```js
@Validate({nameOftheValidator : { message :"Failed", value : 3}})
```

### Min Symbols Validator

```js
class FooBarMin extends Model {
@Field() @Validate({min : 3})
public name: string;
}
```

### Max Symbols Validator

```js
class FooBarMax extends Model {
@Field() @Validate({max : 3})
public name: string;
}
```

### Email Validator

```js
class FooBarEmail extends Model {
@Field() @Validate({email : true})
public name: string;
}
```

### RegExp Validator

```js
class FooBarRegExp extends Model {
@Field() @Validate({regExp : /\d{2}/})
public name: string;
}
```

### Enum Validator

```js
const seasons = {
SUMMER: 'summer',
WINTER: 'winter',
SPRING: 'spring'
}
```

```js
class FooBarEnum extends Model {
@Field() @Validate({enum : seasons})
public season: string;
}
```

### Function validator

```js
class FooBarCustom extends Model {
@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`
```js
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

```js
class Hello extends Model {
@Field() @Validate({oops : true})
public name: string;
}
```