sqlite-zod-orm 3.17.0 → 3.18.0

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.js CHANGED
@@ -4429,6 +4429,26 @@ class QueryBuilder {
4429
4429
  this.iqo.rawWheres.push({ sql, params });
4430
4430
  return this;
4431
4431
  }
4432
+ whereIn(column, values) {
4433
+ if (Array.isArray(values)) {
4434
+ const placeholders = values.map(() => "?").join(", ");
4435
+ this.iqo.rawWheres.push({ sql: `"${column}" IN (${placeholders})`, params: values });
4436
+ } else {
4437
+ const inner = compileIQO(values.tableName, values.iqo);
4438
+ this.iqo.rawWheres.push({ sql: `"${column}" IN (${inner.sql})`, params: inner.params });
4439
+ }
4440
+ return this;
4441
+ }
4442
+ whereNotIn(column, values) {
4443
+ if (Array.isArray(values)) {
4444
+ const placeholders = values.map(() => "?").join(", ");
4445
+ this.iqo.rawWheres.push({ sql: `"${column}" NOT IN (${placeholders})`, params: values });
4446
+ } else {
4447
+ const inner = compileIQO(values.tableName, values.iqo);
4448
+ this.iqo.rawWheres.push({ sql: `"${column}" NOT IN (${inner.sql})`, params: inner.params });
4449
+ }
4450
+ return this;
4451
+ }
4432
4452
  with(...relations) {
4433
4453
  this.iqo.includes.push(...relations);
4434
4454
  return this;
@@ -5483,6 +5503,38 @@ class _Database {
5483
5503
  seed(fixtures) {
5484
5504
  this.load(fixtures, { append: true });
5485
5505
  }
5506
+ diff() {
5507
+ const result = {};
5508
+ const systemCols = new Set(["id", "createdAt", "updatedAt", "deletedAt"]);
5509
+ for (const [tableName, schema] of Object.entries(this.schemas)) {
5510
+ const schemaFields = getStorableFields(schema);
5511
+ const schemaColMap = new Map(schemaFields.map((f) => [f.name, zodTypeToSqlType(f.type)]));
5512
+ const liveColumns = this.columns(tableName);
5513
+ const liveColMap = new Map(liveColumns.map((c) => [c.name, c.type]));
5514
+ const added = [];
5515
+ const removed = [];
5516
+ const typeChanged = [];
5517
+ for (const [col, expectedType] of schemaColMap) {
5518
+ if (!liveColMap.has(col)) {
5519
+ added.push(col);
5520
+ } else {
5521
+ const actualType = liveColMap.get(col);
5522
+ if (actualType !== expectedType) {
5523
+ typeChanged.push({ column: col, expected: expectedType, actual: actualType });
5524
+ }
5525
+ }
5526
+ }
5527
+ for (const col of liveColMap.keys()) {
5528
+ if (!systemCols.has(col) && !schemaColMap.has(col)) {
5529
+ removed.push(col);
5530
+ }
5531
+ }
5532
+ if (added.length > 0 || removed.length > 0 || typeChanged.length > 0) {
5533
+ result[tableName] = { added, removed, typeChanged };
5534
+ }
5535
+ }
5536
+ return result;
5537
+ }
5486
5538
  }
5487
5539
  var Database = _Database;
5488
5540
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlite-zod-orm",
3
- "version": "3.17.0",
3
+ "version": "3.18.0",
4
4
  "description": "Type-safe SQLite ORM for Bun — Zod schemas, fluent queries, auto relationships, zero SQL",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/builder.ts CHANGED
@@ -231,6 +231,39 @@ export class QueryBuilder<T extends Record<string, any>, TResult extends Record<
231
231
  return this;
232
232
  }
233
233
 
234
+ /**
235
+ * Filter by column value being in a list or subquery.
236
+ * ```ts
237
+ * db.users.select().whereIn('id', [1, 2, 3]).all()
238
+ * db.users.select().whereIn('id', db.orders.select('userId')).all()
239
+ * ```
240
+ */
241
+ whereIn(column: keyof T & string, values: any[] | QueryBuilder<any, any>): this {
242
+ if (Array.isArray(values)) {
243
+ const placeholders = values.map(() => '?').join(', ');
244
+ this.iqo.rawWheres.push({ sql: `"${column}" IN (${placeholders})`, params: values });
245
+ } else {
246
+ // Subquery: compile the inner QueryBuilder's IQO
247
+ const inner = compileIQO((values as any).tableName, (values as any).iqo);
248
+ this.iqo.rawWheres.push({ sql: `"${column}" IN (${inner.sql})`, params: inner.params });
249
+ }
250
+ return this;
251
+ }
252
+
253
+ /**
254
+ * Filter by column value NOT being in a list or subquery.
255
+ */
256
+ whereNotIn(column: keyof T & string, values: any[] | QueryBuilder<any, any>): this {
257
+ if (Array.isArray(values)) {
258
+ const placeholders = values.map(() => '?').join(', ');
259
+ this.iqo.rawWheres.push({ sql: `"${column}" NOT IN (${placeholders})`, params: values });
260
+ } else {
261
+ const inner = compileIQO((values as any).tableName, (values as any).iqo);
262
+ this.iqo.rawWheres.push({ sql: `"${column}" NOT IN (${inner.sql})`, params: inner.params });
263
+ }
264
+ return this;
265
+ }
266
+
234
267
  /**
235
268
  * Eagerly load a related entity and attach as an array property.
236
269
  *
package/src/database.ts CHANGED
@@ -473,6 +473,56 @@ class _Database<Schemas extends SchemaMap> {
473
473
  public seed(fixtures: Record<string, Record<string, any>[]>): void {
474
474
  this.load(fixtures, { append: true });
475
475
  }
476
+
477
+ // =========================================================================
478
+ // Schema Diffing
479
+ // =========================================================================
480
+
481
+ /**
482
+ * Compare Zod schemas against the live SQLite table structure.
483
+ * Returns a diff object per table: { added, removed, typeChanged }.
484
+ */
485
+ public diff(): Record<string, { added: string[]; removed: string[]; typeChanged: { column: string; expected: string; actual: string }[] }> {
486
+ const result: Record<string, { added: string[]; removed: string[]; typeChanged: { column: string; expected: string; actual: string }[] }> = {};
487
+ const systemCols = new Set(['id', 'createdAt', 'updatedAt', 'deletedAt']);
488
+
489
+ for (const [tableName, schema] of Object.entries(this.schemas)) {
490
+ const schemaFields = getStorableFields(schema);
491
+ const schemaColMap = new Map(schemaFields.map(f => [f.name, zodTypeToSqlType(f.type)]));
492
+
493
+ const liveColumns = this.columns(tableName);
494
+ const liveColMap = new Map(liveColumns.map(c => [c.name, c.type]));
495
+
496
+ const added: string[] = [];
497
+ const removed: string[] = [];
498
+ const typeChanged: { column: string; expected: string; actual: string }[] = [];
499
+
500
+ // Columns in schema but not in live DB
501
+ for (const [col, expectedType] of schemaColMap) {
502
+ if (!liveColMap.has(col)) {
503
+ added.push(col);
504
+ } else {
505
+ const actualType = liveColMap.get(col)!;
506
+ if (actualType !== expectedType) {
507
+ typeChanged.push({ column: col, expected: expectedType, actual: actualType });
508
+ }
509
+ }
510
+ }
511
+
512
+ // Columns in live DB but not in schema (excluding system columns)
513
+ for (const col of liveColMap.keys()) {
514
+ if (!systemCols.has(col) && !schemaColMap.has(col)) {
515
+ removed.push(col);
516
+ }
517
+ }
518
+
519
+ if (added.length > 0 || removed.length > 0 || typeChanged.length > 0) {
520
+ result[tableName] = { added, removed, typeChanged };
521
+ }
522
+ }
523
+
524
+ return result;
525
+ }
476
526
  }
477
527
 
478
528
  // =============================================================================