@forinda/kickjs-drizzle 1.3.2 → 1.4.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,51 @@
1
+ import { type AppAdapter, type Container } from '@forinda/kickjs-core';
2
+ import { type DrizzleAdapterOptions } from './types';
3
+ /**
4
+ * Drizzle ORM adapter — registers a Drizzle database instance in the DI
5
+ * container and manages its lifecycle.
6
+ *
7
+ * Works with any Drizzle driver: `drizzle-orm/postgres-js`, `drizzle-orm/node-postgres`,
8
+ * `drizzle-orm/mysql2`, `drizzle-orm/better-sqlite3`, `drizzle-orm/libsql`, etc.
9
+ *
10
+ * The adapter is generic — the db type is inferred from what you pass in,
11
+ * so services can inject the fully-typed database instance.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { drizzle } from 'drizzle-orm/better-sqlite3'
16
+ * import * as schema from './schema'
17
+ * import { DrizzleAdapter } from '@forinda/kickjs-drizzle'
18
+ *
19
+ * const db = drizzle({ client: sqlite, schema })
20
+ *
21
+ * bootstrap({
22
+ * modules,
23
+ * adapters: [
24
+ * new DrizzleAdapter({ db, onShutdown: () => sqlite.close() }),
25
+ * ],
26
+ * })
27
+ * ```
28
+ *
29
+ * Inject the typed db instance in services:
30
+ * ```ts
31
+ * import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'
32
+ * import * as schema from './schema'
33
+ *
34
+ * @Service()
35
+ * class UserService {
36
+ * constructor(@Inject(DRIZZLE_DB) private db: BetterSQLite3Database<typeof schema>) {}
37
+ * }
38
+ * ```
39
+ */
40
+ export declare class DrizzleAdapter<TDb = unknown> implements AppAdapter {
41
+ private options;
42
+ name: string;
43
+ private db;
44
+ private onShutdown?;
45
+ constructor(options: DrizzleAdapterOptions<TDb>);
46
+ /** Register the Drizzle db instance in the DI container */
47
+ beforeStart(_app: unknown, container: Container): void;
48
+ /** Close the underlying connection on shutdown */
49
+ shutdown(): Promise<void>;
50
+ }
51
+ //# sourceMappingURL=drizzle.adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle.adapter.d.ts","sourceRoot":"","sources":["../src/drizzle.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,UAAU,EAAE,KAAK,SAAS,EAAS,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAc,KAAK,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAIhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,cAAc,CAAC,GAAG,GAAG,OAAO,CAAE,YAAW,UAAU;IAKlD,OAAO,CAAC,OAAO;IAJ3B,IAAI,SAAmB;IACvB,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,UAAU,CAAC,CAA4B;gBAE3B,OAAO,EAAE,qBAAqB,CAAC,GAAG,CAAC;IAKvD,2DAA2D;IAC3D,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAUtD,kDAAkD;IAC5C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAMhC"}
package/dist/index.d.ts CHANGED
@@ -1,334 +1,6 @@
1
- import { MaybePromise, AppAdapter, Container } from '@forinda/kickjs-core';
2
- import { QueryBuilderAdapter, ParsedQuery } from '@forinda/kickjs-http';
3
-
4
- /** DI token for resolving the Drizzle database instance from the container */
5
- declare const DRIZZLE_DB: unique symbol;
6
- interface DrizzleAdapterOptions<TDb = unknown> {
7
- /**
8
- * Drizzle database instance — the return value of `drizzle()`.
9
- * Preserves the full type so services can inject it type-safely.
10
- *
11
- * @example
12
- * ```ts
13
- * import { drizzle } from 'drizzle-orm/better-sqlite3'
14
- * import * as schema from './schema'
15
- *
16
- * const db = drizzle({ client: sqlite, schema })
17
- * // db is BetterSQLite3Database<typeof schema>
18
- *
19
- * new DrizzleAdapter({ db })
20
- * // TDb is inferred as BetterSQLite3Database<typeof schema>
21
- * ```
22
- */
23
- db: TDb;
24
- /** Enable query logging (default: false) */
25
- logging?: boolean;
26
- /**
27
- * Optional shutdown function to close the underlying connection pool.
28
- * Drizzle doesn't expose a universal disconnect — this lets you pass your
29
- * driver's cleanup (e.g., `pool.end()` for postgres, `client.close()` for libsql).
30
- *
31
- * @example
32
- * ```ts
33
- * const pool = new Pool({ connectionString: '...' })
34
- * const db = drizzle(pool)
35
- *
36
- * new DrizzleAdapter({
37
- * db,
38
- * onShutdown: () => pool.end(),
39
- * })
40
- * ```
41
- */
42
- onShutdown?: () => MaybePromise<any>;
43
- }
44
-
45
- /**
46
- * Drizzle ORM adapter — registers a Drizzle database instance in the DI
47
- * container and manages its lifecycle.
48
- *
49
- * Works with any Drizzle driver: `drizzle-orm/postgres-js`, `drizzle-orm/node-postgres`,
50
- * `drizzle-orm/mysql2`, `drizzle-orm/better-sqlite3`, `drizzle-orm/libsql`, etc.
51
- *
52
- * The adapter is generic — the db type is inferred from what you pass in,
53
- * so services can inject the fully-typed database instance.
54
- *
55
- * @example
56
- * ```ts
57
- * import { drizzle } from 'drizzle-orm/better-sqlite3'
58
- * import * as schema from './schema'
59
- * import { DrizzleAdapter } from '@forinda/kickjs-drizzle'
60
- *
61
- * const db = drizzle({ client: sqlite, schema })
62
- *
63
- * bootstrap({
64
- * modules,
65
- * adapters: [
66
- * new DrizzleAdapter({ db, onShutdown: () => sqlite.close() }),
67
- * ],
68
- * })
69
- * ```
70
- *
71
- * Inject the typed db instance in services:
72
- * ```ts
73
- * import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'
74
- * import * as schema from './schema'
75
- *
76
- * @Service()
77
- * class UserService {
78
- * constructor(@Inject(DRIZZLE_DB) private db: BetterSQLite3Database<typeof schema>) {}
79
- * }
80
- * ```
81
- */
82
- declare class DrizzleAdapter<TDb = unknown> implements AppAdapter {
83
- private options;
84
- name: string;
85
- private db;
86
- private onShutdown?;
87
- constructor(options: DrizzleAdapterOptions<TDb>);
88
- /** Register the Drizzle db instance in the DI container */
89
- beforeStart(_app: unknown, container: Container): void;
90
- /** Close the underlying connection on shutdown */
91
- shutdown(): Promise<void>;
92
- }
93
-
94
- /**
95
- * Configuration for the Drizzle query builder adapter.
96
- *
97
- * Unlike Prisma which uses its own query builder API, Drizzle uses SQL-like
98
- * operators (`eq`, `gt`, `like`, etc.) from `drizzle-orm`. This adapter
99
- * produces a config object that can be spread into Drizzle's `select().from().where()`.
100
- */
101
- interface DrizzleQueryConfig {
102
- /** The Drizzle table schema object (e.g., `users` from your schema) */
103
- table: Record<string, any>;
104
- /** Columns to search across when a search string is provided */
105
- searchColumns?: string[];
106
- }
107
- /**
108
- * Type-safe Drizzle query configuration using Column objects.
109
- *
110
- * Use this instead of `DrizzleQueryConfig` for type-safe column references
111
- * that are validated at compile time. Column objects carry `dataType` metadata
112
- * enabling automatic type coercion of filter values.
113
- *
114
- * @example
115
- * ```ts
116
- * import { users } from './schema'
117
- * import type { DrizzleColumnQueryConfig } from '@forinda/kickjs-drizzle'
118
- *
119
- * const config: DrizzleColumnQueryConfig = {
120
- * columns: {
121
- * status: users.status,
122
- * isActive: users.isActive,
123
- * createdAt: users.createdAt,
124
- * },
125
- * sortable: {
126
- * name: users.name,
127
- * createdAt: users.createdAt,
128
- * },
129
- * searchColumns: [users.firstName, users.lastName, users.email],
130
- * baseCondition: eq(users.tenantId, tenantId),
131
- * }
132
- * ```
133
- */
134
- interface DrizzleColumnQueryConfig {
135
- /**
136
- * Map of filterable field names to Drizzle Column objects.
137
- * Keys are the query parameter names, values are the actual schema columns.
138
- * The column's `dataType` is used for automatic type coercion.
139
- */
140
- columns: Record<string, any>;
141
- /**
142
- * Map of sortable field names to Drizzle Column objects.
143
- * If not provided, falls back to `columns` for sort lookups.
144
- */
145
- sortable?: Record<string, any>;
146
- /**
147
- * Column objects to search across when a search string is provided.
148
- * Each entry should be a Drizzle Column (not a string).
149
- */
150
- searchColumns?: any[];
151
- /**
152
- * A pre-built SQL condition that is always prepended to the WHERE clause.
153
- * Use for scoping queries by tenant, workspace, or other invariants.
154
- *
155
- * @example
156
- * ```ts
157
- * baseCondition: and(eq(tasks.tenantId, tid), eq(tasks.workspaceId, wid))
158
- * ```
159
- */
160
- baseCondition?: any;
161
- }
162
- /**
163
- * Configuration type for defining query param schemas with Drizzle Column objects.
164
- *
165
- * Used in constants files to define which columns are filterable, sortable, and searchable.
166
- * This type is consumed by both `DrizzleQueryAdapter.buildFromColumns()` and `@ApiQueryParams()`.
167
- *
168
- * @example
169
- * ```ts
170
- * import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
171
- * import { tasks } from '@/db/schema'
172
- *
173
- * export const TASK_QUERY_CONFIG: DrizzleQueryParamsConfig = {
174
- * columns: {
175
- * status: tasks.status,
176
- * priority: tasks.priority,
177
- * },
178
- * sortable: {
179
- * title: tasks.title,
180
- * createdAt: tasks.createdAt,
181
- * },
182
- * searchColumns: [tasks.title, tasks.key],
183
- * }
184
- * ```
185
- */
186
- interface DrizzleQueryParamsConfig {
187
- /** Filterable columns: keys are query param names, values are Drizzle Column objects */
188
- columns: Record<string, any>;
189
- /** Sortable columns: keys are query param names, values are Drizzle Column objects */
190
- sortable?: Record<string, any>;
191
- /** Columns for text search */
192
- searchColumns?: any[];
193
- /** Optional base condition for scoping (tenant, workspace, etc.) */
194
- baseCondition?: any;
195
- }
196
- /**
197
- * Convert a DrizzleQueryParamsConfig into a string-based QueryFieldConfig.
198
- * Useful for passing to `@ApiQueryParams()` or other APIs that expect string arrays.
199
- *
200
- * @example
201
- * ```ts
202
- * import { toQueryFieldConfig } from '@forinda/kickjs-drizzle'
203
- *
204
- * const fieldConfig = toQueryFieldConfig(TASK_QUERY_CONFIG)
205
- * // → { filterable: ['status', 'priority'], sortable: ['title', 'createdAt'], searchable: [] }
206
- * ```
207
- */
208
- declare function toQueryFieldConfig(config: DrizzleQueryParamsConfig): {
209
- filterable: string[];
210
- sortable: string[];
211
- searchable: string[];
212
- };
213
- /**
214
- * Result shape compatible with Drizzle's query builder.
215
- * Use with `db.select().from(table).where(result.where).orderBy(...result.orderBy).limit(result.limit).offset(result.offset)`
216
- */
217
- interface DrizzleQueryResult {
218
- /** SQL condition — pass to `.where()` */
219
- where?: any;
220
- /** Array of order expressions — spread into `.orderBy()` */
221
- orderBy: any[];
222
- /** Row limit — pass to `.limit()` */
223
- limit: number;
224
- /** Row offset — pass to `.offset()` */
225
- offset: number;
226
- }
227
- /**
228
- * Drizzle operator functions required by the query adapter.
229
- * Pass these from your `drizzle-orm` import to avoid version coupling.
230
- *
231
- * @example
232
- * ```ts
233
- * import { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc } from 'drizzle-orm'
234
- *
235
- * const adapter = new DrizzleQueryAdapter({
236
- * eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,
237
- * })
238
- * ```
239
- */
240
- interface DrizzleOps {
241
- eq: (column: any, value: any) => any;
242
- ne: (column: any, value: any) => any;
243
- gt: (column: any, value: any) => any;
244
- gte: (column: any, value: any) => any;
245
- lt: (column: any, value: any) => any;
246
- lte: (column: any, value: any) => any;
247
- ilike: (column: any, value: string) => any;
248
- inArray: (column: any, values: any[]) => any;
249
- between?: (column: any, min: any, max: any) => any;
250
- and: (...conditions: any[]) => any;
251
- or: (...conditions: any[]) => any;
252
- asc: (column: any) => any;
253
- desc: (column: any) => any;
254
- }
255
- /**
256
- * Translates a ParsedQuery into Drizzle-compatible query parts.
257
- *
258
- * Supports two modes:
259
- * 1. **String-based** (legacy): `build(parsed, { table, searchColumns })` — looks up columns by string name
260
- * 2. **Column-based** (recommended): `buildFromColumns(parsed, config)` — uses actual Column objects for type safety
261
- *
262
- * @example
263
- * ```ts
264
- * // String-based (legacy)
265
- * const query = adapter.build(parsed, { table: users, searchColumns: ['name', 'email'] })
266
- *
267
- * // Column-based (recommended)
268
- * const query = adapter.buildFromColumns(parsed, {
269
- * columns: { status: users.status, isActive: users.isActive },
270
- * searchColumns: [users.name, users.email],
271
- * baseCondition: eq(users.tenantId, tid),
272
- * })
273
- *
274
- * const results = await db
275
- * .select().from(users)
276
- * .where(query.where)
277
- * .orderBy(...query.orderBy)
278
- * .limit(query.limit)
279
- * .offset(query.offset)
280
- * ```
281
- */
282
- declare class DrizzleQueryAdapter implements QueryBuilderAdapter<DrizzleQueryResult, DrizzleQueryConfig> {
283
- private ops;
284
- readonly name = "DrizzleQueryAdapter";
285
- constructor(ops: DrizzleOps);
286
- /**
287
- * Build query from string-based config (legacy API).
288
- * Prefer `buildFromColumns()` for type safety.
289
- */
290
- build(parsed: ParsedQuery, config?: DrizzleQueryConfig): DrizzleQueryResult;
291
- /**
292
- * Build query using Column objects for type-safe filtering, sorting, and search.
293
- *
294
- * Features over `build()`:
295
- * - Column references validated at compile time
296
- * - Automatic type coercion based on `column.dataType` (boolean, number, date)
297
- * - `baseCondition` support for tenant/workspace scoping
298
- * - Native `between` operator support
299
- * - Separate `sortable` map so filterable and sortable columns can differ
300
- *
301
- * @example
302
- * ```ts
303
- * const query = adapter.buildFromColumns(parsed, {
304
- * columns: { status: tasks.status, priority: tasks.priority },
305
- * sortable: { title: tasks.title, createdAt: tasks.createdAt },
306
- * searchColumns: [tasks.title, tasks.key],
307
- * baseCondition: eq(tasks.workspaceId, wid),
308
- * })
309
- * ```
310
- */
311
- buildFromColumns(parsed: ParsedQuery, config: DrizzleColumnQueryConfig): DrizzleQueryResult;
312
- /** Map a single FilterItem to a Drizzle condition using string-based table lookup */
313
- private buildFilter;
314
- /**
315
- * Map a FilterItem to a Drizzle condition using a Column object.
316
- * Coerces values based on `column.dataType` for type-safe filtering.
317
- */
318
- private buildColumnFilter;
319
- /** Build Drizzle orderBy from SortItem[] */
320
- private buildSort;
321
- /** Attempt to coerce a string value to a number or boolean if appropriate */
322
- private coerce;
323
- /**
324
- * Coerce a string value based on the column's dataType.
325
- *
326
- * - `'boolean'` → `true`/`false`
327
- * - `'number'` / `'bigint'` → `Number(value)`
328
- * - `'date'` → `new Date(value)` (ISO 8601 strings)
329
- * - Everything else → original string
330
- */
331
- private coerceByDataType;
332
- }
333
-
334
- export { DRIZZLE_DB, DrizzleAdapter, type DrizzleAdapterOptions, type DrizzleColumnQueryConfig, type DrizzleOps, DrizzleQueryAdapter, type DrizzleQueryConfig, type DrizzleQueryParamsConfig, type DrizzleQueryResult, toQueryFieldConfig };
1
+ export { DrizzleAdapter } from './drizzle.adapter';
2
+ export { DrizzleQueryAdapter, toQueryFieldConfig } from './query-adapter';
3
+ export { DRIZZLE_DB } from './types';
4
+ export type { DrizzleAdapterOptions } from './types';
5
+ export type { DrizzleQueryConfig, DrizzleColumnQueryConfig, DrizzleQueryParamsConfig, DrizzleQueryResult, DrizzleOps, } from './query-adapter';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,YAAY,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AACpD,YAAY,EACV,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,kBAAkB,EAClB,UAAU,GACX,MAAM,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -1 +1,168 @@
1
- var m=Object.defineProperty;var h=(n,e)=>m(n,"name",{value:e,configurable:!0});import{Logger as b,Scope as f}from"@forinda/kickjs-core";var l=Symbol("DrizzleDB");var u=b.for("DrizzleAdapter"),p=class{static{h(this,"DrizzleAdapter")}options;name="DrizzleAdapter";db;onShutdown;constructor(e){this.options=e,this.db=e.db,this.onShutdown=e.onShutdown}beforeStart(e,s){this.options.logging&&u.info("Query logging enabled"),s.registerFactory(l,()=>this.db,f.SINGLETON),u.info("Drizzle database registered in DI container")}async shutdown(){this.onShutdown&&(await this.onShutdown(),u.info("Drizzle connection closed"))}};function y(n){return{filterable:Object.keys(n.columns),sortable:n.sortable?Object.keys(n.sortable):[],searchable:n.searchColumns?n.searchColumns.map(e=>e.name??"").filter(Boolean):[]}}h(y,"toQueryFieldConfig");var d=class{static{h(this,"DrizzleQueryAdapter")}ops;name="DrizzleQueryAdapter";constructor(e){this.ops=e}build(e,s={}){let t={orderBy:[],limit:e.pagination.limit,offset:e.pagination.offset},r=[];for(let o of e.filters){let i=this.buildFilter(s.table,o);i&&r.push(i)}if(e.search&&s.searchColumns&&s.searchColumns.length>0){let o=s.searchColumns.filter(i=>s.table[i]).map(i=>this.ops.ilike(s.table[i],`%${e.search}%`));o.length>0&&r.push(this.ops.or(...o))}return r.length===1?t.where=r[0]:r.length>1&&(t.where=this.ops.and(...r)),t.orderBy=this.buildSort(s.table,e.sort),t}buildFromColumns(e,s){let t={orderBy:[],limit:e.pagination.limit,offset:e.pagination.offset},r=[];s.baseCondition&&r.push(s.baseCondition);for(let i of e.filters){let a=s.columns[i.field];if(!a)continue;let c=this.buildColumnFilter(a,i);c&&r.push(c)}if(e.search&&s.searchColumns&&s.searchColumns.length>0){let i=s.searchColumns.map(a=>this.ops.ilike(a,`%${e.search}%`));i.length>0&&r.push(this.ops.or(...i))}r.length===1?t.where=r[0]:r.length>1&&(t.where=this.ops.and(...r));let o=s.sortable??s.columns;return t.orderBy=e.sort.filter(i=>o[i.field]).map(i=>i.direction==="desc"?this.ops.desc(o[i.field]):this.ops.asc(o[i.field])),t}buildFilter(e,s){let t=e[s.field];if(!t)return null;let r=this.coerce(s.value);switch(s.operator){case"eq":return this.ops.eq(t,r);case"neq":return this.ops.ne(t,r);case"gt":return this.ops.gt(t,r);case"gte":return this.ops.gte(t,r);case"lt":return this.ops.lt(t,r);case"lte":return this.ops.lte(t,r);case"contains":return this.ops.ilike(t,`%${s.value}%`);case"starts":return this.ops.ilike(t,`${s.value}%`);case"ends":return this.ops.ilike(t,`%${s.value}`);case"in":{let o=s.value.split(",").map(i=>this.coerce(i.trim()));return this.ops.inArray(t,o)}case"between":{let[o,i]=s.value.split(",").map(a=>this.coerce(a.trim()));return this.ops.and(this.ops.gte(t,o),this.ops.lte(t,i))}default:return this.ops.eq(t,r)}}buildColumnFilter(e,s){let t=this.coerceByDataType(s.value,e.dataType);switch(s.operator){case"eq":return this.ops.eq(e,t);case"neq":return this.ops.ne(e,t);case"gt":return this.ops.gt(e,t);case"gte":return this.ops.gte(e,t);case"lt":return this.ops.lt(e,t);case"lte":return this.ops.lte(e,t);case"contains":return this.ops.ilike(e,`%${s.value}%`);case"starts":return this.ops.ilike(e,`${s.value}%`);case"ends":return this.ops.ilike(e,`%${s.value}`);case"in":{let r=s.value.split(",").map(o=>this.coerceByDataType(o.trim(),e.dataType));return this.ops.inArray(e,r)}case"between":{let[r,o]=s.value.split(",").map(c=>c.trim()),i=this.coerceByDataType(r,e.dataType),a=this.coerceByDataType(o,e.dataType);return this.ops.between?this.ops.between(e,i,a):this.ops.and(this.ops.gte(e,i),this.ops.lte(e,a))}default:return this.ops.eq(e,t)}}buildSort(e,s){return s.filter(t=>e[t.field]).map(t=>t.direction==="desc"?this.ops.desc(e[t.field]):this.ops.asc(e[t.field]))}coerce(e){if(e==="true")return!0;if(e==="false")return!1;let s=Number(e);return!Number.isNaN(s)&&e.trim()!==""?s:e}coerceByDataType(e,s){if(!s)return this.coerce(e);switch(s){case"boolean":return e==="true"||e==="1";case"number":case"bigint":{let t=Number(e);return Number.isNaN(t)?e:t}case"date":case"localDate":case"localDateTime":{let t=new Date(e);return Number.isNaN(t.getTime())?e:t}default:return e}}};export{l as DRIZZLE_DB,p as DrizzleAdapter,d as DrizzleQueryAdapter,y as toQueryFieldConfig};
1
+ import { Logger as l, Scope as c } from "@forinda/kickjs-core";
2
+ var u = /* @__PURE__ */ Symbol("DrizzleDB"), h = l.for("DrizzleAdapter"), d = class {
3
+ name = "DrizzleAdapter";
4
+ db;
5
+ onShutdown;
6
+ constructor(e) {
7
+ this.options = e, this.db = e.db, this.onShutdown = e.onShutdown;
8
+ }
9
+ beforeStart(e, t) {
10
+ this.options.logging && h.info("Query logging enabled"), t.registerFactory(u, () => this.db, c.SINGLETON), h.info("Drizzle database registered in DI container");
11
+ }
12
+ async shutdown() {
13
+ this.onShutdown && (await this.onShutdown(), h.info("Drizzle connection closed"));
14
+ }
15
+ };
16
+ function b(e) {
17
+ return {
18
+ filterable: Object.keys(e.columns),
19
+ sortable: e.sortable ? Object.keys(e.sortable) : [],
20
+ searchable: e.searchColumns ? e.searchColumns.map((t) => t.name ?? "").filter(Boolean) : []
21
+ };
22
+ }
23
+ var m = class {
24
+ name = "DrizzleQueryAdapter";
25
+ constructor(e) {
26
+ this.ops = e;
27
+ }
28
+ build(e, t = {}) {
29
+ const s = {
30
+ orderBy: [],
31
+ limit: e.pagination.limit,
32
+ offset: e.pagination.offset
33
+ }, r = [];
34
+ for (const o of e.filters) {
35
+ const i = this.buildFilter(t.table, o);
36
+ i && r.push(i);
37
+ }
38
+ if (e.search && t.searchColumns && t.searchColumns.length > 0) {
39
+ const o = t.searchColumns.filter((i) => t.table[i]).map((i) => this.ops.ilike(t.table[i], `%${e.search}%`));
40
+ o.length > 0 && r.push(this.ops.or(...o));
41
+ }
42
+ return r.length === 1 ? s.where = r[0] : r.length > 1 && (s.where = this.ops.and(...r)), s.orderBy = this.buildSort(t.table, e.sort), s;
43
+ }
44
+ buildFromColumns(e, t) {
45
+ const s = {
46
+ orderBy: [],
47
+ limit: e.pagination.limit,
48
+ offset: e.pagination.offset
49
+ }, r = [];
50
+ t.baseCondition && r.push(t.baseCondition);
51
+ for (const i of e.filters) {
52
+ const n = t.columns[i.field];
53
+ if (!n) continue;
54
+ const a = this.buildColumnFilter(n, i);
55
+ a && r.push(a);
56
+ }
57
+ if (e.search && t.searchColumns && t.searchColumns.length > 0) {
58
+ const i = t.searchColumns.map((n) => this.ops.ilike(n, `%${e.search}%`));
59
+ i.length > 0 && r.push(this.ops.or(...i));
60
+ }
61
+ r.length === 1 ? s.where = r[0] : r.length > 1 && (s.where = this.ops.and(...r));
62
+ const o = t.sortable ?? t.columns;
63
+ return s.orderBy = e.sort.filter((i) => o[i.field]).map((i) => i.direction === "desc" ? this.ops.desc(o[i.field]) : this.ops.asc(o[i.field])), s;
64
+ }
65
+ buildFilter(e, t) {
66
+ const s = e[t.field];
67
+ if (!s) return null;
68
+ const r = this.coerce(t.value);
69
+ switch (t.operator) {
70
+ case "eq":
71
+ return this.ops.eq(s, r);
72
+ case "neq":
73
+ return this.ops.ne(s, r);
74
+ case "gt":
75
+ return this.ops.gt(s, r);
76
+ case "gte":
77
+ return this.ops.gte(s, r);
78
+ case "lt":
79
+ return this.ops.lt(s, r);
80
+ case "lte":
81
+ return this.ops.lte(s, r);
82
+ case "contains":
83
+ return this.ops.ilike(s, `%${t.value}%`);
84
+ case "starts":
85
+ return this.ops.ilike(s, `${t.value}%`);
86
+ case "ends":
87
+ return this.ops.ilike(s, `%${t.value}`);
88
+ case "in": {
89
+ const o = t.value.split(",").map((i) => this.coerce(i.trim()));
90
+ return this.ops.inArray(s, o);
91
+ }
92
+ case "between": {
93
+ const [o, i] = t.value.split(",").map((n) => this.coerce(n.trim()));
94
+ return this.ops.and(this.ops.gte(s, o), this.ops.lte(s, i));
95
+ }
96
+ default:
97
+ return this.ops.eq(s, r);
98
+ }
99
+ }
100
+ buildColumnFilter(e, t) {
101
+ const s = this.coerceByDataType(t.value, e.dataType);
102
+ switch (t.operator) {
103
+ case "eq":
104
+ return this.ops.eq(e, s);
105
+ case "neq":
106
+ return this.ops.ne(e, s);
107
+ case "gt":
108
+ return this.ops.gt(e, s);
109
+ case "gte":
110
+ return this.ops.gte(e, s);
111
+ case "lt":
112
+ return this.ops.lt(e, s);
113
+ case "lte":
114
+ return this.ops.lte(e, s);
115
+ case "contains":
116
+ return this.ops.ilike(e, `%${t.value}%`);
117
+ case "starts":
118
+ return this.ops.ilike(e, `${t.value}%`);
119
+ case "ends":
120
+ return this.ops.ilike(e, `%${t.value}`);
121
+ case "in": {
122
+ const r = t.value.split(",").map((o) => this.coerceByDataType(o.trim(), e.dataType));
123
+ return this.ops.inArray(e, r);
124
+ }
125
+ case "between": {
126
+ const [r, o] = t.value.split(",").map((a) => a.trim()), i = this.coerceByDataType(r, e.dataType), n = this.coerceByDataType(o, e.dataType);
127
+ return this.ops.between ? this.ops.between(e, i, n) : this.ops.and(this.ops.gte(e, i), this.ops.lte(e, n));
128
+ }
129
+ default:
130
+ return this.ops.eq(e, s);
131
+ }
132
+ }
133
+ buildSort(e, t) {
134
+ return t.filter((s) => e[s.field]).map((s) => s.direction === "desc" ? this.ops.desc(e[s.field]) : this.ops.asc(e[s.field]));
135
+ }
136
+ coerce(e) {
137
+ if (e === "true") return !0;
138
+ if (e === "false") return !1;
139
+ const t = Number(e);
140
+ return !Number.isNaN(t) && e.trim() !== "" ? t : e;
141
+ }
142
+ coerceByDataType(e, t) {
143
+ if (!t) return this.coerce(e);
144
+ switch (t) {
145
+ case "boolean":
146
+ return e === "true" || e === "1";
147
+ case "number":
148
+ case "bigint": {
149
+ const s = Number(e);
150
+ return Number.isNaN(s) ? e : s;
151
+ }
152
+ case "date":
153
+ case "localDate":
154
+ case "localDateTime": {
155
+ const s = new Date(e);
156
+ return Number.isNaN(s.getTime()) ? e : s;
157
+ }
158
+ default:
159
+ return e;
160
+ }
161
+ }
162
+ };
163
+ export {
164
+ u as DRIZZLE_DB,
165
+ d as DrizzleAdapter,
166
+ m as DrizzleQueryAdapter,
167
+ b as toQueryFieldConfig
168
+ };
@@ -0,0 +1,241 @@
1
+ import type { QueryBuilderAdapter, ParsedQuery } from '@forinda/kickjs-http';
2
+ /**
3
+ * Configuration for the Drizzle query builder adapter.
4
+ *
5
+ * Unlike Prisma which uses its own query builder API, Drizzle uses SQL-like
6
+ * operators (`eq`, `gt`, `like`, etc.) from `drizzle-orm`. This adapter
7
+ * produces a config object that can be spread into Drizzle's `select().from().where()`.
8
+ */
9
+ export interface DrizzleQueryConfig {
10
+ /** The Drizzle table schema object (e.g., `users` from your schema) */
11
+ table: Record<string, any>;
12
+ /** Columns to search across when a search string is provided */
13
+ searchColumns?: string[];
14
+ }
15
+ /**
16
+ * Type-safe Drizzle query configuration using Column objects.
17
+ *
18
+ * Use this instead of `DrizzleQueryConfig` for type-safe column references
19
+ * that are validated at compile time. Column objects carry `dataType` metadata
20
+ * enabling automatic type coercion of filter values.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { users } from './schema'
25
+ * import type { DrizzleColumnQueryConfig } from '@forinda/kickjs-drizzle'
26
+ *
27
+ * const config: DrizzleColumnQueryConfig = {
28
+ * columns: {
29
+ * status: users.status,
30
+ * isActive: users.isActive,
31
+ * createdAt: users.createdAt,
32
+ * },
33
+ * sortable: {
34
+ * name: users.name,
35
+ * createdAt: users.createdAt,
36
+ * },
37
+ * searchColumns: [users.firstName, users.lastName, users.email],
38
+ * baseCondition: eq(users.tenantId, tenantId),
39
+ * }
40
+ * ```
41
+ */
42
+ export interface DrizzleColumnQueryConfig {
43
+ /**
44
+ * Map of filterable field names to Drizzle Column objects.
45
+ * Keys are the query parameter names, values are the actual schema columns.
46
+ * The column's `dataType` is used for automatic type coercion.
47
+ */
48
+ columns: Record<string, any>;
49
+ /**
50
+ * Map of sortable field names to Drizzle Column objects.
51
+ * If not provided, falls back to `columns` for sort lookups.
52
+ */
53
+ sortable?: Record<string, any>;
54
+ /**
55
+ * Column objects to search across when a search string is provided.
56
+ * Each entry should be a Drizzle Column (not a string).
57
+ */
58
+ searchColumns?: any[];
59
+ /**
60
+ * A pre-built SQL condition that is always prepended to the WHERE clause.
61
+ * Use for scoping queries by tenant, workspace, or other invariants.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * baseCondition: and(eq(tasks.tenantId, tid), eq(tasks.workspaceId, wid))
66
+ * ```
67
+ */
68
+ baseCondition?: any;
69
+ }
70
+ /**
71
+ * Configuration type for defining query param schemas with Drizzle Column objects.
72
+ *
73
+ * Used in constants files to define which columns are filterable, sortable, and searchable.
74
+ * This type is consumed by both `DrizzleQueryAdapter.buildFromColumns()` and `@ApiQueryParams()`.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import type { DrizzleQueryParamsConfig } from '@forinda/kickjs-drizzle'
79
+ * import { tasks } from '@/db/schema'
80
+ *
81
+ * export const TASK_QUERY_CONFIG: DrizzleQueryParamsConfig = {
82
+ * columns: {
83
+ * status: tasks.status,
84
+ * priority: tasks.priority,
85
+ * },
86
+ * sortable: {
87
+ * title: tasks.title,
88
+ * createdAt: tasks.createdAt,
89
+ * },
90
+ * searchColumns: [tasks.title, tasks.key],
91
+ * }
92
+ * ```
93
+ */
94
+ export interface DrizzleQueryParamsConfig {
95
+ /** Filterable columns: keys are query param names, values are Drizzle Column objects */
96
+ columns: Record<string, any>;
97
+ /** Sortable columns: keys are query param names, values are Drizzle Column objects */
98
+ sortable?: Record<string, any>;
99
+ /** Columns for text search */
100
+ searchColumns?: any[];
101
+ /** Optional base condition for scoping (tenant, workspace, etc.) */
102
+ baseCondition?: any;
103
+ }
104
+ /**
105
+ * Convert a DrizzleQueryParamsConfig into a string-based QueryFieldConfig.
106
+ * Useful for passing to `@ApiQueryParams()` or other APIs that expect string arrays.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * import { toQueryFieldConfig } from '@forinda/kickjs-drizzle'
111
+ *
112
+ * const fieldConfig = toQueryFieldConfig(TASK_QUERY_CONFIG)
113
+ * // → { filterable: ['status', 'priority'], sortable: ['title', 'createdAt'], searchable: [] }
114
+ * ```
115
+ */
116
+ export declare function toQueryFieldConfig(config: DrizzleQueryParamsConfig): {
117
+ filterable: string[];
118
+ sortable: string[];
119
+ searchable: string[];
120
+ };
121
+ /**
122
+ * Result shape compatible with Drizzle's query builder.
123
+ * Use with `db.select().from(table).where(result.where).orderBy(...result.orderBy).limit(result.limit).offset(result.offset)`
124
+ */
125
+ export interface DrizzleQueryResult {
126
+ /** SQL condition — pass to `.where()` */
127
+ where?: any;
128
+ /** Array of order expressions — spread into `.orderBy()` */
129
+ orderBy: any[];
130
+ /** Row limit — pass to `.limit()` */
131
+ limit: number;
132
+ /** Row offset — pass to `.offset()` */
133
+ offset: number;
134
+ }
135
+ /**
136
+ * Drizzle operator functions required by the query adapter.
137
+ * Pass these from your `drizzle-orm` import to avoid version coupling.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * import { eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc } from 'drizzle-orm'
142
+ *
143
+ * const adapter = new DrizzleQueryAdapter({
144
+ * eq, ne, gt, gte, lt, lte, ilike, inArray, between, and, or, asc, desc,
145
+ * })
146
+ * ```
147
+ */
148
+ export interface DrizzleOps {
149
+ eq: (column: any, value: any) => any;
150
+ ne: (column: any, value: any) => any;
151
+ gt: (column: any, value: any) => any;
152
+ gte: (column: any, value: any) => any;
153
+ lt: (column: any, value: any) => any;
154
+ lte: (column: any, value: any) => any;
155
+ ilike: (column: any, value: string) => any;
156
+ inArray: (column: any, values: any[]) => any;
157
+ between?: (column: any, min: any, max: any) => any;
158
+ and: (...conditions: any[]) => any;
159
+ or: (...conditions: any[]) => any;
160
+ asc: (column: any) => any;
161
+ desc: (column: any) => any;
162
+ }
163
+ /**
164
+ * Translates a ParsedQuery into Drizzle-compatible query parts.
165
+ *
166
+ * Supports two modes:
167
+ * 1. **String-based** (legacy): `build(parsed, { table, searchColumns })` — looks up columns by string name
168
+ * 2. **Column-based** (recommended): `buildFromColumns(parsed, config)` — uses actual Column objects for type safety
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * // String-based (legacy)
173
+ * const query = adapter.build(parsed, { table: users, searchColumns: ['name', 'email'] })
174
+ *
175
+ * // Column-based (recommended)
176
+ * const query = adapter.buildFromColumns(parsed, {
177
+ * columns: { status: users.status, isActive: users.isActive },
178
+ * searchColumns: [users.name, users.email],
179
+ * baseCondition: eq(users.tenantId, tid),
180
+ * })
181
+ *
182
+ * const results = await db
183
+ * .select().from(users)
184
+ * .where(query.where)
185
+ * .orderBy(...query.orderBy)
186
+ * .limit(query.limit)
187
+ * .offset(query.offset)
188
+ * ```
189
+ */
190
+ export declare class DrizzleQueryAdapter implements QueryBuilderAdapter<DrizzleQueryResult, DrizzleQueryConfig> {
191
+ private ops;
192
+ readonly name = "DrizzleQueryAdapter";
193
+ constructor(ops: DrizzleOps);
194
+ /**
195
+ * Build query from string-based config (legacy API).
196
+ * Prefer `buildFromColumns()` for type safety.
197
+ */
198
+ build(parsed: ParsedQuery, config?: DrizzleQueryConfig): DrizzleQueryResult;
199
+ /**
200
+ * Build query using Column objects for type-safe filtering, sorting, and search.
201
+ *
202
+ * Features over `build()`:
203
+ * - Column references validated at compile time
204
+ * - Automatic type coercion based on `column.dataType` (boolean, number, date)
205
+ * - `baseCondition` support for tenant/workspace scoping
206
+ * - Native `between` operator support
207
+ * - Separate `sortable` map so filterable and sortable columns can differ
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * const query = adapter.buildFromColumns(parsed, {
212
+ * columns: { status: tasks.status, priority: tasks.priority },
213
+ * sortable: { title: tasks.title, createdAt: tasks.createdAt },
214
+ * searchColumns: [tasks.title, tasks.key],
215
+ * baseCondition: eq(tasks.workspaceId, wid),
216
+ * })
217
+ * ```
218
+ */
219
+ buildFromColumns(parsed: ParsedQuery, config: DrizzleColumnQueryConfig): DrizzleQueryResult;
220
+ /** Map a single FilterItem to a Drizzle condition using string-based table lookup */
221
+ private buildFilter;
222
+ /**
223
+ * Map a FilterItem to a Drizzle condition using a Column object.
224
+ * Coerces values based on `column.dataType` for type-safe filtering.
225
+ */
226
+ private buildColumnFilter;
227
+ /** Build Drizzle orderBy from SortItem[] */
228
+ private buildSort;
229
+ /** Attempt to coerce a string value to a number or boolean if appropriate */
230
+ private coerce;
231
+ /**
232
+ * Coerce a string value based on the column's dataType.
233
+ *
234
+ * - `'boolean'` → `true`/`false`
235
+ * - `'number'` / `'bigint'` → `Number(value)`
236
+ * - `'date'` → `new Date(value)` (ISO 8601 strings)
237
+ * - Everything else → original string
238
+ */
239
+ private coerceByDataType;
240
+ }
241
+ //# sourceMappingURL=query-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-adapter.d.ts","sourceRoot":"","sources":["../src/query-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { MaybePromise } from '@forinda/kickjs-core';
2
+ /** DI token for resolving the Drizzle database instance from the container */
3
+ export declare const DRIZZLE_DB: unique symbol;
4
+ export interface DrizzleAdapterOptions<TDb = unknown> {
5
+ /**
6
+ * Drizzle database instance — the return value of `drizzle()`.
7
+ * Preserves the full type so services can inject it type-safely.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { drizzle } from 'drizzle-orm/better-sqlite3'
12
+ * import * as schema from './schema'
13
+ *
14
+ * const db = drizzle({ client: sqlite, schema })
15
+ * // db is BetterSQLite3Database<typeof schema>
16
+ *
17
+ * new DrizzleAdapter({ db })
18
+ * // TDb is inferred as BetterSQLite3Database<typeof schema>
19
+ * ```
20
+ */
21
+ db: TDb;
22
+ /** Enable query logging (default: false) */
23
+ logging?: boolean;
24
+ /**
25
+ * Optional shutdown function to close the underlying connection pool.
26
+ * Drizzle doesn't expose a universal disconnect — this lets you pass your
27
+ * driver's cleanup (e.g., `pool.end()` for postgres, `client.close()` for libsql).
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const pool = new Pool({ connectionString: '...' })
32
+ * const db = drizzle(pool)
33
+ *
34
+ * new DrizzleAdapter({
35
+ * db,
36
+ * onShutdown: () => pool.end(),
37
+ * })
38
+ * ```
39
+ */
40
+ onShutdown?: () => MaybePromise<any>;
41
+ }
42
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,8EAA8E;AAC9E,eAAO,MAAM,UAAU,eAAsB,CAAA;AAE7C,MAAM,WAAW,qBAAqB,CAAC,GAAG,GAAG,OAAO;IAClD;;;;;;;;;;;;;;;OAeG;IACH,EAAE,EAAE,GAAG,CAAA;IAEP,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,EAAE,MAAM,YAAY,CAAC,GAAG,CAAC,CAAA;CACrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forinda/kickjs-drizzle",
3
- "version": "1.3.2",
3
+ "version": "1.4.1-alpha.0",
4
4
  "description": "Drizzle ORM adapter with DI integration, transaction support, and query building for KickJS",
5
5
  "keywords": [
6
6
  "kickjs",
@@ -37,7 +37,8 @@
37
37
  "@forinda/kickjs-queue",
38
38
  "@forinda/kickjs-multi-tenant",
39
39
  "@forinda/kickjs-devtools",
40
- "@forinda/kickjs-notifications"
40
+ "@forinda/kickjs-notifications",
41
+ "vite"
41
42
  ],
42
43
  "type": "module",
43
44
  "main": "dist/index.js",
@@ -53,15 +54,14 @@
53
54
  ],
54
55
  "dependencies": {
55
56
  "reflect-metadata": "^0.2.2",
56
- "@forinda/kickjs-core": "1.3.2",
57
- "@forinda/kickjs-http": "1.3.2"
57
+ "@forinda/kickjs-core": "1.4.1-alpha.0",
58
+ "@forinda/kickjs-http": "1.4.1-alpha.0"
58
59
  },
59
60
  "peerDependencies": {
60
61
  "drizzle-orm": ">=0.30.0"
61
62
  },
62
63
  "devDependencies": {
63
- "@types/node": "^24.5.2",
64
- "tsup": "^8.5.0",
64
+ "@types/node": "^25.0.0",
65
65
  "typescript": "^5.9.2"
66
66
  },
67
67
  "publishConfig": {
@@ -82,8 +82,9 @@
82
82
  "url": "https://github.com/forinda/kick-js/issues"
83
83
  },
84
84
  "scripts": {
85
- "build": "tsup",
86
- "dev": "tsup --watch",
85
+ "build": "vite build && pnpm build:types",
86
+ "build:types": "tsc -p tsconfig.build.json",
87
+ "dev": "vite build --watch",
87
88
  "typecheck": "tsc --noEmit",
88
89
  "clean": "rm -rf dist .turbo",
89
90
  "lint": "tsc --noEmit"