tina4-nodejs 3.13.139 → 3.13.140

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.
@@ -3575,14 +3575,72 @@ var init_cachedDatabase = __esm({
3575
3575
  }
3576
3576
  });
3577
3577
 
3578
+ // ../orm/src/adapters/sqlCrud.ts
3579
+ function buildInsertRow(dialect, table2, data, suffix = "", options = {}) {
3580
+ const keys = Object.keys(data);
3581
+ const sql = buildInsert(dialect, table2, keys, suffix, options.startAt ?? 1);
3582
+ return { sql, values: Object.values(data) };
3583
+ }
3584
+ function buildInsertRows(dialect, table2, rows) {
3585
+ if (rows.length === 0) return null;
3586
+ const keys = Object.keys(rows[0]);
3587
+ const sql = buildInsert(dialect, table2, keys);
3588
+ const paramsList = rows.map((row) => keys.map((k) => row[k]));
3589
+ return { sql, paramsList };
3590
+ }
3591
+ function buildUpdate(dialect, table2, data, filter, params, options = {}) {
3592
+ const startAt = options.startAt ?? 1;
3593
+ const convertFragment = options.convertFragment ?? identityFragment;
3594
+ const dataKeys = Object.keys(data);
3595
+ const setClauses = buildSetClause(dialect, dataKeys, startAt);
3596
+ const whereStart = startAt + dataKeys.length;
3597
+ if (typeof filter === "string") {
3598
+ const where = filter ? ` WHERE ${convertFragment(filter, whereStart)}` : "";
3599
+ return {
3600
+ sql: `UPDATE ${dialect.quote(table2)} SET ${setClauses}${where}`,
3601
+ values: [...Object.values(data), ...params ?? []]
3602
+ };
3603
+ }
3604
+ const whereClauses = buildWhereClause(dialect, Object.keys(filter), whereStart);
3605
+ return {
3606
+ sql: `UPDATE ${dialect.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`,
3607
+ values: [...Object.values(data), ...Object.values(filter)]
3608
+ };
3609
+ }
3610
+ function buildDelete(dialect, table2, filter, params, options = {}) {
3611
+ const startAt = options.startAt ?? 1;
3612
+ const convertFragment = options.convertFragment ?? identityFragment;
3613
+ if (typeof filter === "string") {
3614
+ const where = filter ? ` WHERE ${convertFragment(filter, startAt)}` : "";
3615
+ return {
3616
+ sql: `DELETE FROM ${dialect.quote(table2)}${where}`,
3617
+ values: params ?? []
3618
+ };
3619
+ }
3620
+ const whereClauses = buildWhereClause(dialect, Object.keys(filter), startAt);
3621
+ return {
3622
+ sql: `DELETE FROM ${dialect.quote(table2)} WHERE ${whereClauses}`,
3623
+ values: Object.values(filter)
3624
+ };
3625
+ }
3626
+ var identityFragment;
3627
+ var init_sqlCrud = __esm({
3628
+ "../orm/src/adapters/sqlCrud.ts"() {
3629
+ "use strict";
3630
+ init_sqlDialect();
3631
+ identityFragment = (fragment) => fragment;
3632
+ }
3633
+ });
3634
+
3578
3635
  // ../orm/src/adapters/sqlite.ts
3579
3636
  var sqlite_exports = {};
3580
3637
  __export(sqlite_exports, {
3581
- SQLiteAdapter: () => SQLiteAdapter
3638
+ SQLiteAdapter: () => SQLiteAdapter,
3639
+ resolveSqlitePath: () => resolveSqlitePath
3582
3640
  });
3583
3641
  import { DatabaseSync } from "node:sqlite";
3584
3642
  import { mkdirSync as mkdirSync3 } from "node:fs";
3585
- import { dirname as dirname4, isAbsolute as isAbsolute2, join as join5, resolve as resolve3 } from "node:path";
3643
+ import { dirname as dirname4, isAbsolute as isAbsolute2, join as join5, resolve as resolve3, sep } from "node:path";
3586
3644
  function isIdentifier(str) {
3587
3645
  return /^[A-Za-z_][A-Za-z0-9_]*$/.test(str);
3588
3646
  }
@@ -3613,17 +3671,20 @@ function sqliteVersionAtLeast(major, minor, patch2) {
3613
3671
  }
3614
3672
  function resolveSqlitePath(dbPath) {
3615
3673
  if (dbPath === ":memory:") return dbPath;
3616
- let path10 = dbPath;
3617
- if (!isAbsolute2(path10)) {
3618
- path10 = join5(process.cwd(), path10);
3619
- mkdirSync3(dirname4(path10), { recursive: true });
3620
- } else {
3621
- const cwd = resolve3(process.cwd());
3622
- const abs = resolve3(path10);
3623
- if (abs.startsWith(cwd + "/") || abs === cwd) {
3624
- mkdirSync3(dirname4(abs), { recursive: true });
3625
- }
3674
+ const isWindowsAbs = /^[A-Za-z]:[\\/]/.test(dbPath);
3675
+ if (isAbsolute2(dbPath) || isWindowsAbs) {
3676
+ return dbPath;
3677
+ }
3678
+ const cwd = resolve3(process.cwd());
3679
+ const path10 = join5(cwd, dbPath);
3680
+ const parent = dirname4(path10);
3681
+ const absParent = resolve3(parent);
3682
+ if (absParent !== cwd && !absParent.startsWith(cwd + sep)) {
3683
+ throw new Error(
3684
+ `SQLite path "${dbPath}" resolves outside the project directory: "${absParent}" is not within "${cwd}". Tina4 refuses to create directories outside the project (ADR-0086). Use an absolute path for a database that lives outside the project.`
3685
+ );
3626
3686
  }
3687
+ mkdirSync3(parent, { recursive: true, mode: 509 });
3627
3688
  return path10;
3628
3689
  }
3629
3690
  function fieldTypeToSQLite(def) {
@@ -3659,6 +3720,7 @@ var init_sqlite = __esm({
3659
3720
  "../orm/src/adapters/sqlite.ts"() {
3660
3721
  "use strict";
3661
3722
  init_sqlDialect();
3723
+ init_sqlCrud();
3662
3724
  init_sqlTranslator();
3663
3725
  _sqliteVersionInfo = null;
3664
3726
  SQLiteAdapter = class {
@@ -3779,16 +3841,12 @@ var init_sqlite = __esm({
3779
3841
  }
3780
3842
  insert(table2, data) {
3781
3843
  if (Array.isArray(data)) {
3782
- if (data.length === 0) return { success: true, affectedRows: 0 };
3783
- const keys2 = Object.keys(data[0]);
3784
- const sql2 = buildInsert(ANSI_DIALECT, table2, keys2);
3785
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
3786
- const result = this.executeMany(sql2, paramsList);
3844
+ const batch = buildInsertRows(ANSI_DIALECT, table2, data);
3845
+ if (!batch) return { success: true, affectedRows: 0 };
3846
+ const result = this.executeMany(batch.sql, batch.paramsList);
3787
3847
  return { success: true, affectedRows: result.affectedRows, lastId: result.lastId };
3788
3848
  }
3789
- const keys = Object.keys(data);
3790
- const sql = buildInsert(ANSI_DIALECT, table2, keys);
3791
- const values = Object.values(data);
3849
+ const { sql, values } = buildInsertRow(ANSI_DIALECT, table2, data);
3792
3850
  try {
3793
3851
  const result = this.db.prepare(sql).run(...toSqlParams(values));
3794
3852
  this._lastInsertId = result.lastInsertRowid;
@@ -3798,21 +3856,7 @@ var init_sqlite = __esm({
3798
3856
  }
3799
3857
  }
3800
3858
  update(table2, data, filter, params) {
3801
- const setClauses = buildSetClause(ANSI_DIALECT, Object.keys(data));
3802
- if (typeof filter === "string") {
3803
- const where = filter ? ` WHERE ${filter}` : "";
3804
- const sql2 = `UPDATE ${ANSI_DIALECT.quote(table2)} SET ${setClauses}${where}`;
3805
- const values2 = [...Object.values(data), ...params ?? []];
3806
- try {
3807
- const result = this.db.prepare(sql2).run(...toSqlParams(values2));
3808
- return { success: true, affectedRows: Number(result.changes) };
3809
- } catch (e) {
3810
- return { success: false, affectedRows: 0, error: e.message };
3811
- }
3812
- }
3813
- const whereClauses = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
3814
- const sql = `UPDATE ${ANSI_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
3815
- const values = [...Object.values(data), ...Object.values(filter)];
3859
+ const { sql, values } = buildUpdate(ANSI_DIALECT, table2, data, filter, params);
3816
3860
  try {
3817
3861
  const result = this.db.prepare(sql).run(...toSqlParams(values));
3818
3862
  return { success: true, affectedRows: Number(result.changes) };
@@ -3829,18 +3873,7 @@ var init_sqlite = __esm({
3829
3873
  }
3830
3874
  return { success: true, affectedRows: totalAffected };
3831
3875
  }
3832
- if (typeof filter === "string") {
3833
- const sql2 = filter ? `DELETE FROM "${table2}" WHERE ${filter}` : `DELETE FROM "${table2}"`;
3834
- try {
3835
- const result = this.db.prepare(sql2).run(...toSqlParams(params ?? []));
3836
- return { success: true, affectedRows: Number(result.changes) };
3837
- } catch (e) {
3838
- return { success: false, affectedRows: 0, error: e.message };
3839
- }
3840
- }
3841
- const whereClauses = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
3842
- const sql = `DELETE FROM ${ANSI_DIALECT.quote(table2)} WHERE ${whereClauses}`;
3843
- const values = Object.values(filter);
3876
+ const { sql, values } = buildDelete(ANSI_DIALECT, table2, filter, params);
3844
3877
  try {
3845
3878
  const result = this.db.prepare(sql).run(...toSqlParams(values));
3846
3879
  return { success: true, affectedRows: Number(result.changes) };
@@ -4132,6 +4165,7 @@ var init_postgres = __esm({
4132
4165
  "../orm/src/adapters/postgres.ts"() {
4133
4166
  "use strict";
4134
4167
  init_sqlDialect();
4168
+ init_sqlCrud();
4135
4169
  init_sqlTranslator();
4136
4170
  init_connectTimeout();
4137
4171
  pg = null;
@@ -4333,21 +4367,17 @@ var init_postgres = __esm({
4333
4367
  async insertAsync(table2, data) {
4334
4368
  this.ensureConnected();
4335
4369
  if (Array.isArray(data)) {
4336
- if (data.length === 0) return { success: true, affectedRows: 0 };
4337
- const keys2 = Object.keys(data[0]);
4338
- const sql2 = buildInsert(ANSI_DIALECT, table2, keys2);
4339
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
4370
+ const batch = buildInsertRows(ANSI_DIALECT, table2, data);
4371
+ if (!batch) return { success: true, affectedRows: 0 };
4340
4372
  try {
4341
- const result = await this.executeManyAsync(sql2, paramsList);
4373
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
4342
4374
  if (result.lastId !== void 0) this._lastInsertId = result.lastId;
4343
4375
  return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
4344
4376
  } catch (e) {
4345
4377
  return { success: false, affectedRows: 0, error: e.message };
4346
4378
  }
4347
4379
  }
4348
- const keys = Object.keys(data);
4349
- const sql = buildInsert(POSTGRES_DIALECT, table2, keys, " RETURNING *");
4350
- const values = Object.values(data);
4380
+ const { sql, values } = buildInsertRow(POSTGRES_DIALECT, table2, data, " RETURNING *");
4351
4381
  try {
4352
4382
  const result = await this.client.query(sql, values);
4353
4383
  const insertedRow = result.rows[0];
@@ -4367,26 +4397,10 @@ var init_postgres = __esm({
4367
4397
  }
4368
4398
  async updateAsync(table2, data, filter, params) {
4369
4399
  this.ensureConnected();
4370
- const dataKeys = Object.keys(data);
4371
- let paramIndex = 1;
4372
- const setClauses = buildSetClause(POSTGRES_DIALECT, dataKeys, paramIndex);
4373
- paramIndex += dataKeys.length;
4374
- if (typeof filter === "string") {
4375
- const where = filter ? ` WHERE ${this.convertPlaceholders(filter, paramIndex)}` : "";
4376
- const sql2 = `UPDATE ${POSTGRES_DIALECT.quote(table2)} SET ${setClauses}${where}`;
4377
- const values2 = [...Object.values(data), ...params ?? []];
4378
- try {
4379
- const result = await this.client.query(sql2, values2);
4380
- return { success: true, affectedRows: result.rowCount ?? 0 };
4381
- } catch (e) {
4382
- return { success: false, affectedRows: 0, error: e.message };
4383
- }
4384
- }
4385
- const filterKeys = Object.keys(filter);
4386
- const whereClauses = buildWhereClause(POSTGRES_DIALECT, filterKeys, paramIndex);
4387
- paramIndex += filterKeys.length;
4388
- const sql = `UPDATE ${POSTGRES_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
4389
- const values = [...Object.values(data), ...Object.values(filter)];
4400
+ const { sql, values } = buildUpdate(POSTGRES_DIALECT, table2, data, filter, params, {
4401
+ startAt: 1,
4402
+ convertFragment: (fragment, startAt) => this.convertPlaceholders(fragment, startAt)
4403
+ });
4390
4404
  try {
4391
4405
  const result = await this.client.query(sql, values);
4392
4406
  return { success: true, affectedRows: result.rowCount ?? 0 };
@@ -4399,21 +4413,10 @@ var init_postgres = __esm({
4399
4413
  }
4400
4414
  async deleteAsync(table2, filter, params) {
4401
4415
  this.ensureConnected();
4402
- if (typeof filter === "string") {
4403
- const sql2 = filter ? `DELETE FROM "${table2}" WHERE ${this.bindable(filter, params)}` : `DELETE FROM "${table2}"`;
4404
- try {
4405
- const result = await this.client.query(sql2, params ?? []);
4406
- return { success: true, affectedRows: result.rowCount ?? 0 };
4407
- } catch (e) {
4408
- return { success: false, affectedRows: 0, error: e.message };
4409
- }
4410
- }
4411
- const filterKeys = Object.keys(filter);
4412
- let paramIndex = 1;
4413
- const whereClauses = buildWhereClause(POSTGRES_DIALECT, filterKeys, paramIndex);
4414
- paramIndex += filterKeys.length;
4415
- const sql = `DELETE FROM ${POSTGRES_DIALECT.quote(table2)} WHERE ${whereClauses}`;
4416
- const values = Object.values(filter);
4416
+ const { sql, values } = buildDelete(POSTGRES_DIALECT, table2, filter, params, {
4417
+ startAt: 1,
4418
+ convertFragment: (fragment) => this.bindable(fragment, params)
4419
+ });
4417
4420
  try {
4418
4421
  const result = await this.client.query(sql, values);
4419
4422
  return { success: true, affectedRows: result.rowCount ?? 0 };
@@ -4587,6 +4590,7 @@ var init_mysql = __esm({
4587
4590
  "../orm/src/adapters/mysql.ts"() {
4588
4591
  "use strict";
4589
4592
  init_sqlDialect();
4593
+ init_sqlCrud();
4590
4594
  init_sqlTranslator();
4591
4595
  init_connectTimeout();
4592
4596
  mysql2 = null;
@@ -4768,21 +4772,17 @@ var init_mysql = __esm({
4768
4772
  async insertAsync(table2, data) {
4769
4773
  this.ensureConnected();
4770
4774
  if (Array.isArray(data)) {
4771
- if (data.length === 0) return { success: true, affectedRows: 0 };
4772
- const keys2 = Object.keys(data[0]);
4773
- const sql2 = buildInsert(MYSQL_DIALECT, table2, keys2);
4774
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
4775
+ const batch = buildInsertRows(MYSQL_DIALECT, table2, data);
4776
+ if (!batch) return { success: true, affectedRows: 0 };
4775
4777
  try {
4776
- const result = await this.executeManyAsync(sql2, paramsList);
4778
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
4777
4779
  if (result.lastId !== void 0) this._lastInsertId = result.lastId;
4778
4780
  return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
4779
4781
  } catch (e) {
4780
4782
  return { success: false, affectedRows: 0, error: e.message };
4781
4783
  }
4782
4784
  }
4783
- const keys = Object.keys(data);
4784
- const sql = buildInsert(MYSQL_DIALECT, table2, keys);
4785
- const values = Object.values(data);
4785
+ const { sql, values } = buildInsertRow(MYSQL_DIALECT, table2, data);
4786
4786
  try {
4787
4787
  const result = await this.queryPromise(sql, values);
4788
4788
  this._lastInsertId = result.insertId ?? null;
@@ -4800,21 +4800,7 @@ var init_mysql = __esm({
4800
4800
  }
4801
4801
  async updateAsync(table2, data, filter, params) {
4802
4802
  this.ensureConnected();
4803
- const setClauses = buildSetClause(MYSQL_DIALECT, Object.keys(data));
4804
- if (typeof filter === "string") {
4805
- const where = filter ? ` WHERE ${filter}` : "";
4806
- const sql2 = `UPDATE ${MYSQL_DIALECT.quote(table2)} SET ${setClauses}${where}`;
4807
- const values2 = [...Object.values(data), ...params ?? []];
4808
- try {
4809
- const result = await this.queryPromise(sql2, values2);
4810
- return { success: true, affectedRows: result.affectedRows ?? 0 };
4811
- } catch (e) {
4812
- return { success: false, affectedRows: 0, error: e.message };
4813
- }
4814
- }
4815
- const whereClauses = buildWhereClause(MYSQL_DIALECT, Object.keys(filter));
4816
- const sql = `UPDATE ${MYSQL_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
4817
- const values = [...Object.values(data), ...Object.values(filter)];
4803
+ const { sql, values } = buildUpdate(MYSQL_DIALECT, table2, data, filter, params);
4818
4804
  try {
4819
4805
  const result = await this.queryPromise(sql, values);
4820
4806
  return { success: true, affectedRows: result.affectedRows ?? 0 };
@@ -4827,18 +4813,7 @@ var init_mysql = __esm({
4827
4813
  }
4828
4814
  async deleteAsync(table2, filter, params) {
4829
4815
  this.ensureConnected();
4830
- if (typeof filter === "string") {
4831
- const sql2 = filter ? `DELETE FROM \`${table2}\` WHERE ${filter}` : `DELETE FROM \`${table2}\``;
4832
- try {
4833
- const result = await this.queryPromise(sql2, params ?? []);
4834
- return { success: true, affectedRows: result.affectedRows ?? 0 };
4835
- } catch (e) {
4836
- return { success: false, affectedRows: 0, error: e.message };
4837
- }
4838
- }
4839
- const whereClauses = buildWhereClause(MYSQL_DIALECT, Object.keys(filter));
4840
- const sql = `DELETE FROM ${MYSQL_DIALECT.quote(table2)} WHERE ${whereClauses}`;
4841
- const values = Object.values(filter);
4816
+ const { sql, values } = buildDelete(MYSQL_DIALECT, table2, filter, params);
4842
4817
  try {
4843
4818
  const result = await this.queryPromise(sql, values);
4844
4819
  return { success: true, affectedRows: result.affectedRows ?? 0 };
@@ -4990,6 +4965,7 @@ var init_mssql = __esm({
4990
4965
  "../orm/src/adapters/mssql.ts"() {
4991
4966
  "use strict";
4992
4967
  init_sqlDialect();
4968
+ init_sqlCrud();
4993
4969
  init_sqlTranslator();
4994
4970
  init_connectTimeout();
4995
4971
  tedious = null;
@@ -5246,21 +5222,17 @@ var init_mssql = __esm({
5246
5222
  async insertAsync(table2, data) {
5247
5223
  this.ensureConnected();
5248
5224
  if (Array.isArray(data)) {
5249
- if (data.length === 0) return { success: true, affectedRows: 0 };
5250
- const keys2 = Object.keys(data[0]);
5251
- const sql2 = buildInsert({ quote: MSSQL_DIALECT.quote, marker: ANSI_DIALECT.marker }, table2, keys2);
5252
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
5225
+ const batch = buildInsertRows({ quote: MSSQL_DIALECT.quote, marker: ANSI_DIALECT.marker }, table2, data);
5226
+ if (!batch) return { success: true, affectedRows: 0 };
5253
5227
  try {
5254
- const result = await this.executeManyAsync(sql2, paramsList);
5228
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
5255
5229
  if (result.lastId !== void 0) this._lastInsertId = result.lastId;
5256
5230
  return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
5257
5231
  } catch (e) {
5258
5232
  return { success: false, affectedRows: 0, error: e.message };
5259
5233
  }
5260
5234
  }
5261
- const keys = Object.keys(data);
5262
- const sql = buildInsert(MSSQL_DIALECT, table2, keys, "; SELECT SCOPE_IDENTITY() AS id", 0);
5263
- const values = Object.values(data);
5235
+ const { sql, values } = buildInsertRow(MSSQL_DIALECT, table2, data, "; SELECT SCOPE_IDENTITY() AS id", { startAt: 0 });
5264
5236
  try {
5265
5237
  const result = await this.execSqlPromise(sql, values);
5266
5238
  const id = result.rows[0]?.id ?? null;
@@ -5283,26 +5255,10 @@ var init_mssql = __esm({
5283
5255
  }
5284
5256
  async updateAsync(table2, data, filter, params) {
5285
5257
  this.ensureConnected();
5286
- const dataKeys = Object.keys(data);
5287
- let paramIndex = 0;
5288
- const setClauses = buildSetClause(MSSQL_DIALECT, dataKeys, paramIndex);
5289
- paramIndex += dataKeys.length;
5290
- if (typeof filter === "string") {
5291
- const where = filter ? ` WHERE ${this.convertPlaceholders(filter, paramIndex)}` : "";
5292
- const sql2 = `UPDATE ${MSSQL_DIALECT.quote(table2)} SET ${setClauses}${where}`;
5293
- const values2 = [...Object.values(data), ...params ?? []];
5294
- try {
5295
- const result = await this.execSqlPromise(sql2, values2);
5296
- return { success: true, affectedRows: result.rowCount };
5297
- } catch (e) {
5298
- return { success: false, affectedRows: 0, error: e.message };
5299
- }
5300
- }
5301
- const filterKeys = Object.keys(filter);
5302
- const whereClauses = buildWhereClause(MSSQL_DIALECT, filterKeys, paramIndex);
5303
- paramIndex += filterKeys.length;
5304
- const sql = `UPDATE ${MSSQL_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
5305
- const values = [...Object.values(data), ...Object.values(filter)];
5258
+ const { sql, values } = buildUpdate(MSSQL_DIALECT, table2, data, filter, params, {
5259
+ startAt: 0,
5260
+ convertFragment: (fragment, startAt) => this.convertPlaceholders(fragment, startAt)
5261
+ });
5306
5262
  try {
5307
5263
  const result = await this.execSqlPromise(sql, values);
5308
5264
  return { success: true, affectedRows: result.rowCount };
@@ -5315,21 +5271,10 @@ var init_mssql = __esm({
5315
5271
  }
5316
5272
  async deleteAsync(table2, filter, params) {
5317
5273
  this.ensureConnected();
5318
- if (typeof filter === "string") {
5319
- const sql2 = filter ? `DELETE FROM [${table2}] WHERE ${this.bindable(filter, params)}` : `DELETE FROM [${table2}]`;
5320
- try {
5321
- const result = await this.execSqlPromise(sql2, params ?? []);
5322
- return { success: true, affectedRows: result.rowCount };
5323
- } catch (e) {
5324
- return { success: false, affectedRows: 0, error: e.message };
5325
- }
5326
- }
5327
- const filterKeys = Object.keys(filter);
5328
- let paramIndex = 0;
5329
- const whereClauses = buildWhereClause(MSSQL_DIALECT, filterKeys, paramIndex);
5330
- paramIndex += filterKeys.length;
5331
- const sql = `DELETE FROM ${MSSQL_DIALECT.quote(table2)} WHERE ${whereClauses}`;
5332
- const values = Object.values(filter);
5274
+ const { sql, values } = buildDelete(MSSQL_DIALECT, table2, filter, params, {
5275
+ startAt: 0,
5276
+ convertFragment: (fragment) => this.bindable(fragment, params)
5277
+ });
5333
5278
  try {
5334
5279
  const result = await this.execSqlPromise(sql, values);
5335
5280
  return { success: true, affectedRows: result.rowCount };
@@ -5582,6 +5527,7 @@ var init_firebird = __esm({
5582
5527
  "../orm/src/adapters/firebird.ts"() {
5583
5528
  "use strict";
5584
5529
  init_sqlDialect();
5530
+ init_sqlCrud();
5585
5531
  init_sqlTranslator();
5586
5532
  init_connectTimeout();
5587
5533
  firebird = null;
@@ -5952,17 +5898,13 @@ var init_firebird = __esm({
5952
5898
  async insertAsync(table2, data) {
5953
5899
  this.ensureConnected();
5954
5900
  if (Array.isArray(data)) {
5955
- if (data.length === 0) return { success: true, affectedRows: 0 };
5956
- const keys2 = Object.keys(data[0]);
5957
- const sql2 = buildInsert(FB_DIALECT, table2, keys2);
5958
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
5959
- const result = await this.executeManyAsync(sql2, paramsList);
5901
+ const batch = buildInsertRows(FB_DIALECT, table2, data);
5902
+ if (!batch) return { success: true, affectedRows: 0 };
5903
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
5960
5904
  const lastId2 = await this.readGeneratorId(table2) ?? result.lastId;
5961
5905
  return { success: true, affectedRows: result.totalAffected, lastId: lastId2 ?? void 0 };
5962
5906
  }
5963
- const keys = Object.keys(data);
5964
- const sql = buildInsert(FB_DIALECT, table2, keys);
5965
- const values = Object.values(data);
5907
+ const { sql, values } = buildInsertRow(FB_DIALECT, table2, data);
5966
5908
  await this.executePromise(sql, values);
5967
5909
  const lastId = await this.readGeneratorId(table2);
5968
5910
  return { success: true, affectedRows: 1, lastId: lastId ?? void 0 };
@@ -5972,18 +5914,7 @@ var init_firebird = __esm({
5972
5914
  }
5973
5915
  async updateAsync(table2, data, filter, params) {
5974
5916
  this.ensureConnected();
5975
- const setClauses = buildSetClause(FB_DIALECT, Object.keys(data));
5976
- if (typeof filter === "string") {
5977
- const where = filter ? ` WHERE ${filter}` : "";
5978
- const affected2 = await this.executeReturningCount(
5979
- `UPDATE ${fbQuote(table2)} SET ${setClauses}${where}`,
5980
- [...Object.values(data), ...params ?? []]
5981
- );
5982
- return { success: true, affectedRows: affected2 };
5983
- }
5984
- const whereClauses = buildWhereClause(FB_DIALECT, Object.keys(filter));
5985
- const sql = `UPDATE ${FB_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
5986
- const values = [...Object.values(data), ...Object.values(filter)];
5917
+ const { sql, values } = buildUpdate(FB_DIALECT, table2, data, filter, params);
5987
5918
  const affected = await this.executeReturningCount(sql, values);
5988
5919
  return { success: true, affectedRows: affected };
5989
5920
  }
@@ -5992,14 +5923,7 @@ var init_firebird = __esm({
5992
5923
  }
5993
5924
  async deleteAsync(table2, filter, params) {
5994
5925
  this.ensureConnected();
5995
- if (typeof filter === "string") {
5996
- const where = filter ? ` WHERE ${filter}` : "";
5997
- const affected2 = await this.executeReturningCount(`DELETE FROM ${fbQuote(table2)}${where}`, params ?? []);
5998
- return { success: true, affectedRows: affected2 };
5999
- }
6000
- const whereClauses = buildWhereClause(FB_DIALECT, Object.keys(filter));
6001
- const sql = `DELETE FROM ${FB_DIALECT.quote(table2)} WHERE ${whereClauses}`;
6002
- const values = Object.values(filter);
5926
+ const { sql, values } = buildDelete(FB_DIALECT, table2, filter, params);
6003
5927
  const affected = await this.executeReturningCount(sql, values);
6004
5928
  return { success: true, affectedRows: affected };
6005
5929
  }
@@ -6831,6 +6755,7 @@ var init_odbc = __esm({
6831
6755
  "../orm/src/adapters/odbc.ts"() {
6832
6756
  "use strict";
6833
6757
  init_sqlDialect();
6758
+ init_sqlCrud();
6834
6759
  init_sqlTranslator();
6835
6760
  init_connectTimeout();
6836
6761
  odbcModule = null;
@@ -7030,16 +6955,12 @@ var init_odbc = __esm({
7030
6955
  async insertAsync(table2, data) {
7031
6956
  this.ensureConnected();
7032
6957
  if (Array.isArray(data)) {
7033
- if (data.length === 0) return { success: true, affectedRows: 0 };
7034
- const keys2 = Object.keys(data[0]);
7035
- const sql2 = buildInsert(ANSI_DIALECT, table2, keys2);
7036
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
7037
- const { totalAffected } = await this.executeManyAsync(sql2, paramsList);
6958
+ const batch = buildInsertRows(ANSI_DIALECT, table2, data);
6959
+ if (!batch) return { success: true, affectedRows: 0 };
6960
+ const { totalAffected } = await this.executeManyAsync(batch.sql, batch.paramsList);
7038
6961
  return { success: true, affectedRows: totalAffected };
7039
6962
  }
7040
- const keys = Object.keys(data);
7041
- const sql = buildInsert(ANSI_DIALECT, table2, keys);
7042
- const values = Object.values(data);
6963
+ const { sql, values } = buildInsertRow(ANSI_DIALECT, table2, data);
7043
6964
  try {
7044
6965
  const result = await this.connection.query(sql, values);
7045
6966
  return { success: true, affectedRows: this.affectedCount(result), lastId: this._lastInsertId ?? void 0 };
@@ -7050,17 +6971,7 @@ var init_odbc = __esm({
7050
6971
  /** Update rows in a table matching filter. */
7051
6972
  async updateAsync(table2, data, filter, params) {
7052
6973
  this.ensureConnected();
7053
- const setClauses = buildSetClause(ANSI_DIALECT, Object.keys(data));
7054
- let whereSql;
7055
- let values;
7056
- if (typeof filter === "string") {
7057
- whereSql = filter;
7058
- values = [...Object.values(data), ...params ?? []];
7059
- } else {
7060
- whereSql = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
7061
- values = [...Object.values(data), ...Object.values(filter)];
7062
- }
7063
- const sql = `UPDATE ${ANSI_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereSql}`;
6974
+ const { sql, values } = buildUpdate(ANSI_DIALECT, table2, data, filter, params);
7064
6975
  try {
7065
6976
  const result = await this.connection.query(sql, values);
7066
6977
  return { success: true, affectedRows: this.affectedCount(result) };
@@ -7079,18 +6990,7 @@ var init_odbc = __esm({
7079
6990
  }
7080
6991
  return { success: true, affectedRows: totalAffected };
7081
6992
  }
7082
- if (typeof filter === "string") {
7083
- const sql2 = filter ? `DELETE FROM "${table2}" WHERE ${filter}` : `DELETE FROM "${table2}"`;
7084
- try {
7085
- const result = await this.connection.query(sql2, params ?? []);
7086
- return { success: true, affectedRows: this.affectedCount(result) };
7087
- } catch (e) {
7088
- return { success: false, affectedRows: 0, error: e.message };
7089
- }
7090
- }
7091
- const whereClauses = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
7092
- const sql = `DELETE FROM ${ANSI_DIALECT.quote(table2)} WHERE ${whereClauses}`;
7093
- const values = Object.values(filter);
6993
+ const { sql, values } = buildDelete(ANSI_DIALECT, table2, filter, params);
7094
6994
  try {
7095
6995
  const result = await this.connection.query(sql, values);
7096
6996
  return { success: true, affectedRows: this.affectedCount(result) };
@@ -14501,7 +14401,7 @@ var init_attachment = __esm({
14501
14401
  // ../orm/src/realtime/storage.ts
14502
14402
  import { randomBytes as randomBytes3 } from "node:crypto";
14503
14403
  import { mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, statSync as statSync4 } from "node:fs";
14504
- import { resolve as resolve6, sep } from "node:path";
14404
+ import { resolve as resolve6, sep as sep2 } from "node:path";
14505
14405
  import { createRequire as createRequire6 } from "node:module";
14506
14406
  function loadAwsSdk(packageName) {
14507
14407
  try {
@@ -14554,7 +14454,7 @@ var init_storage = __esm({
14554
14454
  // Resolve inside the root and reject any traversal attempt.
14555
14455
  pathFor(key) {
14556
14456
  const target = resolve6(this.directory, key);
14557
- if (target !== this.directory && !target.startsWith(this.directory + sep)) {
14457
+ if (target !== this.directory && !target.startsWith(this.directory + sep2)) {
14558
14458
  throw new Error(`unsafe storage key: ${JSON.stringify(key)}`);
14559
14459
  }
14560
14460
  return target;
@@ -15071,6 +14971,7 @@ __export(src_exports, {
15071
14971
  resolveDbPool: () => resolveDbPool,
15072
14972
  resolveFirebirdCharset: () => resolveFirebirdCharset,
15073
14973
  resolveGraphConnectTimeout: () => resolveGraphConnectTimeout,
14974
+ resolveSqlitePath: () => resolveSqlitePath,
15074
14975
  rollback: () => rollback,
15075
14976
  seedModels: () => seedModels,
15076
14977
  seedOrm: () => seedOrm,
@@ -17545,7 +17446,7 @@ __export(engine_exports, {
17545
17446
  });
17546
17447
  import { createHash as createHash3, createHmac as createHmac3, randomBytes as randomBytes4 } from "node:crypto";
17547
17448
  import { readFileSync as readFileSync6, existsSync as existsSync8, statSync as statSync6, realpathSync } from "node:fs";
17548
- import { join as join11, resolve as resolve7, isAbsolute as isAbsolute4, sep as sep2 } from "node:path";
17449
+ import { join as join11, resolve as resolve7, isAbsolute as isAbsolute4, sep as sep3 } from "node:path";
17549
17450
  function jsonText(value) {
17550
17451
  try {
17551
17452
  const text = JSON.stringify(value);
@@ -17886,15 +17787,15 @@ function findOutsideQuotes(expr, needle) {
17886
17787
  }
17887
17788
  return -1;
17888
17789
  }
17889
- function splitOutsideQuotes(expr, sep8) {
17890
- if (!expr.includes(sep8)) return [expr];
17790
+ function splitOutsideQuotes(expr, sep9) {
17791
+ if (!expr.includes(sep9)) return [expr];
17891
17792
  const parts = [];
17892
17793
  let currentStart = 0;
17893
17794
  let inQuote = null;
17894
17795
  let depth = 0;
17895
17796
  let bracketDepth = 0;
17896
17797
  let i = 0;
17897
- const sepLen = sep8.length;
17798
+ const sepLen = sep9.length;
17898
17799
  const lastStart = expr.length - sepLen;
17899
17800
  while (i <= lastStart) {
17900
17801
  const ch = expr[i];
@@ -17915,7 +17816,7 @@ function splitOutsideQuotes(expr, sep8) {
17915
17816
  else if (ch === ")") depth--;
17916
17817
  else if (ch === "[") bracketDepth++;
17917
17818
  else if (ch === "]") bracketDepth--;
17918
- if (depth === 0 && bracketDepth === 0 && expr.startsWith(sep8, i)) {
17819
+ if (depth === 0 && bracketDepth === 0 && expr.startsWith(sep9, i)) {
17919
17820
  parts.push(expr.slice(currentStart, i));
17920
17821
  i += sepLen;
17921
17822
  currentStart = i;
@@ -18868,8 +18769,8 @@ var init_engine = __esm({
18868
18769
  },
18869
18770
  first: (v) => Array.isArray(v) ? v[0] ?? null : null,
18870
18771
  last: (v) => Array.isArray(v) ? v[v.length - 1] ?? null : null,
18871
- join: (v, sep8) => Array.isArray(v) ? v.map(String).join(sep8 !== void 0 ? String(sep8) : ", ") : String(v),
18872
- split: (v, sep8) => String(v).split(sep8 !== void 0 ? String(sep8) : " "),
18772
+ join: (v, sep9) => Array.isArray(v) ? v.map(String).join(sep9 !== void 0 ? String(sep9) : ", ") : String(v),
18773
+ split: (v, sep9) => String(v).split(sep9 !== void 0 ? String(sep9) : " "),
18873
18774
  replace: (v, from, to) => {
18874
18775
  const s = String(v);
18875
18776
  if (from !== void 0 && typeof from === "object" && from !== null && !Array.isArray(from)) {
@@ -19273,7 +19174,7 @@ var init_engine = __esm({
19273
19174
  }
19274
19175
  const root = realpathSync(this.templateDir);
19275
19176
  const real = realpathSync(filePath);
19276
- if (real !== root && !real.startsWith(root + sep2)) {
19177
+ if (real !== root && !real.startsWith(root + sep3)) {
19277
19178
  throw new Error(`Template path escapes the templates directory: ${name}`);
19278
19179
  }
19279
19180
  return readFileSync6(real, "utf-8");
@@ -24663,7 +24564,7 @@ var init_dispatchPipeline = __esm({
24663
24564
 
24664
24565
  // ../core/src/static.ts
24665
24566
  import { readFileSync as readFileSync9, realpathSync as realpathSync3, statSync as statSync8 } from "node:fs";
24666
- import { join as join16, extname as extname3, sep as sep3 } from "node:path";
24567
+ import { join as join16, extname as extname3, sep as sep4 } from "node:path";
24667
24568
  import { gzipSync as gzipSync2 } from "node:zlib";
24668
24569
  function isCompressible(contentType) {
24669
24570
  return COMPRESSIBLE_PREFIXES2.some((prefix) => contentType.includes(prefix));
@@ -24694,8 +24595,8 @@ function tryServeStatic(staticDir, req2, res) {
24694
24595
  }
24695
24596
  const stat = statSync8(realPath);
24696
24597
  if (!stat.isFile()) continue;
24697
- if (realPath !== realDir && !realPath.startsWith(realDir + sep3)) continue;
24698
- if (hasHiddenSegment(realPath.slice(realDir.length + 1), sep3)) continue;
24598
+ if (realPath !== realDir && !realPath.startsWith(realDir + sep4)) continue;
24599
+ if (hasHiddenSegment(realPath.slice(realDir.length + 1), sep4)) continue;
24699
24600
  const ext = extname3(realPath);
24700
24601
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
24701
24602
  const etag = `W/"${stat.size}-${Math.floor(stat.mtimeMs / 1e3)}"`;
@@ -25678,7 +25579,7 @@ __export(generate_exports, {
25678
25579
  toTableName: () => toTableName
25679
25580
  });
25680
25581
  import { existsSync as existsSync16, mkdirSync as mkdirSync13, writeFileSync as writeFileSync10 } from "node:fs";
25681
- import { join as join21, relative as relative2, resolve as resolve11, sep as sep4 } from "node:path";
25582
+ import { join as join21, relative as relative2, resolve as resolve11, sep as sep5 } from "node:path";
25682
25583
  function ensureDir(dir) {
25683
25584
  if (__resolution.dryRun) return;
25684
25585
  if (!existsSync16(dir)) {
@@ -25804,7 +25705,7 @@ function toRelPath(absPath) {
25804
25705
  const cwd = process.cwd();
25805
25706
  const rel = relative2(cwd, absPath);
25806
25707
  if (!rel) return absPath;
25807
- return sep4 === "/" ? rel : rel.split(sep4).join("/");
25708
+ return sep5 === "/" ? rel : rel.split(sep5).join("/");
25808
25709
  }
25809
25710
  function captureEditHints(absPath, content) {
25810
25711
  if (!/\.(ts|tsx|js|mjs|cjs|jsx|sql|twig|html\.twig)$/.test(absPath)) return;
@@ -25876,12 +25777,6 @@ function printResolution() {
25876
25777
  lines.push("");
25877
25778
  process.stderr.write(lines.join("\n"));
25878
25779
  }
25879
- function toPlural(name) {
25880
- const lower = name.toLowerCase();
25881
- if (lower.endsWith("s")) return lower;
25882
- if (lower.endsWith("y") && !/[aeiou]y$/i.test(lower)) return lower.slice(0, -1) + "ies";
25883
- return lower + "s";
25884
- }
25885
25780
  function toCamel(name) {
25886
25781
  return name.charAt(0).toLowerCase() + name.slice(1);
25887
25782
  }
@@ -26314,7 +26209,7 @@ ${aiFill(`delete_${singular}`, {
26314
26209
  }
26315
26210
  function generateCrud(name, flags) {
26316
26211
  const table2 = resolveTable(name, flags, { announce: false });
26317
- const routeName = toPlural(table2);
26212
+ const routeName = pluralizeReserved(toSnake(name));
26318
26213
  const isPublic = Boolean(flags.public);
26319
26214
  if (!__resolution.jsonMode) console.log(`
26320
26215
  Generating CRUD for ${name}...
@@ -26568,7 +26463,7 @@ void test${titleName};
26568
26463
  function generateForm(name, flags) {
26569
26464
  const fields = fieldsOrDefault(flags.fields || "");
26570
26465
  const table2 = resolveTable(name, flags, { announce: false });
26571
- const routeName = toPlural(table2);
26466
+ const routeName = pluralizeReserved(toSnake(name));
26572
26467
  const inputTypes = {
26573
26468
  string: "text",
26574
26469
  str: "text",
@@ -26634,7 +26529,7 @@ function generateForm(name, flags) {
26634
26529
  function generateView(name, flags) {
26635
26530
  const fields = fieldsOrDefault(flags.fields || "");
26636
26531
  const table2 = resolveTable(name, flags, { announce: false });
26637
- const routeName = toPlural(table2);
26532
+ const routeName = pluralizeReserved(toSnake(name));
26638
26533
  const cols = fields.map(([f]) => f);
26639
26534
  const dir = resolve11("src/templates/pages");
26640
26535
  ensureDir(dir);
@@ -27646,7 +27541,7 @@ var init_generate = __esm({
27646
27541
  crud: ({ name, table: table2 }) => [
27647
27542
  `Apply the migration: npx tina4nodejs migrate`,
27648
27543
  `Serve and try: npx tina4nodejs serve -> visit /swagger`,
27649
- `Run the gate test: npx tsx tests/${toPlural(table2)}.test.ts`,
27544
+ `Run the gate test: npx tsx tests/${pluralizeReserved(toSnake(name))}.test.ts`,
27650
27545
  `Change fields: edit src/models/${name}.ts then re-run generate crud`
27651
27546
  ],
27652
27547
  migration: () => [
@@ -27664,10 +27559,10 @@ var init_generate = __esm({
27664
27559
  ],
27665
27560
  form: ({ name, table: table2 }) => [
27666
27561
  `Render from a route: res.render("forms/${table2}.twig", { item })`,
27667
- `Add the POST route: npx tina4nodejs generate route ${toPlural(table2)} --model ${name}`
27562
+ `Add the POST route: npx tina4nodejs generate route ${pluralizeReserved(toSnake(name))} --model ${name}`
27668
27563
  ],
27669
- view: ({ table: table2 }) => [
27670
- `Wire routes to render list -> ${toPlural(table2)}.twig, detail -> ${table2}.twig`,
27564
+ view: ({ name, table: table2 }) => [
27565
+ `Wire routes to render list -> ${pluralizeReserved(toSnake(name))}.twig, detail -> ${table2}.twig`,
27671
27566
  `Customize the templates in src/templates/pages/`
27672
27567
  ],
27673
27568
  auth: () => [
@@ -36021,7 +35916,7 @@ ${end}
36021
35916
  // ../core/src/devAdmin.ts
36022
35917
  import { cpus as osCpus } from "node:os";
36023
35918
  import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync23, readdirSync as readdirSync15, mkdirSync as mkdirSync19, copyFileSync as copyFileSync2, statSync as statSync17, openSync as openSync4, closeSync as closeSync4, fstatSync as fstatSync2, fchmodSync as fchmodSync2, ftruncateSync, constants as constants3, realpathSync as realpathSync6, lstatSync } from "node:fs";
36024
- import { join as join28, dirname as dirname13, resolve as resolve17, relative as relative9, sep as sep7, basename as basename6 } from "node:path";
35919
+ import { join as join28, dirname as dirname13, resolve as resolve17, relative as relative9, sep as sep8, basename as basename6 } from "node:path";
36025
35920
  import { fileURLToPath as fileURLToPath6 } from "node:url";
36026
35921
  import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
36027
35922
  function escapeHtml(value) {
@@ -36412,7 +36307,7 @@ function safeJoin(projectRoot3, rel, extraRoots = []) {
36412
36307
  const resolved = realPathOf(resolve17(root, rel));
36413
36308
  const roots = [root, ...extraRoots.filter(Boolean).map((r) => realPathOf(resolve17(r)))];
36414
36309
  for (const r of roots) {
36415
- if (resolved === r || resolved.startsWith(r.endsWith(sep7) ? r : r + sep7)) return resolved;
36310
+ if (resolved === r || resolved.startsWith(r.endsWith(sep8) ? r : r + sep8)) return resolved;
36416
36311
  }
36417
36312
  } catch {
36418
36313
  }
@@ -39951,8 +39846,8 @@ function writeMcpDiscovery(projectRoot3, port) {
39951
39846
  const lines = contents.split(/\r?\n/);
39952
39847
  const already = lines.some((l) => l.trim() === GITIGNORE_LINE || l.trim() === ".tina4");
39953
39848
  if (!already) {
39954
- const sep8 = contents.endsWith("\n") || contents === "" ? "" : "\n";
39955
- fs9.writeFileSync(gitignorePath, `${contents}${sep8}${GITIGNORE_LINE}
39849
+ const sep9 = contents.endsWith("\n") || contents === "" ? "" : "\n";
39850
+ fs9.writeFileSync(gitignorePath, `${contents}${sep9}${GITIGNORE_LINE}
39956
39851
  `, "utf-8");
39957
39852
  }
39958
39853
  }