litedbmodel 2.2.6 → 2.2.8

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 (142) hide show
  1. package/README.md +146 -86
  2. package/dist/Column.d.ts +30 -6
  3. package/dist/Column.d.ts.map +1 -1
  4. package/dist/Column.js +30 -10
  5. package/dist/Column.js.map +1 -1
  6. package/dist/DBModel.d.ts +28 -16
  7. package/dist/DBModel.d.ts.map +1 -1
  8. package/dist/DBModel.js +60 -46
  9. package/dist/DBModel.js.map +1 -1
  10. package/dist/LazyRelation.d.ts +2 -2
  11. package/dist/LazyRelation.js +2 -2
  12. package/dist/TypeCast.d.ts +2 -2
  13. package/dist/TypeCast.d.ts.map +1 -1
  14. package/dist/TypeCast.js +7 -9
  15. package/dist/TypeCast.js.map +1 -1
  16. package/dist/decorators.d.ts +128 -60
  17. package/dist/decorators.d.ts.map +1 -1
  18. package/dist/decorators.js +393 -251
  19. package/dist/decorators.js.map +1 -1
  20. package/dist/drivers/MysqlHelper.d.ts +3 -3
  21. package/dist/drivers/MysqlHelper.d.ts.map +1 -1
  22. package/dist/drivers/MysqlHelper.js +3 -17
  23. package/dist/drivers/MysqlHelper.js.map +1 -1
  24. package/dist/drivers/MysqlSqlBuilder.d.ts.map +1 -1
  25. package/dist/drivers/MysqlSqlBuilder.js +2 -13
  26. package/dist/drivers/MysqlSqlBuilder.js.map +1 -1
  27. package/dist/drivers/PostgresHelper.d.ts +3 -2
  28. package/dist/drivers/PostgresHelper.d.ts.map +1 -1
  29. package/dist/drivers/PostgresHelper.js +3 -16
  30. package/dist/drivers/PostgresHelper.js.map +1 -1
  31. package/dist/drivers/PostgresSqlBuilder.d.ts.map +1 -1
  32. package/dist/drivers/PostgresSqlBuilder.js +2 -14
  33. package/dist/drivers/PostgresSqlBuilder.js.map +1 -1
  34. package/dist/drivers/SqliteHelper.d.ts +4 -2
  35. package/dist/drivers/SqliteHelper.d.ts.map +1 -1
  36. package/dist/drivers/SqliteHelper.js +4 -2
  37. package/dist/drivers/SqliteHelper.js.map +1 -1
  38. package/dist/drivers/SqliteSqlBuilder.d.ts.map +1 -1
  39. package/dist/drivers/SqliteSqlBuilder.js +2 -13
  40. package/dist/drivers/SqliteSqlBuilder.js.map +1 -1
  41. package/dist/index.cjs +861 -816
  42. package/dist/index.d.ts +2 -2
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/scp/coltype.d.ts +14 -5
  46. package/dist/scp/coltype.d.ts.map +1 -1
  47. package/dist/scp/coltype.js +35 -36
  48. package/dist/scp/coltype.js.map +1 -1
  49. package/dist/scp/decorator-adapter.d.ts +12 -15
  50. package/dist/scp/decorator-adapter.d.ts.map +1 -1
  51. package/dist/scp/decorator-adapter.js +13 -15
  52. package/dist/scp/decorator-adapter.js.map +1 -1
  53. package/dist/scp/index.cjs +237 -233
  54. package/dist/scp/index.mjs +237 -233
  55. package/dist/scp/makesql/json-array.d.ts +6 -0
  56. package/dist/scp/makesql/json-array.d.ts.map +1 -1
  57. package/dist/scp/makesql/json-array.js +17 -2
  58. package/dist/scp/makesql/json-array.js.map +1 -1
  59. package/dist/scp/makesql/tx.d.ts.map +1 -1
  60. package/dist/scp/makesql/tx.js +1 -3
  61. package/dist/scp/makesql/tx.js.map +1 -1
  62. package/dist/scp/relation.d.ts.map +1 -1
  63. package/dist/scp/relation.js +8 -10
  64. package/dist/scp/relation.js.map +1 -1
  65. package/docs/BENCHMARK.md +3 -3
  66. package/docs/COMPARISON.md +7 -7
  67. package/docs/api/README.md +18 -18
  68. package/docs/api/classes/Conditions.md +10 -10
  69. package/docs/api/classes/DBHandler.md +1 -1
  70. package/docs/api/classes/DBModel.md +84 -84
  71. package/docs/api/classes/LimitExceededError.md +1 -1
  72. package/docs/api/classes/Middleware.md +1 -1
  73. package/docs/api/classes/SqlRaw.md +1 -1
  74. package/docs/api/classes/SqlRef.md +1 -1
  75. package/docs/api/classes/Values.md +6 -6
  76. package/docs/api/classes/WriteInReadOnlyContextError.md +1 -1
  77. package/docs/api/classes/WriteOutsideTransactionError.md +1 -1
  78. package/docs/api/functions/belongsTo.md +10 -4
  79. package/docs/api/functions/closeAllPools.md +1 -1
  80. package/docs/api/functions/condsToRecord.md +4 -3
  81. package/docs/api/functions/createMiddleware.md +1 -1
  82. package/docs/api/functions/createPostgresDriver.md +1 -1
  83. package/docs/api/functions/createSqliteDriver.md +1 -1
  84. package/docs/api/functions/dbCast.md +1 -1
  85. package/docs/api/functions/dbCastIn.md +1 -1
  86. package/docs/api/functions/dbDynamic.md +1 -1
  87. package/docs/api/functions/dbFalse.md +1 -1
  88. package/docs/api/functions/dbImmediate.md +1 -1
  89. package/docs/api/functions/dbIn.md +1 -1
  90. package/docs/api/functions/dbNotNull.md +1 -1
  91. package/docs/api/functions/dbNow.md +1 -1
  92. package/docs/api/functions/dbNull.md +1 -1
  93. package/docs/api/functions/dbRaw.md +1 -1
  94. package/docs/api/functions/dbTrue.md +1 -1
  95. package/docs/api/functions/dbUuid.md +1 -1
  96. package/docs/api/functions/dbUuidIn.md +1 -1
  97. package/docs/api/functions/formatLocalDate.md +2 -2
  98. package/docs/api/functions/formatUTCDate.md +2 -2
  99. package/docs/api/functions/getDBConfig.md +1 -1
  100. package/docs/api/functions/getDBHandler.md +1 -1
  101. package/docs/api/functions/getTransactionConnection.md +2 -2
  102. package/docs/api/functions/getTransactionContext.md +2 -2
  103. package/docs/api/functions/hasMany.md +11 -5
  104. package/docs/api/functions/hasOne.md +10 -4
  105. package/docs/api/functions/initDBHandler.md +1 -1
  106. package/docs/api/functions/isAnySqlFragment.md +1 -1
  107. package/docs/api/functions/isConnectionError.md +1 -1
  108. package/docs/api/functions/isSqlCondition.md +1 -1
  109. package/docs/api/functions/isSqlFragment.md +1 -1
  110. package/docs/api/functions/isSqlRaw.md +1 -1
  111. package/docs/api/functions/isSqlRef.md +1 -1
  112. package/docs/api/functions/isSqlTypedFragment.md +1 -1
  113. package/docs/api/functions/model.md +8 -155
  114. package/docs/api/functions/parentRef.md +1 -1
  115. package/docs/api/functions/sql.md +1 -1
  116. package/docs/api/globals.md +99 -58
  117. package/docs/api/interfaces/Column.md +32 -31
  118. package/docs/api/interfaces/ColumnDecorator.md +81 -0
  119. package/docs/api/interfaces/ColumnOptions.md +6 -10
  120. package/docs/api/interfaces/CreatedMiddlewareClass.md +1 -1
  121. package/docs/api/interfaces/DBConfig.md +1 -1
  122. package/docs/api/interfaces/DBConfigOptions.md +1 -1
  123. package/docs/api/interfaces/DeleteOptions.md +1 -1
  124. package/docs/api/interfaces/InsertOptions.md +1 -1
  125. package/docs/api/interfaces/LimitConfig.md +1 -1
  126. package/docs/api/interfaces/MiddlewareConfig.md +1 -1
  127. package/docs/api/interfaces/ModelClassDecorator.md +64 -0
  128. package/docs/api/interfaces/ModelOptions.md +1 -1
  129. package/docs/api/interfaces/PkeyResult.md +1 -1
  130. package/docs/api/interfaces/RelationDecorator.md +72 -0
  131. package/docs/api/interfaces/SelectOptions.md +1 -1
  132. package/docs/api/interfaces/SqlCondition.md +1 -1
  133. package/docs/api/interfaces/SqlFragment.md +1 -1
  134. package/docs/api/interfaces/SqlTypedFragment.md +1 -1
  135. package/docs/api/interfaces/TransactionOptions.md +1 -1
  136. package/docs/api/interfaces/UpdateManyOptions.md +1 -1
  137. package/docs/api/interfaces/UpdateOptions.md +1 -1
  138. package/docs/api-guide.md +17 -17
  139. package/docs/architecture.md +14 -10
  140. package/docs/sql-tagged-template.md +5 -5
  141. package/eslint-plugin/rules/require-declare-for-relations.js +59 -4
  142. package/package.json +8 -7
@@ -2230,12 +2230,14 @@ function tupleInPredicate(dialect, table, columns, pgElementTypes) {
2230
2230
  function encodeJsonArrayParam(dialect, values) {
2231
2231
  return encodeJsonParam(dialect, values);
2232
2232
  }
2233
+ var BIGINT_SENTINEL = "\0int:";
2233
2234
  function encodeJsonParam(dialect, payload) {
2234
- return JSON.stringify(payload, (_key, v) => {
2235
- if (typeof v === "bigint") return Number(v);
2235
+ const tagged = JSON.stringify(payload, (_key, v) => {
2236
+ if (typeof v === "bigint") return `${BIGINT_SENTINEL}${v.toString()}`;
2236
2237
  if (dialect === "mysql" && typeof v === "boolean") return v ? 1 : 0;
2237
2238
  return v;
2238
2239
  });
2240
+ return tagged.replace(/"\\u0000int:(-?\d+)"/g, "$1");
2239
2241
  }
2240
2242
  var JsonArrayConditions = class extends DBConditions {
2241
2243
  _dialect;
@@ -2282,6 +2284,11 @@ function andTrailing(head, tails) {
2282
2284
  return [head, ...guardedTails];
2283
2285
  }
2284
2286
 
2287
+ // src/drivers/PostgresHelper.ts
2288
+ function castToJson(val) {
2289
+ return val ?? null;
2290
+ }
2291
+
2285
2292
  // src/TypeCast.ts
2286
2293
  var defaultTypeCast = {
2287
2294
  castToDatetime(val) {
@@ -2406,17 +2413,15 @@ var defaultTypeCast = {
2406
2413
  }
2407
2414
  return [];
2408
2415
  },
2416
+ // A string is JSON text to decode; any other value is already a JSON value
2409
2417
  castToJson(val) {
2410
2418
  if (val === null || val === void 0) return null;
2411
- if (typeof val === "object") return val;
2412
- if (typeof val === "string") {
2413
- try {
2414
- return JSON.parse(val);
2415
- } catch {
2416
- return null;
2417
- }
2419
+ if (typeof val !== "string") return val;
2420
+ try {
2421
+ return JSON.parse(val);
2422
+ } catch {
2423
+ return null;
2418
2424
  }
2419
- return null;
2420
2425
  }
2421
2426
  };
2422
2427
  function parsePostgresArray(literal) {
@@ -2473,7 +2478,7 @@ function castToBooleanArray(val) {
2473
2478
  function castToDatetimeArray(val) {
2474
2479
  return currentTypeCast.castToDatetimeArray(val);
2475
2480
  }
2476
- function castToJson(val) {
2481
+ function castToJson2(val) {
2477
2482
  return currentTypeCast.castToJson(val);
2478
2483
  }
2479
2484
  function formatLocalDate(d) {
@@ -2517,16 +2522,7 @@ var postgresTypeCast = {
2517
2522
  return JSON.stringify(val);
2518
2523
  },
2519
2524
  deserializeJson(val) {
2520
- if (val === null || val === void 0) return null;
2521
- if (typeof val === "object") return val;
2522
- if (typeof val === "string") {
2523
- try {
2524
- return JSON.parse(val);
2525
- } catch {
2526
- return null;
2527
- }
2528
- }
2529
- return null;
2525
+ return castToJson(val);
2530
2526
  },
2531
2527
  serializeBooleanArray(val) {
2532
2528
  if (val === null || val === void 0) return null;
@@ -2830,6 +2826,11 @@ var postgresSqlBuilder = {
2830
2826
  inferPgType
2831
2827
  };
2832
2828
 
2829
+ // src/drivers/MysqlHelper.ts
2830
+ function castToJson3(val) {
2831
+ return val ?? null;
2832
+ }
2833
+
2833
2834
  // src/drivers/MysqlSqlBuilder.ts
2834
2835
  var mysqlTypeCast = {
2835
2836
  driverName: "mysql",
@@ -2855,16 +2856,7 @@ var mysqlTypeCast = {
2855
2856
  return JSON.stringify(val);
2856
2857
  },
2857
2858
  deserializeJson(val) {
2858
- if (val === null || val === void 0) return null;
2859
- if (typeof val === "object") return val;
2860
- if (typeof val === "string") {
2861
- try {
2862
- return JSON.parse(val);
2863
- } catch {
2864
- return null;
2865
- }
2866
- }
2867
- return null;
2859
+ return castToJson3(val);
2868
2860
  },
2869
2861
  serializeBooleanArray(val) {
2870
2862
  if (val === null || val === void 0) return null;
@@ -3032,6 +3024,24 @@ var mysqlSqlBuilder = {
3032
3024
  }
3033
3025
  };
3034
3026
 
3027
+ // src/drivers/SqliteHelper.ts
3028
+ function castToJson4(val) {
3029
+ if (val === null || val === void 0) {
3030
+ return null;
3031
+ }
3032
+ if (typeof val === "object" || typeof val === "number") {
3033
+ return val;
3034
+ }
3035
+ if (typeof val === "string") {
3036
+ try {
3037
+ return JSON.parse(val);
3038
+ } catch {
3039
+ return null;
3040
+ }
3041
+ }
3042
+ return null;
3043
+ }
3044
+
3035
3045
  // src/drivers/SqliteSqlBuilder.ts
3036
3046
  var sqliteTypeCast = {
3037
3047
  driverName: "sqlite",
@@ -3057,16 +3067,7 @@ var sqliteTypeCast = {
3057
3067
  return JSON.stringify(val);
3058
3068
  },
3059
3069
  deserializeJson(val) {
3060
- if (val === null || val === void 0) return null;
3061
- if (typeof val === "object") return val;
3062
- if (typeof val === "string") {
3063
- try {
3064
- return JSON.parse(val);
3065
- } catch {
3066
- return null;
3067
- }
3068
- }
3069
- return null;
3070
+ return castToJson4(val);
3070
3071
  },
3071
3072
  serializeBooleanArray(val) {
3072
3073
  if (val === null || val === void 0) return null;
@@ -3941,8 +3942,8 @@ function sqlTypeToMaterializeClass(sqlType) {
3941
3942
  return "passthrough";
3942
3943
  }
3943
3944
  switch (t) {
3944
- // 32-bit int family: JS number holds the full range exactly. The PostgreSQL SERIAL family maps to
3945
- // its underlying int width (SERIAL/SERIAL4=int4, SMALLSERIAL/SERIAL2=int2).
3945
+ // Integer family. The PostgreSQL SERIAL types are the same integers under an auto-increment
3946
+ // default (SERIAL/SERIAL4=int4, SMALLSERIAL/SERIAL2=int2, BIGSERIAL/SERIAL8=int8).
3946
3947
  case "INTEGER":
3947
3948
  case "INT":
3948
3949
  case "SMALLINT":
@@ -3954,13 +3955,11 @@ function sqlTypeToMaterializeClass(sqlType) {
3954
3955
  case "SERIAL4":
3955
3956
  case "SMALLSERIAL":
3956
3957
  case "SERIAL2":
3957
- return "int32";
3958
- // 64-bit int: needs JS bigint for exactness.
3959
3958
  case "BIGINT":
3960
3959
  case "INT8":
3961
3960
  case "BIGSERIAL":
3962
3961
  case "SERIAL8":
3963
- return "int64";
3962
+ return "int";
3964
3963
  case "BOOLEAN":
3965
3964
  case "BOOL":
3966
3965
  return "bool";
@@ -3997,44 +3996,45 @@ function sqlTypeToMaterializeClass(sqlType) {
3997
3996
  }
3998
3997
  function keyArrayElemScalar(sqlType) {
3999
3998
  switch (sqlTypeToMaterializeClass(sqlType)) {
4000
- case "int32":
4001
- return "float";
4002
- // materializes to a JS number → bc float
4003
- case "int64":
3999
+ case "int":
4000
+ return "int";
4001
+ // materializes to a JS bigint → bc int
4004
4002
  case "date":
4005
4003
  return "string";
4006
- // materializes to a decimal / TZ string → bc string
4004
+ // materializes to a TZ string → bc string
4007
4005
  case "bool":
4008
4006
  return "bool";
4009
4007
  case "passthrough":
4010
4008
  return sqlTypeToBcScalar(sqlType) === "float" ? "float" : "string";
4011
4009
  }
4012
4010
  }
4011
+ var I64_MIN2 = -(2n ** 63n);
4012
+ var I64_MAX2 = 2n ** 63n - 1n;
4013
+ function checkI642(v) {
4014
+ if (v < I64_MIN2 || v > I64_MAX2) {
4015
+ throw new Error(`materialize int: ${v} is outside the i64 range behavior-contracts' \`int\` admits`);
4016
+ }
4017
+ return v;
4018
+ }
4013
4019
  function materializeCell(value, klass) {
4014
4020
  if (value === null || value === void 0) return value;
4015
4021
  switch (klass) {
4016
- case "int64": {
4017
- if (typeof value === "bigint") return value.toString();
4022
+ case "int": {
4023
+ if (typeof value === "bigint") return checkI642(value);
4018
4024
  if (typeof value === "string") {
4019
- if (!/^-?\d+$/.test(value)) throw new Error(`materialize int64: driver returned a non-integer string '${value}'`);
4020
- return value;
4025
+ if (!/^-?\d+$/.test(value)) throw new Error(`materialize int: driver returned a non-integer string '${value}'`);
4026
+ return checkI642(BigInt(value));
4021
4027
  }
4022
4028
  if (typeof value === "number") {
4023
- if (!Number.isInteger(value)) throw new Error(`materialize int64: driver returned a non-integer number ${value} for a 64-bit int column`);
4029
+ if (!Number.isInteger(value)) throw new Error(`materialize int: driver returned a non-integer number ${value} for an integer column`);
4024
4030
  if (!Number.isSafeInteger(value)) {
4025
4031
  throw new Error(
4026
- `materialize int64: driver returned an UNSAFE JS number ${value} for a 64-bit int column \u2014 precision was already lost before materialization (the driver must return int8 as string/bigint, not a rounded double). Configure the driver (better-sqlite3 safeIntegers / mysql2 supportBigNumbers+bigNumberStrings / pg int8-as-string).`
4032
+ `materialize int: driver returned an UNSAFE JS number ${value} for an integer column \u2014 precision was already lost before materialization (the driver must return integers as bigint/string, not a rounded double). Configure the driver (better-sqlite3 safeIntegers / mysql2 supportBigNumbers+bigNumberStrings / pg int-as-bigint).`
4027
4033
  );
4028
4034
  }
4029
- return value.toString();
4035
+ return BigInt(value);
4030
4036
  }
4031
- throw new Error(`materialize int64: unexpected driver JS type ${typeof value}`);
4032
- }
4033
- case "int32": {
4034
- if (typeof value === "number") return value;
4035
- if (typeof value === "bigint") return Number(value);
4036
- if (typeof value === "string" && /^-?\d+$/.test(value)) return Number(value);
4037
- throw new Error(`materialize int32: unexpected driver JS type ${typeof value} (${String(value)})`);
4037
+ throw new Error(`materialize int: unexpected driver JS type ${typeof value}`);
4038
4038
  }
4039
4039
  case "date": {
4040
4040
  if (typeof value === "string") return value;
@@ -5523,8 +5523,7 @@ function onConflictTail(dialect, ports, cols) {
5523
5523
  }
5524
5524
  function pgTypeSpecimen(sqlType) {
5525
5525
  const klass = sqlTypeToMaterializeClass(sqlType);
5526
- if (klass === "int32") return 0;
5527
- if (klass === "int64") return 0n;
5526
+ if (klass === "int") return 0n;
5528
5527
  if (klass === "bool") return false;
5529
5528
  if (klass === "date") return /* @__PURE__ */ new Date(0);
5530
5529
  const scalar = sqlTypeToBcScalar(sqlType);
@@ -6156,10 +6155,6 @@ function materializeChildRows(rows, cols) {
6156
6155
  row[key] = materializeCell(row[key], klass);
6157
6156
  continue;
6158
6157
  }
6159
- if (typeof row[key] === "bigint") {
6160
- const v = row[key];
6161
- row[key] = v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(v) : v.toString();
6162
- }
6163
6158
  }
6164
6159
  }
6165
6160
  return rows;
@@ -6299,133 +6294,116 @@ function compileDeleteManyBundle(name, options, dialectName = "sqlite") {
6299
6294
  var import_reflect_metadata = __toESM(require_Reflect());
6300
6295
  var COLUMNS_KEY = /* @__PURE__ */ Symbol("litedbmodel:columns");
6301
6296
  var RELATIONS_KEY = /* @__PURE__ */ Symbol("litedbmodel:relations");
6302
- function inferTypeCastFromDesignType(target, propertyKey) {
6303
- const designType = Reflect.getMetadata("design:type", target, propertyKey);
6304
- if (!designType) return void 0;
6305
- switch (designType) {
6306
- case Boolean:
6307
- return {
6308
- // v2 read contract: BOOLEAN → boolean, via the shared materializer.
6309
- typeCast: (v) => {
6310
- if (v === void 0) return void 0;
6311
- return materializeCell(v, "bool");
6312
- },
6313
- sqlCast: "boolean"
6314
- };
6315
- case Date:
6316
- return {
6317
- typeCast: (v) => {
6318
- if (v === void 0) return void 0;
6319
- return materializeCell(v, "date");
6320
- },
6321
- // Delegate to driver-specific serializeDatetime
6322
- serialize: (val, typeCast) => {
6323
- if (val === null || val === void 0) return null;
6324
- if (val instanceof Date) {
6325
- return typeCast?.serializeDatetime(val) ?? val;
6326
- }
6327
- return val;
6328
- },
6329
- sqlCast: "timestamp"
6330
- };
6331
- case Number:
6332
- return {
6333
- typeCast: (v) => {
6334
- if (v === void 0) return void 0;
6335
- if (v === null) return null;
6336
- const n = Number(v);
6337
- return isNaN(n) ? null : n;
6338
- }
6339
- };
6340
- case BigInt:
6341
- return {
6342
- // v2 read contract: BIGINT/INT8 → EXACT decimal STRING (no i64 rounding, JSON-safe), via the
6343
- // shared materializer. NOTE: the TS field type stays `bigint` in existing models for source
6344
- // compat, but the VALUE is now the exact string — the whole point of the #9 realignment.
6345
- typeCast: (v) => {
6346
- if (v === void 0) return void 0;
6347
- return materializeCell(v, "int64");
6348
- },
6349
- sqlCast: "bigint"
6350
- };
6351
- // Array, Object, String, and other types require explicit specification
6352
- default:
6353
- return void 0;
6354
- }
6355
- }
6356
- function inferBaseSqlTypeFromDesignType(target, propertyKey) {
6357
- const designType = Reflect.getMetadata("design:type", target, propertyKey);
6358
- if (!designType) return void 0;
6359
- switch (designType) {
6360
- case String:
6361
- return "TEXT";
6362
- case Number:
6363
- return "INTEGER";
6364
- case Boolean:
6365
- return "BOOLEAN";
6366
- case Date:
6367
- return "TIMESTAMP";
6368
- case BigInt:
6369
- return "BIGINT";
6370
- default:
6371
- return void 0;
6297
+ if (typeof Symbol === "function" && !Symbol.metadata) {
6298
+ Object.defineProperty(Symbol, "metadata", {
6299
+ value: /* @__PURE__ */ Symbol.for("Symbol.metadata"),
6300
+ writable: false,
6301
+ enumerable: false,
6302
+ configurable: true
6303
+ });
6304
+ }
6305
+ function isStandardContext(second) {
6306
+ return typeof second === "object" && second !== null && typeof second.kind === "string";
6307
+ }
6308
+ function classMetadataBag(context, propertyKey) {
6309
+ const bag = context.metadata;
6310
+ if (bag === void 0) {
6311
+ throw new Error(
6312
+ `litedbmodel: the standard-decorator context for '${propertyKey}' carries no \`context.metadata\`. litedbmodel defines \`Symbol.metadata\` on import, which every current emit needs to create the bag \u2014 import litedbmodel (or 'litedbmodel/decorators') BEFORE the module that defines the model.`
6313
+ );
6372
6314
  }
6315
+ return bag;
6373
6316
  }
6374
- function registerColumn(target, propertyKey, options) {
6375
- const constructor = target.constructor;
6376
- const columns = Reflect.getMetadata(COLUMNS_KEY, constructor) || /* @__PURE__ */ new Map();
6377
- let finalTypeCast = options.typeCast;
6378
- let finalSerialize = options.serialize;
6379
- let finalSqlCast = options.sqlCast;
6380
- if (!options.skipAutoInfer) {
6381
- const inferred = inferTypeCastFromDesignType(target, propertyKey);
6382
- if (inferred) {
6383
- if (!finalTypeCast) finalTypeCast = inferred.typeCast;
6384
- if (!finalSerialize) finalSerialize = inferred.serialize;
6385
- if (!finalSqlCast) finalSqlCast = inferred.sqlCast;
6386
- }
6317
+ function legacyColumnMap(constructor) {
6318
+ const own = Reflect.getOwnMetadata(COLUMNS_KEY, constructor);
6319
+ if (own !== void 0) return own;
6320
+ const inherited = Reflect.getMetadata(COLUMNS_KEY, constructor);
6321
+ const map = new Map(inherited);
6322
+ Reflect.defineMetadata(COLUMNS_KEY, map, constructor);
6323
+ return map;
6324
+ }
6325
+ function standardColumnMap(bag) {
6326
+ if (!Object.prototype.hasOwnProperty.call(bag, COLUMNS_KEY)) {
6327
+ bag[COLUMNS_KEY] = new Map(bag[COLUMNS_KEY]);
6387
6328
  }
6388
- const baseSqlType = inferBaseSqlTypeFromDesignType(target, propertyKey);
6329
+ return bag[COLUMNS_KEY];
6330
+ }
6331
+ function registerColumn(columns, propertyKey, options) {
6389
6332
  columns.set(propertyKey, {
6390
6333
  columnName: options.columnName,
6391
- typeCast: finalTypeCast,
6392
- serialize: finalSerialize,
6334
+ typeCast: options.typeCast,
6335
+ serialize: options.serialize,
6393
6336
  primaryKey: options.primaryKey,
6394
6337
  autoIncrement: options.autoIncrement,
6395
- sqlCast: finalSqlCast,
6396
- ...baseSqlType !== void 0 ? { baseSqlType } : {}
6338
+ sqlCast: options.sqlCast,
6339
+ ...options.baseSqlType !== void 0 ? { baseSqlType: options.baseSqlType } : {}
6397
6340
  });
6398
- Reflect.defineMetadata(COLUMNS_KEY, columns, constructor);
6399
6341
  }
6400
- function createColumnDecorator(typeCast, serialize, skipAutoInfer = false, sqlCast) {
6342
+ function parseColumnOptions(columnNameOrOptions, propKey) {
6343
+ if (typeof columnNameOrOptions === "string") return { columnName: columnNameOrOptions };
6344
+ if (columnNameOrOptions) {
6345
+ return {
6346
+ columnName: columnNameOrOptions.columnName || propKey,
6347
+ primaryKey: columnNameOrOptions.primaryKey,
6348
+ autoIncrement: columnNameOrOptions.autoIncrement
6349
+ };
6350
+ }
6351
+ return { columnName: propKey };
6352
+ }
6353
+ function rejectNonText(family, val) {
6354
+ if (val === null || val === void 0) return null;
6355
+ if (val instanceof Date) {
6356
+ throw new Error(
6357
+ `litedbmodel: @column.${family}() received a Date. A text column cannot serialize one \u2014 the driver would store an object literal. Use @column.datetime() / @column.date() for a date column, or format the value yourself.`
6358
+ );
6359
+ }
6360
+ if (typeof val === "object") {
6361
+ throw new Error(
6362
+ `litedbmodel: @column.${family}() received an object. Use @column.json<T>() for a JSON column, or @column.custom() with a serializer.`
6363
+ );
6364
+ }
6365
+ return val;
6366
+ }
6367
+ function materializeString(family, v) {
6368
+ if (v === void 0 || v === null) return v;
6369
+ if (typeof v === "string") return v;
6370
+ if (typeof v === "number" || typeof v === "bigint" || typeof v === "boolean") return String(v);
6371
+ throw new Error(
6372
+ `materialize ${family}: driver returned ${typeof v} for a ${family} column. Use @column.passthrough() for a BYTEA/BLOB column, or @column.json<T>() for JSON.`
6373
+ );
6374
+ }
6375
+ function createColumnDecorator(typeCast, serialize, sqlCast, baseSqlType) {
6401
6376
  return function(columnNameOrOptions) {
6402
- return function(target, propertyKey) {
6403
- const propKey = String(propertyKey);
6404
- const shouldSkipAutoInfer = skipAutoInfer || typeCast !== void 0;
6405
- let columnName;
6406
- let primaryKey;
6407
- let autoIncrement;
6408
- if (typeof columnNameOrOptions === "string") {
6409
- columnName = columnNameOrOptions;
6410
- } else if (columnNameOrOptions) {
6411
- columnName = columnNameOrOptions.columnName || propKey;
6412
- primaryKey = columnNameOrOptions.primaryKey;
6413
- autoIncrement = columnNameOrOptions.autoIncrement;
6414
- } else {
6415
- columnName = propKey;
6377
+ return function(targetOrValue, keyOrContext) {
6378
+ if (isStandardContext(keyOrContext)) {
6379
+ const propKey2 = String(keyOrContext.name);
6380
+ const parsed2 = parseColumnOptions(columnNameOrOptions, propKey2);
6381
+ registerColumn(standardColumnMap(classMetadataBag(keyOrContext, propKey2)), propKey2, {
6382
+ ...parsed2,
6383
+ typeCast,
6384
+ serialize,
6385
+ sqlCast,
6386
+ baseSqlType
6387
+ });
6388
+ return;
6416
6389
  }
6417
- registerColumn(target, propKey, {
6418
- columnName,
6390
+ const propKey = String(keyOrContext);
6391
+ const parsed = parseColumnOptions(columnNameOrOptions, propKey);
6392
+ registerColumn(legacyColumnMap(targetOrValue.constructor), propKey, {
6393
+ ...parsed,
6419
6394
  typeCast,
6420
6395
  serialize,
6421
- skipAutoInfer: shouldSkipAutoInfer,
6422
- primaryKey,
6423
- autoIncrement,
6424
- sqlCast
6396
+ sqlCast,
6397
+ baseSqlType
6425
6398
  });
6426
6399
  };
6427
6400
  };
6428
6401
  }
6402
+ function requireColumnFamily() {
6403
+ throw new Error(
6404
+ "litedbmodel: `@column()` no longer declares a column \u2014 a column must state its type with a family: @column.text() / .decimal() / .number() / .boolean() / .bigint() / .datetime() / .date() / .uuid() / .json() / .stringArray() / .intArray() / .numericArray() / .booleanArray() / .datetimeArray() / .passthrough() / .custom(). Every family takes the same argument as `@column()` did (`@column.text('db_name')`, `@column.number({ primaryKey: true })`). The bare form inferred the type from `emitDecoratorMetadata`, which esbuild (tsx/vite/vitest) never emits and standard decorators do not have, so it silently produced untyped reads."
6405
+ );
6406
+ }
6429
6407
  function serializeArray(val, typeCast) {
6430
6408
  if (val === null || val === void 0) return null;
6431
6409
  if (!Array.isArray(val)) return val;
@@ -6463,19 +6441,47 @@ function serializeJson(val, typeCast) {
6463
6441
  return JSON.stringify(val);
6464
6442
  }
6465
6443
  var column = Object.assign(
6466
- // Basic @column() - no type conversion
6467
- createColumnDecorator(),
6444
+ // The bare `@column()` declared no type — it is rejected, with the migration in the message.
6445
+ (_columnNameOrOptions) => requireColumnFamily(),
6468
6446
  {
6469
6447
  // ============================================
6470
6448
  // Primitive Types
6471
6449
  // ============================================
6450
+ /**
6451
+ * Text type (TEXT / VARCHAR / CHAR / ENUM / citext) — the driver value is already a string, so no
6452
+ * cast is applied. The family still DECLARES the column so the typed read types it as `TEXT`.
6453
+ * @example @column.text() name?: string;
6454
+ * @example @column.text('user_name') name?: string;
6455
+ */
6456
+ text: (columnNameOrOptions) => createColumnDecorator(
6457
+ (v) => materializeString("text", v),
6458
+ // the family DECLARES `string`, so it hands back one
6459
+ (val) => rejectNonText("text", val),
6460
+ // …and it cannot SERIALIZE a Date or an object
6461
+ void 0,
6462
+ // no sqlCast family (a text literal needs no SQL cast)
6463
+ "TEXT"
6464
+ // §4.1 token: types the SCP typed read
6465
+ )(columnNameOrOptions),
6466
+ /**
6467
+ * Exact decimal type (NUMERIC / DECIMAL) — read back as its exact decimal STRING (a JS number
6468
+ * rounds past 2^53). The family states the column is `numeric`, so a write binds the string as a
6469
+ * numeric — a batch write (`createMany` / `updateMany`) included.
6470
+ * @example @column.decimal() price?: string;
6471
+ */
6472
+ decimal: (columnNameOrOptions) => createColumnDecorator(
6473
+ (v) => materializeString("decimal", v),
6474
+ (val) => rejectNonText("decimal", val),
6475
+ "numeric"
6476
+ // sqlCast for WHERE / INSERT / batch-write type casting
6477
+ )(columnNameOrOptions),
6472
6478
  /**
6473
6479
  * Boolean type conversion
6474
6480
  * Converts 't'/'f', 'true'/'false', 1/0 to boolean
6475
6481
  * Preserves null for nullable columns, undefined stays undefined
6476
6482
  * @example @column.boolean() is_active?: boolean;
6477
6483
  */
6478
- boolean: (columnName) => createColumnDecorator(
6484
+ boolean: (columnNameOrOptions) => createColumnDecorator(
6479
6485
  // v2 read contract: BOOLEAN → boolean, via the shared materializer (issue #9).
6480
6486
  (v) => {
6481
6487
  if (v === void 0) return void 0;
@@ -6483,42 +6489,38 @@ var column = Object.assign(
6483
6489
  },
6484
6490
  void 0,
6485
6491
  // no custom serialize
6486
- false,
6487
- // allow auto-inference
6488
6492
  "boolean"
6489
6493
  // sqlCast for updateMany type inference
6490
- )(columnName),
6494
+ )(columnNameOrOptions),
6491
6495
  /**
6492
6496
  * Number type conversion (from string)
6493
6497
  * Preserves null for nullable columns, undefined stays undefined
6494
6498
  * @example @column.number() amount?: number;
6495
6499
  */
6496
- number: (columnName) => createColumnDecorator((v) => {
6500
+ number: (columnNameOrOptions) => createColumnDecorator((v) => {
6497
6501
  if (v === void 0) return void 0;
6498
6502
  if (v === null) return null;
6499
6503
  const n = Number(v);
6500
6504
  return isNaN(n) ? null : n;
6501
- })(columnName),
6505
+ })(columnNameOrOptions),
6502
6506
  /**
6503
6507
  * BigInt type conversion
6504
6508
  * Preserves null for nullable columns, undefined stays undefined
6505
- * @example @column.bigint() large_id?: bigint;
6509
+ * @example @column.bigint() large_id?: bigint; // bc `int` — a JS bigint, checked i64
6506
6510
  */
6507
- bigint: (columnName) => createColumnDecorator(
6508
- // v2 read contract: BIGINT/INT8 → EXACT decimal STRING (no i64 rounding, JSON-safe), via the
6509
- // shared materializer (issue #9). The declared TS field type may still be `bigint` in existing
6510
- // models, but the runtime value is now the exact string — that IS the realignment.
6511
+ bigint: (columnNameOrOptions) => createColumnDecorator(
6512
+ // An integer column reads back as a JS `bigint` — behavior-contracts' `int` value model
6513
+ // (`int` = bigint, checked i64), which is what the drivers already hand over. `JSON.stringify`
6514
+ // does not serialize a bigint: give the field a `toJSON`, or convert at the boundary.
6511
6515
  (v) => {
6512
6516
  if (v === void 0) return void 0;
6513
- return materializeCell(v, "int64");
6517
+ return materializeCell(v, "int");
6514
6518
  },
6515
6519
  void 0,
6516
6520
  // no custom serialize
6517
- false,
6518
- // allow auto-inference
6519
6521
  "bigint"
6520
6522
  // sqlCast for WHERE/INSERT type casting
6521
- )(columnName),
6523
+ )(columnNameOrOptions),
6522
6524
  // ============================================
6523
6525
  // Date/Time Types
6524
6526
  // ============================================
@@ -6530,9 +6532,9 @@ var column = Object.assign(
6530
6532
  * - PostgreSQL: Serializes to ISO 8601 UTC string with 'Z' suffix for explicit timezone
6531
6533
  * - MySQL/SQLite: Passes Date object to driver (driver-dependent timezone handling)
6532
6534
  *
6533
- * @example @column.datetime() created_at?: Date;
6535
+ * @example @column.datetime() created_at?: string; // TZ-attached string, NOT a JS Date
6534
6536
  */
6535
- datetime: (columnName) => createColumnDecorator(
6537
+ datetime: (columnNameOrOptions) => createColumnDecorator(
6536
6538
  // v2 read contract: DATE/TIMESTAMP/TIMESTAMPTZ/DATETIME/TIME → TZ-attached STRING (NOT a
6537
6539
  // TZ-shifted JS Date), via the shared materializer (issue #9). A driver already returning the
6538
6540
  // native textual form passes through; a JS Date is rendered to its lossless ISO instant.
@@ -6548,11 +6550,9 @@ var column = Object.assign(
6548
6550
  }
6549
6551
  return val;
6550
6552
  },
6551
- false,
6552
- // allow auto-inference
6553
6553
  "timestamp"
6554
6554
  // sqlCast for updateMany type inference
6555
- )(columnName),
6555
+ )(columnNameOrOptions),
6556
6556
  /**
6557
6557
  * Date type conversion — returns YYYY-MM-DD string.
6558
6558
  * Preserves null for nullable columns, undefined stays undefined.
@@ -6560,9 +6560,9 @@ var column = Object.assign(
6560
6560
  * DB values (Date object or string) are normalized to 'YYYY-MM-DD' string.
6561
6561
  * On write, string values are passed through; Date objects are formatted as 'YYYY-MM-DD'.
6562
6562
  *
6563
- * @example @column.date() birth_date?: string;
6563
+ * @example @column.date() birth_date?: string; // 'YYYY-MM-DD'
6564
6564
  */
6565
- date: (columnName) => createColumnDecorator(
6565
+ date: (columnNameOrOptions) => createColumnDecorator(
6566
6566
  (v) => {
6567
6567
  if (v === void 0) return void 0;
6568
6568
  if (v === null) return null;
@@ -6587,11 +6587,9 @@ var column = Object.assign(
6587
6587
  }
6588
6588
  return val;
6589
6589
  },
6590
- false,
6591
- // allow auto-inference
6592
6590
  "date"
6593
6591
  // sqlCast for updateMany type inference
6594
- )(columnName),
6592
+ )(columnNameOrOptions),
6595
6593
  // ============================================
6596
6594
  // Array Types
6597
6595
  // ============================================
@@ -6600,71 +6598,71 @@ var column = Object.assign(
6600
6598
  * Preserves null for nullable columns, undefined stays undefined
6601
6599
  * @example @column.stringArray() tags?: string[];
6602
6600
  */
6603
- stringArray: (columnName) => createColumnDecorator(
6601
+ stringArray: (columnNameOrOptions) => createColumnDecorator(
6604
6602
  (v) => {
6605
6603
  if (v === void 0) return void 0;
6606
6604
  if (v === null) return null;
6607
6605
  return castToStringArray(v);
6608
6606
  },
6609
6607
  serializeArray,
6610
- false,
6611
6608
  "text[]"
6612
- )(columnName),
6609
+ )(columnNameOrOptions),
6613
6610
  /**
6614
6611
  * Integer array type conversion (integer[])
6615
6612
  * Preserves null for nullable columns, undefined stays undefined
6616
6613
  * @example @column.intArray() scores?: number[];
6617
6614
  */
6618
- intArray: (columnName) => createColumnDecorator(
6615
+ intArray: (columnNameOrOptions) => createColumnDecorator(
6619
6616
  (v) => {
6620
6617
  if (v === void 0) return void 0;
6621
6618
  if (v === null) return null;
6622
6619
  return castToIntegerArray(v);
6623
6620
  },
6624
6621
  serializeArray,
6625
- false,
6626
6622
  "int[]"
6627
- )(columnName),
6623
+ )(columnNameOrOptions),
6628
6624
  /**
6629
6625
  * Numeric array type conversion (numeric[], allows null elements)
6630
6626
  * Preserves null for nullable columns, undefined stays undefined
6631
6627
  * @example @column.numericArray() values?: (number | null)[];
6632
6628
  */
6633
- numericArray: (columnName) => createColumnDecorator(
6629
+ numericArray: (columnNameOrOptions) => createColumnDecorator(
6634
6630
  (v) => {
6635
6631
  if (v === void 0) return void 0;
6636
6632
  if (v === null) return null;
6637
6633
  return castToNumericArray(v);
6638
6634
  },
6639
6635
  serializeArray,
6640
- false,
6641
6636
  "numeric[]"
6642
- )(columnName),
6637
+ )(columnNameOrOptions),
6643
6638
  /**
6644
6639
  * Boolean array type conversion (boolean[])
6645
6640
  * Preserves null for nullable columns, undefined stays undefined
6646
6641
  * @example @column.booleanArray() flags?: (boolean | null)[];
6647
6642
  */
6648
- booleanArray: (columnName) => createColumnDecorator(
6643
+ booleanArray: (columnNameOrOptions) => createColumnDecorator(
6649
6644
  (v) => {
6650
6645
  if (v === void 0) return void 0;
6651
6646
  if (v === null) return null;
6652
6647
  return castToBooleanArray(v);
6653
6648
  },
6654
6649
  serializeBooleanArray,
6655
- false,
6656
6650
  "boolean[]"
6657
- )(columnName),
6651
+ )(columnNameOrOptions),
6658
6652
  /**
6659
6653
  * DateTime array type conversion (timestamp[])
6660
6654
  * Preserves null for nullable columns, undefined stays undefined
6661
- * @example @column.datetimeArray() event_dates?: (Date | null)[];
6655
+ * @example @column.datetimeArray() event_dates?: (string | null)[];
6662
6656
  */
6663
- datetimeArray: (columnName) => createColumnDecorator(
6657
+ datetimeArray: (columnNameOrOptions) => createColumnDecorator(
6658
+ // Element-wise the SAME contract as `@column.datetime()`: a TZ-attached STRING, never a
6659
+ // TZ-shifted JS Date. The array family used to be the one place a `Date` still came back, so
6660
+ // `JSON.stringify` of a row silently re-rendered those elements in UTC — the exact hazard #9
6661
+ // closed for the scalar.
6664
6662
  (v) => {
6665
6663
  if (v === void 0) return void 0;
6666
6664
  if (v === null) return null;
6667
- return castToDatetimeArray(v);
6665
+ return castToDatetimeArray(v).map((d) => d === null ? null : materializeCell(d, "date"));
6668
6666
  },
6669
6667
  // DateTime arrays serialize each Date to ISO string
6670
6668
  (val) => {
@@ -6673,7 +6671,7 @@ var column = Object.assign(
6673
6671
  const mapped = val.map((v) => v === null ? "NULL" : v instanceof Date ? v.toISOString() : String(v));
6674
6672
  return `{${mapped.join(",")}}`;
6675
6673
  }
6676
- )(columnName),
6674
+ )(columnNameOrOptions),
6677
6675
  // ============================================
6678
6676
  // JSON Types
6679
6677
  // ============================================
@@ -6683,16 +6681,15 @@ var column = Object.assign(
6683
6681
  * @example @column.json() metadata?: Record<string, unknown>;
6684
6682
  * @example @column.json<UserSettings>() settings?: UserSettings;
6685
6683
  */
6686
- json: (columnName) => createColumnDecorator(
6684
+ json: (columnNameOrOptions) => createColumnDecorator(
6687
6685
  (v) => {
6688
6686
  if (v === void 0) return void 0;
6689
6687
  if (v === null) return null;
6690
- return castToJson(v);
6688
+ return castToJson2(v);
6691
6689
  },
6692
6690
  serializeJson,
6693
- false,
6694
6691
  "jsonb"
6695
- )(columnName),
6692
+ )(columnNameOrOptions),
6696
6693
  // ============================================
6697
6694
  // UUID Type (PostgreSQL)
6698
6695
  // ============================================
@@ -6721,22 +6718,28 @@ var column = Object.assign(
6721
6718
  if (v === null) return null;
6722
6719
  return String(v);
6723
6720
  },
6724
- void 0,
6725
- // No serialization needed - handled by sqlCast
6726
- true,
6727
- // Skip auto-inference
6721
+ (val) => rejectNonText("uuid", val),
6722
+ // the ::uuid cast handles the rest
6728
6723
  "uuid"
6729
6724
  // SQL type for casting
6730
6725
  )(columnNameOrOptions),
6731
6726
  // ============================================
6732
6727
  // Custom Type Conversion
6733
6728
  // ============================================
6729
+ /**
6730
+ * The driver's value, UNCAST — for a column whose type the library has no cast for (`BYTEA` /
6731
+ * `BLOB` arrives as a driver Buffer, a vendor type as whatever the driver decodes). It states
6732
+ * "this column is passed through", which is a DECLARATION; the removed bare `@column()` was the
6733
+ * absence of one, and produced this same passthrough by accident for every unresolvable type.
6734
+ * @example @column.passthrough() payload?: unknown;
6735
+ */
6736
+ passthrough: (columnNameOrOptions) => createColumnDecorator()(columnNameOrOptions),
6734
6737
  /**
6735
6738
  * Custom type conversion with user-provided function
6736
6739
  * @example @column.custom((v) => String(v).toUpperCase()) status?: string;
6737
6740
  * @example @column.custom((v) => v, (v) => JSON.stringify(v)) data?: MyType; // with serializer
6738
6741
  */
6739
- custom: (castFn, serializeFn, columnName) => createColumnDecorator(castFn, serializeFn)(columnName)
6742
+ custom: (castFn, serializeFn, columnNameOrOptions) => createColumnDecorator(castFn, serializeFn)(columnNameOrOptions)
6740
6743
  }
6741
6744
  );
6742
6745
  function getRelationMeta(modelClass) {
@@ -6780,6 +6783,7 @@ function getPrimaryKey(modelClass) {
6780
6783
  // src/scp/decorator-adapter.ts
6781
6784
  var COLUMN_FAMILY_SQL_TYPE = {
6782
6785
  boolean: "BOOLEAN",
6786
+ numeric: "NUMERIC",
6783
6787
  bigint: "BIGINT",
6784
6788
  timestamp: "TIMESTAMP",
6785
6789
  date: "DATE",