relq 1.0.1 → 1.0.3

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 (194) hide show
  1. package/dist/cjs/addon/buffer/index.cjs +1881 -0
  2. package/dist/cjs/addon/pg/index.cjs +4812 -0
  3. package/dist/cjs/addon/pg-cursor/index.cjs +1451 -0
  4. package/dist/cjs/addon/pg-format/index.cjs +2270 -0
  5. package/dist/cjs/cli/commands/add.cjs +430 -25
  6. package/dist/cjs/cli/commands/branch.cjs +131 -0
  7. package/dist/cjs/cli/commands/checkout.cjs +121 -0
  8. package/dist/cjs/cli/commands/cherry-pick.cjs +282 -0
  9. package/dist/cjs/cli/commands/commit.cjs +21 -29
  10. package/dist/cjs/cli/commands/diff.cjs +144 -69
  11. package/dist/cjs/cli/commands/export.cjs +70 -11
  12. package/dist/cjs/cli/commands/fetch.cjs +42 -18
  13. package/dist/cjs/cli/commands/generate.cjs +28 -54
  14. package/dist/cjs/cli/commands/history.cjs +19 -40
  15. package/dist/cjs/cli/commands/import.cjs +305 -41
  16. package/dist/cjs/cli/commands/init.cjs +69 -59
  17. package/dist/cjs/cli/commands/introspect.cjs +4 -8
  18. package/dist/cjs/cli/commands/log.cjs +84 -15
  19. package/dist/cjs/cli/commands/merge.cjs +207 -0
  20. package/dist/cjs/cli/commands/migrate.cjs +13 -26
  21. package/dist/cjs/cli/commands/pull.cjs +321 -95
  22. package/dist/cjs/cli/commands/push.cjs +228 -52
  23. package/dist/cjs/cli/commands/remote.cjs +17 -0
  24. package/dist/cjs/cli/commands/reset.cjs +148 -0
  25. package/dist/cjs/cli/commands/resolve.cjs +191 -0
  26. package/dist/cjs/cli/commands/rollback.cjs +17 -39
  27. package/dist/cjs/cli/commands/stash.cjs +152 -0
  28. package/dist/cjs/cli/commands/status.cjs +52 -9
  29. package/dist/cjs/cli/commands/sync.cjs +30 -50
  30. package/dist/cjs/cli/commands/tag.cjs +146 -0
  31. package/dist/cjs/cli/index.cjs +117 -10
  32. package/dist/cjs/cli/utils/change-tracker.cjs +107 -3
  33. package/dist/cjs/cli/utils/cli-utils.cjs +217 -0
  34. package/dist/cjs/cli/utils/commit-manager.cjs +3 -3
  35. package/dist/cjs/cli/utils/config-loader.cjs +34 -8
  36. package/dist/cjs/cli/utils/env-loader.cjs +3 -2
  37. package/dist/cjs/cli/utils/fast-introspect.cjs +110 -4
  38. package/dist/cjs/cli/utils/git-utils.cjs +42 -161
  39. package/dist/cjs/cli/utils/pool-manager.cjs +156 -0
  40. package/dist/cjs/cli/utils/project-root.cjs +107 -0
  41. package/dist/cjs/cli/utils/relqignore.cjs +297 -38
  42. package/dist/cjs/cli/utils/repo-manager.cjs +92 -3
  43. package/dist/cjs/cli/utils/schema-comparator.cjs +301 -11
  44. package/dist/cjs/cli/utils/schema-diff.cjs +202 -1
  45. package/dist/cjs/cli/utils/schema-hash.cjs +2 -1
  46. package/dist/cjs/cli/utils/schema-introspect.cjs +9 -5
  47. package/dist/cjs/cli/utils/snapshot-manager.cjs +1 -0
  48. package/dist/cjs/cli/utils/spinner.cjs +14 -106
  49. package/dist/cjs/cli/utils/sql-generator.cjs +2 -2
  50. package/dist/cjs/cli/utils/sql-parser.cjs +94 -7
  51. package/dist/cjs/cli/utils/type-generator.cjs +28 -16
  52. package/dist/cjs/condition/array-condition-builder.cjs +1 -1
  53. package/dist/cjs/condition/condition-collector.cjs +1 -1
  54. package/dist/cjs/condition/fulltext-condition-builder.cjs +1 -1
  55. package/dist/cjs/condition/geometric-condition-builder.cjs +1 -1
  56. package/dist/cjs/condition/jsonb-condition-builder.cjs +1 -1
  57. package/dist/cjs/condition/network-condition-builder.cjs +1 -1
  58. package/dist/cjs/condition/range-condition-builder.cjs +1 -1
  59. package/dist/cjs/copy/copy-builder.cjs +1 -1
  60. package/dist/cjs/core/query-builder.cjs +1 -1
  61. package/dist/cjs/core/relq-client.cjs +2 -2
  62. package/dist/cjs/count/count-builder.cjs +1 -1
  63. package/dist/cjs/cte/cte-builder.cjs +1 -1
  64. package/dist/cjs/delete/delete-builder.cjs +1 -1
  65. package/dist/cjs/function/create-function-builder.cjs +1 -1
  66. package/dist/cjs/functions/advanced-functions.cjs +1 -1
  67. package/dist/cjs/functions/case-builder.cjs +1 -1
  68. package/dist/cjs/functions/geometric-functions.cjs +1 -1
  69. package/dist/cjs/functions/network-functions.cjs +1 -1
  70. package/dist/cjs/functions/sql-functions.cjs +1 -1
  71. package/dist/cjs/indexing/create-index-builder.cjs +1 -1
  72. package/dist/cjs/indexing/drop-index-builder.cjs +1 -1
  73. package/dist/cjs/insert/conflict-builder.cjs +1 -1
  74. package/dist/cjs/insert/insert-builder.cjs +1 -1
  75. package/dist/cjs/maintenance/vacuum-builder.cjs +1 -1
  76. package/dist/cjs/pubsub/listen-notify-builder.cjs +1 -1
  77. package/dist/cjs/pubsub/listener-connection.cjs +2 -2
  78. package/dist/cjs/raw/raw-query-builder.cjs +1 -1
  79. package/dist/cjs/schema/schema-builder.cjs +1 -1
  80. package/dist/cjs/schema-definition/table-definition.cjs +1 -1
  81. package/dist/cjs/select/aggregate-builder.cjs +1 -1
  82. package/dist/cjs/select/select-builder.cjs +1 -1
  83. package/dist/cjs/sequence/sequence-builder.cjs +1 -1
  84. package/dist/cjs/table/alter-table-builder.cjs +1 -1
  85. package/dist/cjs/table/constraint-builder.cjs +1 -1
  86. package/dist/cjs/table/create-table-builder.cjs +1 -1
  87. package/dist/cjs/table/partition-builder.cjs +1 -1
  88. package/dist/cjs/table/truncate-builder.cjs +1 -1
  89. package/dist/cjs/transaction/transaction-builder.cjs +1 -1
  90. package/dist/cjs/trigger/create-trigger-builder.cjs +1 -1
  91. package/dist/cjs/update/array-update-builder.cjs +1 -1
  92. package/dist/cjs/update/update-builder.cjs +1 -1
  93. package/dist/cjs/utils/index.cjs +1 -1
  94. package/dist/cjs/view/create-view-builder.cjs +1 -1
  95. package/dist/cjs/window/window-builder.cjs +1 -1
  96. package/dist/config.d.ts +16 -25
  97. package/dist/esm/cli/commands/add.js +399 -27
  98. package/dist/esm/cli/commands/branch.js +95 -0
  99. package/dist/esm/cli/commands/checkout.js +85 -0
  100. package/dist/esm/cli/commands/cherry-pick.js +246 -0
  101. package/dist/esm/cli/commands/commit.js +22 -30
  102. package/dist/esm/cli/commands/diff.js +144 -69
  103. package/dist/esm/cli/commands/export.js +71 -12
  104. package/dist/esm/cli/commands/fetch.js +42 -18
  105. package/dist/esm/cli/commands/generate.js +28 -54
  106. package/dist/esm/cli/commands/history.js +11 -32
  107. package/dist/esm/cli/commands/import.js +306 -42
  108. package/dist/esm/cli/commands/init.js +65 -55
  109. package/dist/esm/cli/commands/introspect.js +4 -8
  110. package/dist/esm/cli/commands/log.js +78 -10
  111. package/dist/esm/cli/commands/merge.js +171 -0
  112. package/dist/esm/cli/commands/migrate.js +13 -26
  113. package/dist/esm/cli/commands/pull.js +313 -87
  114. package/dist/esm/cli/commands/push.js +223 -47
  115. package/dist/esm/cli/commands/remote.js +14 -0
  116. package/dist/esm/cli/commands/reset.js +112 -0
  117. package/dist/esm/cli/commands/resolve.js +155 -0
  118. package/dist/esm/cli/commands/rollback.js +17 -39
  119. package/dist/esm/cli/commands/stash.js +116 -0
  120. package/dist/esm/cli/commands/status.js +20 -10
  121. package/dist/esm/cli/commands/sync.js +30 -50
  122. package/dist/esm/cli/commands/tag.js +110 -0
  123. package/dist/esm/cli/index.js +118 -11
  124. package/dist/esm/cli/utils/change-tracker.js +107 -3
  125. package/dist/esm/cli/utils/cli-utils.js +169 -0
  126. package/dist/esm/cli/utils/commit-manager.js +3 -3
  127. package/dist/esm/cli/utils/config-loader.js +34 -8
  128. package/dist/esm/cli/utils/env-loader.js +3 -2
  129. package/dist/esm/cli/utils/fast-introspect.js +110 -4
  130. package/dist/esm/cli/utils/git-utils.js +2 -124
  131. package/dist/esm/cli/utils/pool-manager.js +114 -0
  132. package/dist/esm/cli/utils/project-root.js +69 -0
  133. package/dist/esm/cli/utils/relqignore.js +278 -37
  134. package/dist/esm/cli/utils/repo-manager.js +83 -3
  135. package/dist/esm/cli/utils/schema-comparator.js +301 -11
  136. package/dist/esm/cli/utils/schema-diff.js +202 -1
  137. package/dist/esm/cli/utils/schema-hash.js +2 -1
  138. package/dist/esm/cli/utils/schema-introspect.js +9 -5
  139. package/dist/esm/cli/utils/snapshot-manager.js +1 -0
  140. package/dist/esm/cli/utils/spinner.js +1 -101
  141. package/dist/esm/cli/utils/sql-generator.js +2 -2
  142. package/dist/esm/cli/utils/sql-parser.js +94 -7
  143. package/dist/esm/cli/utils/type-generator.js +28 -16
  144. package/dist/esm/condition/array-condition-builder.js +1 -1
  145. package/dist/esm/condition/condition-collector.js +1 -1
  146. package/dist/esm/condition/fulltext-condition-builder.js +1 -1
  147. package/dist/esm/condition/geometric-condition-builder.js +1 -1
  148. package/dist/esm/condition/jsonb-condition-builder.js +1 -1
  149. package/dist/esm/condition/network-condition-builder.js +1 -1
  150. package/dist/esm/condition/range-condition-builder.js +1 -1
  151. package/dist/esm/copy/copy-builder.js +1 -1
  152. package/dist/esm/core/query-builder.js +1 -1
  153. package/dist/esm/core/relq-client.js +2 -2
  154. package/dist/esm/count/count-builder.js +1 -1
  155. package/dist/esm/cte/cte-builder.js +1 -1
  156. package/dist/esm/delete/delete-builder.js +1 -1
  157. package/dist/esm/function/create-function-builder.js +1 -1
  158. package/dist/esm/functions/advanced-functions.js +1 -1
  159. package/dist/esm/functions/case-builder.js +1 -1
  160. package/dist/esm/functions/geometric-functions.js +1 -1
  161. package/dist/esm/functions/network-functions.js +1 -1
  162. package/dist/esm/functions/sql-functions.js +1 -1
  163. package/dist/esm/indexing/create-index-builder.js +1 -1
  164. package/dist/esm/indexing/drop-index-builder.js +1 -1
  165. package/dist/esm/insert/conflict-builder.js +1 -1
  166. package/dist/esm/insert/insert-builder.js +1 -1
  167. package/dist/esm/maintenance/vacuum-builder.js +1 -1
  168. package/dist/esm/pubsub/listen-notify-builder.js +1 -1
  169. package/dist/esm/pubsub/listener-connection.js +2 -2
  170. package/dist/esm/raw/raw-query-builder.js +1 -1
  171. package/dist/esm/schema/schema-builder.js +1 -1
  172. package/dist/esm/schema-definition/table-definition.js +1 -1
  173. package/dist/esm/select/aggregate-builder.js +1 -1
  174. package/dist/esm/select/select-builder.js +1 -1
  175. package/dist/esm/sequence/sequence-builder.js +1 -1
  176. package/dist/esm/table/alter-table-builder.js +1 -1
  177. package/dist/esm/table/constraint-builder.js +1 -1
  178. package/dist/esm/table/create-table-builder.js +1 -1
  179. package/dist/esm/table/partition-builder.js +1 -1
  180. package/dist/esm/table/truncate-builder.js +1 -1
  181. package/dist/esm/transaction/transaction-builder.js +1 -1
  182. package/dist/esm/trigger/create-trigger-builder.js +1 -1
  183. package/dist/esm/update/array-update-builder.js +1 -1
  184. package/dist/esm/update/update-builder.js +1 -1
  185. package/dist/esm/utils/index.js +1 -1
  186. package/dist/esm/view/create-view-builder.js +1 -1
  187. package/dist/esm/window/window-builder.js +1 -1
  188. package/dist/index.d.ts +25 -8
  189. package/dist/schema-builder.d.ts +16 -6
  190. package/package.json +1 -1
  191. /package/dist/{addons/buffer.js → esm/addon/buffer/index.js} +0 -0
  192. /package/dist/{addons/pg.js → esm/addon/pg/index.js} +0 -0
  193. /package/dist/{addons/pg-cursor.js → esm/addon/pg-cursor/index.js} +0 -0
  194. /package/dist/{addons/pg-format.js → esm/addon/pg-format/index.js} +0 -0
@@ -1,6 +1,18 @@
1
+ function parseOptionsArray(options) {
2
+ if (!options)
3
+ return {};
4
+ const result = {};
5
+ for (const opt of options) {
6
+ const eqIdx = opt.indexOf('=');
7
+ if (eqIdx > 0) {
8
+ result[opt.substring(0, eqIdx)] = opt.substring(eqIdx + 1);
9
+ }
10
+ }
11
+ return result;
12
+ }
1
13
  export async function fastIntrospectDatabase(connection, onProgress, options) {
2
14
  const { includeFunctions = false, includeTriggers = false } = options || {};
3
- const { Pool } = await import("../../addon/pg.js");
15
+ const { Pool } = await import("../../addon/pg/index.js");
4
16
  onProgress?.('connecting', connection.database);
5
17
  const pool = new Pool({
6
18
  host: connection.host,
@@ -218,7 +230,7 @@ export async function fastIntrospectDatabase(connection, onProgress, options) {
218
230
  const tables = [];
219
231
  for (const row of tablesResult.rows) {
220
232
  const tableName = row.table_name;
221
- if (tableName.startsWith('_relq'))
233
+ if (tableName.startsWith('_relq') || tableName.startsWith('_kuery'))
222
234
  continue;
223
235
  tables.push({
224
236
  name: tableName,
@@ -340,6 +352,99 @@ export async function fastIntrospectDatabase(connection, onProgress, options) {
340
352
  isEnabled: t.is_enabled,
341
353
  }));
342
354
  }
355
+ onProgress?.('fetching_collations');
356
+ const collationsResult = await pool.query(`
357
+ SELECT
358
+ c.collname as name,
359
+ n.nspname as schema,
360
+ c.collprovider as provider,
361
+ c.collcollate as lc_collate,
362
+ c.collctype as lc_ctype,
363
+ c.collisdeterministic as deterministic
364
+ FROM pg_collation c
365
+ JOIN pg_namespace n ON c.collnamespace = n.oid
366
+ WHERE n.nspname = 'public'
367
+ ORDER BY c.collname;
368
+ `);
369
+ const collations = collationsResult.rows.map(c => ({
370
+ name: c.name,
371
+ schema: c.schema,
372
+ provider: c.provider === 'i' ? 'icu' : c.provider === 'c' ? 'libc' : 'default',
373
+ lcCollate: c.lc_collate,
374
+ lcCtype: c.lc_ctype,
375
+ deterministic: c.deterministic,
376
+ }));
377
+ onProgress?.('fetching_foreign_servers');
378
+ const foreignServersResult = await pool.query(`
379
+ SELECT
380
+ s.srvname as name,
381
+ f.fdwname as fdw,
382
+ s.srvoptions as options
383
+ FROM pg_foreign_server s
384
+ JOIN pg_foreign_data_wrapper f ON s.srvfdw = f.oid
385
+ ORDER BY s.srvname;
386
+ `);
387
+ const foreignServers = foreignServersResult.rows.map(s => ({
388
+ name: s.name,
389
+ foreignDataWrapper: s.fdw,
390
+ options: parseOptionsArray(s.options),
391
+ }));
392
+ onProgress?.('fetching_foreign_tables');
393
+ const foreignTablesResult = await pool.query(`
394
+ SELECT
395
+ c.relname as name,
396
+ n.nspname as schema,
397
+ s.srvname as server_name,
398
+ ft.ftoptions as options
399
+ FROM pg_foreign_table ft
400
+ JOIN pg_class c ON ft.ftrelid = c.oid
401
+ JOIN pg_namespace n ON c.relnamespace = n.oid
402
+ JOIN pg_foreign_server s ON ft.ftserver = s.oid
403
+ WHERE n.nspname = 'public'
404
+ ORDER BY c.relname;
405
+ `);
406
+ const foreignTableNames = foreignTablesResult.rows.map(t => t.name);
407
+ let foreignTableColumns = new Map();
408
+ if (foreignTableNames.length > 0) {
409
+ const ftColsResult = await pool.query(`
410
+ SELECT
411
+ c.relname as table_name,
412
+ a.attname as column_name,
413
+ pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type
414
+ FROM pg_attribute a
415
+ JOIN pg_class c ON a.attrelid = c.oid
416
+ JOIN pg_namespace n ON c.relnamespace = n.oid
417
+ WHERE n.nspname = 'public'
418
+ AND c.relname = ANY($1)
419
+ AND a.attnum > 0
420
+ AND NOT a.attisdropped
421
+ ORDER BY c.relname, a.attnum;
422
+ `, [foreignTableNames]);
423
+ for (const row of ftColsResult.rows) {
424
+ const cols = foreignTableColumns.get(row.table_name) || [];
425
+ cols.push({ name: row.column_name, type: row.data_type });
426
+ foreignTableColumns.set(row.table_name, cols);
427
+ }
428
+ }
429
+ const foreignTables = foreignTablesResult.rows.map(t => ({
430
+ name: t.name,
431
+ schema: t.schema,
432
+ serverName: t.server_name,
433
+ columns: (foreignTableColumns.get(t.name) || []).map((c, i) => ({
434
+ name: c.name,
435
+ dataType: c.type,
436
+ isNullable: true,
437
+ defaultValue: null,
438
+ isPrimaryKey: false,
439
+ isUnique: false,
440
+ ordinalPosition: i + 1,
441
+ maxLength: null,
442
+ precision: null,
443
+ scale: null,
444
+ references: null,
445
+ })),
446
+ options: parseOptionsArray(t.options),
447
+ }));
343
448
  onProgress?.('complete');
344
449
  return {
345
450
  tables,
@@ -347,12 +452,13 @@ export async function fastIntrospectDatabase(connection, onProgress, options) {
347
452
  domains: [],
348
453
  compositeTypes: [],
349
454
  sequences: [],
455
+ collations,
350
456
  functions,
351
457
  triggers,
352
458
  policies: [],
353
459
  partitions,
354
- foreignServers: [],
355
- foreignTables: [],
460
+ foreignServers,
461
+ foreignTables,
356
462
  extensions,
357
463
  };
358
464
  }
@@ -1,35 +1,8 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
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
- }
4
+ export { colors, createSpinner, fatal, error, warning, hint, success, confirm, select, formatBytes, formatDuration, progressBar, requireInit, } from "./cli-utils.js";
5
+ import { colors, error, hint, fatal } from "./cli-utils.js";
33
6
  export function info(message) {
34
7
  console.log(message);
35
8
  }
@@ -250,98 +223,3 @@ export function readSQLFile(filePath) {
250
223
  const validation = validatePostgresSQL(content);
251
224
  return { content, validation };
252
225
  }
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,114 @@
1
+ const pools = new Map();
2
+ const IDLE_TIMEOUT = 30000;
3
+ let cleanupInterval = null;
4
+ function getPoolKey(config) {
5
+ if (config.url) {
6
+ return config.url;
7
+ }
8
+ return `${config.host || 'localhost'}:${config.port || 5432}/${config.database}@${config.user}`;
9
+ }
10
+ function startCleanupInterval() {
11
+ if (cleanupInterval)
12
+ return;
13
+ cleanupInterval = setInterval(() => {
14
+ const now = Date.now();
15
+ for (const [key, entry] of pools.entries()) {
16
+ if (entry.refCount === 0 && now - entry.lastUsed > IDLE_TIMEOUT) {
17
+ entry.pool.end().catch(() => { });
18
+ pools.delete(key);
19
+ }
20
+ }
21
+ if (pools.size === 0 && cleanupInterval) {
22
+ clearInterval(cleanupInterval);
23
+ cleanupInterval = null;
24
+ }
25
+ }, IDLE_TIMEOUT);
26
+ cleanupInterval.unref();
27
+ }
28
+ export async function getPool(config) {
29
+ const key = getPoolKey(config);
30
+ let entry = pools.get(key);
31
+ if (entry) {
32
+ entry.refCount++;
33
+ entry.lastUsed = Date.now();
34
+ return entry.pool;
35
+ }
36
+ const { Pool } = await import("../../addon/pg/index.js");
37
+ const pool = new Pool({
38
+ host: config.host,
39
+ port: config.port || 5432,
40
+ database: config.database,
41
+ user: config.user,
42
+ password: config.password,
43
+ connectionString: config.url,
44
+ ssl: config.ssl,
45
+ max: config.max || 10,
46
+ idleTimeoutMillis: config.idleTimeoutMillis || 10000,
47
+ connectionTimeoutMillis: config.connectionTimeoutMillis || 5000,
48
+ });
49
+ entry = {
50
+ pool,
51
+ refCount: 1,
52
+ lastUsed: Date.now(),
53
+ };
54
+ pools.set(key, entry);
55
+ startCleanupInterval();
56
+ return pool;
57
+ }
58
+ export function releasePool(config) {
59
+ const key = getPoolKey(config);
60
+ const entry = pools.get(key);
61
+ if (entry && entry.refCount > 0) {
62
+ entry.refCount--;
63
+ entry.lastUsed = Date.now();
64
+ }
65
+ }
66
+ export async function withPool(config, fn) {
67
+ const pool = await getPool(config);
68
+ try {
69
+ return await fn(pool);
70
+ }
71
+ finally {
72
+ releasePool(config);
73
+ }
74
+ }
75
+ export async function withClient(config, fn) {
76
+ const pool = await getPool(config);
77
+ const client = await pool.connect();
78
+ try {
79
+ return await fn(client);
80
+ }
81
+ finally {
82
+ client.release();
83
+ releasePool(config);
84
+ }
85
+ }
86
+ export async function withTransaction(config, fn) {
87
+ return withClient(config, async (client) => {
88
+ await client.query('BEGIN');
89
+ try {
90
+ const result = await fn(client);
91
+ await client.query('COMMIT');
92
+ return result;
93
+ }
94
+ catch (error) {
95
+ await client.query('ROLLBACK');
96
+ throw error;
97
+ }
98
+ });
99
+ }
100
+ export async function closeAllPools() {
101
+ if (cleanupInterval) {
102
+ clearInterval(cleanupInterval);
103
+ cleanupInterval = null;
104
+ }
105
+ const closePromises = [];
106
+ for (const [key, entry] of pools.entries()) {
107
+ closePromises.push(entry.pool.end());
108
+ pools.delete(key);
109
+ }
110
+ await Promise.all(closePromises);
111
+ }
112
+ export function getActivePoolCount() {
113
+ return pools.size;
114
+ }
@@ -0,0 +1,69 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ const CONFIG_FILENAMES = [
5
+ 'relq.config.ts',
6
+ 'relq.config.js',
7
+ 'relq.config.mjs',
8
+ ];
9
+ function hasProjectMarker(dir) {
10
+ for (const filename of CONFIG_FILENAMES) {
11
+ if (fs.existsSync(path.join(dir, filename))) {
12
+ return true;
13
+ }
14
+ }
15
+ if (fs.existsSync(path.join(dir, 'package.json'))) {
16
+ return true;
17
+ }
18
+ return false;
19
+ }
20
+ export function findProjectRoot(startDir = process.cwd()) {
21
+ let currentDir = path.resolve(startDir);
22
+ const root = path.parse(currentDir).root;
23
+ const homeDir = os.homedir();
24
+ while (currentDir !== root) {
25
+ if (hasProjectMarker(currentDir)) {
26
+ return currentDir;
27
+ }
28
+ if (currentDir === homeDir) {
29
+ return null;
30
+ }
31
+ currentDir = path.dirname(currentDir);
32
+ }
33
+ return null;
34
+ }
35
+ export function getRelqDir(startDir = process.cwd()) {
36
+ const projectRoot = findProjectRoot(startDir);
37
+ if (!projectRoot) {
38
+ const colors = {
39
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
40
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
41
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
42
+ };
43
+ console.error('');
44
+ console.error(colors.red('fatal:') + ' not a relq project (or any of the parent directories)');
45
+ console.error('');
46
+ console.error(colors.yellow('hint:') + ` Run ${colors.cyan('relq init')} in your project directory to initialize relq.`);
47
+ console.error('');
48
+ process.exit(128);
49
+ }
50
+ return path.join(projectRoot, '.relq');
51
+ }
52
+ export function getProjectRoot(startDir = process.cwd()) {
53
+ const projectRoot = findProjectRoot(startDir);
54
+ if (!projectRoot) {
55
+ const colors = {
56
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
57
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
58
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
59
+ };
60
+ console.error('');
61
+ console.error(colors.red('fatal:') + ' not a relq project (or any of the parent directories)');
62
+ console.error('');
63
+ console.error(colors.yellow('hint:') + ` Run ${colors.cyan('relq init')} in your project directory to initialize relq.`);
64
+ console.error('');
65
+ process.exit(128);
66
+ }
67
+ return projectRoot;
68
+ }
69
+ export default { findProjectRoot, getRelqDir, getProjectRoot };