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,347 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { isInitialized, getStagedChanges, getUnstagedChanges, getHead, loadCommit, } from "./repo-manager.js";
4
+ const isColorSupported = process.stdout.isTTY && !process.env.NO_COLOR;
5
+ export const colors = {
6
+ red: (s) => isColorSupported ? `\x1b[31m${s}\x1b[0m` : s,
7
+ green: (s) => isColorSupported ? `\x1b[32m${s}\x1b[0m` : s,
8
+ yellow: (s) => isColorSupported ? `\x1b[33m${s}\x1b[0m` : s,
9
+ blue: (s) => isColorSupported ? `\x1b[34m${s}\x1b[0m` : s,
10
+ magenta: (s) => isColorSupported ? `\x1b[35m${s}\x1b[0m` : s,
11
+ cyan: (s) => isColorSupported ? `\x1b[36m${s}\x1b[0m` : s,
12
+ white: (s) => isColorSupported ? `\x1b[37m${s}\x1b[0m` : s,
13
+ gray: (s) => isColorSupported ? `\x1b[90m${s}\x1b[0m` : s,
14
+ bold: (s) => isColorSupported ? `\x1b[1m${s}\x1b[0m` : s,
15
+ dim: (s) => isColorSupported ? `\x1b[2m${s}\x1b[0m` : s,
16
+ };
17
+ export function error(message) {
18
+ console.error(`${colors.red('error:')} ${message}`);
19
+ }
20
+ export function fatal(message) {
21
+ console.error(`${colors.red('fatal:')} ${message}`);
22
+ process.exit(128);
23
+ }
24
+ export function warning(message) {
25
+ console.error(`${colors.yellow('warning:')} ${message}`);
26
+ }
27
+ export function hint(message) {
28
+ console.log(`${colors.yellow('hint:')} ${message}`);
29
+ }
30
+ export function success(message) {
31
+ console.log(`${colors.green('✓')} ${message}`);
32
+ }
33
+ export function info(message) {
34
+ console.log(message);
35
+ }
36
+ export function getWorkingTreeStatus(projectRoot = process.cwd()) {
37
+ const initialized = isInitialized(projectRoot);
38
+ const head = initialized ? getHead(projectRoot) : null;
39
+ const headCommit = head ? loadCommit(head, projectRoot) : null;
40
+ const staged = initialized ? getStagedChanges(projectRoot) : [];
41
+ const unstaged = initialized ? getUnstagedChanges(projectRoot) : [];
42
+ return {
43
+ isInitialized: initialized,
44
+ hasHead: !!head,
45
+ headHash: head,
46
+ headMessage: headCommit?.message || null,
47
+ stagedChanges: staged,
48
+ unstagedChanges: unstaged,
49
+ isClean: staged.length === 0 && unstaged.length === 0,
50
+ hasUncommittedChanges: staged.length > 0,
51
+ hasUnstagedChanges: unstaged.length > 0,
52
+ };
53
+ }
54
+ export function requireRepository(projectRoot = process.cwd()) {
55
+ if (!isInitialized(projectRoot)) {
56
+ fatal('not a relq repository (or any of the parent directories): .relq');
57
+ }
58
+ }
59
+ export function requireCleanWorkingTree(projectRoot = process.cwd(), operation = 'operation') {
60
+ const status = getWorkingTreeStatus(projectRoot);
61
+ if (status.isClean) {
62
+ return { clean: true };
63
+ }
64
+ const lines = [];
65
+ if (status.hasUnstagedChanges && status.hasUncommittedChanges) {
66
+ lines.push(`Your local changes would be overwritten by ${operation}.`);
67
+ lines.push(`Please commit your changes or stash them before you ${operation}.`);
68
+ }
69
+ else if (status.hasUncommittedChanges) {
70
+ lines.push(`You have uncommitted changes.`);
71
+ lines.push(`Please commit your changes before you ${operation}.`);
72
+ }
73
+ else {
74
+ lines.push(`You have unstaged changes.`);
75
+ lines.push(`Please stage and commit your changes before you ${operation}.`);
76
+ }
77
+ return { clean: false, message: lines.join('\n') };
78
+ }
79
+ export function printDirtyWorkingTreeError(status, operation) {
80
+ console.log('');
81
+ if (status.hasUnstagedChanges && status.hasUncommittedChanges) {
82
+ error(`Your local changes would be overwritten by ${operation}.`);
83
+ hint(`Commit your changes or stash them before you ${operation}.`);
84
+ }
85
+ else if (status.hasUncommittedChanges) {
86
+ error(`You have uncommitted changes.`);
87
+ hint(`Please commit your changes before you ${operation}.`);
88
+ }
89
+ else {
90
+ error(`You have unstaged changes.`);
91
+ hint(`Please stage and commit your changes before you ${operation}.`);
92
+ }
93
+ console.log('');
94
+ if (status.hasUncommittedChanges) {
95
+ console.log(`Changes to be committed:`);
96
+ console.log(` ${colors.gray('(use "relq restore --staged <file>..." to unstage)')}`);
97
+ console.log('');
98
+ for (const change of status.stagedChanges.slice(0, 10)) {
99
+ const prefix = change.type === 'CREATE' ? 'new' : change.type === 'DROP' ? 'deleted' : 'modified';
100
+ const color = change.type === 'CREATE' ? colors.green : change.type === 'DROP' ? colors.red : colors.yellow;
101
+ console.log(`\t${color(`${prefix}:`.padEnd(12))}${change.objectName}`);
102
+ }
103
+ if (status.stagedChanges.length > 10) {
104
+ console.log(`\t${colors.gray(`... and ${status.stagedChanges.length - 10} more`)}`);
105
+ }
106
+ console.log('');
107
+ }
108
+ if (status.hasUnstagedChanges) {
109
+ console.log(`Changes not staged for commit:`);
110
+ console.log(` ${colors.gray('(use "relq add <file>..." to update what will be committed)')}`);
111
+ console.log(` ${colors.gray('(use "relq restore <file>..." to discard changes in working directory)')}`);
112
+ console.log('');
113
+ for (const change of status.unstagedChanges.slice(0, 10)) {
114
+ const prefix = change.type === 'CREATE' ? 'new' : change.type === 'DROP' ? 'deleted' : 'modified';
115
+ const color = change.type === 'CREATE' ? colors.green : change.type === 'DROP' ? colors.red : colors.yellow;
116
+ console.log(`\t${color(`${prefix}:`.padEnd(12))}${change.objectName}`);
117
+ }
118
+ if (status.unstagedChanges.length > 10) {
119
+ console.log(`\t${colors.gray(`... and ${status.unstagedChanges.length - 10} more`)}`);
120
+ }
121
+ console.log('');
122
+ }
123
+ console.log('Aborting.');
124
+ }
125
+ export function detectConflicts(localChanges, incomingChanges) {
126
+ const conflicts = [];
127
+ const localByKey = new Map();
128
+ for (const change of localChanges) {
129
+ const key = `${change.objectType}:${change.parentName || ''}:${change.objectName}`;
130
+ localByKey.set(key, change);
131
+ }
132
+ const incomingByKey = new Map();
133
+ for (const change of incomingChanges) {
134
+ const key = `${change.objectType}:${change.parentName || ''}:${change.objectName}`;
135
+ incomingByKey.set(key, change);
136
+ }
137
+ for (const [key, localChange] of localByKey) {
138
+ const incomingChange = incomingByKey.get(key);
139
+ if (incomingChange) {
140
+ conflicts.push({
141
+ objectType: localChange.objectType,
142
+ objectName: localChange.objectName,
143
+ localChange,
144
+ incomingChange,
145
+ });
146
+ }
147
+ }
148
+ return {
149
+ hasConflicts: conflicts.length > 0,
150
+ conflicts,
151
+ };
152
+ }
153
+ export function printConflictError(conflictInfo, operation) {
154
+ console.log('');
155
+ error(`Automatic ${operation} failed; fix conflicts and then commit the result.`);
156
+ console.log('');
157
+ console.log(`CONFLICT (content): Merge conflict in schema`);
158
+ console.log('');
159
+ for (const conflict of conflictInfo.conflicts.slice(0, 10)) {
160
+ console.log(` ${colors.red('both modified:')} ${conflict.objectType.toLowerCase()} ${conflict.objectName}`);
161
+ }
162
+ if (conflictInfo.conflicts.length > 10) {
163
+ console.log(` ${colors.gray(`... and ${conflictInfo.conflicts.length - 10} more conflicts`)}`);
164
+ }
165
+ console.log('');
166
+ hint(`Fix conflicts manually and use:`);
167
+ hint(` relq add . - to mark resolution`);
168
+ hint(` relq commit - to complete the ${operation}`);
169
+ console.log('');
170
+ hint(`Or abort the ${operation} with:`);
171
+ hint(` relq ${operation} --abort`);
172
+ console.log('');
173
+ }
174
+ export function checkUncommittedChanges(projectRoot = process.cwd()) {
175
+ const status = getWorkingTreeStatus(projectRoot);
176
+ if (status.isClean) {
177
+ return { status: 'clean' };
178
+ }
179
+ if (status.hasUnstagedChanges) {
180
+ return { status: 'needs_staging', changes: status.unstagedChanges };
181
+ }
182
+ if (status.hasUncommittedChanges) {
183
+ return { status: 'needs_commit', changes: status.stagedChanges };
184
+ }
185
+ return { status: 'clean' };
186
+ }
187
+ export function printMergeStrategyHelp() {
188
+ console.log('');
189
+ console.log('Resolution options:');
190
+ console.log(` ${colors.cyan('--theirs')} Accept all incoming changes (overwrite local)`);
191
+ console.log(` ${colors.cyan('--ours')} Keep all local changes (reject incoming)`);
192
+ console.log(` ${colors.cyan('--force')} Force operation, overwrite local changes`);
193
+ console.log(` ${colors.cyan('--abort')} Abort and restore previous state`);
194
+ console.log('');
195
+ }
196
+ export function validatePostgresSQL(content) {
197
+ const errors = [];
198
+ const warnings = [];
199
+ if (!content.trim()) {
200
+ errors.push('SQL file is empty');
201
+ return { valid: false, errors, warnings };
202
+ }
203
+ const hasValidStatements = /\b(CREATE|ALTER|DROP|INSERT|UPDATE|DELETE|SELECT|GRANT|REVOKE|COMMENT)\b/i.test(content);
204
+ if (!hasValidStatements) {
205
+ errors.push('No valid SQL statements found');
206
+ }
207
+ let contentForQuoteCheck = content;
208
+ contentForQuoteCheck = contentForQuoteCheck.replace(/--[^\n]*/g, '');
209
+ contentForQuoteCheck = contentForQuoteCheck.replace(/\/\*[\s\S]*?\*\//g, '');
210
+ contentForQuoteCheck = contentForQuoteCheck.replace(/\$([a-zA-Z_]*)\$[\s\S]*?\$\1\$/g, '');
211
+ const openParens = (contentForQuoteCheck.match(/\(/g) || []).length;
212
+ const closeParens = (contentForQuoteCheck.match(/\)/g) || []).length;
213
+ if (Math.abs(openParens - closeParens) > 5) {
214
+ errors.push(`Significantly unbalanced parentheses: ${openParens} opening, ${closeParens} closing`);
215
+ }
216
+ const hasPostgresPatterns = (/\bSERIAL\b/i.test(content) ||
217
+ /\bTEXT\b/i.test(content) ||
218
+ /\bJSONB?\b/i.test(content) ||
219
+ /\bUUID\b/i.test(content) ||
220
+ /\bTIMESTAMPTZ\b/i.test(content) ||
221
+ /\bBOOLEAN\b/i.test(content) ||
222
+ /\bCREATE\s+TABLE\b/i.test(content) ||
223
+ /\bCREATE\s+TYPE\b/i.test(content) ||
224
+ /\bCREATE\s+EXTENSION\b/i.test(content));
225
+ if (!hasPostgresPatterns) {
226
+ warnings.push('No PostgreSQL-specific syntax detected. Ensure this is a PostgreSQL schema.');
227
+ }
228
+ if (/\bDROP\s+DATABASE\b/i.test(content)) {
229
+ warnings.push('Found DROP DATABASE statement - this may be dangerous');
230
+ }
231
+ if (/\bTRUNCATE\b/i.test(content)) {
232
+ warnings.push('Found TRUNCATE statement - this will delete data');
233
+ }
234
+ return {
235
+ valid: errors.length === 0,
236
+ errors,
237
+ warnings,
238
+ };
239
+ }
240
+ export function readSQLFile(filePath) {
241
+ const absolutePath = path.resolve(filePath);
242
+ if (!fs.existsSync(absolutePath)) {
243
+ return { error: `pathspec '${filePath}' did not match any files` };
244
+ }
245
+ const stat = fs.statSync(absolutePath);
246
+ if (stat.isDirectory()) {
247
+ return { error: `'${filePath}' is a directory, not a file` };
248
+ }
249
+ const content = fs.readFileSync(absolutePath, 'utf-8');
250
+ const validation = validatePostgresSQL(content);
251
+ return { content, validation };
252
+ }
253
+ export function createSpinner() {
254
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
255
+ let frameIndex = 0;
256
+ let interval = null;
257
+ let currentMessage = '';
258
+ return {
259
+ start(message) {
260
+ currentMessage = message;
261
+ if (process.stdout.isTTY) {
262
+ interval = setInterval(() => {
263
+ process.stdout.write(`\r${frames[frameIndex]} ${currentMessage}`);
264
+ frameIndex = (frameIndex + 1) % frames.length;
265
+ }, 80);
266
+ }
267
+ else {
268
+ console.log(` ${message}...`);
269
+ }
270
+ },
271
+ stop() {
272
+ if (interval) {
273
+ clearInterval(interval);
274
+ interval = null;
275
+ if (process.stdout.isTTY) {
276
+ process.stdout.write('\r' + ' '.repeat(currentMessage.length + 4) + '\r');
277
+ }
278
+ }
279
+ },
280
+ succeed(message) {
281
+ this.stop();
282
+ console.log(`${colors.green('✓')} ${message}`);
283
+ },
284
+ fail(message) {
285
+ this.stop();
286
+ console.log(`${colors.red('✗')} ${message}`);
287
+ },
288
+ info(message) {
289
+ this.stop();
290
+ console.log(`${colors.blue('ℹ')} ${message}`);
291
+ },
292
+ };
293
+ }
294
+ import * as readline from 'readline';
295
+ export function confirm(question, defaultYes = true) {
296
+ const rl = readline.createInterface({
297
+ input: process.stdin,
298
+ output: process.stdout,
299
+ });
300
+ const suffix = defaultYes ? '[Y/n]' : '[y/N]';
301
+ return new Promise((resolve) => {
302
+ rl.question(`${question} ${colors.gray(suffix)} `, (answer) => {
303
+ rl.close();
304
+ const a = answer.trim().toLowerCase();
305
+ if (!a)
306
+ resolve(defaultYes);
307
+ else
308
+ resolve(a === 'y' || a === 'yes');
309
+ });
310
+ });
311
+ }
312
+ export function select(question, options) {
313
+ const rl = readline.createInterface({
314
+ input: process.stdin,
315
+ output: process.stdout,
316
+ });
317
+ console.log(question);
318
+ options.forEach((opt, i) => {
319
+ console.log(` ${i + 1}) ${opt}`);
320
+ });
321
+ return new Promise((resolve) => {
322
+ rl.question(`${colors.gray('Select [1-' + options.length + ']:')} `, (answer) => {
323
+ rl.close();
324
+ const num = parseInt(answer.trim(), 10);
325
+ if (num >= 1 && num <= options.length) {
326
+ resolve(num - 1);
327
+ }
328
+ else {
329
+ resolve(0);
330
+ }
331
+ });
332
+ });
333
+ }
334
+ export function formatBytes(bytes) {
335
+ if (bytes < 1024)
336
+ return `${bytes} B`;
337
+ if (bytes < 1024 * 1024)
338
+ return `${(bytes / 1024).toFixed(1)} KB`;
339
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
340
+ }
341
+ export function formatDuration(ms) {
342
+ if (ms < 1000)
343
+ return `${ms}ms`;
344
+ if (ms < 60000)
345
+ return `${(ms / 1000).toFixed(1)}s`;
346
+ return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
347
+ }
@@ -0,0 +1,263 @@
1
+ export function generateMigration(diff, options = {}) {
2
+ const { includeDown = true } = options;
3
+ const up = [];
4
+ const down = [];
5
+ for (const table of diff.tables.filter(t => t.action === 'remove')) {
6
+ up.push(...generateDropTable(table));
7
+ if (includeDown && table.before) {
8
+ down.unshift(...generateCreateTable(table.before));
9
+ }
10
+ }
11
+ for (const table of diff.tables.filter(t => t.action === 'add')) {
12
+ if (table.after) {
13
+ up.push(...generateCreateTable(table.after));
14
+ if (includeDown) {
15
+ down.unshift(`DROP TABLE IF EXISTS "${table.name}" CASCADE;`);
16
+ }
17
+ }
18
+ }
19
+ for (const table of diff.tables.filter(t => t.action === 'modify')) {
20
+ const { upSQL, downSQL } = generateAlterTable(table, includeDown);
21
+ up.push(...upSQL);
22
+ down.unshift(...downSQL);
23
+ }
24
+ return { up, down };
25
+ }
26
+ export function generateMigrationFile(diff, name, options = {}) {
27
+ const { message, includeComments = true } = options;
28
+ const { up, down } = generateMigration(diff, options);
29
+ const lines = [];
30
+ lines.push(`-- Migration: ${name}`);
31
+ if (message) {
32
+ lines.push(`-- ${message}`);
33
+ }
34
+ lines.push(`-- Generated: ${new Date().toISOString()}`);
35
+ lines.push('');
36
+ lines.push('-- UP');
37
+ if (up.length === 0) {
38
+ lines.push('-- No changes');
39
+ }
40
+ else {
41
+ if (includeComments) {
42
+ lines.push(`-- ${diff.summary.tablesAdded} tables added, ${diff.summary.tablesRemoved} removed, ${diff.summary.tablesModified} modified`);
43
+ }
44
+ lines.push('');
45
+ lines.push(...up);
46
+ }
47
+ lines.push('');
48
+ lines.push('-- DOWN');
49
+ if (down.length === 0) {
50
+ lines.push('-- No rollback');
51
+ }
52
+ else {
53
+ lines.push('');
54
+ lines.push(...down);
55
+ }
56
+ return {
57
+ name,
58
+ content: lines.join('\n'),
59
+ upSQL: up,
60
+ downSQL: down,
61
+ };
62
+ }
63
+ function generateCreateTable(table) {
64
+ const sql = [];
65
+ const columnDefs = [];
66
+ const constraintDefs = [];
67
+ for (const col of table.columns) {
68
+ columnDefs.push(` ${generateColumnDefinition(col)}`);
69
+ }
70
+ const hasPKColumn = table.columns.some(c => c.isPrimaryKey);
71
+ for (const con of table.constraints || []) {
72
+ if (con.type === 'PRIMARY KEY' && hasPKColumn)
73
+ continue;
74
+ constraintDefs.push(` CONSTRAINT "${con.name}" ${con.definition}`);
75
+ }
76
+ const allDefs = [...columnDefs, ...constraintDefs];
77
+ let createSQL = `CREATE TABLE "${table.name}" (\n${allDefs.join(',\n')}\n)`;
78
+ if (table.isPartitioned && table.partitionType && table.partitionKey?.length) {
79
+ createSQL += ` PARTITION BY ${table.partitionType} (${table.partitionKey.join(', ')})`;
80
+ }
81
+ sql.push(createSQL + ';');
82
+ for (const idx of table.indexes || []) {
83
+ if (idx.isPrimary)
84
+ continue;
85
+ sql.push(generateCreateIndex(table.name, idx));
86
+ }
87
+ return sql;
88
+ }
89
+ function generateDropTable(table) {
90
+ return [`DROP TABLE IF EXISTS "${table.name}" CASCADE;`];
91
+ }
92
+ function generateAlterTable(table, includeDown) {
93
+ const upSQL = [];
94
+ const downSQL = [];
95
+ const tableName = table.name;
96
+ for (const col of table.columns || []) {
97
+ const { up, down } = generateColumnChange(tableName, col);
98
+ upSQL.push(...up);
99
+ if (includeDown)
100
+ downSQL.unshift(...down);
101
+ }
102
+ for (const idx of table.indexes || []) {
103
+ const { up, down } = generateIndexChange(tableName, idx);
104
+ upSQL.push(...up);
105
+ if (includeDown)
106
+ downSQL.unshift(...down);
107
+ }
108
+ for (const con of table.constraints || []) {
109
+ const { up, down } = generateConstraintChange(tableName, con);
110
+ upSQL.push(...up);
111
+ if (includeDown)
112
+ downSQL.unshift(...down);
113
+ }
114
+ return { upSQL, downSQL };
115
+ }
116
+ function generateColumnDefinition(col) {
117
+ const parts = [`"${col.name}"`, mapDataType(col)];
118
+ if (col.isPrimaryKey) {
119
+ parts.push('PRIMARY KEY');
120
+ }
121
+ if (!col.isNullable && !col.isPrimaryKey) {
122
+ parts.push('NOT NULL');
123
+ }
124
+ if (col.isUnique && !col.isPrimaryKey) {
125
+ parts.push('UNIQUE');
126
+ }
127
+ if (col.defaultValue) {
128
+ parts.push(`DEFAULT ${col.defaultValue}`);
129
+ }
130
+ if (col.references) {
131
+ parts.push(`REFERENCES "${col.references.table}"("${col.references.column}")`);
132
+ }
133
+ return parts.join(' ');
134
+ }
135
+ function generateColumnChange(tableName, col) {
136
+ const up = [];
137
+ const down = [];
138
+ if (col.action === 'add' && col.after) {
139
+ up.push(`ALTER TABLE "${tableName}" ADD COLUMN ${generateColumnDefinition(col.after)};`);
140
+ down.push(`ALTER TABLE "${tableName}" DROP COLUMN IF EXISTS "${col.name}";`);
141
+ }
142
+ if (col.action === 'remove' && col.before) {
143
+ up.push(`ALTER TABLE "${tableName}" DROP COLUMN IF EXISTS "${col.name}";`);
144
+ down.push(`ALTER TABLE "${tableName}" ADD COLUMN ${generateColumnDefinition(col.before)};`);
145
+ }
146
+ if (col.action === 'modify' && col.changesV2 && col.before && col.after) {
147
+ if (col.changesV2.type) {
148
+ const newType = mapDataType(col.after);
149
+ up.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" TYPE ${newType} USING "${col.name}"::${newType};`);
150
+ down.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" TYPE ${mapDataType(col.before)} USING "${col.name}"::${mapDataType(col.before)};`);
151
+ }
152
+ if (col.changesV2.nullable) {
153
+ if (col.changesV2.nullable.to) {
154
+ up.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" DROP NOT NULL;`);
155
+ down.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" SET NOT NULL;`);
156
+ }
157
+ else {
158
+ up.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" SET NOT NULL;`);
159
+ down.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" DROP NOT NULL;`);
160
+ }
161
+ }
162
+ if (col.changesV2.default) {
163
+ if (col.changesV2.default.to) {
164
+ up.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" SET DEFAULT ${col.changesV2.default.to};`);
165
+ }
166
+ else {
167
+ up.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" DROP DEFAULT;`);
168
+ }
169
+ if (col.changesV2.default.from) {
170
+ down.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" SET DEFAULT ${col.changesV2.default.from};`);
171
+ }
172
+ else {
173
+ down.push(`ALTER TABLE "${tableName}" ALTER COLUMN "${col.name}" DROP DEFAULT;`);
174
+ }
175
+ }
176
+ }
177
+ return { up, down };
178
+ }
179
+ function generateCreateIndex(tableName, idx) {
180
+ const unique = idx.isUnique ? 'UNIQUE ' : '';
181
+ const cols = Array.isArray(idx.columns) ? idx.columns : [idx.columns];
182
+ const colList = cols.map(c => `"${c}"`).join(', ');
183
+ const using = idx.type && idx.type !== 'btree' ? ` USING ${idx.type}` : '';
184
+ return `CREATE ${unique}INDEX IF NOT EXISTS "${idx.name}" ON "${tableName}"${using} (${colList});`;
185
+ }
186
+ function generateIndexChange(tableName, idx) {
187
+ const up = [];
188
+ const down = [];
189
+ if (idx.action === 'add' && idx.after) {
190
+ up.push(generateCreateIndex(tableName, idx.after));
191
+ down.push(`DROP INDEX IF EXISTS "${idx.name}";`);
192
+ }
193
+ if (idx.action === 'remove' && idx.before) {
194
+ up.push(`DROP INDEX IF EXISTS "${idx.name}";`);
195
+ down.push(generateCreateIndex(tableName, idx.before));
196
+ }
197
+ return { up, down };
198
+ }
199
+ function generateConstraintChange(tableName, con) {
200
+ const up = [];
201
+ const down = [];
202
+ if (con.action === 'add' && con.after) {
203
+ up.push(`ALTER TABLE "${tableName}" ADD CONSTRAINT "${con.name}" ${con.after.definition};`);
204
+ down.push(`ALTER TABLE "${tableName}" DROP CONSTRAINT IF EXISTS "${con.name}";`);
205
+ }
206
+ if (con.action === 'remove' && con.before) {
207
+ up.push(`ALTER TABLE "${tableName}" DROP CONSTRAINT IF EXISTS "${con.name}";`);
208
+ down.push(`ALTER TABLE "${tableName}" ADD CONSTRAINT "${con.name}" ${con.before.definition};`);
209
+ }
210
+ return { up, down };
211
+ }
212
+ function mapDataType(col) {
213
+ let type = col.dataType.toUpperCase();
214
+ if ((type === 'VARCHAR' || type === 'CHARACTER VARYING') && col.maxLength) {
215
+ return `VARCHAR(${col.maxLength})`;
216
+ }
217
+ if ((type === 'CHAR' || type === 'CHARACTER' || type === 'BPCHAR') && col.maxLength) {
218
+ return `CHAR(${col.maxLength})`;
219
+ }
220
+ if ((type === 'NUMERIC' || type === 'DECIMAL') && col.precision) {
221
+ if (col.scale) {
222
+ return `NUMERIC(${col.precision}, ${col.scale})`;
223
+ }
224
+ return `NUMERIC(${col.precision})`;
225
+ }
226
+ const typeMap = {
227
+ 'INT4': 'INTEGER',
228
+ 'INT8': 'BIGINT',
229
+ 'INT2': 'SMALLINT',
230
+ 'FLOAT4': 'REAL',
231
+ 'FLOAT8': 'DOUBLE PRECISION',
232
+ 'BOOL': 'BOOLEAN',
233
+ 'TIMESTAMPTZ': 'TIMESTAMP WITH TIME ZONE',
234
+ 'TIMETZ': 'TIME WITH TIME ZONE',
235
+ };
236
+ return typeMap[type] || type;
237
+ }
238
+ export function getNextMigrationNumber(migrationsDir) {
239
+ const fs = require('fs');
240
+ if (!fs.existsSync(migrationsDir)) {
241
+ return '001';
242
+ }
243
+ const files = fs.readdirSync(migrationsDir)
244
+ .filter((f) => f.endsWith('.sql'))
245
+ .sort();
246
+ if (files.length === 0) {
247
+ return '001';
248
+ }
249
+ const lastFile = files[files.length - 1];
250
+ const match = lastFile.match(/^(\d+)/);
251
+ if (match) {
252
+ const num = parseInt(match[1]) + 1;
253
+ return num.toString().padStart(3, '0');
254
+ }
255
+ return '001';
256
+ }
257
+ export function generateTimestampedName(name) {
258
+ const now = new Date();
259
+ const timestamp = now.toISOString()
260
+ .replace(/[-:T]/g, '')
261
+ .slice(0, 14);
262
+ return `${timestamp}_${name.replace(/\s+/g, '_').toLowerCase()}`;
263
+ }
@@ -0,0 +1,74 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ const DEFAULT_PATTERNS = [
4
+ '_relq_*',
5
+ 'pg_*',
6
+ '_temp_*',
7
+ 'tmp_*',
8
+ ];
9
+ export function loadRelqignore(projectRoot = process.cwd()) {
10
+ const ignorePath = path.join(projectRoot, '.relqignore');
11
+ const patterns = [...DEFAULT_PATTERNS];
12
+ if (fs.existsSync(ignorePath)) {
13
+ const content = fs.readFileSync(ignorePath, 'utf-8');
14
+ const lines = content.split('\n');
15
+ for (const line of lines) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed || trimmed.startsWith('#')) {
18
+ continue;
19
+ }
20
+ patterns.push(trimmed);
21
+ }
22
+ }
23
+ return patterns;
24
+ }
25
+ export function createDefaultRelqignore(projectRoot = process.cwd()) {
26
+ const ignorePath = path.join(projectRoot, '.relqignore');
27
+ if (fs.existsSync(ignorePath)) {
28
+ return;
29
+ }
30
+ const content = `# Relq Ignore File
31
+ # Tables and functions matching these patterns will be ignored
32
+
33
+ # Relq internal tables (always ignored)
34
+ _relq_*
35
+
36
+ # PostgreSQL system tables
37
+ pg_*
38
+
39
+ # Temporary tables
40
+ _temp_*
41
+ tmp_*
42
+
43
+ # Add your tables/functions to ignore below:
44
+ # analytics_raw
45
+ # debug_*
46
+ # test_*
47
+ `;
48
+ fs.writeFileSync(ignorePath, content, 'utf-8');
49
+ }
50
+ export function isIgnored(name, patterns) {
51
+ for (const pattern of patterns) {
52
+ if (matchPattern(name, pattern)) {
53
+ return true;
54
+ }
55
+ }
56
+ return false;
57
+ }
58
+ export function filterIgnored(items, patterns) {
59
+ return items.filter(item => !isIgnored(item.name, patterns));
60
+ }
61
+ function matchPattern(name, pattern) {
62
+ if (pattern.startsWith('!')) {
63
+ return !matchPattern(name, pattern.slice(1));
64
+ }
65
+ const regexPattern = pattern
66
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
67
+ .replace(/\*/g, '.*')
68
+ .replace(/\?/g, '.');
69
+ const regex = new RegExp(`^${regexPattern}$`, 'i');
70
+ return regex.test(name);
71
+ }
72
+ export function getIgnorePatterns(projectRoot = process.cwd()) {
73
+ return loadRelqignore(projectRoot);
74
+ }