Query Builder
Minorm uses extended version of squel Query Builder. You can check their docs to have more understanding of all functionality in it.
SELECT queries
To start a query you can use any of two options:
const query = repo.startQuery('post')
or equally same version from a Manager:
const query = manager
.startQuery()
.select()
.field('post.*')
.from('posts', 'post')
Both are equal to the following SQL (to test purposes you can call toString()
on query builder instance):
SELECT post.* FROM posts post
Adding conditions to WHERE part
To add a condition you can use squel where('some = ?', value)
functions or you can use criteria()
function provided by minorm. For example lets add condition that status is either of ACTIVE or DRAFT, and creator_id is 5.
query.criteria({
'post.status': {
$in: ['ACTIVE', 'DRAFT'],
},
'post.creator_id': 5,
})
Which in result will have following SQL:
SELECT post.* FROM posts post WHERE (post.status IN (?, ?)) AND (post.creator_id = ?)
Using JOIN clauses
To add INNER JOIN
you can use squel join('tableToJoin', 'joinedTableAlias', 'alias.someField = joinedTableAlias.id')
or you can minorm helper include('alias', 'someField')
which is the equivalent. Minorm know all relations in your database so it can use it to help you fetch information.
For example let's add reference to our post creator:
query.field('creator.*').include('post', 'creator_id', 'creator')
The third parameter is optional and by default it's uses your column name with removed _id
part. So we can change it to:
query.field('creator.*').include('post', 'creator_id')
This is an equivalent of squel:
query
.field('creator.*')
.join('users', 'creator', 'post.creator_id = creator.id')
All examples will lead to the following SQL:
SELECT post.*, creator.* FROM posts post INNER JOIN users creator ON (post.creator_id = creator.id) WHERE (post.status IN (?, ?)) AND (post.creator_id = ?)
In case that you need LEFT JOIN
you can use tryInclude()
helper with is equivalent of left_join()
.
For example creator may have an avatar and if it's exists in database we need to receive it. Let's add it to our query:
query.field('avatar.*').tryInclude('creator', 'avatar_id')
tryInclude()
also can receive third parameter to make an alias
This is an equivalent of squel:
query
.field('avatar.*')
.left_join('avatars', 'avatar', 'creator.avatar_id = avatar.id')
All examples will lead to the following SQL:
SELECT post.*, creator.*
FROM posts post
INNER JOIN users creator ON (post.creator_id = creator.id)
LEFT JOIN avatars avatar ON (creator.avatar_id = avatar.id)
WHERE (post.status IN (?, ?)) AND (post.creator_id = ?)
Execution
If you have simple query without JOIN clauses you can use execute()
method which will execute query and return result.
For example:
const posts = await repo
.startQuery('post')
.limit(10)
.offset(30)
.execute()
for (const post of posts) {
//Do something with post
}
In case of complex query with includes you can use some sort of magic to receive data in hierarchy format. For example let's execute our example from previous steps:
const postsWithCreatorsAndAvatars = await query
.where('id = ?', 5)
.getMapper()
.fetch()
for (const post of postsWithCreatorsAndAvatars) {
expect(post).toMatchObject({
id: 5,
title: 'foo',
creator_id: 10,
creator: {
id: 10,
login: 'some',
avatar_id: 20,
avatar: {
// OR null if there's no avatar set
id: 20,
path: 'some',
},
},
})
}
So as you can see minorm follows the way that you used to describe your relations in a query.
If you don't need to use this data in hierarchy way you can also use this mechanism:
const posts = await query.execute(true)
for (const postRow of posts) {
const { post, creator, avatar } = postRow
expect(post).toMatchObject({
id: 5,
title: 'foo',
creator_id: 10,
})
expect(creator).toMatchObject({
id: 10,
login: 'some',
avatar_id: 20,
})
expect(avatar).toMatchObject({
id: 20,
path: 'some',
})
}
Please note that in this case when there's no any record from LEFT JOIN
it will return object with all columns with null
values. So in this example it's wrong to check if (avatar !== null)
because it will be always an object.
Please also note that if you have some calculations in your query it will result as a object with key ''
. So for example you added calculation for count. To access it you will need to use:
const { count } = postRow['']
This is limitation of mysql2