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,133 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as readline from 'readline';
4
+ import { requireValidConfig } from "../utils/config-loader.js";
5
+ import { getConnectionDescription } from "../utils/env-loader.js";
6
+ const colors = {
7
+ reset: '\x1b[0m',
8
+ bold: '\x1b[1m',
9
+ dim: '\x1b[2m',
10
+ red: '\x1b[31m',
11
+ green: '\x1b[32m',
12
+ yellow: '\x1b[33m',
13
+ cyan: '\x1b[36m',
14
+ };
15
+ function parseMigration(content) {
16
+ const upMatch = content.match(/--\s*UP\s*\n([\s\S]*?)(?=--\s*DOWN|$)/i);
17
+ const downMatch = content.match(/--\s*DOWN\s*\n([\s\S]*?)$/i);
18
+ return {
19
+ up: upMatch?.[1]?.trim() || '',
20
+ down: downMatch?.[1]?.trim() || '',
21
+ };
22
+ }
23
+ function askConfirm(question) {
24
+ const rl = readline.createInterface({
25
+ input: process.stdin,
26
+ output: process.stdout,
27
+ });
28
+ return new Promise((resolve) => {
29
+ rl.question(`${question} [y/N]: `, (answer) => {
30
+ rl.close();
31
+ resolve(answer.trim().toLowerCase() === 'y');
32
+ });
33
+ });
34
+ }
35
+ export async function rollbackCommand(context) {
36
+ const { config, args, flags } = context;
37
+ if (!config) {
38
+ console.error('Error: No configuration found.');
39
+ process.exit(1);
40
+ }
41
+ requireValidConfig(config);
42
+ const connection = config.connection;
43
+ const migrationsDir = config.migrations?.directory || './migrations';
44
+ const tableName = config.migrations?.tableName || '_relq_migrations';
45
+ const count = parseInt(args[0]) || 1;
46
+ const dryRun = flags['dry-run'] === true;
47
+ const force = flags['force'] === true;
48
+ console.log(`${colors.bold}Rolling back ${count} migration(s)...${colors.reset}`);
49
+ console.log(` Connection: ${getConnectionDescription(connection)}`);
50
+ console.log('');
51
+ try {
52
+ const { Pool } = await import("../../addon/pg.js");
53
+ const pool = new Pool({
54
+ host: connection.host,
55
+ port: connection.port || 5432,
56
+ database: connection.database,
57
+ user: connection.user,
58
+ password: connection.password,
59
+ connectionString: connection.url,
60
+ });
61
+ try {
62
+ const result = await pool.query(`
63
+ SELECT name FROM "${tableName}"
64
+ ORDER BY id DESC
65
+ LIMIT $1;
66
+ `, [count]);
67
+ if (result.rows.length === 0) {
68
+ console.log(`${colors.yellow}No migrations to rollback.${colors.reset}`);
69
+ return;
70
+ }
71
+ const toRollback = result.rows.map(r => r.name);
72
+ console.log(`${colors.bold}Migrations to rollback:${colors.reset}`);
73
+ for (const name of toRollback) {
74
+ console.log(` ${colors.red}• ${name}${colors.reset}`);
75
+ }
76
+ console.log('');
77
+ if (!force && !dryRun) {
78
+ const proceed = await askConfirm(`${colors.red}This will undo ${toRollback.length} migration(s). Continue?${colors.reset}`);
79
+ if (!proceed) {
80
+ console.log('Cancelled.');
81
+ return;
82
+ }
83
+ }
84
+ for (const name of toRollback) {
85
+ const filePath = path.join(migrationsDir, name);
86
+ if (!fs.existsSync(filePath)) {
87
+ console.log(`${colors.yellow}⚠️ Migration file not found: ${name}${colors.reset}`);
88
+ continue;
89
+ }
90
+ const content = fs.readFileSync(filePath, 'utf-8');
91
+ const { down } = parseMigration(content);
92
+ if (!down) {
93
+ console.log(`${colors.yellow}⚠️ No DOWN section in: ${name}${colors.reset}`);
94
+ continue;
95
+ }
96
+ if (dryRun) {
97
+ console.log(`${colors.cyan}[dry-run] Would rollback: ${name}${colors.reset}`);
98
+ console.log(`${colors.dim}${down}${colors.reset}`);
99
+ console.log('');
100
+ }
101
+ else {
102
+ console.log(`Rolling back: ${name}...`);
103
+ const client = await pool.connect();
104
+ try {
105
+ await client.query('BEGIN');
106
+ await client.query(down);
107
+ await client.query(`DELETE FROM "${tableName}" WHERE name = $1`, [name]);
108
+ await client.query('COMMIT');
109
+ console.log(` ${colors.green}✓ Rolled back${colors.reset}`);
110
+ }
111
+ catch (error) {
112
+ await client.query('ROLLBACK');
113
+ throw error;
114
+ }
115
+ finally {
116
+ client.release();
117
+ }
118
+ }
119
+ }
120
+ if (!dryRun) {
121
+ console.log('');
122
+ console.log(`${colors.green}✓ Rolled back ${toRollback.length} migration(s).${colors.reset}`);
123
+ }
124
+ }
125
+ finally {
126
+ await pool.end();
127
+ }
128
+ }
129
+ catch (error) {
130
+ console.error('Error:', error instanceof Error ? error.message : error);
131
+ process.exit(1);
132
+ }
133
+ }
@@ -0,0 +1,107 @@
1
+ import { getConnectionDescription } from "../utils/env-loader.js";
2
+ import { colors } from "../utils/spinner.js";
3
+ import { isInitialized, getHead, loadCommit, shortHash, getStagedChanges, getUnstagedChanges, } from "../utils/repo-manager.js";
4
+ export async function statusCommand(context) {
5
+ const { config, flags } = context;
6
+ const projectRoot = process.cwd();
7
+ const connection = config?.connection;
8
+ console.log('');
9
+ if (!isInitialized(projectRoot)) {
10
+ console.log(`${colors.red('fatal:')} not a relq repository`);
11
+ console.log('');
12
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq init')} ${colors.muted('to initialize.')}`);
13
+ console.log('');
14
+ return;
15
+ }
16
+ const head = getHead(projectRoot);
17
+ const staged = getStagedChanges(projectRoot);
18
+ const unstaged = getUnstagedChanges(projectRoot);
19
+ if (head) {
20
+ const headCommit = loadCommit(head, projectRoot);
21
+ console.log(`On commit ${colors.yellow(shortHash(head))}`);
22
+ if (headCommit) {
23
+ console.log(`${colors.muted(`"${headCommit.message}"`)}`);
24
+ }
25
+ }
26
+ else {
27
+ console.log(`${colors.muted('No commits yet')}`);
28
+ }
29
+ if (connection) {
30
+ console.log(`Database: ${colors.cyan(getConnectionDescription(connection))}`);
31
+ }
32
+ console.log('');
33
+ if (staged.length > 0) {
34
+ console.log(`${colors.green('Changes to be committed:')}`);
35
+ console.log(` ${colors.muted('(use "relq restore --staged <name>..." to unstage)')}`);
36
+ console.log('');
37
+ displayChanges(staged, ' ');
38
+ console.log('');
39
+ }
40
+ if (unstaged.length > 0) {
41
+ console.log(`${colors.red('Changes not staged for commit:')}`);
42
+ console.log(` ${colors.muted('(use "relq add <name>..." to stage)')}`);
43
+ console.log(` ${colors.muted('(use "relq restore <name>..." to discard)')}`);
44
+ console.log('');
45
+ displayChanges(unstaged, ' ');
46
+ console.log('');
47
+ }
48
+ if (staged.length === 0 && unstaged.length === 0) {
49
+ console.log(`${colors.green('nothing to commit, working tree clean')}`);
50
+ console.log('');
51
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq pull')} ${colors.muted('to sync with database.')}`);
52
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq import <file>')} ${colors.muted('to import SQL schema.')}`);
53
+ }
54
+ else {
55
+ if (staged.length > 0 && unstaged.length === 0) {
56
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq commit -m "message"')} ${colors.muted('to commit.')}`);
57
+ }
58
+ else if (unstaged.length > 0) {
59
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq add .')} ${colors.muted('to stage all changes.')}`);
60
+ }
61
+ }
62
+ console.log('');
63
+ }
64
+ function displayChanges(changes, indent = '') {
65
+ const byType = new Map();
66
+ for (const change of changes) {
67
+ const key = change.objectType;
68
+ if (!byType.has(key)) {
69
+ byType.set(key, []);
70
+ }
71
+ byType.get(key).push(change);
72
+ }
73
+ const order = ['TABLE', 'COLUMN', 'INDEX', 'CONSTRAINT', 'PRIMARY_KEY', 'FOREIGN_KEY', 'CHECK', 'EXCLUSION', 'EXTENSION', 'ENUM', 'DOMAIN', 'FUNCTION', 'TRIGGER', 'VIEW'];
74
+ const sorted = [...byType.entries()].sort((a, b) => {
75
+ const aIdx = order.indexOf(a[0]);
76
+ const bIdx = order.indexOf(b[0]);
77
+ return (aIdx === -1 ? 999 : aIdx) - (bIdx === -1 ? 999 : bIdx);
78
+ });
79
+ for (const [type, typeChanges] of sorted) {
80
+ for (const change of typeChanges) {
81
+ const color = change.type === 'CREATE' ? colors.green :
82
+ change.type === 'DROP' ? colors.red :
83
+ colors.yellow;
84
+ const typeLabel = getTypeLabel(change.type, change.objectType);
85
+ const objectName = change.parentName
86
+ ? `${change.parentName}.${change.objectName}`
87
+ : change.objectName;
88
+ console.log(`${indent}${color(typeLabel.padEnd(16))} ${objectName}`);
89
+ }
90
+ }
91
+ }
92
+ function getTypeLabel(changeType, objectType) {
93
+ const objectName = objectType.toLowerCase().replace(/_/g, ' ');
94
+ switch (changeType) {
95
+ case 'CREATE':
96
+ return `new ${objectName}:`;
97
+ case 'DROP':
98
+ return `deleted:`;
99
+ case 'ALTER':
100
+ return `modified:`;
101
+ case 'RENAME':
102
+ return `renamed:`;
103
+ default:
104
+ return `${changeType.toLowerCase()}:`;
105
+ }
106
+ }
107
+ export default statusCommand;
@@ -0,0 +1,76 @@
1
+ import { requireValidConfig } from "../utils/config-loader.js";
2
+ import { getConnectionDescription } from "../utils/env-loader.js";
3
+ import { colors, createSpinner } from "../utils/spinner.js";
4
+ import { isInitialized, fetchRemoteCommits, pushCommit, ensureRemoteTable, getAllCommits, getRepoStatus, } from "../utils/repo-manager.js";
5
+ import { pullCommand } from "./pull.js";
6
+ export async function syncCommand(context) {
7
+ const { config, flags } = context;
8
+ if (!config) {
9
+ console.error('Error: No configuration found.');
10
+ process.exit(1);
11
+ }
12
+ requireValidConfig(config);
13
+ const connection = config.connection;
14
+ const projectRoot = process.cwd();
15
+ console.log('');
16
+ if (!isInitialized(projectRoot)) {
17
+ console.log(`${colors.red('fatal:')} not a relq repository`);
18
+ console.log('');
19
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq init')} ${colors.muted('to initialize.')}`);
20
+ return;
21
+ }
22
+ const spinner = createSpinner();
23
+ try {
24
+ spinner.start('Checking sync status...');
25
+ const status = await getRepoStatus(connection, projectRoot);
26
+ spinner.stop();
27
+ console.log(`On database: ${colors.cyan(getConnectionDescription(connection))}`);
28
+ console.log('');
29
+ if (status.behindBy > 0) {
30
+ console.log(`${colors.yellow('↓')} ${status.behindBy} commit(s) to pull`);
31
+ }
32
+ if (status.aheadBy > 0) {
33
+ console.log(`${colors.green('↑')} ${status.aheadBy} commit(s) to push`);
34
+ }
35
+ if (status.behindBy === 0 && status.aheadBy === 0) {
36
+ console.log(`${colors.green('✓')} Already in sync`);
37
+ console.log('');
38
+ return;
39
+ }
40
+ console.log('');
41
+ if (status.behindBy > 0) {
42
+ console.log(`${colors.cyan('●')} Pulling changes...`);
43
+ console.log('');
44
+ const pullContext = {
45
+ ...context,
46
+ flags: { ...flags, force: true },
47
+ };
48
+ await pullCommand(pullContext);
49
+ }
50
+ if (status.aheadBy > 0) {
51
+ console.log(`${colors.cyan('●')} Pushing commits...`);
52
+ console.log('');
53
+ await ensureRemoteTable(connection);
54
+ const localCommits = getAllCommits(projectRoot);
55
+ const remoteCommits = await fetchRemoteCommits(connection, 100);
56
+ const remoteHashes = new Set(remoteCommits.map(c => c.hash));
57
+ const toPush = localCommits.filter(c => !remoteHashes.has(c.hash));
58
+ spinner.start(`Pushing ${toPush.length} commit(s)...`);
59
+ for (const commit of toPush.reverse()) {
60
+ await pushCommit(connection, commit);
61
+ }
62
+ spinner.succeed(`Pushed ${toPush.length} commit(s)`);
63
+ }
64
+ console.log('');
65
+ const pulledText = status.behindBy > 0 ? `${colors.yellow(`↓ ${status.behindBy}`)} pulled` : '';
66
+ const pushedText = status.aheadBy > 0 ? `${colors.green(`↑ ${status.aheadBy}`)} pushed` : '';
67
+ const separator = pulledText && pushedText ? ' | ' : '';
68
+ console.log(`${colors.green('✓')} Sync complete: ${pulledText}${separator}${pushedText}`);
69
+ }
70
+ catch (error) {
71
+ spinner.fail('Sync failed');
72
+ console.error(colors.red(`Error: ${error instanceof Error ? error.message : error}`));
73
+ process.exit(1);
74
+ }
75
+ console.log('');
76
+ }
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env node
2
+ import { initCommand } from "./commands/init.js";
3
+ import { pullCommand } from "./commands/pull.js";
4
+ import { pushCommand } from "./commands/push.js";
5
+ import { generateCommand } from "./commands/generate.js";
6
+ import { introspectCommand } from "./commands/introspect.js";
7
+ import { syncCommand } from "./commands/sync.js";
8
+ import { statusCommand } from "./commands/status.js";
9
+ import { diffCommand } from "./commands/diff.js";
10
+ import { logCommand } from "./commands/log.js";
11
+ import { rollbackCommand } from "./commands/rollback.js";
12
+ import { commitCommand } from "./commands/commit.js";
13
+ import { fetchCommand } from "./commands/fetch.js";
14
+ import { addCommand } from "./commands/add.js";
15
+ import { importCommand } from "./commands/import.js";
16
+ import { exportCommand } from "./commands/export.js";
17
+ const VERSION = '1.1.0';
18
+ function parseArgs(argv) {
19
+ const args = [];
20
+ const flags = {};
21
+ let command = '';
22
+ for (let i = 2; i < argv.length; i++) {
23
+ const arg = argv[i];
24
+ if (arg.startsWith('--')) {
25
+ const eqIndex = arg.indexOf('=');
26
+ if (eqIndex > -1) {
27
+ flags[arg.slice(2, eqIndex)] = arg.slice(eqIndex + 1);
28
+ }
29
+ else {
30
+ flags[arg.slice(2)] = true;
31
+ }
32
+ }
33
+ else if (arg.startsWith('-') && arg.length === 2) {
34
+ const flag = arg.slice(1);
35
+ const nextArg = argv[i + 1];
36
+ if (nextArg && !nextArg.startsWith('-')) {
37
+ flags[flag] = nextArg;
38
+ i++;
39
+ }
40
+ else {
41
+ flags[flag] = true;
42
+ }
43
+ }
44
+ else if (arg.startsWith('-') && arg.length > 2) {
45
+ const combined = arg.slice(1);
46
+ const nextArg = argv[i + 1];
47
+ if (nextArg && !nextArg.startsWith('-')) {
48
+ flags[combined] = nextArg;
49
+ i++;
50
+ }
51
+ else {
52
+ for (const char of combined) {
53
+ flags[char] = true;
54
+ }
55
+ }
56
+ }
57
+ else if (!command) {
58
+ command = arg;
59
+ }
60
+ else {
61
+ args.push(arg);
62
+ }
63
+ }
64
+ return { command, args, flags };
65
+ }
66
+ function printHelp() {
67
+ console.log(`
68
+ Relq CLI v${VERSION} - Database Schema Version Control
69
+
70
+ Usage: relq <command> [options]
71
+
72
+ Schema Commands:
73
+ init Initialize relq for your project
74
+ status [--check] Show current schema state
75
+ add <table>|. Stage changes for commit
76
+ commit -m "msg" Record schema snapshot
77
+ log [--oneline] Show commit history
78
+
79
+ Sync Commands:
80
+ fetch Download remote commits
81
+ pull [--force] Pull schema from database
82
+ push [--dry-run] Push commits to database
83
+ sync Pull + push in one command
84
+
85
+ Other Commands:
86
+ diff [--sql] Show schema differences
87
+ generate Generate TypeScript types
88
+ introspect Parse database schema
89
+ import <sql-file> Import SQL file to schema
90
+ export [file] Export schema to SQL file
91
+
92
+ Options:
93
+ --help, -h Show this help
94
+ --version, -v Show version
95
+ --config <path> Config file path
96
+ --dry-run Preview changes
97
+ --force Skip confirmations
98
+ --force Skip confirmation prompts
99
+
100
+ Examples:
101
+ relq status
102
+ relq diff --sql
103
+ relq generate -m "add users table"
104
+ relq push
105
+ relq rollback 2
106
+ relq sync
107
+
108
+ Environment Variables:
109
+ DATABASE_CONNECTION_STRING Full connection URL
110
+ DATABASE_HOST/PORT/NAME Individual connection parts
111
+ DATABASE_USER/PASSWORD Credentials
112
+ `);
113
+ }
114
+ function printVersion() {
115
+ console.log(`relq v${VERSION}`);
116
+ }
117
+ function requiresConfig(command) {
118
+ return !['init', 'introspect', 'import', 'help', 'version'].includes(command);
119
+ }
120
+ function requiresDbConnection(command, flags) {
121
+ const alwaysNeedDb = ['pull', 'push', 'fetch', 'introspect'];
122
+ if (alwaysNeedDb.includes(command))
123
+ return true;
124
+ if (command === 'export' && flags['db'])
125
+ return true;
126
+ return false;
127
+ }
128
+ async function main() {
129
+ const { command, args, flags } = parseArgs(process.argv);
130
+ if (flags.help || flags.h || command === 'help') {
131
+ printHelp();
132
+ process.exit(0);
133
+ }
134
+ if (flags.version || flags.v || command === 'version') {
135
+ printVersion();
136
+ process.exit(0);
137
+ }
138
+ if (!command) {
139
+ console.error('Error: No command provided\n');
140
+ printHelp();
141
+ process.exit(1);
142
+ }
143
+ let config = null;
144
+ if (requiresConfig(command)) {
145
+ const configPath = flags.config;
146
+ try {
147
+ const { loadConfigWithEnv, findConfigFile } = await import("./utils/config-loader.js");
148
+ const foundConfig = configPath || findConfigFile();
149
+ if (!foundConfig) {
150
+ console.error('Error: relq.config.ts not found.');
151
+ console.error('Run "relq init" to create one or use --config to specify a path.');
152
+ process.exit(1);
153
+ }
154
+ config = await loadConfigWithEnv(configPath);
155
+ if (requiresDbConnection(command, flags) && !config.connection?.host && !config.connection?.url) {
156
+ console.error('Error: No database connection configured.');
157
+ console.error('Run "relq init" or set DATABASE_* environment variables.');
158
+ process.exit(1);
159
+ }
160
+ }
161
+ catch (error) {
162
+ console.error('Error loading config:', error instanceof Error ? error.message : error);
163
+ process.exit(1);
164
+ }
165
+ }
166
+ const context = { config, args, flags };
167
+ try {
168
+ switch (command) {
169
+ case 'init':
170
+ await initCommand(context);
171
+ break;
172
+ case 'status':
173
+ await statusCommand(context);
174
+ break;
175
+ case 'diff':
176
+ await diffCommand(context);
177
+ break;
178
+ case 'pull':
179
+ await pullCommand(context);
180
+ break;
181
+ case 'commit':
182
+ await commitCommand(context);
183
+ break;
184
+ case 'add':
185
+ await addCommand(context);
186
+ break;
187
+ case 'generate':
188
+ await generateCommand(context);
189
+ break;
190
+ case 'push':
191
+ await pushCommand(context);
192
+ break;
193
+ case 'history':
194
+ case 'log':
195
+ await logCommand(context);
196
+ break;
197
+ case 'fetch':
198
+ await fetchCommand(context);
199
+ break;
200
+ case 'rollback':
201
+ case 'revert':
202
+ await rollbackCommand(context);
203
+ break;
204
+ case 'introspect':
205
+ await introspectCommand(context);
206
+ break;
207
+ case 'sync':
208
+ await syncCommand(context);
209
+ break;
210
+ case 'import':
211
+ await importCommand(args[0], {
212
+ output: flags.output,
213
+ includeFunctions: Boolean(flags['include-functions']),
214
+ includeTriggers: Boolean(flags['include-triggers']),
215
+ force: Boolean(flags.force),
216
+ dryRun: Boolean(flags['dry-run']),
217
+ theirs: Boolean(flags.theirs),
218
+ ours: Boolean(flags.ours),
219
+ abort: Boolean(flags.abort),
220
+ });
221
+ break;
222
+ case 'export':
223
+ await exportCommand(context);
224
+ break;
225
+ case 'migrate':
226
+ console.log('Note: "migrate" is deprecated, use "push" instead.\n');
227
+ await pushCommand(context);
228
+ break;
229
+ default:
230
+ console.error(`Error: Unknown command "${command}"\n`);
231
+ printHelp();
232
+ process.exit(1);
233
+ }
234
+ }
235
+ catch (error) {
236
+ console.error('Error:', error instanceof Error ? error.message : error);
237
+ process.exit(1);
238
+ }
239
+ }
240
+ main().catch(console.error);