sqlite-zod-orm 3.9.0 → 3.11.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
@@ -13,65 +13,6 @@ var __export = (target, all) => {
13
13
  // src/database.ts
14
14
  import { Database as SqliteDatabase } from "bun:sqlite";
15
15
 
16
- // src/ast.ts
17
- var wrapNode = (val) => val !== null && typeof val === "object" && ("type" in val) ? val : { type: "literal", value: val };
18
- function compileAST(node) {
19
- if (node.type === "column")
20
- return { sql: `"${node.name}"`, params: [] };
21
- if (node.type === "literal") {
22
- if (node.value instanceof Date)
23
- return { sql: "?", params: [node.value.toISOString()] };
24
- if (typeof node.value === "boolean")
25
- return { sql: "?", params: [node.value ? 1 : 0] };
26
- return { sql: "?", params: [node.value] };
27
- }
28
- if (node.type === "function") {
29
- const compiledArgs = node.args.map(compileAST);
30
- return {
31
- sql: `${node.name}(${compiledArgs.map((c) => c.sql).join(", ")})`,
32
- params: compiledArgs.flatMap((c) => c.params)
33
- };
34
- }
35
- if (node.type === "operator") {
36
- const left = compileAST(node.left);
37
- const right = compileAST(node.right);
38
- return {
39
- sql: `(${left.sql} ${node.op} ${right.sql})`,
40
- params: [...left.params, ...right.params]
41
- };
42
- }
43
- throw new Error("Unknown AST node type");
44
- }
45
- var createColumnProxy = () => new Proxy({}, {
46
- get: (_, prop) => ({ type: "column", name: prop })
47
- });
48
- var createFunctionProxy = () => new Proxy({}, {
49
- get: (_, funcName) => (...args) => ({
50
- type: "function",
51
- name: funcName.toUpperCase(),
52
- args: args.map(wrapNode)
53
- })
54
- });
55
- var op = {
56
- eq: (left, right) => ({ type: "operator", op: "=", left: wrapNode(left), right: wrapNode(right) }),
57
- ne: (left, right) => ({ type: "operator", op: "!=", left: wrapNode(left), right: wrapNode(right) }),
58
- gt: (left, right) => ({ type: "operator", op: ">", left: wrapNode(left), right: wrapNode(right) }),
59
- gte: (left, right) => ({ type: "operator", op: ">=", left: wrapNode(left), right: wrapNode(right) }),
60
- lt: (left, right) => ({ type: "operator", op: "<", left: wrapNode(left), right: wrapNode(right) }),
61
- lte: (left, right) => ({ type: "operator", op: "<=", left: wrapNode(left), right: wrapNode(right) }),
62
- and: (left, right) => ({ type: "operator", op: "AND", left: wrapNode(left), right: wrapNode(right) }),
63
- or: (left, right) => ({ type: "operator", op: "OR", left: wrapNode(left), right: wrapNode(right) }),
64
- like: (left, right) => ({ type: "operator", op: "LIKE", left: wrapNode(left), right: wrapNode(right) }),
65
- isNull: (node) => ({ type: "operator", op: "IS", left: wrapNode(node), right: { type: "literal", value: null } }),
66
- isNotNull: (node) => ({ type: "operator", op: "IS NOT", left: wrapNode(node), right: { type: "literal", value: null } }),
67
- in: (left, values) => ({
68
- type: "function",
69
- name: `${compileAST(wrapNode(left)).sql} IN`,
70
- args: values.map((v) => wrapNode(v))
71
- }),
72
- not: (node) => ({ type: "operator", op: "NOT", left: { type: "literal", value: "" }, right: wrapNode(node) })
73
- };
74
-
75
16
  // node_modules/zod/v3/external.js
76
17
  var exports_external = {};
77
18
  __export(exports_external, {
@@ -4139,7 +4080,66 @@ function transformFromStorage(row, schema) {
4139
4080
  return transformed;
4140
4081
  }
4141
4082
 
4142
- // src/query.ts
4083
+ // src/ast.ts
4084
+ var wrapNode = (val) => val !== null && typeof val === "object" && ("type" in val) ? val : { type: "literal", value: val };
4085
+ function compileAST(node) {
4086
+ if (node.type === "column")
4087
+ return { sql: `"${node.name}"`, params: [] };
4088
+ if (node.type === "literal") {
4089
+ if (node.value instanceof Date)
4090
+ return { sql: "?", params: [node.value.toISOString()] };
4091
+ if (typeof node.value === "boolean")
4092
+ return { sql: "?", params: [node.value ? 1 : 0] };
4093
+ return { sql: "?", params: [node.value] };
4094
+ }
4095
+ if (node.type === "function") {
4096
+ const compiledArgs = node.args.map(compileAST);
4097
+ return {
4098
+ sql: `${node.name}(${compiledArgs.map((c) => c.sql).join(", ")})`,
4099
+ params: compiledArgs.flatMap((c) => c.params)
4100
+ };
4101
+ }
4102
+ if (node.type === "operator") {
4103
+ const left = compileAST(node.left);
4104
+ const right = compileAST(node.right);
4105
+ return {
4106
+ sql: `(${left.sql} ${node.op} ${right.sql})`,
4107
+ params: [...left.params, ...right.params]
4108
+ };
4109
+ }
4110
+ throw new Error("Unknown AST node type");
4111
+ }
4112
+ var createColumnProxy = () => new Proxy({}, {
4113
+ get: (_, prop) => ({ type: "column", name: prop })
4114
+ });
4115
+ var createFunctionProxy = () => new Proxy({}, {
4116
+ get: (_, funcName) => (...args) => ({
4117
+ type: "function",
4118
+ name: funcName.toUpperCase(),
4119
+ args: args.map(wrapNode)
4120
+ })
4121
+ });
4122
+ var op = {
4123
+ eq: (left, right) => ({ type: "operator", op: "=", left: wrapNode(left), right: wrapNode(right) }),
4124
+ ne: (left, right) => ({ type: "operator", op: "!=", left: wrapNode(left), right: wrapNode(right) }),
4125
+ gt: (left, right) => ({ type: "operator", op: ">", left: wrapNode(left), right: wrapNode(right) }),
4126
+ gte: (left, right) => ({ type: "operator", op: ">=", left: wrapNode(left), right: wrapNode(right) }),
4127
+ lt: (left, right) => ({ type: "operator", op: "<", left: wrapNode(left), right: wrapNode(right) }),
4128
+ lte: (left, right) => ({ type: "operator", op: "<=", left: wrapNode(left), right: wrapNode(right) }),
4129
+ and: (left, right) => ({ type: "operator", op: "AND", left: wrapNode(left), right: wrapNode(right) }),
4130
+ or: (left, right) => ({ type: "operator", op: "OR", left: wrapNode(left), right: wrapNode(right) }),
4131
+ like: (left, right) => ({ type: "operator", op: "LIKE", left: wrapNode(left), right: wrapNode(right) }),
4132
+ isNull: (node) => ({ type: "operator", op: "IS", left: wrapNode(node), right: { type: "literal", value: null } }),
4133
+ isNotNull: (node) => ({ type: "operator", op: "IS NOT", left: wrapNode(node), right: { type: "literal", value: null } }),
4134
+ in: (left, values) => ({
4135
+ type: "function",
4136
+ name: `${compileAST(wrapNode(left)).sql} IN`,
4137
+ args: values.map((v) => wrapNode(v))
4138
+ }),
4139
+ not: (node) => ({ type: "operator", op: "NOT", left: { type: "literal", value: "" }, right: wrapNode(node) })
4140
+ };
4141
+
4142
+ // src/iqo.ts
4143
4143
  var OPERATOR_MAP = {
4144
4144
  $gt: ">",
4145
4145
  $gte: ">=",
@@ -4149,7 +4149,9 @@ var OPERATOR_MAP = {
4149
4149
  $in: "IN",
4150
4150
  $like: "LIKE",
4151
4151
  $notIn: "NOT IN",
4152
- $between: "BETWEEN"
4152
+ $between: "BETWEEN",
4153
+ $isNull: "IS NULL",
4154
+ $isNotNull: "IS NOT NULL"
4153
4155
  };
4154
4156
  function transformValueForStorage(value) {
4155
4157
  if (value instanceof Date)
@@ -4173,7 +4175,7 @@ function compileIQO(tableName, iqo) {
4173
4175
  selectParts.push(`${j.table}.*`);
4174
4176
  }
4175
4177
  }
4176
- let sql = `SELECT ${selectParts.join(", ")} FROM ${tableName}`;
4178
+ let sql = `SELECT ${iqo.distinct ? "DISTINCT " : ""}${selectParts.join(", ")} FROM ${tableName}`;
4177
4179
  for (const j of iqo.joins) {
4178
4180
  sql += ` JOIN ${j.table} ON ${tableName}.${j.fromCol} = ${j.table}.${j.toCol}`;
4179
4181
  }
@@ -4206,6 +4208,10 @@ function compileIQO(tableName, iqo) {
4206
4208
  const [min, max] = w.value;
4207
4209
  whereParts.push(`${qualify(w.field)} BETWEEN ? AND ?`);
4208
4210
  params.push(transformValueForStorage(min), transformValueForStorage(max));
4211
+ } else if (w.operator === "IS NULL") {
4212
+ whereParts.push(`${qualify(w.field)} IS NULL`);
4213
+ } else if (w.operator === "IS NOT NULL") {
4214
+ whereParts.push(`${qualify(w.field)} IS NOT NULL`);
4209
4215
  } else {
4210
4216
  whereParts.push(`${qualify(w.field)} ${w.operator} ?`);
4211
4217
  params.push(transformValueForStorage(w.value));
@@ -4241,6 +4247,22 @@ function compileIQO(tableName, iqo) {
4241
4247
  if (iqo.groupBy.length > 0) {
4242
4248
  sql += ` GROUP BY ${iqo.groupBy.join(", ")}`;
4243
4249
  }
4250
+ if (iqo.having && iqo.having.length > 0) {
4251
+ const havingParts = [];
4252
+ for (const h of iqo.having) {
4253
+ if (h.operator === "IS NULL") {
4254
+ havingParts.push(`${h.field} IS NULL`);
4255
+ } else if (h.operator === "IS NOT NULL") {
4256
+ havingParts.push(`${h.field} IS NOT NULL`);
4257
+ } else {
4258
+ havingParts.push(`${h.field} ${h.operator} ?`);
4259
+ params.push(transformValueForStorage(h.value));
4260
+ }
4261
+ }
4262
+ if (havingParts.length > 0) {
4263
+ sql += ` HAVING ${havingParts.join(" AND ")}`;
4264
+ }
4265
+ }
4244
4266
  if (iqo.orderBy.length > 0) {
4245
4267
  const parts = iqo.orderBy.map((o) => `${o.field} ${o.direction.toUpperCase()}`);
4246
4268
  sql += ` ORDER BY ${parts.join(", ")}`;
@@ -4251,7 +4273,7 @@ function compileIQO(tableName, iqo) {
4251
4273
  sql += ` OFFSET ${iqo.offset}`;
4252
4274
  return { sql, params };
4253
4275
  }
4254
-
4276
+ // src/builder.ts
4255
4277
  class QueryBuilder {
4256
4278
  iqo;
4257
4279
  tableName;
@@ -4274,11 +4296,13 @@ class QueryBuilder {
4274
4296
  whereAST: null,
4275
4297
  joins: [],
4276
4298
  groupBy: [],
4299
+ having: [],
4277
4300
  limit: null,
4278
4301
  offset: null,
4279
4302
  orderBy: [],
4280
4303
  includes: [],
4281
- raw: false
4304
+ raw: false,
4305
+ distinct: false
4282
4306
  };
4283
4307
  }
4284
4308
  select(...cols) {
@@ -4433,6 +4457,61 @@ class QueryBuilder {
4433
4457
  this.iqo.groupBy.push(...fields);
4434
4458
  return this;
4435
4459
  }
4460
+ distinct() {
4461
+ this.iqo.distinct = true;
4462
+ return this;
4463
+ }
4464
+ withTrashed() {
4465
+ this.iqo.wheres = this.iqo.wheres.filter((w) => !(w.field === "deletedAt" && w.operator === "IS NULL"));
4466
+ return this;
4467
+ }
4468
+ having(conditions) {
4469
+ for (const [field, value] of Object.entries(conditions)) {
4470
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
4471
+ for (const [opKey, operand] of Object.entries(value)) {
4472
+ const sqlOp = OPERATOR_MAP[opKey];
4473
+ if (!sqlOp)
4474
+ throw new Error(`Unsupported having operator: '${opKey}'`);
4475
+ this.iqo.having.push({ field, operator: sqlOp, value: operand });
4476
+ }
4477
+ } else {
4478
+ this.iqo.having.push({ field, operator: "=", value });
4479
+ }
4480
+ }
4481
+ return this;
4482
+ }
4483
+ sum(field) {
4484
+ const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4485
+ const aggSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT COALESCE(SUM("${field}"), 0) as val FROM`);
4486
+ const results = this.executor(aggSql, params, true);
4487
+ return results[0]?.val ?? 0;
4488
+ }
4489
+ avg(field) {
4490
+ const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4491
+ const aggSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT AVG("${field}") as val FROM`);
4492
+ const results = this.executor(aggSql, params, true);
4493
+ return results[0]?.val ?? 0;
4494
+ }
4495
+ min(field) {
4496
+ const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4497
+ const aggSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT MIN("${field}") as val FROM`);
4498
+ const results = this.executor(aggSql, params, true);
4499
+ return results[0]?.val ?? null;
4500
+ }
4501
+ max(field) {
4502
+ const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4503
+ const aggSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT MAX("${field}") as val FROM`);
4504
+ const results = this.executor(aggSql, params, true);
4505
+ return results[0]?.val ?? null;
4506
+ }
4507
+ paginate(page = 1, perPage = 20) {
4508
+ const total = this.count();
4509
+ const pages = Math.ceil(total / perPage);
4510
+ this.iqo.limit = perPage;
4511
+ this.iqo.offset = (page - 1) * perPage;
4512
+ const data = this.all();
4513
+ return { data, total, page, perPage, pages };
4514
+ }
4436
4515
  then(onfulfilled, onrejected) {
4437
4516
  try {
4438
4517
  const result = this.all();
@@ -4442,7 +4521,7 @@ class QueryBuilder {
4442
4521
  }
4443
4522
  }
4444
4523
  }
4445
-
4524
+ // src/proxy.ts
4446
4525
  class ColumnNode {
4447
4526
  table;
4448
4527
  column;
@@ -4550,7 +4629,7 @@ function compileProxyQuery(queryResult, aliasMap) {
4550
4629
  const whereParts = [];
4551
4630
  for (const [key, value] of Object.entries(queryResult.where)) {
4552
4631
  let fieldRef;
4553
- const quotedMatch = key.match(/^"([^"]+)"\.\"([^"]+)"$/);
4632
+ const quotedMatch = key.match(/^"([^"]+)"\."([^"]+)"$/);
4554
4633
  if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
4555
4634
  fieldRef = key;
4556
4635
  } else {
@@ -4605,7 +4684,7 @@ function compileProxyQuery(queryResult, aliasMap) {
4605
4684
  const parts = [];
4606
4685
  for (const [key, dir] of Object.entries(queryResult.orderBy)) {
4607
4686
  let fieldRef;
4608
- const quotedMatch = key.match(/^"([^"]+)"\.\"([^"]+)"$/);
4687
+ const quotedMatch = key.match(/^"([^"]+)"\."([^"]+)"$/);
4609
4688
  if (quotedMatch && tablesUsed.has(quotedMatch[1])) {
4610
4689
  fieldRef = key;
4611
4690
  } else {
@@ -4633,9 +4712,13 @@ function executeProxyQuery(schemas, callback, executor) {
4633
4712
  const { sql, params } = compileProxyQuery(queryResult, aliasMap);
4634
4713
  return executor(sql, params);
4635
4714
  }
4715
+
4716
+ // src/query.ts
4636
4717
  function createQueryBuilder(ctx, entityName, initialCols) {
4637
4718
  const schema = ctx.schemas[entityName];
4638
4719
  const executor = (sql, params, raw) => {
4720
+ if (ctx.debug)
4721
+ console.log("[satidb]", sql, params);
4639
4722
  const rows = ctx.db.query(sql).all(...params);
4640
4723
  if (raw)
4641
4724
  return rows;
@@ -4705,6 +4788,9 @@ function createQueryBuilder(ctx, entityName, initialCols) {
4705
4788
  const builder = new QueryBuilder(entityName, executor, singleExecutor, joinResolver, conditionResolver, eagerLoader);
4706
4789
  if (initialCols.length > 0)
4707
4790
  builder.select(...initialCols);
4791
+ if (ctx.softDeletes) {
4792
+ builder.where({ deletedAt: { $isNull: true } });
4793
+ }
4708
4794
  return builder;
4709
4795
  }
4710
4796
 
@@ -4769,6 +4855,14 @@ function buildWhereClause(conditions, tablePrefix) {
4769
4855
  values.push(transformForStorage({ v: operand[0] }).v, transformForStorage({ v: operand[1] }).v);
4770
4856
  continue;
4771
4857
  }
4858
+ if (operator === "$isNull") {
4859
+ parts.push(`${fieldName} IS NULL`);
4860
+ continue;
4861
+ }
4862
+ if (operator === "$isNotNull") {
4863
+ parts.push(`${fieldName} IS NOT NULL`);
4864
+ continue;
4865
+ }
4772
4866
  const sqlOp = { $gt: ">", $gte: ">=", $lt: "<", $lte: "<=", $ne: "!=" }[operator];
4773
4867
  if (!sqlOp)
4774
4868
  throw new Error(`Unsupported operator '${operator}' on '${key}'`);
@@ -4805,9 +4899,16 @@ function insert(ctx, entityName, data) {
4805
4899
  const schema = ctx.schemas[entityName];
4806
4900
  const validatedData = asZodObject(schema).passthrough().parse(data);
4807
4901
  const transformed = transformForStorage(validatedData);
4902
+ if (ctx.timestamps) {
4903
+ const now = new Date().toISOString();
4904
+ transformed.createdAt = now;
4905
+ transformed.updatedAt = now;
4906
+ }
4808
4907
  const columns = Object.keys(transformed);
4809
4908
  const quotedCols = columns.map((c) => `"${c}"`);
4810
4909
  const sql = columns.length === 0 ? `INSERT INTO "${entityName}" DEFAULT VALUES` : `INSERT INTO "${entityName}" (${quotedCols.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
4910
+ if (ctx.debug)
4911
+ console.log("[satidb]", sql, Object.values(transformed));
4811
4912
  const result = ctx.db.query(sql).run(...Object.values(transformed));
4812
4913
  const newEntity = getById(ctx, entityName, result.lastInsertRowid);
4813
4914
  if (!newEntity)
@@ -4818,10 +4919,16 @@ function update(ctx, entityName, id, data) {
4818
4919
  const schema = ctx.schemas[entityName];
4819
4920
  const validatedData = asZodObject(schema).partial().parse(data);
4820
4921
  const transformed = transformForStorage(validatedData);
4821
- if (Object.keys(transformed).length === 0)
4922
+ if (Object.keys(transformed).length === 0 && !ctx.timestamps)
4822
4923
  return getById(ctx, entityName, id);
4924
+ if (ctx.timestamps) {
4925
+ transformed.updatedAt = new Date().toISOString();
4926
+ }
4823
4927
  const setClause = Object.keys(transformed).map((key) => `"${key}" = ?`).join(", ");
4824
- ctx.db.query(`UPDATE "${entityName}" SET ${setClause} WHERE id = ?`).run(...Object.values(transformed), id);
4928
+ const sql = `UPDATE "${entityName}" SET ${setClause} WHERE id = ?`;
4929
+ if (ctx.debug)
4930
+ console.log("[satidb]", sql, [...Object.values(transformed), id]);
4931
+ ctx.db.query(sql).run(...Object.values(transformed), id);
4825
4932
  return getById(ctx, entityName, id);
4826
4933
  }
4827
4934
  function updateWhere(ctx, entityName, data, conditions) {
@@ -4864,6 +4971,24 @@ function upsert(ctx, entityName, data, conditions = {}) {
4864
4971
  function deleteEntity(ctx, entityName, id) {
4865
4972
  ctx.db.query(`DELETE FROM "${entityName}" WHERE id = ?`).run(id);
4866
4973
  }
4974
+ function deleteWhere(ctx, entityName, conditions) {
4975
+ const { clause, values } = ctx.buildWhereClause(conditions);
4976
+ if (!clause)
4977
+ throw new Error("delete().where() requires at least one condition");
4978
+ const result = ctx.db.query(`DELETE FROM "${entityName}" ${clause}`).run(...values);
4979
+ return result.changes ?? 0;
4980
+ }
4981
+ function createDeleteBuilder(ctx, entityName) {
4982
+ let _conditions = {};
4983
+ const builder = {
4984
+ where: (conditions) => {
4985
+ _conditions = { ..._conditions, ...conditions };
4986
+ return builder;
4987
+ },
4988
+ exec: () => deleteWhere(ctx, entityName, _conditions)
4989
+ };
4990
+ return builder;
4991
+ }
4867
4992
  function insertMany(ctx, entityName, rows) {
4868
4993
  if (rows.length === 0)
4869
4994
  return [];
@@ -4874,6 +4999,11 @@ function insertMany(ctx, entityName, rows) {
4874
4999
  for (const data of rows) {
4875
5000
  const validatedData = zodSchema.parse(data);
4876
5001
  const transformed = transformForStorage(validatedData);
5002
+ if (ctx.timestamps) {
5003
+ const now = new Date().toISOString();
5004
+ transformed.createdAt = now;
5005
+ transformed.updatedAt = now;
5006
+ }
4877
5007
  const columns = Object.keys(transformed);
4878
5008
  const quotedCols = columns.map((c) => `"${c}"`);
4879
5009
  const sql = columns.length === 0 ? `INSERT INTO "${entityName}" DEFAULT VALUES` : `INSERT INTO "${entityName}" (${quotedCols.join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
@@ -4924,6 +5054,9 @@ function attachMethods(ctx, entityName, entity) {
4924
5054
  class _Database {
4925
5055
  db;
4926
5056
  _reactive;
5057
+ _timestamps;
5058
+ _softDeletes;
5059
+ _debug;
4927
5060
  schemas;
4928
5061
  relationships;
4929
5062
  options;
@@ -4939,6 +5072,9 @@ class _Database {
4939
5072
  this.schemas = schemas;
4940
5073
  this.options = options;
4941
5074
  this._reactive = options.reactive !== false;
5075
+ this._timestamps = options.timestamps === true;
5076
+ this._softDeletes = options.softDeletes === true;
5077
+ this._debug = options.debug === true;
4942
5078
  this._pollInterval = options.pollInterval ?? 100;
4943
5079
  this.relationships = options.relations ? parseRelationsConfig(options.relations, schemas) : [];
4944
5080
  this._ctx = {
@@ -4946,7 +5082,10 @@ class _Database {
4946
5082
  schemas: this.schemas,
4947
5083
  relationships: this.relationships,
4948
5084
  attachMethods: (name, entity) => attachMethods(this._ctx, name, entity),
4949
- buildWhereClause: (conds, prefix) => buildWhereClause(conds, prefix)
5085
+ buildWhereClause: (conds, prefix) => buildWhereClause(conds, prefix),
5086
+ debug: this._debug,
5087
+ timestamps: this._timestamps,
5088
+ softDeletes: this._softDeletes
4950
5089
  };
4951
5090
  this.initializeTables();
4952
5091
  if (this._reactive)
@@ -4965,7 +5104,17 @@ class _Database {
4965
5104
  return createUpdateBuilder(this._ctx, entityName, idOrData);
4966
5105
  },
4967
5106
  upsert: (conditions, data) => upsert(this._ctx, entityName, data, conditions),
4968
- delete: (id) => deleteEntity(this._ctx, entityName, id),
5107
+ delete: (id) => {
5108
+ if (typeof id === "number") {
5109
+ if (this._softDeletes) {
5110
+ const now = new Date().toISOString();
5111
+ this.db.run(`UPDATE "${entityName}" SET "deletedAt" = ? WHERE id = ?`, now, id);
5112
+ return;
5113
+ }
5114
+ return deleteEntity(this._ctx, entityName, id);
5115
+ }
5116
+ return createDeleteBuilder(this._ctx, entityName);
5117
+ },
4969
5118
  select: (...cols) => createQueryBuilder(this._ctx, entityName, cols),
4970
5119
  on: (event, callback) => {
4971
5120
  return this._registerListener(entityName, event, callback);
@@ -4979,6 +5128,13 @@ class _Database {
4979
5128
  for (const [entityName, schema] of Object.entries(this.schemas)) {
4980
5129
  const storableFields = getStorableFields(schema);
4981
5130
  const columnDefs = storableFields.map((f) => `"${f.name}" ${zodTypeToSqlType(f.type)}`);
5131
+ if (this._timestamps) {
5132
+ columnDefs.push('"createdAt" TEXT');
5133
+ columnDefs.push('"updatedAt" TEXT');
5134
+ }
5135
+ if (this._softDeletes) {
5136
+ columnDefs.push('"deletedAt" TEXT');
5137
+ }
4982
5138
  const constraints = [];
4983
5139
  const belongsToRels = this.relationships.filter((rel) => rel.type === "belongs-to" && rel.from === entityName);
4984
5140
  for (const rel of belongsToRels) {
@@ -5103,7 +5259,21 @@ class _Database {
5103
5259
  this.db.close();
5104
5260
  }
5105
5261
  query(callback) {
5106
- return executeProxyQuery(this.schemas, callback, (sql, params) => this.db.query(sql).all(...params));
5262
+ return executeProxyQuery(this.schemas, callback, (sql, params) => {
5263
+ if (this._debug)
5264
+ console.log("[satidb]", sql, params);
5265
+ return this.db.query(sql).all(...params);
5266
+ });
5267
+ }
5268
+ raw(sql, ...params) {
5269
+ if (this._debug)
5270
+ console.log("[satidb]", sql, params);
5271
+ return this.db.query(sql).all(...params);
5272
+ }
5273
+ exec(sql, ...params) {
5274
+ if (this._debug)
5275
+ console.log("[satidb]", sql, params);
5276
+ this.db.run(sql, ...params);
5107
5277
  }
5108
5278
  }
5109
5279
  var Database = _Database;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlite-zod-orm",
3
- "version": "3.9.0",
3
+ "version": "3.11.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",