@type32/tauri-sqlite-orm 0.2.9 → 0.2.11

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
@@ -286,9 +286,25 @@ declare class TauriORM {
286
286
  private tables;
287
287
  constructor(db: Database, schema?: Record<string, AnyTable | Record<string, Relation>> | undefined);
288
288
  private buildColumnDefinition;
289
+ checkMigration(): Promise<{
290
+ safe: boolean;
291
+ changes: {
292
+ tablesToCreate: string[];
293
+ tablesToRecreate: string[];
294
+ tablesToDrop: string[];
295
+ columnsToAdd: Array<{
296
+ table: string;
297
+ column: string;
298
+ }>;
299
+ };
300
+ }>;
289
301
  migrate(options?: {
290
302
  performDestructiveActions?: boolean;
303
+ dryRun?: boolean;
291
304
  }): Promise<void>;
305
+ private canAddColumnWithAlter;
306
+ private hasColumnDefinitionChanged;
307
+ private recreateTable;
292
308
  select<T extends AnyTable, C extends (keyof T['_']['columns'])[] | undefined = undefined>(table: T, columns?: C): SelectQueryBuilder<T, C>;
293
309
  insert<T extends AnyTable>(table: T): InsertQueryBuilder<T>;
294
310
  update<T extends AnyTable>(table: T): UpdateQueryBuilder<T>;
package/dist/index.d.ts CHANGED
@@ -286,9 +286,25 @@ declare class TauriORM {
286
286
  private tables;
287
287
  constructor(db: Database, schema?: Record<string, AnyTable | Record<string, Relation>> | undefined);
288
288
  private buildColumnDefinition;
289
+ checkMigration(): Promise<{
290
+ safe: boolean;
291
+ changes: {
292
+ tablesToCreate: string[];
293
+ tablesToRecreate: string[];
294
+ tablesToDrop: string[];
295
+ columnsToAdd: Array<{
296
+ table: string;
297
+ column: string;
298
+ }>;
299
+ };
300
+ }>;
289
301
  migrate(options?: {
290
302
  performDestructiveActions?: boolean;
303
+ dryRun?: boolean;
291
304
  }): Promise<void>;
305
+ private canAddColumnWithAlter;
306
+ private hasColumnDefinitionChanged;
307
+ private recreateTable;
292
308
  select<T extends AnyTable, C extends (keyof T['_']['columns'])[] | undefined = undefined>(table: T, columns?: C): SelectQueryBuilder<T, C>;
293
309
  insert<T extends AnyTable>(table: T): InsertQueryBuilder<T>;
294
310
  update<T extends AnyTable>(table: T): UpdateQueryBuilder<T>;
package/dist/index.js CHANGED
@@ -1258,7 +1258,86 @@ var TauriORM = class {
1258
1258
  }
1259
1259
  return sql2;
1260
1260
  }
1261
+ async checkMigration() {
1262
+ const dbTables = await this.db.select(
1263
+ `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`
1264
+ );
1265
+ const dbTableNames = new Set(dbTables.map((t) => t.name));
1266
+ const schemaTableNames = new Set(Array.from(this.tables.keys()));
1267
+ const changes = {
1268
+ tablesToCreate: [],
1269
+ tablesToRecreate: [],
1270
+ tablesToDrop: [],
1271
+ columnsToAdd: []
1272
+ };
1273
+ for (const tableName of schemaTableNames) {
1274
+ if (!dbTableNames.has(tableName)) {
1275
+ changes.tablesToCreate.push(tableName);
1276
+ }
1277
+ }
1278
+ for (const tableName of dbTableNames) {
1279
+ if (!schemaTableNames.has(tableName)) {
1280
+ changes.tablesToDrop.push(tableName);
1281
+ }
1282
+ }
1283
+ for (const table of this.tables.values()) {
1284
+ const tableName = table._.name;
1285
+ if (!dbTableNames.has(tableName)) continue;
1286
+ const existingTableInfo = await this.db.select(`PRAGMA table_info('${tableName}')`);
1287
+ const existingIndexes = await this.db.select(`PRAGMA index_list('${tableName}')`);
1288
+ const uniqueColumns = /* @__PURE__ */ new Set();
1289
+ for (const index of existingIndexes) {
1290
+ if (index.unique === 1 && index.origin === "u") {
1291
+ const indexInfo = await this.db.select(`PRAGMA index_info('${index.name}')`);
1292
+ if (indexInfo.length === 1) {
1293
+ uniqueColumns.add(indexInfo[0].name);
1294
+ }
1295
+ }
1296
+ }
1297
+ const existingColumns = new Map(existingTableInfo.map((c) => [c.name, c]));
1298
+ const schemaColumns = table._.columns;
1299
+ let needsRecreate = false;
1300
+ for (const [colName, column] of Object.entries(schemaColumns)) {
1301
+ const existing = existingColumns.get(colName);
1302
+ if (!existing) {
1303
+ if (!this.canAddColumnWithAlter(column)) {
1304
+ needsRecreate = true;
1305
+ break;
1306
+ }
1307
+ changes.columnsToAdd.push({ table: tableName, column: colName });
1308
+ } else {
1309
+ const hasUniqueInDB = uniqueColumns.has(colName);
1310
+ const wantsUnique = !!column.options.unique;
1311
+ if (hasUniqueInDB !== wantsUnique || this.hasColumnDefinitionChanged(column, existing)) {
1312
+ needsRecreate = true;
1313
+ break;
1314
+ }
1315
+ }
1316
+ }
1317
+ for (const existingCol of existingColumns.keys()) {
1318
+ if (!schemaColumns[existingCol]) {
1319
+ needsRecreate = true;
1320
+ break;
1321
+ }
1322
+ }
1323
+ if (needsRecreate) {
1324
+ changes.tablesToRecreate.push(tableName);
1325
+ }
1326
+ }
1327
+ const safe = changes.tablesToRecreate.length === 0 && changes.tablesToDrop.length === 0;
1328
+ return { safe, changes };
1329
+ }
1261
1330
  async migrate(options) {
1331
+ if (options?.dryRun) {
1332
+ const check = await this.checkMigration();
1333
+ console.log("[Tauri-ORM] Migration Preview (Dry Run):");
1334
+ console.log(" Tables to create:", check.changes.tablesToCreate);
1335
+ console.log(" Tables to recreate (DESTRUCTIVE):", check.changes.tablesToRecreate);
1336
+ console.log(" Tables to drop:", check.changes.tablesToDrop);
1337
+ console.log(" Columns to add:", check.changes.columnsToAdd);
1338
+ console.log(" Safe migration:", check.safe);
1339
+ return;
1340
+ }
1262
1341
  const dbTables = await this.db.select(
1263
1342
  `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`
1264
1343
  );
@@ -1269,30 +1348,62 @@ var TauriORM = class {
1269
1348
  const tableExists = dbTableNames.has(tableName);
1270
1349
  if (!tableExists) {
1271
1350
  const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
1272
- const createSql = `CREATE TABLE ${tableName}
1273
- (
1274
- ${columnsSql}
1275
- )`;
1351
+ const createSql = `CREATE TABLE ${tableName} (${columnsSql})`;
1276
1352
  await this.db.execute(createSql);
1277
1353
  } else {
1278
1354
  const existingTableInfo = await this.db.select(`PRAGMA table_info('${tableName}')`);
1279
- const existingColumnNames = new Set(existingTableInfo.map((c) => c.name));
1280
- const schemaColumnNames = new Set(Object.keys(table._.columns));
1281
- for (const column of Object.values(table._.columns)) {
1282
- if (!existingColumnNames.has(column._.name)) {
1283
- const columnSql = this.buildColumnDefinition(column, true);
1284
- const alterSql = `ALTER TABLE ${tableName}
1285
- ADD COLUMN ${columnSql}`;
1286
- await this.db.execute(alterSql);
1355
+ const existingIndexes = await this.db.select(`PRAGMA index_list('${tableName}')`);
1356
+ const uniqueColumns = /* @__PURE__ */ new Set();
1357
+ for (const index of existingIndexes) {
1358
+ if (index.unique === 1 && index.origin === "u") {
1359
+ const indexInfo = await this.db.select(`PRAGMA index_info('${index.name}')`);
1360
+ if (indexInfo.length === 1) {
1361
+ uniqueColumns.add(indexInfo[0].name);
1362
+ }
1363
+ }
1364
+ }
1365
+ const existingColumns = new Map(existingTableInfo.map((c) => [c.name, c]));
1366
+ const schemaColumns = table._.columns;
1367
+ let needsRecreate = false;
1368
+ const columnsToAdd = [];
1369
+ for (const [colName, column] of Object.entries(schemaColumns)) {
1370
+ const existing = existingColumns.get(colName);
1371
+ if (!existing) {
1372
+ if (this.canAddColumnWithAlter(column)) {
1373
+ columnsToAdd.push(column);
1374
+ } else {
1375
+ needsRecreate = true;
1376
+ break;
1377
+ }
1378
+ } else {
1379
+ const hasUniqueInDB = uniqueColumns.has(colName);
1380
+ const wantsUnique = !!column.options.unique;
1381
+ if (hasUniqueInDB !== wantsUnique) {
1382
+ needsRecreate = true;
1383
+ break;
1384
+ }
1385
+ if (this.hasColumnDefinitionChanged(column, existing)) {
1386
+ needsRecreate = true;
1387
+ break;
1388
+ }
1287
1389
  }
1288
1390
  }
1289
1391
  if (options?.performDestructiveActions) {
1290
- for (const colName of existingColumnNames) {
1291
- if (!schemaColumnNames.has(colName)) {
1292
- await this.dropColumn(tableName, colName);
1392
+ for (const existingCol of existingColumns.keys()) {
1393
+ if (!schemaColumns[existingCol]) {
1394
+ needsRecreate = true;
1395
+ break;
1293
1396
  }
1294
1397
  }
1295
1398
  }
1399
+ if (needsRecreate) {
1400
+ await this.recreateTable(tableName, table);
1401
+ } else if (columnsToAdd.length > 0) {
1402
+ for (const column of columnsToAdd) {
1403
+ const columnSql = this.buildColumnDefinition(column, true);
1404
+ await this.db.execute(`ALTER TABLE ${tableName} ADD COLUMN ${columnSql}`);
1405
+ }
1406
+ }
1296
1407
  }
1297
1408
  }
1298
1409
  if (options?.performDestructiveActions) {
@@ -1303,6 +1414,38 @@ var TauriORM = class {
1303
1414
  }
1304
1415
  }
1305
1416
  }
1417
+ canAddColumnWithAlter(column) {
1418
+ if (column.options.primaryKey) return false;
1419
+ if (column.options.unique) return false;
1420
+ if (column._.notNull && column.options.default === void 0 && !column.options.$defaultFn) return false;
1421
+ return true;
1422
+ }
1423
+ hasColumnDefinitionChanged(column, existing) {
1424
+ if (column.type.toUpperCase() !== existing.type.toUpperCase()) return true;
1425
+ if (column._.notNull !== (existing.notnull === 1)) return true;
1426
+ if (!!column.options.primaryKey !== (existing.pk === 1)) return true;
1427
+ const hasDefault = column.options.default !== void 0;
1428
+ const existingHasDefault = existing.dflt_value !== null;
1429
+ if (hasDefault !== existingHasDefault) return true;
1430
+ return false;
1431
+ }
1432
+ async recreateTable(tableName, table) {
1433
+ const tempTableName = `${tableName}_new_${Date.now()}`;
1434
+ const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
1435
+ await this.db.execute(`CREATE TABLE ${tempTableName} (${columnsSql})`);
1436
+ const oldColumns = await this.db.select(`PRAGMA table_info('${tableName}')`);
1437
+ const oldColumnNames = oldColumns.map((c) => c.name);
1438
+ const newColumnNames = Object.keys(table._.columns);
1439
+ const commonColumns = oldColumnNames.filter((name) => newColumnNames.includes(name));
1440
+ if (commonColumns.length > 0) {
1441
+ const columnsList = commonColumns.join(", ");
1442
+ await this.db.execute(
1443
+ `INSERT INTO ${tempTableName} (${columnsList}) SELECT ${columnsList} FROM ${tableName}`
1444
+ );
1445
+ }
1446
+ await this.db.execute(`DROP TABLE ${tableName}`);
1447
+ await this.db.execute(`ALTER TABLE ${tempTableName} RENAME TO ${tableName}`);
1448
+ }
1306
1449
  select(table, columns) {
1307
1450
  const internalTable = this.tables.get(table._.name);
1308
1451
  if (!internalTable) {
package/dist/index.mjs CHANGED
@@ -1159,7 +1159,86 @@ var TauriORM = class {
1159
1159
  }
1160
1160
  return sql2;
1161
1161
  }
1162
+ async checkMigration() {
1163
+ const dbTables = await this.db.select(
1164
+ `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`
1165
+ );
1166
+ const dbTableNames = new Set(dbTables.map((t) => t.name));
1167
+ const schemaTableNames = new Set(Array.from(this.tables.keys()));
1168
+ const changes = {
1169
+ tablesToCreate: [],
1170
+ tablesToRecreate: [],
1171
+ tablesToDrop: [],
1172
+ columnsToAdd: []
1173
+ };
1174
+ for (const tableName of schemaTableNames) {
1175
+ if (!dbTableNames.has(tableName)) {
1176
+ changes.tablesToCreate.push(tableName);
1177
+ }
1178
+ }
1179
+ for (const tableName of dbTableNames) {
1180
+ if (!schemaTableNames.has(tableName)) {
1181
+ changes.tablesToDrop.push(tableName);
1182
+ }
1183
+ }
1184
+ for (const table of this.tables.values()) {
1185
+ const tableName = table._.name;
1186
+ if (!dbTableNames.has(tableName)) continue;
1187
+ const existingTableInfo = await this.db.select(`PRAGMA table_info('${tableName}')`);
1188
+ const existingIndexes = await this.db.select(`PRAGMA index_list('${tableName}')`);
1189
+ const uniqueColumns = /* @__PURE__ */ new Set();
1190
+ for (const index of existingIndexes) {
1191
+ if (index.unique === 1 && index.origin === "u") {
1192
+ const indexInfo = await this.db.select(`PRAGMA index_info('${index.name}')`);
1193
+ if (indexInfo.length === 1) {
1194
+ uniqueColumns.add(indexInfo[0].name);
1195
+ }
1196
+ }
1197
+ }
1198
+ const existingColumns = new Map(existingTableInfo.map((c) => [c.name, c]));
1199
+ const schemaColumns = table._.columns;
1200
+ let needsRecreate = false;
1201
+ for (const [colName, column] of Object.entries(schemaColumns)) {
1202
+ const existing = existingColumns.get(colName);
1203
+ if (!existing) {
1204
+ if (!this.canAddColumnWithAlter(column)) {
1205
+ needsRecreate = true;
1206
+ break;
1207
+ }
1208
+ changes.columnsToAdd.push({ table: tableName, column: colName });
1209
+ } else {
1210
+ const hasUniqueInDB = uniqueColumns.has(colName);
1211
+ const wantsUnique = !!column.options.unique;
1212
+ if (hasUniqueInDB !== wantsUnique || this.hasColumnDefinitionChanged(column, existing)) {
1213
+ needsRecreate = true;
1214
+ break;
1215
+ }
1216
+ }
1217
+ }
1218
+ for (const existingCol of existingColumns.keys()) {
1219
+ if (!schemaColumns[existingCol]) {
1220
+ needsRecreate = true;
1221
+ break;
1222
+ }
1223
+ }
1224
+ if (needsRecreate) {
1225
+ changes.tablesToRecreate.push(tableName);
1226
+ }
1227
+ }
1228
+ const safe = changes.tablesToRecreate.length === 0 && changes.tablesToDrop.length === 0;
1229
+ return { safe, changes };
1230
+ }
1162
1231
  async migrate(options) {
1232
+ if (options?.dryRun) {
1233
+ const check = await this.checkMigration();
1234
+ console.log("[Tauri-ORM] Migration Preview (Dry Run):");
1235
+ console.log(" Tables to create:", check.changes.tablesToCreate);
1236
+ console.log(" Tables to recreate (DESTRUCTIVE):", check.changes.tablesToRecreate);
1237
+ console.log(" Tables to drop:", check.changes.tablesToDrop);
1238
+ console.log(" Columns to add:", check.changes.columnsToAdd);
1239
+ console.log(" Safe migration:", check.safe);
1240
+ return;
1241
+ }
1163
1242
  const dbTables = await this.db.select(
1164
1243
  `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`
1165
1244
  );
@@ -1170,30 +1249,62 @@ var TauriORM = class {
1170
1249
  const tableExists = dbTableNames.has(tableName);
1171
1250
  if (!tableExists) {
1172
1251
  const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
1173
- const createSql = `CREATE TABLE ${tableName}
1174
- (
1175
- ${columnsSql}
1176
- )`;
1252
+ const createSql = `CREATE TABLE ${tableName} (${columnsSql})`;
1177
1253
  await this.db.execute(createSql);
1178
1254
  } else {
1179
1255
  const existingTableInfo = await this.db.select(`PRAGMA table_info('${tableName}')`);
1180
- const existingColumnNames = new Set(existingTableInfo.map((c) => c.name));
1181
- const schemaColumnNames = new Set(Object.keys(table._.columns));
1182
- for (const column of Object.values(table._.columns)) {
1183
- if (!existingColumnNames.has(column._.name)) {
1184
- const columnSql = this.buildColumnDefinition(column, true);
1185
- const alterSql = `ALTER TABLE ${tableName}
1186
- ADD COLUMN ${columnSql}`;
1187
- await this.db.execute(alterSql);
1256
+ const existingIndexes = await this.db.select(`PRAGMA index_list('${tableName}')`);
1257
+ const uniqueColumns = /* @__PURE__ */ new Set();
1258
+ for (const index of existingIndexes) {
1259
+ if (index.unique === 1 && index.origin === "u") {
1260
+ const indexInfo = await this.db.select(`PRAGMA index_info('${index.name}')`);
1261
+ if (indexInfo.length === 1) {
1262
+ uniqueColumns.add(indexInfo[0].name);
1263
+ }
1264
+ }
1265
+ }
1266
+ const existingColumns = new Map(existingTableInfo.map((c) => [c.name, c]));
1267
+ const schemaColumns = table._.columns;
1268
+ let needsRecreate = false;
1269
+ const columnsToAdd = [];
1270
+ for (const [colName, column] of Object.entries(schemaColumns)) {
1271
+ const existing = existingColumns.get(colName);
1272
+ if (!existing) {
1273
+ if (this.canAddColumnWithAlter(column)) {
1274
+ columnsToAdd.push(column);
1275
+ } else {
1276
+ needsRecreate = true;
1277
+ break;
1278
+ }
1279
+ } else {
1280
+ const hasUniqueInDB = uniqueColumns.has(colName);
1281
+ const wantsUnique = !!column.options.unique;
1282
+ if (hasUniqueInDB !== wantsUnique) {
1283
+ needsRecreate = true;
1284
+ break;
1285
+ }
1286
+ if (this.hasColumnDefinitionChanged(column, existing)) {
1287
+ needsRecreate = true;
1288
+ break;
1289
+ }
1188
1290
  }
1189
1291
  }
1190
1292
  if (options?.performDestructiveActions) {
1191
- for (const colName of existingColumnNames) {
1192
- if (!schemaColumnNames.has(colName)) {
1193
- await this.dropColumn(tableName, colName);
1293
+ for (const existingCol of existingColumns.keys()) {
1294
+ if (!schemaColumns[existingCol]) {
1295
+ needsRecreate = true;
1296
+ break;
1194
1297
  }
1195
1298
  }
1196
1299
  }
1300
+ if (needsRecreate) {
1301
+ await this.recreateTable(tableName, table);
1302
+ } else if (columnsToAdd.length > 0) {
1303
+ for (const column of columnsToAdd) {
1304
+ const columnSql = this.buildColumnDefinition(column, true);
1305
+ await this.db.execute(`ALTER TABLE ${tableName} ADD COLUMN ${columnSql}`);
1306
+ }
1307
+ }
1197
1308
  }
1198
1309
  }
1199
1310
  if (options?.performDestructiveActions) {
@@ -1204,6 +1315,38 @@ var TauriORM = class {
1204
1315
  }
1205
1316
  }
1206
1317
  }
1318
+ canAddColumnWithAlter(column) {
1319
+ if (column.options.primaryKey) return false;
1320
+ if (column.options.unique) return false;
1321
+ if (column._.notNull && column.options.default === void 0 && !column.options.$defaultFn) return false;
1322
+ return true;
1323
+ }
1324
+ hasColumnDefinitionChanged(column, existing) {
1325
+ if (column.type.toUpperCase() !== existing.type.toUpperCase()) return true;
1326
+ if (column._.notNull !== (existing.notnull === 1)) return true;
1327
+ if (!!column.options.primaryKey !== (existing.pk === 1)) return true;
1328
+ const hasDefault = column.options.default !== void 0;
1329
+ const existingHasDefault = existing.dflt_value !== null;
1330
+ if (hasDefault !== existingHasDefault) return true;
1331
+ return false;
1332
+ }
1333
+ async recreateTable(tableName, table) {
1334
+ const tempTableName = `${tableName}_new_${Date.now()}`;
1335
+ const columnsSql = Object.values(table._.columns).map((col) => this.buildColumnDefinition(col)).join(", ");
1336
+ await this.db.execute(`CREATE TABLE ${tempTableName} (${columnsSql})`);
1337
+ const oldColumns = await this.db.select(`PRAGMA table_info('${tableName}')`);
1338
+ const oldColumnNames = oldColumns.map((c) => c.name);
1339
+ const newColumnNames = Object.keys(table._.columns);
1340
+ const commonColumns = oldColumnNames.filter((name) => newColumnNames.includes(name));
1341
+ if (commonColumns.length > 0) {
1342
+ const columnsList = commonColumns.join(", ");
1343
+ await this.db.execute(
1344
+ `INSERT INTO ${tempTableName} (${columnsList}) SELECT ${columnsList} FROM ${tableName}`
1345
+ );
1346
+ }
1347
+ await this.db.execute(`DROP TABLE ${tableName}`);
1348
+ await this.db.execute(`ALTER TABLE ${tempTableName} RENAME TO ${tableName}`);
1349
+ }
1207
1350
  select(table, columns) {
1208
1351
  const internalTable = this.tables.get(table._.name);
1209
1352
  if (!internalTable) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@type32/tauri-sqlite-orm",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
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",