relq 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +862 -0
  3. package/dist/addons/buffer.js +1869 -0
  4. package/dist/addons/pg-cursor.js +1425 -0
  5. package/dist/addons/pg-format.js +2248 -0
  6. package/dist/addons/pg.js +4790 -0
  7. package/dist/bin/relq.js +2 -0
  8. package/dist/cjs/cache/index.cjs +9 -0
  9. package/dist/cjs/cache/query-cache.cjs +311 -0
  10. package/dist/cjs/cli/commands/add.cjs +82 -0
  11. package/dist/cjs/cli/commands/commit.cjs +145 -0
  12. package/dist/cjs/cli/commands/diff.cjs +84 -0
  13. package/dist/cjs/cli/commands/export.cjs +333 -0
  14. package/dist/cjs/cli/commands/fetch.cjs +59 -0
  15. package/dist/cjs/cli/commands/generate.cjs +242 -0
  16. package/dist/cjs/cli/commands/history.cjs +165 -0
  17. package/dist/cjs/cli/commands/import.cjs +524 -0
  18. package/dist/cjs/cli/commands/init.cjs +437 -0
  19. package/dist/cjs/cli/commands/introspect.cjs +142 -0
  20. package/dist/cjs/cli/commands/log.cjs +62 -0
  21. package/dist/cjs/cli/commands/migrate.cjs +167 -0
  22. package/dist/cjs/cli/commands/pull.cjs +410 -0
  23. package/dist/cjs/cli/commands/push.cjs +165 -0
  24. package/dist/cjs/cli/commands/rollback.cjs +169 -0
  25. package/dist/cjs/cli/commands/status.cjs +110 -0
  26. package/dist/cjs/cli/commands/sync.cjs +79 -0
  27. package/dist/cjs/cli/index.cjs +275 -0
  28. package/dist/cjs/cli/utils/change-tracker.cjs +446 -0
  29. package/dist/cjs/cli/utils/commit-manager.cjs +239 -0
  30. package/dist/cjs/cli/utils/config-loader.cjs +127 -0
  31. package/dist/cjs/cli/utils/env-loader.cjs +62 -0
  32. package/dist/cjs/cli/utils/fast-introspect.cjs +398 -0
  33. package/dist/cjs/cli/utils/git-utils.cjs +404 -0
  34. package/dist/cjs/cli/utils/migration-generator.cjs +269 -0
  35. package/dist/cjs/cli/utils/relqignore.cjs +114 -0
  36. package/dist/cjs/cli/utils/repo-manager.cjs +515 -0
  37. package/dist/cjs/cli/utils/schema-comparator.cjs +313 -0
  38. package/dist/cjs/cli/utils/schema-diff.cjs +284 -0
  39. package/dist/cjs/cli/utils/schema-hash.cjs +108 -0
  40. package/dist/cjs/cli/utils/schema-introspect.cjs +455 -0
  41. package/dist/cjs/cli/utils/snapshot-manager.cjs +223 -0
  42. package/dist/cjs/cli/utils/spinner.cjs +108 -0
  43. package/dist/cjs/cli/utils/sql-generator.cjs +520 -0
  44. package/dist/cjs/cli/utils/sql-parser.cjs +999 -0
  45. package/dist/cjs/cli/utils/type-generator.cjs +2061 -0
  46. package/dist/cjs/condition/array-condition-builder.cjs +503 -0
  47. package/dist/cjs/condition/array-numeric-condition-builder.cjs +186 -0
  48. package/dist/cjs/condition/array-specialized-condition-builder.cjs +206 -0
  49. package/dist/cjs/condition/array-string-condition-builder.cjs +146 -0
  50. package/dist/cjs/condition/base-condition-builder.cjs +2 -0
  51. package/dist/cjs/condition/condition-collector.cjs +284 -0
  52. package/dist/cjs/condition/fulltext-condition-builder.cjs +61 -0
  53. package/dist/cjs/condition/geometric-condition-builder.cjs +208 -0
  54. package/dist/cjs/condition/index.cjs +25 -0
  55. package/dist/cjs/condition/jsonb-condition-builder.cjs +160 -0
  56. package/dist/cjs/condition/network-condition-builder.cjs +230 -0
  57. package/dist/cjs/condition/range-condition-builder.cjs +82 -0
  58. package/dist/cjs/config/config.cjs +190 -0
  59. package/dist/cjs/config/index.cjs +9 -0
  60. package/dist/cjs/constants/pg-values.cjs +68 -0
  61. package/dist/cjs/copy/copy-builder.cjs +316 -0
  62. package/dist/cjs/copy/index.cjs +6 -0
  63. package/dist/cjs/core/query-builder.cjs +440 -0
  64. package/dist/cjs/core/relq-client.cjs +1831 -0
  65. package/dist/cjs/core/typed-kuery-client.cjs +2 -0
  66. package/dist/cjs/count/count-builder.cjs +88 -0
  67. package/dist/cjs/count/index.cjs +5 -0
  68. package/dist/cjs/cte/cte-builder.cjs +89 -0
  69. package/dist/cjs/cte/index.cjs +5 -0
  70. package/dist/cjs/ddl/function.cjs +48 -0
  71. package/dist/cjs/ddl/index.cjs +7 -0
  72. package/dist/cjs/ddl/sql.cjs +54 -0
  73. package/dist/cjs/delete/delete-builder.cjs +135 -0
  74. package/dist/cjs/delete/index.cjs +5 -0
  75. package/dist/cjs/errors/relq-errors.cjs +329 -0
  76. package/dist/cjs/examples/fulltext-search-test.cjs +122 -0
  77. package/dist/cjs/explain/explain-builder.cjs +99 -0
  78. package/dist/cjs/explain/index.cjs +5 -0
  79. package/dist/cjs/function/create-function-builder.cjs +196 -0
  80. package/dist/cjs/function/index.cjs +6 -0
  81. package/dist/cjs/functions/advanced-functions.cjs +241 -0
  82. package/dist/cjs/functions/case-builder.cjs +66 -0
  83. package/dist/cjs/functions/geometric-functions.cjs +104 -0
  84. package/dist/cjs/functions/index.cjs +184 -0
  85. package/dist/cjs/functions/network-functions.cjs +86 -0
  86. package/dist/cjs/functions/sql-functions.cjs +431 -0
  87. package/dist/cjs/index.cjs +164 -0
  88. package/dist/cjs/indexing/create-index-builder.cjs +187 -0
  89. package/dist/cjs/indexing/drop-index-builder.cjs +89 -0
  90. package/dist/cjs/indexing/index-types.cjs +2 -0
  91. package/dist/cjs/indexing/index.cjs +8 -0
  92. package/dist/cjs/insert/conflict-builder.cjs +173 -0
  93. package/dist/cjs/insert/index.cjs +5 -0
  94. package/dist/cjs/insert/insert-builder.cjs +254 -0
  95. package/dist/cjs/introspect/index.cjs +229 -0
  96. package/dist/cjs/maintenance/index.cjs +6 -0
  97. package/dist/cjs/maintenance/vacuum-builder.cjs +166 -0
  98. package/dist/cjs/pubsub/index.cjs +7 -0
  99. package/dist/cjs/pubsub/listen-notify-builder.cjs +57 -0
  100. package/dist/cjs/pubsub/listener-connection.cjs +180 -0
  101. package/dist/cjs/raw/index.cjs +5 -0
  102. package/dist/cjs/raw/raw-query-builder.cjs +27 -0
  103. package/dist/cjs/schema/index.cjs +15 -0
  104. package/dist/cjs/schema/schema-builder.cjs +1167 -0
  105. package/dist/cjs/schema-builder.cjs +21 -0
  106. package/dist/cjs/schema-definition/column-types.cjs +829 -0
  107. package/dist/cjs/schema-definition/index.cjs +62 -0
  108. package/dist/cjs/schema-definition/introspection.cjs +620 -0
  109. package/dist/cjs/schema-definition/partitions.cjs +129 -0
  110. package/dist/cjs/schema-definition/pg-enum.cjs +76 -0
  111. package/dist/cjs/schema-definition/pg-function.cjs +91 -0
  112. package/dist/cjs/schema-definition/pg-sequence.cjs +56 -0
  113. package/dist/cjs/schema-definition/pg-trigger.cjs +108 -0
  114. package/dist/cjs/schema-definition/relations.cjs +98 -0
  115. package/dist/cjs/schema-definition/sql-expressions.cjs +202 -0
  116. package/dist/cjs/schema-definition/table-definition.cjs +636 -0
  117. package/dist/cjs/select/aggregate-builder.cjs +179 -0
  118. package/dist/cjs/select/index.cjs +5 -0
  119. package/dist/cjs/select/select-builder.cjs +233 -0
  120. package/dist/cjs/sequence/index.cjs +7 -0
  121. package/dist/cjs/sequence/sequence-builder.cjs +264 -0
  122. package/dist/cjs/table/alter-table-builder.cjs +146 -0
  123. package/dist/cjs/table/constraint-builder.cjs +102 -0
  124. package/dist/cjs/table/create-table-builder.cjs +248 -0
  125. package/dist/cjs/table/index.cjs +17 -0
  126. package/dist/cjs/table/partition-builder.cjs +131 -0
  127. package/dist/cjs/table/truncate-builder.cjs +70 -0
  128. package/dist/cjs/transaction/index.cjs +6 -0
  129. package/dist/cjs/transaction/transaction-builder.cjs +78 -0
  130. package/dist/cjs/trigger/create-trigger-builder.cjs +174 -0
  131. package/dist/cjs/trigger/index.cjs +6 -0
  132. package/dist/cjs/types/aggregate-types.cjs +2 -0
  133. package/dist/cjs/types/config-types.cjs +40 -0
  134. package/dist/cjs/types/inference-types.cjs +18 -0
  135. package/dist/cjs/types/pagination-types.cjs +7 -0
  136. package/dist/cjs/types/result-types.cjs +2 -0
  137. package/dist/cjs/types/schema-types.cjs +2 -0
  138. package/dist/cjs/types/subscription-types.cjs +2 -0
  139. package/dist/cjs/types.cjs +2 -0
  140. package/dist/cjs/update/array-update-builder.cjs +205 -0
  141. package/dist/cjs/update/index.cjs +13 -0
  142. package/dist/cjs/update/update-builder.cjs +195 -0
  143. package/dist/cjs/utils/case-converter.cjs +58 -0
  144. package/dist/cjs/utils/environment-detection.cjs +120 -0
  145. package/dist/cjs/utils/index.cjs +10 -0
  146. package/dist/cjs/utils/pool-defaults.cjs +106 -0
  147. package/dist/cjs/utils/type-coercion.cjs +118 -0
  148. package/dist/cjs/view/create-view-builder.cjs +180 -0
  149. package/dist/cjs/view/index.cjs +7 -0
  150. package/dist/cjs/window/index.cjs +5 -0
  151. package/dist/cjs/window/window-builder.cjs +80 -0
  152. package/dist/config.cjs +1 -0
  153. package/dist/config.d.ts +655 -0
  154. package/dist/config.js +1 -0
  155. package/dist/esm/cache/index.js +1 -0
  156. package/dist/esm/cache/query-cache.js +303 -0
  157. package/dist/esm/cli/commands/add.js +78 -0
  158. package/dist/esm/cli/commands/commit.js +109 -0
  159. package/dist/esm/cli/commands/diff.js +81 -0
  160. package/dist/esm/cli/commands/export.js +297 -0
  161. package/dist/esm/cli/commands/fetch.js +56 -0
  162. package/dist/esm/cli/commands/generate.js +206 -0
  163. package/dist/esm/cli/commands/history.js +129 -0
  164. package/dist/esm/cli/commands/import.js +488 -0
  165. package/dist/esm/cli/commands/init.js +401 -0
  166. package/dist/esm/cli/commands/introspect.js +106 -0
  167. package/dist/esm/cli/commands/log.js +59 -0
  168. package/dist/esm/cli/commands/migrate.js +131 -0
  169. package/dist/esm/cli/commands/pull.js +374 -0
  170. package/dist/esm/cli/commands/push.js +129 -0
  171. package/dist/esm/cli/commands/rollback.js +133 -0
  172. package/dist/esm/cli/commands/status.js +107 -0
  173. package/dist/esm/cli/commands/sync.js +76 -0
  174. package/dist/esm/cli/index.js +240 -0
  175. package/dist/esm/cli/utils/change-tracker.js +405 -0
  176. package/dist/esm/cli/utils/commit-manager.js +191 -0
  177. package/dist/esm/cli/utils/config-loader.js +86 -0
  178. package/dist/esm/cli/utils/env-loader.js +57 -0
  179. package/dist/esm/cli/utils/fast-introspect.js +362 -0
  180. package/dist/esm/cli/utils/git-utils.js +347 -0
  181. package/dist/esm/cli/utils/migration-generator.js +263 -0
  182. package/dist/esm/cli/utils/relqignore.js +74 -0
  183. package/dist/esm/cli/utils/repo-manager.js +444 -0
  184. package/dist/esm/cli/utils/schema-comparator.js +307 -0
  185. package/dist/esm/cli/utils/schema-diff.js +276 -0
  186. package/dist/esm/cli/utils/schema-hash.js +69 -0
  187. package/dist/esm/cli/utils/schema-introspect.js +418 -0
  188. package/dist/esm/cli/utils/snapshot-manager.js +179 -0
  189. package/dist/esm/cli/utils/spinner.js +101 -0
  190. package/dist/esm/cli/utils/sql-generator.js +504 -0
  191. package/dist/esm/cli/utils/sql-parser.js +992 -0
  192. package/dist/esm/cli/utils/type-generator.js +2058 -0
  193. package/dist/esm/condition/array-condition-builder.js +495 -0
  194. package/dist/esm/condition/array-numeric-condition-builder.js +182 -0
  195. package/dist/esm/condition/array-specialized-condition-builder.js +200 -0
  196. package/dist/esm/condition/array-string-condition-builder.js +142 -0
  197. package/dist/esm/condition/base-condition-builder.js +1 -0
  198. package/dist/esm/condition/condition-collector.js +275 -0
  199. package/dist/esm/condition/fulltext-condition-builder.js +53 -0
  200. package/dist/esm/condition/geometric-condition-builder.js +200 -0
  201. package/dist/esm/condition/index.js +7 -0
  202. package/dist/esm/condition/jsonb-condition-builder.js +152 -0
  203. package/dist/esm/condition/network-condition-builder.js +222 -0
  204. package/dist/esm/condition/range-condition-builder.js +74 -0
  205. package/dist/esm/config/config.js +150 -0
  206. package/dist/esm/config/index.js +1 -0
  207. package/dist/esm/constants/pg-values.js +63 -0
  208. package/dist/esm/copy/copy-builder.js +308 -0
  209. package/dist/esm/copy/index.js +1 -0
  210. package/dist/esm/core/query-builder.js +426 -0
  211. package/dist/esm/core/relq-client.js +1791 -0
  212. package/dist/esm/core/typed-kuery-client.js +1 -0
  213. package/dist/esm/count/count-builder.js +81 -0
  214. package/dist/esm/count/index.js +1 -0
  215. package/dist/esm/cte/cte-builder.js +82 -0
  216. package/dist/esm/cte/index.js +1 -0
  217. package/dist/esm/ddl/function.js +45 -0
  218. package/dist/esm/ddl/index.js +2 -0
  219. package/dist/esm/ddl/sql.js +51 -0
  220. package/dist/esm/delete/delete-builder.js +128 -0
  221. package/dist/esm/delete/index.js +1 -0
  222. package/dist/esm/errors/relq-errors.js +310 -0
  223. package/dist/esm/examples/fulltext-search-test.js +117 -0
  224. package/dist/esm/explain/explain-builder.js +95 -0
  225. package/dist/esm/explain/index.js +1 -0
  226. package/dist/esm/function/create-function-builder.js +188 -0
  227. package/dist/esm/function/index.js +1 -0
  228. package/dist/esm/functions/advanced-functions.js +231 -0
  229. package/dist/esm/functions/case-builder.js +58 -0
  230. package/dist/esm/functions/geometric-functions.js +97 -0
  231. package/dist/esm/functions/index.js +171 -0
  232. package/dist/esm/functions/network-functions.js +79 -0
  233. package/dist/esm/functions/sql-functions.js +421 -0
  234. package/dist/esm/index.js +34 -0
  235. package/dist/esm/indexing/create-index-builder.js +180 -0
  236. package/dist/esm/indexing/drop-index-builder.js +81 -0
  237. package/dist/esm/indexing/index-types.js +1 -0
  238. package/dist/esm/indexing/index.js +2 -0
  239. package/dist/esm/insert/conflict-builder.js +162 -0
  240. package/dist/esm/insert/index.js +1 -0
  241. package/dist/esm/insert/insert-builder.js +247 -0
  242. package/dist/esm/introspect/index.js +224 -0
  243. package/dist/esm/maintenance/index.js +1 -0
  244. package/dist/esm/maintenance/vacuum-builder.js +158 -0
  245. package/dist/esm/pubsub/index.js +1 -0
  246. package/dist/esm/pubsub/listen-notify-builder.js +48 -0
  247. package/dist/esm/pubsub/listener-connection.js +173 -0
  248. package/dist/esm/raw/index.js +1 -0
  249. package/dist/esm/raw/raw-query-builder.js +20 -0
  250. package/dist/esm/schema/index.js +1 -0
  251. package/dist/esm/schema/schema-builder.js +1150 -0
  252. package/dist/esm/schema-builder.js +2 -0
  253. package/dist/esm/schema-definition/column-types.js +738 -0
  254. package/dist/esm/schema-definition/index.js +10 -0
  255. package/dist/esm/schema-definition/introspection.js +614 -0
  256. package/dist/esm/schema-definition/partitions.js +123 -0
  257. package/dist/esm/schema-definition/pg-enum.js +70 -0
  258. package/dist/esm/schema-definition/pg-function.js +85 -0
  259. package/dist/esm/schema-definition/pg-sequence.js +50 -0
  260. package/dist/esm/schema-definition/pg-trigger.js +102 -0
  261. package/dist/esm/schema-definition/relations.js +90 -0
  262. package/dist/esm/schema-definition/sql-expressions.js +193 -0
  263. package/dist/esm/schema-definition/table-definition.js +630 -0
  264. package/dist/esm/select/aggregate-builder.js +172 -0
  265. package/dist/esm/select/index.js +1 -0
  266. package/dist/esm/select/select-builder.js +226 -0
  267. package/dist/esm/sequence/index.js +1 -0
  268. package/dist/esm/sequence/sequence-builder.js +255 -0
  269. package/dist/esm/table/alter-table-builder.js +138 -0
  270. package/dist/esm/table/constraint-builder.js +95 -0
  271. package/dist/esm/table/create-table-builder.js +241 -0
  272. package/dist/esm/table/index.js +5 -0
  273. package/dist/esm/table/partition-builder.js +121 -0
  274. package/dist/esm/table/truncate-builder.js +63 -0
  275. package/dist/esm/transaction/index.js +1 -0
  276. package/dist/esm/transaction/transaction-builder.js +70 -0
  277. package/dist/esm/trigger/create-trigger-builder.js +166 -0
  278. package/dist/esm/trigger/index.js +1 -0
  279. package/dist/esm/types/aggregate-types.js +1 -0
  280. package/dist/esm/types/config-types.js +36 -0
  281. package/dist/esm/types/inference-types.js +12 -0
  282. package/dist/esm/types/pagination-types.js +4 -0
  283. package/dist/esm/types/result-types.js +1 -0
  284. package/dist/esm/types/schema-types.js +1 -0
  285. package/dist/esm/types/subscription-types.js +1 -0
  286. package/dist/esm/types.js +1 -0
  287. package/dist/esm/update/array-update-builder.js +192 -0
  288. package/dist/esm/update/index.js +2 -0
  289. package/dist/esm/update/update-builder.js +188 -0
  290. package/dist/esm/utils/case-converter.js +55 -0
  291. package/dist/esm/utils/environment-detection.js +113 -0
  292. package/dist/esm/utils/index.js +2 -0
  293. package/dist/esm/utils/pool-defaults.js +100 -0
  294. package/dist/esm/utils/type-coercion.js +110 -0
  295. package/dist/esm/view/create-view-builder.js +171 -0
  296. package/dist/esm/view/index.js +1 -0
  297. package/dist/esm/window/index.js +1 -0
  298. package/dist/esm/window/window-builder.js +73 -0
  299. package/dist/index.cjs +1 -0
  300. package/dist/index.d.ts +10341 -0
  301. package/dist/index.js +1 -0
  302. package/dist/schema-builder.cjs +1 -0
  303. package/dist/schema-builder.d.ts +2272 -0
  304. package/dist/schema-builder.js +1 -0
  305. package/package.json +55 -0
@@ -0,0 +1,2058 @@
1
+ const EXCLUDED_TABLES = ['_relq_migrations', 'relq_migrations'];
2
+ const EXCLUDED_FUNCTIONS = [
3
+ 'armor', 'dearmor', 'crypt', 'decrypt', 'encrypt', 'digest', 'hmac',
4
+ 'gen_salt', 'gen_random_bytes', 'gen_random_uuid', 'pgp_', 'decrypt_iv',
5
+ 'encrypt_iv'
6
+ ];
7
+ function toCamelCase(str) {
8
+ const cleaned = str.replace(/^[_0-9]+/, '');
9
+ return cleaned
10
+ .split('_')
11
+ .map((word, i) => i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
12
+ .join('');
13
+ }
14
+ function toPascalCase(str) {
15
+ const cleaned = str.replace(/^[_0-9]+/, '');
16
+ return cleaned
17
+ .split('_')
18
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
19
+ .join('');
20
+ }
21
+ function inferTsTypeFromSqlType(sqlType) {
22
+ const normalized = sqlType.toLowerCase().replace(/\([^)]*\)/g, '').trim();
23
+ if (['integer', 'int', 'int4', 'smallint', 'int2', 'bigint', 'int8',
24
+ 'numeric', 'decimal', 'real', 'float4', 'float8', 'double precision',
25
+ 'float', 'money'].includes(normalized)) {
26
+ return 'number';
27
+ }
28
+ if (['boolean', 'bool'].includes(normalized)) {
29
+ return 'boolean';
30
+ }
31
+ if (['timestamp', 'timestamptz', 'date', 'time', 'timetz'].includes(normalized)) {
32
+ return 'Date';
33
+ }
34
+ if (['inet', 'cidr', 'macaddr', 'macaddr8'].includes(normalized)) {
35
+ return 'string';
36
+ }
37
+ if (normalized === 'uuid') {
38
+ return 'string';
39
+ }
40
+ return 'string';
41
+ }
42
+ function generateColumnBuilderFromType(sqlType) {
43
+ const normalized = sqlType.toLowerCase().trim();
44
+ const paramMatch = normalized.match(/^([a-z_][a-z0-9_\s]*?)(?:\s*\(([^)]+)\))?$/i);
45
+ if (!paramMatch)
46
+ return `text()`;
47
+ const baseType = paramMatch[1].trim();
48
+ const params = paramMatch[2];
49
+ if (['integer', 'int', 'int4'].includes(baseType)) {
50
+ return 'integer()';
51
+ }
52
+ if (['smallint', 'int2'].includes(baseType)) {
53
+ return 'smallint()';
54
+ }
55
+ if (['bigint', 'int8'].includes(baseType)) {
56
+ return 'bigint()';
57
+ }
58
+ if (baseType === 'numeric' || baseType === 'decimal') {
59
+ if (params) {
60
+ const [precision, scale] = params.split(',').map(s => s.trim());
61
+ if (scale) {
62
+ return `numeric().precision(${precision}).scale(${scale})`;
63
+ }
64
+ return `numeric().precision(${precision})`;
65
+ }
66
+ return 'numeric()';
67
+ }
68
+ if (['real', 'float4'].includes(baseType)) {
69
+ return 'real()';
70
+ }
71
+ if (['float8', 'double precision'].includes(baseType)) {
72
+ return 'doublePrecision()';
73
+ }
74
+ if (baseType === 'text') {
75
+ return 'text()';
76
+ }
77
+ if (baseType === 'varchar' || baseType === 'character varying') {
78
+ if (params) {
79
+ return `varchar().length(${params})`;
80
+ }
81
+ return 'varchar()';
82
+ }
83
+ if (baseType === 'char' || baseType === 'character' || baseType === 'bpchar') {
84
+ if (params) {
85
+ return `char().length(${params})`;
86
+ }
87
+ return 'char()';
88
+ }
89
+ if (baseType === 'citext') {
90
+ return 'citext()';
91
+ }
92
+ if (baseType === 'boolean' || baseType === 'bool') {
93
+ return 'boolean()';
94
+ }
95
+ if (baseType === 'uuid') {
96
+ return 'uuid()';
97
+ }
98
+ if (baseType === 'inet') {
99
+ return 'inet()';
100
+ }
101
+ if (baseType === 'timestamp' || baseType === 'timestamptz') {
102
+ return 'timestamp().withTimezone()';
103
+ }
104
+ if (baseType === 'date') {
105
+ return 'date()';
106
+ }
107
+ if (baseType === 'time' || baseType === 'timetz') {
108
+ return 'time()';
109
+ }
110
+ if (baseType === 'jsonb') {
111
+ return 'jsonb()';
112
+ }
113
+ if (baseType === 'json') {
114
+ return 'json()';
115
+ }
116
+ if (baseType === 'bytea') {
117
+ return 'bytea()';
118
+ }
119
+ return 'text()';
120
+ }
121
+ function convertSqlCheckToTypedExpr(check) {
122
+ const trimmed = check.trim();
123
+ const betweenExact = trimmed.match(/^VALUE\s+BETWEEN\s+(\S+)\s+AND\s+(\S+)$/i);
124
+ if (betweenExact) {
125
+ return `value.between('${betweenExact[1]}', '${betweenExact[2]}')`;
126
+ }
127
+ if (/\sAND\s/i.test(trimmed) && !/\bBETWEEN\b/i.test(trimmed)) {
128
+ const parts = splitCheckByAnd(trimmed);
129
+ if (parts.length > 1) {
130
+ const parsedParts = parts.map(p => convertSqlCheckToTypedExpr(p.trim()));
131
+ return parsedParts.reduce((acc, part, idx) => {
132
+ if (idx === 0)
133
+ return part;
134
+ return `${acc}.and(${part})`;
135
+ });
136
+ }
137
+ }
138
+ const regexMatch = trimmed.match(/^VALUE\s+~\*\s+'([^']+)'$/i);
139
+ if (regexMatch) {
140
+ const regex = regexMatch[1].replace(/\\/g, '\\\\').replace(/'/g, "\\'");
141
+ return `value.matches('${regex}')`;
142
+ }
143
+ const csRegexMatch = trimmed.match(/^VALUE\s+~\s+'([^']+)'$/i);
144
+ if (csRegexMatch) {
145
+ const regex = csRegexMatch[1].replace(/\\/g, '\\\\').replace(/'/g, "\\'");
146
+ return `value.matchesCaseSensitive('${regex}')`;
147
+ }
148
+ const gtMatch = trimmed.match(/^VALUE\s*>\s*([^\s]+)$/i);
149
+ if (gtMatch) {
150
+ return `value.gt('${gtMatch[1]}')`;
151
+ }
152
+ const gteMatch = trimmed.match(/^VALUE\s*>=\s*([^\s]+)$/i);
153
+ if (gteMatch) {
154
+ return `value.gte('${gteMatch[1]}')`;
155
+ }
156
+ const ltMatch = trimmed.match(/^VALUE\s*<\s*([^\s]+)$/i);
157
+ if (ltMatch) {
158
+ return `value.lt('${ltMatch[1]}')`;
159
+ }
160
+ const lteMatch = trimmed.match(/^VALUE\s*<=\s*([^\s]+)$/i);
161
+ if (lteMatch) {
162
+ return `value.lte('${lteMatch[1]}')`;
163
+ }
164
+ const eqMatch = trimmed.match(/^VALUE\s*=\s*(.+)$/i);
165
+ if (eqMatch) {
166
+ const val = eqMatch[1].trim();
167
+ if (val.startsWith("'") && val.endsWith("'")) {
168
+ return `value.eq(${val})`;
169
+ }
170
+ return `value.eq('${val}')`;
171
+ }
172
+ const lengthLte = trimmed.match(/^LENGTH\s*\(\s*VALUE\s*\)\s*<=\s*(\d+)$/i);
173
+ if (lengthLte) {
174
+ return `value.lengthLte(${lengthLte[1]})`;
175
+ }
176
+ const lengthGte = trimmed.match(/^LENGTH\s*\(\s*VALUE\s*\)\s*>=\s*(\d+)$/i);
177
+ if (lengthGte) {
178
+ return `value.lengthGte(${lengthGte[1]})`;
179
+ }
180
+ const lengthLt = trimmed.match(/^LENGTH\s*\(\s*VALUE\s*\)\s*<\s*(\d+)$/i);
181
+ if (lengthLt) {
182
+ return `value.lengthLt(${lengthLt[1]})`;
183
+ }
184
+ const lengthGt = trimmed.match(/^LENGTH\s*\(\s*VALUE\s*\)\s*>\s*(\d+)$/i);
185
+ if (lengthGt) {
186
+ return `value.lengthGt(${lengthGt[1]})`;
187
+ }
188
+ const lengthEq = trimmed.match(/^LENGTH\s*\(\s*VALUE\s*\)\s*=\s*(\d+)$/i);
189
+ if (lengthEq) {
190
+ return `value.lengthEq(${lengthEq[1]})`;
191
+ }
192
+ const notLike = trimmed.match(/^VALUE\s+NOT\s+LIKE\s+'([^']+)'$/i);
193
+ if (notLike) {
194
+ return `value.notLike('${notLike[1].replace(/'/g, "\\'")}')`;
195
+ }
196
+ const like = trimmed.match(/^VALUE\s+LIKE\s+'([^']+)'$/i);
197
+ if (like) {
198
+ return `value.like('${like[1].replace(/'/g, "\\'")}')`;
199
+ }
200
+ const inMatch = trimmed.match(/^VALUE\s+IN\s*\(([^)]+)\)$/i);
201
+ if (inMatch) {
202
+ return `value.in([${inMatch[1]}])`;
203
+ }
204
+ const notInMatch = trimmed.match(/^VALUE\s+NOT\s+IN\s*\(([^)]+)\)$/i);
205
+ if (notInMatch) {
206
+ return `value.notIn([${notInMatch[1]}])`;
207
+ }
208
+ const escapedCheck = check.replace(/'/g, "\\'");
209
+ return `value.matches('${escapedCheck}')`;
210
+ }
211
+ function splitCheckByAnd(expr) {
212
+ const parts = [];
213
+ let current = '';
214
+ let depth = 0;
215
+ let inQuote = false;
216
+ let quoteChar = '';
217
+ let i = 0;
218
+ while (i < expr.length) {
219
+ const char = expr[i];
220
+ if (!inQuote) {
221
+ if (char === "'" || char === '"') {
222
+ inQuote = true;
223
+ quoteChar = char;
224
+ current += char;
225
+ }
226
+ else if (char === '(' || char === '[') {
227
+ depth++;
228
+ current += char;
229
+ }
230
+ else if (char === ')' || char === ']') {
231
+ depth--;
232
+ current += char;
233
+ }
234
+ else if (depth === 0 && expr.substring(i).toUpperCase().startsWith(' AND ')) {
235
+ if (current.trim()) {
236
+ parts.push(current.trim());
237
+ }
238
+ current = '';
239
+ i += 5;
240
+ continue;
241
+ }
242
+ else {
243
+ current += char;
244
+ }
245
+ }
246
+ else {
247
+ current += char;
248
+ if (char === quoteChar && expr[i - 1] !== '\\') {
249
+ inQuote = false;
250
+ }
251
+ }
252
+ i++;
253
+ }
254
+ if (current.trim()) {
255
+ parts.push(current.trim());
256
+ }
257
+ return parts;
258
+ }
259
+ function getColumnType(col, enumNames, domainNames, compositeNames) {
260
+ let pgType = col.dataType.toLowerCase();
261
+ const isArray = pgType.startsWith('_') || pgType.endsWith('[]');
262
+ if (pgType.startsWith('_')) {
263
+ pgType = pgType.slice(1);
264
+ }
265
+ if (pgType.endsWith('[]')) {
266
+ pgType = pgType.slice(0, -2);
267
+ }
268
+ const paramMatch = pgType.match(/^([a-z_]+)(?:\(([^)]+)\))?$/);
269
+ const baseType = paramMatch ? paramMatch[1] : pgType;
270
+ const paramsStr = paramMatch ? paramMatch[2] : null;
271
+ if (enumNames && enumNames.has(baseType)) {
272
+ const enumVarName = toCamelCase(baseType) + 'Enum';
273
+ let typeFunc = `${enumVarName}()`;
274
+ if (isArray) {
275
+ typeFunc += '.array()';
276
+ }
277
+ return typeFunc;
278
+ }
279
+ if (compositeNames && compositeNames.has(baseType)) {
280
+ const compositeVarName = toCamelCase(baseType) + 'Composite';
281
+ let typeFunc = `${compositeVarName}()`;
282
+ if (isArray) {
283
+ typeFunc += '.array()';
284
+ }
285
+ return typeFunc;
286
+ }
287
+ if (domainNames && domainNames.has(baseType)) {
288
+ const domainVarName = toCamelCase(baseType) + 'Domain';
289
+ let typeFunc = `${domainVarName}()`;
290
+ if (isArray) {
291
+ typeFunc += '.array()';
292
+ }
293
+ return typeFunc;
294
+ }
295
+ let length = col.maxLength;
296
+ let precision = col.precision;
297
+ let scale = col.scale;
298
+ if (paramsStr) {
299
+ const params = paramsStr.split(',').map(p => p.trim());
300
+ if (params.length === 1 && !isNaN(Number(params[0]))) {
301
+ length = Number(params[0]);
302
+ }
303
+ else if (params.length === 2) {
304
+ precision = Number(params[0]);
305
+ scale = Number(params[1]);
306
+ }
307
+ }
308
+ const colWithParams = { ...col, maxLength: length, precision, scale };
309
+ let typeFunc = getTypeFunctionBase(baseType, colWithParams);
310
+ if (isArray) {
311
+ typeFunc += '.array()';
312
+ }
313
+ return typeFunc;
314
+ }
315
+ function getTypeFunctionBase(pgType, col) {
316
+ if (['int4', 'integer'].includes(pgType))
317
+ return 'integer()';
318
+ if (['int2', 'smallint'].includes(pgType))
319
+ return 'smallint()';
320
+ if (['int8', 'bigint'].includes(pgType))
321
+ return 'bigint()';
322
+ if (['serial', 'serial4'].includes(pgType))
323
+ return 'serial()';
324
+ if (['serial2', 'smallserial'].includes(pgType))
325
+ return 'smallserial()';
326
+ if (['serial8', 'bigserial'].includes(pgType))
327
+ return 'bigserial()';
328
+ if (['float4', 'real'].includes(pgType))
329
+ return 'real()';
330
+ if (['float8', 'double precision'].includes(pgType))
331
+ return 'doublePrecision()';
332
+ if (pgType === 'numeric' || pgType === 'decimal') {
333
+ if (col.precision && col.scale) {
334
+ return `numeric().precision(${col.precision}).scale(${col.scale})`;
335
+ }
336
+ else if (col.precision) {
337
+ return `numeric().precision(${col.precision})`;
338
+ }
339
+ return 'numeric()';
340
+ }
341
+ if (pgType === 'text')
342
+ return 'text()';
343
+ if (pgType === 'varchar' || pgType === 'character varying') {
344
+ return col.maxLength ? `varchar().length(${col.maxLength})` : 'varchar()';
345
+ }
346
+ if (pgType === 'char' || pgType === 'character' || pgType === 'bpchar') {
347
+ return col.maxLength ? `char().length(${col.maxLength})` : 'char()';
348
+ }
349
+ if (pgType === 'boolean' || pgType === 'bool')
350
+ return 'boolean()';
351
+ if (pgType === 'uuid')
352
+ return 'uuid()';
353
+ if (pgType === 'jsonb')
354
+ return 'jsonb()';
355
+ if (pgType === 'json')
356
+ return 'json()';
357
+ if (pgType === 'timestamp')
358
+ return 'timestamp()';
359
+ if (pgType === 'timestamptz')
360
+ return 'timestamp().withTimezone()';
361
+ if (pgType === 'date')
362
+ return 'date()';
363
+ if (pgType === 'time')
364
+ return 'time()';
365
+ if (pgType === 'timetz')
366
+ return 'time().withTimezone()';
367
+ if (pgType === 'interval')
368
+ return 'interval()';
369
+ if (pgType === 'bytea')
370
+ return 'bytea()';
371
+ if (pgType === 'inet')
372
+ return 'inet()';
373
+ if (pgType === 'cidr')
374
+ return 'cidr()';
375
+ if (pgType === 'macaddr')
376
+ return 'macaddr()';
377
+ if (pgType === 'vector') {
378
+ return col.maxLength ? `vector().dimensions(${col.maxLength})` : 'vector()';
379
+ }
380
+ if (pgType === 'tsvector')
381
+ return 'tsvector()';
382
+ if (pgType === 'tsquery')
383
+ return 'tsquery()';
384
+ if (pgType === 'citext')
385
+ return 'citext()';
386
+ if (pgType === 'hstore')
387
+ return 'hstore()';
388
+ if (pgType === 'ltree')
389
+ return 'ltree()';
390
+ if (pgType === 'lquery')
391
+ return 'lquery()';
392
+ if (pgType === 'ltxtquery')
393
+ return 'ltxtquery()';
394
+ if (pgType === 'cube')
395
+ return 'cube()';
396
+ if (pgType === 'semver')
397
+ return 'semver()';
398
+ return 'text()';
399
+ }
400
+ function parseGeneratedExpression(expr, camelCase) {
401
+ expr = expr.trim();
402
+ if (expr.startsWith('(') && expr.endsWith(')')) {
403
+ expr = expr.slice(1, -1).trim();
404
+ }
405
+ const arithmeticResult = parseArithmeticExpression(expr, camelCase);
406
+ if (arithmeticResult) {
407
+ return arithmeticResult;
408
+ }
409
+ const functionResult = parseFunctionExpression(expr, camelCase);
410
+ if (functionResult) {
411
+ return functionResult;
412
+ }
413
+ if (/^[a-z_][a-z0-9_]*$/i.test(expr)) {
414
+ const colName = camelCase ? toCamelCase(expr) : expr;
415
+ return `table.${colName}`;
416
+ }
417
+ const colMatch = expr.match(/[a-z_][a-z0-9_]*/i);
418
+ if (colMatch) {
419
+ const colName = camelCase ? toCamelCase(colMatch[0]) : colMatch[0];
420
+ return `table.${colName}`;
421
+ }
422
+ return `table.id /* TODO: Fix expression: ${expr.replace(/\*\//g, '* /')} */`;
423
+ }
424
+ function parseArithmeticExpression(expr, camelCase) {
425
+ const tokens = [];
426
+ const operators = [];
427
+ let current = '';
428
+ let parenDepth = 0;
429
+ let inQuote = false;
430
+ let quoteChar = '';
431
+ for (let i = 0; i < expr.length; i++) {
432
+ const char = expr[i];
433
+ const nextChar = i + 1 < expr.length ? expr[i + 1] : '';
434
+ if (!inQuote && (char === "'" || char === '"')) {
435
+ inQuote = true;
436
+ quoteChar = char;
437
+ current += char;
438
+ }
439
+ else if (inQuote && char === quoteChar) {
440
+ inQuote = false;
441
+ current += char;
442
+ }
443
+ else if (inQuote) {
444
+ current += char;
445
+ }
446
+ else if (char === '(') {
447
+ parenDepth++;
448
+ current += char;
449
+ }
450
+ else if (char === ')') {
451
+ parenDepth--;
452
+ current += char;
453
+ }
454
+ else if (parenDepth === 0 && char === '|' && nextChar === '|') {
455
+ if (current.trim()) {
456
+ tokens.push(current.trim());
457
+ }
458
+ operators.push('||');
459
+ current = '';
460
+ i++;
461
+ }
462
+ else if (parenDepth === 0 && ['+', '-', '*', '/'].includes(char)) {
463
+ if (char === '-' && current.trim() === '') {
464
+ current += char;
465
+ }
466
+ else {
467
+ if (current.trim()) {
468
+ tokens.push(current.trim());
469
+ }
470
+ operators.push(char);
471
+ current = '';
472
+ }
473
+ }
474
+ else {
475
+ current += char;
476
+ }
477
+ }
478
+ if (current.trim()) {
479
+ tokens.push(current.trim());
480
+ }
481
+ if (tokens.length < 2 || operators.length < 1) {
482
+ return null;
483
+ }
484
+ let result = parseSimpleTerm(tokens[0], camelCase);
485
+ if (!result)
486
+ return null;
487
+ for (let i = 0; i < operators.length; i++) {
488
+ const nextTerm = parseSimpleTerm(tokens[i + 1], camelCase);
489
+ if (!nextTerm)
490
+ return null;
491
+ const method = operatorToMethod(operators[i]);
492
+ result = `${result}.${method}(${nextTerm})`;
493
+ }
494
+ return result;
495
+ }
496
+ function operatorToMethod(op) {
497
+ switch (op) {
498
+ case '+': return 'add';
499
+ case '-': return 'subtract';
500
+ case '*': return 'multiply';
501
+ case '/': return 'divide';
502
+ case '||': return 'concat';
503
+ default: return 'add';
504
+ }
505
+ }
506
+ function parseSimpleTerm(term, camelCase) {
507
+ term = term.trim();
508
+ term = term.replace(/::[\w\s\[\]]+$/gi, '').trim();
509
+ if (term.startsWith("'") && term.endsWith("'")) {
510
+ return term;
511
+ }
512
+ if (/^-?\d+(\.\d+)?$/.test(term)) {
513
+ return term;
514
+ }
515
+ if (/^[a-z_][a-z0-9_]*$/i.test(term)) {
516
+ const colName = camelCase ? toCamelCase(term) : term;
517
+ return `table.${colName}`;
518
+ }
519
+ if (term.startsWith('"') && term.endsWith('"')) {
520
+ const name = term.slice(1, -1);
521
+ const colName = camelCase ? toCamelCase(name) : name;
522
+ return `table.${colName}`;
523
+ }
524
+ const funcResult = parseFunctionExpression(term, camelCase);
525
+ if (funcResult) {
526
+ return funcResult;
527
+ }
528
+ if (term.startsWith('(') && term.endsWith(')')) {
529
+ const inner = term.slice(1, -1);
530
+ const arithmeticResult = parseArithmeticExpression(inner, camelCase);
531
+ if (arithmeticResult) {
532
+ return `(${arithmeticResult})`;
533
+ }
534
+ const simpleResult = parseSimpleTerm(inner, camelCase);
535
+ if (simpleResult) {
536
+ return simpleResult;
537
+ }
538
+ }
539
+ const arithmeticResult = parseArithmeticExpression(term, camelCase);
540
+ if (arithmeticResult) {
541
+ return arithmeticResult;
542
+ }
543
+ return null;
544
+ }
545
+ function parseFunctionExpression(expr, camelCase) {
546
+ const funcMatch = expr.match(/^([a-z_][a-z0-9_]*)\s*\((.+)\)$/i);
547
+ if (!funcMatch)
548
+ return null;
549
+ const funcName = funcMatch[1].toLowerCase();
550
+ const argsStr = funcMatch[2];
551
+ const args = parseArguments(argsStr);
552
+ switch (funcName) {
553
+ case 'coalesce': {
554
+ const parsedArgs = args.map(a => parseSimpleTerm(a.trim(), camelCase) || a.trim());
555
+ return `F.coalesce(${parsedArgs.join(', ')})`;
556
+ }
557
+ case 'nullif': {
558
+ const parsedArgs = args.map(a => parseSimpleTerm(a.trim(), camelCase) || a.trim());
559
+ return `F.nullif(${parsedArgs.join(', ')})`;
560
+ }
561
+ case 'lower': {
562
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
563
+ return arg ? `F.lower(${arg})` : null;
564
+ }
565
+ case 'upper': {
566
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
567
+ return arg ? `F.upper(${arg})` : null;
568
+ }
569
+ case 'trim': {
570
+ const arithmetic = parseArithmeticExpression(args[0]?.trim() || '', camelCase);
571
+ if (arithmetic) {
572
+ return `F.trim(${arithmetic})`;
573
+ }
574
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
575
+ return arg ? `F.trim(${arg})` : null;
576
+ }
577
+ case 'length': {
578
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
579
+ return arg ? `F.length(${arg})` : null;
580
+ }
581
+ case 'abs': {
582
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
583
+ return arg ? `F.abs(${arg})` : null;
584
+ }
585
+ case 'ceil':
586
+ case 'ceiling': {
587
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
588
+ return arg ? `F.ceil(${arg})` : null;
589
+ }
590
+ case 'floor': {
591
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
592
+ return arg ? `F.floor(${arg})` : null;
593
+ }
594
+ case 'round': {
595
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
596
+ const decimals = args[1]?.trim();
597
+ if (decimals) {
598
+ return arg ? `F.round(${arg}, ${decimals})` : null;
599
+ }
600
+ return arg ? `F.round(${arg})` : null;
601
+ }
602
+ case 'concat': {
603
+ const parsedArgs = args.map(a => {
604
+ const trimmed = a.trim();
605
+ if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
606
+ return trimmed;
607
+ }
608
+ return parseSimpleTerm(trimmed, camelCase) || trimmed;
609
+ });
610
+ return `F.concat(${parsedArgs.join(', ')})`;
611
+ }
612
+ case 'greatest': {
613
+ const parsedArgs = args.map(a => parseSimpleTerm(a.trim(), camelCase) || a.trim());
614
+ return `F.greatest(${parsedArgs.join(', ')})`;
615
+ }
616
+ case 'least': {
617
+ const parsedArgs = args.map(a => parseSimpleTerm(a.trim(), camelCase) || a.trim());
618
+ return `F.least(${parsedArgs.join(', ')})`;
619
+ }
620
+ case 'md5': {
621
+ const arg = parseSimpleTerm(args[0]?.trim() || '', camelCase);
622
+ return arg ? `F.md5(${arg})` : null;
623
+ }
624
+ default:
625
+ return null;
626
+ }
627
+ }
628
+ function parseArguments(argsStr) {
629
+ const args = [];
630
+ let current = '';
631
+ let parenDepth = 0;
632
+ for (const char of argsStr) {
633
+ if (char === '(') {
634
+ parenDepth++;
635
+ current += char;
636
+ }
637
+ else if (char === ')') {
638
+ parenDepth--;
639
+ current += char;
640
+ }
641
+ else if (char === ',' && parenDepth === 0) {
642
+ args.push(current);
643
+ current = '';
644
+ }
645
+ else {
646
+ current += char;
647
+ }
648
+ }
649
+ if (current) {
650
+ args.push(current);
651
+ }
652
+ return args;
653
+ }
654
+ function formatDefaultValue(val, col, domainMap) {
655
+ if (!val)
656
+ return null;
657
+ const cleaned = val.replace(/::[\w\s\[\]]+$/gi, '').trim();
658
+ if (cleaned.startsWith('nextval('))
659
+ return null;
660
+ if (cleaned.toLowerCase().includes('gen_random_uuid') && col.isPrimaryKey) {
661
+ return null;
662
+ }
663
+ if (cleaned.toLowerCase() === 'true')
664
+ return 'true';
665
+ if (cleaned.toLowerCase() === 'false')
666
+ return 'false';
667
+ let baseDataType = col.dataType.toLowerCase().replace(/\([^)]*\)$/, '').trim();
668
+ if (domainMap && domainMap.has(baseDataType)) {
669
+ baseDataType = domainMap.get(baseDataType).toLowerCase().replace(/\([^)]*\)$/, '').trim();
670
+ }
671
+ const isNumeric = ['numeric', 'decimal'].includes(baseDataType);
672
+ const isBigInt = ['int8', 'bigint'].includes(baseDataType);
673
+ if (/^-?\d+$/.test(cleaned)) {
674
+ if (isNumeric) {
675
+ return `'${cleaned}'`;
676
+ }
677
+ else if (isBigInt) {
678
+ return `BigInt(${cleaned})`;
679
+ }
680
+ return cleaned;
681
+ }
682
+ if (/^-?\d+\.\d+$/.test(cleaned)) {
683
+ return isNumeric ? `'${cleaned}'` : cleaned;
684
+ }
685
+ if (cleaned.toLowerCase() === 'gen_random_uuid()')
686
+ return 'genRandomUuid()';
687
+ if (cleaned.toLowerCase() === 'uuid_generate_v4()')
688
+ return 'genRandomUuid()';
689
+ if (cleaned.toLowerCase() === 'now()')
690
+ return 'now()';
691
+ if (cleaned.toLowerCase() === 'current_timestamp')
692
+ return 'now()';
693
+ if (cleaned.toLowerCase() === 'current_date')
694
+ return 'currentDate()';
695
+ if (cleaned === "'{}'") {
696
+ const isArray = col.dataType.endsWith('[]') || col.dataType.startsWith('_');
697
+ if (isArray)
698
+ return 'emptyArray()';
699
+ return 'emptyObject()';
700
+ }
701
+ if (cleaned === "'[]'" || cleaned === 'ARRAY[]')
702
+ return 'emptyArray()';
703
+ const pgArrayMatch = cleaned.match(/^'?\{([^}]*)\}'?$/);
704
+ if (pgArrayMatch) {
705
+ const contents = pgArrayMatch[1];
706
+ if (contents === '') {
707
+ return 'emptyArray()';
708
+ }
709
+ const values = contents.split(',').map(v => {
710
+ const trimmed = v.trim();
711
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
712
+ return `'${trimmed.slice(1, -1)}'`;
713
+ }
714
+ return `'${trimmed}'`;
715
+ });
716
+ return `[${values.join(', ')}]`;
717
+ }
718
+ if (cleaned.startsWith('ARRAY[')) {
719
+ const arrayContent = cleaned.match(/ARRAY\[([^\]]*)\]/i);
720
+ if (arrayContent && arrayContent[1]) {
721
+ const values = arrayContent[1].split(',').map(v => {
722
+ const trimmed = v.trim();
723
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
724
+ return trimmed;
725
+ }
726
+ if (/^(true|false)$/i.test(trimmed)) {
727
+ return trimmed.toLowerCase();
728
+ }
729
+ if (/^null$/i.test(trimmed)) {
730
+ return 'null';
731
+ }
732
+ const unquoted = trimmed.replace(/^'|'$/g, '');
733
+ return `'${unquoted}'`;
734
+ });
735
+ return `[${values.join(', ')}]`;
736
+ }
737
+ return 'emptyArray()';
738
+ }
739
+ const isJsonColumn = col.dataType.toLowerCase().includes('json');
740
+ if (isJsonColumn && cleaned.startsWith("'") && cleaned.endsWith("'")) {
741
+ const jsonStr = cleaned.slice(1, -1).replace(/''/g, "'");
742
+ try {
743
+ const parsed = JSON.parse(jsonStr);
744
+ return JSON.stringify(parsed);
745
+ }
746
+ catch {
747
+ }
748
+ }
749
+ if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
750
+ const str = cleaned.slice(1, -1).replace(/'/g, "\\'");
751
+ return `'${str}'`;
752
+ }
753
+ return null;
754
+ }
755
+ function generateColumnDef(col, seenColumns, camelCase = true, checkValues, enumNames, domainNames, compositeNames, domainMap) {
756
+ if (seenColumns.has(col.name)) {
757
+ return null;
758
+ }
759
+ seenColumns.add(col.name);
760
+ const colType = getColumnType(col, enumNames, domainNames, compositeNames);
761
+ let propName;
762
+ let typeCall;
763
+ if (camelCase) {
764
+ propName = toCamelCase(col.name);
765
+ if (propName !== col.name) {
766
+ typeCall = injectColumnName(colType, col.name);
767
+ }
768
+ else {
769
+ typeCall = colType;
770
+ }
771
+ }
772
+ else {
773
+ propName = col.name;
774
+ typeCall = colType;
775
+ }
776
+ const parts = [typeCall];
777
+ if (checkValues && checkValues.length > 0) {
778
+ const quotedValues = checkValues.map(v => `'${v}'`).join(', ');
779
+ parts.push(`.check(${quotedValues})`);
780
+ }
781
+ if (col.isPrimaryKey) {
782
+ parts.push('.primaryKey()');
783
+ }
784
+ if (!col.isNullable && !col.isPrimaryKey && !col.isGenerated) {
785
+ parts.push('.notNull()');
786
+ }
787
+ if (col.isUnique && !col.isPrimaryKey) {
788
+ parts.push('.unique()');
789
+ }
790
+ if (col.isGenerated && col.generationExpression) {
791
+ const typedExpr = parseGeneratedExpression(col.generationExpression, camelCase);
792
+ parts.push(`.generatedAlwaysAs((table, F) => ${typedExpr})`);
793
+ }
794
+ else {
795
+ const defaultVal = formatDefaultValue(col.defaultValue, col, domainMap);
796
+ if (defaultVal) {
797
+ parts.push(`.default(${defaultVal})`);
798
+ }
799
+ }
800
+ if (col.references) {
801
+ let refStr = `.references(() => ${toCamelCase(col.references.table)}.${toCamelCase(col.references.column)})`;
802
+ if (col.references.onDelete && col.references.onDelete !== 'NO ACTION') {
803
+ refStr = `.references(() => ${toCamelCase(col.references.table)}.${toCamelCase(col.references.column)}, { onDelete: '${col.references.onDelete.toLowerCase()}' })`;
804
+ }
805
+ if (col.references.onUpdate && col.references.onUpdate !== 'NO ACTION') {
806
+ if (col.references.onDelete && col.references.onDelete !== 'NO ACTION') {
807
+ refStr = `.references(() => ${toCamelCase(col.references.table)}.${toCamelCase(col.references.column)}, { onDelete: '${col.references.onDelete.toLowerCase()}', onUpdate: '${col.references.onUpdate.toLowerCase()}' })`;
808
+ }
809
+ else {
810
+ refStr = `.references(() => ${toCamelCase(col.references.table)}.${toCamelCase(col.references.column)}, { onUpdate: '${col.references.onUpdate.toLowerCase()}' })`;
811
+ }
812
+ }
813
+ parts.push(refStr);
814
+ }
815
+ const columnLine = `${propName}: ${parts.join('')}`;
816
+ if (col.comment) {
817
+ const safeComment = col.comment.replace(/\*\//g, '* /');
818
+ return ` /** ${safeComment} */\n ${columnLine}`;
819
+ }
820
+ return ` ${columnLine}`;
821
+ }
822
+ function injectColumnName(typeCall, columnName) {
823
+ return typeCall.replace(/^(\w+)(<[^>]+>)?\(\)/, `$1$2('${columnName}')`);
824
+ }
825
+ function generateIndexes(indexes, columnNames, camelCase = true) {
826
+ const nonPkIndexes = indexes.filter(idx => !idx.isPrimary);
827
+ if (nonPkIndexes.length === 0) {
828
+ return null;
829
+ }
830
+ let usesExpressions = false;
831
+ const indexLines = nonPkIndexes.map(idx => {
832
+ let columnsArr;
833
+ if (Array.isArray(idx.columns)) {
834
+ columnsArr = idx.columns;
835
+ }
836
+ else if (typeof idx.columns === 'string') {
837
+ const cleaned = idx.columns.replace(/^\{|\}$/g, '');
838
+ columnsArr = cleaned.split(',').map(s => s.trim()).filter(Boolean);
839
+ }
840
+ else {
841
+ columnsArr = [];
842
+ }
843
+ const hasExpression = idx.expression || idx.definition?.includes('(');
844
+ const sqlFunctions = new Set(['lower', 'upper', 'coalesce', 'concat', 'to_tsvector', 'toTsvector',
845
+ 'plainto_tsquery', 'ts_rank', 'substring', 'trim', 'length', 'position', 'replace', 'left', 'right',
846
+ 'english', 'simple', 'german', 'french', 'spanish', 'now', 'current_timestamp', 'current_date']);
847
+ const validColumns = columnsArr.filter(c => {
848
+ const trimmed = c.trim().toLowerCase();
849
+ if (!trimmed || !/^[a-zA-Z_]/.test(trimmed))
850
+ return false;
851
+ if (sqlFunctions.has(trimmed))
852
+ return false;
853
+ return columnNames.some(cn => cn.toLowerCase() === trimmed || toCamelCase(cn).toLowerCase() === trimmed);
854
+ });
855
+ if (validColumns.length === 0 && hasExpression) {
856
+ usesExpressions = true;
857
+ const expr = idx.expression || extractExpressionFromDef(idx.definition);
858
+ if (expr) {
859
+ const parsedExpr = parseIndexExpression(expr, camelCase);
860
+ let line;
861
+ if (parsedExpr) {
862
+ line = ` index('${idx.name}').expression(exp => ${parsedExpr})`;
863
+ }
864
+ else {
865
+ const escapedExpr = expr.replace(/'/g, "\\'").replace(/\n/g, ' ');
866
+ line = ` index('${idx.name}').expression(exp => exp.raw('${escapedExpr}'))`;
867
+ }
868
+ if (idx.isUnique)
869
+ line += '.unique()';
870
+ if (idx.type && idx.type !== 'btree')
871
+ line += `.using('${idx.type.toUpperCase()}')`;
872
+ if (idx.operatorClasses && idx.operatorClasses.length > 0) {
873
+ line += `.opclass('${idx.operatorClasses[0]}')`;
874
+ }
875
+ if (idx.whereClause) {
876
+ const whereCallback = parseWhereClause(idx.whereClause, camelCase);
877
+ line += `.where(${whereCallback})`;
878
+ }
879
+ return line;
880
+ }
881
+ return null;
882
+ }
883
+ if (validColumns.length === 0)
884
+ return null;
885
+ const cols = validColumns.map(c => {
886
+ const propName = camelCase ? toCamelCase(c) : c;
887
+ return `table.${propName}`;
888
+ }).join(', ');
889
+ let line = ` index('${idx.name}').on(${cols})`;
890
+ if (idx.isUnique) {
891
+ line += '.unique()';
892
+ }
893
+ if (idx.type && idx.type !== 'btree') {
894
+ line += `.using('${idx.type.toUpperCase()}')`;
895
+ }
896
+ if (idx.operatorClasses && idx.operatorClasses.length > 0) {
897
+ line += `.opclass('${idx.operatorClasses[0]}')`;
898
+ }
899
+ if (idx.whereClause) {
900
+ const whereCallback = parseWhereClause(idx.whereClause, camelCase);
901
+ line += `.where(${whereCallback})`;
902
+ }
903
+ return line;
904
+ }).filter(Boolean);
905
+ if (indexLines.length === 0)
906
+ return null;
907
+ if (usesExpressions) {
908
+ return ` (table, index, F) => [\n${indexLines.join(',\n')},\n ]`;
909
+ }
910
+ else {
911
+ return ` (table, index) => [\n${indexLines.join(',\n')},\n ]`;
912
+ }
913
+ }
914
+ function extractExpressionFromDef(definition) {
915
+ if (!definition)
916
+ return null;
917
+ const onMatch = definition.match(/\bON\s+\w+\s*(?:USING\s+\w+\s*)?\(/i);
918
+ if (!onMatch)
919
+ return null;
920
+ const startIdx = onMatch.index + onMatch[0].length;
921
+ let depth = 1;
922
+ let endIdx = startIdx;
923
+ for (let i = startIdx; i < definition.length && depth > 0; i++) {
924
+ if (definition[i] === '(')
925
+ depth++;
926
+ else if (definition[i] === ')')
927
+ depth--;
928
+ if (depth > 0)
929
+ endIdx = i + 1;
930
+ }
931
+ const expr = definition.slice(startIdx, endIdx).trim();
932
+ return expr || null;
933
+ }
934
+ function parseIndexExpression(expr, camelCase) {
935
+ expr = expr.trim();
936
+ const tsvectorMatch = expr.match(/^to_tsvector\s*\(\s*'([^']+)'\s*,\s*(.+)\s*\)$/i);
937
+ if (tsvectorMatch) {
938
+ const config = tsvectorMatch[1];
939
+ const innerExpr = tsvectorMatch[2].trim();
940
+ const parsedInner = parseIndexExpressionPart(innerExpr, camelCase);
941
+ if (parsedInner) {
942
+ return `exp.toTsvector('${config}', ${parsedInner})`;
943
+ }
944
+ }
945
+ const lowerMatch = expr.match(/^LOWER\s*\(\s*([a-z_][a-z0-9_]*)(?:::TEXT)?\s*\)$/i);
946
+ if (lowerMatch) {
947
+ const col = camelCase ? toCamelCase(lowerMatch[1]) : lowerMatch[1];
948
+ return `exp.lower(exp.col('${col}'))`;
949
+ }
950
+ const upperMatch = expr.match(/^UPPER\s*\(\s*([a-z_][a-z0-9_]*)(?:::TEXT)?\s*\)$/i);
951
+ if (upperMatch) {
952
+ const col = camelCase ? toCamelCase(upperMatch[1]) : upperMatch[1];
953
+ return `exp.upper(exp.col('${col}'))`;
954
+ }
955
+ const orderedColMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+(DESC|ASC)(?:\s+NULLS\s+(FIRST|LAST))?$/i);
956
+ if (orderedColMatch) {
957
+ const col = camelCase ? toCamelCase(orderedColMatch[1]) : orderedColMatch[1];
958
+ const order = orderedColMatch[2].toLowerCase();
959
+ const nulls = orderedColMatch[3]?.toLowerCase();
960
+ let result = `exp.col('${col}')`;
961
+ if (order === 'desc') {
962
+ result += '.desc()';
963
+ }
964
+ else {
965
+ result += '.asc()';
966
+ }
967
+ if (nulls === 'last') {
968
+ result += '.nullsLast()';
969
+ }
970
+ else if (nulls === 'first') {
971
+ result += '.nullsFirst()';
972
+ }
973
+ return result;
974
+ }
975
+ if (/^[a-z_][a-z0-9_]*$/i.test(expr)) {
976
+ const col = camelCase ? toCamelCase(expr) : expr;
977
+ return `exp.col('${col}')`;
978
+ }
979
+ return null;
980
+ }
981
+ function parseIndexExpressionPart(expr, camelCase) {
982
+ expr = expr.trim();
983
+ if (expr.includes(' || ')) {
984
+ const parts = splitByConcatOperator(expr);
985
+ if (parts.length > 1) {
986
+ const parsedParts = parts.map(p => parseIndexExpressionPart(p.trim(), camelCase));
987
+ if (parsedParts.every(p => p !== null)) {
988
+ return `exp.concat(${parsedParts.join(', ')})`;
989
+ }
990
+ }
991
+ }
992
+ const coalesceMatch = expr.match(/^COALESCE\s*\(\s*([^,]+)\s*,\s*(.+)\s*\)$/i);
993
+ if (coalesceMatch) {
994
+ const firstArg = coalesceMatch[1].trim();
995
+ const defaultArg = coalesceMatch[2].trim();
996
+ let parsedFirst = null;
997
+ const colCastMatch = firstArg.match(/^([a-z_][a-z0-9_]*)::TEXT$/i);
998
+ if (colCastMatch) {
999
+ const col = camelCase ? toCamelCase(colCastMatch[1]) : colCastMatch[1];
1000
+ parsedFirst = `exp.asText(exp.col('${col}'))`;
1001
+ }
1002
+ else if (/^[a-z_][a-z0-9_]*$/i.test(firstArg)) {
1003
+ const col = camelCase ? toCamelCase(firstArg) : firstArg;
1004
+ parsedFirst = `exp.col('${col}')`;
1005
+ }
1006
+ if (parsedFirst) {
1007
+ if (defaultArg === "''" || defaultArg === "''") {
1008
+ return `exp.coalesce(${parsedFirst}, '')`;
1009
+ }
1010
+ if (/^'[^']*'$/.test(defaultArg)) {
1011
+ return `exp.coalesce(${parsedFirst}, ${defaultArg})`;
1012
+ }
1013
+ }
1014
+ }
1015
+ const colCastMatch = expr.match(/^([a-z_][a-z0-9_]*)::TEXT$/i);
1016
+ if (colCastMatch) {
1017
+ const col = camelCase ? toCamelCase(colCastMatch[1]) : colCastMatch[1];
1018
+ return `exp.asText(exp.col('${col}'))`;
1019
+ }
1020
+ if (/^[a-z_][a-z0-9_]*$/i.test(expr)) {
1021
+ const col = camelCase ? toCamelCase(expr) : expr;
1022
+ return `exp.col('${col}')`;
1023
+ }
1024
+ if (/^'[^']*'$/.test(expr)) {
1025
+ return expr;
1026
+ }
1027
+ return null;
1028
+ }
1029
+ function splitByConcatOperator(expr) {
1030
+ const parts = [];
1031
+ let current = '';
1032
+ let parenDepth = 0;
1033
+ for (let i = 0; i < expr.length; i++) {
1034
+ const char = expr[i];
1035
+ if (char === '(') {
1036
+ parenDepth++;
1037
+ current += char;
1038
+ }
1039
+ else if (char === ')') {
1040
+ parenDepth--;
1041
+ current += char;
1042
+ }
1043
+ else if (parenDepth === 0 && expr.slice(i, i + 4) === ' || ') {
1044
+ if (current.trim()) {
1045
+ parts.push(current.trim());
1046
+ }
1047
+ current = '';
1048
+ i += 3;
1049
+ }
1050
+ else {
1051
+ current += char;
1052
+ }
1053
+ }
1054
+ if (current.trim()) {
1055
+ parts.push(current.trim());
1056
+ }
1057
+ return parts;
1058
+ }
1059
+ function parseWhereValue(value, camelCase) {
1060
+ value = value.trim();
1061
+ if (/^'.*'$/.test(value)) {
1062
+ return value;
1063
+ }
1064
+ if (/^-?\d+(\.\d+)?$/.test(value)) {
1065
+ return value;
1066
+ }
1067
+ if (/^TRUE$/i.test(value)) {
1068
+ return 'true';
1069
+ }
1070
+ if (/^FALSE$/i.test(value)) {
1071
+ return 'false';
1072
+ }
1073
+ if (/^NOW\(\)$/i.test(value)) {
1074
+ return 'w.now()';
1075
+ }
1076
+ if (/^CURRENT_DATE$/i.test(value)) {
1077
+ return 'w.currentDate()';
1078
+ }
1079
+ if (/^CURRENT_TIMESTAMP$/i.test(value)) {
1080
+ return 'w.currentTimestamp()';
1081
+ }
1082
+ const dateIntervalMatch = value.match(/^(CURRENT_DATE|CURRENT_TIMESTAMP|NOW\(\))\s*\+\s*INTERVAL\s*'([^']+)'$/i);
1083
+ if (dateIntervalMatch) {
1084
+ const dateFn = dateIntervalMatch[1].toUpperCase();
1085
+ const interval = dateIntervalMatch[2];
1086
+ if (dateFn === 'CURRENT_DATE') {
1087
+ return `w.currentDate().plus(w.interval('${interval}'))`;
1088
+ }
1089
+ else if (dateFn === 'CURRENT_TIMESTAMP') {
1090
+ return `w.currentTimestamp().plus(w.interval('${interval}'))`;
1091
+ }
1092
+ else {
1093
+ return `w.now().plus(w.interval('${interval}'))`;
1094
+ }
1095
+ }
1096
+ const dateMinusIntervalMatch = value.match(/^(CURRENT_DATE|CURRENT_TIMESTAMP|NOW\(\))\s*-\s*INTERVAL\s*'([^']+)'$/i);
1097
+ if (dateMinusIntervalMatch) {
1098
+ const dateFn = dateMinusIntervalMatch[1].toUpperCase();
1099
+ const interval = dateMinusIntervalMatch[2];
1100
+ if (dateFn === 'CURRENT_DATE') {
1101
+ return `w.currentDate().minus(w.interval('${interval}'))`;
1102
+ }
1103
+ else if (dateFn === 'CURRENT_TIMESTAMP') {
1104
+ return `w.currentTimestamp().minus(w.interval('${interval}'))`;
1105
+ }
1106
+ else {
1107
+ return `w.now().minus(w.interval('${interval}'))`;
1108
+ }
1109
+ }
1110
+ if (/^[a-z_][a-z0-9_]*$/i.test(value)) {
1111
+ const valCol = camelCase ? toCamelCase(value) : value;
1112
+ return `table.${valCol}`;
1113
+ }
1114
+ return null;
1115
+ }
1116
+ function parseSingleCondition(clause, camelCase) {
1117
+ clause = clause.trim();
1118
+ while (clause.startsWith('(') && clause.endsWith(')')) {
1119
+ let depth = 0;
1120
+ let matched = true;
1121
+ for (let i = 0; i < clause.length - 1; i++) {
1122
+ if (clause[i] === '(')
1123
+ depth++;
1124
+ else if (clause[i] === ')')
1125
+ depth--;
1126
+ if (depth === 0 && i < clause.length - 1) {
1127
+ matched = false;
1128
+ break;
1129
+ }
1130
+ }
1131
+ if (matched) {
1132
+ clause = clause.slice(1, -1).trim();
1133
+ }
1134
+ else {
1135
+ break;
1136
+ }
1137
+ }
1138
+ const isNullMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+IS\s+NULL$/i);
1139
+ if (isNullMatch) {
1140
+ const col = camelCase ? toCamelCase(isNullMatch[1]) : isNullMatch[1];
1141
+ return `w.col(table.${col}).isNull()`;
1142
+ }
1143
+ const isNotNullMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+IS\s+NOT\s+NULL$/i);
1144
+ if (isNotNullMatch) {
1145
+ const col = camelCase ? toCamelCase(isNotNullMatch[1]) : isNotNullMatch[1];
1146
+ return `w.col(table.${col}).isNotNull()`;
1147
+ }
1148
+ const notInMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+NOT\s+IN\s*\((.+)\)$/i);
1149
+ if (notInMatch) {
1150
+ const col = camelCase ? toCamelCase(notInMatch[1]) : notInMatch[1];
1151
+ const valuesStr = notInMatch[2];
1152
+ const values = valuesStr.match(/'[^']*'/g)?.join(', ') || valuesStr;
1153
+ return `w.col(table.${col}).notIn([${values}])`;
1154
+ }
1155
+ const inMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+IN\s*\((.+)\)$/i);
1156
+ if (inMatch) {
1157
+ const col = camelCase ? toCamelCase(inMatch[1]) : inMatch[1];
1158
+ const valuesStr = inMatch[2];
1159
+ const values = valuesStr.match(/'[^']*'/g)?.join(', ') || valuesStr;
1160
+ return `w.col(table.${col}).in([${values}])`;
1161
+ }
1162
+ const comparisonMatch = clause.match(/^([a-z_][a-z0-9_]*)\s*(<=?|>=?|<>|!=|=)\s*(.+)$/i);
1163
+ if (comparisonMatch) {
1164
+ const col = camelCase ? toCamelCase(comparisonMatch[1]) : comparisonMatch[1];
1165
+ const op = comparisonMatch[2];
1166
+ const value = comparisonMatch[3].trim();
1167
+ let method;
1168
+ switch (op) {
1169
+ case '=':
1170
+ method = 'eq';
1171
+ break;
1172
+ case '<>':
1173
+ case '!=':
1174
+ method = 'neq';
1175
+ break;
1176
+ case '<':
1177
+ method = 'lt';
1178
+ break;
1179
+ case '<=':
1180
+ method = 'lte';
1181
+ break;
1182
+ case '>':
1183
+ method = 'gt';
1184
+ break;
1185
+ case '>=':
1186
+ method = 'gte';
1187
+ break;
1188
+ default: method = 'eq';
1189
+ }
1190
+ const parsedValue = parseWhereValue(value, camelCase);
1191
+ if (parsedValue === null) {
1192
+ return null;
1193
+ }
1194
+ return `w.col(table.${col}).${method}(${parsedValue})`;
1195
+ }
1196
+ const likeMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+LIKE\s+('.+')$/i);
1197
+ if (likeMatch) {
1198
+ const col = camelCase ? toCamelCase(likeMatch[1]) : likeMatch[1];
1199
+ return `w.col(table.${col}).like(${likeMatch[2]})`;
1200
+ }
1201
+ const ilikeMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+ILIKE\s+('.+')$/i);
1202
+ if (ilikeMatch) {
1203
+ const col = camelCase ? toCamelCase(ilikeMatch[1]) : ilikeMatch[1];
1204
+ return `w.col(table.${col}).ilike(${ilikeMatch[2]})`;
1205
+ }
1206
+ const betweenMatch = clause.match(/^([a-z_][a-z0-9_]*)\s+BETWEEN\s+(.+)\s+AND\s+(.+)$/i);
1207
+ if (betweenMatch) {
1208
+ const col = camelCase ? toCamelCase(betweenMatch[1]) : betweenMatch[1];
1209
+ const min = parseWhereValue(betweenMatch[2].trim(), camelCase);
1210
+ const max = parseWhereValue(betweenMatch[3].trim(), camelCase);
1211
+ if (min && max) {
1212
+ return `w.col(table.${col}).between(${min}, ${max})`;
1213
+ }
1214
+ }
1215
+ return null;
1216
+ }
1217
+ function splitByOperator(clause, operator) {
1218
+ const parts = [];
1219
+ let current = '';
1220
+ let parenDepth = 0;
1221
+ let i = 0;
1222
+ while (i < clause.length) {
1223
+ const char = clause[i];
1224
+ if (char === '(') {
1225
+ parenDepth++;
1226
+ current += char;
1227
+ i++;
1228
+ }
1229
+ else if (char === ')') {
1230
+ parenDepth--;
1231
+ current += char;
1232
+ i++;
1233
+ }
1234
+ else if (parenDepth === 0) {
1235
+ const remaining = clause.slice(i);
1236
+ const match = remaining.match(new RegExp(`^\\s+${operator}\\s+`, 'i'));
1237
+ if (match) {
1238
+ if (current.trim()) {
1239
+ parts.push(current.trim());
1240
+ }
1241
+ current = '';
1242
+ i += match[0].length;
1243
+ }
1244
+ else {
1245
+ current += char;
1246
+ i++;
1247
+ }
1248
+ }
1249
+ else {
1250
+ current += char;
1251
+ i++;
1252
+ }
1253
+ }
1254
+ if (current.trim()) {
1255
+ parts.push(current.trim());
1256
+ }
1257
+ return parts.length > 1 ? parts : null;
1258
+ }
1259
+ function parseCompoundCondition(clause, camelCase) {
1260
+ clause = clause.trim();
1261
+ while (clause.startsWith('(') && clause.endsWith(')')) {
1262
+ let depth = 0;
1263
+ let matched = true;
1264
+ for (let i = 0; i < clause.length - 1; i++) {
1265
+ if (clause[i] === '(')
1266
+ depth++;
1267
+ else if (clause[i] === ')')
1268
+ depth--;
1269
+ if (depth === 0 && i < clause.length - 1) {
1270
+ matched = false;
1271
+ break;
1272
+ }
1273
+ }
1274
+ if (matched) {
1275
+ clause = clause.slice(1, -1).trim();
1276
+ }
1277
+ else {
1278
+ break;
1279
+ }
1280
+ }
1281
+ const orParts = splitByOperator(clause, 'OR');
1282
+ if (orParts && orParts.length > 1) {
1283
+ const parsedParts = orParts.map(p => parseCompoundCondition(p, camelCase));
1284
+ if (parsedParts.every(p => p !== null)) {
1285
+ const chained = parsedParts.reduce((acc, part, i) => i === 0 ? part : `${acc}.or(${part})`);
1286
+ return chained;
1287
+ }
1288
+ return null;
1289
+ }
1290
+ const andParts = splitByOperator(clause, 'AND');
1291
+ if (andParts && andParts.length > 1) {
1292
+ const parsedParts = andParts.map(p => parseCompoundCondition(p, camelCase));
1293
+ if (parsedParts.every(p => p !== null)) {
1294
+ const chained = parsedParts.reduce((acc, part, i) => i === 0 ? part : `${acc}.and(${part})`);
1295
+ return chained;
1296
+ }
1297
+ return null;
1298
+ }
1299
+ return parseSingleCondition(clause, camelCase);
1300
+ }
1301
+ function parseWhereClause(whereClause, camelCase) {
1302
+ const result = parseCompoundCondition(whereClause, camelCase);
1303
+ if (result) {
1304
+ return `(w) => ${result}`;
1305
+ }
1306
+ throw new Error(`Unable to parse WHERE clause: ${whereClause}`);
1307
+ }
1308
+ function parseCheckExpression(expr, camelCase) {
1309
+ expr = expr.trim();
1310
+ while (expr.startsWith('(') && expr.endsWith(')')) {
1311
+ let depth = 0;
1312
+ let matched = true;
1313
+ for (let i = 0; i < expr.length - 1; i++) {
1314
+ if (expr[i] === '(')
1315
+ depth++;
1316
+ else if (expr[i] === ')')
1317
+ depth--;
1318
+ if (depth === 0 && i < expr.length - 1) {
1319
+ matched = false;
1320
+ break;
1321
+ }
1322
+ }
1323
+ if (matched) {
1324
+ expr = expr.slice(1, -1).trim();
1325
+ }
1326
+ else {
1327
+ break;
1328
+ }
1329
+ }
1330
+ const orParts = splitCheckByOperator(expr, 'OR');
1331
+ if (orParts && orParts.length > 1) {
1332
+ const parsedParts = orParts.map(p => parseCheckExpression(p, camelCase));
1333
+ if (parsedParts.every(p => p !== null)) {
1334
+ return parsedParts.reduce((acc, part, i) => i === 0 ? part : `${acc}.or(${part})`);
1335
+ }
1336
+ return null;
1337
+ }
1338
+ const andParts = splitCheckByOperator(expr, 'AND');
1339
+ if (andParts && andParts.length > 1) {
1340
+ const parsedParts = andParts.map(p => parseCheckExpression(p, camelCase));
1341
+ if (parsedParts.every(p => p !== null)) {
1342
+ return parsedParts.reduce((acc, part, i) => i === 0 ? part : `${acc}.and(${part})`);
1343
+ }
1344
+ return null;
1345
+ }
1346
+ const isNullMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+IS\s+NULL$/i);
1347
+ if (isNullMatch) {
1348
+ const col = camelCase ? toCamelCase(isNullMatch[1]) : isNullMatch[1];
1349
+ return `table.${col}.isNull()`;
1350
+ }
1351
+ const isNotNullMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+IS\s+NOT\s+NULL$/i);
1352
+ if (isNotNullMatch) {
1353
+ const col = camelCase ? toCamelCase(isNotNullMatch[1]) : isNotNullMatch[1];
1354
+ return `table.${col}.isNotNull()`;
1355
+ }
1356
+ const betweenMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+BETWEEN\s+(.+)\s+AND\s+(.+)$/i);
1357
+ if (betweenMatch) {
1358
+ const col = camelCase ? toCamelCase(betweenMatch[1]) : betweenMatch[1];
1359
+ const min = parseCheckValue(betweenMatch[2].trim(), camelCase);
1360
+ const max = parseCheckValue(betweenMatch[3].trim(), camelCase);
1361
+ if (min && max) {
1362
+ return `table.${col}.between(${min}, ${max})`;
1363
+ }
1364
+ }
1365
+ const inMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+IN\s*\(([^)]+)\)$/i);
1366
+ if (inMatch) {
1367
+ const col = camelCase ? toCamelCase(inMatch[1]) : inMatch[1];
1368
+ const values = inMatch[2].split(',').map(v => v.trim());
1369
+ return `table.${col}.in([${values.join(', ')}])`;
1370
+ }
1371
+ const notInMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+NOT\s+IN\s*\(([^)]+)\)$/i);
1372
+ if (notInMatch) {
1373
+ const col = camelCase ? toCamelCase(notInMatch[1]) : notInMatch[1];
1374
+ const values = notInMatch[2].split(',').map(v => v.trim());
1375
+ return `table.${col}.notIn([${values.join(', ')}])`;
1376
+ }
1377
+ const regexMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+(~\*|~)\s+'([^']+)'$/i);
1378
+ if (regexMatch) {
1379
+ const col = camelCase ? toCamelCase(regexMatch[1]) : regexMatch[1];
1380
+ const pattern = regexMatch[3].replace(/\\/g, '\\\\').replace(/'/g, "\\'");
1381
+ const method = regexMatch[2] === '~*' ? 'matchesInsensitive' : 'matches';
1382
+ return `table.${col}.${method}('${pattern}')`;
1383
+ }
1384
+ const lengthMatch = expr.match(/^LENGTH\(([a-z_][a-z0-9_]*)(?:::TEXT)?\)\s*(<=?|>=?|<>|!=|=)\s*(\d+)$/i);
1385
+ if (lengthMatch) {
1386
+ const col = camelCase ? toCamelCase(lengthMatch[1]) : lengthMatch[1];
1387
+ const op = lengthMatch[2];
1388
+ const value = lengthMatch[3];
1389
+ const method = op === '>=' ? 'gte' : op === '<=' ? 'lte' : op === '>' ? 'gt' : op === '<' ? 'lt' : op === '=' ? 'eq' : 'neq';
1390
+ return `table.${col}.asText().length().${method}(${value})`;
1391
+ }
1392
+ const absMatch = expr.match(/^ABS\(([a-z_][a-z0-9_]*)\)\s*(<=?|>=?|<>|!=|=)\s*(.+)$/i);
1393
+ if (absMatch) {
1394
+ const col = camelCase ? toCamelCase(absMatch[1]) : absMatch[1];
1395
+ const op = absMatch[2];
1396
+ const value = parseCheckValue(absMatch[3].trim(), camelCase);
1397
+ if (value) {
1398
+ const method = op === '>=' ? 'gte' : op === '<=' ? 'lte' : op === '>' ? 'gt' : op === '<' ? 'lt' : op === '=' ? 'eq' : 'neq';
1399
+ return `table.${col}.abs().${method}(${value})`;
1400
+ }
1401
+ }
1402
+ const arithmeticMatch = expr.match(/^([a-z_][a-z0-9_]*)\s*([+\-])\s*([a-z_][a-z0-9_]*)\s*(<=?|>=?|<>|!=|=)\s*(.+)$/i);
1403
+ if (arithmeticMatch) {
1404
+ const col1 = camelCase ? toCamelCase(arithmeticMatch[1]) : arithmeticMatch[1];
1405
+ const op = arithmeticMatch[2];
1406
+ const col2 = camelCase ? toCamelCase(arithmeticMatch[3]) : arithmeticMatch[3];
1407
+ const cmpOp = arithmeticMatch[4];
1408
+ const value = parseCheckValue(arithmeticMatch[5].trim(), camelCase);
1409
+ if (value) {
1410
+ const arithMethod = op === '+' ? 'plus' : 'minus';
1411
+ const cmpMethod = cmpOp === '>=' ? 'gte' : cmpOp === '<=' ? 'lte' : cmpOp === '>' ? 'gt' : cmpOp === '<' ? 'lt' : cmpOp === '=' ? 'eq' : 'neq';
1412
+ return `table.${col1}.${arithMethod}(table.${col2}).${cmpMethod}(${value})`;
1413
+ }
1414
+ }
1415
+ const comparisonMatch = expr.match(/^([a-z_][a-z0-9_]*)\s*(<=?|>=?|<>|!=|=)\s*(.+)$/i);
1416
+ if (comparisonMatch) {
1417
+ const col = camelCase ? toCamelCase(comparisonMatch[1]) : comparisonMatch[1];
1418
+ const op = comparisonMatch[2];
1419
+ const value = parseCheckValue(comparisonMatch[3].trim(), camelCase);
1420
+ if (value) {
1421
+ const method = op === '>=' ? 'gte' : op === '<=' ? 'lte' : op === '>' ? 'gt' : op === '<' ? 'lt' : op === '=' ? 'eq' : 'neq';
1422
+ return `table.${col}.${method}(${value})`;
1423
+ }
1424
+ }
1425
+ return null;
1426
+ }
1427
+ function parseCheckValue(value, camelCase) {
1428
+ value = value.trim();
1429
+ if (/^-?\d+(\.\d+)?$/.test(value)) {
1430
+ return value;
1431
+ }
1432
+ if (/^TRUE$/i.test(value))
1433
+ return 'true';
1434
+ if (/^FALSE$/i.test(value))
1435
+ return 'false';
1436
+ if (/^'.*'$/.test(value)) {
1437
+ return value;
1438
+ }
1439
+ if (/^NULL$/i.test(value)) {
1440
+ return 'null';
1441
+ }
1442
+ if (/^[a-z_][a-z0-9_]*$/i.test(value)) {
1443
+ const col = camelCase ? toCamelCase(value) : value;
1444
+ return `table.${col}`;
1445
+ }
1446
+ return null;
1447
+ }
1448
+ function splitCheckByOperator(expr, operator) {
1449
+ if (operator === 'AND' && /\bBETWEEN\b.*\bAND\b/i.test(expr)) {
1450
+ const betweenMatch = expr.match(/^([a-z_][a-z0-9_]*)\s+BETWEEN\s+\S+\s+AND\s+\S+$/i);
1451
+ if (betweenMatch) {
1452
+ return null;
1453
+ }
1454
+ }
1455
+ const parts = [];
1456
+ let current = '';
1457
+ let parenDepth = 0;
1458
+ let i = 0;
1459
+ while (i < expr.length) {
1460
+ const char = expr[i];
1461
+ if (char === '(') {
1462
+ parenDepth++;
1463
+ current += char;
1464
+ i++;
1465
+ }
1466
+ else if (char === ')') {
1467
+ parenDepth--;
1468
+ current += char;
1469
+ i++;
1470
+ }
1471
+ else if (parenDepth === 0) {
1472
+ const remaining = expr.slice(i);
1473
+ const match = remaining.match(new RegExp(`^\\s+${operator}\\s+`, 'i'));
1474
+ if (match) {
1475
+ if (operator === 'AND' && /\bBETWEEN\s+\S+$/i.test(current.trim())) {
1476
+ current += match[0];
1477
+ i += match[0].length;
1478
+ continue;
1479
+ }
1480
+ if (current.trim()) {
1481
+ parts.push(current.trim());
1482
+ }
1483
+ current = '';
1484
+ i += match[0].length;
1485
+ }
1486
+ else {
1487
+ current += char;
1488
+ i++;
1489
+ }
1490
+ }
1491
+ else {
1492
+ current += char;
1493
+ i++;
1494
+ }
1495
+ }
1496
+ if (current.trim()) {
1497
+ parts.push(current.trim());
1498
+ }
1499
+ return parts.length > 1 ? parts : null;
1500
+ }
1501
+ function generateCheckConstraints(constraints, camelCase) {
1502
+ const checkConstraints = constraints.filter(c => {
1503
+ if (c.type !== 'CHECK')
1504
+ return false;
1505
+ if (/::text\s*=\s*ANY/i.test(c.definition))
1506
+ return false;
1507
+ return true;
1508
+ });
1509
+ if (checkConstraints.length === 0)
1510
+ return null;
1511
+ const lines = [];
1512
+ for (const check of checkConstraints) {
1513
+ let expr = check.definition.trim();
1514
+ const checkMatch = expr.match(/CHECK\s*\(/i);
1515
+ if (checkMatch && checkMatch.index !== undefined) {
1516
+ const startIdx = checkMatch.index + checkMatch[0].length;
1517
+ let depth = 1;
1518
+ let endIdx = startIdx;
1519
+ for (let i = startIdx; i < expr.length && depth > 0; i++) {
1520
+ if (expr[i] === '(')
1521
+ depth++;
1522
+ else if (expr[i] === ')')
1523
+ depth--;
1524
+ if (depth === 0)
1525
+ endIdx = i;
1526
+ }
1527
+ if (endIdx > startIdx) {
1528
+ expr = expr.substring(startIdx, endIdx).trim();
1529
+ }
1530
+ }
1531
+ else if (expr.startsWith('(') && expr.endsWith(')')) {
1532
+ expr = expr.slice(1, -1).trim();
1533
+ }
1534
+ const parsed = parseCheckExpression(expr, camelCase);
1535
+ if (parsed) {
1536
+ lines.push(` check.constraint('${check.name}', ${parsed})`);
1537
+ }
1538
+ }
1539
+ if (lines.length === 0)
1540
+ return null;
1541
+ return `(table, check) => [\n${lines.join(',\n')},\n ]`;
1542
+ }
1543
+ function generateDefineTable(table, camelCase = true, childPartitions, enumNames, domainNames, compositeNames, domainMap) {
1544
+ const tableName = toCamelCase(table.name);
1545
+ const seenColumns = new Set();
1546
+ const checkConstraints = (table.constraints || []).filter(c => c.type === 'CHECK');
1547
+ const columnChecks = new Map();
1548
+ for (const check of checkConstraints) {
1549
+ const enumMatch = check.definition.match(/\((\w+)\)::text\s*=\s*ANY\s*\(\s*(?:ARRAY\[)?([^\]]+)\]/i);
1550
+ if (enumMatch) {
1551
+ const colName = enumMatch[1];
1552
+ const valuesStr = enumMatch[2];
1553
+ const values = valuesStr
1554
+ .match(/'([^']+)'/g)
1555
+ ?.map(v => v.replace(/'/g, '')) || [];
1556
+ if (values.length > 0) {
1557
+ columnChecks.set(colName.toLowerCase(), values);
1558
+ }
1559
+ }
1560
+ }
1561
+ const columns = table.columns
1562
+ .map(col => generateColumnDef(col, seenColumns, camelCase, columnChecks.get(col.name.toLowerCase()), enumNames, domainNames, compositeNames, domainMap))
1563
+ .filter(Boolean);
1564
+ const columnNames = Array.from(seenColumns);
1565
+ const indexesFn = table.indexes ? generateIndexes(table.indexes, columnNames, camelCase) : null;
1566
+ const checkConstraintsFn = table.constraints ? generateCheckConstraints(table.constraints, camelCase) : null;
1567
+ const hasPartition = table.isPartitioned && table.partitionType && table.partitionKey?.length;
1568
+ const hasChildPartitions = childPartitions && childPartitions.length > 0;
1569
+ if (hasPartition || indexesFn || hasChildPartitions || checkConstraintsFn) {
1570
+ const parts = [];
1571
+ if (hasPartition) {
1572
+ let rawPartitionKey = table.partitionKey || [];
1573
+ if (typeof rawPartitionKey === 'string') {
1574
+ rawPartitionKey = rawPartitionKey
1575
+ .replace(/^\{|\}$/g, '')
1576
+ .split(',')
1577
+ .map(k => k.trim())
1578
+ .filter(Boolean);
1579
+ }
1580
+ if (!Array.isArray(rawPartitionKey)) {
1581
+ rawPartitionKey = [String(rawPartitionKey)];
1582
+ }
1583
+ const cleanedPartitionKey = rawPartitionKey.map((k) => {
1584
+ return k.replace(/^\{|\}$/g, '').trim();
1585
+ }).filter(Boolean);
1586
+ const partitionCol = camelCase ? toCamelCase(cleanedPartitionKey[0]) : cleanedPartitionKey[0];
1587
+ const partitionTypeLC = (table.partitionType || 'LIST').toLowerCase();
1588
+ if (partitionTypeLC === 'hash') {
1589
+ parts.push(` partitionBy: (table, p) => p.hash(table.${partitionCol}, 4)`);
1590
+ }
1591
+ else {
1592
+ parts.push(` partitionBy: (table, p) => p.${partitionTypeLC}(table.${partitionCol})`);
1593
+ }
1594
+ }
1595
+ if (hasChildPartitions && childPartitions) {
1596
+ const partitionLines = childPartitions.map(cp => {
1597
+ const bound = cp.partitionBound || '';
1598
+ if (bound.includes('DEFAULT')) {
1599
+ return ` partition('${cp.name}').default()`;
1600
+ }
1601
+ const listMatch = bound.match(/IN\s*\(([^)]+)\)/i);
1602
+ if (listMatch) {
1603
+ const valuesStr = listMatch[1];
1604
+ const values = valuesStr.match(/'([^']+)'/g)?.map((v) => v.replace(/'/g, '')) || [];
1605
+ return ` partition('${cp.name}').in([${values.map((v) => `'${v}'`).join(', ')}])`;
1606
+ }
1607
+ const rangeMatch = bound.match(/FROM\s*\(([^)]+)\)\s*TO\s*\(([^)]+)\)/i);
1608
+ if (rangeMatch) {
1609
+ const from = rangeMatch[1].replace(/'/g, '').trim();
1610
+ const to = rangeMatch[2].replace(/'/g, '').trim();
1611
+ return ` partition('${cp.name}').from('${from}').to('${to}')`;
1612
+ }
1613
+ const hashMatch = bound.match(/MODULUS\s+(\d+),\s*REMAINDER\s+(\d+)/i);
1614
+ if (hashMatch) {
1615
+ const remainder = parseInt(hashMatch[2], 10);
1616
+ return ` partition('${cp.name}').remainder(${remainder})`;
1617
+ }
1618
+ return ` // Unknown partition: ${cp.name} - ${bound}`;
1619
+ });
1620
+ parts.push(` partitions: (partition) => [\n${partitionLines.join(',\n')},\n ]`);
1621
+ }
1622
+ if (checkConstraintsFn) {
1623
+ parts.push(` checkConstraints: ${checkConstraintsFn.trim()}`);
1624
+ }
1625
+ if (indexesFn) {
1626
+ parts.push(` indexes: ${indexesFn.trim()}`);
1627
+ }
1628
+ const jsDoc = table.comment ? `/**\n * ${table.comment.replace(/\*\//g, '* /')}\n */\n` : '';
1629
+ return `${jsDoc}export const ${tableName} = defineTable('${table.name}', {
1630
+ ${columns.join(',\n')},
1631
+ }, {
1632
+ ${parts.join(',\n')},
1633
+ })`;
1634
+ }
1635
+ const jsDoc = table.comment ? `/**\n * ${table.comment.replace(/\*\//g, '* /')}\n */\n` : '';
1636
+ return `${jsDoc}export const ${tableName} = defineTable('${table.name}', {
1637
+ ${columns.join(',\n')},
1638
+ })`;
1639
+ }
1640
+ export function generateTypeScript(schema, options = {}) {
1641
+ const { includeDefineTables = true, includeSchema = true, includeFunctions = true, includeTriggers = true, camelCase = true, importPath = 'relq/schema-builder', } = options;
1642
+ const partitionTableNames = new Set(schema.partitions.map((p) => p.name.toLowerCase()));
1643
+ const tables = schema.tables.filter(t => !EXCLUDED_TABLES.includes(t.name.toLowerCase()) &&
1644
+ !partitionTableNames.has(t.name.toLowerCase()));
1645
+ const parts = [
1646
+ '/**',
1647
+ ' * Auto-generated by Relq CLI',
1648
+ ` * Generated at: ${new Date().toISOString()}`,
1649
+ ' * DO NOT EDIT - changes will be overwritten',
1650
+ ' */',
1651
+ '',
1652
+ ];
1653
+ const imports = new Set(['defineTable']);
1654
+ for (const table of tables) {
1655
+ for (const col of table.columns) {
1656
+ const rawType = col.dataType.toLowerCase().replace(/^_/, '');
1657
+ const pgType = rawType.replace(/\([^)]*\)$/, '').trim();
1658
+ if (['int4', 'integer'].includes(pgType))
1659
+ imports.add('integer');
1660
+ else if (['int2', 'smallint'].includes(pgType))
1661
+ imports.add('smallint');
1662
+ else if (['int8', 'bigint'].includes(pgType))
1663
+ imports.add('bigint');
1664
+ else if (['serial', 'serial4'].includes(pgType))
1665
+ imports.add('serial');
1666
+ else if (['serial8', 'bigserial'].includes(pgType))
1667
+ imports.add('bigserial');
1668
+ else if (['float4', 'real'].includes(pgType))
1669
+ imports.add('real');
1670
+ else if (['float8', 'double precision'].includes(pgType))
1671
+ imports.add('doublePrecision');
1672
+ else if (pgType === 'numeric' || pgType === 'decimal')
1673
+ imports.add('numeric');
1674
+ else if (pgType === 'text')
1675
+ imports.add('text');
1676
+ else if (pgType === 'varchar' || pgType === 'character varying')
1677
+ imports.add('varchar');
1678
+ else if (pgType === 'char' || pgType === 'character' || pgType === 'bpchar')
1679
+ imports.add('char');
1680
+ else if (pgType === 'boolean' || pgType === 'bool')
1681
+ imports.add('boolean');
1682
+ else if (pgType === 'uuid')
1683
+ imports.add('uuid');
1684
+ else if (pgType === 'jsonb')
1685
+ imports.add('jsonb');
1686
+ else if (pgType === 'json')
1687
+ imports.add('json');
1688
+ else if (pgType === 'timestamp' || pgType === 'timestamptz')
1689
+ imports.add('timestamp');
1690
+ else if (pgType === 'date')
1691
+ imports.add('date');
1692
+ else if (pgType === 'time' || pgType === 'timetz')
1693
+ imports.add('time');
1694
+ else if (pgType === 'interval')
1695
+ imports.add('interval');
1696
+ else if (pgType === 'bytea')
1697
+ imports.add('bytea');
1698
+ else if (pgType === 'inet')
1699
+ imports.add('inet');
1700
+ else if (pgType === 'tsvector')
1701
+ imports.add('tsvector');
1702
+ else if (pgType === 'tsquery')
1703
+ imports.add('tsquery');
1704
+ else if (pgType === 'vector')
1705
+ imports.add('vector');
1706
+ else if (pgType === 'citext')
1707
+ imports.add('citext');
1708
+ else if (pgType === 'hstore')
1709
+ imports.add('hstore');
1710
+ else if (pgType === 'ltree')
1711
+ imports.add('ltree');
1712
+ else if (pgType === 'lquery')
1713
+ imports.add('lquery');
1714
+ else if (pgType === 'ltxtquery')
1715
+ imports.add('ltxtquery');
1716
+ else if (pgType === 'cube')
1717
+ imports.add('cube');
1718
+ else
1719
+ imports.add('text');
1720
+ if (col.defaultValue) {
1721
+ const d = col.defaultValue.toLowerCase();
1722
+ if (d.includes('gen_random_uuid') || d.includes('uuid_generate')) {
1723
+ imports.add('genRandomUuid');
1724
+ }
1725
+ if (d.includes('now()') || d.includes('current_timestamp'))
1726
+ imports.add('now');
1727
+ if (d.includes('current_date'))
1728
+ imports.add('currentDate');
1729
+ const isArrayType = col.dataType.endsWith('[]') || col.dataType.startsWith('_');
1730
+ if (d.includes("'{}'")) {
1731
+ if (isArrayType) {
1732
+ imports.add('emptyArray');
1733
+ }
1734
+ else {
1735
+ imports.add('emptyObject');
1736
+ }
1737
+ }
1738
+ if (d.includes("'[]'") || d.includes('array[]'))
1739
+ imports.add('emptyArray');
1740
+ }
1741
+ }
1742
+ }
1743
+ const userFunctions = schema.functions?.filter((f) => !f.name.startsWith('pg_') &&
1744
+ !EXCLUDED_FUNCTIONS.some(ex => f.name.startsWith(ex) || f.name === ex)) || [];
1745
+ if (includeFunctions && userFunctions.length > 0) {
1746
+ imports.add('pgFunction');
1747
+ }
1748
+ if (includeTriggers && schema.triggers && schema.triggers.length > 0) {
1749
+ imports.add('pgTrigger');
1750
+ }
1751
+ if (schema.sequences && schema.sequences.length > 0) {
1752
+ imports.add('pgSequence');
1753
+ }
1754
+ if (schema.enums && schema.enums.length > 0) {
1755
+ imports.add('pgEnum');
1756
+ }
1757
+ if (schema.domains && schema.domains.length > 0) {
1758
+ imports.add('pgDomain');
1759
+ for (const domainDef of schema.domains) {
1760
+ const rawType = domainDef.baseType.toLowerCase().replace(/^_/, '');
1761
+ const pgType = rawType.replace(/\([^)]*\)$/, '').trim();
1762
+ if (['int4', 'integer'].includes(pgType))
1763
+ imports.add('integer');
1764
+ else if (['int2', 'smallint'].includes(pgType))
1765
+ imports.add('smallint');
1766
+ else if (['int8', 'bigint'].includes(pgType))
1767
+ imports.add('bigint');
1768
+ else if (['float4', 'real'].includes(pgType))
1769
+ imports.add('real');
1770
+ else if (['float8', 'double precision'].includes(pgType))
1771
+ imports.add('doublePrecision');
1772
+ else if (pgType === 'numeric' || pgType === 'decimal')
1773
+ imports.add('numeric');
1774
+ else if (pgType === 'text')
1775
+ imports.add('text');
1776
+ else if (pgType === 'varchar' || pgType === 'character varying')
1777
+ imports.add('varchar');
1778
+ else if (pgType === 'char' || pgType === 'character' || pgType === 'bpchar')
1779
+ imports.add('char');
1780
+ else if (pgType === 'boolean' || pgType === 'bool')
1781
+ imports.add('boolean');
1782
+ else if (pgType === 'uuid')
1783
+ imports.add('uuid');
1784
+ else if (pgType === 'inet')
1785
+ imports.add('inet');
1786
+ else if (pgType === 'citext')
1787
+ imports.add('citext');
1788
+ }
1789
+ }
1790
+ if (schema.compositeTypes && schema.compositeTypes.length > 0) {
1791
+ imports.add('pgComposite');
1792
+ for (const composite of schema.compositeTypes) {
1793
+ for (const attr of composite.attributes || []) {
1794
+ const rawType = attr.type.toLowerCase().replace(/^_/, '');
1795
+ const pgType = rawType.replace(/\([^)]*\)$/, '').trim();
1796
+ if (['int4', 'integer'].includes(pgType))
1797
+ imports.add('integer');
1798
+ else if (['int2', 'smallint'].includes(pgType))
1799
+ imports.add('smallint');
1800
+ else if (['int8', 'bigint'].includes(pgType))
1801
+ imports.add('bigint');
1802
+ else if (['float4', 'real'].includes(pgType))
1803
+ imports.add('real');
1804
+ else if (['float8', 'double precision'].includes(pgType))
1805
+ imports.add('doublePrecision');
1806
+ else if (pgType === 'numeric' || pgType === 'decimal')
1807
+ imports.add('numeric');
1808
+ else if (pgType === 'text')
1809
+ imports.add('text');
1810
+ else if (pgType === 'varchar' || pgType === 'character varying')
1811
+ imports.add('varchar');
1812
+ else if (pgType === 'char' || pgType === 'character' || pgType === 'bpchar')
1813
+ imports.add('char');
1814
+ else if (pgType === 'boolean' || pgType === 'bool')
1815
+ imports.add('boolean');
1816
+ else if (pgType === 'uuid')
1817
+ imports.add('uuid');
1818
+ else if (pgType === 'jsonb')
1819
+ imports.add('jsonb');
1820
+ else if (pgType === 'json')
1821
+ imports.add('json');
1822
+ else if (pgType === 'timestamp' || pgType === 'timestamptz')
1823
+ imports.add('timestamp');
1824
+ else if (pgType === 'date')
1825
+ imports.add('date');
1826
+ else if (pgType === 'time' || pgType === 'timetz')
1827
+ imports.add('time');
1828
+ else if (pgType === 'inet')
1829
+ imports.add('inet');
1830
+ }
1831
+ }
1832
+ }
1833
+ if (schema.extensions && schema.extensions.length > 0) {
1834
+ imports.add('pgExtensions');
1835
+ }
1836
+ parts.push(`import {`);
1837
+ parts.push(` ${Array.from(imports).sort().join(',\n ')},`);
1838
+ parts.push(`} from '${importPath}';`);
1839
+ parts.push('');
1840
+ if (schema.enums && schema.enums.length > 0) {
1841
+ parts.push('// ============================================');
1842
+ parts.push('// Enum Definitions');
1843
+ parts.push('// ============================================');
1844
+ parts.push('');
1845
+ for (const enumDef of schema.enums) {
1846
+ const enumName = toCamelCase(enumDef.name) + 'Enum';
1847
+ const values = enumDef.values.map((v) => `'${v}'`).join(', ');
1848
+ parts.push(`export const ${enumName} = pgEnum('${enumDef.name}', [${values}]);`);
1849
+ }
1850
+ parts.push('');
1851
+ }
1852
+ if (schema.domains && schema.domains.length > 0) {
1853
+ parts.push('// ============================================');
1854
+ parts.push('// Domain Type Definitions');
1855
+ parts.push('// ============================================');
1856
+ parts.push('');
1857
+ for (const domainDef of schema.domains) {
1858
+ const domainName = toCamelCase(domainDef.name) + 'Domain';
1859
+ const columnBuilderCall = generateColumnBuilderFromType(domainDef.baseType);
1860
+ if (domainDef.check) {
1861
+ const checkExpr = convertSqlCheckToTypedExpr(domainDef.check);
1862
+ parts.push(`export const ${domainName} = pgDomain('${domainDef.name}',`);
1863
+ parts.push(` ${columnBuilderCall},`);
1864
+ parts.push(` (value) => [${checkExpr}]`);
1865
+ parts.push(`);`);
1866
+ }
1867
+ else {
1868
+ parts.push(`export const ${domainName} = pgDomain('${domainDef.name}', ${columnBuilderCall});`);
1869
+ }
1870
+ }
1871
+ parts.push('');
1872
+ }
1873
+ if (schema.compositeTypes && schema.compositeTypes.length > 0) {
1874
+ parts.push('// ============================================');
1875
+ parts.push('// Composite Type Definitions');
1876
+ parts.push('// ============================================');
1877
+ parts.push('');
1878
+ for (const compDef of schema.compositeTypes) {
1879
+ const compName = toCamelCase(compDef.name) + 'Composite';
1880
+ const fields = (compDef.attributes || [])
1881
+ .map((attr) => {
1882
+ const fieldName = toCamelCase(attr.name);
1883
+ const fieldType = getColumnType({ name: attr.name, dataType: attr.type });
1884
+ return ` ${fieldName}: ${fieldType}`;
1885
+ })
1886
+ .join(',\n');
1887
+ if (fields) {
1888
+ parts.push(`export const ${compName} = pgComposite('${compDef.name}', {`);
1889
+ parts.push(fields);
1890
+ parts.push('});');
1891
+ }
1892
+ else {
1893
+ parts.push(`export const ${compName} = pgComposite('${compDef.name}', {});`);
1894
+ }
1895
+ }
1896
+ parts.push('');
1897
+ }
1898
+ if (includeDefineTables) {
1899
+ parts.push('// ============================================');
1900
+ parts.push('// Table Definitions');
1901
+ parts.push('// ============================================');
1902
+ parts.push('');
1903
+ const enumNames = new Set((schema.enums || []).map((e) => e.name.toLowerCase()));
1904
+ const domainNames = new Set((schema.domains || []).map((d) => d.name.toLowerCase()));
1905
+ const compositeNames = new Set((schema.compositeTypes || []).map((c) => c.name.toLowerCase()));
1906
+ const domainMap = new Map((schema.domains || []).map((d) => [d.name.toLowerCase(), d.baseType]));
1907
+ for (const table of tables) {
1908
+ const childPartitions = schema.partitions.filter((p) => p.parentTable === table.name);
1909
+ parts.push(generateDefineTable(table, camelCase, childPartitions, enumNames, domainNames, compositeNames, domainMap));
1910
+ parts.push('');
1911
+ }
1912
+ }
1913
+ parts.push('// ============================================');
1914
+ parts.push('// Type Exports');
1915
+ parts.push('// ============================================');
1916
+ parts.push('');
1917
+ for (const table of tables) {
1918
+ const tableName = toCamelCase(table.name);
1919
+ const typeName = toPascalCase(table.name);
1920
+ parts.push(`export type ${typeName} = typeof ${tableName}.$inferSelect;`);
1921
+ parts.push(`export type New${typeName} = typeof ${tableName}.$inferInsert;`);
1922
+ }
1923
+ parts.push('');
1924
+ if (schema.sequences && schema.sequences.length > 0) {
1925
+ parts.push('// ============================================');
1926
+ parts.push('// Database Sequences');
1927
+ parts.push('// ============================================');
1928
+ parts.push('');
1929
+ for (const seq of schema.sequences) {
1930
+ const seqName = toCamelCase(seq.name);
1931
+ const opts = [];
1932
+ if (seq.dataType) {
1933
+ opts.push(` as: '${seq.dataType}'`);
1934
+ }
1935
+ if (seq.start !== undefined) {
1936
+ opts.push(` start: ${seq.start}`);
1937
+ }
1938
+ if (seq.increment !== undefined) {
1939
+ opts.push(` increment: ${seq.increment}`);
1940
+ }
1941
+ if (seq.minValue !== undefined) {
1942
+ opts.push(` minValue: ${seq.minValue === null ? 'null' : seq.minValue}`);
1943
+ }
1944
+ if (seq.maxValue !== undefined) {
1945
+ opts.push(` maxValue: ${seq.maxValue === null ? 'null' : seq.maxValue}`);
1946
+ }
1947
+ if (seq.cache !== undefined) {
1948
+ opts.push(` cache: ${seq.cache}`);
1949
+ }
1950
+ if (seq.cycle !== undefined) {
1951
+ opts.push(` cycle: ${seq.cycle}`);
1952
+ }
1953
+ if (seq.ownedBy) {
1954
+ opts.push(` ownedBy: '${seq.ownedBy}'`);
1955
+ }
1956
+ if (opts.length > 0) {
1957
+ parts.push(`export const ${seqName} = pgSequence('${seq.name}', {`);
1958
+ parts.push(opts.join(',\n') + ',');
1959
+ parts.push(`});`);
1960
+ }
1961
+ else {
1962
+ parts.push(`export const ${seqName} = pgSequence('${seq.name}');`);
1963
+ }
1964
+ parts.push('');
1965
+ }
1966
+ }
1967
+ if (includeFunctions && schema.functions && schema.functions.length > 0) {
1968
+ const userFunctions = schema.functions.filter(f => !f.name.startsWith('pg_') &&
1969
+ !EXCLUDED_FUNCTIONS.some(ex => f.name.startsWith(ex) || f.name === ex));
1970
+ if (userFunctions.length > 0) {
1971
+ parts.push('// ============================================');
1972
+ parts.push('// Database Functions');
1973
+ parts.push('// ============================================');
1974
+ parts.push('');
1975
+ for (const func of userFunctions) {
1976
+ const funcName = toCamelCase(func.name);
1977
+ const escapedDefinition = func.definition
1978
+ .replace(/\\/g, '\\\\')
1979
+ .replace(/`/g, '\\`')
1980
+ .replace(/\${/g, '\\${');
1981
+ const argsStr = func.argTypes && func.argTypes.length > 0
1982
+ ? func.argTypes.map((arg, i) => `{ name: 'arg${i}', type: '${arg}' }`).join(', ')
1983
+ : '';
1984
+ if (func.comment) {
1985
+ const safeComment = func.comment.replace(/\*\//g, '* /');
1986
+ parts.push(`/**\n * ${safeComment}\n */`);
1987
+ }
1988
+ parts.push(`export const ${funcName} = pgFunction('${func.name}', {`);
1989
+ if (argsStr) {
1990
+ parts.push(` args: [${argsStr}],`);
1991
+ }
1992
+ parts.push(` returns: '${func.returnType}',`);
1993
+ parts.push(` language: '${func.language}',`);
1994
+ parts.push(` raw: \`${escapedDefinition}\`,`);
1995
+ parts.push(`});`);
1996
+ parts.push('');
1997
+ }
1998
+ }
1999
+ }
2000
+ if (includeTriggers && schema.triggers && schema.triggers.length > 0) {
2001
+ const tableNames = new Set(tables.map(t => t.name.toLowerCase()));
2002
+ const validTriggers = schema.triggers.filter((t) => tableNames.has(t.tableName.toLowerCase()) &&
2003
+ !partitionTableNames.has(t.tableName.toLowerCase()));
2004
+ if (validTriggers.length > 0) {
2005
+ parts.push('// ============================================');
2006
+ parts.push('// Database Triggers');
2007
+ parts.push('// ============================================');
2008
+ parts.push('');
2009
+ const seenTriggerNames = new Set();
2010
+ for (const trigger of validTriggers) {
2011
+ const tableCamel = toCamelCase(trigger.tableName);
2012
+ const funcCamel = toCamelCase(trigger.functionName);
2013
+ let triggerName = toCamelCase(trigger.name);
2014
+ if (seenTriggerNames.has(triggerName)) {
2015
+ triggerName = `${triggerName}_${tableCamel}`;
2016
+ }
2017
+ seenTriggerNames.add(triggerName);
2018
+ const timing = (trigger.timing || 'AFTER').toUpperCase();
2019
+ const event = (trigger.event || 'INSERT').toUpperCase();
2020
+ const timingProp = timing === 'BEFORE' ? 'before' :
2021
+ timing === 'INSTEAD OF' ? 'insteadOf' : 'after';
2022
+ if (trigger.comment) {
2023
+ const safeComment = trigger.comment.replace(/\*\//g, '* /');
2024
+ parts.push(`/**\n * ${safeComment}\n */`);
2025
+ }
2026
+ parts.push(`export const ${triggerName} = pgTrigger('${trigger.name}', {`);
2027
+ parts.push(` on: ${tableCamel},`);
2028
+ parts.push(` ${timingProp}: '${event}',`);
2029
+ parts.push(` forEachRow: true,`);
2030
+ parts.push(` execute: ${funcCamel},`);
2031
+ parts.push(`});`);
2032
+ parts.push('');
2033
+ }
2034
+ }
2035
+ }
2036
+ if (includeSchema) {
2037
+ parts.push('// ============================================');
2038
+ parts.push('// Schema Export');
2039
+ parts.push('// ============================================');
2040
+ parts.push('');
2041
+ const tableRefs = tables.map(t => ` ${toCamelCase(t.name)},`).join('\n');
2042
+ parts.push('export const schema = {');
2043
+ parts.push(tableRefs);
2044
+ parts.push('} as const;');
2045
+ parts.push('');
2046
+ const schemaTypes = tables.map(t => ` ${toCamelCase(t.name)}: typeof ${toCamelCase(t.name)};`).join('\n');
2047
+ parts.push('export type DatabaseSchema = {');
2048
+ parts.push(schemaTypes);
2049
+ parts.push('};');
2050
+ }
2051
+ if (schema.extensions && schema.extensions.length > 0) {
2052
+ parts.push('');
2053
+ parts.push('// Enabled Extensions');
2054
+ const extArgs = schema.extensions.map((e) => `'${e}'`).join(', ');
2055
+ parts.push(`export const enabledExtensions = pgExtensions(${extArgs});`);
2056
+ }
2057
+ return parts.join('\n');
2058
+ }