ORM Exports

In this section we will look at all the properties of the orm.exports object from the getting-started section. Let’s take a look at the relevant piece of code again:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const Tabel = require('tabel');
const config = require('./config');

const orm = new Tabel(config);

require('./tables')(orm);

module.exports = orm.exports;
/**
This is what the exports look like:

this.exports = {
orm: this,
table: this.table.bind(this),
trx: this.trx.bind(this),
raw: this.raw.bind(this),
migrator: this.migrator,
cache: this.cache,
knex: this.knex,
scoper: this.scoper,
shape: this.shape
};
**/

Now let’s go over each property of this exports object.


orm

const {orm} = require('orm')

The orm object which orchestrates everything. Can be used in fancy ways to define new tables and relationships on the fly. We are not going to cover that part right now. If you are interested in knowing more about this particular export, read the source.


table

const {table} = require('orm')

The main function which is used to work with database-tables. Has been covered thoroughly in the docs. If you need to revise, just revisit query-building section.


trx

const {trx} = require('orm')

Something which provides a begin transaction, commit on no error, rollback on error functionality. Usage given below:

1
2
3
4
5
6
7
8
trx((t) => {
return Promise.all([
table('posts', t).insert(...),
table('tags', t).insert(...)
]).then(([posts, tags]) => {
return table('post_tag', t).insert(...);
});
});


raw

const {raw} = require('orm')

Use this helper for inserting raw sql into non-*Raw query-building methods. Usage below:

1
table('posts').select('*', raw('count(comments.id) as num_comments')).comments().join().groupBy('posts.id').all();


migrator

You won’t really need to use this anywhere. It is used by the migrations-cli. You can read its code here.


cache

const {cache} = require('orm')

An instance of KRedis. You can use it for sessions, caching, and what not.


knex

const {knex} = require('orm')

An instance of Knex. Not sure what you’d use it for, but it does come in handy at times.


scoper

const {scoper} = require('orm')

scoper is used for conditionally building query-chain on a table. This is specially useful for applying various where-clauses, order-by clauses, even eager-loads on a query-chain, based on dynamic parameters. We’ll try to explain this using an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const {scoper, table} = require('orm');

async function getPosts(params={}) {
const postsScoper = scoper({
search: (t, text) => {
if (isString(text) && text.length > 0) {
return t.applySearchClause(text);
} else {
return t;
}
},

ids: (t, ids=[]) => {
ids = ids.filter((id) => isuuid(id)); // sanitize ids
return t.whereIn('id', ids);
},

only_published: (t, flag) => {
if (flag) {
return t.where('is_published', true);
} else {
return t;
}
}
});

const postsTable = table('posts').eagerLoad('tags').whereNotDeleted();

const scopedTable = postsScoper.apply(postsTable.fork(), params);
// The above line scopes the postsTable based on the supplied params.
// So if params contain a key `ids`, against which it has a list of ids
// the whereIn clause in that particular scope will be applied on the
// table which is supplied to `postsScoper.apply` method call.

const [posts, total] = await Promise.all([
scopedTable.all(),
postsTable.count()
]);

return {posts, total};
}

shape

const {shape} = require('orm')

shape is used to vaidate input data in an async manner. Doesn’t matter if your checks are all synchronous, shape will check them in an async manner. This is very useful for validating data against external data sources. Example below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const {table, shape} = require('orm');

async function createUser(data={}) {
const validation = shape({
username: async (username) => {
if (isString(username) && username.length > 0) {
const existing = await findUserByUsername(username);
return existing ? 'username taken' : null;
} else {
return 'invalid';
}
},

password: (password) => {
return isString(password) && password.length >= 7 ? null : 'invalid';
},

repeat_password: (repeat_password, {password}) => {
return repeat_password === password ? null : 'invalid';
}
});

const errors = await validation.errors(data);
// Errors will be 'null' if all checks pass.
// If any check fails, errors will be an object that contains error messages.
// Validation will also fail for keys in data which are not specified when
// defining a validation

if (errors) {
throw errors;
} else {
return await table('users').insert(data);
}
}


Fin.