@type32/tauri-sqlite-orm 0.1.8 → 0.1.9

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/index.d.mts CHANGED
@@ -188,6 +188,12 @@ declare const notExists: (subquery: SQL | {
188
188
  declare const asc: (column: Column) => string;
189
189
  declare const desc: (column: Column) => string;
190
190
 
191
+ type InferInsert<T> = T extends {
192
+ $inferInsert: infer I;
193
+ } ? I : never;
194
+ type InferSelect<T> = T extends {
195
+ $inferSelect: infer S;
196
+ } ? S : never;
191
197
  declare class SelectQueryBuilder<T> {
192
198
  private _table;
193
199
  private _selectedColumns;
@@ -222,11 +228,17 @@ declare class TauriORM {
222
228
  constructor(dbUri: string);
223
229
  private getDb;
224
230
  configureQuery(tables: Record<string, Table<any>>, relations: Record<string, Record<string, RelationConfig>>): void;
225
- select<T>(fields?: Record<string, Column<any>>): SelectQueryBuilder<T>;
226
- selectDistinct<T>(fields?: Record<string, Column<any>>): SelectQueryBuilder<T>;
227
- insert(table: Table<any>): {
228
- _table: any;
229
- _rows: Record<string, any>[];
231
+ select<TFields extends Record<string, Column<any>>>(fields: TFields): SelectQueryBuilder<{
232
+ [K in keyof TFields]: TFields[K]["_dataType"];
233
+ }>;
234
+ select<T = any>(fields?: undefined): SelectQueryBuilder<T>;
235
+ selectDistinct<TFields extends Record<string, Column<any>>>(fields: TFields): SelectQueryBuilder<{
236
+ [K in keyof TFields]: TFields[K]["_dataType"];
237
+ }>;
238
+ selectDistinct<T = any>(fields?: undefined): SelectQueryBuilder<T>;
239
+ insert<TTable extends Table<any>>(table: TTable): {
240
+ _table: TTable;
241
+ _rows: Array<InferInsert<TTable>>;
230
242
  _selectSql: {
231
243
  clause: string;
232
244
  bindings: any[];
@@ -243,7 +255,7 @@ declare class TauriORM {
243
255
  setWhere?: SQL;
244
256
  };
245
257
  _returning: null | "__RETURNING_ID__" | Record<string, Column<any>>;
246
- values(rowOrRows: Record<string, any> | Record<string, any>[]): /*elided*/ any;
258
+ values(rowOrRows: InferInsert<TTable> | Array<InferInsert<TTable>>): /*elided*/ any;
247
259
  select(qb: {
248
260
  toSQL?: () => {
249
261
  clause: string;
@@ -266,15 +278,15 @@ declare class TauriORM {
266
278
  _buildConflictClause(): string;
267
279
  _executeWithReturning(db: any, query: string, bindings: any[]): Promise<any>;
268
280
  };
269
- update(table: Table<any>): {
270
- _table: any;
271
- _data: Record<string, any> | null;
281
+ update<TTable extends Table<any>>(table: TTable): {
282
+ _table: TTable;
283
+ _data: Partial<InferInsert<TTable>> | null;
272
284
  _where: Record<string, any> | SQL | null;
273
285
  _orderBy: Array<string | SQL>;
274
286
  _limit: number | null;
275
287
  _from: Table<any> | null;
276
288
  _returning: null | Record<string, Column<any>>;
277
- set(data: Record<string, any>): /*elided*/ any;
289
+ set(data: Partial<InferInsert<TTable>>): /*elided*/ any;
278
290
  where(cond: Record<string, any> | SQL): /*elided*/ any;
279
291
  orderBy(...clauses: (string | Column<any> | SQL)[]): /*elided*/ any;
280
292
  limit(n: number): /*elided*/ any;
@@ -282,13 +294,13 @@ declare class TauriORM {
282
294
  returning(fields?: Record<string, Column<any>>): any;
283
295
  execute(): Promise<unknown>;
284
296
  };
285
- delete(table: Table<any>): {
286
- _table: any;
287
- _where: Record<string, any> | SQL | null;
297
+ delete<TTable extends Table<any>>(table: TTable): {
298
+ _table: TTable;
299
+ _where: Partial<InferInsert<TTable>> | SQL | null;
288
300
  _orderBy: Array<string | SQL>;
289
301
  _limit: number | null;
290
302
  _returning: null | Record<string, Column<any>>;
291
- where(cond: Record<string, any> | SQL): /*elided*/ any;
303
+ where(cond: Partial<InferInsert<TTable>> | SQL): /*elided*/ any;
292
304
  orderBy(...clauses: (string | Column<any> | SQL)[]): /*elided*/ any;
293
305
  limit(n: number): /*elided*/ any;
294
306
  returning(fields?: Record<string, Column<any>>): any;
@@ -299,6 +311,8 @@ declare class TauriORM {
299
311
  private generateCreateTableSql;
300
312
  createTableIfNotExists(table: Table<any>): Promise<void>;
301
313
  createTablesIfNotExist(tables: Table<any>[]): Promise<void>;
314
+ private generateCreateIndexSqls;
315
+ private createIndexesForTable;
302
316
  private ensureMigrationsTable;
303
317
  private hasMigration;
304
318
  private recordMigration;
@@ -306,7 +320,14 @@ declare class TauriORM {
306
320
  name?: string;
307
321
  track?: boolean;
308
322
  }): Promise<void>;
309
- configure(tables: Record<string, Table<any>>, relDefs?: Record<string, Record<string, RelationConfig>>): this;
323
+ configure<TTables extends Record<string, Table<any>>, TRelDefs extends Record<string, Record<string, RelationConfig>> = Record<string, Record<string, RelationConfig>>>(tables: TTables, relDefs?: TRelDefs): this & {
324
+ query: {
325
+ [K in keyof TTables]: {
326
+ findMany: (opts?: any) => Promise<Array<InferSelect<TTables[K]>>>;
327
+ findFirst: (opts?: any) => Promise<InferSelect<TTables[K]> | null>;
328
+ };
329
+ };
330
+ };
310
331
  migrateConfigured(options?: {
311
332
  name?: string;
312
333
  track?: boolean;
@@ -349,6 +370,8 @@ declare class TauriORM {
349
370
  private setSchemaMeta;
350
371
  private normalizeColumn;
351
372
  private computeModelSignature;
373
+ getSchemaSignature(): string;
374
+ printSchemaDiff(): Promise<void>;
352
375
  isSchemaDirty(): Promise<{
353
376
  dirty: boolean;
354
377
  current: string;
@@ -365,6 +388,7 @@ declare class TauriORM {
365
388
  dropExtraColumns?: boolean;
366
389
  preserveData?: boolean;
367
390
  }): Promise<void>;
391
+ private forcePushForTables;
368
392
  }
369
393
  type OneConfig = {
370
394
  fields?: Column[];
package/dist/index.d.ts CHANGED
@@ -188,6 +188,12 @@ declare const notExists: (subquery: SQL | {
188
188
  declare const asc: (column: Column) => string;
189
189
  declare const desc: (column: Column) => string;
190
190
 
191
+ type InferInsert<T> = T extends {
192
+ $inferInsert: infer I;
193
+ } ? I : never;
194
+ type InferSelect<T> = T extends {
195
+ $inferSelect: infer S;
196
+ } ? S : never;
191
197
  declare class SelectQueryBuilder<T> {
192
198
  private _table;
193
199
  private _selectedColumns;
@@ -222,11 +228,17 @@ declare class TauriORM {
222
228
  constructor(dbUri: string);
223
229
  private getDb;
224
230
  configureQuery(tables: Record<string, Table<any>>, relations: Record<string, Record<string, RelationConfig>>): void;
225
- select<T>(fields?: Record<string, Column<any>>): SelectQueryBuilder<T>;
226
- selectDistinct<T>(fields?: Record<string, Column<any>>): SelectQueryBuilder<T>;
227
- insert(table: Table<any>): {
228
- _table: any;
229
- _rows: Record<string, any>[];
231
+ select<TFields extends Record<string, Column<any>>>(fields: TFields): SelectQueryBuilder<{
232
+ [K in keyof TFields]: TFields[K]["_dataType"];
233
+ }>;
234
+ select<T = any>(fields?: undefined): SelectQueryBuilder<T>;
235
+ selectDistinct<TFields extends Record<string, Column<any>>>(fields: TFields): SelectQueryBuilder<{
236
+ [K in keyof TFields]: TFields[K]["_dataType"];
237
+ }>;
238
+ selectDistinct<T = any>(fields?: undefined): SelectQueryBuilder<T>;
239
+ insert<TTable extends Table<any>>(table: TTable): {
240
+ _table: TTable;
241
+ _rows: Array<InferInsert<TTable>>;
230
242
  _selectSql: {
231
243
  clause: string;
232
244
  bindings: any[];
@@ -243,7 +255,7 @@ declare class TauriORM {
243
255
  setWhere?: SQL;
244
256
  };
245
257
  _returning: null | "__RETURNING_ID__" | Record<string, Column<any>>;
246
- values(rowOrRows: Record<string, any> | Record<string, any>[]): /*elided*/ any;
258
+ values(rowOrRows: InferInsert<TTable> | Array<InferInsert<TTable>>): /*elided*/ any;
247
259
  select(qb: {
248
260
  toSQL?: () => {
249
261
  clause: string;
@@ -266,15 +278,15 @@ declare class TauriORM {
266
278
  _buildConflictClause(): string;
267
279
  _executeWithReturning(db: any, query: string, bindings: any[]): Promise<any>;
268
280
  };
269
- update(table: Table<any>): {
270
- _table: any;
271
- _data: Record<string, any> | null;
281
+ update<TTable extends Table<any>>(table: TTable): {
282
+ _table: TTable;
283
+ _data: Partial<InferInsert<TTable>> | null;
272
284
  _where: Record<string, any> | SQL | null;
273
285
  _orderBy: Array<string | SQL>;
274
286
  _limit: number | null;
275
287
  _from: Table<any> | null;
276
288
  _returning: null | Record<string, Column<any>>;
277
- set(data: Record<string, any>): /*elided*/ any;
289
+ set(data: Partial<InferInsert<TTable>>): /*elided*/ any;
278
290
  where(cond: Record<string, any> | SQL): /*elided*/ any;
279
291
  orderBy(...clauses: (string | Column<any> | SQL)[]): /*elided*/ any;
280
292
  limit(n: number): /*elided*/ any;
@@ -282,13 +294,13 @@ declare class TauriORM {
282
294
  returning(fields?: Record<string, Column<any>>): any;
283
295
  execute(): Promise<unknown>;
284
296
  };
285
- delete(table: Table<any>): {
286
- _table: any;
287
- _where: Record<string, any> | SQL | null;
297
+ delete<TTable extends Table<any>>(table: TTable): {
298
+ _table: TTable;
299
+ _where: Partial<InferInsert<TTable>> | SQL | null;
288
300
  _orderBy: Array<string | SQL>;
289
301
  _limit: number | null;
290
302
  _returning: null | Record<string, Column<any>>;
291
- where(cond: Record<string, any> | SQL): /*elided*/ any;
303
+ where(cond: Partial<InferInsert<TTable>> | SQL): /*elided*/ any;
292
304
  orderBy(...clauses: (string | Column<any> | SQL)[]): /*elided*/ any;
293
305
  limit(n: number): /*elided*/ any;
294
306
  returning(fields?: Record<string, Column<any>>): any;
@@ -299,6 +311,8 @@ declare class TauriORM {
299
311
  private generateCreateTableSql;
300
312
  createTableIfNotExists(table: Table<any>): Promise<void>;
301
313
  createTablesIfNotExist(tables: Table<any>[]): Promise<void>;
314
+ private generateCreateIndexSqls;
315
+ private createIndexesForTable;
302
316
  private ensureMigrationsTable;
303
317
  private hasMigration;
304
318
  private recordMigration;
@@ -306,7 +320,14 @@ declare class TauriORM {
306
320
  name?: string;
307
321
  track?: boolean;
308
322
  }): Promise<void>;
309
- configure(tables: Record<string, Table<any>>, relDefs?: Record<string, Record<string, RelationConfig>>): this;
323
+ configure<TTables extends Record<string, Table<any>>, TRelDefs extends Record<string, Record<string, RelationConfig>> = Record<string, Record<string, RelationConfig>>>(tables: TTables, relDefs?: TRelDefs): this & {
324
+ query: {
325
+ [K in keyof TTables]: {
326
+ findMany: (opts?: any) => Promise<Array<InferSelect<TTables[K]>>>;
327
+ findFirst: (opts?: any) => Promise<InferSelect<TTables[K]> | null>;
328
+ };
329
+ };
330
+ };
310
331
  migrateConfigured(options?: {
311
332
  name?: string;
312
333
  track?: boolean;
@@ -349,6 +370,8 @@ declare class TauriORM {
349
370
  private setSchemaMeta;
350
371
  private normalizeColumn;
351
372
  private computeModelSignature;
373
+ getSchemaSignature(): string;
374
+ printSchemaDiff(): Promise<void>;
352
375
  isSchemaDirty(): Promise<{
353
376
  dirty: boolean;
354
377
  current: string;
@@ -365,6 +388,7 @@ declare class TauriORM {
365
388
  dropExtraColumns?: boolean;
366
389
  preserveData?: boolean;
367
390
  }): Promise<void>;
391
+ private forcePushForTables;
368
392
  }
369
393
  type OneConfig = {
370
394
  fields?: Column[];
package/dist/index.js CHANGED
@@ -213,12 +213,19 @@ function unique(name) {
213
213
  return {
214
214
  on: (...cols) => ({
215
215
  name,
216
- columns: cols.map((c) => c.name)
216
+ columns: cols.map((c) => c.name),
217
+ // runtime marker for DDL rendering
218
+ kind: "unique"
217
219
  })
218
220
  };
219
221
  }
220
222
  function primaryKey(opts) {
221
- return { name: opts.name, columns: opts.columns.map((c) => c.name) };
223
+ return {
224
+ name: opts.name,
225
+ columns: opts.columns.map((c) => c.name),
226
+ // runtime marker for DDL rendering
227
+ kind: "primaryKey"
228
+ };
222
229
  }
223
230
  function check(name, expr) {
224
231
  return { name, expr };
@@ -647,7 +654,10 @@ var TauriORM = class {
647
654
  _relations = null;
648
655
  _dbPromise;
649
656
  constructor(dbUri) {
650
- this._dbPromise = import_plugin_sql.default.load(dbUri);
657
+ this._dbPromise = import_plugin_sql.default.load(dbUri).then(async (db) => {
658
+ await db.execute("PRAGMA foreign_keys = ON");
659
+ return db;
660
+ });
651
661
  }
652
662
  async getDb() {
653
663
  return this._dbPromise;
@@ -721,7 +731,7 @@ var TauriORM = class {
721
731
  return ret;
722
732
  }
723
733
  for (const data of this._rows) {
724
- const finalData = { ...data };
734
+ const finalData = Object.assign({}, data);
725
735
  const schema = this._table._schema;
726
736
  for (const [key, col] of Object.entries(schema)) {
727
737
  if (finalData[key] === void 0) {
@@ -1016,19 +1026,86 @@ var TauriORM = class {
1016
1026
  }
1017
1027
  return def;
1018
1028
  });
1019
- return `CREATE TABLE IF NOT EXISTS ${tableName} (${columnDefs.join(
1020
- ", "
1021
- )});`;
1029
+ const tableConstraints = [];
1030
+ const constraints = table._constraints;
1031
+ if (constraints && constraints.length) {
1032
+ for (const spec of constraints) {
1033
+ if (spec.expr) {
1034
+ const name = spec.name;
1035
+ const expr = spec.expr.raw ?? spec.expr?.raw ?? String(spec.expr);
1036
+ tableConstraints.push(
1037
+ name ? `CONSTRAINT ${name} CHECK (${expr})` : `CHECK (${expr})`
1038
+ );
1039
+ continue;
1040
+ }
1041
+ if (spec.foreignColumns) {
1042
+ const name = spec.name;
1043
+ const cols = spec.columns.join(", ");
1044
+ const fTable = spec.foreignTable;
1045
+ const fCols = spec.foreignColumns.join(", ");
1046
+ let clause = `${name ? `CONSTRAINT ${name} ` : ""}FOREIGN KEY (${cols}) REFERENCES ${fTable} (${fCols})`;
1047
+ if (spec.onDelete)
1048
+ clause += ` ON DELETE ${String(
1049
+ spec.onDelete
1050
+ ).toUpperCase()}`;
1051
+ if (spec.onUpdate)
1052
+ clause += ` ON UPDATE ${String(
1053
+ spec.onUpdate
1054
+ ).toUpperCase()}`;
1055
+ tableConstraints.push(clause);
1056
+ continue;
1057
+ }
1058
+ if (spec.columns) {
1059
+ const cols = spec.columns.join(", ");
1060
+ const name = spec.name;
1061
+ const isPk = spec.kind === "primaryKey" || name && name.toLowerCase().includes("pk");
1062
+ if (isPk) {
1063
+ tableConstraints.push(
1064
+ name ? `CONSTRAINT ${name} PRIMARY KEY (${cols})` : `PRIMARY KEY (${cols})`
1065
+ );
1066
+ } else {
1067
+ tableConstraints.push(
1068
+ name ? `CONSTRAINT ${name} UNIQUE (${cols})` : `UNIQUE (${cols})`
1069
+ );
1070
+ }
1071
+ continue;
1072
+ }
1073
+ }
1074
+ }
1075
+ const parts = [...columnDefs, ...tableConstraints];
1076
+ return `CREATE TABLE IF NOT EXISTS ${tableName} (${parts.join(", ")});`;
1022
1077
  }
1023
1078
  async createTableIfNotExists(table) {
1024
1079
  const sql2 = this.generateCreateTableSql(table);
1025
1080
  await this.run(sql2);
1081
+ await this.createIndexesForTable(table);
1026
1082
  }
1027
1083
  async createTablesIfNotExist(tables) {
1028
1084
  for (const t of tables) {
1029
1085
  await this.createTableIfNotExists(t);
1030
1086
  }
1031
1087
  }
1088
+ generateCreateIndexSqls(table) {
1089
+ const tableName = table._tableName;
1090
+ const indexes = table._indexes || [];
1091
+ const stmts = [];
1092
+ for (const idx of indexes) {
1093
+ const unique2 = idx.unique ? "UNIQUE " : "";
1094
+ if (!idx.name) continue;
1095
+ const colList = Array.isArray(idx.columns) ? idx.columns : [];
1096
+ if (colList.length === 0) continue;
1097
+ const cols = `(${colList.join(", ")})`;
1098
+ const where = idx.where?.raw ? ` WHERE ${idx.where.raw}` : "";
1099
+ stmts.push(
1100
+ `CREATE ${unique2}INDEX IF NOT EXISTS ${idx.name} ON ${tableName} ${cols}${where};`
1101
+ );
1102
+ }
1103
+ return stmts;
1104
+ }
1105
+ async createIndexesForTable(table) {
1106
+ const stmts = this.generateCreateIndexSqls(table);
1107
+ for (const s of stmts) await this.run(s);
1108
+ }
1032
1109
  async ensureMigrationsTable() {
1033
1110
  await this.run(
1034
1111
  `CREATE TABLE IF NOT EXISTS _migrations (name TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)`
@@ -1053,20 +1130,23 @@ var TauriORM = class {
1053
1130
  const track = options?.track ?? true;
1054
1131
  if (track) {
1055
1132
  await this.ensureMigrationsTable();
1133
+ }
1134
+ await this.forcePushForTables(tables, { preserveData: true });
1135
+ if (track) {
1056
1136
  const name = options?.name ?? `init:${tables.map((t) => t._tableName).join(",")}`;
1057
1137
  const already = await this.hasMigration(name);
1058
- if (already) return;
1059
- await this.createTablesIfNotExist(tables);
1060
- await this.recordMigration(name);
1061
- return;
1138
+ if (!already) await this.recordMigration(name);
1062
1139
  }
1063
- await this.createTablesIfNotExist(tables);
1064
1140
  }
1065
1141
  // Configure schema and relations, and generate db.query automatically
1066
1142
  configure(tables, relDefs) {
1067
1143
  this._tables = tables;
1068
1144
  this._relations = relDefs ?? {};
1069
- this.query = makeQueryAPI(tables, this._relations, this.getDb.bind(this));
1145
+ this.query = makeQueryAPI(
1146
+ tables,
1147
+ this._relations ?? {},
1148
+ this.getDb.bind(this)
1149
+ );
1070
1150
  return this;
1071
1151
  }
1072
1152
  // Convenience: migrate from configured tables
@@ -1074,6 +1154,7 @@ var TauriORM = class {
1074
1154
  if (!this._tables)
1075
1155
  throw new Error("No tables configured. Call db.configure({...}) first.");
1076
1156
  await this.migrate(Object.values(this._tables), options);
1157
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
1077
1158
  }
1078
1159
  // --- Schema diff and CLI-like helpers ---
1079
1160
  async diffSchema() {
@@ -1200,6 +1281,13 @@ var TauriORM = class {
1200
1281
  entries.sort((a, b) => a.table.localeCompare(b.table));
1201
1282
  return JSON.stringify(entries);
1202
1283
  }
1284
+ getSchemaSignature() {
1285
+ return this.computeModelSignature();
1286
+ }
1287
+ async printSchemaDiff() {
1288
+ const diff = await this.diffSchema();
1289
+ console.log("Schema diff:", JSON.stringify(diff, null, 2));
1290
+ }
1203
1291
  async isSchemaDirty() {
1204
1292
  const sig = this.computeModelSignature();
1205
1293
  const stored = await this.getSchemaMeta("schema_signature");
@@ -1209,7 +1297,9 @@ var TauriORM = class {
1209
1297
  const status = await this.isSchemaDirty();
1210
1298
  if (!this._tables) throw new Error("No tables configured.");
1211
1299
  if (status.dirty) {
1212
- await this.migrate(Object.values(this._tables), options);
1300
+ await this.forcePushForTables(Object.values(this._tables), {
1301
+ preserveData: true
1302
+ });
1213
1303
  await this.setSchemaMeta(
1214
1304
  "schema_signature",
1215
1305
  this.computeModelSignature()
@@ -1250,13 +1340,17 @@ var TauriORM = class {
1250
1340
  // Force push model to DB: add missing tables/columns, rebuild tables if incompatible
1251
1341
  async forcePush(options) {
1252
1342
  if (!this._tables) throw new Error("No tables configured.");
1343
+ await this.forcePushForTables(Object.values(this._tables), options);
1344
+ }
1345
+ async forcePushForTables(tables, options) {
1253
1346
  const dbi = await this.getDb();
1254
1347
  const preserve = options?.preserveData !== false;
1255
- for (const tbl of Object.values(this._tables)) {
1348
+ for (const tbl of tables) {
1256
1349
  const tableName = tbl._tableName;
1257
1350
  const exists2 = await this.tableExists(tableName);
1258
1351
  if (!exists2) {
1259
1352
  await this.run(this.buildCreateTableSQL(tbl));
1353
+ await this.createIndexesForTable(tbl);
1260
1354
  continue;
1261
1355
  }
1262
1356
  const existingCols = await dbi.select(
@@ -1301,6 +1395,7 @@ var TauriORM = class {
1301
1395
  }
1302
1396
  await this.run(`DROP TABLE ${tableName}`);
1303
1397
  await this.run(`ALTER TABLE ${tmp} RENAME TO ${tableName}`);
1398
+ await this.createIndexesForTable(tbl);
1304
1399
  } else {
1305
1400
  for (const m of missing) {
1306
1401
  let clause = `${m.name} ${m.type}`;
@@ -1311,6 +1406,7 @@ var TauriORM = class {
1311
1406
  }
1312
1407
  await this.run(`ALTER TABLE ${tableName} ADD COLUMN ${clause}`);
1313
1408
  }
1409
+ await this.createIndexesForTable(tbl);
1314
1410
  }
1315
1411
  }
1316
1412
  await this.setSchemaMeta("schema_signature", this.computeModelSignature());
package/dist/index.mjs CHANGED
@@ -135,12 +135,19 @@ function unique(name) {
135
135
  return {
136
136
  on: (...cols) => ({
137
137
  name,
138
- columns: cols.map((c) => c.name)
138
+ columns: cols.map((c) => c.name),
139
+ // runtime marker for DDL rendering
140
+ kind: "unique"
139
141
  })
140
142
  };
141
143
  }
142
144
  function primaryKey(opts) {
143
- return { name: opts.name, columns: opts.columns.map((c) => c.name) };
145
+ return {
146
+ name: opts.name,
147
+ columns: opts.columns.map((c) => c.name),
148
+ // runtime marker for DDL rendering
149
+ kind: "primaryKey"
150
+ };
144
151
  }
145
152
  function check(name, expr) {
146
153
  return { name, expr };
@@ -569,7 +576,10 @@ var TauriORM = class {
569
576
  _relations = null;
570
577
  _dbPromise;
571
578
  constructor(dbUri) {
572
- this._dbPromise = Database.load(dbUri);
579
+ this._dbPromise = Database.load(dbUri).then(async (db) => {
580
+ await db.execute("PRAGMA foreign_keys = ON");
581
+ return db;
582
+ });
573
583
  }
574
584
  async getDb() {
575
585
  return this._dbPromise;
@@ -643,7 +653,7 @@ var TauriORM = class {
643
653
  return ret;
644
654
  }
645
655
  for (const data of this._rows) {
646
- const finalData = { ...data };
656
+ const finalData = Object.assign({}, data);
647
657
  const schema = this._table._schema;
648
658
  for (const [key, col] of Object.entries(schema)) {
649
659
  if (finalData[key] === void 0) {
@@ -938,19 +948,86 @@ var TauriORM = class {
938
948
  }
939
949
  return def;
940
950
  });
941
- return `CREATE TABLE IF NOT EXISTS ${tableName} (${columnDefs.join(
942
- ", "
943
- )});`;
951
+ const tableConstraints = [];
952
+ const constraints = table._constraints;
953
+ if (constraints && constraints.length) {
954
+ for (const spec of constraints) {
955
+ if (spec.expr) {
956
+ const name = spec.name;
957
+ const expr = spec.expr.raw ?? spec.expr?.raw ?? String(spec.expr);
958
+ tableConstraints.push(
959
+ name ? `CONSTRAINT ${name} CHECK (${expr})` : `CHECK (${expr})`
960
+ );
961
+ continue;
962
+ }
963
+ if (spec.foreignColumns) {
964
+ const name = spec.name;
965
+ const cols = spec.columns.join(", ");
966
+ const fTable = spec.foreignTable;
967
+ const fCols = spec.foreignColumns.join(", ");
968
+ let clause = `${name ? `CONSTRAINT ${name} ` : ""}FOREIGN KEY (${cols}) REFERENCES ${fTable} (${fCols})`;
969
+ if (spec.onDelete)
970
+ clause += ` ON DELETE ${String(
971
+ spec.onDelete
972
+ ).toUpperCase()}`;
973
+ if (spec.onUpdate)
974
+ clause += ` ON UPDATE ${String(
975
+ spec.onUpdate
976
+ ).toUpperCase()}`;
977
+ tableConstraints.push(clause);
978
+ continue;
979
+ }
980
+ if (spec.columns) {
981
+ const cols = spec.columns.join(", ");
982
+ const name = spec.name;
983
+ const isPk = spec.kind === "primaryKey" || name && name.toLowerCase().includes("pk");
984
+ if (isPk) {
985
+ tableConstraints.push(
986
+ name ? `CONSTRAINT ${name} PRIMARY KEY (${cols})` : `PRIMARY KEY (${cols})`
987
+ );
988
+ } else {
989
+ tableConstraints.push(
990
+ name ? `CONSTRAINT ${name} UNIQUE (${cols})` : `UNIQUE (${cols})`
991
+ );
992
+ }
993
+ continue;
994
+ }
995
+ }
996
+ }
997
+ const parts = [...columnDefs, ...tableConstraints];
998
+ return `CREATE TABLE IF NOT EXISTS ${tableName} (${parts.join(", ")});`;
944
999
  }
945
1000
  async createTableIfNotExists(table) {
946
1001
  const sql2 = this.generateCreateTableSql(table);
947
1002
  await this.run(sql2);
1003
+ await this.createIndexesForTable(table);
948
1004
  }
949
1005
  async createTablesIfNotExist(tables) {
950
1006
  for (const t of tables) {
951
1007
  await this.createTableIfNotExists(t);
952
1008
  }
953
1009
  }
1010
+ generateCreateIndexSqls(table) {
1011
+ const tableName = table._tableName;
1012
+ const indexes = table._indexes || [];
1013
+ const stmts = [];
1014
+ for (const idx of indexes) {
1015
+ const unique2 = idx.unique ? "UNIQUE " : "";
1016
+ if (!idx.name) continue;
1017
+ const colList = Array.isArray(idx.columns) ? idx.columns : [];
1018
+ if (colList.length === 0) continue;
1019
+ const cols = `(${colList.join(", ")})`;
1020
+ const where = idx.where?.raw ? ` WHERE ${idx.where.raw}` : "";
1021
+ stmts.push(
1022
+ `CREATE ${unique2}INDEX IF NOT EXISTS ${idx.name} ON ${tableName} ${cols}${where};`
1023
+ );
1024
+ }
1025
+ return stmts;
1026
+ }
1027
+ async createIndexesForTable(table) {
1028
+ const stmts = this.generateCreateIndexSqls(table);
1029
+ for (const s of stmts) await this.run(s);
1030
+ }
954
1031
  async ensureMigrationsTable() {
955
1032
  await this.run(
956
1033
  `CREATE TABLE IF NOT EXISTS _migrations (name TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)`
@@ -975,20 +1052,23 @@ var TauriORM = class {
975
1052
  const track = options?.track ?? true;
976
1053
  if (track) {
977
1054
  await this.ensureMigrationsTable();
1055
+ }
1056
+ await this.forcePushForTables(tables, { preserveData: true });
1057
+ if (track) {
978
1058
  const name = options?.name ?? `init:${tables.map((t) => t._tableName).join(",")}`;
979
1059
  const already = await this.hasMigration(name);
980
- if (already) return;
981
- await this.createTablesIfNotExist(tables);
982
- await this.recordMigration(name);
983
- return;
1060
+ if (!already) await this.recordMigration(name);
984
1061
  }
985
- await this.createTablesIfNotExist(tables);
986
1062
  }
987
1063
  // Configure schema and relations, and generate db.query automatically
988
1064
  configure(tables, relDefs) {
989
1065
  this._tables = tables;
990
1066
  this._relations = relDefs ?? {};
991
- this.query = makeQueryAPI(tables, this._relations, this.getDb.bind(this));
1067
+ this.query = makeQueryAPI(
1068
+ tables,
1069
+ this._relations ?? {},
1070
+ this.getDb.bind(this)
1071
+ );
992
1072
  return this;
993
1073
  }
994
1074
  // Convenience: migrate from configured tables
@@ -996,6 +1076,7 @@ var TauriORM = class {
996
1076
  if (!this._tables)
997
1077
  throw new Error("No tables configured. Call db.configure({...}) first.");
998
1078
  await this.migrate(Object.values(this._tables), options);
1079
+ await this.setSchemaMeta("schema_signature", this.computeModelSignature());
999
1080
  }
1000
1081
  // --- Schema diff and CLI-like helpers ---
1001
1082
  async diffSchema() {
@@ -1122,6 +1203,13 @@ var TauriORM = class {
1122
1203
  entries.sort((a, b) => a.table.localeCompare(b.table));
1123
1204
  return JSON.stringify(entries);
1124
1205
  }
1206
+ getSchemaSignature() {
1207
+ return this.computeModelSignature();
1208
+ }
1209
+ async printSchemaDiff() {
1210
+ const diff = await this.diffSchema();
1211
+ console.log("Schema diff:", JSON.stringify(diff, null, 2));
1212
+ }
1125
1213
  async isSchemaDirty() {
1126
1214
  const sig = this.computeModelSignature();
1127
1215
  const stored = await this.getSchemaMeta("schema_signature");
@@ -1131,7 +1219,9 @@ var TauriORM = class {
1131
1219
  const status = await this.isSchemaDirty();
1132
1220
  if (!this._tables) throw new Error("No tables configured.");
1133
1221
  if (status.dirty) {
1134
- await this.migrate(Object.values(this._tables), options);
1222
+ await this.forcePushForTables(Object.values(this._tables), {
1223
+ preserveData: true
1224
+ });
1135
1225
  await this.setSchemaMeta(
1136
1226
  "schema_signature",
1137
1227
  this.computeModelSignature()
@@ -1172,13 +1262,17 @@ var TauriORM = class {
1172
1262
  // Force push model to DB: add missing tables/columns, rebuild tables if incompatible
1173
1263
  async forcePush(options) {
1174
1264
  if (!this._tables) throw new Error("No tables configured.");
1265
+ await this.forcePushForTables(Object.values(this._tables), options);
1266
+ }
1267
+ async forcePushForTables(tables, options) {
1175
1268
  const dbi = await this.getDb();
1176
1269
  const preserve = options?.preserveData !== false;
1177
- for (const tbl of Object.values(this._tables)) {
1270
+ for (const tbl of tables) {
1178
1271
  const tableName = tbl._tableName;
1179
1272
  const exists2 = await this.tableExists(tableName);
1180
1273
  if (!exists2) {
1181
1274
  await this.run(this.buildCreateTableSQL(tbl));
1275
+ await this.createIndexesForTable(tbl);
1182
1276
  continue;
1183
1277
  }
1184
1278
  const existingCols = await dbi.select(
@@ -1223,6 +1317,7 @@ var TauriORM = class {
1223
1317
  }
1224
1318
  await this.run(`DROP TABLE ${tableName}`);
1225
1319
  await this.run(`ALTER TABLE ${tmp} RENAME TO ${tableName}`);
1320
+ await this.createIndexesForTable(tbl);
1226
1321
  } else {
1227
1322
  for (const m of missing) {
1228
1323
  let clause = `${m.name} ${m.type}`;
@@ -1233,6 +1328,7 @@ var TauriORM = class {
1233
1328
  }
1234
1329
  await this.run(`ALTER TABLE ${tableName} ADD COLUMN ${clause}`);
1235
1330
  }
1331
+ await this.createIndexesForTable(tbl);
1236
1332
  }
1237
1333
  }
1238
1334
  await this.setSchemaMeta("schema_signature", this.computeModelSignature());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@type32/tauri-sqlite-orm",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "A Drizzle-like ORM for Tauri v2's SQL JS API plugin.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",