@hono-crud/drizzle 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/index.d.ts +991 -0
- package/dist/index.js +4 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kauan Guesser
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @hono-crud/drizzle
|
|
2
|
+
|
|
3
|
+
Drizzle ORM CRUD adapter for [hono-crud](https://github.com/kshdotdev/hono-crud).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hono-crud/drizzle hono-crud hono zod drizzle-orm drizzle-zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { fromHono, registerCrud, defineModel, defineMeta } from 'hono-crud';
|
|
15
|
+
import {
|
|
16
|
+
DrizzleCreateEndpoint,
|
|
17
|
+
DrizzleReadEndpoint,
|
|
18
|
+
DrizzleListEndpoint,
|
|
19
|
+
type DrizzleDatabase,
|
|
20
|
+
} from '@hono-crud/drizzle';
|
|
21
|
+
|
|
22
|
+
const app = fromHono(new Hono());
|
|
23
|
+
registerCrud(app, '/users', {
|
|
24
|
+
model,
|
|
25
|
+
meta,
|
|
26
|
+
endpoints: { create: DrizzleCreateEndpoint, read: DrizzleReadEndpoint, list: DrizzleListEndpoint },
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Exports `DrizzleAdapters`, the `Drizzle*Endpoint` classes, `createDrizzleCrud`, `createDrizzleSchemas`, and the `DrizzleDatabase` type.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,991 @@
|
|
|
1
|
+
import { Table, SQL, Column } from 'drizzle-orm';
|
|
2
|
+
import { MetaInput, IncludeOptions, FilterCondition, RelationConfig, CreateEndpoint, ModelObject, ReadEndpoint, UpdateEndpoint, NestedUpdateInput, NestedWriteResult, DeleteEndpoint, ListEndpoint, ListFilters, PaginatedResult, RestoreEndpoint, BatchCreateEndpoint, BatchDeleteEndpoint, BatchRestoreEndpoint, BatchUpdateEndpoint, BatchUpdateItem, AggregateEndpoint, AggregateOptions, AggregateResult, BatchUpsertEndpoint, CloneEndpoint, UpsertEndpoint, SearchEndpoint, SearchOptions, SearchResult, ExportEndpoint, ImportEndpoint, VersionCompareEndpoint, VersionHistoryEndpoint, VersionReadEndpoint, VersionRollbackEndpoint, AdapterBundle } from 'hono-crud/internal';
|
|
3
|
+
import { Env } from 'hono';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal query builder interface used for type-safe method calls.
|
|
8
|
+
* All Drizzle query builders satisfy this interface at runtime.
|
|
9
|
+
*/
|
|
10
|
+
interface QueryBuilder extends PromiseLike<unknown[]> {
|
|
11
|
+
where(condition: unknown): QueryBuilder;
|
|
12
|
+
limit(n: number): QueryBuilder;
|
|
13
|
+
offset(n: number): QueryBuilder;
|
|
14
|
+
orderBy(...columns: unknown[]): QueryBuilder;
|
|
15
|
+
set(data: Record<string, unknown>): QueryBuilder;
|
|
16
|
+
values(data: Record<string, unknown> | Record<string, unknown>[]): QueryBuilder;
|
|
17
|
+
returning(): QueryBuilder;
|
|
18
|
+
onConflictDoUpdate(config: {
|
|
19
|
+
target: unknown[];
|
|
20
|
+
set: Record<string, unknown>;
|
|
21
|
+
where?: unknown;
|
|
22
|
+
}): QueryBuilder;
|
|
23
|
+
onConflictDoNothing(config?: {
|
|
24
|
+
target?: unknown[];
|
|
25
|
+
}): QueryBuilder;
|
|
26
|
+
onDuplicateKeyUpdate(config: {
|
|
27
|
+
set: Record<string, unknown>;
|
|
28
|
+
}): QueryBuilder;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Internal database interface used for type-safe method calls.
|
|
32
|
+
* All Drizzle databases (PostgreSQL, MySQL, SQLite) satisfy this interface at runtime.
|
|
33
|
+
*/
|
|
34
|
+
interface Database {
|
|
35
|
+
select(fields?: Record<string, unknown>): {
|
|
36
|
+
from(table: Table): QueryBuilder;
|
|
37
|
+
};
|
|
38
|
+
insert(table: Table): QueryBuilder;
|
|
39
|
+
update(table: Table): QueryBuilder;
|
|
40
|
+
delete(table: Table): QueryBuilder;
|
|
41
|
+
transaction<T>(fn: (tx: Database) => Promise<T>): Promise<T>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Casts a database to the internal Database interface for method calls.
|
|
45
|
+
* This is safe because all Drizzle databases have these methods at runtime.
|
|
46
|
+
*/
|
|
47
|
+
declare function cast<T>(instance: T): Database;
|
|
48
|
+
/**
|
|
49
|
+
* Base constraint for Drizzle database types.
|
|
50
|
+
* Your database type must have select, insert, update, delete, and transaction methods.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { drizzle } from 'drizzle-orm/postgres-js';
|
|
55
|
+
* import * as schema from './schema';
|
|
56
|
+
*
|
|
57
|
+
* const database = drizzle(client, { schema });
|
|
58
|
+
*
|
|
59
|
+
* // Pass typeof database as the DB generic parameter
|
|
60
|
+
* class UserCreate extends DrizzleCreateEndpoint<Env, UserMeta, typeof database> {
|
|
61
|
+
* db = database; // Full type safety!
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
interface DrizzleDatabaseConstraint {
|
|
66
|
+
select: unknown;
|
|
67
|
+
insert: unknown;
|
|
68
|
+
update: unknown;
|
|
69
|
+
delete: unknown;
|
|
70
|
+
transaction: unknown;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* @deprecated Pass your database type as a generic parameter instead
|
|
74
|
+
*/
|
|
75
|
+
type DrizzleDatabase = DrizzleDatabaseConstraint;
|
|
76
|
+
/**
|
|
77
|
+
* @deprecated Pass your database type as a generic parameter instead
|
|
78
|
+
*/
|
|
79
|
+
type DrizzleDB = DrizzleDatabaseConstraint;
|
|
80
|
+
/**
|
|
81
|
+
* Drizzle SQL dialect identifier used to branch dialect-specific behavior
|
|
82
|
+
* (e.g. native upsert syntax: `ON CONFLICT DO UPDATE` for sqlite/pg vs
|
|
83
|
+
* `ON DUPLICATE KEY UPDATE` for mysql).
|
|
84
|
+
*
|
|
85
|
+
* The default for {@link createDrizzleCrud} is `'sqlite'` (preserves
|
|
86
|
+
* pre-existing portable behavior). Set explicitly when targeting PostgreSQL
|
|
87
|
+
* or MySQL to enable the appropriate code paths.
|
|
88
|
+
*/
|
|
89
|
+
type DrizzleDialect = 'sqlite' | 'pg' | 'mysql';
|
|
90
|
+
/**
|
|
91
|
+
* Type helper for defining Hono Env with database in Variables.
|
|
92
|
+
* Use this when injecting the database via middleware.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { DrizzleEnv } from 'hono-crud/adapters/drizzle';
|
|
97
|
+
*
|
|
98
|
+
* type AppEnv = DrizzleEnv<typeof db>;
|
|
99
|
+
*
|
|
100
|
+
* const app = new Hono<AppEnv>();
|
|
101
|
+
*
|
|
102
|
+
* app.use('*', async (c, next) => {
|
|
103
|
+
* c.set('db', db);
|
|
104
|
+
* await next();
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* // Endpoints can now access db from context automatically
|
|
108
|
+
* class ProjectCreate extends DrizzleCreateEndpoint<AppEnv, typeof projectMeta> {
|
|
109
|
+
* _meta = projectMeta;
|
|
110
|
+
* // No db property needed - comes from context!
|
|
111
|
+
* }
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
type DrizzleEnv<DB = DrizzleDatabaseConstraint> = {
|
|
115
|
+
Variables: {
|
|
116
|
+
db: DB;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Gets the Drizzle table from the model.
|
|
121
|
+
*/
|
|
122
|
+
declare function getTable<M extends MetaInput>(meta: M): Table;
|
|
123
|
+
/**
|
|
124
|
+
* Gets a column from the table with proper type safety.
|
|
125
|
+
* Uses drizzle-orm's getTableColumns for type-safe column access.
|
|
126
|
+
*
|
|
127
|
+
* @param table - The Drizzle table
|
|
128
|
+
* @param field - The field/column name
|
|
129
|
+
* @returns The column
|
|
130
|
+
* @throws Error if the column is not found in the table
|
|
131
|
+
*/
|
|
132
|
+
declare function getColumn(table: Table, field: string): Column;
|
|
133
|
+
/**
|
|
134
|
+
* Loads related records for a given item using Drizzle queries.
|
|
135
|
+
*/
|
|
136
|
+
declare function loadDrizzleRelation<T extends Record<string, unknown>>(db: DrizzleDatabase, item: T, relationName: string, relationConfig: RelationConfig<Table>): Promise<T>;
|
|
137
|
+
/**
|
|
138
|
+
* Loads all requested relations for an item.
|
|
139
|
+
* Note: For multiple items, use `batchLoadDrizzleRelations` to avoid N+1 queries.
|
|
140
|
+
*/
|
|
141
|
+
declare function loadDrizzleRelations<T extends Record<string, unknown>, M extends MetaInput>(db: DrizzleDatabase, item: T, meta: M, includeOptions?: IncludeOptions): Promise<T>;
|
|
142
|
+
/**
|
|
143
|
+
* Batch loads relations for multiple items to avoid N+1 queries.
|
|
144
|
+
* Instead of N queries per relation, this uses 1 query per relation using inArray().
|
|
145
|
+
*/
|
|
146
|
+
declare function batchLoadDrizzleRelations<T extends Record<string, unknown>, M extends MetaInput>(db: DrizzleDatabase, items: T[], meta: M, includeOptions?: IncludeOptions): Promise<T[]>;
|
|
147
|
+
/**
|
|
148
|
+
* Builds a where condition from filter conditions.
|
|
149
|
+
*/
|
|
150
|
+
declare function buildWhereCondition(table: Table, filter: FilterCondition): SQL | undefined;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Drizzle Create endpoint.
|
|
154
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
155
|
+
*
|
|
156
|
+
* The database can be provided in three ways:
|
|
157
|
+
* 1. Direct property: `db = myDb;`
|
|
158
|
+
* 2. Context injection via middleware: `c.set('db', myDb)`
|
|
159
|
+
* 3. Factory function: `createDrizzleCrud(db, meta)`
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* // Pattern 1: Direct property (backward compatible)
|
|
164
|
+
* class UserCreate extends DrizzleCreateEndpoint<Env, typeof userMeta> {
|
|
165
|
+
* _meta = userMeta;
|
|
166
|
+
* db = db;
|
|
167
|
+
* }
|
|
168
|
+
*
|
|
169
|
+
* // Pattern 2: Context injection (cleanest - no db property needed)
|
|
170
|
+
* class UserCreate extends DrizzleCreateEndpoint<AppEnv, typeof userMeta> {
|
|
171
|
+
* _meta = userMeta;
|
|
172
|
+
* // db comes from c.set('db', myDb) in middleware
|
|
173
|
+
* }
|
|
174
|
+
*
|
|
175
|
+
* // Pattern 3: Factory function (no _meta or db needed)
|
|
176
|
+
* const User = createDrizzleCrud(db, userMeta);
|
|
177
|
+
* class UserCreate extends User.Create {
|
|
178
|
+
* schema = { tags: ['Users'] };
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare abstract class DrizzleCreateEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends CreateEndpoint<E, M> {
|
|
183
|
+
/**
|
|
184
|
+
* Drizzle database instance.
|
|
185
|
+
* Can be undefined if using context-based injection via middleware.
|
|
186
|
+
*/
|
|
187
|
+
db?: DrizzleDatabase;
|
|
188
|
+
/**
|
|
189
|
+
* Whether to wrap create and nested operations in a transaction.
|
|
190
|
+
* When true, the entire create operation (including nested writes) will be atomic.
|
|
191
|
+
* @default false
|
|
192
|
+
*/
|
|
193
|
+
protected useTransaction: boolean;
|
|
194
|
+
/** Current transaction context (set during transaction execution) */
|
|
195
|
+
protected _tx?: DrizzleDatabase;
|
|
196
|
+
/**
|
|
197
|
+
* Gets the database instance to use. Checks in order:
|
|
198
|
+
* 1. Transaction context (if in transaction)
|
|
199
|
+
* 2. Direct property
|
|
200
|
+
* 3. Context variables (if middleware injected)
|
|
201
|
+
*/
|
|
202
|
+
protected getDb(): DrizzleDatabase;
|
|
203
|
+
protected getTable(): Table;
|
|
204
|
+
/**
|
|
205
|
+
* Gets a related table from the relation config.
|
|
206
|
+
*/
|
|
207
|
+
protected getRelatedTable(relationConfig: RelationConfig): Table | undefined;
|
|
208
|
+
create(data: ModelObject<M['model']>, tx?: unknown): Promise<ModelObject<M['model']>>;
|
|
209
|
+
/**
|
|
210
|
+
* Creates nested related records.
|
|
211
|
+
*/
|
|
212
|
+
protected createNested(parentId: string | number, relationName: string, relationConfig: RelationConfig, data: unknown, tx?: unknown): Promise<unknown[]>;
|
|
213
|
+
/**
|
|
214
|
+
* Override handle to wrap in transaction when useTransaction is true.
|
|
215
|
+
*/
|
|
216
|
+
handle(): Promise<Response>;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Drizzle Read endpoint.
|
|
220
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
221
|
+
*
|
|
222
|
+
* Supports soft delete filtering when the model has `softDelete` configured.
|
|
223
|
+
* Soft-deleted records are excluded by default.
|
|
224
|
+
*
|
|
225
|
+
* Supports relation includes via `?include=relation1,relation2`.
|
|
226
|
+
*/
|
|
227
|
+
declare abstract class DrizzleReadEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends ReadEndpoint<E, M> {
|
|
228
|
+
/** Drizzle database instance */
|
|
229
|
+
db?: DrizzleDatabase;
|
|
230
|
+
/** Gets the database instance from property or context */
|
|
231
|
+
protected getDb(): DrizzleDatabase;
|
|
232
|
+
protected getTable(): Table;
|
|
233
|
+
protected getColumn(field: string): Column;
|
|
234
|
+
read(lookupValue: string, additionalFilters?: Record<string, string>, includeOptions?: IncludeOptions): Promise<ModelObject<M['model']> | null>;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Drizzle Update endpoint.
|
|
238
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
239
|
+
*
|
|
240
|
+
* Supports soft delete filtering when the model has `softDelete` configured.
|
|
241
|
+
* Soft-deleted records cannot be updated.
|
|
242
|
+
*/
|
|
243
|
+
declare abstract class DrizzleUpdateEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends UpdateEndpoint<E, M> {
|
|
244
|
+
/** Drizzle database instance */
|
|
245
|
+
db?: DrizzleDatabase;
|
|
246
|
+
/**
|
|
247
|
+
* Whether to wrap update and nested operations in a transaction.
|
|
248
|
+
* When true, the entire update operation (including nested writes) will be atomic.
|
|
249
|
+
* @default false
|
|
250
|
+
*/
|
|
251
|
+
protected useTransaction: boolean;
|
|
252
|
+
/** Current transaction context (set during transaction execution) */
|
|
253
|
+
protected _tx?: DrizzleDatabase;
|
|
254
|
+
/** Gets the database instance from property, transaction, or context */
|
|
255
|
+
protected getDb(): DrizzleDatabase;
|
|
256
|
+
protected getTable(): Table;
|
|
257
|
+
protected getColumn(field: string): Column;
|
|
258
|
+
/**
|
|
259
|
+
* Gets a related table from the relation config.
|
|
260
|
+
*/
|
|
261
|
+
protected getRelatedTable(relationConfig: RelationConfig): Table | undefined;
|
|
262
|
+
/**
|
|
263
|
+
* Finds an existing record for audit logging.
|
|
264
|
+
*/
|
|
265
|
+
protected findExisting(lookupValue: string, additionalFilters?: Record<string, string>, tx?: unknown): Promise<ModelObject<M['model']> | null>;
|
|
266
|
+
update(lookupValue: string, data: Partial<ModelObject<M['model']>>, additionalFilters?: Record<string, string>, tx?: unknown): Promise<ModelObject<M['model']> | null>;
|
|
267
|
+
/**
|
|
268
|
+
* Processes nested write operations.
|
|
269
|
+
*/
|
|
270
|
+
protected processNestedWrites(parentId: string | number, relationName: string, relationConfig: RelationConfig, operations: NestedUpdateInput, tx?: unknown): Promise<NestedWriteResult>;
|
|
271
|
+
/**
|
|
272
|
+
* Override handle to wrap in transaction when useTransaction is true.
|
|
273
|
+
*/
|
|
274
|
+
handle(): Promise<Response>;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Drizzle Delete endpoint.
|
|
278
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
279
|
+
*
|
|
280
|
+
* Supports soft delete when the model has `softDelete` configured.
|
|
281
|
+
* When soft delete is enabled, sets the deletion timestamp instead of removing the record.
|
|
282
|
+
*/
|
|
283
|
+
declare abstract class DrizzleDeleteEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends DeleteEndpoint<E, M> {
|
|
284
|
+
/** Drizzle database instance */
|
|
285
|
+
db?: DrizzleDatabase;
|
|
286
|
+
/**
|
|
287
|
+
* Whether to wrap delete and cascade operations in a transaction.
|
|
288
|
+
* When true, the entire delete operation (including cascade deletes) will be atomic.
|
|
289
|
+
* @default false
|
|
290
|
+
*/
|
|
291
|
+
protected useTransaction: boolean;
|
|
292
|
+
/** Current transaction context (set during transaction execution) */
|
|
293
|
+
protected _tx?: DrizzleDatabase;
|
|
294
|
+
/** Gets the database instance from property, transaction, or context */
|
|
295
|
+
protected getDb(): DrizzleDatabase;
|
|
296
|
+
protected getTable(): Table;
|
|
297
|
+
protected getColumn(field: string): Column;
|
|
298
|
+
/**
|
|
299
|
+
* Gets a related table from the relation config.
|
|
300
|
+
*/
|
|
301
|
+
protected getRelatedTable(relationConfig: RelationConfig): Table | undefined;
|
|
302
|
+
/**
|
|
303
|
+
* Finds a record without deleting it (for constraint checks).
|
|
304
|
+
*/
|
|
305
|
+
findForDelete(lookupValue: string, additionalFilters?: Record<string, string>, tx?: unknown): Promise<ModelObject<M['model']> | null>;
|
|
306
|
+
delete(lookupValue: string, additionalFilters?: Record<string, string>, tx?: unknown): Promise<ModelObject<M['model']> | null>;
|
|
307
|
+
/**
|
|
308
|
+
* Counts related records for restrict check.
|
|
309
|
+
*/
|
|
310
|
+
protected countRelated(parentId: string | number, _relationName: string, relationConfig: RelationConfig, tx?: unknown): Promise<number>;
|
|
311
|
+
/**
|
|
312
|
+
* Deletes related records for cascade delete.
|
|
313
|
+
*/
|
|
314
|
+
protected deleteRelated(parentId: string | number, _relationName: string, relationConfig: RelationConfig, tx?: unknown): Promise<number>;
|
|
315
|
+
/**
|
|
316
|
+
* Sets foreign key to null for related records.
|
|
317
|
+
*/
|
|
318
|
+
protected nullifyRelated(parentId: string | number, _relationName: string, relationConfig: RelationConfig, tx?: unknown): Promise<number>;
|
|
319
|
+
/**
|
|
320
|
+
* Override handle to wrap in transaction when useTransaction is true.
|
|
321
|
+
*/
|
|
322
|
+
handle(): Promise<Response>;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Drizzle List endpoint with filtering, sorting, and pagination.
|
|
326
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
327
|
+
*
|
|
328
|
+
* Supports soft delete filtering when the model has `softDelete` configured:
|
|
329
|
+
* - By default, soft-deleted records are excluded
|
|
330
|
+
* - Use `?withDeleted=true` to include deleted records
|
|
331
|
+
* - Use `?onlyDeleted=true` to show only deleted records
|
|
332
|
+
*/
|
|
333
|
+
declare abstract class DrizzleListEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends ListEndpoint<E, M> {
|
|
334
|
+
/** Drizzle database instance */
|
|
335
|
+
db?: DrizzleDatabase;
|
|
336
|
+
/**
|
|
337
|
+
* SQL dialect of the underlying Drizzle database.
|
|
338
|
+
*
|
|
339
|
+
* Drives the substring-match function emitted on the `?search=` path:
|
|
340
|
+
* `INSTR` for sqlite, `POSITION` for pg, `LOCATE` for mysql — matching
|
|
341
|
+
* how the dedicated search endpoint (`DrizzleSearchEndpoint`) and the
|
|
342
|
+
* export endpoint (`DrizzleExportEndpoint`) emit search SQL. Set via
|
|
343
|
+
* {@link createDrizzleCrud}'s `options.dialect`, or override in your
|
|
344
|
+
* subclass. Defaults to `'sqlite'` for backward compatibility with
|
|
345
|
+
* pre-existing portable behavior.
|
|
346
|
+
*
|
|
347
|
+
* See {@link DrizzleUpsertEndpoint.dialect} for full semantics.
|
|
348
|
+
*/
|
|
349
|
+
protected dialect: DrizzleDialect;
|
|
350
|
+
/** Gets the database instance from property or context */
|
|
351
|
+
protected getDb(): DrizzleDatabase;
|
|
352
|
+
protected getTable(): Table;
|
|
353
|
+
protected getColumn(field: string): Column;
|
|
354
|
+
list(filters: ListFilters): Promise<PaginatedResult<ModelObject<M['model']>>>;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Drizzle Restore endpoint for un-deleting soft-deleted records.
|
|
358
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
359
|
+
*
|
|
360
|
+
* Only works with models that have `softDelete` enabled.
|
|
361
|
+
* Sets the deletion timestamp back to null.
|
|
362
|
+
*/
|
|
363
|
+
declare abstract class DrizzleRestoreEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends RestoreEndpoint<E, M> {
|
|
364
|
+
/** Drizzle database instance */
|
|
365
|
+
db?: DrizzleDatabase;
|
|
366
|
+
/**
|
|
367
|
+
* Whether to wrap restore operation in a transaction.
|
|
368
|
+
* Useful when combined with hooks that perform additional operations.
|
|
369
|
+
* @default false
|
|
370
|
+
*/
|
|
371
|
+
protected useTransaction: boolean;
|
|
372
|
+
/** Current transaction context (set during transaction execution) */
|
|
373
|
+
protected _tx?: DrizzleDatabase;
|
|
374
|
+
/** Gets the database instance from property, transaction, or context */
|
|
375
|
+
protected getDb(): DrizzleDatabase;
|
|
376
|
+
protected getTable(): Table;
|
|
377
|
+
protected getColumn(field: string): Column;
|
|
378
|
+
restore(lookupValue: string, additionalFilters?: Record<string, string>, tx?: unknown): Promise<ModelObject<M['model']> | null>;
|
|
379
|
+
/**
|
|
380
|
+
* Override handle to wrap in transaction when useTransaction is true.
|
|
381
|
+
*/
|
|
382
|
+
handle(): Promise<Response>;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Drizzle Batch Create endpoint.
|
|
387
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
388
|
+
*/
|
|
389
|
+
declare abstract class DrizzleBatchCreateEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends BatchCreateEndpoint<E, M> {
|
|
390
|
+
/** Drizzle database instance */
|
|
391
|
+
db?: DrizzleDatabase;
|
|
392
|
+
/** Gets the database instance from property or context */
|
|
393
|
+
protected getDb(): DrizzleDatabase;
|
|
394
|
+
protected getTable(): Table;
|
|
395
|
+
batchCreate(items: Partial<ModelObject<M['model']>>[]): Promise<ModelObject<M['model']>[]>;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Drizzle Batch Update endpoint.
|
|
399
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
400
|
+
*
|
|
401
|
+
* Supports soft delete filtering (cannot update deleted records).
|
|
402
|
+
*/
|
|
403
|
+
declare abstract class DrizzleBatchUpdateEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends BatchUpdateEndpoint<E, M> {
|
|
404
|
+
/** Drizzle database instance */
|
|
405
|
+
db?: DrizzleDatabase;
|
|
406
|
+
/** Gets the database instance from property or context */
|
|
407
|
+
protected getDb(): DrizzleDatabase;
|
|
408
|
+
protected getTable(): Table;
|
|
409
|
+
protected getColumn(field: string): Column;
|
|
410
|
+
batchUpdate(items: BatchUpdateItem<ModelObject<M['model']>>[]): Promise<{
|
|
411
|
+
updated: ModelObject<M['model']>[];
|
|
412
|
+
notFound: string[];
|
|
413
|
+
}>;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Drizzle Batch Delete endpoint.
|
|
417
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
418
|
+
*
|
|
419
|
+
* Supports soft delete when the model has `softDelete` configured.
|
|
420
|
+
*/
|
|
421
|
+
declare abstract class DrizzleBatchDeleteEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends BatchDeleteEndpoint<E, M> {
|
|
422
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
423
|
+
db?: DrizzleDatabase;
|
|
424
|
+
/** Gets the database instance from property or context. */
|
|
425
|
+
protected getDb(): DrizzleDatabase;
|
|
426
|
+
protected getTable(): Table;
|
|
427
|
+
protected getColumn(field: string): Column;
|
|
428
|
+
batchDelete(ids: string[]): Promise<{
|
|
429
|
+
deleted: ModelObject<M['model']>[];
|
|
430
|
+
notFound: string[];
|
|
431
|
+
}>;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Drizzle Batch Restore endpoint for un-deleting soft-deleted records.
|
|
435
|
+
* Works with any Drizzle dialect (PostgreSQL, MySQL, SQLite).
|
|
436
|
+
*
|
|
437
|
+
* Only works with models that have `softDelete` enabled.
|
|
438
|
+
*/
|
|
439
|
+
declare abstract class DrizzleBatchRestoreEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends BatchRestoreEndpoint<E, M> {
|
|
440
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
441
|
+
db?: DrizzleDatabase;
|
|
442
|
+
/** Gets the database instance from property or context. */
|
|
443
|
+
protected getDb(): DrizzleDatabase;
|
|
444
|
+
protected getTable(): Table;
|
|
445
|
+
protected getColumn(field: string): Column;
|
|
446
|
+
batchRestore(ids: string[]): Promise<{
|
|
447
|
+
restored: ModelObject<M['model']>[];
|
|
448
|
+
notFound: string[];
|
|
449
|
+
}>;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Emit a dialect-correct case-insensitive substring-match SQL expression.
|
|
454
|
+
*
|
|
455
|
+
* Replaces the previous `LOWER(col) LIKE LOWER('%needle%') ESCAPE '\\'`
|
|
456
|
+
* approach: by using the native substring-position function for each
|
|
457
|
+
* dialect, the needle is never injected into a pattern, so LIKE
|
|
458
|
+
* wildcards (`%`, `_`) and the LIKE escape character lose their
|
|
459
|
+
* special meaning entirely — no wildcard surface means no escape
|
|
460
|
+
* needed.
|
|
461
|
+
*
|
|
462
|
+
* Dialect mapping:
|
|
463
|
+
* - `'sqlite'` → `INSTR(LOWER(col), LOWER(needle)) > 0`
|
|
464
|
+
* - `'pg'` → `POSITION(LOWER(needle) IN LOWER(col)) > 0`
|
|
465
|
+
* - `'mysql'` → `LOCATE(LOWER(needle), LOWER(col)) > 0`
|
|
466
|
+
*
|
|
467
|
+
* All three return a 1-based position (or 0 for "not found"), so
|
|
468
|
+
* `> 0` is the dialect-agnostic predicate that means "needle is a
|
|
469
|
+
* substring of col".
|
|
470
|
+
*/
|
|
471
|
+
declare function substringMatch(col: Column | SQL, needle: string, dialect: DrizzleDialect): SQL;
|
|
472
|
+
/**
|
|
473
|
+
* Drizzle Upsert endpoint.
|
|
474
|
+
* Creates a record if it doesn't exist, updates it if it does.
|
|
475
|
+
*/
|
|
476
|
+
declare abstract class DrizzleUpsertEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends UpsertEndpoint<E, M> {
|
|
477
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
478
|
+
db?: DrizzleDatabase;
|
|
479
|
+
/**
|
|
480
|
+
* SQL dialect of the underlying Drizzle database.
|
|
481
|
+
*
|
|
482
|
+
* Used to branch dialect-specific behavior — currently the native upsert
|
|
483
|
+
* path (`ON CONFLICT DO UPDATE` for sqlite/pg vs `ON DUPLICATE KEY UPDATE`
|
|
484
|
+
* for mysql). Set via {@link createDrizzleCrud}'s `options.dialect`, or
|
|
485
|
+
* override in your subclass. Defaults to `'sqlite'` for backward
|
|
486
|
+
* compatibility with pre-existing portable behavior.
|
|
487
|
+
*/
|
|
488
|
+
protected dialect: DrizzleDialect;
|
|
489
|
+
/** Gets the database instance from property or context. */
|
|
490
|
+
protected getDb(): DrizzleDatabase;
|
|
491
|
+
protected getTable(): Table;
|
|
492
|
+
protected getColumn(field: string): Column;
|
|
493
|
+
findExisting(data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']> | null>;
|
|
494
|
+
create(data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']>>;
|
|
495
|
+
update(existing: ModelObject<M['model']>, data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']>>;
|
|
496
|
+
/**
|
|
497
|
+
* Performs a native database upsert using ON CONFLICT DO UPDATE (PostgreSQL/SQLite)
|
|
498
|
+
* or ON DUPLICATE KEY UPDATE (MySQL).
|
|
499
|
+
*
|
|
500
|
+
* Note: This method cannot accurately determine if the record was created or updated.
|
|
501
|
+
* The `created` flag is set to `false` by default. If you need accurate create/update
|
|
502
|
+
* tracking, use the standard upsert pattern (useNativeUpsert = false).
|
|
503
|
+
*/
|
|
504
|
+
protected nativeUpsert(data: Partial<ModelObject<M['model']>>, _tx?: unknown): Promise<{
|
|
505
|
+
data: ModelObject<M['model']>;
|
|
506
|
+
created: boolean;
|
|
507
|
+
}>;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Drizzle Batch Upsert endpoint.
|
|
511
|
+
*/
|
|
512
|
+
declare abstract class DrizzleBatchUpsertEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends BatchUpsertEndpoint<E, M> {
|
|
513
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
514
|
+
db?: DrizzleDatabase;
|
|
515
|
+
/**
|
|
516
|
+
* SQL dialect of the underlying Drizzle database. See
|
|
517
|
+
* {@link DrizzleUpsertEndpoint.dialect} for full semantics.
|
|
518
|
+
*/
|
|
519
|
+
protected dialect: DrizzleDialect;
|
|
520
|
+
/** Gets the database instance from property or context. */
|
|
521
|
+
protected getDb(): DrizzleDatabase;
|
|
522
|
+
protected getTable(): Table;
|
|
523
|
+
protected getColumn(field: string): Column;
|
|
524
|
+
findExisting(data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']> | null>;
|
|
525
|
+
create(data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']>>;
|
|
526
|
+
update(existing: ModelObject<M['model']>, data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']>>;
|
|
527
|
+
/**
|
|
528
|
+
* Performs a native database batch upsert using ON CONFLICT DO UPDATE (PostgreSQL/SQLite)
|
|
529
|
+
* or ON DUPLICATE KEY UPDATE (MySQL).
|
|
530
|
+
*
|
|
531
|
+
* Note: This method cannot accurately determine which records were created vs updated.
|
|
532
|
+
* All records are marked as `created: false`. If you need accurate tracking,
|
|
533
|
+
* use the standard batch upsert pattern (useNativeUpsert = false).
|
|
534
|
+
*/
|
|
535
|
+
protected nativeBatchUpsert(items: Partial<ModelObject<M['model']>>[], _tx?: unknown): Promise<{
|
|
536
|
+
items: Array<{
|
|
537
|
+
data: ModelObject<M['model']>;
|
|
538
|
+
created: boolean;
|
|
539
|
+
index: number;
|
|
540
|
+
}>;
|
|
541
|
+
createdCount: number;
|
|
542
|
+
updatedCount: number;
|
|
543
|
+
totalCount: number;
|
|
544
|
+
errors?: Array<{
|
|
545
|
+
index: number;
|
|
546
|
+
error: string;
|
|
547
|
+
}>;
|
|
548
|
+
}>;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Drizzle Version History endpoint.
|
|
552
|
+
* Lists all versions for a record.
|
|
553
|
+
*/
|
|
554
|
+
declare abstract class DrizzleVersionHistoryEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends VersionHistoryEndpoint<E, M> {
|
|
555
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
556
|
+
db?: DrizzleDatabase;
|
|
557
|
+
/** Gets the database instance from property or context. */
|
|
558
|
+
protected getDb(): DrizzleDatabase;
|
|
559
|
+
protected getTable(): Table;
|
|
560
|
+
protected getColumn(field: string): Column;
|
|
561
|
+
protected recordExists(lookupValue: string): Promise<boolean>;
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Drizzle Version Read endpoint.
|
|
565
|
+
* Gets a specific version of a record.
|
|
566
|
+
*/
|
|
567
|
+
declare abstract class DrizzleVersionReadEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends VersionReadEndpoint<E, M> {
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Drizzle Version Compare endpoint.
|
|
571
|
+
* Compares two versions of a record.
|
|
572
|
+
*/
|
|
573
|
+
declare abstract class DrizzleVersionCompareEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends VersionCompareEndpoint<E, M> {
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Drizzle Version Rollback endpoint.
|
|
577
|
+
* Rolls back a record to a previous version.
|
|
578
|
+
*/
|
|
579
|
+
declare abstract class DrizzleVersionRollbackEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends VersionRollbackEndpoint<E, M> {
|
|
580
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
581
|
+
db?: DrizzleDatabase;
|
|
582
|
+
/** Gets the database instance from property or context. */
|
|
583
|
+
protected getDb(): DrizzleDatabase;
|
|
584
|
+
protected getTable(): Table;
|
|
585
|
+
protected getColumn(field: string): Column;
|
|
586
|
+
rollback(lookupValue: string, versionData: Record<string, unknown>, newVersion: number): Promise<ModelObject<M['model']>>;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Drizzle Aggregate endpoint.
|
|
590
|
+
* Computes aggregations (COUNT, SUM, AVG, MIN, MAX) with GROUP BY support.
|
|
591
|
+
*/
|
|
592
|
+
declare abstract class DrizzleAggregateEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends AggregateEndpoint<E, M> {
|
|
593
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
594
|
+
db?: DrizzleDatabase;
|
|
595
|
+
/** Gets the database instance from property or context. */
|
|
596
|
+
protected getDb(): DrizzleDatabase;
|
|
597
|
+
protected getTable(): Table;
|
|
598
|
+
protected getColumn(field: string): Column;
|
|
599
|
+
aggregate(options: AggregateOptions): Promise<AggregateResult>;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Drizzle Search endpoint.
|
|
603
|
+
* Provides full-text search with relevance scoring and highlighting.
|
|
604
|
+
*
|
|
605
|
+
* For PostgreSQL, this can leverage native tsvector/tsquery for better performance.
|
|
606
|
+
* For SQLite/MySQL/PostgreSQL non-vector mode, it falls back to dialect-native
|
|
607
|
+
* substring-position search (INSTR/POSITION/LOCATE) with in-memory scoring.
|
|
608
|
+
*
|
|
609
|
+
* Features:
|
|
610
|
+
* - PostgreSQL: Uses to_tsvector() and plainto_tsquery() for native full-text search
|
|
611
|
+
* - Fallback: dialect-native substring match with in-memory scoring
|
|
612
|
+
* - Configurable field weights
|
|
613
|
+
* - Search modes: 'any' (OR), 'all' (AND), 'phrase' (exact)
|
|
614
|
+
* - Highlighted snippets
|
|
615
|
+
* - Combined with standard list filters
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```ts
|
|
619
|
+
* class ArticleSearch extends DrizzleSearchEndpoint<Env, typeof articleMeta> {
|
|
620
|
+
* _meta = articleMeta;
|
|
621
|
+
* db = db;
|
|
622
|
+
* schema = { tags: ['Articles'], summary: 'Search articles' };
|
|
623
|
+
*
|
|
624
|
+
* protected searchFields = ['title', 'content', 'tags'];
|
|
625
|
+
* protected fieldWeights = { title: 2.0, content: 1.0, tags: 1.5 };
|
|
626
|
+
* protected filterFields = ['status', 'categoryId'];
|
|
627
|
+
* }
|
|
628
|
+
* ```
|
|
629
|
+
*/
|
|
630
|
+
declare abstract class DrizzleSearchEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends SearchEndpoint<E, M> {
|
|
631
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
632
|
+
db?: DrizzleDatabase;
|
|
633
|
+
/**
|
|
634
|
+
* SQL dialect of the underlying Drizzle database.
|
|
635
|
+
*
|
|
636
|
+
* Drives the substring-match function emitted on the fallback search path:
|
|
637
|
+
* `INSTR` for sqlite, `POSITION` for pg, `LOCATE` for mysql. Set via
|
|
638
|
+
* {@link createDrizzleCrud}'s `options.dialect`, or override in your
|
|
639
|
+
* subclass. Defaults to `'sqlite'` for backward compatibility with
|
|
640
|
+
* pre-existing portable behavior.
|
|
641
|
+
*
|
|
642
|
+
* See {@link DrizzleUpsertEndpoint.dialect} for full semantics.
|
|
643
|
+
*/
|
|
644
|
+
protected dialect: DrizzleDialect;
|
|
645
|
+
/** Gets the database instance from property or context. */
|
|
646
|
+
protected getDb(): DrizzleDatabase;
|
|
647
|
+
/**
|
|
648
|
+
* Enable PostgreSQL native full-text search.
|
|
649
|
+
* When true and vectorColumn is set, uses tsvector/tsquery.
|
|
650
|
+
* When false, uses substring-position-based search with in-memory scoring.
|
|
651
|
+
*/
|
|
652
|
+
protected useNativeSearch: boolean;
|
|
653
|
+
/**
|
|
654
|
+
* PostgreSQL tsvector column name for native full-text search.
|
|
655
|
+
* If set and useNativeSearch is true, searches against this column.
|
|
656
|
+
*/
|
|
657
|
+
protected vectorColumn?: string;
|
|
658
|
+
/**
|
|
659
|
+
* PostgreSQL text search configuration (e.g., 'english', 'simple').
|
|
660
|
+
*/
|
|
661
|
+
protected vectorConfig: string;
|
|
662
|
+
protected getTable(): Table;
|
|
663
|
+
protected getColumn(field: string): Column;
|
|
664
|
+
/**
|
|
665
|
+
* Performs search on database.
|
|
666
|
+
*/
|
|
667
|
+
search(options: SearchOptions, filters: ListFilters): Promise<SearchResult<ModelObject<M['model']>>>;
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Drizzle Export endpoint.
|
|
671
|
+
* Exports data in CSV or JSON format with support for filtering and field selection.
|
|
672
|
+
*/
|
|
673
|
+
declare abstract class DrizzleExportEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends ExportEndpoint<E, M> {
|
|
674
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
675
|
+
db?: DrizzleDatabase;
|
|
676
|
+
/**
|
|
677
|
+
* SQL dialect of the underlying Drizzle database. Drives the
|
|
678
|
+
* substring-match function emitted on the `?search=` path. See
|
|
679
|
+
* {@link DrizzleUpsertEndpoint.dialect} for full semantics.
|
|
680
|
+
*/
|
|
681
|
+
protected dialect: DrizzleDialect;
|
|
682
|
+
/** Gets the database instance from property or context. */
|
|
683
|
+
protected getDb(): DrizzleDatabase;
|
|
684
|
+
protected getTable(): Table;
|
|
685
|
+
protected getColumn(field: string): Column;
|
|
686
|
+
list(filters: ListFilters): Promise<PaginatedResult<ModelObject<M['model']>>>;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Drizzle Import endpoint.
|
|
690
|
+
* Imports data from CSV or JSON with support for create and upsert modes.
|
|
691
|
+
*/
|
|
692
|
+
declare abstract class DrizzleImportEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends ImportEndpoint<E, M> {
|
|
693
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
694
|
+
db?: DrizzleDatabase;
|
|
695
|
+
/** Gets the database instance from property or context. */
|
|
696
|
+
protected getDb(): DrizzleDatabase;
|
|
697
|
+
protected getTable(): Table;
|
|
698
|
+
protected getColumn(field: string): Column;
|
|
699
|
+
/**
|
|
700
|
+
* Finds an existing record by upsert keys.
|
|
701
|
+
*/
|
|
702
|
+
findExisting(data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']> | null>;
|
|
703
|
+
/**
|
|
704
|
+
* Creates a new record.
|
|
705
|
+
*/
|
|
706
|
+
create(data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']>>;
|
|
707
|
+
/**
|
|
708
|
+
* Updates an existing record.
|
|
709
|
+
*/
|
|
710
|
+
update(existing: ModelObject<M['model']>, data: Partial<ModelObject<M['model']>>): Promise<ModelObject<M['model']>>;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Drizzle Clone endpoint.
|
|
714
|
+
*
|
|
715
|
+
* Reads the source row by `lookupField`, lets the base `CloneEndpoint`
|
|
716
|
+
* strip primary keys + `excludeFromClone` fields and apply body overrides,
|
|
717
|
+
* then inserts the result with a freshly-generated primary key.
|
|
718
|
+
*
|
|
719
|
+
* Soft-deleted source rows are not cloneable — the SELECT predicate adds
|
|
720
|
+
* `IS NULL` on the soft-delete column when the model has soft-delete
|
|
721
|
+
* configured.
|
|
722
|
+
*
|
|
723
|
+
* Composite-PK note: the base class strips ALL primary keys but this
|
|
724
|
+
* implementation only fills `primaryKeys[0]` via `generateId()`. Models with
|
|
725
|
+
* composite primary keys must subclass and override `createClone` to fill the
|
|
726
|
+
* remaining columns.
|
|
727
|
+
*
|
|
728
|
+
* Override `generateId()` to swap UUIDv4 for ULID/snowflake/etc.
|
|
729
|
+
*/
|
|
730
|
+
declare abstract class DrizzleCloneEndpoint<E extends Env = Env, M extends MetaInput = MetaInput> extends CloneEndpoint<E, M> {
|
|
731
|
+
/** Drizzle database instance. Can be undefined if using context injection. */
|
|
732
|
+
db?: DrizzleDatabase;
|
|
733
|
+
/** Gets the database instance from property or context. */
|
|
734
|
+
protected getDb(): DrizzleDatabase;
|
|
735
|
+
protected getTable(): Table;
|
|
736
|
+
protected getColumn(field: string): Column;
|
|
737
|
+
/** Generates the primary-key value for the cloned row. Defaults to UUIDv4. */
|
|
738
|
+
protected generateId(): string;
|
|
739
|
+
findSource(lookupValue: string, additionalFilters?: Record<string, string>): Promise<ModelObject<M['model']> | null>;
|
|
740
|
+
createClone(data: ModelObject<M['model']>): Promise<ModelObject<M['model']>>;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Return type of createDrizzleCrud factory function.
|
|
745
|
+
* Provides type-safe base classes for all CRUD operations.
|
|
746
|
+
*/
|
|
747
|
+
type ConfiguredDrizzleEndpoint<TEndpoint, M extends MetaInput> = new () => TEndpoint & {
|
|
748
|
+
_meta: M;
|
|
749
|
+
db: DrizzleDatabaseConstraint;
|
|
750
|
+
};
|
|
751
|
+
interface DrizzleCrudClasses<M extends MetaInput, E extends Env = Env> {
|
|
752
|
+
Create: ConfiguredDrizzleEndpoint<DrizzleCreateEndpoint<E, M>, M>;
|
|
753
|
+
Read: ConfiguredDrizzleEndpoint<DrizzleReadEndpoint<E, M>, M>;
|
|
754
|
+
Update: ConfiguredDrizzleEndpoint<DrizzleUpdateEndpoint<E, M>, M>;
|
|
755
|
+
Delete: ConfiguredDrizzleEndpoint<DrizzleDeleteEndpoint<E, M>, M>;
|
|
756
|
+
List: ConfiguredDrizzleEndpoint<DrizzleListEndpoint<E, M>, M>;
|
|
757
|
+
Restore: ConfiguredDrizzleEndpoint<DrizzleRestoreEndpoint<E, M>, M>;
|
|
758
|
+
Upsert: ConfiguredDrizzleEndpoint<DrizzleUpsertEndpoint<E, M>, M>;
|
|
759
|
+
Search: ConfiguredDrizzleEndpoint<DrizzleSearchEndpoint<E, M>, M>;
|
|
760
|
+
BatchCreate: ConfiguredDrizzleEndpoint<DrizzleBatchCreateEndpoint<E, M>, M>;
|
|
761
|
+
BatchUpdate: ConfiguredDrizzleEndpoint<DrizzleBatchUpdateEndpoint<E, M>, M>;
|
|
762
|
+
BatchDelete: ConfiguredDrizzleEndpoint<DrizzleBatchDeleteEndpoint<E, M>, M>;
|
|
763
|
+
BatchRestore: ConfiguredDrizzleEndpoint<DrizzleBatchRestoreEndpoint<E, M>, M>;
|
|
764
|
+
BatchUpsert: ConfiguredDrizzleEndpoint<DrizzleBatchUpsertEndpoint<E, M>, M>;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Options accepted by {@link createDrizzleCrud}.
|
|
768
|
+
*/
|
|
769
|
+
interface CreateDrizzleCrudOptions {
|
|
770
|
+
/**
|
|
771
|
+
* SQL dialect of the Drizzle database. Used to branch dialect-specific
|
|
772
|
+
* behavior such as native upsert syntax (`ON CONFLICT DO UPDATE` for
|
|
773
|
+
* `'sqlite'`/`'pg'` vs `ON DUPLICATE KEY UPDATE` for `'mysql'`).
|
|
774
|
+
*
|
|
775
|
+
* Defaults to `'sqlite'`, which preserves the pre-existing portable
|
|
776
|
+
* behavior for callers that don't specify a dialect.
|
|
777
|
+
*
|
|
778
|
+
* @default 'sqlite'
|
|
779
|
+
*/
|
|
780
|
+
dialect?: DrizzleDialect;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Creates a set of Drizzle CRUD endpoint base classes with db and meta pre-configured.
|
|
784
|
+
* This is the cleanest pattern - no need to set `_meta` or `db` in your classes.
|
|
785
|
+
*
|
|
786
|
+
* @param db - Your Drizzle database instance
|
|
787
|
+
* @param meta - The meta object (from defineMeta)
|
|
788
|
+
* @param options - Optional factory options. Pass `{ dialect: 'pg' | 'mysql' | 'sqlite' }`
|
|
789
|
+
* to enable dialect-specific code paths (e.g. native upsert syntax).
|
|
790
|
+
* Defaults to `{ dialect: 'sqlite' }`.
|
|
791
|
+
* @returns Object with Create, Read, Update, Delete, List base classes
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```ts
|
|
795
|
+
* import { createDrizzleCrud } from 'hono-crud/adapters/drizzle';
|
|
796
|
+
*
|
|
797
|
+
* const projectMeta = defineMeta({ model: ProjectModel, fields: projectSchemas.insert });
|
|
798
|
+
* const Project = createDrizzleCrud(db, projectMeta, { dialect: 'pg' });
|
|
799
|
+
*
|
|
800
|
+
* // Now define endpoints with minimal boilerplate:
|
|
801
|
+
* class ProjectCreate extends Project.Create {
|
|
802
|
+
* schema = { tags: ["Projects"], summary: "Create a new project" };
|
|
803
|
+
* }
|
|
804
|
+
*
|
|
805
|
+
* class ProjectList extends Project.List {
|
|
806
|
+
* schema = { tags: ["Projects"], summary: "List all projects" };
|
|
807
|
+
* protected searchFields = ["name", "clientName"];
|
|
808
|
+
* protected filterFields = ["status"];
|
|
809
|
+
* }
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
declare function createDrizzleCrud<M extends MetaInput, E extends Env = Env>(db: DrizzleDatabaseConstraint, meta: M, options?: CreateDrizzleCrudOptions): DrizzleCrudClasses<M, E>;
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Drizzle-Zod schema utilities.
|
|
816
|
+
*
|
|
817
|
+
* This module provides helpers for generating Zod schemas from Drizzle tables
|
|
818
|
+
* using drizzle-zod. This allows automatic schema generation for CRUD operations.
|
|
819
|
+
*
|
|
820
|
+
* Note: drizzle-zod is an optional peer dependency. These utilities will only
|
|
821
|
+
* work if drizzle-zod is installed.
|
|
822
|
+
*
|
|
823
|
+
* @example
|
|
824
|
+
* ```ts
|
|
825
|
+
* import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
|
826
|
+
* import { createDrizzleSchemas } from 'hono-crud/adapters/drizzle';
|
|
827
|
+
*
|
|
828
|
+
* const users = pgTable('users', {
|
|
829
|
+
* id: uuid('id').primaryKey().defaultRandom(),
|
|
830
|
+
* name: text('name').notNull(),
|
|
831
|
+
* email: text('email').notNull().unique(),
|
|
832
|
+
* createdAt: timestamp('created_at').defaultNow(),
|
|
833
|
+
* });
|
|
834
|
+
*
|
|
835
|
+
* const { select: UserSchema, insert: CreateUserSchema } = await createDrizzleSchemas(users);
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Duck-typed interface for Drizzle tables.
|
|
841
|
+
* This allows compatibility across different drizzle-orm versions and package installations.
|
|
842
|
+
*/
|
|
843
|
+
type DrizzleTable = {
|
|
844
|
+
_: {
|
|
845
|
+
name: string;
|
|
846
|
+
columns: Record<string, unknown>;
|
|
847
|
+
};
|
|
848
|
+
};
|
|
849
|
+
/**
|
|
850
|
+
* Re-export createSelectSchema from drizzle-zod.
|
|
851
|
+
* Creates a Zod schema for SELECT queries (all columns as required/optional based on table definition).
|
|
852
|
+
*
|
|
853
|
+
* @param table - Drizzle table definition
|
|
854
|
+
* @param refine - Optional refinements for specific columns
|
|
855
|
+
* @returns Promise resolving to a Zod schema for the table's select type
|
|
856
|
+
*
|
|
857
|
+
* @example
|
|
858
|
+
* ```ts
|
|
859
|
+
* import { users } from './schema';
|
|
860
|
+
* import { createSelectSchema } from 'hono-crud/adapters/drizzle';
|
|
861
|
+
*
|
|
862
|
+
* const UserSchema = await createSelectSchema(users);
|
|
863
|
+
* type User = z.infer<typeof UserSchema>;
|
|
864
|
+
* ```
|
|
865
|
+
*/
|
|
866
|
+
declare function createSelectSchema<T extends DrizzleTable>(table: T, refine?: Record<string, z.ZodTypeAny>): Promise<z.ZodObject<Record<string, z.ZodTypeAny>>>;
|
|
867
|
+
/**
|
|
868
|
+
* Re-export createInsertSchema from drizzle-zod.
|
|
869
|
+
* Creates a Zod schema for INSERT queries (columns with defaults become optional).
|
|
870
|
+
*
|
|
871
|
+
* @param table - Drizzle table definition
|
|
872
|
+
* @param refine - Optional refinements for specific columns
|
|
873
|
+
* @returns Promise resolving to a Zod schema for the table's insert type
|
|
874
|
+
*
|
|
875
|
+
* @example
|
|
876
|
+
* ```ts
|
|
877
|
+
* import { users } from './schema';
|
|
878
|
+
* import { createInsertSchema } from 'hono-crud/adapters/drizzle';
|
|
879
|
+
*
|
|
880
|
+
* const CreateUserSchema = await createInsertSchema(users);
|
|
881
|
+
* type CreateUser = z.infer<typeof CreateUserSchema>;
|
|
882
|
+
* ```
|
|
883
|
+
*/
|
|
884
|
+
declare function createInsertSchema<T extends DrizzleTable>(table: T, refine?: Record<string, z.ZodTypeAny>): Promise<z.ZodObject<Record<string, z.ZodTypeAny>>>;
|
|
885
|
+
/**
|
|
886
|
+
* Re-export createUpdateSchema from drizzle-zod (if available).
|
|
887
|
+
* Creates a Zod schema for UPDATE queries (all columns become optional).
|
|
888
|
+
*
|
|
889
|
+
* Note: createUpdateSchema may not be available in older versions of drizzle-zod.
|
|
890
|
+
* Use createInsertSchema(table).partial() as an alternative.
|
|
891
|
+
*
|
|
892
|
+
* @param table - Drizzle table definition
|
|
893
|
+
* @param refine - Optional refinements for specific columns
|
|
894
|
+
* @returns Promise resolving to a Zod schema for the table's update type
|
|
895
|
+
*
|
|
896
|
+
* @example
|
|
897
|
+
* ```ts
|
|
898
|
+
* import { users } from './schema';
|
|
899
|
+
* import { createUpdateSchema } from 'hono-crud/adapters/drizzle';
|
|
900
|
+
*
|
|
901
|
+
* const UpdateUserSchema = await createUpdateSchema(users);
|
|
902
|
+
* type UpdateUser = z.infer<typeof UpdateUserSchema>;
|
|
903
|
+
* ```
|
|
904
|
+
*/
|
|
905
|
+
declare function createUpdateSchema<T extends DrizzleTable>(table: T, refine?: Record<string, z.ZodTypeAny>): Promise<z.ZodObject<Record<string, z.ZodTypeAny>>>;
|
|
906
|
+
/**
|
|
907
|
+
* Result of createDrizzleSchemas helper.
|
|
908
|
+
*/
|
|
909
|
+
interface DrizzleSchemas {
|
|
910
|
+
/** Schema for SELECT queries (full record) */
|
|
911
|
+
select: z.ZodObject<Record<string, z.ZodTypeAny>>;
|
|
912
|
+
/** Schema for INSERT queries (required fields only) */
|
|
913
|
+
insert: z.ZodObject<Record<string, z.ZodTypeAny>>;
|
|
914
|
+
/** Schema for UPDATE queries (all fields optional) */
|
|
915
|
+
update: z.ZodObject<Record<string, z.ZodTypeAny>>;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Creates all three common schemas (select, insert, update) for a Drizzle table.
|
|
919
|
+
*
|
|
920
|
+
* This is a convenience helper that generates:
|
|
921
|
+
* - `select`: Full record schema for reading data
|
|
922
|
+
* - `insert`: Schema for creating new records (with date coercion for JSON input)
|
|
923
|
+
* - `update`: Partial schema for updating records (with date coercion for JSON input)
|
|
924
|
+
*
|
|
925
|
+
* Date coercion is automatically applied to timestamp/date columns, allowing
|
|
926
|
+
* both Date objects and ISO 8601 date strings as input values.
|
|
927
|
+
*
|
|
928
|
+
* @param table - Drizzle table definition
|
|
929
|
+
* @param options - Optional configuration
|
|
930
|
+
* @param options.insertRefine - Refinements for insert schema
|
|
931
|
+
* @param options.selectRefine - Refinements for select schema
|
|
932
|
+
* @param options.updateRefine - Refinements for update schema
|
|
933
|
+
* @param options.coerceDates - Whether to coerce date strings to Date objects (default: true)
|
|
934
|
+
* @returns Promise resolving to object containing select, insert, and update schemas
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```ts
|
|
938
|
+
* import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
|
939
|
+
* import { createDrizzleSchemas, defineModel, defineMeta } from 'hono-crud/adapters/drizzle';
|
|
940
|
+
* import { z } from 'zod';
|
|
941
|
+
*
|
|
942
|
+
* const users = pgTable('users', {
|
|
943
|
+
* id: uuid('id').primaryKey().defaultRandom(),
|
|
944
|
+
* name: text('name').notNull(),
|
|
945
|
+
* email: text('email').notNull().unique(),
|
|
946
|
+
* });
|
|
947
|
+
*
|
|
948
|
+
* // Generate schemas from table
|
|
949
|
+
* const schemas = await createDrizzleSchemas(users, {
|
|
950
|
+
* insertRefine: {
|
|
951
|
+
* email: z.string().email(), // Add email validation
|
|
952
|
+
* },
|
|
953
|
+
* });
|
|
954
|
+
*
|
|
955
|
+
* // Use with hono-crud model
|
|
956
|
+
* const UserModel = defineModel({
|
|
957
|
+
* tableName: 'users',
|
|
958
|
+
* schema: schemas.select,
|
|
959
|
+
* primaryKeys: ['id'],
|
|
960
|
+
* table: users,
|
|
961
|
+
* });
|
|
962
|
+
* ```
|
|
963
|
+
*/
|
|
964
|
+
declare function createDrizzleSchemas<T extends DrizzleTable>(table: T, options?: {
|
|
965
|
+
insertRefine?: Record<string, z.ZodTypeAny>;
|
|
966
|
+
selectRefine?: Record<string, z.ZodTypeAny>;
|
|
967
|
+
updateRefine?: Record<string, z.ZodTypeAny>;
|
|
968
|
+
/** Whether to coerce date strings to Date objects. Default: true */
|
|
969
|
+
coerceDates?: boolean;
|
|
970
|
+
}): Promise<DrizzleSchemas>;
|
|
971
|
+
/**
|
|
972
|
+
* Checks if drizzle-zod is available (from cache only).
|
|
973
|
+
* Returns true only if drizzle-zod has been successfully loaded before.
|
|
974
|
+
* @returns true if drizzle-zod has been loaded
|
|
975
|
+
*/
|
|
976
|
+
declare function isDrizzleZodAvailable(): boolean;
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Drizzle adapter bundle for use with `defineEndpoints`.
|
|
980
|
+
*
|
|
981
|
+
* Populates the 11 verbs Drizzle implements natively plus a stub
|
|
982
|
+
* `CloneEndpoint` (throws on request — subclass to implement).
|
|
983
|
+
*
|
|
984
|
+
* @example
|
|
985
|
+
* ```ts
|
|
986
|
+
* const endpoints = defineEndpoints({ meta, create: {}, search: { fields: ['name'] } }, DrizzleAdapters);
|
|
987
|
+
* ```
|
|
988
|
+
*/
|
|
989
|
+
declare const DrizzleAdapters: AdapterBundle;
|
|
990
|
+
|
|
991
|
+
export { type CreateDrizzleCrudOptions, type Database, DrizzleAdapters, DrizzleAggregateEndpoint, DrizzleBatchCreateEndpoint, DrizzleBatchDeleteEndpoint, DrizzleBatchRestoreEndpoint, DrizzleBatchUpdateEndpoint, DrizzleBatchUpsertEndpoint, DrizzleCloneEndpoint, DrizzleCreateEndpoint, type DrizzleCrudClasses, type DrizzleDB, type DrizzleDatabase, type DrizzleDatabaseConstraint, DrizzleDeleteEndpoint, type DrizzleDialect, type DrizzleEnv, DrizzleExportEndpoint, DrizzleImportEndpoint, DrizzleListEndpoint, DrizzleReadEndpoint, DrizzleRestoreEndpoint, type DrizzleSchemas, DrizzleSearchEndpoint, DrizzleUpdateEndpoint, DrizzleUpsertEndpoint, DrizzleVersionCompareEndpoint, DrizzleVersionHistoryEndpoint, DrizzleVersionReadEndpoint, DrizzleVersionRollbackEndpoint, type QueryBuilder, batchLoadDrizzleRelations, buildWhereCondition, cast, createDrizzleCrud, createDrizzleSchemas, createInsertSchema, createSelectSchema, createUpdateSchema, getColumn, getTable, isDrizzleZodAvailable, loadDrizzleRelation, loadDrizzleRelations, substringMatch };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import {getTableColumns,eq,inArray,between,isNull,isNotNull,ilike,like,notInArray,lte,lt,gte,gt,ne as ne$1,sql,and,or,desc,asc}from'drizzle-orm';import {UpsertEndpoint,BatchUpsertEndpoint,VersionHistoryEndpoint,VersionReadEndpoint,VersionCompareEndpoint,VersionRollbackEndpoint,AggregateEndpoint,computeAggregations,SearchEndpoint,searchInMemory,ExportEndpoint,ImportEndpoint,CloneEndpoint,CreateEndpoint,getLogger,ReadEndpoint,UpdateEndpoint,DeleteEndpoint,ListEndpoint,RestoreEndpoint,BatchCreateEndpoint,BatchUpdateEndpoint,BatchDeleteEndpoint,BatchRestoreEndpoint}from'hono-crud/internal';import {z}from'zod';function X(a){return a}function f(a){if(!a.model.table)throw new Error(`Model ${a.model.tableName} does not have a table reference`);return a.model.table}function b(a,e){let t=getTableColumns(a),o=t[e];if(!o)throw new Error(`Column '${e}' not found in table. Available columns: ${Object.keys(t).join(", ")}`);return o}async function pe(a,e,t,o){if(!o.table)return e;let n=o.table;switch(o.type){case "hasOne":{let r=o.localKey||"id",s=e[r];if(s==null)return e;let i=b(n,o.foreignKey),l=await a.select().from(n).where(eq(i,s)).limit(1);return {...e,[t]:l[0]||null}}case "hasMany":{let r=o.localKey||"id",s=e[r];if(s==null)return {...e,[t]:[]};let i=b(n,o.foreignKey),l=await a.select().from(n).where(eq(i,s));return {...e,[t]:l}}case "belongsTo":{let r=e[o.foreignKey];if(r==null)return {...e,[t]:null};let s=b(n,o.localKey||"id"),i=await a.select().from(n).where(eq(s,r)).limit(1);return {...e,[t]:i[0]||null}}default:return e}}async function de(a,e,t,o){if(!o?.relations?.length||!t.model.relations)return e;let n={...e};for(let r of o.relations){let s=t.model.relations[r];s&&(n=await pe(a,n,r,s));}return n}async function S(a,e,t,o){if(!e.length||!o?.relations?.length||!t.model.relations)return e;let n=e.map(r=>({...r}));for(let r of o.relations){let s=t.model.relations[r];if(!s||!s.table)continue;let i=s.table;switch(s.type){case "hasOne":case "hasMany":{let l=s.localKey||"id",d=[...new Set(n.map(p=>p[l]).filter(p=>p!=null))];if(d.length===0){n=n.map(p=>({...p,[r]:s.type==="hasMany"?[]:null}));continue}let u=b(i,s.foreignKey),c=await a.select().from(i).where(inArray(u,d)),m=new Map;for(let p of c){let g=p[s.foreignKey];m.has(g)||m.set(g,[]),m.get(g).push(p);}n=n.map(p=>{let g=p[l],h=m.get(g)||[];return {...p,[r]:s.type==="hasMany"?h:h[0]||null}});break}case "belongsTo":{let l=s.localKey||"id",d=[...new Set(n.map(p=>p[s.foreignKey]).filter(p=>p!=null))];if(d.length===0){n=n.map(p=>({...p,[r]:null}));continue}let u=b(i,l),c=await a.select().from(i).where(inArray(u,d)),m=new Map;for(let p of c){let g=p[l];m.set(g,p);}n=n.map(p=>{let g=p[s.foreignKey];return {...p,[r]:m.get(g)||null}});break}}}return n}function O(a,e){let t=b(a,e.field);switch(e.operator){case "eq":return eq(t,e.value);case "ne":return ne$1(t,e.value);case "gt":return gt(t,e.value);case "gte":return gte(t,e.value);case "lt":return lt(t,e.value);case "lte":return lte(t,e.value);case "in":return inArray(t,e.value);case "nin":return notInArray(t,e.value);case "like":return like(t,e.value);case "ilike":return ilike(t,e.value);case "null":return e.value?isNull(t):isNotNull(t);case "between":{let[o,n]=e.value;return between(t,o,n)}default:return}}function D(a){let e=a;if(e._tx)return e._tx;if(e.db)return e.db;let t=e.context?.get?.("db");if(t)return t;throw new Error(`Database not configured. Either:
|
|
2
|
+
1. Set db property: db = myDb;
|
|
3
|
+
2. Use middleware: c.set("db", myDb);
|
|
4
|
+
3. Use factory: createDrizzleCrud(db, meta)`)}function ee(a,e,t){switch(t){case "pg":return sql`POSITION(LOWER(${e}) IN LOWER(${a})) > 0`;case "mysql":return sql`LOCATE(LOWER(${e}), LOWER(${a})) > 0`;default:return sql`INSTR(LOWER(${a}), LOWER(${e})) > 0`}}function Je(a){return a.split(/\s+/).filter(e=>e.length>0)}var j=class extends UpsertEndpoint{db;dialect="sqlite";getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async findExisting(e){let t=this.getTable(),o=this.getUpsertKeys(),n=this.getSoftDeleteConfig(),r=[];for(let i of o){let l=e[i];l!==void 0&&r.push(eq(this.getColumn(i),l));}return n.enabled&&r.push(isNull(this.getColumn(n.field))),r.length===0?null:(await this.getDb().select().from(t).where(and(...r)).limit(1))[0]||null}async create(e){let t=this.getTable(),o=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(t).values(o).returning())[0]}async update(e,t){let o=this.getTable(),n=this._meta.model.primaryKeys[0],r=e[n];return (await this.getDb().update(o).set(this.applyManagedUpdateFields(t)).where(eq(this.getColumn(n),r)).returning())[0]}async nativeUpsert(e,t){let o=this.getTable(),n=this.getUpsertKeys(),r=this._meta.model.primaryKeys[0],s=this.getSoftDeleteConfig(),i=this.getTimestampsConfig(),l=this.applyManagedInsertFields(e,"drizzle"),d={};for(let[h,y]of Object.entries(e))!n.includes(h)&&h!==r&&(this.createOnlyFields?.includes(h)||(d[h]=y));i.enabled&&(d[i.updatedAt]=Date.now());let u=n.map(h=>this.getColumn(h)),c;s.enabled&&(c=isNull(this.getColumn(s.field)));let m=Object.keys(d).length>0?d:{[r]:sql`${this.getColumn(r)}`},p=this.getDb().insert(o).values(l);return this.dialect==="mysql"?{data:(await p.onDuplicateKeyUpdate({set:m}).returning())[0],created:false}:{data:(await p.onConflictDoUpdate({target:u,set:m,where:c}).returning())[0],created:false}}},_=class extends BatchUpsertEndpoint{db;dialect="sqlite";getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async findExisting(e){let t=this.getTable(),o=this.getUpsertKeys(),n=[];for(let s of o){let i=e[s];i!==void 0&&n.push(eq(this.getColumn(s),i));}return n.length===0?null:(await this.getDb().select().from(t).where(and(...n)).limit(1))[0]||null}async create(e){let t=this.getTable(),o=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(t).values(o).returning())[0]}async update(e,t){let o=this.getTable(),n=this._meta.model.primaryKeys[0],r=e[n];return (await this.getDb().update(o).set(this.applyManagedUpdateFields(t)).where(eq(this.getColumn(n),r)).returning())[0]}async nativeBatchUpsert(e,t){if(e.length===0)return {items:[],createdCount:0,updatedCount:0,totalCount:0};let o=this.getTable(),n=this.getUpsertKeys(),r=this._meta.model.primaryKeys[0],s=this.getTimestampsConfig(),i=e.map(g=>this.applyManagedInsertFields(g,"drizzle")),l={},d=e[0];for(let g of Object.keys(d))!n.includes(g)&&g!==r&&(this.createOnlyFields?.includes(g)||(l[g]=sql`excluded.${sql.identifier(g)}`));s.enabled&&(l[s.updatedAt]=Date.now());let u=n.map(g=>this.getColumn(g)),c=Object.keys(l).length>0?l:{[r]:sql`${this.getColumn(r)}`},m=this.getDb().insert(o).values(i),p=await(this.dialect==="mysql"?m.onDuplicateKeyUpdate({set:c}):m.onConflictDoUpdate({target:u,set:c})).returning();return {items:p.map((g,h)=>({data:g,created:false,index:h})),createdCount:0,updatedCount:p.length,totalCount:p.length}}},ge=class extends VersionHistoryEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async recordExists(e){let t=this.getTable(),o=await this.getDb().select({count:sql`count(*)`}).from(t).where(eq(this.getColumn("id"),e));return Number(o[0]?.count)>0}},me=class extends VersionReadEndpoint{},be=class extends VersionCompareEndpoint{},he=class extends VersionRollbackEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async rollback(e,t,o){let n=this.getTable(),r=this.getVersioningConfig().field;return (await this.getDb().update(n).set({...t,[r]:o}).where(eq(this.getColumn("id"),e)).returning())[0]}},G=class extends AggregateEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async aggregate(e){let t=this.getTable(),o=[],n=this.getSoftDeleteConfig();if(n.enabled){let{query:i}=await this.getValidatedData();i?.withDeleted===true||i?.withDeleted==="true"||o.push(isNull(this.getColumn(n.field)));}if(e.filters)for(let[i,l]of Object.entries(e.filters))if(typeof l=="object"&&l!==null)for(let[d,u]of Object.entries(l)){let c=O(t,{field:i,operator:d,value:u});c&&o.push(c);}else o.push(eq(this.getColumn(i),l));let r=o.length>0?and(...o):void 0,s=await this.getDb().select().from(t).where(r);return computeAggregations(s,e)}},I=class extends SearchEndpoint{db;dialect="sqlite";getDb(){return D(this)}useNativeSearch=false;vectorColumn;vectorConfig="english";getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async search(e,t){let o=this.getTable(),n=[],r=this.getSoftDeleteConfig();r.enabled&&(t.options.onlyDeleted?n.push(isNotNull(this.getColumn(r.field))):t.options.withDeleted||n.push(isNull(this.getColumn(r.field))));for(let w of t.filters){let M=O(o,w);M&&n.push(M);}let s=this.getSearchableFields(),i=e.fields||Object.keys(s);if(this.useNativeSearch&&this.vectorColumn){let w=this.getColumn(this.vectorColumn),M=e.mode==="phrase"?sql`phraseto_tsquery(${this.vectorConfig}, ${e.query})`:e.mode==="all"?sql`plainto_tsquery(${this.vectorConfig}, ${e.query})`:sql`to_tsquery(${this.vectorConfig}, ${e.query.split(/\s+/).join(" | ")})`;n.push(sql`${w} @@ ${M}`);}else {let w=(M,x)=>{try{let ie=this.getColumn(M);return ee(sql`CAST(${ie} AS TEXT)`,x,this.dialect)}catch{return}};if(e.mode==="all"){let M=Je(e.query);if(M.length>0){let x=[];for(let ie of M){let ue=i.map(ae=>w(ae,ie)).filter(ae=>ae!==void 0);ue.length>0&&x.push(or(...ue));}x.length>0&&n.push(and(...x));}}else {let M=i.map(x=>w(x,e.query)).filter(x=>x!==void 0);M.length>0&&n.push(or(...M));}}let l=n.length>0?and(...n):void 0,d=await this.getDb().select({count:sql`count(*)`}).from(o).where(l),u=Number(d[0]?.count)||0,c=this.getDb().select().from(o).where(l);if(t.options.order_by){let w=this.getColumn(t.options.order_by),M=t.options.order_by_direction==="desc"?desc:asc;c=c.orderBy(M(w));}let m=t.options.page||1,p=t.options.per_page||this.defaultPerPage;c=c.limit(p).offset((m-1)*p);let g=await c,h=e.mode==="all"?{...e,mode:"any"}:e,y=searchInMemory(g,h,s),R={relations:t.options.include||[]},$=y.map(w=>w.item),se=await S(this.getDb(),$,this._meta,R);return {items:y.map((w,M)=>({...w,item:se[M]})),totalCount:u}}},H=class extends ExportEndpoint{db;dialect="sqlite";getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async list(e){let t=this.getTable(),o=[],n=this.getSoftDeleteConfig();if(n.enabled){let h=this.getColumn(n.field);e.options.onlyDeleted?o.push(isNotNull(h)):e.options.withDeleted||o.push(isNull(h));}for(let h of e.filters){let y=O(t,h);y&&o.push(y);}if(e.options.search&&this.searchFields.length>0){let h=e.options.search,y=this.searchFields.map(R=>{let $=this.getColumn(R);return ee($,h,this.dialect)});o.push(or(...y));}let r=o.length>0?and(...o):void 0,s=await this.getDb().select({count:sql`count(*)`}).from(t).where(r),i=Number(s[0]?.count)||0,l=this.getDb().select().from(t).where(r);if(e.options.order_by){let h=this.getColumn(e.options.order_by),y=e.options.order_by_direction==="desc"?desc:asc;l=l.orderBy(y(h));}let d=e.options.page||1,u=e.options.per_page||this.defaultPerPage;l=l.limit(u).offset((d-1)*u);let c=await l,m={relations:e.options.include||[]},p=await S(this.getDb(),c,this._meta,m),g=Math.ceil(i/u);return {result:p,result_info:{page:d,per_page:u,total_count:i,total_pages:g,has_next_page:d<g,has_prev_page:d>1}}}},J=class extends ImportEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async findExisting(e){let t=this.getTable(),o=this.getUpsertKeys(),n=this.getSoftDeleteConfig(),r=[];for(let i of o){let l=e[i];l!==void 0&&r.push(eq(this.getColumn(i),l));}return n.enabled&&r.push(isNull(this.getColumn(n.field))),r.length===0?null:(await this.getDb().select().from(t).where(and(...r)).limit(1))[0]||null}async create(e){let t=this.getTable(),o=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(t).values(o).returning())[0]}async update(e,t){let o=this.getTable(),n=this._meta.model.primaryKeys[0],r=e[n];return (await this.getDb().update(o).set(this.applyManagedUpdateFields(t)).where(eq(this.getColumn(n),r)).returning())[0]}},Y=class extends CloneEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}generateId(){return crypto.randomUUID()}async findSource(e,t){let o=this.getTable(),n=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),s=[eq(n,e)];if(t)for(let[l,d]of Object.entries(t))s.push(eq(this.getColumn(l),d));r.enabled&&s.push(isNull(this.getColumn(r.field)));let i=await this.getDb().select().from(o).where(and(...s)).limit(1);return i[0]?i[0]:null}async createClone(e){let t=this.getTable(),o=this.applyManagedInsertFields(e,"drizzle",()=>this.generateId());return (await this.getDb().insert(t).values(o).returning())[0]}};var U=class extends CreateEndpoint{db;useTransaction=false;getDb(){return D(this)}getTable(){return f(this._meta)}getRelatedTable(e){return e.table}async create(e,t){let o=t??this.getDb(),n=this.getTable(),r=this.applyManagedInsertFields(e,"drizzle");return (await o.insert(n).values(r).returning())[0]}async createNested(e,t,o,n,r){let s=r??this.getDb(),i=this.getRelatedTable(o);if(!i)return getLogger().warn(`Related table not found for ${t}. Add 'table' to the relation config.`),[];let l=Array.isArray(n)?n:[n],d=[];for(let u of l){if(typeof u!="object"||u===null)continue;let c={...u,id:crypto.randomUUID(),[o.foreignKey]:e},m=await s.insert(i).values(c).returning();m[0]&&d.push(m[0]);}return d}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},B=class extends ReadEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async read(e,t,o){let n=this.getTable(),r=this.getColumn(this.lookupField),s=this.getSoftDeleteConfig(),i=[eq(r,e)];if(t)for(let[u,c]of Object.entries(t))i.push(eq(this.getColumn(u),c));s.enabled&&i.push(isNull(this.getColumn(s.field)));let l=await this.getDb().select().from(n).where(and(...i)).limit(1);return l[0]?await de(this.getDb(),l[0],this._meta,o):null}},A=class extends UpdateEndpoint{db;useTransaction=false;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}getRelatedTable(e){return e.table}async findExisting(e,t,o){let n=o??this.getDb(),r=this.getTable(),s=this.getColumn(this.lookupField),i=this.getSoftDeleteConfig(),l=[eq(s,e)];if(t)for(let[u,c]of Object.entries(t))l.push(eq(this.getColumn(u),c));return i.enabled&&l.push(isNull(this.getColumn(i.field))),(await n.select().from(r).where(and(...l)).limit(1))[0]||null}async update(e,t,o,n){let r=n??this.getDb(),s=this.getTable(),i=this.getColumn(this.lookupField),l=this.getSoftDeleteConfig(),d=[eq(i,e)];if(o)for(let[c,m]of Object.entries(o))d.push(eq(this.getColumn(c),m));return l.enabled&&d.push(isNull(this.getColumn(l.field))),(await r.update(s).set(this.applyManagedUpdateFields(t)).where(and(...d)).returning())[0]||null}async processNestedWrites(e,t,o,n,r){let s=r??this.getDb(),i=this.getRelatedTable(o);if(!i)return getLogger().warn(`Related table not found for ${t}. Add 'table' to the relation config.`),{created:[],updated:[],deleted:[],connected:[],disconnected:[]};let l={created:[],updated:[],deleted:[],connected:[],disconnected:[]},d=b(i,o.foreignKey),u=b(i,"id");if(n.create){let c=Array.isArray(n.create)?n.create:[n.create];for(let m of c){if(typeof m!="object"||m===null)continue;let p={...m,id:crypto.randomUUID(),[o.foreignKey]:e},g=await s.insert(i).values(p).returning();g[0]&&l.created.push(g[0]);}}if(n.update)for(let c of n.update){if(!c.id||!(await s.select().from(i).where(and(eq(u,c.id),eq(d,e))).limit(1))[0])continue;let{id:p,...g}=c,h=await s.update(i).set(g).where(eq(u,p)).returning();h[0]&&l.updated.push(h[0]);}if(n.delete)for(let c of n.delete)(await s.delete(i).where(and(eq(u,c),eq(d,e))).returning())[0]&&l.deleted.push(c);if(n.connect)for(let c of n.connect)(await s.update(i).set({[o.foreignKey]:e}).where(eq(u,c)).returning())[0]&&l.connected.push(c);if(n.disconnect)for(let c of n.disconnect)(await s.update(i).set({[o.foreignKey]:null}).where(and(eq(u,c),eq(d,e))).returning())[0]&&l.disconnected.push(c);return l}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},L=class extends DeleteEndpoint{db;useTransaction=false;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}getRelatedTable(e){return e.table}async findForDelete(e,t,o){let n=o??this.getDb(),r=this.getTable(),s=this.getColumn(this.lookupField),i=this.getSoftDeleteConfig(),l=[eq(s,e)];if(t)for(let[u,c]of Object.entries(t))l.push(eq(this.getColumn(u),c));return i.enabled&&l.push(isNull(this.getColumn(i.field))),(await n.select().from(r).where(and(...l)).limit(1))[0]||null}async delete(e,t,o){let n=o??this.getDb(),r=this.getTable(),s=this.getColumn(this.lookupField),i=this.getSoftDeleteConfig(),l=[eq(s,e)];if(t)for(let[d,u]of Object.entries(t))l.push(eq(this.getColumn(d),u));return i.enabled&&l.push(isNull(this.getColumn(i.field))),i.enabled?(await n.update(r).set({[i.field]:new Date}).where(and(...l)).returning())[0]||null:(await n.delete(r).where(and(...l)).returning())[0]||null}async countRelated(e,t,o,n){let r=n??this.getDb(),s=this.getRelatedTable(o);if(!s)return 0;let i=b(s,o.foreignKey),l=await r.select({count:sql`count(*)`}).from(s).where(eq(i,e));return Number(l[0]?.count)||0}async deleteRelated(e,t,o,n){let r=n??this.getDb(),s=this.getRelatedTable(o);if(!s)return 0;let i=b(s,o.foreignKey);return (await r.delete(s).where(eq(i,e)).returning()).length}async nullifyRelated(e,t,o,n){let r=n??this.getDb(),s=this.getRelatedTable(o);if(!s)return 0;let i=b(s,o.foreignKey);return (await r.update(s).set({[o.foreignKey]:null}).where(eq(i,e)).returning()).length}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},K=class extends ListEndpoint{db;dialect="sqlite";getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async list(e){let t=this.getTable(),o=[],n=this.getSoftDeleteConfig();if(n.enabled){let y=this.getColumn(n.field);e.options.onlyDeleted?o.push(isNotNull(y)):e.options.withDeleted||o.push(isNull(y));}for(let y of e.filters){let R=O(t,y);R&&o.push(R);}if(e.options.search&&this.searchFields.length>0){let y=e.options.search,R=this.searchFields.map($=>{let se=this.getColumn($);return ee(se,y,this.dialect)});o.push(or(...R));}let r=o.length>0?and(...o):void 0,s=this.getDb(),i=await s.select({count:sql`count(*)`}).from(t).where(r),l=Number(i[0]?.count)||0,d=s.select().from(t).where(r);if(e.options.order_by){let y=this.getColumn(e.options.order_by),R=e.options.order_by_direction==="desc"?desc:asc;d=d.orderBy(R(y));}let u=e.options.page||1,c=e.options.per_page||this.defaultPerPage;d=d.limit(c).offset((u-1)*c);let m=await d,p={relations:e.options.include||[]},g=await S(this.getDb(),m,this._meta,p),h=Math.ceil(l/c);return {result:g,result_info:{page:u,per_page:c,total_count:l,total_pages:h,has_next_page:u<h,has_prev_page:u>1}}}},Z=class extends RestoreEndpoint{db;useTransaction=false;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async restore(e,t,o){let n=o??this.getDb(),r=this.getTable(),s=this.getColumn(this.lookupField),i=this.getSoftDeleteConfig(),l=[eq(s,e)];if(t)for(let[u,c]of Object.entries(t))l.push(eq(this.getColumn(u),c));return l.push(isNotNull(this.getColumn(i.field))),(await n.update(r).set({[i.field]:null}).where(and(...l)).returning())[0]||null}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}};var F=class extends BatchCreateEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}async batchCreate(e){let t=this.getTable(),o=e.map(r=>this.applyManagedInsertFields(r,"drizzle"));return await this.getDb().insert(t).values(o).returning()}},Q=class extends BatchUpdateEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async batchUpdate(e){let t=this.getTable(),o=this.getColumn(this.lookupField),n=this.getSoftDeleteConfig(),r=[],s=[];for(let i of e){let l=[eq(o,i.id)];n.enabled&&l.push(isNull(this.getColumn(n.field)));let d=await this.getDb().update(t).set(this.applyManagedUpdateFields(i.data)).where(and(...l)).returning();d[0]?r.push(d[0]):s.push(i.id);}return {updated:r,notFound:s}}},N=class extends BatchDeleteEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async batchDelete(e){let t=this.getTable(),o=this.getColumn(this.lookupField),n=this.getSoftDeleteConfig(),r=[inArray(o,e)];n.enabled&&r.push(isNull(this.getColumn(n.field)));let s;n.enabled?s=await this.getDb().update(t).set({[n.field]:new Date}).where(and(...r)).returning():s=await this.getDb().delete(t).where(and(...r)).returning();let i=s,l=new Set(i.map(u=>String(u[this.lookupField]))),d=e.filter(u=>!l.has(u));return {deleted:i,notFound:d}}},q=class extends BatchRestoreEndpoint{db;getDb(){return D(this)}getTable(){return f(this._meta)}getColumn(e){return b(this.getTable(),e)}async batchRestore(e){let t=this.getTable(),o=this.getColumn(this.lookupField),n=this.getSoftDeleteConfig(),r=[inArray(o,e),isNotNull(this.getColumn(n.field))],i=await this.getDb().update(t).set({[n.field]:null}).where(and(...r)).returning(),l=new Set(i.map(u=>String(u[this.lookupField]))),d=e.filter(u=>!l.has(u));return {restored:i,notFound:d}}};function ln(a,e,t){let o=t?.dialect??"sqlite";return {Create:class extends U{_meta=e;db=a},Read:class extends B{_meta=e;db=a},Update:class extends A{_meta=e;db=a},Delete:class extends L{_meta=e;db=a},List:class extends K{_meta=e;db=a;dialect=o},Restore:class extends Z{_meta=e;db=a},Upsert:class extends j{_meta=e;db=a;dialect=o},Search:class extends I{_meta=e;db=a;dialect=o},BatchCreate:class extends F{_meta=e;db=a},BatchUpdate:class extends Q{_meta=e;db=a},BatchDelete:class extends N{_meta=e;db=a},BatchRestore:class extends q{_meta=e;db=a},BatchUpsert:class extends _{_meta=e;db=a;dialect=o}}}var oe=null,Te=false,ne=null;async function re(){if(Te){if(ne)throw ne;return oe}Te=true;try{return oe=await import('drizzle-zod'),oe}catch{throw ne=new Error("drizzle-zod is not installed. Please install it: npm install drizzle-zod"),ne}}async function mt(a,e){return (await re()).createSelectSchema(a,e)}async function bt(a,e){return (await re()).createInsertSchema(a,e)}async function ht(a,e){let t=await re();return t.createUpdateSchema?t.createUpdateSchema(a,e):t.createInsertSchema(a,e).partial()}async function ft(a,e){let t=await re(),o=e?.coerceDates!==false,n=o?Mt(a):new Set,r=t.createSelectSchema(a,e?.selectRefine),s=t.createInsertSchema(a,e?.insertRefine),i;return t.createUpdateSchema?i=t.createUpdateSchema(a,e?.updateRefine):i=t.createInsertSchema(a,e?.updateRefine).partial(),o&&n.size>0&&(s=Re(s,n),i=Re(i,n)),{select:r,insert:s,update:i}}function zt(){return oe!==null}var Dt=z.preprocess(a=>{if(a instanceof Date)return a;if(typeof a=="string"){let e=new Date(a);if(!isNaN(e.getTime()))return e}return a},z.date()),yt=z.preprocess(a=>{if(a==null)return null;if(a instanceof Date)return a;if(typeof a=="string"){let e=new Date(a);if(!isNaN(e.getTime()))return e}return a},z.date().nullable());function Mt(a){let e=new Set,t=a;for(let[o,n]of Object.entries(t)){if(o==="_"||o==="$inferInsert"||o==="$inferSelect")continue;let r=n;if(!r||typeof r!="object")continue;let s=String(r.dataType??"").toLowerCase(),i=String(r.columnType??"").toLowerCase(),l=r.config,d=String(l?.dataType??"").toLowerCase();(s.includes("timestamp")||s.includes("date")||s.includes("datetime")||i.includes("pgtimestamp")||i.includes("pgdate")||i.includes("mysqltimestamp")||i.includes("mysqldate")||i.includes("sqlitetimestamp")||d.includes("timestamp")||d.includes("date"))&&e.add(o);}return e}function Re(a,e){if(e.size===0)return a;let t=a.shape,o={};for(let[n,r]of Object.entries(t))if(e.has(n)){let s=r.isOptional?.()??false,i=r.isNullable?.()??false,l=Dt;(i||s)&&(l=yt),s&&(l=l.optional()),o[n]=l;}else o[n]=r;return z.object(o)}var kn={CreateEndpoint:U,ListEndpoint:K,ReadEndpoint:B,UpdateEndpoint:A,DeleteEndpoint:L,RestoreEndpoint:Z,BatchCreateEndpoint:F,BatchUpdateEndpoint:Q,BatchDeleteEndpoint:N,BatchRestoreEndpoint:q,BatchUpsertEndpoint:_,SearchEndpoint:I,AggregateEndpoint:G,ExportEndpoint:H,ImportEndpoint:J,UpsertEndpoint:j,CloneEndpoint:Y};export{kn as DrizzleAdapters,G as DrizzleAggregateEndpoint,F as DrizzleBatchCreateEndpoint,N as DrizzleBatchDeleteEndpoint,q as DrizzleBatchRestoreEndpoint,Q as DrizzleBatchUpdateEndpoint,_ as DrizzleBatchUpsertEndpoint,Y as DrizzleCloneEndpoint,U as DrizzleCreateEndpoint,L as DrizzleDeleteEndpoint,H as DrizzleExportEndpoint,J as DrizzleImportEndpoint,K as DrizzleListEndpoint,B as DrizzleReadEndpoint,Z as DrizzleRestoreEndpoint,I as DrizzleSearchEndpoint,A as DrizzleUpdateEndpoint,j as DrizzleUpsertEndpoint,be as DrizzleVersionCompareEndpoint,ge as DrizzleVersionHistoryEndpoint,me as DrizzleVersionReadEndpoint,he as DrizzleVersionRollbackEndpoint,S as batchLoadDrizzleRelations,O as buildWhereCondition,X as cast,ln as createDrizzleCrud,ft as createDrizzleSchemas,bt as createInsertSchema,mt as createSelectSchema,ht as createUpdateSchema,b as getColumn,f as getTable,zt as isDrizzleZodAvailable,pe as loadDrizzleRelation,de as loadDrizzleRelations,ee as substringMatch};
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hono-crud/drizzle",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Drizzle ORM CRUD adapter for hono-crud",
|
|
5
|
+
"author": "Kauan Guesser <contato@kauan.net>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/kshdotdev/hono-crud.git",
|
|
10
|
+
"directory": "packages/drizzle"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/kshdotdev/hono-crud#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/kshdotdev/hono-crud/issues"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "dist/index.js",
|
|
18
|
+
"types": "dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"hono",
|
|
27
|
+
"crud",
|
|
28
|
+
"drizzle",
|
|
29
|
+
"drizzle-orm",
|
|
30
|
+
"adapter"
|
|
31
|
+
],
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20.19.0"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"hono-crud": "0.13.4"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"drizzle-orm": ">=0.30.0",
|
|
49
|
+
"drizzle-zod": ">=0.8.0",
|
|
50
|
+
"hono": ">=4.11.7 <5",
|
|
51
|
+
"zod": ">=4.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"drizzle-orm": "^0.45.1",
|
|
55
|
+
"drizzle-zod": "^0.8.3",
|
|
56
|
+
"hono": "^4.11.4",
|
|
57
|
+
"tsup": "^8.4.0",
|
|
58
|
+
"typescript": "^5.8.3",
|
|
59
|
+
"zod": "^4.3.5"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"typecheck": "tsc --noEmit",
|
|
64
|
+
"clean": "rm -rf dist .tsup"
|
|
65
|
+
}
|
|
66
|
+
}
|