@nodefony/drizzle 10.0.0-alpha.9 → 10.0.0-beta.1

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.
Files changed (39) hide show
  1. package/README.md +19 -19
  2. package/dist/index.js +3 -3
  3. package/dist/nodefony/command/orm-generate.js +3 -3
  4. package/dist/nodefony/config/defineModuleConfig.js +2 -2
  5. package/dist/nodefony/entity/userTable.js +1 -1
  6. package/dist/nodefony/registerStores.js +2 -2
  7. package/dist/nodefony/service/DrizzleService.js +26 -12
  8. package/dist/nodefony/src/DrizzleAuditStore.js +1 -1
  9. package/dist/nodefony/src/connectorTarget.js +1 -1
  10. package/dist/nodefony/src/migrator/DrizzleMigrator.js +3 -3
  11. package/dist/nodefony/src/migrator/adopt.js +1 -1
  12. package/dist/nodefony/src/migrator/destructive.js +2 -3
  13. package/dist/nodefony/src/migrator/drivers/mysqlDriver.js +1 -1
  14. package/dist/nodefony/src/migrator/drivers/postgresDriver.js +1 -1
  15. package/dist/nodefony/src/migrator/explain.js +7 -10
  16. package/dist/nodefony/src/migrator/history.js +25 -2
  17. package/dist/nodefony/src/migrator/kit.js +23 -9
  18. package/dist/nodefony/src/migrator/rebuildCopy.js +6 -6
  19. package/dist/nodefony/src/migrator/resolve.js +4 -4
  20. package/dist/nodefony/src/migrator/sources.js +13 -8
  21. package/dist/nodefony/src/orm-core/DrizzleOrm.js +49 -29
  22. package/dist/nodefony/src/orm-core/DrizzleRepository.js +38 -26
  23. package/dist/nodefony/src/queryKit.js +5 -5
  24. package/dist/types/nodefony/src/DrizzleUserRepository.d.ts +1 -1
  25. package/dist/types/nodefony/src/connectorTarget.d.ts +1 -1
  26. package/dist/types/nodefony/src/migrator/DrizzleMigrator.d.ts +4 -4
  27. package/dist/types/nodefony/src/migrator/destructive.d.ts +1 -1
  28. package/dist/types/nodefony/src/migrator/drivers/index.d.ts +2 -2
  29. package/dist/types/nodefony/src/migrator/explain.d.ts +9 -9
  30. package/dist/types/nodefony/src/migrator/name.d.ts +1 -1
  31. package/dist/types/nodefony/src/migrator/types.d.ts +2 -2
  32. package/dist/types/nodefony/src/orm-core/DrizzleOrm.d.ts +3 -3
  33. package/dist/types/nodefony/src/orm-core/DrizzleRepository.d.ts +1 -1
  34. package/dist/types/nodefony/src/orm-core/ddlPlan.d.ts +2 -2
  35. package/dist/types/nodefony/src/queryKit.d.ts +9 -9
  36. package/dist/types/nodefony/src/safeTarget.d.ts +2 -2
  37. package/docs/index.md +13 -13
  38. package/docs/migrations.md +1 -1
  39. package/package.json +14 -14
@@ -431,17 +431,18 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
431
431
  }
432
432
  async onConnect() {
433
433
  await this.#releasePrevious();
434
- this.#tables = Object.create(null);
434
+ const tables = Object.create(null);
435
+ this.#tables = tables;
435
436
  this.#relations = Object.create(null);
436
437
  const entities = this.#ownEntities();
437
438
  switch (this.#dialect) {
438
439
  case "sqlite":
439
- await this.#connectSqlite(entities);
440
+ await this.#connectSqlite(entities, tables);
440
441
  break;
441
442
  case "postgres":
442
- await this.#connectPostgres(entities);
443
+ await this.#connectPostgres(entities, tables);
443
444
  break;
444
- case "mysql": await this.#connectMysql(entities);
445
+ case "mysql": await this.#connectMysql(entities, tables);
445
446
  }
446
447
  if (this.#deriveSchema) {
447
448
  await this.#reconcileSchema();
@@ -461,7 +462,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
461
462
  * La méthode devient asynchrone pour cette seule raison ; le pilote, lui,
462
463
  * reste synchrone une fois chargé (`client.exec`, `client.pragma`).
463
464
  */
464
- async #connectSqlite(entities) {
465
+ async #connectSqlite(entities, tables) {
465
466
  let Sqlite;
466
467
  let sqliteDrizzle;
467
468
  try {
@@ -471,7 +472,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
471
472
  Sqlite = resolved;
472
473
  sqliteDrizzle = (await import("drizzle-orm/better-sqlite3")).drizzle;
473
474
  } catch (e) {
474
- throw new Error(`DrizzleOrm "${this.name}": the sqlite dialect needs the optional driver \`better-sqlite3\` (run \`npm i better-sqlite3\`). ${e.message}`, { cause: e });
475
+ throw new Error(`DrizzleOrm "${this.name}": the sqlite dialect needs the optional driver \`better-sqlite3\` (run \`npm i better-sqlite3\`). ` + e.message, { cause: e });
475
476
  }
476
477
  const client = new Sqlite(this.#filename);
477
478
  if (this.#filename !== ":memory:") {
@@ -506,7 +507,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
506
507
  for (const entity of entities) {
507
508
  this.#assertDialectTable(entity, SQLiteTable, "sqlite");
508
509
  const table = entity.schema;
509
- this.#tables[entity.name] = table;
510
+ tables[entity.name] = table;
510
511
  entity.model = table;
511
512
  }
512
513
  if (!this.#deriveSchema) return;
@@ -537,12 +538,12 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
537
538
  #rawQuery = async (sql, params = []) => {
538
539
  switch (this.#dialect) {
539
540
  case "sqlite": {
540
- const statement = this.#client.prepare(sql);
541
+ const statement = this.#sqliteClient().prepare(sql);
541
542
  return statement.reader ? statement.all(...params) : [];
542
543
  }
543
- case "postgres": return (await this.#pgPool.query(toDollarParams(sql), params)).rows;
544
+ case "postgres": return (await this.#pgClient().query(toDollarParams(sql), params)).rows;
544
545
  case "mysql": {
545
- const [rows] = await this.#mysqlPool.query(sql, params);
546
+ const [rows] = await this.#mysqlClient().query(sql, params);
546
547
  return Array.isArray(rows) ? rows : [];
547
548
  }
548
549
  }
@@ -555,13 +556,13 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
555
556
  async #rawExec(sql) {
556
557
  switch (this.#dialect) {
557
558
  case "sqlite":
558
- this.#client.exec(sql);
559
+ this.#sqliteClient().exec(sql);
559
560
  return;
560
561
  case "postgres":
561
- await this.#pgPool.query(sql);
562
+ await this.#pgClient().query(sql);
562
563
  return;
563
564
  case "mysql":
564
- await this.#mysqlPool.query(sql);
565
+ await this.#mysqlClient().query(sql);
565
566
  return;
566
567
  }
567
568
  }
@@ -640,20 +641,20 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
640
641
  case "sqlite": {
641
642
  const t = table;
642
643
  if (empechees.has(getTableConfig(t).name)) continue;
643
- for (const statement of this.#createIndexesSQL(t)) this.#client.exec(statement);
644
+ for (const statement of this.#createIndexesSQL(t)) this.#sqliteClient().exec(statement);
644
645
  break;
645
646
  }
646
647
  case "postgres": {
647
648
  const t = table;
648
649
  if (empechees.has(getTableConfig$1(t).name)) continue;
649
- for (const statement of this.#createIndexesPgSQL(t)) await this.#pgPool.query(statement);
650
+ for (const statement of this.#createIndexesPgSQL(t)) await this.#pgClient().query(statement);
650
651
  break;
651
652
  }
652
653
  case "mysql": {
653
654
  const t = table;
654
655
  if (empechees.has(getTableConfig$2(t).name)) continue;
655
656
  for (const statement of this.#createIndexesMysqlSQL(t)) try {
656
- await this.#mysqlPool.query(statement);
657
+ await this.#mysqlClient().query(statement);
657
658
  } catch (error) {
658
659
  if (error.code !== "ER_DUP_KEYNAME") throw error;
659
660
  }
@@ -677,7 +678,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
677
678
  * déploiement SQLite ne les tire jamais. Pool partagé ; DDL dérivé pour dev/test
678
679
  * (prod = drizzle-kit). Échec d'import → message actionnable (`npm i pg`).
679
680
  */
680
- async #connectPostgres(entities) {
681
+ async #connectPostgres(entities, tables) {
681
682
  if (!this.#url) throw new Error(`DrizzleOrm "${this.name}": dialect "postgres" requires a connection \`url\`.`);
682
683
  let PoolCtor;
683
684
  let pgDrizzle;
@@ -708,7 +709,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
708
709
  this.#pgPool = pool;
709
710
  this.#db = pgDrizzle(pool);
710
711
  try {
711
- await this.#finishPostgres(entities, pool, pgDrizzle);
712
+ await this.#finishPostgres(entities, tables, pool, pgDrizzle);
712
713
  } catch (e) {
713
714
  this.#unwireAll();
714
715
  await pool.end().catch(() => void 0);
@@ -719,11 +720,11 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
719
720
  }
720
721
  }
721
722
  /** Suite de la connexion postgres — isolée pour rendre `connect()` atomique. */
722
- async #finishPostgres(entities, pool, pgDrizzle) {
723
+ async #finishPostgres(entities, tables, pool, pgDrizzle) {
723
724
  this.#beginTx = async () => {
724
725
  const cx = await pool.connect();
725
726
  const puitsTx = (err) => {
726
- this.connectionLost(`pg (transaction) : ${err?.message ?? String(err)}`);
727
+ this.connectionLost(`pg (transaction) : ${err instanceof Error ? err.message : String(err)}`);
727
728
  };
728
729
  cx.on("error", puitsTx);
729
730
  /** Rend la connexion, en retirant d'abord NOTRE puits. */
@@ -748,7 +749,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
748
749
  for (const entity of entities) {
749
750
  this.#assertDialectTable(entity, PgTable, "postgres");
750
751
  const table = entity.schema;
751
- this.#tables[entity.name] = table;
752
+ tables[entity.name] = table;
752
753
  entity.model = table;
753
754
  }
754
755
  if (!this.#deriveSchema) return;
@@ -809,7 +810,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
809
810
  */
810
811
  #wirePgLifecycle(pool) {
811
812
  const onError = (err) => {
812
- this.connectionLost(`pg: ${err?.message ?? String(err)}`);
813
+ this.connectionLost(`pg: ${err instanceof Error ? err.message : String(err)}`);
813
814
  };
814
815
  const onConnect = () => {
815
816
  this.connectionRestored();
@@ -853,7 +854,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
853
854
  this.connectionRestored();
854
855
  cx.on("error", (err) => {
855
856
  if (this.#mysqlPool !== pool) return;
856
- this.connectionLost(`mysql: ${err?.message ?? String(err)}`);
857
+ this.connectionLost(`mysql: ${err instanceof Error ? err.message : String(err)}`);
857
858
  });
858
859
  cx.stream?.once("close", () => {
859
860
  if (this.#mysqlPool !== pool) return;
@@ -873,7 +874,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
873
874
  * `datetime(3)` (kind `dateMs` du colKit) sont écrites/relues en UTC — mêmes
874
875
  * instants que `timestamptz` PG, sans dépendre de la timezone du serveur.
875
876
  */
876
- async #connectMysql(entities) {
877
+ async #connectMysql(entities, tables) {
877
878
  if (!this.#url) throw new Error(`DrizzleOrm "${this.name}": dialect "mysql" requires a connection \`url\`.`);
878
879
  let pool;
879
880
  let mysqlDrizzle;
@@ -903,7 +904,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
903
904
  this.#mysqlPool = pool;
904
905
  this.#db = mysqlDrizzle(pool);
905
906
  try {
906
- await this.#finishMysql(entities, pool, mysqlDrizzle);
907
+ await this.#finishMysql(entities, tables, pool, mysqlDrizzle);
907
908
  } catch (e) {
908
909
  this.#unwireAll();
909
910
  await pool.end().catch(() => void 0);
@@ -914,7 +915,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
914
915
  }
915
916
  }
916
917
  /** Suite de la connexion mysql — isolée pour rendre `connect()` atomique. */
917
- async #finishMysql(entities, pool, mysqlDrizzle) {
918
+ async #finishMysql(entities, tables, pool, mysqlDrizzle) {
918
919
  this.#beginTx = async () => {
919
920
  const cx = await pool.getConnection();
920
921
  try {
@@ -937,7 +938,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
937
938
  for (const entity of entities) {
938
939
  this.#assertDialectTable(entity, MySqlTable, "mysql");
939
940
  const table = entity.schema;
940
- this.#tables[entity.name] = table;
941
+ tables[entity.name] = table;
941
942
  entity.model = table;
942
943
  }
943
944
  if (!this.#deriveSchema) return;
@@ -977,7 +978,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
977
978
  const table = this.#tables?.[name];
978
979
  if (!this.#db) throw new Error(`DrizzleOrm "${this.name}": non connecté — impossible de rendre un dépôt pour "${name}". Les tables ne sont résolues qu'à la connexion. Si ce run est une commande en ligne, elle n'a pas déclaré \`externalServices\` (CONSOLE_DATA_RUN_PROFILE).`);
979
980
  if (!table) throw new Error(`DrizzleOrm "${this.name}": no entity table registered under "${name}".`);
980
- if (this.#repositories === null) this.#repositories = Object.create(null);
981
+ this.#repositories ??= Object.create(null);
981
982
  let repository = this.#repositories[name];
982
983
  if (repository === void 0) {
983
984
  repository = new DrizzleRepository(this.#db, table, this.#relations?.[name] ?? {}, this.name, this.#dialect);
@@ -1010,6 +1011,25 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
1010
1011
  throw error;
1011
1012
  }
1012
1013
  }
1014
+ /**
1015
+ * Connexion SQLite courante — lève si le connecteur n'est pas ouvert. Les
1016
+ * appelants ne passent ici qu'une fois `onConnect` engagé : la levée ne sert
1017
+ * qu'à typer, et à dire la cause si l'ordre était un jour rompu.
1018
+ */
1019
+ #sqliteClient() {
1020
+ if (this.#client === null) throw new Error(`DrizzleOrm "${this.name}": not connected.`);
1021
+ return this.#client;
1022
+ }
1023
+ /** Pool PostgreSQL courant — même contrat que {@link #sqliteClient}. */
1024
+ #pgClient() {
1025
+ if (this.#pgPool === null) throw new Error(`DrizzleOrm "${this.name}": not connected.`);
1026
+ return this.#pgPool;
1027
+ }
1028
+ /** Pool MySQL courant — même contrat que {@link #sqliteClient}. */
1029
+ #mysqlClient() {
1030
+ if (this.#mysqlPool === null) throw new Error(`DrizzleOrm "${this.name}": not connected.`);
1031
+ return this.#mysqlPool;
1032
+ }
1013
1033
  getNativeConnection() {
1014
1034
  if (!this.#db) throw new Error(`DrizzleOrm "${this.name}": not connected.`);
1015
1035
  return this.#db;
@@ -1123,7 +1143,7 @@ var DrizzleOrm = class DrizzleOrm extends Orm {
1123
1143
  * @returns sonde `pool` (taille max, idle, empruntées, en attente).
1124
1144
  */
1125
1145
  #probePgPool(pool) {
1126
- const max = pool.options?.max;
1146
+ const max = pool.options.max;
1127
1147
  return { pool: {
1128
1148
  size: typeof max === "number" ? max : 10,
1129
1149
  available: pool.idleCount,
@@ -83,11 +83,28 @@ var DrizzleRepository = class DrizzleRepository {
83
83
  this.#dialect = dialect;
84
84
  this.#transactional = transactional;
85
85
  }
86
- /** Colonne Drizzle d'une table par nom logique. */
86
+ /** Colonne Drizzle d'une table par nom logique ; `undefined` si elle n'existe pas. */
87
87
  #col(table, name) {
88
88
  return table[name];
89
89
  }
90
90
  /**
91
+ * Colonne EXIGÉE : un nom inconnu lève au lieu de partir dans le SQL.
92
+ *
93
+ * Strict (B2) : champ inconnu = erreur, pas un skip silencieux (qui ferait
94
+ * disparaître la condition → fuite « renvoie tout »), ni un `undefined` glissé
95
+ * dans un `ORDER BY` (rendu `no such column: asc`). Même contrat que Mongoose.
96
+ * Requêtes natives → `getNativeConnection()`.
97
+ *
98
+ * @param name - nom logique du champ (critère, tri, clé étrangère).
99
+ * @param table - table qui doit le porter (défaut : celle du repository).
100
+ * @throws UnknownCriteriaField si la table ne porte pas ce champ.
101
+ */
102
+ #requireCol(name, table = this.#table) {
103
+ const col = this.#col(table, name);
104
+ if (col === void 0) throw new UnknownCriteriaField(name, getTableName(table), Object.keys(getTableColumns(table)));
105
+ return col;
106
+ }
107
+ /**
91
108
  * Colonnes de la PK de la table (mémoïsées) : colonnes inline `.primaryKey()`
92
109
  * d'abord (introspection core, valide sur tous les dialectes — couvre toutes
93
110
  * les entités framework), sinon PK composite déclarée via `primaryKey({
@@ -128,7 +145,7 @@ var DrizzleRepository = class DrizzleRepository {
128
145
  const qualified = sql.join(pk, sql.raw(", "));
129
146
  const inner = where ? sql`select ${qualified} from ${this.#table} where ${where} limit 1` : sql`select ${qualified} from ${this.#table} limit 1`;
130
147
  const output = sql.join(pk.map((col) => sql.identifier(col.name)), sql.raw(", "));
131
- const first = pk[0];
148
+ const first = pk.at(0);
132
149
  const target = pk.length === 1 && first ? sql`${first}` : sql`(${qualified})`;
133
150
  return sql`${target} in (select ${output} from (${inner}) as picked)`;
134
151
  }
@@ -229,12 +246,11 @@ var DrizzleRepository = class DrizzleRepository {
229
246
  for (const [field, value] of Object.entries(criteria)) {
230
247
  if (field === "$or") {
231
248
  if (!Array.isArray(value)) throw new Error(`DrizzleRepository(${getTableName(this.#table)}): $or attend un tableau de critères.`);
232
- const branches = value.map((branch) => this.#where(branch)).filter((branch) => branch !== void 0);
233
- if (branches.length > 0) conds.push(branches.length === 1 ? branches[0] : or(...branches));
249
+ const [first, ...rest] = value.map((branch) => this.#where(branch)).filter((branch) => branch !== void 0);
250
+ if (first !== void 0) conds.push(rest.length === 0 ? first : or(first, ...rest));
234
251
  continue;
235
252
  }
236
- const col = this.#col(this.#table, field);
237
- if (!col) throw new UnknownCriteriaField(field, getTableName(this.#table), Object.keys(getTableColumns(this.#table)));
253
+ const col = this.#requireCol(field);
238
254
  if (isFieldOperators(value)) this.#pushOperators(conds, col, value);
239
255
  else if (value === null) conds.push(isNull(col));
240
256
  else conds.push(eq(col, value));
@@ -305,14 +321,13 @@ var DrizzleRepository = class DrizzleRepository {
305
321
  const conds = [];
306
322
  let i = 0;
307
323
  for (const [field, value] of Object.entries(criteria)) {
308
- const col = this.#col(this.#table, field);
309
- if (!col) throw new UnknownCriteriaField(field, getTableName(this.#table), Object.keys(getTableColumns(this.#table)));
324
+ const col = this.#requireCol(field);
310
325
  conds.push(value === null ? isNull(col) : eq(col, sql.param(sql.placeholder(`p${i}`), col)));
311
326
  i++;
312
327
  }
313
328
  if (conds.length > 0) query = query.where(conds.length === 1 ? conds[0] : and(...conds));
314
329
  }
315
- if (options?.order?.length) query = query.orderBy(...options.order.map(([field, dir]) => dir === "DESC" ? desc(this.#col(this.#table, field)) : asc(this.#col(this.#table, field))));
330
+ if (options?.order?.length) query = query.orderBy(...options.order.map(([field, dir]) => dir === "DESC" ? desc(this.#requireCol(field)) : asc(this.#requireCol(field))));
316
331
  if (options?.limit !== void 0) query = query.limit(sql.placeholder("lim"));
317
332
  else if (options?.offset !== void 0 && this.#dialect === "sqlite") query = query.limit(sql`-1`);
318
333
  else if (options?.offset !== void 0 && this.#dialect === "mysql") query = query.limit(Number.MAX_SAFE_INTEGER);
@@ -335,7 +350,7 @@ var DrizzleRepository = class DrizzleRepository {
335
350
  const shape = this.#selectShape(criteria, options);
336
351
  if (shape === null) return null;
337
352
  let cache = this.#preparedSelects;
338
- if (cache === null) cache = this.#preparedSelects = /* @__PURE__ */ new Map();
353
+ cache ??= this.#preparedSelects = /* @__PURE__ */ new Map();
339
354
  let entry = cache.get(shape.key);
340
355
  if (entry === void 0) {
341
356
  if (cache.size >= PREPARED_CACHE_MAX) return null;
@@ -364,12 +379,12 @@ var DrizzleRepository = class DrizzleRepository {
364
379
  let query = this.#db.select().from(execTable(this.#table)).$dynamic();
365
380
  const where = this.#where(criteria);
366
381
  if (where) query = query.where(where);
367
- if (options?.order?.length) query = query.orderBy(...options.order.map(([field, dir]) => dir === "DESC" ? desc(this.#col(this.#table, field)) : asc(this.#col(this.#table, field))));
382
+ if (options?.order?.length) query = query.orderBy(...options.order.map(([field, dir]) => dir === "DESC" ? desc(this.#requireCol(field)) : asc(this.#requireCol(field))));
368
383
  if (options?.limit !== void 0) query = query.limit(options.limit);
369
384
  else if (options?.offset !== void 0 && this.#dialect === "sqlite") query = query.limit(sql`-1`);
370
385
  else if (options?.offset !== void 0 && this.#dialect === "mysql") query = query.limit(Number.MAX_SAFE_INTEGER);
371
386
  if (options?.offset !== void 0) query = query.offset(options.offset);
372
- return await this.#prof(query);
387
+ return this.#prof(query);
373
388
  }
374
389
  /** Eager-load manuel des relations déclarées (1 requête `IN (...)` par relation). */
375
390
  async #populate(rows, relations) {
@@ -379,7 +394,7 @@ var DrizzleRepository = class DrizzleRepository {
379
394
  if (!rel) throw new Error(`DrizzleRepository(${name}): relation "${name}" non déclarée.`);
380
395
  if (rel.type === "one-to-many") {
381
396
  const parentIds = rows.map((row) => row[rel.localKey]);
382
- const fkCol = this.#col(rel.targetTable, rel.foreignKey);
397
+ const fkCol = this.#requireCol(rel.foreignKey, rel.targetTable);
383
398
  const children = await this.#prof(this.#db.select().from(execTable(rel.targetTable)).where(inArray(fkCol, parentIds)));
384
399
  const byParent = /* @__PURE__ */ new Map();
385
400
  for (const child of children) {
@@ -391,7 +406,7 @@ var DrizzleRepository = class DrizzleRepository {
391
406
  for (const row of rows) row[name] = byParent.get(row[rel.localKey]) ?? [];
392
407
  } else {
393
408
  const fkValues = rows.map((row) => row[rel.foreignKey]).filter((value) => value !== null && value !== void 0);
394
- const idCol = this.#col(rel.targetTable, rel.targetKey);
409
+ const idCol = this.#requireCol(rel.targetKey, rel.targetTable);
395
410
  const parents = fkValues.length > 0 ? await this.#prof(this.#db.select().from(execTable(rel.targetTable)).where(inArray(idCol, fkValues))) : [];
396
411
  const byId = new Map(parents.map((p) => [p[rel.targetKey], p]));
397
412
  for (const row of rows) row[name] = byId.get(row[rel.foreignKey]) ?? null;
@@ -441,8 +456,7 @@ var DrizzleRepository = class DrizzleRepository {
441
456
  values[field] = value;
442
457
  continue;
443
458
  }
444
- const col = this.#col(this.#table, field);
445
- if (!col) throw new UnknownCriteriaField(field, getTableName(this.#table), Object.keys(getTableColumns(this.#table)));
459
+ const col = this.#requireCol(field);
446
460
  const apply = (fn, v) => {
447
461
  set[field] = sql`${sql.raw(fn)}(${col}, ${v})`;
448
462
  values[field] = v;
@@ -457,9 +471,7 @@ var DrizzleRepository = class DrizzleRepository {
457
471
  }
458
472
  async upsert(criteria, update, insertOnly) {
459
473
  const target = Object.keys(criteria).map((field) => {
460
- const col = this.#col(this.#table, field);
461
- if (!col) throw new UnknownCriteriaField(field, getTableName(this.#table), Object.keys(getTableColumns(this.#table)));
462
- return col;
474
+ return this.#requireCol(field);
463
475
  });
464
476
  const write = this.#writeSet(update);
465
477
  const values = {
@@ -486,8 +498,7 @@ var DrizzleRepository = class DrizzleRepository {
486
498
  async increment(criteria, changes) {
487
499
  const setObj = {};
488
500
  for (const [field, delta] of Object.entries(changes)) {
489
- const col = this.#col(this.#table, field);
490
- if (!col) throw new UnknownCriteriaField(field, getTableName(this.#table), Object.keys(getTableColumns(this.#table)));
501
+ const col = this.#requireCol(field);
491
502
  setObj[field] = sql`${col} + ${delta}`;
492
503
  }
493
504
  if (this.#dialect === "mysql") return this.#mysqlUpdateOneReturning(setObj, criteria);
@@ -511,7 +522,7 @@ var DrizzleRepository = class DrizzleRepository {
511
522
  /** DELETE atomique d'AU PLUS une ligne (PK via `#pickOne`), RETURNING la ligne. */
512
523
  async #deleteOneReturning(criteria) {
513
524
  const pick = this.#pickOne(this.#where(criteria));
514
- return await this.#prof(this.#db.delete(execTable(this.#table)).where(pick).returning());
525
+ return this.#prof(this.#db.delete(execTable(this.#table)).where(pick).returning());
515
526
  }
516
527
  /** PK obligatoire en mysql (les verbes re-SELECTent par PK). Fail-loud sinon. */
517
528
  #requirePk(verb) {
@@ -522,7 +533,8 @@ var DrizzleRepository = class DrizzleRepository {
522
533
  /** WHERE d'égalité sur la PK (valeurs plates lues par nom de colonne). */
523
534
  #pkWhere(pk, values) {
524
535
  const conds = pk.map((col) => eq(col, values[col.name]));
525
- return conds.length === 1 ? conds[0] : and(...conds);
536
+ const [first, ...rest] = conds;
537
+ return first !== void 0 && rest.length === 0 ? first : and(...conds);
526
538
  }
527
539
  /** SELECT d'UNE ligne par valeurs de PK (relecture post-mutation mysql). */
528
540
  async #selectByPk(pk, values) {
@@ -544,7 +556,7 @@ var DrizzleRepository = class DrizzleRepository {
544
556
  async #mysqlUpdateOneReturning(set, criteria) {
545
557
  const pk = this.#requirePk("updateOne");
546
558
  const where = this.#where(criteria);
547
- const target = (await this.#runSelect(criteria, { limit: 1 }))[0];
559
+ const target = (await this.#runSelect(criteria, { limit: 1 })).at(0);
548
560
  if (!target) return null;
549
561
  const pkCond = this.#pkWhere(pk, target);
550
562
  const result = await this.#prof(this.#db.update(execTable(this.#table)).set(set).where(where ? and(pkCond, where) : pkCond));
@@ -556,7 +568,7 @@ var DrizzleRepository = class DrizzleRepository {
556
568
  async #mysqlDeleteOneReturning(criteria) {
557
569
  const pk = this.#requirePk("deleteOne");
558
570
  const where = this.#where(criteria);
559
- const target = (await this.#runSelect(criteria, { limit: 1 }))[0];
571
+ const target = (await this.#runSelect(criteria, { limit: 1 })).at(0);
560
572
  if (!target) return null;
561
573
  const pkCond = this.#pkWhere(pk, target);
562
574
  const result = await this.#prof(this.#db.delete(execTable(this.#table)).where(where ? and(pkCond, where) : pkCond));
@@ -591,7 +603,7 @@ var DrizzleRepository = class DrizzleRepository {
591
603
  */
592
604
  async countDistinct(field, criteria) {
593
605
  const where = this.#where(criteria);
594
- const builder = this.#db.select({ value: countDistinct(this.#col(this.#table, field)) }).from(execTable(this.#table)).$dynamic();
606
+ const builder = this.#db.select({ value: countDistinct(this.#requireCol(field)) }).from(execTable(this.#table)).$dynamic();
595
607
  const rows = await this.#prof(where ? builder.where(where) : builder);
596
608
  return Number(rows[0]?.value ?? 0);
597
609
  }
@@ -30,12 +30,12 @@ import { sql } from "drizzle-orm";
30
30
  */
31
31
  async function findUserIdBySocialProvider(db, dialect, provider, providerId) {
32
32
  switch (dialect) {
33
- case "sqlite": return (await db.all(sql`SELECT "id" AS id FROM ${ident("sqlite", USER_TABLE_NAME)}
33
+ case "sqlite": return db.all(sql`SELECT "id" AS id FROM ${ident("sqlite", USER_TABLE_NAME)}
34
34
  WHERE EXISTS (
35
35
  SELECT 1 FROM json_each(${ident("sqlite", USER_TABLE_NAME)}."socialProviders")
36
36
  WHERE json_extract(value, '$.provider') = ${provider}
37
37
  AND json_extract(value, '$.providerId') = ${providerId}
38
- ) LIMIT 1`))[0]?.id ?? null;
38
+ ) LIMIT 1`)[0]?.id ?? null;
39
39
  case "postgres": {
40
40
  const pattern = JSON.stringify([{
41
41
  provider,
@@ -95,7 +95,7 @@ async function reserveIdempotencyKeyMysql(db, args) {
95
95
  const [inserted] = await exec.execute(sql`INSERT IGNORE INTO ${sql.raw("`idempotency_key`")}
96
96
  (${sql.raw("`key`, `fingerprint`, `state`, `response`, `expiresAt`")})
97
97
  VALUES (${key}, ${fingerprint}, 'if', NULL, ${leaseExpiresAt})`);
98
- if ((inserted?.affectedRows ?? 0) === 1) return true;
98
+ if ((inserted.affectedRows ?? 0) === 1) return true;
99
99
  const [stolen] = await exec.execute(sql`UPDATE ${sql.raw("`idempotency_key`")}
100
100
  SET ${sql.raw("`fingerprint`")} = ${fingerprint},
101
101
  ${sql.raw("`state`")} = 'if',
@@ -103,7 +103,7 @@ async function reserveIdempotencyKeyMysql(db, args) {
103
103
  ${sql.raw("`expiresAt`")} = ${leaseExpiresAt}
104
104
  WHERE ${sql.raw("`key`")} = ${key}
105
105
  AND ${sql.raw("`expiresAt`")} < ${now}`);
106
- return (stolen?.affectedRows ?? 0) > 0;
106
+ return (stolen.affectedRows ?? 0) > 0;
107
107
  }
108
108
  /** Identifiant quoté selon le dialecte (`"x"` SQL standard, `` `x` `` MySQL). */
109
109
  function ident(dialect, name) {
@@ -189,7 +189,7 @@ function orderBySql(dialect, order, allowed, fallback, tiebreaker) {
189
189
  /** Exécute un SELECT et normalise le retour en tableau de lignes (API native divergente). */
190
190
  async function runSelect(db, dialect, query) {
191
191
  switch (dialect) {
192
- case "sqlite": return await db.all(query);
192
+ case "sqlite": return db.all(query);
193
193
  case "postgres": return (await db.execute(query)).rows;
194
194
  case "mysql": {
195
195
  const [rows] = await db.execute(query);
@@ -40,7 +40,7 @@ export declare class DrizzleUserRepository implements IUserRepository {
40
40
  updateMany(criteria: Criteria<IPasswordAuthenticatedUser>, data: Partial<IPasswordAuthenticatedUser>): Promise<number>;
41
41
  delete(criteria: Criteria<IPasswordAuthenticatedUser>): Promise<number>;
42
42
  count(criteria?: Criteria<IPasswordAuthenticatedUser>): Promise<number>;
43
- countDistinct(field: keyof IPasswordAuthenticatedUser & string, criteria?: Criteria<IPasswordAuthenticatedUser>): Promise<number>;
43
+ countDistinct(field: Extract<keyof IPasswordAuthenticatedUser, string>, criteria?: Criteria<IPasswordAuthenticatedUser>): Promise<number>;
44
44
  withTransaction(tx: ITransaction): IUserRepository;
45
45
  findByIdentifier(identifier: string): Promise<IPasswordAuthenticatedUser | null>;
46
46
  /**
@@ -35,7 +35,7 @@ export declare function defaultConnectorFilename(kernel: Kernel | null, name: st
35
35
  export interface IConnectorTarget {
36
36
  dialect: SqlDialect;
37
37
  filename?: string;
38
- url?: string;
38
+ url?: string | undefined;
39
39
  }
40
40
  /**
41
41
  * Résout les coordonnées d'un connecteur : dialecte, et fichier ou URL.
@@ -10,7 +10,7 @@ export interface IDrizzleMigratorOptions extends IMigrationTarget {
10
10
  /** Registre de sources, espace de noms OUVERT. */
11
11
  sources: readonly IMigrationSource[];
12
12
  /** Délai d'attente du verrou (ms). */
13
- lockTimeoutMs?: number;
13
+ lockTimeoutMs?: number | undefined;
14
14
  /** Qui applique — hôte du job par défaut. */
15
15
  appliedBy?: string;
16
16
  /** Horloge, injectable pour les tests. */
@@ -71,12 +71,12 @@ export declare class DrizzleMigrator {
71
71
  * @returns ce qui a été levé et ré-aligné.
72
72
  */
73
73
  repair(options?: {
74
- source?: string;
75
- updateHashes?: boolean;
74
+ source?: string | undefined;
75
+ updateHashes?: boolean | undefined;
76
76
  forget?: readonly {
77
77
  source: string;
78
78
  tag: string;
79
- }[];
79
+ }[] | undefined;
80
80
  }): Promise<{
81
81
  cleared: {
82
82
  source: string;
@@ -155,5 +155,5 @@ export declare function touchesExistingRows(files: readonly {
155
155
  */
156
156
  export declare function checkDataAdvice(connector: string, target?: {
157
157
  dialect: string;
158
- target?: string;
158
+ target?: string | undefined;
159
159
  }): string;
@@ -8,9 +8,9 @@ export interface IMigrationTarget {
8
8
  /** Dialecte du connecteur. */
9
9
  dialect: SqlDialect;
10
10
  /** Fichier SQLite (dialecte `sqlite`). */
11
- filename?: string;
11
+ filename?: string | undefined;
12
12
  /** URL de connexion DIRECTE (dialectes `postgres` et `mysql`). */
13
- url?: string;
13
+ url?: string | undefined;
14
14
  }
15
15
  /**
16
16
  * Ouvre le pilote à connexion unique du dialecte demandé.
@@ -108,15 +108,15 @@ export interface IMigrationEntryReport {
108
108
  /** Où en est cette migration pour CE connecteur. */
109
109
  status: "applied" | "pending" | "failed" | "drifted" | "missing";
110
110
  /** Début de l'application, en millisecondes — absent si jamais appliquée. */
111
- appliedAt?: number;
111
+ appliedAt?: number | undefined;
112
112
  /** Durée de l'application, en millisecondes. */
113
- durationMs?: number;
113
+ durationMs?: number | undefined;
114
114
  /** Ce qui l'a appliquée, tel que l'historique l'a retenu. */
115
- appliedBy?: string;
115
+ appliedBy?: string | undefined;
116
116
  /** Déploiement qui l'a portée — groupe les migrations d'un même passage. */
117
- runId?: string;
117
+ runId?: string | undefined;
118
118
  /** Motif de l'échec, quand elle a échoué. */
119
- error?: string;
119
+ error?: string | undefined;
120
120
  }
121
121
  /**
122
122
  * La charge utile figée — cœur NEUTRE au premier niveau, spécifique du pilote
@@ -155,7 +155,7 @@ export interface IMigrationReport {
155
155
  * Son ABSENCE est un fait, pas un oubli : sur une base conforme, il n'y a
156
156
  * rien à nommer.
157
157
  */
158
- divergence?: ISchemaComparison;
158
+ divergence?: ISchemaComparison | undefined;
159
159
  /**
160
160
  * Ce que le passage a DÉTRUIT, nommé — présent au seul run réel qui a
161
161
  * appliqué une migration destructive, absent partout ailleurs.
@@ -166,7 +166,7 @@ export interface IMigrationReport {
166
166
  * octet de ce qu'il relit ne la mentionne. Son absence est un fait : rien
167
167
  * n'a été détruit.
168
168
  */
169
- destructive?: IDestructiveFinding[];
169
+ destructive?: IDestructiveFinding[] | undefined;
170
170
  /** Tout ce qui est propre au pilote SQL vit ici, et nulle part ailleurs. */
171
171
  driver: {
172
172
  kind: "sql";
@@ -174,9 +174,9 @@ export interface IMigrationReport {
174
174
  ddl: string;
175
175
  historyTable: string;
176
176
  /** La base visée, sans identifiant ni mot de passe. */
177
- target?: string;
177
+ target?: string | undefined;
178
178
  /** `true` quand la cible vient de `NF_MIGRATE_DATABASE_URL`. */
179
- fromMigrateUrl?: boolean;
179
+ fromMigrateUrl?: boolean | undefined;
180
180
  };
181
181
  }
182
182
  /** Grille des codes de sortie — **figée, jamais réaffectée**. */
@@ -34,7 +34,7 @@ export type MigrationNameCheck = {
34
34
  * geste qui échoue est pire que ne rien proposer, parce qu'il fait perdre
35
35
  * un aller-retour ET la confiance dans les autres suggestions.
36
36
  */
37
- suggestion?: string;
37
+ suggestion?: string | undefined;
38
38
  };
39
39
  /**
40
40
  * Dérive un nom acceptable d'une saisie qui ne l'est pas.
@@ -98,9 +98,9 @@ export interface IMigrationVerdict {
98
98
  /** Connecteur concerné. */
99
99
  connector: string;
100
100
  /** Source de migrations concernée, quand le refus en désigne une. */
101
- source?: string;
101
+ source?: string | undefined;
102
102
  /** Tag concerné, quand le refus en désigne un. */
103
- tag?: string;
103
+ tag?: string | undefined;
104
104
  /** Faits constatés, sans mise en forme — de quoi rendre la phrase. */
105
105
  facts: Record<string, string | number | boolean | readonly string[]>;
106
106
  /** Ce qu'il faut faire ensuite, du plus direct au plus assumé. */
@@ -13,12 +13,12 @@ export interface DrizzleOrmOptions {
13
13
  */
14
14
  dialect?: SqlDialect;
15
15
  /** Fichier SQLite (`":memory:"` par défaut) — dialecte `sqlite` uniquement. */
16
- filename?: string;
16
+ filename?: string | undefined;
17
17
  /**
18
18
  * Chaîne de connexion (`postgres://…`, `mysql://…`) — dialectes `postgres`/
19
19
  * `mysql`. Requise pour ces dialectes.
20
20
  */
21
- url?: string;
21
+ url?: string | undefined;
22
22
  /**
23
23
  * Container du service qui construit l'ORM — il porte le `syslog` du kernel.
24
24
  *
@@ -28,7 +28,7 @@ export interface DrizzleOrmOptions {
28
28
  * échecs des sondes, jamais le diagnostic de la reprise. Omis en usage
29
29
  * direct (bancs de test) : l'ORM reste alors autonome, comme avant.
30
30
  */
31
- container?: Container;
31
+ container?: Container | undefined;
32
32
  /**
33
33
  * Le schéma doit-il être DÉRIVÉ du code à la connexion ?
34
34
  *
@@ -15,7 +15,7 @@ import type { Criteria, IRepository, ITransaction, RepositoryReadOptions, Update
15
15
  * La surface d'exécution native qui DIVERGE (`db.all` vs `db.execute().rows`)
16
16
  * est routée par le `queryKit` — jamais ici.
17
17
  */
18
- export type DrizzleDb = BetterSQLite3Database<Record<string, never>>;
18
+ export type DrizzleDb = BetterSQLite3Database;
19
19
  /** Table Drizzle multi-dialecte (l'union honnête des variantes colKit). */
20
20
  export type DrizzleTable = SQLiteTable | PgTable | MySqlTable;
21
21
  /** Colonne Drizzle dialecte-agnostique (classe de base — acceptée par les
@@ -24,9 +24,9 @@ export interface IResolvedForeignKey {
24
24
  /** Colonnes visées, dans le même ordre que {@link columns}. */
25
25
  readonly foreignColumns: readonly string[];
26
26
  /** Politique d'effacement du parent (`restrict`, `set null`, `cascade`…). */
27
- readonly onDelete?: string;
27
+ readonly onDelete?: string | undefined;
28
28
  /** Politique de mise à jour de la clé du parent. */
29
- readonly onUpdate?: string;
29
+ readonly onUpdate?: string | undefined;
30
30
  }
31
31
  /** Une table à créer, et les tables que ses clés étrangères désignent. */
32
32
  export interface ITableDependency {