boldr-orm

0.1.7 • Public • Published

boldr-orm

Commitizen friendly styled with prettier

ORM for Boldr on top of ObjectionJS with additional utilities for GraphQL

ObjectionJS documentation: http://vincit.github.io/objection.js/
ObjectionJS Repo: https://github.com/Vincit/objection.js/

Extra Features

Boldr ORM (BORM) adds additional functionality on top of ObjectionJS.

  • Automatically added timestamps
  • Table name generated from model name automatically
  • Soft delete functionality
  • GraphQL helpers

Automatic Timestamps

By default all models are assumed to reference tables with createdAt and updatedAt fields. These fields are managed by Boldr ORM and updated whenever data is added or removed.

To disable time stamps:

Add static addTimestamps = false; on to your model.

Two additional helper methods are included for times when you might not want to modify the timestamp.

modify: updates the updatedAt column of the table to current time (new Date().toISOString()).
dontModify: keeps the current timestamps in place when the query is executed.

Default Table Name

Leave the table name generation to the ORM if you're feeling like it.

class Article extends Model {
    static tableName = 'Article';
    ...
}
 
class Article extends Model {
    ...
}

Soft Delete

To enable soft delete functionality, add static softDelete = true; to the model.

Don't forget your table must contain a deletedAt column, as a nullable timestamp.

Soft delete enabled models, aren't actually removed when the delete method is called. Instead the value of the deletedAt column is filled with the current timestamp. Queries don't return data which have a timestamp in the deletedAt field.

Helper methods implemented for Soft Delete:
delete: archive or delete a row (depending on whether softDelete is true or false)
archive: archive (soft delete) a row (use delete it's the same thing)
withArchived: return all data regardless of whether or not they been "deleted" or archived.
onlyArchived: return only the data which has been deleted with softDelete enabled. restore: restore (unarchive) an archived set of data.
forceDelete: actually delete a row from the database

If you want to use some other column name instead of deletedAt you can do static softDelete = 'deleted_at';

class Post extends Model {
    // Enable soft delete
    static softDelete = true;
}
 
// soft delete
Post.query().where('id', 1).delete();
// restore an archived row
Post.query().where('id', 1).restore();
// get all non-archived posts
Post.query();
// get all posts (including archived / "soft deleted" ones)
Post.query().withArchived();
// retrieve only archived posts
Post.query().onlyArchived();
// completely remove a post from the database
Post.query().forceDelete();

GraphQL Helpers

getDeleteByIdResolver()

returns a resolver for GraphQL delete mutation deleteCategory(id: ID) { DeletedItem } Mutation: { deleteCategory: Category.getDeleteByIdResolver() }

getFindByIdSubResolver()

returns a resolver for finding model by id. It optionally takes a propName argument which denotes the name of the field containing the id. type Store { id: ID!, name: String!, category: Category} Query: { Store: { category: Category.getFindByIdSubResolver() } } Query: { Store: { category: Category.getFindByIdSubResolver('categoryId') } }

save and saveAndFetch

save: inserts a model if the id column does not exist, otherwise updates it.
saveAndFetch: saves the model and then fetches it.

wrapWhere

Wraps the where condition till now into braces
so builder.where('a', 'b').orWhere('c', 'd').wrapWhere().where('e', 'f'); becomes "WHERE (a = 'b' OR c = 'd') AND e = 'f'"

whereByOr(obj)

creates an and (or - or - or) condition

q.where('id', 1).whereByOr({posts: 100, user: 'admin'})
// where `id` = 1 and (`posts` = 100 or `user` = 'admin')

whereByAnd(obj)

creates an or (and - and - and) condition

q.where('id', 1).whereByAnd({posts: 100, user: 'admin'})
// where `id` = 1 or (`posts` = 100 and `user` = 'admin')

find Method

find: find is like where except if only a single argument is given, it treats the argument as an id.

// all three are equivalent
Person.query().find(1);
Person.query().where('id', 1);
Person.query().findById(1);
 
// both are equivalent
Person.query().find('name', 'John');
Person.query().where('name', 'John');

where and find methods on model

Instead of doing Person.query().where() you can do Person.where()
Instead of doing Person.query().find() you can do Person.find()

Easier Relationships

You can define all your relationships in the $relations method.

Methods for defining relations

belongsTo(model, options) hasOne(model, options) hasMany(model, options) hasManyThrough(model, options)

options are totally optional. they can be:

name: name of the relationship (by default name of the model in camelCase)
joinFrom: join field from (by default ModelTableName.camelCasedModelNameId)
joinTo: join field to (by default ModelTableName.id)
filter: apply this filter to the model
through: {
    model: if there is a model for the through table
    table: tableName of the table to join through
    from: join through from
    to: join through to
    filter: filter to apply on the join table
    extra: extra fields to select from the through table
}
class Pet extends Model {
    static $relations() {
     this.hasOne(Pet);
        this.hasMany(Toy, {name: 'toys'});
        this.belongsTo(Person);
        this.hasManyThrough(Pet, {
         name: 'siblings',
            through: {
             table: 'Pet_Siblings',
                from: 'pet_id',
                to: 'sibling_id',
            },
        });
    }
}

Model can be a model object, or an absolute path to a model class. It can also be a relative path if you set the basePath of all models using Model.setBasePath(path)

InputError Class

import {InputError} from 'boldr-orm';
 
async function saveStore(store) {
    if (!store.name) {
        throw new InputError({
            name: 'Name is required',
        });
    }
}
 
// Alternatively instead of importing InputError you can simply throw Model.Error
async function saveStore(store) {
    if (!store.name) {
        throw new Store.Error({
            name: 'Name is required',
        });
    }
}

Readme

Keywords

none

Package Sidebar

Install

npm i boldr-orm

Weekly Downloads

1

Version

0.1.7

License

MIT

Last publish

Collaborators

  • strues