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,401 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as readline from 'readline';
4
+ import { loadEnvConfig } from "../utils/env-loader.js";
5
+ import { initRepository, ensureRemoteTable, isInitialized } from "../utils/repo-manager.js";
6
+ import { createDefaultRelqignore } from "../utils/relqignore.js";
7
+ import { colors, createSpinner } from "../utils/spinner.js";
8
+ function ask(rl, question, defaultValue) {
9
+ const suffix = defaultValue ? ` ${colors.muted(`[${defaultValue}]`)}` : '';
10
+ return new Promise((resolve) => {
11
+ rl.question(`${question}${suffix}: `, (answer) => {
12
+ resolve(answer.trim() || defaultValue || '');
13
+ });
14
+ });
15
+ }
16
+ function askYesNo(rl, question, defaultYes = true) {
17
+ const suffix = defaultYes ? colors.muted('[Y/n]') : colors.muted('[y/N]');
18
+ return new Promise((resolve) => {
19
+ rl.question(`${question} ${suffix}: `, (answer) => {
20
+ const a = answer.trim().toLowerCase();
21
+ if (!a)
22
+ resolve(defaultYes);
23
+ else
24
+ resolve(a === 'y' || a === 'yes');
25
+ });
26
+ });
27
+ }
28
+ function detectSchemaPath() {
29
+ const cwd = process.cwd();
30
+ if (fs.existsSync(path.join(cwd, 'src'))) {
31
+ return './src/db/schema.ts';
32
+ }
33
+ if (fs.existsSync(path.join(cwd, 'app'))) {
34
+ return './app/db/schema.ts';
35
+ }
36
+ if (fs.existsSync(path.join(cwd, 'db'))) {
37
+ return './db/schema.ts';
38
+ }
39
+ if (fs.existsSync(path.join(cwd, 'lib'))) {
40
+ return './lib/db/schema.ts';
41
+ }
42
+ return './src/db/schema.ts';
43
+ }
44
+ function checkEnvVars() {
45
+ const vars = {
46
+ DATABASE_HOST: process.env.DATABASE_HOST,
47
+ DATABASE_PORT: process.env.DATABASE_PORT,
48
+ DATABASE_NAME: process.env.DATABASE_NAME,
49
+ DATABASE_USER: process.env.DATABASE_USER,
50
+ DATABASE_PASSWORD: process.env.DATABASE_PASSWORD,
51
+ RELQ_PG_CONN_URL: process.env.RELQ_PG_CONN_URL,
52
+ };
53
+ const hasConnUrl = !!vars.RELQ_PG_CONN_URL;
54
+ const hasIndividual = !!(vars.DATABASE_HOST && vars.DATABASE_NAME);
55
+ return {
56
+ found: hasConnUrl || hasIndividual,
57
+ vars,
58
+ };
59
+ }
60
+ function generateConfig(options) {
61
+ let connectionBlock;
62
+ if (options.useEnv) {
63
+ if (process.env.RELQ_PG_CONN_URL) {
64
+ connectionBlock = ` connection: {
65
+ url: process.env.RELQ_PG_CONN_URL,
66
+ },`;
67
+ }
68
+ else {
69
+ connectionBlock = ` connection: {
70
+ host: process.env.DATABASE_HOST,
71
+ port: parseInt(process.env.DATABASE_PORT || '5432'),
72
+ database: process.env.DATABASE_NAME,
73
+ user: process.env.DATABASE_USER,
74
+ password: process.env.DATABASE_PASSWORD,
75
+ },`;
76
+ }
77
+ }
78
+ else {
79
+ connectionBlock = ` connection: {
80
+ host: '${options.host}',
81
+ port: ${options.port},
82
+ database: '${options.database}',
83
+ user: '${options.user}',
84
+ password: '${options.password}',
85
+ },`;
86
+ }
87
+ return `import { defineConfig } from 'relq/config';
88
+
89
+ export default defineConfig({
90
+ ${connectionBlock}
91
+
92
+ // Author for commits (required)
93
+ author: '${options.author}',
94
+
95
+ // Schema file path
96
+ schema: '${options.schemaPath}',
97
+
98
+ // What to track
99
+ generate: {
100
+ includeFunctions: ${options.includeFunctions},
101
+ includeTriggers: ${options.includeTriggers},
102
+ includeRLS: false,
103
+ camelCase: true,
104
+ },
105
+
106
+ // Migrations
107
+ migrations: {
108
+ directory: './migrations',
109
+ tableName: '_relq_migrations',
110
+ },
111
+
112
+ // Sync settings
113
+ sync: {
114
+ commitLimit: 1000,
115
+ },
116
+ });
117
+ `;
118
+ }
119
+ export async function initCommand(context) {
120
+ const cwd = process.cwd();
121
+ const spinner = createSpinner();
122
+ console.log('');
123
+ console.log(`${colors.bold('Relq')} - Git-like schema versioning for PostgreSQL`);
124
+ console.log('');
125
+ const { findConfigFileRecursive } = await import("../utils/config-loader.js");
126
+ const existingConfig = findConfigFileRecursive(cwd);
127
+ const localRelqExists = isInitialized(cwd);
128
+ let projectRoot = cwd;
129
+ let existingConfigValues = null;
130
+ if (existingConfig) {
131
+ projectRoot = existingConfig.directory;
132
+ try {
133
+ const { loadConfig } = await import("../../config/config.js");
134
+ existingConfigValues = await loadConfig(existingConfig.path);
135
+ }
136
+ catch {
137
+ }
138
+ if (existingConfig.directory !== cwd) {
139
+ console.log(`${colors.cyan('ℹ')} Found ${colors.cyan('relq.config.ts')} in parent directory:`);
140
+ console.log(` ${colors.muted(existingConfig.path)}`);
141
+ console.log('');
142
+ console.log(`${colors.muted('Run commands from project root:')} ${colors.cyan(existingConfig.directory)}`);
143
+ console.log('');
144
+ return;
145
+ }
146
+ const relqFolderExists = isInitialized(projectRoot);
147
+ if (relqFolderExists) {
148
+ console.log(`${colors.green('✓')} Relq is already initialized.`);
149
+ console.log('');
150
+ console.log(` ${colors.green('●')} ${colors.muted('relq.config.ts')}`);
151
+ console.log(` ${colors.green('●')} ${colors.muted('.relq/')} folder`);
152
+ console.log('');
153
+ console.log(`${colors.muted('Use')} ${colors.cyan('relq status')} ${colors.muted('to see current state.')}`);
154
+ console.log(`${colors.muted('Use')} ${colors.cyan('relq pull')} ${colors.muted('to sync with database.')}`);
155
+ return;
156
+ }
157
+ else {
158
+ console.log(`${colors.yellow('⚠')} Found ${colors.cyan('relq.config.ts')} but ${colors.cyan('.relq/')} folder is missing.`);
159
+ console.log('');
160
+ console.log(`${colors.muted('This could mean the setup was incomplete.')}`);
161
+ console.log('');
162
+ const rl = readline.createInterface({
163
+ input: process.stdin,
164
+ output: process.stdout,
165
+ });
166
+ try {
167
+ const upgrade = await askYesNo(rl, `Complete setup using existing config?`, true);
168
+ if (upgrade) {
169
+ const missingFields = [];
170
+ if (!existingConfigValues?.author || existingConfigValues.author === 'Developer <dev@example.com>') {
171
+ missingFields.push('author');
172
+ }
173
+ if (!existingConfigValues?.schema) {
174
+ missingFields.push('schema');
175
+ }
176
+ if (!existingConfigValues?.connection?.host && !existingConfigValues?.connection?.url) {
177
+ const hasEnvConnection = process.env.DATABASE_HOST || process.env.RELQ_PG_CONN_URL;
178
+ if (!hasEnvConnection) {
179
+ missingFields.push('connection');
180
+ }
181
+ }
182
+ if (missingFields.length > 0) {
183
+ console.log('');
184
+ console.log(`${colors.yellow('⚠')} Your config is missing required fields:`);
185
+ for (const field of missingFields) {
186
+ console.log(` ${colors.red('●')} ${field}`);
187
+ }
188
+ console.log('');
189
+ console.log(`${colors.cyan('●')} Let's fill in the missing fields:`);
190
+ console.log('');
191
+ let authorValue = existingConfigValues?.author;
192
+ let schemaValue = existingConfigValues?.schema;
193
+ if (missingFields.includes('author')) {
194
+ authorValue = await ask(rl, 'Author (Name <email>)', 'Developer <dev@example.com>');
195
+ }
196
+ if (missingFields.includes('schema')) {
197
+ schemaValue = await ask(rl, 'Schema file path', detectSchemaPath());
198
+ }
199
+ if (missingFields.includes('connection')) {
200
+ console.log('');
201
+ console.log(`${colors.red('●')} Connection not configured.`);
202
+ console.log(` ${colors.muted('Set DATABASE_* environment variables in .env')}`);
203
+ console.log(` ${colors.muted('or update relq.config.ts with connection details.')}`);
204
+ rl.close();
205
+ return;
206
+ }
207
+ if (authorValue || schemaValue) {
208
+ console.log('');
209
+ spinner.start('Updating relq.config.ts...');
210
+ const configContent = fs.readFileSync(existingConfig.path, 'utf-8');
211
+ let updatedContent = configContent;
212
+ if (missingFields.includes('author') && authorValue) {
213
+ if (updatedContent.includes('connection:')) {
214
+ updatedContent = updatedContent.replace(/(connection:\s*\{[^}]+\},?)/, `$1\n\n // Author for commits (required)\n author: '${authorValue}',`);
215
+ }
216
+ }
217
+ if (missingFields.includes('schema') && schemaValue) {
218
+ if (updatedContent.includes('author:')) {
219
+ updatedContent = updatedContent.replace(/(author:\s*['"][^'"]+['"],?)/, `$1\n\n // Schema file path\n schema: '${schemaValue}',`);
220
+ }
221
+ }
222
+ fs.writeFileSync(existingConfig.path, updatedContent, 'utf-8');
223
+ spinner.succeed('Updated relq.config.ts');
224
+ existingConfigValues = { ...existingConfigValues, author: authorValue, schema: schemaValue };
225
+ }
226
+ }
227
+ rl.close();
228
+ console.log('');
229
+ console.log(`${colors.cyan('●')} Completing setup...`);
230
+ console.log('');
231
+ initRepository(projectRoot);
232
+ console.log(` ${colors.green('✓')} Created ${colors.cyan('.relq/')} folder`);
233
+ createDefaultRelqignore(projectRoot);
234
+ console.log(` ${colors.green('✓')} Created ${colors.cyan('.relqignore')}`);
235
+ const gitignorePath = path.join(projectRoot, '.gitignore');
236
+ if (fs.existsSync(gitignorePath)) {
237
+ const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
238
+ if (!gitignore.includes('.relq')) {
239
+ fs.appendFileSync(gitignorePath, '\n# Relq local state\n.relq/\n');
240
+ console.log(` ${colors.green('✓')} Added ${colors.cyan('.relq/')} to .gitignore`);
241
+ }
242
+ }
243
+ if (existingConfigValues?.connection) {
244
+ spinner.start('Creating _relq_commits table...');
245
+ try {
246
+ await ensureRemoteTable(existingConfigValues.connection);
247
+ spinner.succeed('Created _relq_commits table');
248
+ }
249
+ catch (error) {
250
+ spinner.fail('Could not create table (check connection)');
251
+ }
252
+ }
253
+ console.log('');
254
+ console.log(`${colors.green('✓')} Setup complete!`);
255
+ console.log('');
256
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq pull')} ${colors.muted('to sync with database.')}`);
257
+ return;
258
+ }
259
+ rl.close();
260
+ console.log('');
261
+ console.log(`${colors.muted('Cancelled.')}`);
262
+ return;
263
+ }
264
+ catch {
265
+ rl.close();
266
+ return;
267
+ }
268
+ }
269
+ }
270
+ const rl = readline.createInterface({
271
+ input: process.stdin,
272
+ output: process.stdout,
273
+ });
274
+ try {
275
+ console.log(`${colors.cyan('●')} Checking for database connection...`);
276
+ console.log('');
277
+ const envCheck = checkEnvVars();
278
+ let useEnv = false;
279
+ let host = 'localhost';
280
+ let port = '5432';
281
+ let database = '';
282
+ let user = 'postgres';
283
+ let password = '';
284
+ if (envCheck.found) {
285
+ console.log(`${colors.green('✓')} Found database environment variables:`);
286
+ if (envCheck.vars.RELQ_PG_CONN_URL) {
287
+ console.log(` ${colors.green('✓')} RELQ_PG_CONN_URL`);
288
+ }
289
+ else {
290
+ if (envCheck.vars.DATABASE_HOST)
291
+ console.log(` ${colors.green('✓')} DATABASE_HOST: ${envCheck.vars.DATABASE_HOST}`);
292
+ if (envCheck.vars.DATABASE_PORT)
293
+ console.log(` ${colors.green('✓')} DATABASE_PORT: ${envCheck.vars.DATABASE_PORT}`);
294
+ if (envCheck.vars.DATABASE_NAME)
295
+ console.log(` ${colors.green('✓')} DATABASE_NAME: ${envCheck.vars.DATABASE_NAME}`);
296
+ if (envCheck.vars.DATABASE_USER)
297
+ console.log(` ${colors.green('✓')} DATABASE_USER: ${envCheck.vars.DATABASE_USER}`);
298
+ if (envCheck.vars.DATABASE_PASSWORD)
299
+ console.log(` ${colors.green('✓')} DATABASE_PASSWORD: ***`);
300
+ }
301
+ console.log('');
302
+ useEnv = await askYesNo(rl, 'Use these environment variables?', true);
303
+ console.log('');
304
+ }
305
+ if (!useEnv) {
306
+ console.log(`${colors.cyan('●')} Database Connection`);
307
+ console.log('');
308
+ host = await ask(rl, ' Host', 'localhost');
309
+ port = await ask(rl, ' Port', '5432');
310
+ database = await ask(rl, ' Database');
311
+ user = await ask(rl, ' User', 'postgres');
312
+ password = await ask(rl, ' Password');
313
+ console.log('');
314
+ }
315
+ const detectedPath = detectSchemaPath();
316
+ console.log(`${colors.cyan('●')} Schema Configuration`);
317
+ console.log('');
318
+ const schemaPath = await ask(rl, ' Schema file path', detectedPath);
319
+ console.log('');
320
+ console.log(`${colors.cyan('●')} Author (for commit history)`);
321
+ console.log('');
322
+ const author = await ask(rl, ' Name <email>', 'Developer <dev@example.com>');
323
+ console.log('');
324
+ console.log(`${colors.cyan('●')} Features to track`);
325
+ console.log('');
326
+ const includeFunctions = await askYesNo(rl, ' Include functions?', false);
327
+ const includeTriggers = await askYesNo(rl, ' Include triggers?', false);
328
+ console.log('');
329
+ rl.close();
330
+ console.log(`${colors.cyan('●')} Creating files...`);
331
+ console.log('');
332
+ const configPath = path.join(cwd, 'relq.config.ts');
333
+ if (!fs.existsSync(configPath)) {
334
+ const configContent = generateConfig({
335
+ useEnv,
336
+ host,
337
+ port,
338
+ database,
339
+ user,
340
+ password,
341
+ schemaPath,
342
+ author,
343
+ includeFunctions,
344
+ includeTriggers,
345
+ });
346
+ fs.writeFileSync(configPath, configContent, 'utf-8');
347
+ console.log(` ${colors.green('✓')} Created ${colors.cyan('relq.config.ts')}`);
348
+ }
349
+ else {
350
+ console.log(` ${colors.yellow('○')} ${colors.cyan('relq.config.ts')} already exists`);
351
+ }
352
+ initRepository(cwd);
353
+ console.log(` ${colors.green('✓')} Created ${colors.cyan('.relq/')} folder`);
354
+ createDefaultRelqignore(cwd);
355
+ console.log(` ${colors.green('✓')} Created ${colors.cyan('.relqignore')}`);
356
+ const schemaDir = path.dirname(schemaPath);
357
+ if (!fs.existsSync(schemaDir)) {
358
+ fs.mkdirSync(schemaDir, { recursive: true });
359
+ console.log(` ${colors.green('✓')} Created ${colors.cyan(schemaDir + '/')}`);
360
+ }
361
+ const gitignorePath = path.join(cwd, '.gitignore');
362
+ if (fs.existsSync(gitignorePath)) {
363
+ const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
364
+ if (!gitignore.includes('.relq')) {
365
+ fs.appendFileSync(gitignorePath, '\n# Relq local state\n.relq/\n');
366
+ console.log(` ${colors.green('✓')} Added ${colors.cyan('.relq/')} to ${colors.cyan('.gitignore')}`);
367
+ }
368
+ }
369
+ console.log('');
370
+ spinner.start('Connecting to database...');
371
+ try {
372
+ const envConfig = loadEnvConfig();
373
+ const connection = useEnv && envConfig ? envConfig : {
374
+ host,
375
+ port: parseInt(port),
376
+ database,
377
+ user,
378
+ password,
379
+ };
380
+ await ensureRemoteTable(connection);
381
+ spinner.succeed('Created _relq_commits table');
382
+ }
383
+ catch (error) {
384
+ spinner.fail('Could not connect to database');
385
+ console.log(` ${colors.yellow('⚠')} ${colors.muted('Run relq pull after fixing connection')}`);
386
+ }
387
+ console.log('');
388
+ console.log(`${colors.green('✓')} ${colors.bold('Relq initialized successfully!')}`);
389
+ console.log('');
390
+ console.log(`${colors.bold('Next steps:')}`);
391
+ console.log(` 1. Review ${colors.cyan('relq.config.ts')}`);
392
+ console.log(` 2. Run ${colors.cyan('relq pull')} to sync with database`);
393
+ console.log(` 3. Run ${colors.cyan('relq status')} to see current state`);
394
+ console.log('');
395
+ }
396
+ catch (error) {
397
+ rl.close();
398
+ console.error(colors.red(`Error: ${error instanceof Error ? error.message : error}`));
399
+ process.exit(1);
400
+ }
401
+ }
@@ -0,0 +1,106 @@
1
+ import * as fs from 'fs';
2
+ import * as readline from 'readline';
3
+ import { parseSqlToDefineTable } from "../../introspect/index.js";
4
+ function readStdin() {
5
+ return new Promise((resolve) => {
6
+ let data = '';
7
+ process.stdin.setEncoding('utf-8');
8
+ process.stdin.on('data', chunk => data += chunk);
9
+ process.stdin.on('end', () => resolve(data));
10
+ });
11
+ }
12
+ function readInteractive() {
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ });
17
+ console.log('Enter SQL (CREATE TABLE statements). End with empty line:\n');
18
+ return new Promise((resolve) => {
19
+ const lines = [];
20
+ let emptyLineCount = 0;
21
+ rl.on('line', (line) => {
22
+ if (line.trim() === '') {
23
+ emptyLineCount++;
24
+ if (emptyLineCount >= 2) {
25
+ rl.close();
26
+ resolve(lines.join('\n'));
27
+ }
28
+ }
29
+ else {
30
+ emptyLineCount = 0;
31
+ lines.push(line);
32
+ }
33
+ });
34
+ rl.on('close', () => {
35
+ resolve(lines.join('\n'));
36
+ });
37
+ });
38
+ }
39
+ export async function introspectCommand(context) {
40
+ const { flags } = context;
41
+ const filePath = flags['file'];
42
+ const useStdin = flags['stdin'] === true;
43
+ let sql;
44
+ if (filePath) {
45
+ if (!fs.existsSync(filePath)) {
46
+ console.error(`Error: File not found: ${filePath}`);
47
+ process.exit(1);
48
+ }
49
+ sql = fs.readFileSync(filePath, 'utf-8');
50
+ console.log(`📄 Reading from: ${filePath}\n`);
51
+ }
52
+ else if (useStdin || !process.stdin.isTTY) {
53
+ sql = await readStdin();
54
+ }
55
+ else {
56
+ sql = await readInteractive();
57
+ }
58
+ if (!sql.trim()) {
59
+ console.error('Error: No SQL input provided.');
60
+ console.error('Usage: relq introspect --file schema.sql');
61
+ console.error(' or: cat schema.sql | relq introspect');
62
+ process.exit(1);
63
+ }
64
+ console.log('🔍 Parsing SQL...\n');
65
+ try {
66
+ const tables = parseSqlToDefineTable(sql);
67
+ if (tables.length === 0) {
68
+ console.log('No CREATE TABLE statements found.');
69
+ return;
70
+ }
71
+ console.log(`Found ${tables.length} table(s):\n`);
72
+ const output = [
73
+ "import { defineTable, serial, integer, bigint, varchar, text, boolean, uuid, jsonb, json, timestamp, date, numeric, vector } from 'relq/schema-builder';",
74
+ '',
75
+ ];
76
+ for (const table of tables) {
77
+ output.push(generateDefineTableCode(table));
78
+ output.push('');
79
+ }
80
+ console.log(output.join('\n'));
81
+ }
82
+ catch (error) {
83
+ console.error('Error parsing SQL:', error instanceof Error ? error.message : error);
84
+ process.exit(1);
85
+ }
86
+ }
87
+ function generateDefineTableCode(table) {
88
+ const columns = table.columns.map(col => {
89
+ const parts = [];
90
+ parts.push(col.typeCode);
91
+ if (col.isPrimaryKey)
92
+ parts.push('.primaryKey()');
93
+ if (!col.isNullable && !col.isPrimaryKey)
94
+ parts.push('.notNull()');
95
+ if (col.isUnique)
96
+ parts.push('.unique()');
97
+ if (col.references)
98
+ parts.push(`.references('${col.references.table}', '${col.references.column}')`);
99
+ if (col.defaultValue)
100
+ parts.push(`.default(${col.defaultValue})`);
101
+ return ` ${col.name}: ${parts.join('')},`;
102
+ });
103
+ return `export const ${table.name} = defineTable('${table.name}', {
104
+ ${columns.join('\n')}
105
+ });`;
106
+ }
@@ -0,0 +1,59 @@
1
+ import { colors } from "../utils/spinner.js";
2
+ import { isInitialized, getHead, getCommitHistory, shortHash, } from "../utils/repo-manager.js";
3
+ function formatDate(timestamp) {
4
+ const date = new Date(timestamp);
5
+ const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
6
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
7
+ const dayName = days[date.getDay()];
8
+ const monthName = months[date.getMonth()];
9
+ const day = date.getDate();
10
+ const time = date.toTimeString().split(' ')[0];
11
+ const year = date.getFullYear();
12
+ return `${dayName} ${monthName} ${day} ${time} ${year}`;
13
+ }
14
+ export async function logCommand(context) {
15
+ const { flags } = context;
16
+ const projectRoot = process.cwd();
17
+ const limit = parseInt(flags['n']) || 10;
18
+ const oneline = flags['oneline'] === true;
19
+ console.log('');
20
+ if (!isInitialized(projectRoot)) {
21
+ console.log(`${colors.red('fatal:')} not a relq repository`);
22
+ console.log('');
23
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq init')} ${colors.muted('to initialize.')}`);
24
+ return;
25
+ }
26
+ const head = getHead(projectRoot);
27
+ const commits = getCommitHistory(limit, projectRoot);
28
+ if (commits.length === 0) {
29
+ console.log(`${colors.muted('No commits yet.')}`);
30
+ console.log('');
31
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq commit -m "message"')} ${colors.muted('to create first commit.')}`);
32
+ console.log('');
33
+ return;
34
+ }
35
+ for (const commit of commits) {
36
+ const isHead = commit.hash === head;
37
+ if (oneline) {
38
+ const headMarker = isHead ? `${colors.cyan('(HEAD)')} ` : '';
39
+ console.log(`${colors.yellow(shortHash(commit.hash))} ${headMarker}${commit.message}`);
40
+ }
41
+ else {
42
+ console.log(`${colors.yellow(`commit ${commit.hash}`)}`);
43
+ if (isHead) {
44
+ console.log(`${colors.cyan('(HEAD)')}`);
45
+ }
46
+ console.log(`Author: ${commit.author}`);
47
+ console.log(`Date: ${formatDate(commit.timestamp)}`);
48
+ console.log('');
49
+ console.log(` ${commit.message}`);
50
+ console.log('');
51
+ console.log(` ${colors.muted(`${commit.stats.tables} tables, ${commit.stats.columns} columns`)}`);
52
+ console.log('');
53
+ }
54
+ }
55
+ if (!oneline) {
56
+ console.log('');
57
+ }
58
+ }
59
+ export { logCommand as historyCommand };