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
package/dist/index.cjs CHANGED
@@ -1158,14 +1158,14 @@ __export(index_exports, {
1158
1158
  _legacyOr: () => or,
1159
1159
  and: () => and,
1160
1160
  belongsTo: () => belongsTo,
1161
- castToBoolean: () => castToBoolean,
1162
- castToBooleanArray: () => castToBooleanArray,
1163
- castToDatetime: () => castToDatetime,
1164
- castToDatetimeArray: () => castToDatetimeArray,
1165
- castToIntegerArray: () => castToIntegerArray,
1166
- castToJson: () => castToJson,
1167
- castToNumericArray: () => castToNumericArray,
1168
- castToStringArray: () => castToStringArray,
1161
+ castToBoolean: () => castToBoolean2,
1162
+ castToBooleanArray: () => castToBooleanArray2,
1163
+ castToDatetime: () => castToDatetime2,
1164
+ castToDatetimeArray: () => castToDatetimeArray2,
1165
+ castToIntegerArray: () => castToIntegerArray2,
1166
+ castToJson: () => castToJson2,
1167
+ castToNumericArray: () => castToNumericArray2,
1168
+ castToStringArray: () => castToStringArray2,
1169
1169
  closeAllPools: () => closeAllPools2,
1170
1170
  column: () => column,
1171
1171
  columnsToNames: () => columnsToNames,
@@ -1595,6 +1595,166 @@ var defaultLogger = {
1595
1595
  error: console.error
1596
1596
  };
1597
1597
 
1598
+ // src/drivers/PostgresHelper.ts
1599
+ function castToDatetime(val) {
1600
+ if (val === null || val === void 0) {
1601
+ return null;
1602
+ }
1603
+ if (val instanceof Date) {
1604
+ return val;
1605
+ }
1606
+ if (typeof val === "string" || typeof val === "number") {
1607
+ const date = new Date(val);
1608
+ return isNaN(date.getTime()) ? null : date;
1609
+ }
1610
+ return null;
1611
+ }
1612
+ function castToBoolean(val) {
1613
+ if (val === null || val === void 0) {
1614
+ return null;
1615
+ }
1616
+ if (typeof val === "boolean") {
1617
+ return val;
1618
+ }
1619
+ if (typeof val === "string") {
1620
+ const lower = val.toLowerCase();
1621
+ if (lower === "true" || lower === "t" || lower === "1") {
1622
+ return true;
1623
+ }
1624
+ if (lower === "false" || lower === "f" || lower === "0") {
1625
+ return false;
1626
+ }
1627
+ }
1628
+ if (typeof val === "number") {
1629
+ return val !== 0;
1630
+ }
1631
+ return null;
1632
+ }
1633
+ function castToIntegerArray(val) {
1634
+ if (val === null || val === void 0) {
1635
+ return [];
1636
+ }
1637
+ if (Array.isArray(val)) {
1638
+ return val.map((v) => {
1639
+ if (typeof v === "number") return v;
1640
+ const n = parseInt(String(v), 10);
1641
+ return isNaN(n) ? 0 : n;
1642
+ });
1643
+ }
1644
+ if (typeof val === "string") {
1645
+ return pgArrayParse(val).map((v) => {
1646
+ const n = parseInt(v, 10);
1647
+ return isNaN(n) ? 0 : n;
1648
+ });
1649
+ }
1650
+ return [];
1651
+ }
1652
+ function castToNumericArray(val) {
1653
+ if (val === null || val === void 0) {
1654
+ return [];
1655
+ }
1656
+ if (Array.isArray(val)) {
1657
+ return val.map((v) => {
1658
+ if (v === null || v === void 0) return null;
1659
+ if (typeof v === "number") return v;
1660
+ const n = parseFloat(String(v));
1661
+ return isNaN(n) ? null : n;
1662
+ });
1663
+ }
1664
+ if (typeof val === "string") {
1665
+ return pgArrayParse(val).map((v) => {
1666
+ if (v === "NULL" || v === "") return null;
1667
+ const n = parseFloat(v);
1668
+ return isNaN(n) ? null : n;
1669
+ });
1670
+ }
1671
+ return [];
1672
+ }
1673
+ function castToStringArray(val) {
1674
+ if (val === null || val === void 0) {
1675
+ return [];
1676
+ }
1677
+ if (Array.isArray(val)) {
1678
+ return val.map((v) => String(v));
1679
+ }
1680
+ if (typeof val === "string") {
1681
+ return pgArrayParse(val);
1682
+ }
1683
+ return [];
1684
+ }
1685
+ function castToBooleanArray(val) {
1686
+ if (val === null || val === void 0) {
1687
+ return [];
1688
+ }
1689
+ if (Array.isArray(val)) {
1690
+ return val.map((v) => castToBoolean(v));
1691
+ }
1692
+ if (typeof val === "string") {
1693
+ return pgArrayParse(val).map((v) => castToBoolean(v));
1694
+ }
1695
+ return [];
1696
+ }
1697
+ function castToDatetimeArray(val) {
1698
+ if (val === null || val === void 0) {
1699
+ return [];
1700
+ }
1701
+ if (Array.isArray(val)) {
1702
+ return val.map((v) => castToDatetime(v));
1703
+ }
1704
+ if (typeof val === "string") {
1705
+ return pgArrayParse(val).map((v) => castToDatetime(v));
1706
+ }
1707
+ return [];
1708
+ }
1709
+ function castToJson(val) {
1710
+ return val ?? null;
1711
+ }
1712
+ function pgArrayParse(literal) {
1713
+ if (!literal || literal === "{}") {
1714
+ return [];
1715
+ }
1716
+ let content = literal.trim();
1717
+ if (content.startsWith("{") && content.endsWith("}")) {
1718
+ content = content.slice(1, -1);
1719
+ }
1720
+ if (content === "") {
1721
+ return [];
1722
+ }
1723
+ const result = [];
1724
+ let current = "";
1725
+ let inQuotes = false;
1726
+ let escaped = false;
1727
+ for (let i = 0; i < content.length; i++) {
1728
+ const char = content[i];
1729
+ if (escaped) {
1730
+ current += char;
1731
+ escaped = false;
1732
+ continue;
1733
+ }
1734
+ if (char === "\\") {
1735
+ escaped = true;
1736
+ continue;
1737
+ }
1738
+ if (char === '"') {
1739
+ inQuotes = !inQuotes;
1740
+ continue;
1741
+ }
1742
+ if (char === "," && !inQuotes) {
1743
+ result.push(current);
1744
+ current = "";
1745
+ continue;
1746
+ }
1747
+ current += char;
1748
+ }
1749
+ if (current !== "" || result.length > 0) {
1750
+ result.push(current);
1751
+ }
1752
+ return result;
1753
+ }
1754
+ function formatSqlCast(placeholder, sqlCast) {
1755
+ return `${placeholder}::${sqlCast}`;
1756
+ }
1757
+
1598
1758
  // src/TypeCast.ts
1599
1759
  var defaultTypeCast = {
1600
1760
  castToDatetime(val) {
@@ -1719,17 +1879,15 @@ var defaultTypeCast = {
1719
1879
  }
1720
1880
  return [];
1721
1881
  },
1882
+ // A string is JSON text to decode; any other value is already a JSON value
1722
1883
  castToJson(val) {
1723
1884
  if (val === null || val === void 0) return null;
1724
- if (typeof val === "object") return val;
1725
- if (typeof val === "string") {
1726
- try {
1727
- return JSON.parse(val);
1728
- } catch {
1729
- return null;
1730
- }
1885
+ if (typeof val !== "string") return val;
1886
+ try {
1887
+ return JSON.parse(val);
1888
+ } catch {
1889
+ return null;
1731
1890
  }
1732
- return null;
1733
1891
  }
1734
1892
  };
1735
1893
  function parsePostgresArray(literal) {
@@ -1780,28 +1938,28 @@ function resetTypeCastImpl() {
1780
1938
  function getTypeCast() {
1781
1939
  return currentTypeCast;
1782
1940
  }
1783
- function castToDatetime(val) {
1941
+ function castToDatetime2(val) {
1784
1942
  return currentTypeCast.castToDatetime(val);
1785
1943
  }
1786
- function castToBoolean(val) {
1944
+ function castToBoolean2(val) {
1787
1945
  return currentTypeCast.castToBoolean(val);
1788
1946
  }
1789
- function castToIntegerArray(val) {
1947
+ function castToIntegerArray2(val) {
1790
1948
  return currentTypeCast.castToIntegerArray(val);
1791
1949
  }
1792
- function castToNumericArray(val) {
1950
+ function castToNumericArray2(val) {
1793
1951
  return currentTypeCast.castToNumericArray(val);
1794
1952
  }
1795
- function castToStringArray(val) {
1953
+ function castToStringArray2(val) {
1796
1954
  return currentTypeCast.castToStringArray(val);
1797
1955
  }
1798
- function castToBooleanArray(val) {
1956
+ function castToBooleanArray2(val) {
1799
1957
  return currentTypeCast.castToBooleanArray(val);
1800
1958
  }
1801
- function castToDatetimeArray(val) {
1959
+ function castToDatetimeArray2(val) {
1802
1960
  return currentTypeCast.castToDatetimeArray(val);
1803
1961
  }
1804
- function castToJson(val) {
1962
+ function castToJson2(val) {
1805
1963
  return currentTypeCast.castToJson(val);
1806
1964
  }
1807
1965
  function formatLocalDate(d) {
@@ -1845,16 +2003,7 @@ var postgresTypeCast = {
1845
2003
  return JSON.stringify(val);
1846
2004
  },
1847
2005
  deserializeJson(val) {
1848
- if (val === null || val === void 0) return null;
1849
- if (typeof val === "object") return val;
1850
- if (typeof val === "string") {
1851
- try {
1852
- return JSON.parse(val);
1853
- } catch {
1854
- return null;
1855
- }
1856
- }
1857
- return null;
2006
+ return castToJson(val);
1858
2007
  },
1859
2008
  serializeBooleanArray(val) {
1860
2009
  if (val === null || val === void 0) return null;
@@ -2158,73 +2307,151 @@ var postgresSqlBuilder = {
2158
2307
  inferPgType
2159
2308
  };
2160
2309
 
2161
- // src/drivers/MysqlSqlBuilder.ts
2162
- var mysqlTypeCast = {
2163
- driverName: "mysql",
2164
- serializeArray(val) {
2165
- if (val === null || val === void 0) return null;
2166
- return JSON.stringify(val);
2167
- },
2168
- deserializeArray(val) {
2169
- if (val === null || val === void 0) return null;
2170
- if (Array.isArray(val)) return val;
2171
- if (typeof val === "string") {
2172
- try {
2173
- const parsed = JSON.parse(val);
2174
- return Array.isArray(parsed) ? parsed : null;
2175
- } catch {
2176
- return null;
2177
- }
2178
- }
2179
- return null;
2180
- },
2181
- serializeJson(val) {
2182
- if (val === null || val === void 0) return null;
2183
- return JSON.stringify(val);
2184
- },
2185
- deserializeJson(val) {
2186
- if (val === null || val === void 0) return null;
2187
- if (typeof val === "object") return val;
2188
- if (typeof val === "string") {
2189
- try {
2190
- return JSON.parse(val);
2191
- } catch {
2192
- return null;
2193
- }
2194
- }
2195
- return null;
2196
- },
2197
- serializeBooleanArray(val) {
2198
- if (val === null || val === void 0) return null;
2199
- return JSON.stringify(val);
2200
- },
2201
- deserializeBooleanArray(val) {
2202
- if (val === null || val === void 0) return null;
2203
- if (Array.isArray(val)) return val;
2204
- if (typeof val === "string") {
2205
- try {
2206
- const parsed = JSON.parse(val);
2207
- return Array.isArray(parsed) ? parsed : null;
2208
- } catch {
2209
- return null;
2210
- }
2211
- }
2310
+ // src/drivers/MysqlHelper.ts
2311
+ function castToDatetime3(val) {
2312
+ if (val === null || val === void 0) {
2212
2313
  return null;
2213
- },
2214
- /**
2215
- * MySQL: return Date object as-is, let mysql2 driver handle conversion
2216
- * Note: MySQL DATETIME has no timezone - values stored/retrieved in server timezone
2217
- */
2218
- serializeDatetime(val) {
2219
- return val;
2220
- },
2221
- /**
2222
- * MySQL: return Date object as-is, let mysql2 driver handle conversion
2223
- */
2224
- serializeDate(val) {
2314
+ }
2315
+ if (val instanceof Date) {
2225
2316
  return val;
2226
2317
  }
2227
- };
2318
+ if (typeof val === "string" || typeof val === "number") {
2319
+ const date = new Date(val);
2320
+ return isNaN(date.getTime()) ? null : date;
2321
+ }
2322
+ return null;
2323
+ }
2324
+ function castToBoolean3(val) {
2325
+ if (val === null || val === void 0) {
2326
+ return null;
2327
+ }
2328
+ if (typeof val === "boolean") {
2329
+ return val;
2330
+ }
2331
+ if (typeof val === "number") {
2332
+ return val !== 0;
2333
+ }
2334
+ if (typeof val === "string") {
2335
+ const lower = val.toLowerCase();
2336
+ if (lower === "true" || lower === "1") {
2337
+ return true;
2338
+ }
2339
+ if (lower === "false" || lower === "0") {
2340
+ return false;
2341
+ }
2342
+ }
2343
+ if (Buffer.isBuffer(val)) {
2344
+ return val[0] !== 0;
2345
+ }
2346
+ return null;
2347
+ }
2348
+ function castToIntegerArray3(val) {
2349
+ if (val === null || val === void 0) {
2350
+ return [];
2351
+ }
2352
+ if (Array.isArray(val)) {
2353
+ return val.map((v) => {
2354
+ const n = parseInt(String(v), 10);
2355
+ return isNaN(n) ? 0 : n;
2356
+ });
2357
+ }
2358
+ if (typeof val === "string") {
2359
+ try {
2360
+ const parsed = JSON.parse(val);
2361
+ if (Array.isArray(parsed)) {
2362
+ return parsed.map((v) => {
2363
+ const n = parseInt(String(v), 10);
2364
+ return isNaN(n) ? 0 : n;
2365
+ });
2366
+ }
2367
+ } catch {
2368
+ }
2369
+ }
2370
+ return [];
2371
+ }
2372
+ function castToStringArray3(val) {
2373
+ if (val === null || val === void 0) {
2374
+ return [];
2375
+ }
2376
+ if (Array.isArray(val)) {
2377
+ return val.map((v) => String(v));
2378
+ }
2379
+ if (typeof val === "string") {
2380
+ try {
2381
+ const parsed = JSON.parse(val);
2382
+ if (Array.isArray(parsed)) {
2383
+ return parsed.map((v) => String(v));
2384
+ }
2385
+ } catch {
2386
+ }
2387
+ }
2388
+ return [];
2389
+ }
2390
+ function castToJson3(val) {
2391
+ return val ?? null;
2392
+ }
2393
+ function formatSqlCast2(placeholder, _sqlCast) {
2394
+ return placeholder;
2395
+ }
2396
+
2397
+ // src/drivers/MysqlSqlBuilder.ts
2398
+ var mysqlTypeCast = {
2399
+ driverName: "mysql",
2400
+ serializeArray(val) {
2401
+ if (val === null || val === void 0) return null;
2402
+ return JSON.stringify(val);
2403
+ },
2404
+ deserializeArray(val) {
2405
+ if (val === null || val === void 0) return null;
2406
+ if (Array.isArray(val)) return val;
2407
+ if (typeof val === "string") {
2408
+ try {
2409
+ const parsed = JSON.parse(val);
2410
+ return Array.isArray(parsed) ? parsed : null;
2411
+ } catch {
2412
+ return null;
2413
+ }
2414
+ }
2415
+ return null;
2416
+ },
2417
+ serializeJson(val) {
2418
+ if (val === null || val === void 0) return null;
2419
+ return JSON.stringify(val);
2420
+ },
2421
+ deserializeJson(val) {
2422
+ return castToJson3(val);
2423
+ },
2424
+ serializeBooleanArray(val) {
2425
+ if (val === null || val === void 0) return null;
2426
+ return JSON.stringify(val);
2427
+ },
2428
+ deserializeBooleanArray(val) {
2429
+ if (val === null || val === void 0) return null;
2430
+ if (Array.isArray(val)) return val;
2431
+ if (typeof val === "string") {
2432
+ try {
2433
+ const parsed = JSON.parse(val);
2434
+ return Array.isArray(parsed) ? parsed : null;
2435
+ } catch {
2436
+ return null;
2437
+ }
2438
+ }
2439
+ return null;
2440
+ },
2441
+ /**
2442
+ * MySQL: return Date object as-is, let mysql2 driver handle conversion
2443
+ * Note: MySQL DATETIME has no timezone - values stored/retrieved in server timezone
2444
+ */
2445
+ serializeDatetime(val) {
2446
+ return val;
2447
+ },
2448
+ /**
2449
+ * MySQL: return Date object as-is, let mysql2 driver handle conversion
2450
+ */
2451
+ serializeDate(val) {
2452
+ return val;
2453
+ }
2454
+ };
2228
2455
  var mysqlSqlBuilder = {
2229
2456
  driverType: "mysql",
2230
2457
  typeCast: mysqlTypeCast,
@@ -2360,6 +2587,103 @@ var mysqlSqlBuilder = {
2360
2587
  }
2361
2588
  };
2362
2589
 
2590
+ // src/drivers/SqliteHelper.ts
2591
+ function castToDatetime4(val) {
2592
+ if (val === null || val === void 0) {
2593
+ return null;
2594
+ }
2595
+ if (val instanceof Date) {
2596
+ return val;
2597
+ }
2598
+ if (typeof val === "string" || typeof val === "number") {
2599
+ const date = new Date(val);
2600
+ return isNaN(date.getTime()) ? null : date;
2601
+ }
2602
+ return null;
2603
+ }
2604
+ function castToBoolean4(val) {
2605
+ if (val === null || val === void 0) {
2606
+ return null;
2607
+ }
2608
+ if (typeof val === "boolean") {
2609
+ return val;
2610
+ }
2611
+ if (typeof val === "number") {
2612
+ return val !== 0;
2613
+ }
2614
+ if (typeof val === "string") {
2615
+ const lower = val.toLowerCase();
2616
+ if (lower === "true" || lower === "1") {
2617
+ return true;
2618
+ }
2619
+ if (lower === "false" || lower === "0") {
2620
+ return false;
2621
+ }
2622
+ }
2623
+ return null;
2624
+ }
2625
+ function castToIntegerArray4(val) {
2626
+ if (val === null || val === void 0) {
2627
+ return [];
2628
+ }
2629
+ if (Array.isArray(val)) {
2630
+ return val.map((v) => {
2631
+ const n = parseInt(String(v), 10);
2632
+ return isNaN(n) ? 0 : n;
2633
+ });
2634
+ }
2635
+ if (typeof val === "string") {
2636
+ try {
2637
+ const parsed = JSON.parse(val);
2638
+ if (Array.isArray(parsed)) {
2639
+ return parsed.map((v) => {
2640
+ const n = parseInt(String(v), 10);
2641
+ return isNaN(n) ? 0 : n;
2642
+ });
2643
+ }
2644
+ } catch {
2645
+ }
2646
+ }
2647
+ return [];
2648
+ }
2649
+ function castToStringArray4(val) {
2650
+ if (val === null || val === void 0) {
2651
+ return [];
2652
+ }
2653
+ if (Array.isArray(val)) {
2654
+ return val.map((v) => String(v));
2655
+ }
2656
+ if (typeof val === "string") {
2657
+ try {
2658
+ const parsed = JSON.parse(val);
2659
+ if (Array.isArray(parsed)) {
2660
+ return parsed.map((v) => String(v));
2661
+ }
2662
+ } catch {
2663
+ }
2664
+ }
2665
+ return [];
2666
+ }
2667
+ function castToJson4(val) {
2668
+ if (val === null || val === void 0) {
2669
+ return null;
2670
+ }
2671
+ if (typeof val === "object" || typeof val === "number") {
2672
+ return val;
2673
+ }
2674
+ if (typeof val === "string") {
2675
+ try {
2676
+ return JSON.parse(val);
2677
+ } catch {
2678
+ return null;
2679
+ }
2680
+ }
2681
+ return null;
2682
+ }
2683
+ function formatSqlCast3(placeholder, _sqlCast) {
2684
+ return placeholder;
2685
+ }
2686
+
2363
2687
  // src/drivers/SqliteSqlBuilder.ts
2364
2688
  var sqliteTypeCast = {
2365
2689
  driverName: "sqlite",
@@ -2385,16 +2709,7 @@ var sqliteTypeCast = {
2385
2709
  return JSON.stringify(val);
2386
2710
  },
2387
2711
  deserializeJson(val) {
2388
- if (val === null || val === void 0) return null;
2389
- if (typeof val === "object") return val;
2390
- if (typeof val === "string") {
2391
- try {
2392
- return JSON.parse(val);
2393
- } catch {
2394
- return null;
2395
- }
2396
- }
2397
- return null;
2712
+ return castToJson4(val);
2398
2713
  },
2399
2714
  serializeBooleanArray(val) {
2400
2715
  if (val === null || val === void 0) return null;
@@ -3551,436 +3866,66 @@ var MysqlDriver = class {
3551
3866
  const [selectResult] = await conn.query(selectSql, [insertId, insertId + affectedRows]);
3552
3867
  const rows2 = selectResult;
3553
3868
  this.logger.debug(`Retry succeeded in ${duration}ms, rows: ${rows2.length}`);
3554
- return {
3555
- rows: rows2,
3556
- rowCount: rows2.length
3557
- };
3558
- }
3559
- }
3560
- }
3561
- const resultObj = result;
3562
- const rowCount = resultObj.affectedRows ?? 0;
3563
- const rows = Array.isArray(result) ? result : [];
3564
- this.logger.debug(`Retry succeeded in ${duration}ms, affected: ${rowCount}`);
3565
- return {
3566
- rows,
3567
- rowCount
3568
- };
3569
- } catch (retryError) {
3570
- this.logger.error(`Retry also failed: ${sqlWithoutReturning}`, retryError);
3571
- throw retryError;
3572
- }
3573
- }
3574
- this.logger.error(`Write failed: ${sqlWithoutReturning}`, error);
3575
- throw error;
3576
- }
3577
- }
3578
- /**
3579
- * Get a connection for transaction (uses writer pool if available)
3580
- */
3581
- async getConnection() {
3582
- const pool = this.writerPool || this.pool;
3583
- const connection = await pool.getConnection();
3584
- return new MysqlConnection(connection, this.logger);
3585
- }
3586
- /**
3587
- * Close all connections
3588
- */
3589
- async close() {
3590
- await closePool2(this.config);
3591
- if (this.writerConfig) {
3592
- await closePool2(this.writerConfig);
3593
- }
3594
- }
3595
- /**
3596
- * Set logger
3597
- */
3598
- setLogger(logger) {
3599
- this.logger = logger;
3600
- }
3601
- /**
3602
- * Get the underlying pool (for advanced use)
3603
- */
3604
- getPool() {
3605
- return this.pool;
3606
- }
3607
- /**
3608
- * Get the underlying writer pool
3609
- */
3610
- getWriterPool() {
3611
- return this.writerPool;
3612
- }
3613
- };
3614
-
3615
- // src/drivers/PostgresHelper.ts
3616
- function castToDatetime2(val) {
3617
- if (val === null || val === void 0) {
3618
- return null;
3619
- }
3620
- if (val instanceof Date) {
3621
- return val;
3622
- }
3623
- if (typeof val === "string" || typeof val === "number") {
3624
- const date = new Date(val);
3625
- return isNaN(date.getTime()) ? null : date;
3626
- }
3627
- return null;
3628
- }
3629
- function castToBoolean2(val) {
3630
- if (val === null || val === void 0) {
3631
- return null;
3632
- }
3633
- if (typeof val === "boolean") {
3634
- return val;
3635
- }
3636
- if (typeof val === "string") {
3637
- const lower = val.toLowerCase();
3638
- if (lower === "true" || lower === "t" || lower === "1") {
3639
- return true;
3640
- }
3641
- if (lower === "false" || lower === "f" || lower === "0") {
3642
- return false;
3643
- }
3644
- }
3645
- if (typeof val === "number") {
3646
- return val !== 0;
3647
- }
3648
- return null;
3649
- }
3650
- function castToIntegerArray2(val) {
3651
- if (val === null || val === void 0) {
3652
- return [];
3653
- }
3654
- if (Array.isArray(val)) {
3655
- return val.map((v) => {
3656
- if (typeof v === "number") return v;
3657
- const n = parseInt(String(v), 10);
3658
- return isNaN(n) ? 0 : n;
3659
- });
3660
- }
3661
- if (typeof val === "string") {
3662
- return pgArrayParse(val).map((v) => {
3663
- const n = parseInt(v, 10);
3664
- return isNaN(n) ? 0 : n;
3665
- });
3666
- }
3667
- return [];
3668
- }
3669
- function castToNumericArray2(val) {
3670
- if (val === null || val === void 0) {
3671
- return [];
3672
- }
3673
- if (Array.isArray(val)) {
3674
- return val.map((v) => {
3675
- if (v === null || v === void 0) return null;
3676
- if (typeof v === "number") return v;
3677
- const n = parseFloat(String(v));
3678
- return isNaN(n) ? null : n;
3679
- });
3680
- }
3681
- if (typeof val === "string") {
3682
- return pgArrayParse(val).map((v) => {
3683
- if (v === "NULL" || v === "") return null;
3684
- const n = parseFloat(v);
3685
- return isNaN(n) ? null : n;
3686
- });
3687
- }
3688
- return [];
3689
- }
3690
- function castToStringArray2(val) {
3691
- if (val === null || val === void 0) {
3692
- return [];
3693
- }
3694
- if (Array.isArray(val)) {
3695
- return val.map((v) => String(v));
3696
- }
3697
- if (typeof val === "string") {
3698
- return pgArrayParse(val);
3699
- }
3700
- return [];
3701
- }
3702
- function castToBooleanArray2(val) {
3703
- if (val === null || val === void 0) {
3704
- return [];
3705
- }
3706
- if (Array.isArray(val)) {
3707
- return val.map((v) => castToBoolean2(v));
3708
- }
3709
- if (typeof val === "string") {
3710
- return pgArrayParse(val).map((v) => castToBoolean2(v));
3711
- }
3712
- return [];
3713
- }
3714
- function castToDatetimeArray2(val) {
3715
- if (val === null || val === void 0) {
3716
- return [];
3717
- }
3718
- if (Array.isArray(val)) {
3719
- return val.map((v) => castToDatetime2(v));
3720
- }
3721
- if (typeof val === "string") {
3722
- return pgArrayParse(val).map((v) => castToDatetime2(v));
3723
- }
3724
- return [];
3725
- }
3726
- function castToJson2(val) {
3727
- if (val === null || val === void 0) {
3728
- return null;
3729
- }
3730
- if (typeof val === "object") {
3731
- return val;
3732
- }
3733
- if (typeof val === "string") {
3734
- try {
3735
- return JSON.parse(val);
3736
- } catch {
3737
- return null;
3738
- }
3739
- }
3740
- return null;
3741
- }
3742
- function pgArrayParse(literal) {
3743
- if (!literal || literal === "{}") {
3744
- return [];
3745
- }
3746
- let content = literal.trim();
3747
- if (content.startsWith("{") && content.endsWith("}")) {
3748
- content = content.slice(1, -1);
3749
- }
3750
- if (content === "") {
3751
- return [];
3752
- }
3753
- const result = [];
3754
- let current = "";
3755
- let inQuotes = false;
3756
- let escaped = false;
3757
- for (let i = 0; i < content.length; i++) {
3758
- const char = content[i];
3759
- if (escaped) {
3760
- current += char;
3761
- escaped = false;
3762
- continue;
3763
- }
3764
- if (char === "\\") {
3765
- escaped = true;
3766
- continue;
3767
- }
3768
- if (char === '"') {
3769
- inQuotes = !inQuotes;
3770
- continue;
3771
- }
3772
- if (char === "," && !inQuotes) {
3773
- result.push(current);
3774
- current = "";
3775
- continue;
3776
- }
3777
- current += char;
3778
- }
3779
- if (current !== "" || result.length > 0) {
3780
- result.push(current);
3781
- }
3782
- return result;
3783
- }
3784
- function formatSqlCast(placeholder, sqlCast) {
3785
- return `${placeholder}::${sqlCast}`;
3786
- }
3787
-
3788
- // src/drivers/SqliteHelper.ts
3789
- function castToDatetime3(val) {
3790
- if (val === null || val === void 0) {
3791
- return null;
3792
- }
3793
- if (val instanceof Date) {
3794
- return val;
3795
- }
3796
- if (typeof val === "string" || typeof val === "number") {
3797
- const date = new Date(val);
3798
- return isNaN(date.getTime()) ? null : date;
3799
- }
3800
- return null;
3801
- }
3802
- function castToBoolean3(val) {
3803
- if (val === null || val === void 0) {
3804
- return null;
3805
- }
3806
- if (typeof val === "boolean") {
3807
- return val;
3808
- }
3809
- if (typeof val === "number") {
3810
- return val !== 0;
3811
- }
3812
- if (typeof val === "string") {
3813
- const lower = val.toLowerCase();
3814
- if (lower === "true" || lower === "1") {
3815
- return true;
3816
- }
3817
- if (lower === "false" || lower === "0") {
3818
- return false;
3819
- }
3820
- }
3821
- return null;
3822
- }
3823
- function castToIntegerArray3(val) {
3824
- if (val === null || val === void 0) {
3825
- return [];
3826
- }
3827
- if (Array.isArray(val)) {
3828
- return val.map((v) => {
3829
- const n = parseInt(String(v), 10);
3830
- return isNaN(n) ? 0 : n;
3831
- });
3832
- }
3833
- if (typeof val === "string") {
3834
- try {
3835
- const parsed = JSON.parse(val);
3836
- if (Array.isArray(parsed)) {
3837
- return parsed.map((v) => {
3838
- const n = parseInt(String(v), 10);
3839
- return isNaN(n) ? 0 : n;
3840
- });
3841
- }
3842
- } catch {
3843
- }
3844
- }
3845
- return [];
3846
- }
3847
- function castToStringArray3(val) {
3848
- if (val === null || val === void 0) {
3849
- return [];
3850
- }
3851
- if (Array.isArray(val)) {
3852
- return val.map((v) => String(v));
3853
- }
3854
- if (typeof val === "string") {
3855
- try {
3856
- const parsed = JSON.parse(val);
3857
- if (Array.isArray(parsed)) {
3858
- return parsed.map((v) => String(v));
3859
- }
3860
- } catch {
3861
- }
3862
- }
3863
- return [];
3864
- }
3865
- function castToJson3(val) {
3866
- if (val === null || val === void 0) {
3867
- return null;
3868
- }
3869
- if (typeof val === "object") {
3870
- return val;
3871
- }
3872
- if (typeof val === "string") {
3873
- try {
3874
- return JSON.parse(val);
3875
- } catch {
3876
- return null;
3877
- }
3878
- }
3879
- return null;
3880
- }
3881
- function formatSqlCast2(placeholder, _sqlCast) {
3882
- return placeholder;
3883
- }
3884
-
3885
- // src/drivers/MysqlHelper.ts
3886
- function castToDatetime4(val) {
3887
- if (val === null || val === void 0) {
3888
- return null;
3889
- }
3890
- if (val instanceof Date) {
3891
- return val;
3892
- }
3893
- if (typeof val === "string" || typeof val === "number") {
3894
- const date = new Date(val);
3895
- return isNaN(date.getTime()) ? null : date;
3896
- }
3897
- return null;
3898
- }
3899
- function castToBoolean4(val) {
3900
- if (val === null || val === void 0) {
3901
- return null;
3902
- }
3903
- if (typeof val === "boolean") {
3904
- return val;
3905
- }
3906
- if (typeof val === "number") {
3907
- return val !== 0;
3908
- }
3909
- if (typeof val === "string") {
3910
- const lower = val.toLowerCase();
3911
- if (lower === "true" || lower === "1") {
3912
- return true;
3913
- }
3914
- if (lower === "false" || lower === "0") {
3915
- return false;
3916
- }
3917
- }
3918
- if (Buffer.isBuffer(val)) {
3919
- return val[0] !== 0;
3920
- }
3921
- return null;
3922
- }
3923
- function castToIntegerArray4(val) {
3924
- if (val === null || val === void 0) {
3925
- return [];
3926
- }
3927
- if (Array.isArray(val)) {
3928
- return val.map((v) => {
3929
- const n = parseInt(String(v), 10);
3930
- return isNaN(n) ? 0 : n;
3931
- });
3932
- }
3933
- if (typeof val === "string") {
3934
- try {
3935
- const parsed = JSON.parse(val);
3936
- if (Array.isArray(parsed)) {
3937
- return parsed.map((v) => {
3938
- const n = parseInt(String(v), 10);
3939
- return isNaN(n) ? 0 : n;
3940
- });
3869
+ return {
3870
+ rows: rows2,
3871
+ rowCount: rows2.length
3872
+ };
3873
+ }
3874
+ }
3875
+ }
3876
+ const resultObj = result;
3877
+ const rowCount = resultObj.affectedRows ?? 0;
3878
+ const rows = Array.isArray(result) ? result : [];
3879
+ this.logger.debug(`Retry succeeded in ${duration}ms, affected: ${rowCount}`);
3880
+ return {
3881
+ rows,
3882
+ rowCount
3883
+ };
3884
+ } catch (retryError) {
3885
+ this.logger.error(`Retry also failed: ${sqlWithoutReturning}`, retryError);
3886
+ throw retryError;
3887
+ }
3941
3888
  }
3942
- } catch {
3889
+ this.logger.error(`Write failed: ${sqlWithoutReturning}`, error);
3890
+ throw error;
3943
3891
  }
3944
3892
  }
3945
- return [];
3946
- }
3947
- function castToStringArray4(val) {
3948
- if (val === null || val === void 0) {
3949
- return [];
3950
- }
3951
- if (Array.isArray(val)) {
3952
- return val.map((v) => String(v));
3893
+ /**
3894
+ * Get a connection for transaction (uses writer pool if available)
3895
+ */
3896
+ async getConnection() {
3897
+ const pool = this.writerPool || this.pool;
3898
+ const connection = await pool.getConnection();
3899
+ return new MysqlConnection(connection, this.logger);
3953
3900
  }
3954
- if (typeof val === "string") {
3955
- try {
3956
- const parsed = JSON.parse(val);
3957
- if (Array.isArray(parsed)) {
3958
- return parsed.map((v) => String(v));
3959
- }
3960
- } catch {
3901
+ /**
3902
+ * Close all connections
3903
+ */
3904
+ async close() {
3905
+ await closePool2(this.config);
3906
+ if (this.writerConfig) {
3907
+ await closePool2(this.writerConfig);
3961
3908
  }
3962
3909
  }
3963
- return [];
3964
- }
3965
- function castToJson4(val) {
3966
- if (val === null || val === void 0) {
3967
- return null;
3910
+ /**
3911
+ * Set logger
3912
+ */
3913
+ setLogger(logger) {
3914
+ this.logger = logger;
3968
3915
  }
3969
- if (typeof val === "object") {
3970
- return val;
3916
+ /**
3917
+ * Get the underlying pool (for advanced use)
3918
+ */
3919
+ getPool() {
3920
+ return this.pool;
3971
3921
  }
3972
- if (typeof val === "string") {
3973
- try {
3974
- return JSON.parse(val);
3975
- } catch {
3976
- return null;
3977
- }
3922
+ /**
3923
+ * Get the underlying writer pool
3924
+ */
3925
+ getWriterPool() {
3926
+ return this.writerPool;
3978
3927
  }
3979
- return null;
3980
- }
3981
- function formatSqlCast3(placeholder, _sqlCast) {
3982
- return placeholder;
3983
- }
3928
+ };
3984
3929
 
3985
3930
  // src/drivers/index.ts
3986
3931
  function getSqlBuilder(driverType) {
@@ -4003,9 +3948,9 @@ function getSqlCastFormatter(driverType) {
4003
3948
  case "postgres":
4004
3949
  return (placeholder, sqlType) => formatSqlCast(placeholder, sqlType);
4005
3950
  case "sqlite":
4006
- return (placeholder, sqlType) => formatSqlCast2(placeholder, sqlType);
4007
- case "mysql":
4008
3951
  return (placeholder, sqlType) => formatSqlCast3(placeholder, sqlType);
3952
+ case "mysql":
3953
+ return (placeholder, sqlType) => formatSqlCast2(placeholder, sqlType);
4009
3954
  default:
4010
3955
  return (placeholder) => placeholder;
4011
3956
  }
@@ -5344,7 +5289,7 @@ function orderToString(order) {
5344
5289
  }
5345
5290
  return order.toString();
5346
5291
  }
5347
- function createColumn(columnName, tableName, modelName, propertyName, sqlCast) {
5292
+ function createColumn(columnName, tableName, modelName, propertyName, sqlCast, serialize) {
5348
5293
  const fn = function() {
5349
5294
  return columnName;
5350
5295
  };
@@ -5379,6 +5324,11 @@ function createColumn(columnName, tableName, modelName, propertyName, sqlCast) {
5379
5324
  writable: false,
5380
5325
  enumerable: true
5381
5326
  });
5327
+ Object.defineProperty(fn, "serialize", {
5328
+ value: serialize,
5329
+ writable: false,
5330
+ enumerable: false
5331
+ });
5382
5332
  if (sqlCast) {
5383
5333
  fn.eq = (value) => ({ [columnName]: new DBCast(value, sqlCast, "=") });
5384
5334
  fn.ne = (value) => ({ [columnName]: new DBCast(value, sqlCast, "!=") });
@@ -5525,7 +5475,12 @@ function createOrCond(condGroups) {
5525
5475
  function isOrCond(cond) {
5526
5476
  return typeof cond === "object" && cond !== null && "_type" in cond && cond._type === "or";
5527
5477
  }
5528
- function condToKeyValue(cond) {
5478
+ function serializeCondValue(col, value, typeCast) {
5479
+ const serialize = col.serialize;
5480
+ if (serialize === void 0) return value;
5481
+ return Array.isArray(value) ? value.map((v) => serialize(v, typeCast)) : serialize(value, typeCast);
5482
+ }
5483
+ function condToKeyValue(cond, typeCast) {
5529
5484
  if (cond.length === 1) {
5530
5485
  return [cond[0], true];
5531
5486
  }
@@ -5535,7 +5490,7 @@ function condToKeyValue(cond) {
5535
5490
  }
5536
5491
  if (Array.isArray(keyOrCol)) {
5537
5492
  const columns = keyOrCol;
5538
- const tuples = value;
5493
+ const tuples = value.map((t) => t.map((v, i) => serializeCondValue(columns[i], v, typeCast)));
5539
5494
  const columnNames = columns.map((col2) => col2.columnName);
5540
5495
  return ["__tuple__", dbTupleIn(columnNames, tuples)];
5541
5496
  }
@@ -5550,13 +5505,14 @@ function condToKeyValue(cond) {
5550
5505
  if (value instanceof DBToken) {
5551
5506
  return [col.columnName, value];
5552
5507
  }
5508
+ const bound = serializeCondValue(col, value, typeCast);
5553
5509
  if (sqlCast) {
5554
- if (Array.isArray(value)) {
5555
- return [col.columnName, new DBCastArray(value, sqlCast)];
5510
+ if (Array.isArray(bound)) {
5511
+ return [col.columnName, new DBCastArray(bound, sqlCast)];
5556
5512
  }
5557
- return [col.columnName, new DBCast(value, sqlCast, "=")];
5513
+ return [col.columnName, new DBCast(bound, sqlCast, "=")];
5558
5514
  }
5559
- return [col.columnName, value];
5515
+ return [col.columnName, bound];
5560
5516
  }
5561
5517
  function sqlFragmentToKeyValue(frag) {
5562
5518
  if (frag.params.length === 0) {
@@ -5567,14 +5523,14 @@ function sqlFragmentToKeyValue(frag) {
5567
5523
  }
5568
5524
  return [frag.sql, [...frag.params]];
5569
5525
  }
5570
- function condsToRecord(conditions) {
5526
+ function condsToRecord(conditions, typeCast) {
5571
5527
  const result = {};
5572
5528
  for (const cond of conditions) {
5573
5529
  if (cond === SKIP) {
5574
5530
  continue;
5575
5531
  }
5576
5532
  if (isOrCond(cond)) {
5577
- const orGroups = cond.conditions.map((group) => condsToRecord(group));
5533
+ const orGroups = cond.conditions.map((group) => condsToRecord(group, typeCast));
5578
5534
  result["__or__"] = orGroups;
5579
5535
  } else if (isAnySqlFragment(cond)) {
5580
5536
  const kv = sqlFragmentToKeyValue(cond);
@@ -5583,7 +5539,7 @@ function condsToRecord(conditions) {
5583
5539
  result[key] = value;
5584
5540
  }
5585
5541
  } else {
5586
- const kv = condToKeyValue(cond);
5542
+ const kv = condToKeyValue(cond, typeCast);
5587
5543
  if (kv === null) continue;
5588
5544
  const [key, value] = kv;
5589
5545
  result[key] = value;
@@ -5632,12 +5588,14 @@ function resolvePgArrayCast(sql2, values) {
5632
5588
  function encodeJsonArrayParam(dialect, values) {
5633
5589
  return encodeJsonParam(dialect, values);
5634
5590
  }
5591
+ var BIGINT_SENTINEL = "\0int:";
5635
5592
  function encodeJsonParam(dialect, payload) {
5636
- return JSON.stringify(payload, (_key, v) => {
5637
- if (typeof v === "bigint") return Number(v);
5593
+ const tagged = JSON.stringify(payload, (_key, v) => {
5594
+ if (typeof v === "bigint") return `${BIGINT_SENTINEL}${v.toString()}`;
5638
5595
  if (dialect === "mysql" && typeof v === "boolean") return v ? 1 : 0;
5639
5596
  return v;
5640
5597
  });
5598
+ return tagged.replace(/"\\u0000int:(-?\d+)"/g, "$1");
5641
5599
  }
5642
5600
 
5643
5601
  // src/scp/makesql/json-batch.ts
@@ -5799,8 +5757,8 @@ function sqlTypeToMaterializeClass(sqlType) {
5799
5757
  return "passthrough";
5800
5758
  }
5801
5759
  switch (t) {
5802
- // 32-bit int family: JS number holds the full range exactly. The PostgreSQL SERIAL family maps to
5803
- // its underlying int width (SERIAL/SERIAL4=int4, SMALLSERIAL/SERIAL2=int2).
5760
+ // Integer family. The PostgreSQL SERIAL types are the same integers under an auto-increment
5761
+ // default (SERIAL/SERIAL4=int4, SMALLSERIAL/SERIAL2=int2, BIGSERIAL/SERIAL8=int8).
5804
5762
  case "INTEGER":
5805
5763
  case "INT":
5806
5764
  case "SMALLINT":
@@ -5812,13 +5770,11 @@ function sqlTypeToMaterializeClass(sqlType) {
5812
5770
  case "SERIAL4":
5813
5771
  case "SMALLSERIAL":
5814
5772
  case "SERIAL2":
5815
- return "int32";
5816
- // 64-bit int: needs JS bigint for exactness.
5817
5773
  case "BIGINT":
5818
5774
  case "INT8":
5819
5775
  case "BIGSERIAL":
5820
5776
  case "SERIAL8":
5821
- return "int64";
5777
+ return "int";
5822
5778
  case "BOOLEAN":
5823
5779
  case "BOOL":
5824
5780
  return "bool";
@@ -5853,31 +5809,33 @@ function sqlTypeToMaterializeClass(sqlType) {
5853
5809
  );
5854
5810
  }
5855
5811
  }
5812
+ var I64_MIN2 = -(2n ** 63n);
5813
+ var I64_MAX2 = 2n ** 63n - 1n;
5814
+ function checkI642(v) {
5815
+ if (v < I64_MIN2 || v > I64_MAX2) {
5816
+ throw new Error(`materialize int: ${v} is outside the i64 range behavior-contracts' \`int\` admits`);
5817
+ }
5818
+ return v;
5819
+ }
5856
5820
  function materializeCell(value, klass) {
5857
5821
  if (value === null || value === void 0) return value;
5858
5822
  switch (klass) {
5859
- case "int64": {
5860
- if (typeof value === "bigint") return value.toString();
5823
+ case "int": {
5824
+ if (typeof value === "bigint") return checkI642(value);
5861
5825
  if (typeof value === "string") {
5862
- if (!/^-?\d+$/.test(value)) throw new Error(`materialize int64: driver returned a non-integer string '${value}'`);
5863
- return value;
5826
+ if (!/^-?\d+$/.test(value)) throw new Error(`materialize int: driver returned a non-integer string '${value}'`);
5827
+ return checkI642(BigInt(value));
5864
5828
  }
5865
5829
  if (typeof value === "number") {
5866
- if (!Number.isInteger(value)) throw new Error(`materialize int64: driver returned a non-integer number ${value} for a 64-bit int column`);
5830
+ if (!Number.isInteger(value)) throw new Error(`materialize int: driver returned a non-integer number ${value} for an integer column`);
5867
5831
  if (!Number.isSafeInteger(value)) {
5868
5832
  throw new Error(
5869
- `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).`
5833
+ `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).`
5870
5834
  );
5871
5835
  }
5872
- return value.toString();
5836
+ return BigInt(value);
5873
5837
  }
5874
- throw new Error(`materialize int64: unexpected driver JS type ${typeof value}`);
5875
- }
5876
- case "int32": {
5877
- if (typeof value === "number") return value;
5878
- if (typeof value === "bigint") return Number(value);
5879
- if (typeof value === "string" && /^-?\d+$/.test(value)) return Number(value);
5880
- throw new Error(`materialize int32: unexpected driver JS type ${typeof value} (${String(value)})`);
5838
+ throw new Error(`materialize int: unexpected driver JS type ${typeof value}`);
5881
5839
  }
5882
5840
  case "date": {
5883
5841
  if (typeof value === "string") return value;
@@ -6376,133 +6334,131 @@ function compileCreateManyBundle(name, options, dialectName = "sqlite", resolveC
6376
6334
  var import_reflect_metadata = __toESM(require_Reflect());
6377
6335
  var COLUMNS_KEY = /* @__PURE__ */ Symbol("litedbmodel:columns");
6378
6336
  var RELATIONS_KEY = /* @__PURE__ */ Symbol("litedbmodel:relations");
6379
- function inferTypeCastFromDesignType(target, propertyKey) {
6380
- const designType = Reflect.getMetadata("design:type", target, propertyKey);
6381
- if (!designType) return void 0;
6382
- switch (designType) {
6383
- case Boolean:
6384
- return {
6385
- // v2 read contract: BOOLEAN → boolean, via the shared materializer.
6386
- typeCast: (v) => {
6387
- if (v === void 0) return void 0;
6388
- return materializeCell(v, "bool");
6389
- },
6390
- sqlCast: "boolean"
6391
- };
6392
- case Date:
6393
- return {
6394
- typeCast: (v) => {
6395
- if (v === void 0) return void 0;
6396
- return materializeCell(v, "date");
6397
- },
6398
- // Delegate to driver-specific serializeDatetime
6399
- serialize: (val, typeCast) => {
6400
- if (val === null || val === void 0) return null;
6401
- if (val instanceof Date) {
6402
- return typeCast?.serializeDatetime(val) ?? val;
6403
- }
6404
- return val;
6405
- },
6406
- sqlCast: "timestamp"
6407
- };
6408
- case Number:
6409
- return {
6410
- typeCast: (v) => {
6411
- if (v === void 0) return void 0;
6412
- if (v === null) return null;
6413
- const n = Number(v);
6414
- return isNaN(n) ? null : n;
6415
- }
6416
- };
6417
- case BigInt:
6418
- return {
6419
- // v2 read contract: BIGINT/INT8 → EXACT decimal STRING (no i64 rounding, JSON-safe), via the
6420
- // shared materializer. NOTE: the TS field type stays `bigint` in existing models for source
6421
- // compat, but the VALUE is now the exact string — the whole point of the #9 realignment.
6422
- typeCast: (v) => {
6423
- if (v === void 0) return void 0;
6424
- return materializeCell(v, "int64");
6425
- },
6426
- sqlCast: "bigint"
6427
- };
6428
- // Array, Object, String, and other types require explicit specification
6429
- default:
6430
- return void 0;
6337
+ if (typeof Symbol === "function" && !Symbol.metadata) {
6338
+ Object.defineProperty(Symbol, "metadata", {
6339
+ value: /* @__PURE__ */ Symbol.for("Symbol.metadata"),
6340
+ writable: false,
6341
+ enumerable: false,
6342
+ configurable: true
6343
+ });
6344
+ }
6345
+ function isStandardContext(second) {
6346
+ return typeof second === "object" && second !== null && typeof second.kind === "string";
6347
+ }
6348
+ function classMetadataBag(context, propertyKey) {
6349
+ const bag = context.metadata;
6350
+ if (bag === void 0) {
6351
+ throw new Error(
6352
+ `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.`
6353
+ );
6431
6354
  }
6355
+ return bag;
6432
6356
  }
6433
- function inferBaseSqlTypeFromDesignType(target, propertyKey) {
6434
- const designType = Reflect.getMetadata("design:type", target, propertyKey);
6435
- if (!designType) return void 0;
6436
- switch (designType) {
6437
- case String:
6438
- return "TEXT";
6439
- case Number:
6440
- return "INTEGER";
6441
- case Boolean:
6442
- return "BOOLEAN";
6443
- case Date:
6444
- return "TIMESTAMP";
6445
- case BigInt:
6446
- return "BIGINT";
6447
- default:
6448
- return void 0;
6357
+ function legacyColumnMap(constructor) {
6358
+ const own = Reflect.getOwnMetadata(COLUMNS_KEY, constructor);
6359
+ if (own !== void 0) return own;
6360
+ const inherited = Reflect.getMetadata(COLUMNS_KEY, constructor);
6361
+ const map = new Map(inherited);
6362
+ Reflect.defineMetadata(COLUMNS_KEY, map, constructor);
6363
+ return map;
6364
+ }
6365
+ function standardColumnMap(bag) {
6366
+ if (!Object.prototype.hasOwnProperty.call(bag, COLUMNS_KEY)) {
6367
+ bag[COLUMNS_KEY] = new Map(bag[COLUMNS_KEY]);
6449
6368
  }
6369
+ return bag[COLUMNS_KEY];
6450
6370
  }
6451
- function registerColumn(target, propertyKey, options) {
6452
- const constructor = target.constructor;
6453
- const columns = Reflect.getMetadata(COLUMNS_KEY, constructor) || /* @__PURE__ */ new Map();
6454
- let finalTypeCast = options.typeCast;
6455
- let finalSerialize = options.serialize;
6456
- let finalSqlCast = options.sqlCast;
6457
- if (!options.skipAutoInfer) {
6458
- const inferred = inferTypeCastFromDesignType(target, propertyKey);
6459
- if (inferred) {
6460
- if (!finalTypeCast) finalTypeCast = inferred.typeCast;
6461
- if (!finalSerialize) finalSerialize = inferred.serialize;
6462
- if (!finalSqlCast) finalSqlCast = inferred.sqlCast;
6463
- }
6371
+ function legacyRelationList(constructor) {
6372
+ const own = Reflect.getOwnMetadata(RELATIONS_KEY, constructor);
6373
+ if (own !== void 0) return own;
6374
+ const inherited = Reflect.getMetadata(RELATIONS_KEY, constructor);
6375
+ const list = inherited !== void 0 ? [...inherited] : [];
6376
+ Reflect.defineMetadata(RELATIONS_KEY, list, constructor);
6377
+ return list;
6378
+ }
6379
+ function standardRelationList(bag) {
6380
+ if (!Object.prototype.hasOwnProperty.call(bag, RELATIONS_KEY)) {
6381
+ const inherited = bag[RELATIONS_KEY];
6382
+ bag[RELATIONS_KEY] = inherited !== void 0 ? [...inherited] : [];
6464
6383
  }
6465
- const baseSqlType = inferBaseSqlTypeFromDesignType(target, propertyKey);
6384
+ return bag[RELATIONS_KEY];
6385
+ }
6386
+ function registerColumn(columns, propertyKey, options) {
6466
6387
  columns.set(propertyKey, {
6467
6388
  columnName: options.columnName,
6468
- typeCast: finalTypeCast,
6469
- serialize: finalSerialize,
6389
+ typeCast: options.typeCast,
6390
+ serialize: options.serialize,
6470
6391
  primaryKey: options.primaryKey,
6471
6392
  autoIncrement: options.autoIncrement,
6472
- sqlCast: finalSqlCast,
6473
- ...baseSqlType !== void 0 ? { baseSqlType } : {}
6393
+ sqlCast: options.sqlCast,
6394
+ ...options.baseSqlType !== void 0 ? { baseSqlType: options.baseSqlType } : {}
6474
6395
  });
6475
- Reflect.defineMetadata(COLUMNS_KEY, columns, constructor);
6476
6396
  }
6477
- function createColumnDecorator(typeCast, serialize, skipAutoInfer = false, sqlCast) {
6397
+ function parseColumnOptions(columnNameOrOptions, propKey) {
6398
+ if (typeof columnNameOrOptions === "string") return { columnName: columnNameOrOptions };
6399
+ if (columnNameOrOptions) {
6400
+ return {
6401
+ columnName: columnNameOrOptions.columnName || propKey,
6402
+ primaryKey: columnNameOrOptions.primaryKey,
6403
+ autoIncrement: columnNameOrOptions.autoIncrement
6404
+ };
6405
+ }
6406
+ return { columnName: propKey };
6407
+ }
6408
+ function rejectNonText(family, val) {
6409
+ if (val === null || val === void 0) return null;
6410
+ if (val instanceof Date) {
6411
+ throw new Error(
6412
+ `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.`
6413
+ );
6414
+ }
6415
+ if (typeof val === "object") {
6416
+ throw new Error(
6417
+ `litedbmodel: @column.${family}() received an object. Use @column.json<T>() for a JSON column, or @column.custom() with a serializer.`
6418
+ );
6419
+ }
6420
+ return val;
6421
+ }
6422
+ function materializeString(family, v) {
6423
+ if (v === void 0 || v === null) return v;
6424
+ if (typeof v === "string") return v;
6425
+ if (typeof v === "number" || typeof v === "bigint" || typeof v === "boolean") return String(v);
6426
+ throw new Error(
6427
+ `materialize ${family}: driver returned ${typeof v} for a ${family} column. Use @column.passthrough() for a BYTEA/BLOB column, or @column.json<T>() for JSON.`
6428
+ );
6429
+ }
6430
+ function createColumnDecorator(typeCast, serialize, sqlCast, baseSqlType) {
6478
6431
  return function(columnNameOrOptions) {
6479
- return function(target, propertyKey) {
6480
- const propKey = String(propertyKey);
6481
- const shouldSkipAutoInfer = skipAutoInfer || typeCast !== void 0;
6482
- let columnName;
6483
- let primaryKey;
6484
- let autoIncrement;
6485
- if (typeof columnNameOrOptions === "string") {
6486
- columnName = columnNameOrOptions;
6487
- } else if (columnNameOrOptions) {
6488
- columnName = columnNameOrOptions.columnName || propKey;
6489
- primaryKey = columnNameOrOptions.primaryKey;
6490
- autoIncrement = columnNameOrOptions.autoIncrement;
6491
- } else {
6492
- columnName = propKey;
6432
+ return function(targetOrValue, keyOrContext) {
6433
+ if (isStandardContext(keyOrContext)) {
6434
+ const propKey2 = String(keyOrContext.name);
6435
+ const parsed2 = parseColumnOptions(columnNameOrOptions, propKey2);
6436
+ registerColumn(standardColumnMap(classMetadataBag(keyOrContext, propKey2)), propKey2, {
6437
+ ...parsed2,
6438
+ typeCast,
6439
+ serialize,
6440
+ sqlCast,
6441
+ baseSqlType
6442
+ });
6443
+ return;
6493
6444
  }
6494
- registerColumn(target, propKey, {
6495
- columnName,
6445
+ const propKey = String(keyOrContext);
6446
+ const parsed = parseColumnOptions(columnNameOrOptions, propKey);
6447
+ registerColumn(legacyColumnMap(targetOrValue.constructor), propKey, {
6448
+ ...parsed,
6496
6449
  typeCast,
6497
6450
  serialize,
6498
- skipAutoInfer: shouldSkipAutoInfer,
6499
- primaryKey,
6500
- autoIncrement,
6501
- sqlCast
6451
+ sqlCast,
6452
+ baseSqlType
6502
6453
  });
6503
6454
  };
6504
6455
  };
6505
6456
  }
6457
+ function requireColumnFamily() {
6458
+ throw new Error(
6459
+ "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."
6460
+ );
6461
+ }
6506
6462
  function serializeArray(val, typeCast) {
6507
6463
  if (val === null || val === void 0) return null;
6508
6464
  if (!Array.isArray(val)) return val;
@@ -6540,19 +6496,47 @@ function serializeJson(val, typeCast) {
6540
6496
  return JSON.stringify(val);
6541
6497
  }
6542
6498
  var column = Object.assign(
6543
- // Basic @column() - no type conversion
6544
- createColumnDecorator(),
6499
+ // The bare `@column()` declared no type — it is rejected, with the migration in the message.
6500
+ (_columnNameOrOptions) => requireColumnFamily(),
6545
6501
  {
6546
6502
  // ============================================
6547
6503
  // Primitive Types
6548
6504
  // ============================================
6505
+ /**
6506
+ * Text type (TEXT / VARCHAR / CHAR / ENUM / citext) — the driver value is already a string, so no
6507
+ * cast is applied. The family still DECLARES the column so the typed read types it as `TEXT`.
6508
+ * @example @column.text() name?: string;
6509
+ * @example @column.text('user_name') name?: string;
6510
+ */
6511
+ text: (columnNameOrOptions) => createColumnDecorator(
6512
+ (v) => materializeString("text", v),
6513
+ // the family DECLARES `string`, so it hands back one
6514
+ (val) => rejectNonText("text", val),
6515
+ // …and it cannot SERIALIZE a Date or an object
6516
+ void 0,
6517
+ // no sqlCast family (a text literal needs no SQL cast)
6518
+ "TEXT"
6519
+ // §4.1 token: types the SCP typed read
6520
+ )(columnNameOrOptions),
6521
+ /**
6522
+ * Exact decimal type (NUMERIC / DECIMAL) — read back as its exact decimal STRING (a JS number
6523
+ * rounds past 2^53). The family states the column is `numeric`, so a write binds the string as a
6524
+ * numeric — a batch write (`createMany` / `updateMany`) included.
6525
+ * @example @column.decimal() price?: string;
6526
+ */
6527
+ decimal: (columnNameOrOptions) => createColumnDecorator(
6528
+ (v) => materializeString("decimal", v),
6529
+ (val) => rejectNonText("decimal", val),
6530
+ "numeric"
6531
+ // sqlCast for WHERE / INSERT / batch-write type casting
6532
+ )(columnNameOrOptions),
6549
6533
  /**
6550
6534
  * Boolean type conversion
6551
6535
  * Converts 't'/'f', 'true'/'false', 1/0 to boolean
6552
6536
  * Preserves null for nullable columns, undefined stays undefined
6553
6537
  * @example @column.boolean() is_active?: boolean;
6554
6538
  */
6555
- boolean: (columnName) => createColumnDecorator(
6539
+ boolean: (columnNameOrOptions) => createColumnDecorator(
6556
6540
  // v2 read contract: BOOLEAN → boolean, via the shared materializer (issue #9).
6557
6541
  (v) => {
6558
6542
  if (v === void 0) return void 0;
@@ -6560,42 +6544,38 @@ var column = Object.assign(
6560
6544
  },
6561
6545
  void 0,
6562
6546
  // no custom serialize
6563
- false,
6564
- // allow auto-inference
6565
6547
  "boolean"
6566
6548
  // sqlCast for updateMany type inference
6567
- )(columnName),
6549
+ )(columnNameOrOptions),
6568
6550
  /**
6569
6551
  * Number type conversion (from string)
6570
6552
  * Preserves null for nullable columns, undefined stays undefined
6571
6553
  * @example @column.number() amount?: number;
6572
6554
  */
6573
- number: (columnName) => createColumnDecorator((v) => {
6555
+ number: (columnNameOrOptions) => createColumnDecorator((v) => {
6574
6556
  if (v === void 0) return void 0;
6575
6557
  if (v === null) return null;
6576
6558
  const n = Number(v);
6577
6559
  return isNaN(n) ? null : n;
6578
- })(columnName),
6560
+ })(columnNameOrOptions),
6579
6561
  /**
6580
6562
  * BigInt type conversion
6581
6563
  * Preserves null for nullable columns, undefined stays undefined
6582
- * @example @column.bigint() large_id?: bigint;
6564
+ * @example @column.bigint() large_id?: bigint; // bc `int` — a JS bigint, checked i64
6583
6565
  */
6584
- bigint: (columnName) => createColumnDecorator(
6585
- // v2 read contract: BIGINT/INT8 → EXACT decimal STRING (no i64 rounding, JSON-safe), via the
6586
- // shared materializer (issue #9). The declared TS field type may still be `bigint` in existing
6587
- // models, but the runtime value is now the exact string — that IS the realignment.
6566
+ bigint: (columnNameOrOptions) => createColumnDecorator(
6567
+ // An integer column reads back as a JS `bigint` — behavior-contracts' `int` value model
6568
+ // (`int` = bigint, checked i64), which is what the drivers already hand over. `JSON.stringify`
6569
+ // does not serialize a bigint: give the field a `toJSON`, or convert at the boundary.
6588
6570
  (v) => {
6589
6571
  if (v === void 0) return void 0;
6590
- return materializeCell(v, "int64");
6572
+ return materializeCell(v, "int");
6591
6573
  },
6592
6574
  void 0,
6593
6575
  // no custom serialize
6594
- false,
6595
- // allow auto-inference
6596
6576
  "bigint"
6597
6577
  // sqlCast for WHERE/INSERT type casting
6598
- )(columnName),
6578
+ )(columnNameOrOptions),
6599
6579
  // ============================================
6600
6580
  // Date/Time Types
6601
6581
  // ============================================
@@ -6607,9 +6587,9 @@ var column = Object.assign(
6607
6587
  * - PostgreSQL: Serializes to ISO 8601 UTC string with 'Z' suffix for explicit timezone
6608
6588
  * - MySQL/SQLite: Passes Date object to driver (driver-dependent timezone handling)
6609
6589
  *
6610
- * @example @column.datetime() created_at?: Date;
6590
+ * @example @column.datetime() created_at?: string; // TZ-attached string, NOT a JS Date
6611
6591
  */
6612
- datetime: (columnName) => createColumnDecorator(
6592
+ datetime: (columnNameOrOptions) => createColumnDecorator(
6613
6593
  // v2 read contract: DATE/TIMESTAMP/TIMESTAMPTZ/DATETIME/TIME → TZ-attached STRING (NOT a
6614
6594
  // TZ-shifted JS Date), via the shared materializer (issue #9). A driver already returning the
6615
6595
  // native textual form passes through; a JS Date is rendered to its lossless ISO instant.
@@ -6625,11 +6605,9 @@ var column = Object.assign(
6625
6605
  }
6626
6606
  return val;
6627
6607
  },
6628
- false,
6629
- // allow auto-inference
6630
6608
  "timestamp"
6631
6609
  // sqlCast for updateMany type inference
6632
- )(columnName),
6610
+ )(columnNameOrOptions),
6633
6611
  /**
6634
6612
  * Date type conversion — returns YYYY-MM-DD string.
6635
6613
  * Preserves null for nullable columns, undefined stays undefined.
@@ -6637,9 +6615,9 @@ var column = Object.assign(
6637
6615
  * DB values (Date object or string) are normalized to 'YYYY-MM-DD' string.
6638
6616
  * On write, string values are passed through; Date objects are formatted as 'YYYY-MM-DD'.
6639
6617
  *
6640
- * @example @column.date() birth_date?: string;
6618
+ * @example @column.date() birth_date?: string; // 'YYYY-MM-DD'
6641
6619
  */
6642
- date: (columnName) => createColumnDecorator(
6620
+ date: (columnNameOrOptions) => createColumnDecorator(
6643
6621
  (v) => {
6644
6622
  if (v === void 0) return void 0;
6645
6623
  if (v === null) return null;
@@ -6664,11 +6642,9 @@ var column = Object.assign(
6664
6642
  }
6665
6643
  return val;
6666
6644
  },
6667
- false,
6668
- // allow auto-inference
6669
6645
  "date"
6670
6646
  // sqlCast for updateMany type inference
6671
- )(columnName),
6647
+ )(columnNameOrOptions),
6672
6648
  // ============================================
6673
6649
  // Array Types
6674
6650
  // ============================================
@@ -6677,71 +6653,71 @@ var column = Object.assign(
6677
6653
  * Preserves null for nullable columns, undefined stays undefined
6678
6654
  * @example @column.stringArray() tags?: string[];
6679
6655
  */
6680
- stringArray: (columnName) => createColumnDecorator(
6656
+ stringArray: (columnNameOrOptions) => createColumnDecorator(
6681
6657
  (v) => {
6682
6658
  if (v === void 0) return void 0;
6683
6659
  if (v === null) return null;
6684
- return castToStringArray(v);
6660
+ return castToStringArray2(v);
6685
6661
  },
6686
6662
  serializeArray,
6687
- false,
6688
6663
  "text[]"
6689
- )(columnName),
6664
+ )(columnNameOrOptions),
6690
6665
  /**
6691
6666
  * Integer array type conversion (integer[])
6692
6667
  * Preserves null for nullable columns, undefined stays undefined
6693
6668
  * @example @column.intArray() scores?: number[];
6694
6669
  */
6695
- intArray: (columnName) => createColumnDecorator(
6670
+ intArray: (columnNameOrOptions) => createColumnDecorator(
6696
6671
  (v) => {
6697
6672
  if (v === void 0) return void 0;
6698
6673
  if (v === null) return null;
6699
- return castToIntegerArray(v);
6674
+ return castToIntegerArray2(v);
6700
6675
  },
6701
6676
  serializeArray,
6702
- false,
6703
6677
  "int[]"
6704
- )(columnName),
6678
+ )(columnNameOrOptions),
6705
6679
  /**
6706
6680
  * Numeric array type conversion (numeric[], allows null elements)
6707
6681
  * Preserves null for nullable columns, undefined stays undefined
6708
6682
  * @example @column.numericArray() values?: (number | null)[];
6709
6683
  */
6710
- numericArray: (columnName) => createColumnDecorator(
6684
+ numericArray: (columnNameOrOptions) => createColumnDecorator(
6711
6685
  (v) => {
6712
6686
  if (v === void 0) return void 0;
6713
6687
  if (v === null) return null;
6714
- return castToNumericArray(v);
6688
+ return castToNumericArray2(v);
6715
6689
  },
6716
6690
  serializeArray,
6717
- false,
6718
6691
  "numeric[]"
6719
- )(columnName),
6692
+ )(columnNameOrOptions),
6720
6693
  /**
6721
6694
  * Boolean array type conversion (boolean[])
6722
6695
  * Preserves null for nullable columns, undefined stays undefined
6723
6696
  * @example @column.booleanArray() flags?: (boolean | null)[];
6724
6697
  */
6725
- booleanArray: (columnName) => createColumnDecorator(
6698
+ booleanArray: (columnNameOrOptions) => createColumnDecorator(
6726
6699
  (v) => {
6727
6700
  if (v === void 0) return void 0;
6728
6701
  if (v === null) return null;
6729
- return castToBooleanArray(v);
6702
+ return castToBooleanArray2(v);
6730
6703
  },
6731
6704
  serializeBooleanArray,
6732
- false,
6733
6705
  "boolean[]"
6734
- )(columnName),
6706
+ )(columnNameOrOptions),
6735
6707
  /**
6736
6708
  * DateTime array type conversion (timestamp[])
6737
6709
  * Preserves null for nullable columns, undefined stays undefined
6738
- * @example @column.datetimeArray() event_dates?: (Date | null)[];
6710
+ * @example @column.datetimeArray() event_dates?: (string | null)[];
6739
6711
  */
6740
- datetimeArray: (columnName) => createColumnDecorator(
6712
+ datetimeArray: (columnNameOrOptions) => createColumnDecorator(
6713
+ // Element-wise the SAME contract as `@column.datetime()`: a TZ-attached STRING, never a
6714
+ // TZ-shifted JS Date. The array family used to be the one place a `Date` still came back, so
6715
+ // `JSON.stringify` of a row silently re-rendered those elements in UTC — the exact hazard #9
6716
+ // closed for the scalar.
6741
6717
  (v) => {
6742
6718
  if (v === void 0) return void 0;
6743
6719
  if (v === null) return null;
6744
- return castToDatetimeArray(v);
6720
+ return castToDatetimeArray2(v).map((d) => d === null ? null : materializeCell(d, "date"));
6745
6721
  },
6746
6722
  // DateTime arrays serialize each Date to ISO string
6747
6723
  (val) => {
@@ -6750,7 +6726,7 @@ var column = Object.assign(
6750
6726
  const mapped = val.map((v) => v === null ? "NULL" : v instanceof Date ? v.toISOString() : String(v));
6751
6727
  return `{${mapped.join(",")}}`;
6752
6728
  }
6753
- )(columnName),
6729
+ )(columnNameOrOptions),
6754
6730
  // ============================================
6755
6731
  // JSON Types
6756
6732
  // ============================================
@@ -6760,16 +6736,15 @@ var column = Object.assign(
6760
6736
  * @example @column.json() metadata?: Record<string, unknown>;
6761
6737
  * @example @column.json<UserSettings>() settings?: UserSettings;
6762
6738
  */
6763
- json: (columnName) => createColumnDecorator(
6739
+ json: (columnNameOrOptions) => createColumnDecorator(
6764
6740
  (v) => {
6765
6741
  if (v === void 0) return void 0;
6766
6742
  if (v === null) return null;
6767
- return castToJson(v);
6743
+ return castToJson2(v);
6768
6744
  },
6769
6745
  serializeJson,
6770
- false,
6771
6746
  "jsonb"
6772
- )(columnName),
6747
+ )(columnNameOrOptions),
6773
6748
  // ============================================
6774
6749
  // UUID Type (PostgreSQL)
6775
6750
  // ============================================
@@ -6798,61 +6773,101 @@ var column = Object.assign(
6798
6773
  if (v === null) return null;
6799
6774
  return String(v);
6800
6775
  },
6801
- void 0,
6802
- // No serialization needed - handled by sqlCast
6803
- true,
6804
- // Skip auto-inference
6776
+ (val) => rejectNonText("uuid", val),
6777
+ // the ::uuid cast handles the rest
6805
6778
  "uuid"
6806
6779
  // SQL type for casting
6807
6780
  )(columnNameOrOptions),
6808
6781
  // ============================================
6809
6782
  // Custom Type Conversion
6810
6783
  // ============================================
6784
+ /**
6785
+ * The driver's value, UNCAST — for a column whose type the library has no cast for (`BYTEA` /
6786
+ * `BLOB` arrives as a driver Buffer, a vendor type as whatever the driver decodes). It states
6787
+ * "this column is passed through", which is a DECLARATION; the removed bare `@column()` was the
6788
+ * absence of one, and produced this same passthrough by accident for every unresolvable type.
6789
+ * @example @column.passthrough() payload?: unknown;
6790
+ */
6791
+ passthrough: (columnNameOrOptions) => createColumnDecorator()(columnNameOrOptions),
6811
6792
  /**
6812
6793
  * Custom type conversion with user-provided function
6813
6794
  * @example @column.custom((v) => String(v).toUpperCase()) status?: string;
6814
6795
  * @example @column.custom((v) => v, (v) => JSON.stringify(v)) data?: MyType; // with serializer
6815
6796
  */
6816
- custom: (castFn, serializeFn, columnName) => createColumnDecorator(castFn, serializeFn)(columnName)
6797
+ custom: (castFn, serializeFn, columnNameOrOptions) => createColumnDecorator(castFn, serializeFn)(columnNameOrOptions)
6817
6798
  }
6818
6799
  );
6819
- function registerRelation(target, propertyKey, type, keysFactory, options) {
6820
- const constructor = target.constructor;
6821
- const relations = Reflect.getMetadata(RELATIONS_KEY, constructor) || [];
6822
- relations.push({
6823
- propertyKey,
6824
- type,
6825
- keysFactory,
6826
- options
6827
- });
6828
- Reflect.defineMetadata(RELATIONS_KEY, relations, constructor);
6800
+ function registerRelation(relations, propertyKey, type, keysFactory, options) {
6801
+ relations.push({ propertyKey, type, keysFactory, options });
6802
+ }
6803
+ function createRelationDecorator(type, keys, options) {
6804
+ return function(targetOrValue, keyOrContext) {
6805
+ if (isStandardContext(keyOrContext)) {
6806
+ const propKey2 = String(keyOrContext.name);
6807
+ registerRelation(standardRelationList(classMetadataBag(keyOrContext, propKey2)), propKey2, type, keys, options);
6808
+ if (typeof keyOrContext.addInitializer !== "function") {
6809
+ throw new Error(
6810
+ `litedbmodel: the standard-decorator context for relation '${propKey2}' has no \`addInitializer\`, so the class field cannot be removed and would shadow the relation getter.`
6811
+ );
6812
+ }
6813
+ keyOrContext.addInitializer(function() {
6814
+ if (Object.prototype.hasOwnProperty.call(this, propKey2)) {
6815
+ delete this[propKey2];
6816
+ }
6817
+ });
6818
+ return;
6819
+ }
6820
+ const propKey = String(keyOrContext);
6821
+ registerRelation(legacyRelationList(targetOrValue.constructor), propKey, type, keys, options);
6822
+ };
6829
6823
  }
6830
6824
  function hasMany(keys, options) {
6831
- return function(target, propertyKey) {
6832
- registerRelation(target, String(propertyKey), "hasMany", keys, options);
6833
- };
6825
+ return createRelationDecorator("hasMany", keys, options);
6834
6826
  }
6835
6827
  function belongsTo(keys, options) {
6836
- return function(target, propertyKey) {
6837
- registerRelation(target, String(propertyKey), "belongsTo", keys, options);
6838
- };
6828
+ return createRelationDecorator("belongsTo", keys, options);
6839
6829
  }
6840
6830
  function hasOne(keys, options) {
6841
- return function(target, propertyKey) {
6842
- registerRelation(target, String(propertyKey), "hasOne", keys, options);
6843
- };
6831
+ return createRelationDecorator("hasOne", keys, options);
6844
6832
  }
6845
6833
  function getRelationMeta(modelClass) {
6846
6834
  return modelClass._relationMeta || Reflect.getMetadata(RELATIONS_KEY, modelClass) || [];
6847
6835
  }
6848
- function model(tableNameOrConstructor, options) {
6836
+ function model(tableNameOrConstructor, optionsOrContext) {
6849
6837
  if (typeof tableNameOrConstructor === "string") {
6850
6838
  const tableName = tableNameOrConstructor;
6851
- return function(constructor) {
6852
- return applyModelDecorator(constructor, tableName, options);
6839
+ const options = optionsOrContext;
6840
+ return function(constructor, context) {
6841
+ return applyToClass(constructor, context, tableName, options);
6842
+ };
6843
+ }
6844
+ return applyToClass(tableNameOrConstructor, optionsOrContext);
6845
+ }
6846
+ function applyToClass(constructor, context, tableName, options) {
6847
+ const members = modelMembers(constructor, context);
6848
+ if (!isStandardContext(context)) return applyModelDecorator(constructor, members, tableName, options);
6849
+ if (typeof context.addInitializer !== "function") {
6850
+ throw new Error(
6851
+ `litedbmodel: the standard-decorator context for '${constructor.name}' has no \`addInitializer\`, so \`@model\` cannot assemble the model after the class is defined.`
6852
+ );
6853
+ }
6854
+ context.addInitializer(function() {
6855
+ applyModelDecorator(this, members, tableName, options);
6856
+ });
6857
+ return constructor;
6858
+ }
6859
+ function modelMembers(constructor, context) {
6860
+ if (isStandardContext(context)) {
6861
+ const bag = classMetadataBag(context, String(constructor.name ?? "model"));
6862
+ return {
6863
+ columns: bag[COLUMNS_KEY] ?? /* @__PURE__ */ new Map(),
6864
+ relations: bag[RELATIONS_KEY] ?? []
6853
6865
  };
6854
6866
  }
6855
- return applyModelDecorator(tableNameOrConstructor);
6867
+ return {
6868
+ columns: Reflect.getMetadata(COLUMNS_KEY, constructor) ?? /* @__PURE__ */ new Map(),
6869
+ relations: Reflect.getMetadata(RELATIONS_KEY, constructor) ?? []
6870
+ };
6856
6871
  }
6857
6872
  function isCompositeKeys(keys) {
6858
6873
  return Array.isArray(keys[0]);
@@ -6872,9 +6887,8 @@ function parseKeys(keys) {
6872
6887
  };
6873
6888
  }
6874
6889
  }
6875
- function applyModelDecorator(constructor, tableName, options) {
6876
- const columns = Reflect.getMetadata(COLUMNS_KEY, constructor) || /* @__PURE__ */ new Map();
6877
- const relations = Reflect.getMetadata(RELATIONS_KEY, constructor) || [];
6890
+ function applyModelDecorator(constructor, members, tableName, options) {
6891
+ const { columns, relations } = members;
6878
6892
  const modelName = constructor.name;
6879
6893
  if (tableName) {
6880
6894
  Object.defineProperty(constructor, "TABLE_NAME", {
@@ -6937,7 +6951,7 @@ function applyModelDecorator(constructor, tableName, options) {
6937
6951
  const effectiveTableName = tableName ?? modelName.toLowerCase();
6938
6952
  for (const [propKey, meta] of columns) {
6939
6953
  Object.defineProperty(constructor, propKey, {
6940
- value: createColumn(meta.columnName, effectiveTableName, modelName, propKey, meta.sqlCast),
6954
+ value: createColumn(meta.columnName, effectiveTableName, modelName, propKey, meta.sqlCast, meta.serialize),
6941
6955
  writable: false,
6942
6956
  enumerable: true,
6943
6957
  configurable: false
@@ -6981,17 +6995,36 @@ function applyModelDecorator(constructor, tableName, options) {
6981
6995
  const keys = keysFactory();
6982
6996
  const { sourceKeys, targetKeys, targetModelName } = parseKeys(keys);
6983
6997
  const order = options2?.order ? orderToString(options2.order()) : null;
6984
- const conditions = options2?.where ? condsToRecord(options2.where()) : void 0;
6985
6998
  return this._loadRelation(type, targetModelName, {
6986
6999
  sourceKeys,
6987
7000
  targetKeys,
6988
7001
  order,
6989
- conditions,
7002
+ where: options2?.where?.(),
6990
7003
  limit: options2?.limit,
6991
7004
  hardLimit: options2?.hardLimit,
6992
7005
  relationName: propertyKey
6993
7006
  });
6994
7007
  },
7008
+ /**
7009
+ * A relation is a getter, but a class FIELD declaring it still writes to the property. Which
7010
+ * write it is depends on `useDefineForClassFields`: with define semantics (the default from
7011
+ * target ES2022) the field is `defineProperty`-d onto the instance, bypassing this setter — the
7012
+ * standard protocol's initializer removes that shadowing property. With SET semantics (the
7013
+ * default below ES2022) the field ASSIGNS, and an accessor with no setter throws
7014
+ * `Cannot set property … which has only a getter` on EVERY instantiation.
7015
+ *
7016
+ * So: the field's own `undefined` is ignored, and any other value is honoured as an own
7017
+ * property — priming a relation (a loaded graph, a test double) reads back what was set.
7018
+ */
7019
+ set: function(value) {
7020
+ if (value === void 0) return;
7021
+ Object.defineProperty(this, propertyKey, {
7022
+ value,
7023
+ writable: true,
7024
+ enumerable: true,
7025
+ configurable: true
7026
+ });
7027
+ },
6995
7028
  enumerable: true,
6996
7029
  configurable: false
6997
7030
  });
@@ -7109,6 +7142,7 @@ function serializeRecord(modelClass, record, typeCast) {
7109
7142
  // src/scp/decorator-adapter.ts
7110
7143
  var COLUMN_FAMILY_SQL_TYPE = {
7111
7144
  boolean: "BOOLEAN",
7145
+ numeric: "NUMERIC",
7112
7146
  bigint: "BIGINT",
7113
7147
  timestamp: "TIMESTAMP",
7114
7148
  date: "DATE",
@@ -7261,23 +7295,6 @@ function createDriver(config, options) {
7261
7295
  }
7262
7296
  function getTypeCastForDriver(driverType) {
7263
7297
  if (driverType === "sqlite") {
7264
- return {
7265
- castToDatetime: castToDatetime3,
7266
- castToBoolean: castToBoolean3,
7267
- castToIntegerArray: castToIntegerArray3,
7268
- castToNumericArray: (val) => castToIntegerArray3(val).map((v) => v),
7269
- castToStringArray: castToStringArray3,
7270
- castToBooleanArray: (val) => {
7271
- const arr = castToStringArray3(val);
7272
- return arr.map((v) => castToBoolean3(v));
7273
- },
7274
- castToDatetimeArray: (val) => {
7275
- const arr = castToStringArray3(val);
7276
- return arr.map((v) => castToDatetime3(v));
7277
- },
7278
- castToJson: castToJson3
7279
- };
7280
- } else if (driverType === "mysql") {
7281
7298
  return {
7282
7299
  castToDatetime: castToDatetime4,
7283
7300
  castToBoolean: castToBoolean4,
@@ -7294,16 +7311,33 @@ function getTypeCastForDriver(driverType) {
7294
7311
  },
7295
7312
  castToJson: castToJson4
7296
7313
  };
7314
+ } else if (driverType === "mysql") {
7315
+ return {
7316
+ castToDatetime: castToDatetime3,
7317
+ castToBoolean: castToBoolean3,
7318
+ castToIntegerArray: castToIntegerArray3,
7319
+ castToNumericArray: (val) => castToIntegerArray3(val).map((v) => v),
7320
+ castToStringArray: castToStringArray3,
7321
+ castToBooleanArray: (val) => {
7322
+ const arr = castToStringArray3(val);
7323
+ return arr.map((v) => castToBoolean3(v));
7324
+ },
7325
+ castToDatetimeArray: (val) => {
7326
+ const arr = castToStringArray3(val);
7327
+ return arr.map((v) => castToDatetime3(v));
7328
+ },
7329
+ castToJson: castToJson3
7330
+ };
7297
7331
  } else {
7298
7332
  return {
7299
- castToDatetime: castToDatetime2,
7300
- castToBoolean: castToBoolean2,
7301
- castToIntegerArray: castToIntegerArray2,
7302
- castToNumericArray: castToNumericArray2,
7303
- castToStringArray: castToStringArray2,
7304
- castToBooleanArray: castToBooleanArray2,
7305
- castToDatetimeArray: castToDatetimeArray2,
7306
- castToJson: castToJson2
7333
+ castToDatetime,
7334
+ castToBoolean,
7335
+ castToIntegerArray,
7336
+ castToNumericArray,
7337
+ castToStringArray,
7338
+ castToBooleanArray,
7339
+ castToDatetimeArray,
7340
+ castToJson
7307
7341
  };
7308
7342
  }
7309
7343
  }
@@ -8054,8 +8088,8 @@ var DBModel = class _DBModel {
8054
8088
  * ```typescript
8055
8089
  * @model('users')
8056
8090
  * class UserModel extends DBModel {
8057
- * @column() id?: number;
8058
- * @column() name?: string;
8091
+ * @column.number() id?: number;
8092
+ * @column.text() name?: string;
8059
8093
  * }
8060
8094
  * export const User = UserModel.asModel();
8061
8095
  * export type User = UserModel;
@@ -8187,15 +8221,14 @@ var DBModel = class _DBModel {
8187
8221
  static _scpColumnTypesCache = /* @__PURE__ */ new WeakMap();
8188
8222
  /**
8189
8223
  * The §4.1 column-type OVERRIDES for the SCP read/write bundle (the F1 `columnTypes` escape hatch).
8190
- * Phase F-2 (#105): a column whose SQL type cannot be derived from the decorator — no explicit
8191
- * `sqlCast` family AND no `baseSqlType` (its TS `design:type` is `Object`, e.g. a NULLABLE
8192
- * `string | null` / `number | null` field: TS emits `design:type = Object` for a union) — would
8193
- * otherwise take the blanket-INTEGER default and THROW `materialize int32` on a live string. Because
8224
+ * A column whose SQL type cannot be derived from its family — `@column.number()`, whose JS `number`
8225
+ * backs an INTEGER just as well as a REAL/DECIMAL (pg returns DECIMAL as a string that an `int32`
8226
+ * materialize REJECTS) — would otherwise take the blanket-INTEGER default and THROW. Because
8194
8227
  * the DBModel read path does its OWN v1 de-box (`_createInstance` → `typeCastFromDB`), the SCP typed
8195
8228
  * read only needs a NON-THROWING, passthrough-safe SQL type for such columns: we pin them to `TEXT`
8196
8229
  * (passthrough — the driver value flows through unchanged, then v1 casts it). Columns WITH a derivable
8197
- * type (explicit family / a non-union `design:type`) keep it. This preserves the v1 read contract
8198
- * exactly (int→number, string→string) while never throwing on an undeterminable nullable column.
8230
+ * type (every family but `@column.number()`) keep it. This preserves the v1 read contract exactly
8231
+ * (int→number, string→string) while never throwing on a column whose width the model did not state.
8199
8232
  * @internal
8200
8233
  */
8201
8234
  static _scpColumnTypes() {
@@ -8207,7 +8240,7 @@ var DBModel = class _DBModel {
8207
8240
  for (const [propKey, m] of meta) {
8208
8241
  const baseSqlType = m.baseSqlType;
8209
8242
  if (m.sqlCast !== void 0) continue;
8210
- if (baseSqlType !== void 0 && baseSqlType !== "INTEGER") continue;
8243
+ if (baseSqlType !== void 0) continue;
8211
8244
  columnTypes[propKey] = "TEXT";
8212
8245
  }
8213
8246
  }
@@ -8316,6 +8349,30 @@ var DBModel = class _DBModel {
8316
8349
  return void 0;
8317
8350
  }
8318
8351
  }
8352
+ /**
8353
+ * A subquery's `[column, value]` conditions, each literal value bound the way the column's family
8354
+ * writes it (see {@link _getConditionTypeCast}); a correlation reference passes through.
8355
+ * @internal
8356
+ */
8357
+ static _subqueryConditions(conditions) {
8358
+ const typeCast = this._getConditionTypeCast();
8359
+ return conditions.map(([col, value]) => ({
8360
+ column: col,
8361
+ value: value instanceof DBToken ? value : serializeCondValue(col, value, typeCast)
8362
+ }));
8363
+ }
8364
+ /**
8365
+ * The driver's type cast a condition value binds with — the one a create / update serializes with.
8366
+ * Returns undefined if DBHandler is not initialized, like {@link _getSqlCastFormatter}.
8367
+ * @internal
8368
+ */
8369
+ static _getConditionTypeCast() {
8370
+ try {
8371
+ return getTypeCast2(this.getDriverType());
8372
+ } catch {
8373
+ return void 0;
8374
+ }
8375
+ }
8319
8376
  /**
8320
8377
  * Get a DBHandler instance for this model.
8321
8378
  * Connection priority:
@@ -8550,7 +8607,7 @@ var DBModel = class _DBModel {
8550
8607
  }
8551
8608
  const normalizedCond = normalizeConditions(conditions);
8552
8609
  if (this.FIND_FILTER) {
8553
- const filterCondition = condsToRecord(this.FIND_FILTER);
8610
+ const filterCondition = condsToRecord(this.FIND_FILTER, this._getConditionTypeCast());
8554
8611
  normalizedCond.add(filterCondition);
8555
8612
  }
8556
8613
  const formatter = this._getSqlCastFormatter();
@@ -8669,7 +8726,7 @@ var DBModel = class _DBModel {
8669
8726
  /** Merge FIND_FILTER (the model's default filter) into a condition object (v1 `_buildSelectSQL` parity). */
8670
8727
  static _mergeFindFilter(conditions) {
8671
8728
  if (!this.FIND_FILTER) return conditions;
8672
- const filter = condsToRecord(this.FIND_FILTER);
8729
+ const filter = condsToRecord(this.FIND_FILTER, this._getConditionTypeCast());
8673
8730
  return { ...conditions, ...filter };
8674
8731
  }
8675
8732
  /** Build model instances from raw rows, wiring the deferred relation context (v1 `query` parity). @internal */
@@ -8738,7 +8795,7 @@ var DBModel = class _DBModel {
8738
8795
  }
8739
8796
  const normalizedCond = normalizeConditions(conditions);
8740
8797
  if (this.FIND_FILTER) {
8741
- const filterCondition = condsToRecord(this.FIND_FILTER);
8798
+ const filterCondition = condsToRecord(this.FIND_FILTER, this._getConditionTypeCast());
8742
8799
  normalizedCond.add(filterCondition);
8743
8800
  }
8744
8801
  const formatter = this._getSqlCastFormatter();
@@ -9071,10 +9128,7 @@ var DBModel = class _DBModel {
9071
9128
  const parentColumns = pairs.map((pair) => pair[0]);
9072
9129
  const selectColumns = pairs.map((pair) => pair[1]);
9073
9130
  const targetTableName = selectColumns[0]?.tableName ?? "";
9074
- const subqueryConditions = conditions.map(([col, value]) => ({
9075
- column: col,
9076
- value
9077
- }));
9131
+ const subqueryConditions = this._subqueryConditions(conditions);
9078
9132
  return ["__subquery__", new DBSubquery(parentColumns, targetTableName, selectColumns, subqueryConditions, "IN")];
9079
9133
  }
9080
9134
  /**
@@ -9110,10 +9164,7 @@ var DBModel = class _DBModel {
9110
9164
  const parentColumns = pairs.map((pair) => pair[0]);
9111
9165
  const selectColumns = pairs.map((pair) => pair[1]);
9112
9166
  const targetTableName = selectColumns[0]?.tableName ?? "";
9113
- const subqueryConditions = conditions.map(([col, value]) => ({
9114
- column: col,
9115
- value
9116
- }));
9167
+ const subqueryConditions = this._subqueryConditions(conditions);
9117
9168
  return ["__subquery__", new DBSubquery(parentColumns, targetTableName, selectColumns, subqueryConditions, "NOT IN")];
9118
9169
  }
9119
9170
  /**
@@ -9141,10 +9192,7 @@ var DBModel = class _DBModel {
9141
9192
  */
9142
9193
  static exists(conditions) {
9143
9194
  const targetTableName = conditions[0]?.[0]?.tableName ?? "";
9144
- const subqueryConditions = conditions.map(([col, value]) => ({
9145
- column: col,
9146
- value
9147
- }));
9195
+ const subqueryConditions = this._subqueryConditions(conditions);
9148
9196
  return ["__exists__", new DBExists(targetTableName, subqueryConditions, false)];
9149
9197
  }
9150
9198
  /**
@@ -9171,10 +9219,7 @@ var DBModel = class _DBModel {
9171
9219
  */
9172
9220
  static notExists(conditions) {
9173
9221
  const targetTableName = conditions[0]?.[0]?.tableName ?? "";
9174
- const subqueryConditions = conditions.map(([col, value]) => ({
9175
- column: col,
9176
- value
9177
- }));
9222
+ const subqueryConditions = this._subqueryConditions(conditions);
9178
9223
  return ["__exists__", new DBExists(targetTableName, subqueryConditions, true)];
9179
9224
  }
9180
9225
  // ============================================
@@ -9425,7 +9470,7 @@ var DBModel = class _DBModel {
9425
9470
  }
9426
9471
  const relationConfig = {
9427
9472
  targetClass: TargetClass,
9428
- conditions: config.conditions,
9473
+ conditions: config.where ? condsToRecord(config.where, TargetClass._getConditionTypeCast()) : void 0,
9429
9474
  order: config.order,
9430
9475
  limit: config.limit,
9431
9476
  hardLimit: config.hardLimit,
@@ -9722,7 +9767,7 @@ var DBModel = class _DBModel {
9722
9767
  */
9723
9768
  static find(conditions, options) {
9724
9769
  const core = async (conds, opts) => {
9725
- const conditionRecord = condsToRecord(conds);
9770
+ const conditionRecord = condsToRecord(conds, this._getConditionTypeCast());
9726
9771
  const hardLimit = _DBModel._limitConfig.findHardLimit;
9727
9772
  const shouldCheckLimit = hardLimit != null && !opts?.limit;
9728
9773
  const effectiveOpts = shouldCheckLimit ? { ...opts, limit: hardLimit + 1 } : opts;
@@ -9756,7 +9801,7 @@ var DBModel = class _DBModel {
9756
9801
  */
9757
9802
  static findOne(conditions, options) {
9758
9803
  const core = async (conds, opts) => {
9759
- const conditionRecord = condsToRecord(conds);
9804
+ const conditionRecord = condsToRecord(conds, this._getConditionTypeCast());
9760
9805
  const results = await this._select(conditionRecord, { ...opts, limit: 1 });
9761
9806
  return results.length > 0 ? results[0] : null;
9762
9807
  };
@@ -9834,7 +9879,7 @@ var DBModel = class _DBModel {
9834
9879
  */
9835
9880
  static count(conditions) {
9836
9881
  const core = async (conds) => {
9837
- const conditionRecord = condsToRecord(conds);
9882
+ const conditionRecord = condsToRecord(conds, this._getConditionTypeCast());
9838
9883
  return this._count(conditionRecord);
9839
9884
  };
9840
9885
  return this._applyMiddleware("count", core, [conditions]);
@@ -9968,7 +10013,7 @@ var DBModel = class _DBModel {
9968
10013
  */
9969
10014
  static update(conditions, values, options) {
9970
10015
  const core = async (conds, vals, opts) => {
9971
- const conditionRecord = condsToRecord(conds);
10016
+ const conditionRecord = condsToRecord(conds, this._getConditionTypeCast());
9972
10017
  const valueRecord = pairsToRecord(vals);
9973
10018
  if (!opts?.returning) {
9974
10019
  await this._update(conditionRecord, valueRecord, {});
@@ -10020,7 +10065,7 @@ var DBModel = class _DBModel {
10020
10065
  */
10021
10066
  static delete(conditions, options) {
10022
10067
  const core = async (conds, opts) => {
10023
- const conditionRecord = condsToRecord(conds);
10068
+ const conditionRecord = condsToRecord(conds, this._getConditionTypeCast());
10024
10069
  if (!opts?.returning) {
10025
10070
  await this._delete(conditionRecord, {});
10026
10071
  return null;
@@ -10426,12 +10471,12 @@ var DBModel = class _DBModel {
10426
10471
  * // Define models using appropriate base class
10427
10472
  * @model('users')
10428
10473
  * class UserModel extends BaseDB {
10429
- * @column() id?: number;
10474
+ * @column.number() id?: number;
10430
10475
  * }
10431
10476
  *
10432
10477
  * @model('articles')
10433
10478
  * class ArticleModel extends CmsDB {
10434
- * @column() id?: number;
10479
+ * @column.number() id?: number;
10435
10480
  * }
10436
10481
  *
10437
10482
  * // Each base class has independent transactions