@hedystia/db 2.0.5 → 2.0.7
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/dist/cache/index.mjs +12 -0
- package/dist/cache/index.mjs.map +1 -0
- package/dist/cache/manager.mjs +156 -153
- package/dist/cache/manager.mjs.map +1 -1
- package/dist/cache/memory-store.mjs +113 -111
- package/dist/cache/memory-store.mjs.map +1 -1
- package/dist/cli/commands/migrate.cjs +78 -0
- package/dist/cli/commands/migrate.cjs.map +1 -0
- package/dist/cli/commands/migrate.mjs +83 -0
- package/dist/cli/commands/migrate.mjs.map +1 -0
- package/dist/cli.cjs +36 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +37 -0
- package/dist/cli.mjs.map +1 -1
- package/dist/core/database.cjs +72 -29
- package/dist/core/database.cjs.map +1 -1
- package/dist/core/database.d.cts +65 -0
- package/dist/core/database.d.mts +65 -0
- package/dist/core/database.mjs +88 -34
- package/dist/core/database.mjs.map +1 -1
- package/dist/core/repository.mjs +414 -410
- package/dist/core/repository.mjs.map +1 -1
- package/dist/drivers/driver.mjs +9 -7
- package/dist/drivers/driver.mjs.map +1 -1
- package/dist/drivers/file.mjs +315 -312
- package/dist/drivers/file.mjs.map +1 -1
- package/dist/drivers/index.mjs +15 -6
- package/dist/drivers/index.mjs.map +1 -1
- package/dist/drivers/mysql.mjs +261 -256
- package/dist/drivers/mysql.mjs.map +1 -1
- package/dist/drivers/sql-compiler.mjs +4 -1
- package/dist/drivers/sql-compiler.mjs.map +1 -1
- package/dist/drivers/sqlite.cjs +12 -1
- package/dist/drivers/sqlite.cjs.map +1 -1
- package/dist/drivers/sqlite.mjs +258 -242
- package/dist/drivers/sqlite.mjs.map +1 -1
- package/dist/errors.mjs +48 -64
- package/dist/errors.mjs.map +1 -1
- package/dist/index.mjs +21 -9
- package/dist/index.mjs.map +1 -1
- package/dist/schema/column.mjs +155 -157
- package/dist/schema/column.mjs.map +1 -1
- package/dist/schema/columns/index.mjs +103 -171
- package/dist/schema/columns/index.mjs.map +1 -1
- package/dist/schema/index.mjs +15 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/schema/registry.mjs +122 -119
- package/dist/schema/registry.mjs.map +1 -1
- package/dist/schema/table.mjs +4 -1
- package/dist/schema/table.mjs.map +1 -1
- package/dist/sync/synchronizer.mjs +2 -1
- package/dist/sync/synchronizer.mjs.map +1 -1
- package/dist/types.d.cts +67 -6
- package/dist/types.d.mts +67 -6
- package/package.json +1 -1
package/dist/schema/table.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { __esmMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
1
2
|
//#region src/schema/table.ts
|
|
2
3
|
/**
|
|
3
4
|
* Define a database table with its columns
|
|
@@ -34,7 +35,9 @@ function table(name, columns, options) {
|
|
|
34
35
|
...columns
|
|
35
36
|
};
|
|
36
37
|
}
|
|
38
|
+
var init_table = __esmMin((() => {}));
|
|
37
39
|
//#endregion
|
|
38
|
-
|
|
40
|
+
init_table();
|
|
41
|
+
export { init_table, table };
|
|
39
42
|
|
|
40
43
|
//# sourceMappingURL=table.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.mjs","names":[],"sources":["../../src/schema/table.ts"],"sourcesContent":["import type { ColumnMetadata, DeferredRefMeta, TableCacheConfig, TableDefinition } from \"../types\";\nimport type { ColumnBuilder } from \"./column\";\n\ntype BindColumn<C, TableName extends string, ColName extends string> =\n C extends ColumnBuilder<infer T, any, any, infer Ref>\n ? ColumnBuilder<\n T,\n TableName,\n ColName,\n Ref extends DeferredRefMeta<any, infer ToTable, infer ToColumn, infer RelName>\n ? DeferredRefMeta<ColName, ToTable, ToColumn, RelName>\n : never\n >\n : never;\n\ntype BoundColumns<C extends Record<string, ColumnBuilder<any, any, any, any>>, N extends string> = {\n [K in keyof C]: BindColumn<C[K], N, Extract<K, string>>;\n};\n\ntype ExtractDeferredRefs<C extends Record<string, ColumnBuilder<any, any, any, any>>> = {\n [K in keyof C]: C[K] extends ColumnBuilder<any, any, any, infer Ref> ? Ref : never;\n}[keyof C];\n\n/**\n * Define a database table with its columns\n * @param {string} name - The table name\n * @param {Record<string, ColumnBuilder<any>>} columns - Column definitions\n * @returns {TableDefinition<T, C>} The table definition object with column accessors\n */\nexport function table<\n N extends string,\n C extends Record<string, ColumnBuilder<any, any, any, any>>,\n>(\n name: N,\n columns: C,\n options?: { cache?: TableCacheConfig },\n): TableDefinition<\n { [K in keyof C]: C[K][\"__type\"] },\n BoundColumns<C, N>,\n N,\n ExtractDeferredRefs<BoundColumns<C, N>>\n> {\n const columnsArray: ColumnMetadata[] = [];\n const deferredRefs: TableDefinition[\"__deferredRefs\"] = [];\n const columnMap: Record<string, string> = {};\n\n for (const [key, builder] of Object.entries(columns)) {\n const meta = builder.__build(key);\n columnsArray.push(meta);\n columnMap[key] = meta.name;\n\n const ref = builder.__getDeferredRef();\n if (ref) {\n deferredRefs.push({\n columnName: key,\n resolve: ref.resolve,\n onDelete: ref.onDelete,\n onUpdate: ref.onUpdate,\n relationName: ref.relationName,\n });\n }\n\n (builder as any).__tableName = name;\n (builder as any).__columnName = key;\n }\n\n const def = {\n __table: true,\n __name: name,\n __columns: columnsArray,\n __columnMap: columnMap,\n __cache: options?.cache,\n __deferredRefs: deferredRefs,\n ...columns,\n };\n\n return def as any;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"table.mjs","names":[],"sources":["../../src/schema/table.ts"],"sourcesContent":["import type { ColumnMetadata, DeferredRefMeta, TableCacheConfig, TableDefinition } from \"../types\";\nimport type { ColumnBuilder } from \"./column\";\n\ntype BindColumn<C, TableName extends string, ColName extends string> =\n C extends ColumnBuilder<infer T, any, any, infer Ref>\n ? ColumnBuilder<\n T,\n TableName,\n ColName,\n Ref extends DeferredRefMeta<any, infer ToTable, infer ToColumn, infer RelName>\n ? DeferredRefMeta<ColName, ToTable, ToColumn, RelName>\n : never\n >\n : never;\n\ntype BoundColumns<C extends Record<string, ColumnBuilder<any, any, any, any>>, N extends string> = {\n [K in keyof C]: BindColumn<C[K], N, Extract<K, string>>;\n};\n\ntype ExtractDeferredRefs<C extends Record<string, ColumnBuilder<any, any, any, any>>> = {\n [K in keyof C]: C[K] extends ColumnBuilder<any, any, any, infer Ref> ? Ref : never;\n}[keyof C];\n\n/**\n * Define a database table with its columns\n * @param {string} name - The table name\n * @param {Record<string, ColumnBuilder<any>>} columns - Column definitions\n * @returns {TableDefinition<T, C>} The table definition object with column accessors\n */\nexport function table<\n N extends string,\n C extends Record<string, ColumnBuilder<any, any, any, any>>,\n>(\n name: N,\n columns: C,\n options?: { cache?: TableCacheConfig },\n): TableDefinition<\n { [K in keyof C]: C[K][\"__type\"] },\n BoundColumns<C, N>,\n N,\n ExtractDeferredRefs<BoundColumns<C, N>>\n> {\n const columnsArray: ColumnMetadata[] = [];\n const deferredRefs: TableDefinition[\"__deferredRefs\"] = [];\n const columnMap: Record<string, string> = {};\n\n for (const [key, builder] of Object.entries(columns)) {\n const meta = builder.__build(key);\n columnsArray.push(meta);\n columnMap[key] = meta.name;\n\n const ref = builder.__getDeferredRef();\n if (ref) {\n deferredRefs.push({\n columnName: key,\n resolve: ref.resolve,\n onDelete: ref.onDelete,\n onUpdate: ref.onUpdate,\n relationName: ref.relationName,\n });\n }\n\n (builder as any).__tableName = name;\n (builder as any).__columnName = key;\n }\n\n const def = {\n __table: true,\n __name: name,\n __columns: columnsArray,\n __columnMap: columnMap,\n __cache: options?.cache,\n __deferredRefs: deferredRefs,\n ...columns,\n };\n\n return def as any;\n}\n"],"mappings":";;;;;;;;AA6BA,SAAgB,MAId,MACA,SACA,SAMA;CACA,MAAM,eAAiC,EAAE;CACzC,MAAM,eAAkD,EAAE;CAC1D,MAAM,YAAoC,EAAE;AAE5C,MAAK,MAAM,CAAC,KAAK,YAAY,OAAO,QAAQ,QAAQ,EAAE;EACpD,MAAM,OAAO,QAAQ,QAAQ,IAAI;AACjC,eAAa,KAAK,KAAK;AACvB,YAAU,OAAO,KAAK;EAEtB,MAAM,MAAM,QAAQ,kBAAkB;AACtC,MAAI,IACF,cAAa,KAAK;GAChB,YAAY;GACZ,SAAS,IAAI;GACb,UAAU,IAAI;GACd,UAAU,IAAI;GACd,cAAc,IAAI;GACnB,CAAC;AAGH,UAAgB,cAAc;AAC9B,UAAgB,eAAe;;AAalC,QAVY;EACV,SAAS;EACT,QAAQ;EACR,WAAW;EACX,aAAa;EACb,SAAS,SAAS;EAClB,gBAAgB;EAChB,GAAG;EACJ"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SyncError } from "../errors.mjs";
|
|
1
|
+
import { SyncError, init_errors } from "../errors.mjs";
|
|
2
2
|
//#region src/sync/synchronizer.ts
|
|
3
|
+
init_errors();
|
|
3
4
|
/**
|
|
4
5
|
* Schema synchronizer that compares the database state with the schema registry
|
|
5
6
|
* and applies non-destructive changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synchronizer.mjs","names":[],"sources":["../../src/sync/synchronizer.ts"],"sourcesContent":["import { SyncError } from \"../errors\";\nimport type { SchemaRegistry } from \"../schema\";\nimport type { DatabaseDriver, TableMetadata } from \"../types\";\n\n/**\n * Schema synchronizer that compares the database state with the schema registry\n * and applies non-destructive changes\n */\nexport class Synchronizer {\n private driver: DatabaseDriver;\n private registry: SchemaRegistry;\n\n constructor(driver: DatabaseDriver, registry: SchemaRegistry) {\n this.driver = driver;\n this.registry = registry;\n }\n\n /**\n * Synchronize database schema with registry definitions\n * @param {boolean} [force=false] - Allow destructive operations (drop columns)\n */\n async sync(force = false): Promise<void> {\n const tables = this.registry.getAllTables();\n\n for (const [, tableMeta] of tables) {\n await this.syncTable(tableMeta, force);\n }\n }\n\n private async syncTable(meta: TableMetadata, force: boolean): Promise<void> {\n const exists = await this.driver.tableExists(meta.name);\n if (!exists) {\n await this.driver.createTable(meta);\n return;\n }\n\n const existingCols = await this.driver.getTableColumns(meta.name);\n const existingNames = new Set(existingCols.map((c) => c.name));\n const schemaNames = new Set(meta.columns.map((c) => c.name));\n\n for (const colMeta of meta.columns) {\n if (!existingNames.has(colMeta.name)) {\n await this.driver.addColumn(meta.name, colMeta);\n }\n }\n\n if (force) {\n for (const existingName of existingNames) {\n if (!schemaNames.has(existingName)) {\n try {\n await this.driver.dropColumn(meta.name, existingName);\n } catch (err: any) {\n throw new SyncError(`Failed to drop column ${existingName}: ${err.message}`);\n }\n }\n }\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"synchronizer.mjs","names":[],"sources":["../../src/sync/synchronizer.ts"],"sourcesContent":["import { SyncError } from \"../errors\";\nimport type { SchemaRegistry } from \"../schema\";\nimport type { DatabaseDriver, TableMetadata } from \"../types\";\n\n/**\n * Schema synchronizer that compares the database state with the schema registry\n * and applies non-destructive changes\n */\nexport class Synchronizer {\n private driver: DatabaseDriver;\n private registry: SchemaRegistry;\n\n constructor(driver: DatabaseDriver, registry: SchemaRegistry) {\n this.driver = driver;\n this.registry = registry;\n }\n\n /**\n * Synchronize database schema with registry definitions\n * @param {boolean} [force=false] - Allow destructive operations (drop columns)\n */\n async sync(force = false): Promise<void> {\n const tables = this.registry.getAllTables();\n\n for (const [, tableMeta] of tables) {\n await this.syncTable(tableMeta, force);\n }\n }\n\n private async syncTable(meta: TableMetadata, force: boolean): Promise<void> {\n const exists = await this.driver.tableExists(meta.name);\n if (!exists) {\n await this.driver.createTable(meta);\n return;\n }\n\n const existingCols = await this.driver.getTableColumns(meta.name);\n const existingNames = new Set(existingCols.map((c) => c.name));\n const schemaNames = new Set(meta.columns.map((c) => c.name));\n\n for (const colMeta of meta.columns) {\n if (!existingNames.has(colMeta.name)) {\n await this.driver.addColumn(meta.name, colMeta);\n }\n }\n\n if (force) {\n for (const existingName of existingNames) {\n if (!schemaNames.has(existingName)) {\n try {\n await this.driver.dropColumn(meta.name, existingName);\n } catch (err: any) {\n throw new SyncError(`Failed to drop column ${existingName}: ${err.message}`);\n }\n }\n }\n }\n }\n}\n"],"mappings":";;aAAsC;;;;;AAQtC,IAAa,eAAb,MAA0B;CACxB;CACA;CAEA,YAAY,QAAwB,UAA0B;AAC5D,OAAK,SAAS;AACd,OAAK,WAAW;;;;;;CAOlB,MAAM,KAAK,QAAQ,OAAsB;EACvC,MAAM,SAAS,KAAK,SAAS,cAAc;AAE3C,OAAK,MAAM,GAAG,cAAc,OAC1B,OAAM,KAAK,UAAU,WAAW,MAAM;;CAI1C,MAAc,UAAU,MAAqB,OAA+B;AAE1E,MAAI,CADW,MAAM,KAAK,OAAO,YAAY,KAAK,KAAK,EAC1C;AACX,SAAM,KAAK,OAAO,YAAY,KAAK;AACnC;;EAGF,MAAM,eAAe,MAAM,KAAK,OAAO,gBAAgB,KAAK,KAAK;EACjE,MAAM,gBAAgB,IAAI,IAAI,aAAa,KAAK,MAAM,EAAE,KAAK,CAAC;EAC9D,MAAM,cAAc,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;AAE5D,OAAK,MAAM,WAAW,KAAK,QACzB,KAAI,CAAC,cAAc,IAAI,QAAQ,KAAK,CAClC,OAAM,KAAK,OAAO,UAAU,KAAK,MAAM,QAAQ;AAInD,MAAI;QACG,MAAM,gBAAgB,cACzB,KAAI,CAAC,YAAY,IAAI,aAAa,CAChC,KAAI;AACF,UAAM,KAAK,OAAO,WAAW,KAAK,MAAM,aAAa;YAC9C,KAAU;AACjB,UAAM,IAAI,UAAU,yBAAyB,aAAa,IAAI,IAAI,UAAU"}
|
package/dist/types.d.cts
CHANGED
|
@@ -101,26 +101,76 @@ type InferInsert<T> = T extends TableDefinition<infer R, any, any> ? { [K in key
|
|
|
101
101
|
type AutoIncrementKeys<T> = T extends TableDefinition<infer R, any, any> ? keyof R : never;
|
|
102
102
|
/** Extract the updatable type from a table definition (all fields become optional) */
|
|
103
103
|
type InferUpdate<T> = T extends TableDefinition<infer R, any, any> ? Partial<R> : never;
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Condition operators for a single column in a WHERE clause.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* // Exact match
|
|
110
|
+
* { age: { eq: 25 } }
|
|
111
|
+
* // Range query
|
|
112
|
+
* { age: { gte: 18, lte: 65 } }
|
|
113
|
+
* // Pattern matching
|
|
114
|
+
* { name: { like: "%alice%" } }
|
|
115
|
+
* // Set membership
|
|
116
|
+
* { status: { in: ["active", "pending"] } }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
105
119
|
interface WhereCondition {
|
|
120
|
+
/** Equal to — matches rows where the column value equals the given value */
|
|
106
121
|
eq?: unknown;
|
|
122
|
+
/** Not equal to — matches rows where the column value differs from the given value */
|
|
107
123
|
neq?: unknown;
|
|
124
|
+
/** Greater than — matches rows where the column value is strictly greater */
|
|
108
125
|
gt?: unknown;
|
|
126
|
+
/** Greater than or equal to — matches rows where the column value is greater or equal */
|
|
109
127
|
gte?: unknown;
|
|
128
|
+
/** Less than — matches rows where the column value is strictly less */
|
|
110
129
|
lt?: unknown;
|
|
130
|
+
/** Less than or equal to — matches rows where the column value is less or equal */
|
|
111
131
|
lte?: unknown;
|
|
132
|
+
/** SQL LIKE — matches rows where the column value matches the pattern (use `%` as wildcard) */
|
|
112
133
|
like?: string;
|
|
134
|
+
/** SQL NOT LIKE — matches rows where the column value does not match the pattern */
|
|
113
135
|
notLike?: string;
|
|
136
|
+
/** IN — matches rows where the column value is one of the given values */
|
|
114
137
|
in?: unknown[];
|
|
138
|
+
/** NOT IN — matches rows where the column value is not one of the given values */
|
|
115
139
|
notIn?: unknown[];
|
|
140
|
+
/** IS NULL / IS NOT NULL — when `true`, matches rows where the column is NULL; when `false`, matches non-NULL */
|
|
116
141
|
isNull?: boolean;
|
|
142
|
+
/** BETWEEN — matches rows where the column value falls within the inclusive range `[min, max]` */
|
|
117
143
|
between?: [unknown, unknown];
|
|
118
144
|
}
|
|
119
|
-
/**
|
|
120
|
-
type
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
/** Flatten an intersection into a single object type for better autocomplete */
|
|
146
|
+
type Flat<T> = { [K in keyof T]: T[K] } & {};
|
|
147
|
+
/** Column-level filter conditions for a WHERE clause */
|
|
148
|
+
type WhereFields<T> = Flat<{ [K in keyof T]?: T[K] | WhereCondition }>;
|
|
149
|
+
/**
|
|
150
|
+
* Type-safe WHERE clause supporting equality, operators, and logical combinators (OR/AND).
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* // Simple equality
|
|
155
|
+
* { where: { name: "Alice" } }
|
|
156
|
+
*
|
|
157
|
+
* // Using operators
|
|
158
|
+
* { where: { age: { gte: 18 } } }
|
|
159
|
+
*
|
|
160
|
+
* // OR — matches rows satisfying at least one condition
|
|
161
|
+
* { where: { OR: [{ name: "Alice" }, { name: "Bob" }] } }
|
|
162
|
+
*
|
|
163
|
+
* // AND — matches rows satisfying all conditions
|
|
164
|
+
* { where: { AND: [{ age: { gte: 18 } }, { active: true }] } }
|
|
165
|
+
*
|
|
166
|
+
* // Combined AND + OR
|
|
167
|
+
* { where: { AND: [{ age: { gte: 18 } }], OR: [{ name: "Alice" }, { name: "Bob" }] } }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
type WhereClause<T = Record<string, any>> = Flat<{ [K in keyof T]?: T[K] | WhereCondition } & {
|
|
171
|
+
/** Logical OR — matches rows satisfying **at least one** of the given conditions */OR?: WhereFields<T>[]; /** Logical AND — matches rows satisfying **all** of the given conditions */
|
|
172
|
+
AND?: WhereFields<T>[];
|
|
173
|
+
}>;
|
|
124
174
|
/** Options for querying rows — filtering, sorting, pagination, and relation loading */
|
|
125
175
|
interface QueryOptions<T = Record<string, any>, Rel extends Record<string, any> = {}> {
|
|
126
176
|
/** Filter conditions */
|
|
@@ -271,20 +321,31 @@ interface DatabaseDriver {
|
|
|
271
321
|
}
|
|
272
322
|
/** Generic repository interface providing CRUD operations for a table */
|
|
273
323
|
interface Repository<T extends Record<string, any>> {
|
|
324
|
+
/** Find all rows matching the given options */
|
|
274
325
|
find(options?: QueryOptions<T>): Promise<T[]>;
|
|
326
|
+
/** Find all rows matching the given options (alias for {@link find}) */
|
|
275
327
|
findMany(options?: QueryOptions<T>): Promise<T[]>;
|
|
328
|
+
/** Find the first row matching the given options, or `null` if none found */
|
|
276
329
|
findFirst(options?: QueryOptions<T>): Promise<T | null>;
|
|
330
|
+
/** Insert one or more rows into the table */
|
|
277
331
|
insert(data: Partial<T> | Partial<T>[]): Promise<T>;
|
|
332
|
+
/** Insert multiple rows into the table */
|
|
278
333
|
insertMany(data: Partial<T>[]): Promise<T[]>;
|
|
334
|
+
/** Update rows matching the where clause */
|
|
279
335
|
update(options: UpdateOptions<T>): Promise<T[]>;
|
|
336
|
+
/** Delete rows matching the where clause */
|
|
280
337
|
delete(options: DeleteOptions<T>): Promise<number>;
|
|
338
|
+
/** Count rows matching the where clause */
|
|
281
339
|
count(options?: Pick<QueryOptions<T>, "where">): Promise<number>;
|
|
340
|
+
/** Check whether at least one row matches the where clause */
|
|
282
341
|
exists(options: Pick<QueryOptions<T>, "where">): Promise<boolean>;
|
|
342
|
+
/** Insert a row if it doesn't exist, or update it if it does */
|
|
283
343
|
upsert(options: {
|
|
284
344
|
where: WhereClause<T>;
|
|
285
345
|
create: Partial<T>;
|
|
286
346
|
update: Partial<T>;
|
|
287
347
|
}): Promise<T>;
|
|
348
|
+
/** Remove all rows from the table */
|
|
288
349
|
truncate(): Promise<void>;
|
|
289
350
|
}
|
|
290
351
|
type AnyTableDef = TableDefinition<any, any, any, any>;
|
package/dist/types.d.mts
CHANGED
|
@@ -101,26 +101,76 @@ type InferInsert<T> = T extends TableDefinition<infer R, any, any> ? { [K in key
|
|
|
101
101
|
type AutoIncrementKeys<T> = T extends TableDefinition<infer R, any, any> ? keyof R : never;
|
|
102
102
|
/** Extract the updatable type from a table definition (all fields become optional) */
|
|
103
103
|
type InferUpdate<T> = T extends TableDefinition<infer R, any, any> ? Partial<R> : never;
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Condition operators for a single column in a WHERE clause.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* // Exact match
|
|
110
|
+
* { age: { eq: 25 } }
|
|
111
|
+
* // Range query
|
|
112
|
+
* { age: { gte: 18, lte: 65 } }
|
|
113
|
+
* // Pattern matching
|
|
114
|
+
* { name: { like: "%alice%" } }
|
|
115
|
+
* // Set membership
|
|
116
|
+
* { status: { in: ["active", "pending"] } }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
105
119
|
interface WhereCondition {
|
|
120
|
+
/** Equal to — matches rows where the column value equals the given value */
|
|
106
121
|
eq?: unknown;
|
|
122
|
+
/** Not equal to — matches rows where the column value differs from the given value */
|
|
107
123
|
neq?: unknown;
|
|
124
|
+
/** Greater than — matches rows where the column value is strictly greater */
|
|
108
125
|
gt?: unknown;
|
|
126
|
+
/** Greater than or equal to — matches rows where the column value is greater or equal */
|
|
109
127
|
gte?: unknown;
|
|
128
|
+
/** Less than — matches rows where the column value is strictly less */
|
|
110
129
|
lt?: unknown;
|
|
130
|
+
/** Less than or equal to — matches rows where the column value is less or equal */
|
|
111
131
|
lte?: unknown;
|
|
132
|
+
/** SQL LIKE — matches rows where the column value matches the pattern (use `%` as wildcard) */
|
|
112
133
|
like?: string;
|
|
134
|
+
/** SQL NOT LIKE — matches rows where the column value does not match the pattern */
|
|
113
135
|
notLike?: string;
|
|
136
|
+
/** IN — matches rows where the column value is one of the given values */
|
|
114
137
|
in?: unknown[];
|
|
138
|
+
/** NOT IN — matches rows where the column value is not one of the given values */
|
|
115
139
|
notIn?: unknown[];
|
|
140
|
+
/** IS NULL / IS NOT NULL — when `true`, matches rows where the column is NULL; when `false`, matches non-NULL */
|
|
116
141
|
isNull?: boolean;
|
|
142
|
+
/** BETWEEN — matches rows where the column value falls within the inclusive range `[min, max]` */
|
|
117
143
|
between?: [unknown, unknown];
|
|
118
144
|
}
|
|
119
|
-
/**
|
|
120
|
-
type
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
/** Flatten an intersection into a single object type for better autocomplete */
|
|
146
|
+
type Flat<T> = { [K in keyof T]: T[K] } & {};
|
|
147
|
+
/** Column-level filter conditions for a WHERE clause */
|
|
148
|
+
type WhereFields<T> = Flat<{ [K in keyof T]?: T[K] | WhereCondition }>;
|
|
149
|
+
/**
|
|
150
|
+
* Type-safe WHERE clause supporting equality, operators, and logical combinators (OR/AND).
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* // Simple equality
|
|
155
|
+
* { where: { name: "Alice" } }
|
|
156
|
+
*
|
|
157
|
+
* // Using operators
|
|
158
|
+
* { where: { age: { gte: 18 } } }
|
|
159
|
+
*
|
|
160
|
+
* // OR — matches rows satisfying at least one condition
|
|
161
|
+
* { where: { OR: [{ name: "Alice" }, { name: "Bob" }] } }
|
|
162
|
+
*
|
|
163
|
+
* // AND — matches rows satisfying all conditions
|
|
164
|
+
* { where: { AND: [{ age: { gte: 18 } }, { active: true }] } }
|
|
165
|
+
*
|
|
166
|
+
* // Combined AND + OR
|
|
167
|
+
* { where: { AND: [{ age: { gte: 18 } }], OR: [{ name: "Alice" }, { name: "Bob" }] } }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
type WhereClause<T = Record<string, any>> = Flat<{ [K in keyof T]?: T[K] | WhereCondition } & {
|
|
171
|
+
/** Logical OR — matches rows satisfying **at least one** of the given conditions */OR?: WhereFields<T>[]; /** Logical AND — matches rows satisfying **all** of the given conditions */
|
|
172
|
+
AND?: WhereFields<T>[];
|
|
173
|
+
}>;
|
|
124
174
|
/** Options for querying rows — filtering, sorting, pagination, and relation loading */
|
|
125
175
|
interface QueryOptions<T = Record<string, any>, Rel extends Record<string, any> = {}> {
|
|
126
176
|
/** Filter conditions */
|
|
@@ -271,20 +321,31 @@ interface DatabaseDriver {
|
|
|
271
321
|
}
|
|
272
322
|
/** Generic repository interface providing CRUD operations for a table */
|
|
273
323
|
interface Repository<T extends Record<string, any>> {
|
|
324
|
+
/** Find all rows matching the given options */
|
|
274
325
|
find(options?: QueryOptions<T>): Promise<T[]>;
|
|
326
|
+
/** Find all rows matching the given options (alias for {@link find}) */
|
|
275
327
|
findMany(options?: QueryOptions<T>): Promise<T[]>;
|
|
328
|
+
/** Find the first row matching the given options, or `null` if none found */
|
|
276
329
|
findFirst(options?: QueryOptions<T>): Promise<T | null>;
|
|
330
|
+
/** Insert one or more rows into the table */
|
|
277
331
|
insert(data: Partial<T> | Partial<T>[]): Promise<T>;
|
|
332
|
+
/** Insert multiple rows into the table */
|
|
278
333
|
insertMany(data: Partial<T>[]): Promise<T[]>;
|
|
334
|
+
/** Update rows matching the where clause */
|
|
279
335
|
update(options: UpdateOptions<T>): Promise<T[]>;
|
|
336
|
+
/** Delete rows matching the where clause */
|
|
280
337
|
delete(options: DeleteOptions<T>): Promise<number>;
|
|
338
|
+
/** Count rows matching the where clause */
|
|
281
339
|
count(options?: Pick<QueryOptions<T>, "where">): Promise<number>;
|
|
340
|
+
/** Check whether at least one row matches the where clause */
|
|
282
341
|
exists(options: Pick<QueryOptions<T>, "where">): Promise<boolean>;
|
|
342
|
+
/** Insert a row if it doesn't exist, or update it if it does */
|
|
283
343
|
upsert(options: {
|
|
284
344
|
where: WhereClause<T>;
|
|
285
345
|
create: Partial<T>;
|
|
286
346
|
update: Partial<T>;
|
|
287
347
|
}): Promise<T>;
|
|
348
|
+
/** Remove all rows from the table */
|
|
288
349
|
truncate(): Promise<void>;
|
|
289
350
|
}
|
|
290
351
|
type AnyTableDef = TableDefinition<any, any, any, any>;
|