Skip to content

query building

kapil verma edited this page Jun 30, 2019 · 2 revisions

title: Query Building


Query Building

The query-building part of tabel is a very thin layer over knex.js query builder. If you have used knex.js, you'll feel right at home using tabel. This section contains a list of all query building methods provided by tabel. Before we covering the query building API, we'll have a look at a mechanism called forking.


Forking

Internally, table queues up your query building operations using closures, and applies them on the knex.js query builder lazily. This allows you to "fork" a query chain into several different ones. Example given below:

const {table} = require('orm');

async function getDifferentTypesOfPosts(ids=[]) {
  const postsTable = table('posts').where('id', 'in', ids); // starts a new query chain
  const activePostsTable = postsTable.fork().where('is_active', true);
  const inactivePostsTable = postsTable.fork().where('is_active', false);

  const [posts, activePosts, inactivePosts] = await Promise.all([
    postsTable.all(),
    activePostsTable.all(),
    inactivePostsTable.all()
  ]);

  return {posts, activePosts, inactivePosts};
}

Hope this example is enough to clear up the concept of forking. We'll cover all the query building methods available on table next.


.select

.select(...cols)

Specifies the columns you want to select in your query. Supplied columns will be prefixed with the table's name if they are simple strings without a '.' in them. Example below:

const {table} = require('orm');

const rows = await table('posts').select('id', 'title').all();

.select Can also be used to specify aggregate columns using the raw helper. Example below:

const {table, raw} = require('orm');

const postsTable = table('posts').comments().join().groupBy('posts.id');
// the above code joins the related table 'comments' to 'posts' via the relationship defined
// in the table-definition of 'posts'

const postsWithCommentCounts = await postsTable
  .select('*', raw('count(comments.id) as num_comments'))
  .all()
;
// the above code will translate to:
// select posts.*, count(comments.id) as num_comments ...

.whereFalse

.whereFalse()

Adds a where false clause in your query, which results in 0 rows being scoped, and you get an empty array as the result. Example below:

const posts = await table('posts').whereFalse().all();
console.log(posts.length); // outputs 0

.whereKey

.whereKey(keyCondition)

Adds a where clause on the key column of the table. Works on tables with composite-keys. Accepts either single value or an array of values and applies either a where clause or a where in clause accordingly. Example below:

async function getPostById(id) {
  return await table('posts').whereKey(id).first();
}

async function getPostsByIds(ids=[]) {
  return await table('posts').whereKey(ids).all();
}

async function getRowByCompositeKey({foo_id, bar_id}) {
  return await table('foo_bar').whereKey({foo_id, bar_id}).first();
}

async function getRowsByCompositeKeys(keys=[]) {
  // keys = [{foo_id: ..., bar_id: ...}, {foo_id: ..., bar_id: ...}, ...];
  return await table('foo_bar').whereKey(keys).all();
}

Refer to the table-definitions section to read up on how to set up key columns.


.orWhereKey

.orWhereKey(keyCondition)

Same as .whereKey method, just adds an or where clause instead of a where clause to the query chain, on the table's key columns.


.where

.where(...args)

Adds a where clause to the query chain. Takes arguments in several different formats. Examples below:

.where(conditions={})

const post = await table('posts').where({title: 'foo'}).first();
// adds a "where posts.title = 'foo'" clause to the query

.where(conditions=(() => {}))

const posts = await table('posts')
  .where((q) => {
    q.where('created_at', '>=', startDate);
    q.where('created_at', '<=', endDate);
  })
  .all()
;
// adds a nested where clause to the query

.where(field, val)

const post = await table('posts').where('title', 'foo').first();
// adds a "where posts.title = 'foo'" clause to the query

.where(field, op, val)

const posts = await table('posts').where('created_at', '>', someDate).all();
// adds a "where posts.created_at > someDate" clause to the query
// op can also be 'in', 'not in', 'between', 'not between'

.orWhere

.orWhere(...args)

Same as .where method, just adds an or where clause instead of a where clause to the query chain.


.whereNot

.whereNot(...args)

Same as .where method, just adds a where not clause instead of a where clause to the query chain.


.orWhereNot

.orWhereNot(...args)

Same as .whereNot method, just adds a or where not clause instead of a where not clause to the query chain.


.whereIn

.whereIn(key, values)

Adds a where ... in ... clause to the query chain. Can apply the clause on multiple columns at once. Can handle empty value arrays. Examples below:

.whereIn(key, values=[])

async function getPostsByTitles(titles=[]) {
  return await table('posts').whereIn('titles', titles).all();
}

.whereIn(keys=[], values=[])

async function getPostsByIdAndTities(idTitlesList=[]) {
  // idTitlesList = [{id: '..', title: '..'}, {id: '..', title: '..'}, ...]

  return await table('posts').where(['id', 'title'], idTitlesList).all();
}

.orWhereIn

.orWhereIn(key, values)

Same as .whereIn method, just adds a or where ... in ... clause instead of a where ... in ... clause to the query chain.


.whereNotIn

.whereNotIn(key, values)

Same as .whereIn method, just adds a where ... not in ... clause instead of a where ... in ... clause to the query chain.


.orWhereNotIn

.orWhereNotIn(key, values)

Same as .whereNotIn method, just adds a or where ... not in ... clause instead of a where ... not in ... clause to the query chain.


.whereNull

.whereNull(field)

Adds a where ... is null clause to the query chain. Example below:

async function getPostsWithoutComments() {
  return await table('posts').comments().leftJoin().whereNull('comments.id').all();
  // we left join 'comments' table to 'posts' table via the relation defined in the
  // table-definition of 'posts'. Relation joins covered in detail in their section.
}

.orWhereNull

.orWhereNull(field)

Same as .whereNull method, just adds a or where ... is null instead of a where ... is null clause to the query chain.


.whereNotNull

.whereNotNull(field)

Same as .whereNull method, just adds a where ... is not null instead of a where ... is null clause to the query chain.


.orWhereNotNull

.orWhereNotNull(field)

Same as .whereNotNull method, just adds a or where ... is not null instead of a where ... is not null clause to the query chain.


.whereBetween

.whereBetween(field, [min, max])

Adds a where ... between ... and ... clause to the query chain. Example below:

async function getPostsBetweenDates(minDate, maxDate) {
  return await table('posts').whereBetween('created_at', [minDate, maxDate]).all();
}

.orWhereBetween

.orWhereBetween(field, [min, max])

Same as .whereBetween method, just adds a or where ... between ... and ... instead of a where ... between ... and ... clause to the query chain.


.whereNotBetween

.whereNotBetween(field, [min, max])

Same as .whereBetween method, just adds a where ... not between ... and ... instead of a where ... between ... and ... clause to the query chain.


.orWhereNotBetween

.orWhereNotBetween(field, [min, max])

Same as .whereNotBetween method, just adds a or where ... not between ... and ... instead of a where ... not between ... and ... clause to the query chain.


.whereRaw

.whereRaw(condition, bindings)

Adds a where ... clause to the query chain. Variables can be supplied as bindings which are escaped by knex.js. Example below:

async function getPostsByTitle(title='') {
  return await table('posts')
    .whereRaw('lower(title) like ?', [`%${title.toLowerCase()}%`])
    .all()
  ;
}

.orWhereRaw

.orWhereRaw(condition, bindings)

Same as whereRaw method, just adds a or where ... clause instead of a where ... clause to the query chcain


.offset

.offset(offset)

Adds an offset ... clause to the query chain. Example below:

const posts = await table('posts').orderBy('created_at', 'desc').offset(20).all();

.limit

.limit(limit)

Adds a limit ... clause to the query chain. Example below:

const posts = await table('posts').limit(10).all();

.forPage

.forPage(page, perPage)

Adds a limit ... offset ... clause to the query chain based on page and perPage. If perPage argument is not provided, value from table-definition is used. Example below:

const posts = await table('posts').forPage(2, 25).all();

.orderBy

.orderBy(field, direction)

Adds an order by ... clause to the query chain. Example below:

const posts = await table('posts').orderBy('created_at', 'asc').all();

.orderByRaw

.orderByRaw(sql, bindings)

Adds an order by ... clause to the query chain. More complex sql constructs can be applied using this method on the order by ... clause. Example below:

const {table, raw} = require('orm');

function getPostsOrderedByCommentsCount() {
  return await table('posts')
    .comments()
    .join()
    .select('*', raw('count(comments.id)'))
    .groupBy('posts.id')
    .orderByRaw('count(comments.id)')
    .all()
  ;
}

.groupBy

.groupBy(...cols)

Adds a group by ... clause to the query. Example below:

const posts = await table('posts').author().join().groupBy('users.id');

.groupByRaw

.groupByRaw(sql, bindings)

Adds a group by ... clause to the query chain. More complex sql constructs can be applied using this method on the group by ... clause. Example below:

const posts = await table('posts')
  .select('posts.title', 'users.email', raw(count('posts.id')))
  .author()
  .join()
  .groupBy('users.id with rollup')
;

.having

.having(col, op, val)

Adds a having ... clause to the query.


.havingRaw

.havingRaw(sql, bindings)

Adds a having ... clause to the query chain. More complex sql constructs can be applied using this method on the having ... clause.


.distinct

.distinct()

Adds a distinct clause to the query chain.


.join

.join(tableName, ...args)

Adds a join clause to the query chain. Takes arguments in 2 different ways. Examples below:

.join(tableName, fieldA, op, fieldB)

const posts = await table('posts').join('users', 'posts.author_id', '=', 'users.id').all();

.join(tableName, joiner=((j) => {}))

const posts = await table('posts')
  .comments().join()
  .join('users', (j) => {
    j.on('posts.author_id', '=', 'users.id')
    j.orOn('comments.author_id', '=', 'users.id')
  })
  .all()
;

.leftJoin

.leftJoin(tableName, ...args)

Similar to .join. Just applies a left join instead of a join.


Clone this wiki locally