@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.
Files changed (55) hide show
  1. package/dist/cache/index.mjs +12 -0
  2. package/dist/cache/index.mjs.map +1 -0
  3. package/dist/cache/manager.mjs +156 -153
  4. package/dist/cache/manager.mjs.map +1 -1
  5. package/dist/cache/memory-store.mjs +113 -111
  6. package/dist/cache/memory-store.mjs.map +1 -1
  7. package/dist/cli/commands/migrate.cjs +78 -0
  8. package/dist/cli/commands/migrate.cjs.map +1 -0
  9. package/dist/cli/commands/migrate.mjs +83 -0
  10. package/dist/cli/commands/migrate.mjs.map +1 -0
  11. package/dist/cli.cjs +36 -0
  12. package/dist/cli.cjs.map +1 -1
  13. package/dist/cli.mjs +37 -0
  14. package/dist/cli.mjs.map +1 -1
  15. package/dist/core/database.cjs +72 -29
  16. package/dist/core/database.cjs.map +1 -1
  17. package/dist/core/database.d.cts +65 -0
  18. package/dist/core/database.d.mts +65 -0
  19. package/dist/core/database.mjs +88 -34
  20. package/dist/core/database.mjs.map +1 -1
  21. package/dist/core/repository.mjs +414 -410
  22. package/dist/core/repository.mjs.map +1 -1
  23. package/dist/drivers/driver.mjs +9 -7
  24. package/dist/drivers/driver.mjs.map +1 -1
  25. package/dist/drivers/file.mjs +315 -312
  26. package/dist/drivers/file.mjs.map +1 -1
  27. package/dist/drivers/index.mjs +15 -6
  28. package/dist/drivers/index.mjs.map +1 -1
  29. package/dist/drivers/mysql.mjs +261 -256
  30. package/dist/drivers/mysql.mjs.map +1 -1
  31. package/dist/drivers/sql-compiler.mjs +4 -1
  32. package/dist/drivers/sql-compiler.mjs.map +1 -1
  33. package/dist/drivers/sqlite.cjs +12 -1
  34. package/dist/drivers/sqlite.cjs.map +1 -1
  35. package/dist/drivers/sqlite.mjs +258 -242
  36. package/dist/drivers/sqlite.mjs.map +1 -1
  37. package/dist/errors.mjs +48 -64
  38. package/dist/errors.mjs.map +1 -1
  39. package/dist/index.mjs +21 -9
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/schema/column.mjs +155 -157
  42. package/dist/schema/column.mjs.map +1 -1
  43. package/dist/schema/columns/index.mjs +103 -171
  44. package/dist/schema/columns/index.mjs.map +1 -1
  45. package/dist/schema/index.mjs +15 -0
  46. package/dist/schema/index.mjs.map +1 -0
  47. package/dist/schema/registry.mjs +122 -119
  48. package/dist/schema/registry.mjs.map +1 -1
  49. package/dist/schema/table.mjs +4 -1
  50. package/dist/schema/table.mjs.map +1 -1
  51. package/dist/sync/synchronizer.mjs +2 -1
  52. package/dist/sync/synchronizer.mjs.map +1 -1
  53. package/dist/types.d.cts +67 -6
  54. package/dist/types.d.mts +67 -6
  55. package/package.json +1 -1
@@ -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
- export { table };
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":";;;;;;;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
+ {"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":";;;;;;AAQA,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"}
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
- /** Condition operators for a single column in a WHERE clause */
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
- /** Type-safe WHERE clause supporting equality, operators, and logical combinators (OR/AND) */
120
- type WhereClause<T = Record<string, any>> = { [K in keyof T]?: T[K] | WhereCondition } & {
121
- OR?: WhereClause<T>[];
122
- AND?: WhereClause<T>[];
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
- /** Condition operators for a single column in a WHERE clause */
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
- /** Type-safe WHERE clause supporting equality, operators, and logical combinators (OR/AND) */
120
- type WhereClause<T = Record<string, any>> = { [K in keyof T]?: T[K] | WhereCondition } & {
121
- OR?: WhereClause<T>[];
122
- AND?: WhereClause<T>[];
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hedystia/db",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Next-gen TypeScript ORM for building type-safe database layers at lightspeed",
5
5
  "homepage": "https://docs.hedystia.com",
6
6
  "devDependencies": {