Exploring My Favorite AdonisJS Model Query Builder Macros: Tips and Examples

In this lesson, I'll highlight a few of my favorite Model Query Builder Macros that I carry with me from project to project. Have a favorite of your own? Let me know in the comments!

Published
Mar 12, 23
Duration
9m 23s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

🕑 Chapters

00:00 - Intro & Explanation
01:03 - Macro WhereTrue & WhereFalse
02:50 - Macro Any
04:35 - Macro SelectCount
06:10 - Macro SelectIds
07:40 - Macro SelectId
08:23 - Macro SelectIdOrFail
09:00 - Macro Outro


Model Query Builder Macro Provider

import type { ApplicationContract } from '@ioc:Adonis/Core/Application'

/*
|--------------------------------------------------------------------------
| Provider
|--------------------------------------------------------------------------
|
| Your application is not ready when this file is loaded by the framework.
| Hence, the top level imports relying on the IoC container will not work.
| You must import them inside the life-cycle methods defined inside
| the provider class.
|
| @example:
|
| public async ready () {
|   const Database = this.app.container.resolveBinding('Adonis/Lucid/Database')
|   const Event = this.app.container.resolveBinding('Adonis/Core/Event')
|   Event.on('db:query', Database.prettyPrint)
| }
|
*/
export default class ModelQueryBuilderMacroProvider {
  constructor(protected app: ApplicationContract) {}

  public register() {
    // Register your own bindings
  }

  public async boot() {
    // All bindings are ready, feel free to use them
    const { ModelQueryBuilder } = this.app.container.resolveBinding('Adonis/Lucid/Database')

    // adds truthy where statement check on the query builder
    ModelQueryBuilder.macro('whereTrue', function(columnName: string) {
      return this.where(columnName, true)
    })

    // adds falsy where statement check on the query builder
    ModelQueryBuilder.macro('whereFalse', function(columnName: string) {
      return this.where(columnName, false)
    })

    // returns whether any records mached the built query
    ModelQueryBuilder.macro('any', async function() {
      const result = await this.count('* as total')
      return result.at(0).$extras.total > 0
    })

    // returns just the final count result for the query
    ModelQueryBuilder.macro('selectCount', async function() {
      const result = await this.count('* as total')
      return BigInt(result.at(0).$extras.total)
    })

    // returns an array of ids for the built query
    ModelQueryBuilder.macro('selectIds', async function(primaryKey: string = 'id') {
      const results = await this.select(primaryKey)
      return results.map(result => result[primaryKey])
    })

    // returns the first id for the built query
    ModelQueryBuilder.macro('selectId', async function(primaryKey: string = 'id') {
      const result = await this.select(primaryKey).first()
      return result && result[primaryKey]
    })

    // returns the first id for the built query, throws if no records
    ModelQueryBuilder.macro('selectIdOrFail', async function(primaryKey: string = 'id') {
      const result = await this.select(primaryKey).firstOrFail()
      return result[primaryKey]
    })
  }

  public async ready() {
    // App is ready
  }

  public async shutdown() {
    // Cleanup, since app is going down
  }
}
Copied!

Model Query Builder Macro Context

declare module '@ioc:Adonis/Lucid/Orm' {
  interface ModelQueryBuilderContract<
    Model extends LucidModel,
    Result = InstanceType<Model>
    > {
    // macro typescript definitions here
    whereTrue(columnName: string): this
    whereFalse(columnName: string): this
    any(): Promise<boolean>
    selectCount(): Promise<BigInt>
    selectIds(primaryKey?: string): Promise<number[]>
    selectId(primaryKey?: string): Promise<number | undefined>
    selectIdOrFail(primaryKey?: string): Promise<number>
  }
}
Copied!

Join The Discussion! (0 Comments)

Please sign in or sign up for free to join in on the dicussion.

robot comment bubble

Be the first to Comment!