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
@@ -37,27 +37,19 @@ exports.historyCommand = historyCommand;
37
37
  const fs = __importStar(require("fs"));
38
38
  const config_loader_1 = require("../utils/config-loader.cjs");
39
39
  const env_loader_1 = require("../utils/env-loader.cjs");
40
- const colors = {
41
- reset: '\x1b[0m',
42
- bold: '\x1b[1m',
43
- dim: '\x1b[2m',
44
- red: '\x1b[31m',
45
- green: '\x1b[32m',
46
- yellow: '\x1b[33m',
47
- cyan: '\x1b[36m',
48
- };
40
+ const cli_utils_1 = require("../utils/cli-utils.cjs");
41
+ const pool_manager_1 = require("../utils/pool-manager.cjs");
49
42
  async function historyCommand(context) {
50
43
  const { config, flags } = context;
51
44
  if (!config) {
52
- console.error('Error: No configuration found.');
53
- process.exit(1);
45
+ (0, cli_utils_1.fatal)('No configuration found', `run ${cli_utils_1.colors.cyan('relq init')} to create a configuration file`);
54
46
  }
55
- (0, config_loader_1.requireValidConfig)(config);
47
+ await (0, config_loader_1.requireValidConfig)(config, { calledFrom: 'history' });
56
48
  const connection = config.connection;
57
49
  const migrationsDir = config.migrations?.directory || './migrations';
58
50
  const tableName = config.migrations?.tableName || '_relq_migrations';
59
51
  const limit = parseInt(flags['n']) || 20;
60
- console.log(`${colors.bold}Migration History${colors.reset}`);
52
+ console.log('Migration History');
61
53
  console.log(`Database: ${(0, env_loader_1.getConnectionDescription)(connection)}`);
62
54
  console.log('');
63
55
  try {
@@ -76,42 +68,41 @@ async function historyCommand(context) {
76
68
  const toShow = history.slice(0, limit);
77
69
  const pendingCount = history.filter(h => h.pending).length;
78
70
  const appliedCount = history.filter(h => !h.pending).length;
79
- console.log(`${colors.dim}Showing ${toShow.length} of ${history.length} migrations${colors.reset}`);
80
- console.log(`${colors.green}${appliedCount} applied${colors.reset}, ${colors.yellow}${pendingCount} pending${colors.reset}`);
71
+ console.log(`Showing ${toShow.length} of ${history.length} migrations`);
72
+ console.log(`${appliedCount} applied, ${pendingCount} pending`);
81
73
  console.log('');
82
74
  for (const record of toShow) {
83
75
  if (record.pending) {
84
- console.log(`${colors.yellow}○ ${record.name}${colors.reset} ${colors.dim}(pending)${colors.reset}`);
76
+ console.log(`${cli_utils_1.colors.yellow}○ ${record.name}${cli_utils_1.colors.reset} ${cli_utils_1.colors.dim}(pending)${cli_utils_1.colors.reset}`);
85
77
  }
86
78
  else {
87
79
  const date = record.appliedAt ? formatDate(record.appliedAt) : '';
88
- console.log(`${colors.green}● ${record.name}${colors.reset} ${colors.dim}${date}${colors.reset}`);
80
+ console.log(`${cli_utils_1.colors.green}● ${record.name}${cli_utils_1.colors.reset} ${cli_utils_1.colors.dim}${date}${cli_utils_1.colors.reset}`);
89
81
  }
90
82
  }
91
83
  if (history.length > limit) {
92
84
  console.log('');
93
- console.log(`${colors.dim}Use "relq history -n ${history.length}" to see all.${colors.reset}`);
85
+ console.log(`${cli_utils_1.colors.dim}Use "relq history -n ${history.length}" to see all.${cli_utils_1.colors.reset}`);
94
86
  }
95
87
  }
96
88
  catch (error) {
97
89
  if (error?.code === '42P01') {
98
- console.log(`${colors.yellow}No migration table found.${colors.reset}`);
99
- console.log(`Run "${colors.cyan}relq push${colors.reset}" to initialize.`);
90
+ console.log(`${cli_utils_1.colors.yellow}No migration table found.${cli_utils_1.colors.reset}`);
91
+ console.log(`Run "${cli_utils_1.colors.cyan}relq push${cli_utils_1.colors.reset}" to initialize.`);
100
92
  console.log('');
101
93
  const files = getMigrationFiles(migrationsDir);
102
94
  if (files.length > 0) {
103
- console.log(`${colors.bold}Pending migrations:${colors.reset}`);
95
+ console.log(`${cli_utils_1.colors.bold}Pending migrations:${cli_utils_1.colors.reset}`);
104
96
  for (const file of files.slice(0, limit)) {
105
- console.log(` ${colors.yellow}○ ${file}${colors.reset}`);
97
+ console.log(` ${cli_utils_1.colors.yellow}○ ${file}${cli_utils_1.colors.reset}`);
106
98
  }
107
99
  }
108
100
  else {
109
- console.log(`${colors.dim}No migration files found.${colors.reset}`);
101
+ console.log(`${cli_utils_1.colors.dim}No migration files found.${cli_utils_1.colors.reset}`);
110
102
  }
111
103
  return;
112
104
  }
113
- console.error('Error:', error instanceof Error ? error.message : error);
114
- process.exit(1);
105
+ (0, cli_utils_1.fatal)('Failed to load history', error instanceof Error ? error.message : String(error));
115
106
  }
116
107
  }
117
108
  function getMigrationFiles(migrationsDir) {
@@ -123,29 +114,17 @@ function getMigrationFiles(migrationsDir) {
123
114
  .sort();
124
115
  }
125
116
  async function getAppliedMigrations(connection, tableName) {
126
- const { Pool } = await Promise.resolve().then(() => __importStar(require("../../../addons/pg.js")));
127
- const pool = new Pool({
128
- host: connection.host,
129
- port: connection.port || 5432,
130
- database: connection.database,
131
- user: connection.user,
132
- password: connection.password,
133
- connectionString: connection.url,
134
- });
135
- try {
117
+ return (0, pool_manager_1.withPool)(connection, async (pool) => {
136
118
  const result = await pool.query(`
137
119
  SELECT name, applied_at
138
120
  FROM "${tableName}"
139
121
  ORDER BY id DESC;
140
122
  `);
141
- return result.rows.map(r => ({
123
+ return result.rows.map((r) => ({
142
124
  name: r.name,
143
125
  appliedAt: new Date(r.applied_at),
144
126
  }));
145
- }
146
- finally {
147
- await pool.end();
148
- }
127
+ });
149
128
  }
150
129
  function formatDate(date) {
151
130
  const now = new Date();
@@ -41,27 +41,24 @@ const type_generator_1 = require("../utils/type-generator.cjs");
41
41
  const repo_manager_1 = require("../utils/repo-manager.cjs");
42
42
  const schema_comparator_1 = require("../utils/schema-comparator.cjs");
43
43
  const change_tracker_1 = require("../utils/change-tracker.cjs");
44
+ const relqignore_1 = require("../utils/relqignore.cjs");
44
45
  const git_utils_1 = require("../utils/git-utils.cjs");
45
- async function importCommand(sqlFilePath, options = {}) {
46
+ async function importCommand(sqlFilePath, options = {}, projectRoot = process.cwd()) {
46
47
  const { includeFunctions = false, includeTriggers = false, force = false, dryRun = false } = options;
47
- const projectRoot = process.cwd();
48
48
  const spinner = (0, git_utils_1.createSpinner)();
49
49
  console.log('');
50
50
  if (!sqlFilePath) {
51
- (0, git_utils_1.error)('No SQL file specified.');
52
- console.log('');
53
- console.log('usage: relq import <sql-file> [options]');
54
- console.log('');
55
- console.log('Options:');
56
- console.log(' --output <path> Output schema file path');
57
- console.log(' --force Force import, overwrite local changes');
58
- console.log(' --dry-run Preview changes without applying');
59
- console.log(' --theirs Accept all incoming changes');
60
- console.log(' --ours Keep all local changes (reject incoming)');
61
- console.log(' --abort Abort the import operation');
62
- console.log(' --include-functions Include functions in import');
63
- console.log(' --include-triggers Include triggers in import');
64
- process.exit(1);
51
+ (0, git_utils_1.fatal)('No SQL file specified', 'usage: relq import <sql-file> [options]\n\n' +
52
+ 'Options:\n' +
53
+ ' --output <path> Output schema file path\n' +
54
+ ' --force Force import, overwrite local changes\n' +
55
+ ' --dry-run Preview changes without applying\n' +
56
+ ' --theirs Accept all incoming changes\n' +
57
+ ' --ours Keep all local changes (reject incoming)\n' +
58
+ ' --abort Abort the import operation\n' +
59
+ ' --include-functions Include functions in import\n' +
60
+ ' --include-triggers Include triggers in import');
61
+ return;
65
62
  }
66
63
  if (options.abort) {
67
64
  console.log('Aborting import...');
@@ -84,11 +81,8 @@ async function importCommand(sqlFilePath, options = {}) {
84
81
  (0, git_utils_1.warning)(warn);
85
82
  }
86
83
  if (!validation.valid) {
87
- (0, git_utils_1.error)('Invalid PostgreSQL SQL file:');
88
- for (const err of validation.errors) {
89
- console.log(` - ${err}`);
90
- }
91
- process.exit(1);
84
+ (0, git_utils_1.fatal)('Invalid PostgreSQL SQL file', validation.errors.join('\n - '));
85
+ return;
92
86
  }
93
87
  console.log(`Importing ${git_utils_1.colors.cyan(path.basename(sqlFilePath))} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(sqlContent.length)})`)}`);
94
88
  console.log('');
@@ -103,7 +97,8 @@ async function importCommand(sqlFilePath, options = {}) {
103
97
  (0, git_utils_1.printDirtyWorkingTreeError)(status, 'import');
104
98
  console.log('');
105
99
  (0, git_utils_1.printMergeStrategyHelp)();
106
- process.exit(1);
100
+ (0, git_utils_1.fatal)('Working tree is not clean', 'Commit or stash your changes before importing.');
101
+ return;
107
102
  }
108
103
  }
109
104
  spinner.start('Parsing SQL schema');
@@ -144,26 +139,138 @@ async function importCommand(sqlFilePath, options = {}) {
144
139
  }
145
140
  }
146
141
  console.log('');
142
+ const ignorePatterns = (0, relqignore_1.loadRelqignore)(projectRoot);
143
+ let ignoredCount = 0;
144
+ const filteredTables = parsedSchema.tables.filter(table => {
145
+ if ((0, relqignore_1.isTableIgnored)(table.name, ignorePatterns).ignored) {
146
+ ignoredCount++;
147
+ return false;
148
+ }
149
+ return true;
150
+ }).map(table => {
151
+ const filteredColumns = table.columns.filter(col => {
152
+ if ((0, relqignore_1.isColumnIgnored)(table.name, col.name, ignorePatterns).ignored) {
153
+ ignoredCount++;
154
+ return false;
155
+ }
156
+ return true;
157
+ });
158
+ const filteredIndexes = table.indexes.filter(idx => {
159
+ if ((0, relqignore_1.isIndexIgnored)(table.name, idx.name, ignorePatterns).ignored) {
160
+ ignoredCount++;
161
+ return false;
162
+ }
163
+ return true;
164
+ });
165
+ const filteredConstraints = table.constraints.filter(con => {
166
+ if ((0, relqignore_1.isConstraintIgnored)(table.name, con.name, ignorePatterns).ignored) {
167
+ ignoredCount++;
168
+ return false;
169
+ }
170
+ return true;
171
+ });
172
+ return {
173
+ ...table,
174
+ columns: filteredColumns,
175
+ indexes: filteredIndexes,
176
+ constraints: filteredConstraints,
177
+ };
178
+ });
179
+ const filteredEnums = parsedSchema.enums.filter(e => {
180
+ if ((0, relqignore_1.isEnumIgnored)(e.name, ignorePatterns).ignored) {
181
+ ignoredCount++;
182
+ return false;
183
+ }
184
+ return true;
185
+ });
186
+ const filteredDomains = parsedSchema.domains.filter(d => {
187
+ if ((0, relqignore_1.isDomainIgnored)(d.name, ignorePatterns).ignored) {
188
+ ignoredCount++;
189
+ return false;
190
+ }
191
+ return true;
192
+ });
193
+ const filteredCompositeTypes = parsedSchema.compositeTypes.filter(c => {
194
+ if ((0, relqignore_1.isCompositeTypeIgnored)(c.name, ignorePatterns).ignored) {
195
+ ignoredCount++;
196
+ return false;
197
+ }
198
+ return true;
199
+ });
200
+ const filteredSequences = parsedSchema.sequences.filter(s => {
201
+ if ((0, relqignore_1.isSequenceIgnored)(s.name, ignorePatterns).ignored) {
202
+ ignoredCount++;
203
+ return false;
204
+ }
205
+ return true;
206
+ });
207
+ const filteredFunctions = functions.filter(f => {
208
+ if ((0, relqignore_1.isFunctionIgnored)(f.name, ignorePatterns).ignored) {
209
+ ignoredCount++;
210
+ return false;
211
+ }
212
+ return true;
213
+ });
214
+ const filteredSchema = {
215
+ tables: filteredTables,
216
+ enums: filteredEnums,
217
+ domains: filteredDomains,
218
+ compositeTypes: filteredCompositeTypes,
219
+ sequences: filteredSequences,
220
+ collations: parsedSchema.collations,
221
+ foreignTables: parsedSchema.foreignTables,
222
+ views: parsedSchema.views,
223
+ materializedViews: parsedSchema.materializedViews,
224
+ foreignServers: parsedSchema.foreignServers,
225
+ extensions: parsedSchema.extensions,
226
+ partitions: parsedSchema.partitions,
227
+ };
228
+ if (ignoredCount > 0) {
229
+ console.log(`${ignoredCount} object(s) ignored by .relqignore`);
230
+ }
231
+ const dependencyErrors = (0, relqignore_1.validateIgnoreDependencies)({
232
+ tables: filteredTables.map(t => ({
233
+ name: t.name,
234
+ columns: t.columns.map(c => ({
235
+ name: c.name,
236
+ type: c.dataType,
237
+ default: c.defaultValue,
238
+ })),
239
+ })),
240
+ enums: parsedSchema.enums,
241
+ domains: parsedSchema.domains,
242
+ sequences: parsedSchema.sequences,
243
+ compositeTypes: parsedSchema.compositeTypes,
244
+ }, ignorePatterns);
245
+ if (dependencyErrors.length > 0) {
246
+ spinner.stop();
247
+ const errorMessages = dependencyErrors.map(e => e.message).join('\n ');
248
+ (0, git_utils_1.fatal)('Dependency validation failed', `${errorMessages}\n\nEither un-ignore the type or add the column to .relqignore`);
249
+ return;
250
+ }
147
251
  spinner.start('Generating TypeScript schema');
148
- const dbSchema = convertToDbSchema(parsedSchema, functions, triggers, comments);
252
+ const dbSchema = convertToDbSchema(filteredSchema, filteredFunctions, triggers, comments);
149
253
  const typescriptContent = (0, type_generator_1.generateTypeScript)(dbSchema, {
150
254
  camelCase: true,
151
255
  includeFunctions,
152
256
  includeTriggers,
153
257
  });
154
258
  spinner.succeed('Generated TypeScript schema');
155
- const normalizedSchema = convertToNormalizedSchema(parsedSchema, functions, triggers);
259
+ const incomingSchema = convertToNormalizedSchema(filteredSchema, filteredFunctions, triggers);
156
260
  const existingSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
261
+ const replaceAll = options.theirs === true;
262
+ let mergedSchema;
157
263
  let changes = [];
158
264
  if (existingSnapshot) {
159
265
  spinner.start('Detecting changes');
266
+ mergedSchema = mergeSchemas(existingSnapshot, incomingSchema, replaceAll);
160
267
  const beforeSchema = snapshotToDbSchema(existingSnapshot);
161
- const afterSchema = snapshotToDbSchema(normalizedSchema);
268
+ const afterSchema = snapshotToDbSchema(mergedSchema);
162
269
  changes = (0, schema_comparator_1.compareSchemas)(beforeSchema, afterSchema);
163
270
  spinner.stop();
164
271
  if (changes.length > 0) {
165
272
  console.log('');
166
- console.log(`${git_utils_1.colors.bold('Changes detected:')}`);
273
+ console.log(`${git_utils_1.colors.bold('Changes detected:')}${replaceAll ? git_utils_1.colors.yellow(' (--theirs: full replacement)') : ''}`);
167
274
  console.log('');
168
275
  const creates = changes.filter(c => c.type === 'CREATE');
169
276
  const alters = changes.filter(c => c.type === 'ALTER');
@@ -185,11 +292,17 @@ async function importCommand(sqlFilePath, options = {}) {
185
292
  }
186
293
  }
187
294
  if (drops.length > 0) {
188
- for (const change of drops.slice(0, 10)) {
189
- console.log(`\t${git_utils_1.colors.red((0, change_tracker_1.getChangeDisplayName)(change))}`);
295
+ if (replaceAll) {
296
+ for (const change of drops.slice(0, 10)) {
297
+ console.log(`\t${git_utils_1.colors.red((0, change_tracker_1.getChangeDisplayName)(change))}`);
298
+ }
299
+ if (drops.length > 10) {
300
+ console.log(`\t${git_utils_1.colors.gray(`... and ${drops.length - 10} more deletions`)}`);
301
+ }
190
302
  }
191
- if (drops.length > 10) {
192
- console.log(`\t${git_utils_1.colors.gray(`... and ${drops.length - 10} more deletions`)}`);
303
+ else {
304
+ console.log('');
305
+ console.log(`${drops.length} object(s) only in existing schema (preserved)`);
193
306
  }
194
307
  }
195
308
  console.log('');
@@ -201,16 +314,25 @@ async function importCommand(sqlFilePath, options = {}) {
201
314
  }
202
315
  }
203
316
  else {
317
+ mergedSchema = incomingSchema;
204
318
  changes = [];
205
319
  console.log(`${git_utils_1.colors.cyan('First import')} - creating initial snapshot`);
206
320
  }
321
+ const mergedDbSchema = snapshotToDbSchemaForGeneration(mergedSchema);
322
+ const finalTypescriptContent = (0, type_generator_1.generateTypeScript)(mergedDbSchema, {
323
+ camelCase: true,
324
+ includeFunctions,
325
+ includeTriggers,
326
+ });
207
327
  if (dryRun) {
208
328
  console.log('');
209
329
  console.log(`${git_utils_1.colors.yellow('Dry run mode')} - no files written`);
210
330
  console.log('');
211
331
  console.log('Would write:');
212
- console.log(` ${git_utils_1.colors.cyan(options.output || './db/schema.ts')} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(typescriptContent.length)})`)}`);
213
- console.log(` ${git_utils_1.colors.cyan('.relq/snapshot.json')}`);
332
+ const dryRunOutputPath = options.output || './db/schema.ts';
333
+ const dryRunAbsPath = path.resolve(projectRoot, dryRunOutputPath);
334
+ console.log(` ${git_utils_1.colors.cyan(dryRunAbsPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
335
+ console.log(` ${git_utils_1.colors.cyan(path.join(projectRoot, '.relq/snapshot.json'))}`);
214
336
  if (changes.length > 0) {
215
337
  console.log(` Stage ${changes.length} change(s)`);
216
338
  }
@@ -218,29 +340,29 @@ async function importCommand(sqlFilePath, options = {}) {
218
340
  return;
219
341
  }
220
342
  const outputPath = options.output || './db/schema.ts';
221
- const absoluteOutputPath = path.resolve(outputPath);
343
+ const absoluteOutputPath = path.resolve(projectRoot, outputPath);
222
344
  const outputDir = path.dirname(absoluteOutputPath);
223
345
  if (!fs.existsSync(outputDir)) {
224
346
  fs.mkdirSync(outputDir, { recursive: true });
225
347
  }
226
- fs.writeFileSync(absoluteOutputPath, typescriptContent, 'utf-8');
227
- console.log(`Written ${git_utils_1.colors.cyan(outputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(typescriptContent.length)})`)}`);
228
- (0, repo_manager_1.saveSnapshot)(normalizedSchema, projectRoot);
348
+ fs.writeFileSync(absoluteOutputPath, finalTypescriptContent, 'utf-8');
349
+ console.log(`Written ${git_utils_1.colors.cyan(absoluteOutputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
350
+ (0, repo_manager_1.saveSnapshot)(mergedSchema, projectRoot);
229
351
  if (changes.length > 0) {
230
352
  (0, repo_manager_1.addUnstagedChanges)(changes, projectRoot);
231
353
  (0, repo_manager_1.stageChanges)(['.'], projectRoot);
232
354
  console.log('');
233
- console.log(`${git_utils_1.colors.green('✓')} ${changes.length} change(s) staged for commit`);
355
+ console.log(`${changes.length} change(s) staged for commit`);
234
356
  }
235
357
  console.log('');
236
- console.log(`${git_utils_1.colors.green('Import successful.')}`);
358
+ console.log('Import successful.');
237
359
  console.log('');
238
360
  if (changes.length > 0) {
239
- (0, git_utils_1.hint)('Run "relq status" to see staged changes');
240
- (0, git_utils_1.hint)('Run "relq commit -m <message>" to commit');
361
+ (0, git_utils_1.hint)("run 'relq status' to see staged changes");
362
+ (0, git_utils_1.hint)("run 'relq commit -m <message>' to commit");
241
363
  }
242
364
  else {
243
- (0, git_utils_1.hint)('Run "relq status" to see current state');
365
+ (0, git_utils_1.hint)("run 'relq status' to see current state");
244
366
  }
245
367
  console.log('');
246
368
  }
@@ -337,6 +459,7 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
337
459
  cycle: s.cycle,
338
460
  ownedBy: s.ownedBy,
339
461
  })) || [],
462
+ collations: [],
340
463
  extensions: parsed.extensions,
341
464
  partitions: parsed.partitions,
342
465
  functions: functions.map(f => ({
@@ -442,6 +565,17 @@ function convertToNormalizedSchema(parsed, functions = [], triggers = []) {
442
565
  forEach: 'STATEMENT',
443
566
  functionName: t.functionName || '',
444
567
  })),
568
+ views: parsed.views.map(v => ({
569
+ name: v.name,
570
+ schema: v.schema || 'public',
571
+ definition: v.definition,
572
+ })),
573
+ materializedViews: parsed.materializedViews.map(mv => ({
574
+ name: mv.name,
575
+ schema: mv.schema || 'public',
576
+ definition: mv.definition,
577
+ withData: mv.withData ?? true,
578
+ })),
445
579
  };
446
580
  }
447
581
  function snapshotToDbSchema(snapshot) {
@@ -521,4 +655,134 @@ function snapshotToDbSchema(snapshot) {
521
655
  sequences: [],
522
656
  });
523
657
  }
658
+ function snapshotToDbSchemaForGeneration(snapshot) {
659
+ return {
660
+ tables: snapshot.tables.map(t => ({
661
+ name: t.name,
662
+ schema: t.schema || 'public',
663
+ comment: null,
664
+ columns: t.columns.map(c => ({
665
+ name: c.name,
666
+ dataType: c.type,
667
+ udtName: c.type,
668
+ isNullable: c.nullable,
669
+ defaultValue: c.default ?? null,
670
+ isPrimaryKey: c.primaryKey || false,
671
+ isUnique: c.unique || false,
672
+ maxLength: null,
673
+ precision: null,
674
+ scale: null,
675
+ references: null,
676
+ comment: null,
677
+ isGenerated: c.isGenerated || false,
678
+ generationExpression: c.generationExpression || null,
679
+ identityGeneration: c.identity?.type || null,
680
+ })),
681
+ indexes: t.indexes.map(i => ({
682
+ name: i.name,
683
+ columns: Array.isArray(i.columns) ? i.columns : [i.columns],
684
+ isUnique: i.unique || false,
685
+ isPrimary: false,
686
+ type: i.type || 'btree',
687
+ definition: i.definition,
688
+ whereClause: i.whereClause,
689
+ comment: null,
690
+ })),
691
+ constraints: t.constraints?.map(c => ({
692
+ name: c.name,
693
+ type: c.type,
694
+ columns: [],
695
+ definition: c.definition,
696
+ })) || [],
697
+ rowCount: 0,
698
+ isPartitioned: t.isPartitioned || false,
699
+ partitionType: t.partitionType,
700
+ partitionKey: t.partitionKey ? [t.partitionKey].flat() : undefined,
701
+ })),
702
+ enums: snapshot.enums?.map(e => ({
703
+ name: e.name,
704
+ values: e.values,
705
+ })) || [],
706
+ domains: snapshot.domains?.map(d => ({
707
+ name: d.name,
708
+ baseType: d.baseType,
709
+ isNotNull: d.notNull || false,
710
+ defaultValue: d.default || null,
711
+ checkExpression: d.check || null,
712
+ check: d.check,
713
+ default: d.default,
714
+ notNull: d.notNull,
715
+ })) || [],
716
+ compositeTypes: snapshot.compositeTypes?.map(c => ({
717
+ name: c.name,
718
+ attributes: c.attributes || [],
719
+ })) || [],
720
+ sequences: snapshot.sequences?.map(s => ({
721
+ name: s.name,
722
+ dataType: s.dataType,
723
+ start: s.startValue,
724
+ increment: s.increment,
725
+ minValue: s.minValue,
726
+ maxValue: s.maxValue,
727
+ cache: s.cache,
728
+ cycle: s.cycle,
729
+ ownedBy: s.ownedBy ?? undefined,
730
+ })) || [],
731
+ collations: [],
732
+ extensions: (snapshot.extensions || []).map(e => typeof e === 'string' ? e : e.name),
733
+ partitions: [],
734
+ functions: snapshot.functions?.map(f => ({
735
+ name: f.name,
736
+ schema: 'public',
737
+ returnType: f.returnType,
738
+ argTypes: f.argTypes || [],
739
+ language: f.language,
740
+ definition: '',
741
+ isAggregate: false,
742
+ volatility: 'VOLATILE',
743
+ })) || [],
744
+ triggers: snapshot.triggers?.map(t => ({
745
+ name: t.name,
746
+ tableName: t.table,
747
+ timing: t.timing,
748
+ event: t.events?.[0] || '',
749
+ functionName: t.functionName || '',
750
+ definition: '',
751
+ isEnabled: t.isEnabled ?? true,
752
+ })) || [],
753
+ policies: [],
754
+ foreignServers: [],
755
+ foreignTables: [],
756
+ };
757
+ }
758
+ function mergeSchemas(existing, incoming, replaceAll = false) {
759
+ if (replaceAll) {
760
+ return incoming;
761
+ }
762
+ function mergeByName(existingArr, incomingArr) {
763
+ const incomingMap = new Map(incomingArr.map(item => [item.name, item]));
764
+ const resultMap = new Map();
765
+ for (const item of existingArr) {
766
+ resultMap.set(item.name, item);
767
+ }
768
+ for (const item of incomingArr) {
769
+ resultMap.set(item.name, item);
770
+ }
771
+ return Array.from(resultMap.values());
772
+ }
773
+ return {
774
+ extensions: mergeByName(existing.extensions || [], incoming.extensions || []),
775
+ enums: mergeByName(existing.enums || [], incoming.enums || []),
776
+ domains: mergeByName(existing.domains || [], incoming.domains || []),
777
+ compositeTypes: mergeByName(existing.compositeTypes || [], incoming.compositeTypes || []),
778
+ sequences: mergeByName(existing.sequences || [], incoming.sequences || []),
779
+ collations: mergeByName(existing.collations || [], incoming.collations || []),
780
+ tables: mergeByName(existing.tables || [], incoming.tables || []),
781
+ functions: mergeByName(existing.functions || [], incoming.functions || []),
782
+ triggers: mergeByName(existing.triggers || [], incoming.triggers || []),
783
+ views: mergeByName(existing.views || [], incoming.views || []),
784
+ materializedViews: mergeByName(existing.materializedViews || [], incoming.materializedViews || []),
785
+ foreignTables: mergeByName(existing.foreignTables || [], incoming.foreignTables || []),
786
+ };
787
+ }
524
788
  exports.default = importCommand;