AdonisJSでDBから件数検索できるgetCountを追加する
AdonisJSでDBから件数検索できるgetCountを追加する
2022/11/24

検索件数が知りたいときに数値を返すgetCountを作成する。

await User.query().getCount();
// => 23

いちおうcount()は存在する。

AdonisのORMにはcount関数が存在するのだが、通常のSQL同様の結果が返ってきて不便

await Database.query().from('users').count('* as total')
// => [ { total: 23 } ]

配列だし、オブジェクトだし、、扱いにくい。

なので、このcount関数をマクロという機能を使い、便利な関数をQueryBuilderに自作しようと思います。

getCountを作成する

providers/AppProvider.tsのbootに以下のコードを追加します。

export default class AppProvider {
  public async boot() {
    const {
      DatabaseQueryBuilder
    } = this.app.container.use('Adonis/Lucid/Database')

    DatabaseQueryBuilder.macro('getCount', async function () {
      const result = await this.count('* as total')
      return BigInt(result[0].total)
    })

		const {
		  ModelQueryBuilder
		} = this.app.container.use('Adonis/Lucid/Database')
		
		ModelQueryBuilder.macro('getCount', async function () {
		  const result = await this.count('* as total')
		  return BigInt(result[0].$extras.total)
		})
  }
}

Database.query('users')...User.query()...の2パターンで実行できるように、DatebaseQueryBuilderとModelQueryBuilderに同じgetCountを作成しています。

これを使おうとするとgetCountなんで関数ねぇよとTypeScriptに怒られるので、型を追加します。
Adonisではcontracts/というディレクトリにすでにいくつかの型が作成されていますので、contracts以下に追加します。

database.tslucid.tsという2ファイルを作成しました。

declare module '@ioc:Adonis/Lucid/Database' {
  interface DatabaseQueryBuilderContract<Result> {
    getCount(): Promise<BigInt>
  }
}
declare module '@ioc:Adonis/Lucid/Orm' {
  interface ModelQueryBuilderContract<
    Model extends LucidModel,
    Result = InstanceType<Model>
  > {
    getCount(): Promise<BigInt>
  }
}

大きな値も扱えるようにBigIntにしています。

これで以下のように実行することができます。

await User.query().getCount()
// もしくは
await Database.query().from('users').getCount()
// => 23n    BigIntにはnがつく

以上になります。

この他にも、AdonisJS v5へのアップグレードで行ったことをまとめました。
なにか役に立てたら幸いです。