Skip to content

@forinda/kickjs-drizzle

Drizzle ORM adapter for KickJS with DI integration and query building. Works with any Drizzle driver (PostgreSQL, MySQL, SQLite, LibSQL).

Installation

bash
pnpm add @forinda/kickjs-drizzle drizzle-orm
# Plus your driver:
pnpm add postgres        # PostgreSQL (postgres.js)
pnpm add better-sqlite3  # SQLite
pnpm add @libsql/client  # Turso/LibSQL
pnpm add mysql2          # MySQL

Exports

ExportDescription
DrizzleAdapterAppAdapter that registers the Drizzle db in DI and manages lifecycle
DrizzleQueryAdapterTranslates ParsedQuery into Drizzle-compatible where/orderBy/limit/offset
DRIZZLE_DBSymbol token for DI injection

Types

TypeDescription
DrizzleAdapterOptionsConstructor options for DrizzleAdapter
DrizzleQueryConfigConfig for DrizzleQueryAdapter.build() (table, searchColumns)
DrizzleQueryResultOutput shape with where, orderBy, limit, offset
DrizzleOpsInterface for drizzle-orm operator functions passed to the query adapter

DrizzleAdapter

Options

ts
interface DrizzleAdapterOptions {
  /** Drizzle db instance (return value of drizzle()) */
  db: any
  /** Enable query logging (default: false) */
  logging?: boolean
  /** Cleanup function to close the connection pool on shutdown */
  onShutdown?: () => void | Promise<void>
}

Usage

ts
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import { DrizzleAdapter, DRIZZLE_DB } from '@forinda/kickjs-drizzle'

const client = postgres(process.env.DATABASE_URL!)
const db = drizzle(client)

bootstrap({
  modules,
  adapters: [
    new DrizzleAdapter({
      db,
      logging: true,
      onShutdown: () => client.end(),
    }),
  ],
})

Inject in services

ts
import { Service, Inject } from '@forinda/kickjs-core'
import { DRIZZLE_DB } from '@forinda/kickjs-drizzle'
import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'

@Service()
class UserService {
  @Inject(DRIZZLE_DB) private db!: PostgresJsDatabase
}

DrizzleQueryAdapter

Translates KickJS ParsedQuery objects into Drizzle query builder arguments.

Constructor

Pass the drizzle-orm operator functions:

ts
import { eq, ne, gt, gte, lt, lte, ilike, inArray, and, or, asc, desc } from 'drizzle-orm'
import { DrizzleQueryAdapter } from '@forinda/kickjs-drizzle'

const queryAdapter = new DrizzleQueryAdapter({
  eq, ne, gt, gte, lt, lte, ilike, inArray, and, or, asc, desc,
})

Usage

ts
import { users } from './schema'

@Get('/')
async list(ctx: RequestContext) {
  const parsed = ctx.qs({ filters: ['name', 'email', 'role'], sort: ['name', 'createdAt'] })
  const query = queryAdapter.build(parsed, {
    table: users,
    searchColumns: ['name', 'email'],
  })

  const results = await db
    .select()
    .from(users)
    .where(query.where)
    .orderBy(...query.orderBy)
    .limit(query.limit)
    .offset(query.offset)

  return ctx.json(results)
}

Filter operator mapping

KickJS OperatorDrizzle FunctionExample Query
eqeq()?filter=role:eq:admin
neqne()?filter=status:neq:deleted
gtgt()?filter=age:gt:18
gtegte()?filter=price:gte:100
ltlt()?filter=stock:lt:10
ltelte()?filter=rating:lte:3
containsilike('%val%')?filter=name:contains:john
startsilike('val%')?filter=email:starts:admin
endsilike('%val')?filter=domain:ends:.com
ininArray()?filter=status:in:active,pending
betweengte() AND lte()?filter=price:between:10,50

Released under the MIT License.