relq 1.0.1 → 1.0.2

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 (159) 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 +30 -1
  6. package/dist/cjs/cli/commands/branch.cjs +141 -0
  7. package/dist/cjs/cli/commands/checkout.cjs +134 -0
  8. package/dist/cjs/cli/commands/cherry-pick.cjs +283 -0
  9. package/dist/cjs/cli/commands/diff.cjs +148 -69
  10. package/dist/cjs/cli/commands/export.cjs +64 -5
  11. package/dist/cjs/cli/commands/fetch.cjs +34 -4
  12. package/dist/cjs/cli/commands/history.cjs +1 -1
  13. package/dist/cjs/cli/commands/import.cjs +283 -12
  14. package/dist/cjs/cli/commands/log.cjs +75 -0
  15. package/dist/cjs/cli/commands/merge.cjs +224 -0
  16. package/dist/cjs/cli/commands/migrate.cjs +1 -1
  17. package/dist/cjs/cli/commands/pull.cjs +123 -7
  18. package/dist/cjs/cli/commands/push.cjs +245 -29
  19. package/dist/cjs/cli/commands/remote.cjs +16 -0
  20. package/dist/cjs/cli/commands/reset.cjs +169 -0
  21. package/dist/cjs/cli/commands/resolve.cjs +193 -0
  22. package/dist/cjs/cli/commands/rollback.cjs +1 -1
  23. package/dist/cjs/cli/commands/stash.cjs +154 -0
  24. package/dist/cjs/cli/commands/status.cjs +48 -0
  25. package/dist/cjs/cli/commands/tag.cjs +147 -0
  26. package/dist/cjs/cli/index.cjs +46 -2
  27. package/dist/cjs/cli/utils/commit-manager.cjs +3 -3
  28. package/dist/cjs/cli/utils/env-loader.cjs +3 -2
  29. package/dist/cjs/cli/utils/fast-introspect.cjs +1 -1
  30. package/dist/cjs/cli/utils/project-root.cjs +56 -0
  31. package/dist/cjs/cli/utils/relqignore.cjs +296 -38
  32. package/dist/cjs/cli/utils/repo-manager.cjs +45 -3
  33. package/dist/cjs/cli/utils/schema-introspect.cjs +2 -2
  34. package/dist/cjs/cli/utils/sql-generator.cjs +1 -1
  35. package/dist/cjs/cli/utils/sql-parser.cjs +94 -7
  36. package/dist/cjs/condition/array-condition-builder.cjs +1 -1
  37. package/dist/cjs/condition/condition-collector.cjs +1 -1
  38. package/dist/cjs/condition/fulltext-condition-builder.cjs +1 -1
  39. package/dist/cjs/condition/geometric-condition-builder.cjs +1 -1
  40. package/dist/cjs/condition/jsonb-condition-builder.cjs +1 -1
  41. package/dist/cjs/condition/network-condition-builder.cjs +1 -1
  42. package/dist/cjs/condition/range-condition-builder.cjs +1 -1
  43. package/dist/cjs/copy/copy-builder.cjs +1 -1
  44. package/dist/cjs/core/query-builder.cjs +1 -1
  45. package/dist/cjs/core/relq-client.cjs +2 -2
  46. package/dist/cjs/count/count-builder.cjs +1 -1
  47. package/dist/cjs/cte/cte-builder.cjs +1 -1
  48. package/dist/cjs/delete/delete-builder.cjs +1 -1
  49. package/dist/cjs/function/create-function-builder.cjs +1 -1
  50. package/dist/cjs/functions/advanced-functions.cjs +1 -1
  51. package/dist/cjs/functions/case-builder.cjs +1 -1
  52. package/dist/cjs/functions/geometric-functions.cjs +1 -1
  53. package/dist/cjs/functions/network-functions.cjs +1 -1
  54. package/dist/cjs/functions/sql-functions.cjs +1 -1
  55. package/dist/cjs/indexing/create-index-builder.cjs +1 -1
  56. package/dist/cjs/indexing/drop-index-builder.cjs +1 -1
  57. package/dist/cjs/insert/conflict-builder.cjs +1 -1
  58. package/dist/cjs/insert/insert-builder.cjs +1 -1
  59. package/dist/cjs/maintenance/vacuum-builder.cjs +1 -1
  60. package/dist/cjs/pubsub/listen-notify-builder.cjs +1 -1
  61. package/dist/cjs/pubsub/listener-connection.cjs +2 -2
  62. package/dist/cjs/raw/raw-query-builder.cjs +1 -1
  63. package/dist/cjs/schema/schema-builder.cjs +1 -1
  64. package/dist/cjs/schema-definition/table-definition.cjs +1 -1
  65. package/dist/cjs/select/aggregate-builder.cjs +1 -1
  66. package/dist/cjs/select/select-builder.cjs +1 -1
  67. package/dist/cjs/sequence/sequence-builder.cjs +1 -1
  68. package/dist/cjs/table/alter-table-builder.cjs +1 -1
  69. package/dist/cjs/table/constraint-builder.cjs +1 -1
  70. package/dist/cjs/table/create-table-builder.cjs +1 -1
  71. package/dist/cjs/table/partition-builder.cjs +1 -1
  72. package/dist/cjs/table/truncate-builder.cjs +1 -1
  73. package/dist/cjs/transaction/transaction-builder.cjs +1 -1
  74. package/dist/cjs/trigger/create-trigger-builder.cjs +1 -1
  75. package/dist/cjs/update/array-update-builder.cjs +1 -1
  76. package/dist/cjs/update/update-builder.cjs +1 -1
  77. package/dist/cjs/utils/index.cjs +1 -1
  78. package/dist/cjs/view/create-view-builder.cjs +1 -1
  79. package/dist/cjs/window/window-builder.cjs +1 -1
  80. package/dist/esm/cli/commands/add.js +30 -1
  81. package/dist/esm/cli/commands/branch.js +105 -0
  82. package/dist/esm/cli/commands/checkout.js +98 -0
  83. package/dist/esm/cli/commands/cherry-pick.js +247 -0
  84. package/dist/esm/cli/commands/diff.js +148 -69
  85. package/dist/esm/cli/commands/export.js +64 -5
  86. package/dist/esm/cli/commands/fetch.js +35 -5
  87. package/dist/esm/cli/commands/history.js +1 -1
  88. package/dist/esm/cli/commands/import.js +283 -12
  89. package/dist/esm/cli/commands/log.js +74 -0
  90. package/dist/esm/cli/commands/merge.js +188 -0
  91. package/dist/esm/cli/commands/migrate.js +1 -1
  92. package/dist/esm/cli/commands/pull.js +124 -8
  93. package/dist/esm/cli/commands/push.js +246 -30
  94. package/dist/esm/cli/commands/remote.js +13 -0
  95. package/dist/esm/cli/commands/reset.js +133 -0
  96. package/dist/esm/cli/commands/resolve.js +157 -0
  97. package/dist/esm/cli/commands/rollback.js +1 -1
  98. package/dist/esm/cli/commands/stash.js +118 -0
  99. package/dist/esm/cli/commands/status.js +15 -0
  100. package/dist/esm/cli/commands/tag.js +111 -0
  101. package/dist/esm/cli/index.js +47 -3
  102. package/dist/esm/cli/utils/commit-manager.js +3 -3
  103. package/dist/esm/cli/utils/env-loader.js +3 -2
  104. package/dist/esm/cli/utils/fast-introspect.js +1 -1
  105. package/dist/esm/cli/utils/project-root.js +19 -0
  106. package/dist/esm/cli/utils/relqignore.js +277 -37
  107. package/dist/esm/cli/utils/repo-manager.js +41 -3
  108. package/dist/esm/cli/utils/schema-introspect.js +2 -2
  109. package/dist/esm/cli/utils/sql-generator.js +1 -1
  110. package/dist/esm/cli/utils/sql-parser.js +94 -7
  111. package/dist/esm/condition/array-condition-builder.js +1 -1
  112. package/dist/esm/condition/condition-collector.js +1 -1
  113. package/dist/esm/condition/fulltext-condition-builder.js +1 -1
  114. package/dist/esm/condition/geometric-condition-builder.js +1 -1
  115. package/dist/esm/condition/jsonb-condition-builder.js +1 -1
  116. package/dist/esm/condition/network-condition-builder.js +1 -1
  117. package/dist/esm/condition/range-condition-builder.js +1 -1
  118. package/dist/esm/copy/copy-builder.js +1 -1
  119. package/dist/esm/core/query-builder.js +1 -1
  120. package/dist/esm/core/relq-client.js +2 -2
  121. package/dist/esm/count/count-builder.js +1 -1
  122. package/dist/esm/cte/cte-builder.js +1 -1
  123. package/dist/esm/delete/delete-builder.js +1 -1
  124. package/dist/esm/function/create-function-builder.js +1 -1
  125. package/dist/esm/functions/advanced-functions.js +1 -1
  126. package/dist/esm/functions/case-builder.js +1 -1
  127. package/dist/esm/functions/geometric-functions.js +1 -1
  128. package/dist/esm/functions/network-functions.js +1 -1
  129. package/dist/esm/functions/sql-functions.js +1 -1
  130. package/dist/esm/indexing/create-index-builder.js +1 -1
  131. package/dist/esm/indexing/drop-index-builder.js +1 -1
  132. package/dist/esm/insert/conflict-builder.js +1 -1
  133. package/dist/esm/insert/insert-builder.js +1 -1
  134. package/dist/esm/maintenance/vacuum-builder.js +1 -1
  135. package/dist/esm/pubsub/listen-notify-builder.js +1 -1
  136. package/dist/esm/pubsub/listener-connection.js +2 -2
  137. package/dist/esm/raw/raw-query-builder.js +1 -1
  138. package/dist/esm/schema/schema-builder.js +1 -1
  139. package/dist/esm/schema-definition/table-definition.js +1 -1
  140. package/dist/esm/select/aggregate-builder.js +1 -1
  141. package/dist/esm/select/select-builder.js +1 -1
  142. package/dist/esm/sequence/sequence-builder.js +1 -1
  143. package/dist/esm/table/alter-table-builder.js +1 -1
  144. package/dist/esm/table/constraint-builder.js +1 -1
  145. package/dist/esm/table/create-table-builder.js +1 -1
  146. package/dist/esm/table/partition-builder.js +1 -1
  147. package/dist/esm/table/truncate-builder.js +1 -1
  148. package/dist/esm/transaction/transaction-builder.js +1 -1
  149. package/dist/esm/trigger/create-trigger-builder.js +1 -1
  150. package/dist/esm/update/array-update-builder.js +1 -1
  151. package/dist/esm/update/update-builder.js +1 -1
  152. package/dist/esm/utils/index.js +1 -1
  153. package/dist/esm/view/create-view-builder.js +1 -1
  154. package/dist/esm/window/window-builder.js +1 -1
  155. package/package.json +1 -1
  156. /package/dist/{addons/buffer.js → esm/addon/buffer/index.js} +0 -0
  157. /package/dist/{addons/pg.js → esm/addon/pg/index.js} +0 -0
  158. /package/dist/{addons/pg-cursor.js → esm/addon/pg-cursor/index.js} +0 -0
  159. /package/dist/{addons/pg-format.js → esm/addon/pg-format/index.js} +0 -0
@@ -1,23 +1,88 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ const REQUIRES_PARENT = [
4
+ 'COLUMN', 'INDEX', 'CONSTRAINT', 'CHECK', 'PRIMARY_KEY',
5
+ 'FOREIGN_KEY', 'EXCLUSION', 'PARTITION', 'TRIGGER'
6
+ ];
3
7
  const DEFAULT_PATTERNS = [
4
- '_relq_*',
5
- 'pg_*',
6
- '_temp_*',
7
- 'tmp_*',
8
+ 'TABLE:_relq_*',
9
+ 'TABLE:pg_*',
10
+ 'TABLE:_temp_*',
11
+ 'TABLE:tmp_*',
8
12
  ];
13
+ export function parsePattern(line) {
14
+ const trimmed = line.trim();
15
+ if (!trimmed || trimmed.startsWith('#')) {
16
+ return null;
17
+ }
18
+ let negated = false;
19
+ let pattern = trimmed;
20
+ if (pattern.startsWith('!')) {
21
+ negated = true;
22
+ pattern = pattern.slice(1);
23
+ }
24
+ const colonIndex = pattern.indexOf(':');
25
+ if (colonIndex > 0) {
26
+ const typeStr = pattern.slice(0, colonIndex).toUpperCase();
27
+ const rest = pattern.slice(colonIndex + 1);
28
+ const validTypes = [
29
+ 'TABLE', 'COLUMN', 'INDEX', 'CONSTRAINT', 'CHECK', 'PRIMARY_KEY',
30
+ 'FOREIGN_KEY', 'EXCLUSION', 'PARTITION', 'ENUM', 'DOMAIN', 'SEQUENCE',
31
+ 'COMPOSITE_TYPE', 'FUNCTION', 'PROCEDURE', 'TRIGGER', 'VIEW',
32
+ 'MATERIALIZED_VIEW', 'FOREIGN_TABLE', 'EXTENSION', 'COLLATION'
33
+ ];
34
+ if (validTypes.includes(typeStr)) {
35
+ const type = typeStr;
36
+ if (REQUIRES_PARENT.includes(type)) {
37
+ const dotIndex = rest.indexOf('.');
38
+ if (dotIndex > 0) {
39
+ return {
40
+ type,
41
+ parent: rest.slice(0, dotIndex),
42
+ pattern: rest.slice(dotIndex + 1),
43
+ negated,
44
+ raw: trimmed,
45
+ };
46
+ }
47
+ else {
48
+ console.warn(`Warning: ${type} pattern requires table name (e.g., ${type}:table_name.pattern)`);
49
+ return null;
50
+ }
51
+ }
52
+ else {
53
+ return {
54
+ type,
55
+ parent: null,
56
+ pattern: rest,
57
+ negated,
58
+ raw: trimmed,
59
+ };
60
+ }
61
+ }
62
+ }
63
+ return {
64
+ type: 'TABLE',
65
+ parent: null,
66
+ pattern,
67
+ negated,
68
+ raw: trimmed,
69
+ };
70
+ }
9
71
  export function loadRelqignore(projectRoot = process.cwd()) {
10
72
  const ignorePath = path.join(projectRoot, '.relqignore');
11
- const patterns = [...DEFAULT_PATTERNS];
73
+ const patterns = [];
74
+ for (const defaultPattern of DEFAULT_PATTERNS) {
75
+ const parsed = parsePattern(defaultPattern);
76
+ if (parsed)
77
+ patterns.push(parsed);
78
+ }
12
79
  if (fs.existsSync(ignorePath)) {
13
80
  const content = fs.readFileSync(ignorePath, 'utf-8');
14
81
  const lines = content.split('\n');
15
82
  for (const line of lines) {
16
- const trimmed = line.trim();
17
- if (!trimmed || trimmed.startsWith('#')) {
18
- continue;
19
- }
20
- patterns.push(trimmed);
83
+ const parsed = parsePattern(line);
84
+ if (parsed)
85
+ patterns.push(parsed);
21
86
  }
22
87
  }
23
88
  return patterns;
@@ -28,40 +93,58 @@ export function createDefaultRelqignore(projectRoot = process.cwd()) {
28
93
  return;
29
94
  }
30
95
  const content = `# Relq Ignore File
31
- # Tables and functions matching these patterns will be ignored
96
+ # Objects matching these patterns will be ignored in import/export/add/commit
97
+
98
+ # =============================================================================
99
+ # PATTERN FORMAT
100
+ # =============================================================================
101
+ # TYPE:pattern - Match specific object type
102
+ # TYPE:table.pattern - Match sub-objects (columns, indexes, etc.)
103
+ # pattern - Match tables (backward compatible)
104
+ # !pattern - Negate (un-ignore) a pattern
105
+
106
+ # =============================================================================
107
+ # TYPES
108
+ # =============================================================================
109
+ # TABLE, COLUMN, INDEX, CONSTRAINT, CHECK, PRIMARY_KEY, FOREIGN_KEY, EXCLUSION
110
+ # PARTITION, ENUM, DOMAIN, SEQUENCE, COMPOSITE_TYPE, FUNCTION, PROCEDURE
111
+ # TRIGGER, VIEW, MATERIALIZED_VIEW, FOREIGN_TABLE, EXTENSION, COLLATION
112
+
113
+ # =============================================================================
114
+ # DEFAULT PATTERNS (always applied)
115
+ # =============================================================================
116
+ # TABLE:_relq_* - Relq internal tables
117
+ # TABLE:pg_* - PostgreSQL system tables
118
+ # TABLE:_temp_* - Temporary tables
119
+ # TABLE:tmp_* - Temporary tables
120
+
121
+ # =============================================================================
122
+ # EXAMPLES
123
+ # =============================================================================
124
+
125
+ # Ignore specific tables
126
+ # TABLE:debug_*
127
+ # TABLE:test_*
128
+
129
+ # Ignore sensitive columns (table.column format required)
130
+ # COLUMN:users.password_hash
131
+ # COLUMN:*.api_key
32
132
 
33
- # Relq internal tables (always ignored)
34
- _relq_*
133
+ # Ignore temporary indexes
134
+ # INDEX:*.idx_temp_*
35
135
 
36
- # PostgreSQL system tables
37
- pg_*
136
+ # Ignore debug functions
137
+ # FUNCTION:debug_*
38
138
 
39
- # Temporary tables
40
- _temp_*
41
- tmp_*
139
+ # Ignore internal triggers
140
+ # TRIGGER:audit_logs.*
42
141
 
43
- # Add your tables/functions to ignore below:
44
- # analytics_raw
45
- # debug_*
46
- # test_*
142
+ # Ignore test enums
143
+ # ENUM:test_*
47
144
  `;
48
145
  fs.writeFileSync(ignorePath, content, 'utf-8');
49
146
  }
50
- export function isIgnored(name, patterns) {
51
- for (const pattern of patterns) {
52
- if (matchPattern(name, pattern)) {
53
- return true;
54
- }
55
- }
56
- return false;
57
- }
58
- export function filterIgnored(items, patterns) {
59
- return items.filter(item => !isIgnored(item.name, patterns));
60
- }
61
- function matchPattern(name, pattern) {
62
- if (pattern.startsWith('!')) {
63
- return !matchPattern(name, pattern.slice(1));
64
- }
147
+ function matchGlob(name, pattern) {
65
148
  const regexPattern = pattern
66
149
  .replace(/[.+^${}()|[\]\\]/g, '\\$&')
67
150
  .replace(/\*/g, '.*')
@@ -69,6 +152,163 @@ function matchPattern(name, pattern) {
69
152
  const regex = new RegExp(`^${regexPattern}$`, 'i');
70
153
  return regex.test(name);
71
154
  }
155
+ export function isIgnored(objectType, objectName, parentName, patterns) {
156
+ let isIgnored = false;
157
+ let matchedPattern;
158
+ for (const pattern of patterns) {
159
+ if (pattern.type !== null && pattern.type !== objectType) {
160
+ continue;
161
+ }
162
+ if (pattern.parent !== null) {
163
+ if (parentName === null || !matchGlob(parentName, pattern.parent)) {
164
+ continue;
165
+ }
166
+ }
167
+ if (matchGlob(objectName, pattern.pattern)) {
168
+ if (pattern.negated) {
169
+ isIgnored = false;
170
+ matchedPattern = pattern;
171
+ }
172
+ else {
173
+ isIgnored = true;
174
+ matchedPattern = pattern;
175
+ }
176
+ }
177
+ }
178
+ return {
179
+ ignored: isIgnored,
180
+ pattern: matchedPattern,
181
+ reason: matchedPattern ? `Matched pattern: ${matchedPattern.raw}` : undefined,
182
+ };
183
+ }
184
+ export function isTableIgnored(tableName, patterns) {
185
+ return isIgnored('TABLE', tableName, null, patterns);
186
+ }
187
+ export function isColumnIgnored(tableName, columnName, patterns) {
188
+ return isIgnored('COLUMN', columnName, tableName, patterns);
189
+ }
190
+ export function isIndexIgnored(tableName, indexName, patterns) {
191
+ return isIgnored('INDEX', indexName, tableName, patterns);
192
+ }
193
+ export function isConstraintIgnored(tableName, constraintName, patterns) {
194
+ return isIgnored('CONSTRAINT', constraintName, tableName, patterns);
195
+ }
196
+ export function isTriggerIgnored(tableName, triggerName, patterns) {
197
+ return isIgnored('TRIGGER', triggerName, tableName, patterns);
198
+ }
199
+ export function isEnumIgnored(enumName, patterns) {
200
+ return isIgnored('ENUM', enumName, null, patterns);
201
+ }
202
+ export function isDomainIgnored(domainName, patterns) {
203
+ return isIgnored('DOMAIN', domainName, null, patterns);
204
+ }
205
+ export function isSequenceIgnored(sequenceName, patterns) {
206
+ return isIgnored('SEQUENCE', sequenceName, null, patterns);
207
+ }
208
+ export function isCompositeTypeIgnored(typeName, patterns) {
209
+ return isIgnored('COMPOSITE_TYPE', typeName, null, patterns);
210
+ }
211
+ export function isFunctionIgnored(functionName, patterns) {
212
+ return isIgnored('FUNCTION', functionName, null, patterns);
213
+ }
214
+ export function isViewIgnored(viewName, patterns) {
215
+ return isIgnored('VIEW', viewName, null, patterns);
216
+ }
217
+ export function validateIgnoreDependencies(schema, patterns) {
218
+ const errors = [];
219
+ const ignoredEnums = new Set();
220
+ const ignoredDomains = new Set();
221
+ const ignoredSequences = new Set();
222
+ const ignoredComposites = new Set();
223
+ for (const e of schema.enums) {
224
+ if (isEnumIgnored(e.name, patterns).ignored) {
225
+ ignoredEnums.add(e.name.toLowerCase());
226
+ }
227
+ }
228
+ for (const d of schema.domains) {
229
+ if (isDomainIgnored(d.name, patterns).ignored) {
230
+ ignoredDomains.add(d.name.toLowerCase());
231
+ }
232
+ }
233
+ for (const s of schema.sequences) {
234
+ if (isSequenceIgnored(s.name, patterns).ignored) {
235
+ ignoredSequences.add(s.name.toLowerCase());
236
+ }
237
+ }
238
+ for (const c of schema.compositeTypes) {
239
+ if (isCompositeTypeIgnored(c.name, patterns).ignored) {
240
+ ignoredComposites.add(c.name.toLowerCase());
241
+ }
242
+ }
243
+ for (const table of schema.tables) {
244
+ if (isTableIgnored(table.name, patterns).ignored) {
245
+ continue;
246
+ }
247
+ for (const column of table.columns) {
248
+ if (isColumnIgnored(table.name, column.name, patterns).ignored) {
249
+ continue;
250
+ }
251
+ const typeLower = column.type.toLowerCase().replace(/\[\]$/, '');
252
+ if (ignoredEnums.has(typeLower)) {
253
+ errors.push({
254
+ type: 'ENUM',
255
+ name: column.type,
256
+ usedBy: { table: table.name, column: column.name },
257
+ message: `Column "${table.name}.${column.name}" uses ignored ENUM "${column.type}". Either un-ignore the ENUM or ignore this column.`,
258
+ });
259
+ }
260
+ if (ignoredDomains.has(typeLower)) {
261
+ errors.push({
262
+ type: 'DOMAIN',
263
+ name: column.type,
264
+ usedBy: { table: table.name, column: column.name },
265
+ message: `Column "${table.name}.${column.name}" uses ignored DOMAIN "${column.type}". Either un-ignore the DOMAIN or ignore this column.`,
266
+ });
267
+ }
268
+ if (ignoredComposites.has(typeLower)) {
269
+ errors.push({
270
+ type: 'COMPOSITE_TYPE',
271
+ name: column.type,
272
+ usedBy: { table: table.name, column: column.name },
273
+ message: `Column "${table.name}.${column.name}" uses ignored COMPOSITE_TYPE "${column.type}". Either un-ignore the type or ignore this column.`,
274
+ });
275
+ }
276
+ if (column.default) {
277
+ const seqMatch = column.default.match(/nextval\(['"]?([^'"()]+)['"]?/i);
278
+ if (seqMatch) {
279
+ const seqName = seqMatch[1].toLowerCase().replace(/::regclass$/, '');
280
+ if (ignoredSequences.has(seqName)) {
281
+ errors.push({
282
+ type: 'SEQUENCE',
283
+ name: seqMatch[1],
284
+ usedBy: { table: table.name, column: column.name },
285
+ message: `Column "${table.name}.${column.name}" uses ignored SEQUENCE "${seqMatch[1]}". Either un-ignore the SEQUENCE or ignore this column.`,
286
+ });
287
+ }
288
+ }
289
+ }
290
+ }
291
+ }
292
+ return errors;
293
+ }
294
+ export function filterTables(tables, patterns) {
295
+ return tables.filter(t => !isTableIgnored(t.name, patterns).ignored);
296
+ }
297
+ export function filterColumns(tableName, columns, patterns) {
298
+ return columns.filter(c => !isColumnIgnored(tableName, c.name, patterns).ignored);
299
+ }
300
+ export function filterIndexes(tableName, indexes, patterns) {
301
+ return indexes.filter(i => !isIndexIgnored(tableName, i.name, patterns).ignored);
302
+ }
303
+ export function filterEnums(enums, patterns) {
304
+ return enums.filter(e => !isEnumIgnored(e.name, patterns).ignored);
305
+ }
306
+ export function filterDomains(domains, patterns) {
307
+ return domains.filter(d => !isDomainIgnored(d.name, patterns).ignored);
308
+ }
72
309
  export function getIgnorePatterns(projectRoot = process.cwd()) {
73
310
  return loadRelqignore(projectRoot);
74
311
  }
312
+ export function filterIgnored(items, patterns) {
313
+ return items.filter(item => !isTableIgnored(item.name, patterns).ignored);
314
+ }
@@ -279,7 +279,7 @@ export function hasUncommittedChanges(projectRoot = process.cwd()) {
279
279
  return state.staged.length > 0 || state.unstaged.length > 0;
280
280
  }
281
281
  export async function ensureRemoteTable(connection) {
282
- const { Pool } = await import("../../addon/pg.js");
282
+ const { Pool } = await import("../../addon/pg/index.js");
283
283
  const pool = new Pool({
284
284
  host: connection.host,
285
285
  port: connection.port || 5432,
@@ -311,7 +311,7 @@ export async function ensureRemoteTable(connection) {
311
311
  }
312
312
  }
313
313
  export async function fetchRemoteCommits(connection, limit = 100) {
314
- const { Pool } = await import("../../addon/pg.js");
314
+ const { Pool } = await import("../../addon/pg/index.js");
315
315
  const pool = new Pool({
316
316
  host: connection.host,
317
317
  port: connection.port || 5432,
@@ -347,7 +347,7 @@ export async function getRemoteHead(connection) {
347
347
  return commits.length > 0 ? commits[0].hash : null;
348
348
  }
349
349
  export async function pushCommit(connection, commit) {
350
- const { Pool } = await import("../../addon/pg.js");
350
+ const { Pool } = await import("../../addon/pg/index.js");
351
351
  const pool = new Pool({
352
352
  host: connection.host,
353
353
  port: connection.port || 5432,
@@ -442,3 +442,41 @@ export function migrateSnapshot(snapshot) {
442
442
  foreignTables: snapshot.foreignTables || [],
443
443
  };
444
444
  }
445
+ export function loadTags(projectRoot = process.cwd()) {
446
+ const tagPath = path.join(projectRoot, '.relq', 'tags.json');
447
+ if (fs.existsSync(tagPath)) {
448
+ return JSON.parse(fs.readFileSync(tagPath, 'utf-8'));
449
+ }
450
+ return {};
451
+ }
452
+ export function saveTags(tags, projectRoot = process.cwd()) {
453
+ const tagPath = path.join(projectRoot, '.relq', 'tags.json');
454
+ fs.writeFileSync(tagPath, JSON.stringify(tags, null, 2));
455
+ }
456
+ export function resolveRef(ref, projectRoot = process.cwd()) {
457
+ const commit = loadCommit(ref, projectRoot);
458
+ if (commit)
459
+ return commit.hash;
460
+ const tags = loadTags(projectRoot);
461
+ if (tags[ref])
462
+ return tags[ref].hash;
463
+ const headMatch = ref.match(/^HEAD~(\d+)$/);
464
+ if (headMatch) {
465
+ const offset = parseInt(headMatch[1]);
466
+ let current = getHead(projectRoot);
467
+ for (let i = 0; i < offset && current; i++) {
468
+ const c = loadCommit(current, projectRoot);
469
+ if (!c || !c.parentHash)
470
+ return null;
471
+ current = c.parentHash;
472
+ }
473
+ return current;
474
+ }
475
+ return null;
476
+ }
477
+ export function loadParentCommit(hash, projectRoot = process.cwd()) {
478
+ const commit = loadCommit(hash, projectRoot);
479
+ if (!commit || !commit.parentHash)
480
+ return null;
481
+ return loadCommit(commit.parentHash, projectRoot);
482
+ }
@@ -1,6 +1,6 @@
1
1
  export async function introspectDatabase(connection, onProgress, options) {
2
2
  const { includeFunctions = false, includeTriggers = false } = options || {};
3
- const { Pool } = await import("../../addon/pg.js");
3
+ const { Pool } = await import("../../addon/pg/index.js");
4
4
  onProgress?.('connecting', connection.database);
5
5
  const pool = new Pool({
6
6
  host: connection.host,
@@ -396,7 +396,7 @@ function parseOptions(options) {
396
396
  return result;
397
397
  }
398
398
  export async function tableHasData(connection, tableName) {
399
- const { Pool } = await import("../../addon/pg.js");
399
+ const { Pool } = await import("../../addon/pg/index.js");
400
400
  const pool = new Pool({
401
401
  host: connection.host,
402
402
  port: connection.port || 5432,
@@ -206,7 +206,7 @@ function generateColumnSQL(col) {
206
206
  if (col.identityGeneration) {
207
207
  parts.push(`GENERATED ${col.identityGeneration} AS IDENTITY`);
208
208
  }
209
- if (!col.isNullable && !col.isPrimaryKey) {
209
+ if (!col.isNullable && !col.isPrimaryKey && !col.identityGeneration) {
210
210
  parts.push('NOT NULL');
211
211
  }
212
212
  if (col.defaultValue !== null && col.defaultValue !== undefined && !col.isGenerated) {
@@ -6,6 +6,9 @@ export function parseSqlFile(sqlContent) {
6
6
  const sequences = [];
7
7
  const collations = [];
8
8
  const foreignTables = [];
9
+ const views = [];
10
+ const materializedViews = [];
11
+ const foreignServers = [];
9
12
  const extensions = [];
10
13
  const partitions = [];
11
14
  const cleanedSql = removeComments(sqlContent);
@@ -18,7 +21,14 @@ export function parseSqlFile(sqlContent) {
18
21
  parseTables(cleanedSql, tables, partitions, enums, domains);
19
22
  parseIndexes(cleanedSql, tables);
20
23
  parseForeignTables(cleanedSql, foreignTables);
21
- return { tables, enums, domains, compositeTypes, sequences, collations, foreignTables, extensions, partitions };
24
+ parseViews(cleanedSql, views);
25
+ parseMaterializedViews(cleanedSql, materializedViews);
26
+ parseForeignServers(cleanedSql, foreignServers);
27
+ return {
28
+ tables, enums, domains, compositeTypes, sequences, collations,
29
+ foreignTables, views, materializedViews, foreignServers,
30
+ extensions, partitions
31
+ };
22
32
  }
23
33
  function removeComments(sql) {
24
34
  let result = sql.replace(/\/\*[\s\S]*?\*\//g, '');
@@ -110,11 +120,11 @@ function parseCompositeTypeBody(body) {
110
120
  const trimmed = line.trim();
111
121
  if (!trimmed)
112
122
  continue;
113
- const attrMatch = trimmed.match(/^(\w+)\s+(.+)$/);
123
+ const attrMatch = trimmed.match(/^(?:"([^"]+)"|(\w+))\s+(.+)$/);
114
124
  if (attrMatch) {
115
125
  attributes.push({
116
- name: attrMatch[1],
117
- type: attrMatch[2].trim().replace(/,\s*$/, ''),
126
+ name: attrMatch[1] || attrMatch[2],
127
+ type: attrMatch[3].trim().replace(/,\s*$/, ''),
118
128
  });
119
129
  }
120
130
  }
@@ -613,9 +623,9 @@ function extractMaxLength(type) {
613
623
  }
614
624
  function parseConstraint(def) {
615
625
  const upper = def.toUpperCase();
616
- const namedMatch = def.match(/CONSTRAINT\s+(\w+)\s+(.+)/i);
617
- const constraintDef = namedMatch ? namedMatch[2] : def;
618
- const constraintName = namedMatch ? namedMatch[1] : '';
626
+ const namedMatch = def.match(/CONSTRAINT\s+(?:"([^"]+)"|(\w+))\s+(.+)/is);
627
+ const constraintDef = namedMatch ? namedMatch[3] : def;
628
+ const constraintName = namedMatch ? (namedMatch[1] || namedMatch[2]) : '';
619
629
  const constraintUpper = constraintDef.toUpperCase();
620
630
  if (constraintUpper.startsWith('PRIMARY KEY')) {
621
631
  const colsMatch = constraintDef.match(/PRIMARY\s+KEY\s*\(\s*([^)]+)\s*\)/i);
@@ -991,4 +1001,81 @@ export function parseComments(sql) {
991
1001
  }
992
1002
  return comments;
993
1003
  }
1004
+ function parseViews(sql, views) {
1005
+ const viewRegex = /CREATE\s+(?:OR\s+REPLACE\s+)?VIEW\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:(?:"?(\w+)"?\.)?"?(\w+)"?)\s*(?:\(([^)]+)\))?\s+AS\s+([\s\S]+?)(?:;|\s+WITH\s+(?:CASCADED|LOCAL)\s+CHECK\s+OPTION\s*;)/gi;
1006
+ let match;
1007
+ while ((match = viewRegex.exec(sql)) !== null) {
1008
+ const schema = match[1] || 'public';
1009
+ const name = match[2];
1010
+ const columnsStr = match[3];
1011
+ const definition = match[4].trim();
1012
+ const columns = columnsStr
1013
+ ? columnsStr.split(',').map(c => c.trim().replace(/"/g, ''))
1014
+ : undefined;
1015
+ views.push({
1016
+ name,
1017
+ schema,
1018
+ definition,
1019
+ columns,
1020
+ });
1021
+ }
1022
+ const simpleViewRegex = /CREATE\s+(?:OR\s+REPLACE\s+)?VIEW\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:(?:"?(\w+)"?\.)?"?(\w+)"?)\s*AS\s+(SELECT[\s\S]+?);/gi;
1023
+ while ((match = simpleViewRegex.exec(sql)) !== null) {
1024
+ const schema = match[1] || 'public';
1025
+ const name = match[2];
1026
+ const definition = match[3].trim();
1027
+ if (views.some(v => v.name === name))
1028
+ continue;
1029
+ views.push({
1030
+ name,
1031
+ schema,
1032
+ definition,
1033
+ });
1034
+ }
1035
+ }
1036
+ function parseMaterializedViews(sql, materializedViews) {
1037
+ const mviewRegex = /CREATE\s+MATERIALIZED\s+VIEW\s+(?:IF\s+NOT\s+EXISTS\s+)?(?:(?:"?(\w+)"?\.)?"?(\w+)"?)\s*(?:\(([^)]+)\))?\s+AS\s+([\s\S]+?)(?:WITH\s+(NO\s+)?DATA\s*)?;/gi;
1038
+ let match;
1039
+ while ((match = mviewRegex.exec(sql)) !== null) {
1040
+ const schema = match[1] || 'public';
1041
+ const name = match[2];
1042
+ const columnsStr = match[3];
1043
+ const definition = match[4].trim();
1044
+ const withNoData = match[5] !== undefined;
1045
+ const columns = columnsStr
1046
+ ? columnsStr.split(',').map(c => c.trim().replace(/"/g, ''))
1047
+ : undefined;
1048
+ materializedViews.push({
1049
+ name,
1050
+ schema,
1051
+ definition,
1052
+ columns,
1053
+ withData: !withNoData,
1054
+ });
1055
+ }
1056
+ }
1057
+ function parseForeignServers(sql, foreignServers) {
1058
+ const serverRegex = /CREATE\s+SERVER\s+(?:IF\s+NOT\s+EXISTS\s+)?"?(\w+)"?\s+FOREIGN\s+DATA\s+WRAPPER\s+"?(\w+)"?\s*(?:OPTIONS\s*\(([^)]+)\))?;/gi;
1059
+ let match;
1060
+ while ((match = serverRegex.exec(sql)) !== null) {
1061
+ const name = match[1];
1062
+ const fdwName = match[2];
1063
+ const optionsStr = match[3];
1064
+ const options = {};
1065
+ if (optionsStr) {
1066
+ const optParts = optionsStr.split(',');
1067
+ for (const part of optParts) {
1068
+ const optMatch = part.trim().match(/(\w+)\s+'([^']+)'/);
1069
+ if (optMatch) {
1070
+ options[optMatch[1]] = optMatch[2];
1071
+ }
1072
+ }
1073
+ }
1074
+ foreignServers.push({
1075
+ name,
1076
+ fdwName,
1077
+ options: Object.keys(options).length > 0 ? options : undefined,
1078
+ });
1079
+ }
1080
+ }
994
1081
  export default parseSqlFile;
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  import { ArrayStringConditionBuilder } from "./array-string-condition-builder.js";
3
3
  import { ArrayNumericConditionBuilder } from "./array-numeric-condition-builder.js";
4
4
  import { ArrayUuidConditionBuilder, ArrayDateConditionBuilder, ArrayJsonbConditionBuilder } from "./array-specialized-condition-builder.js";
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  import { JsonbConditionCollector, buildJsonbConditionSQL } from "./jsonb-condition-builder.js";
3
3
  import { ArrayConditionCollector, buildArrayConditionSQL } from "./array-condition-builder.js";
4
4
  import { FulltextConditionCollector, buildFulltextConditionSQL } from "./fulltext-condition-builder.js";
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  export class FulltextConditionCollector {
3
3
  parent;
4
4
  constructor(parent) {
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  export class GeometricConditionCollector {
3
3
  parent;
4
4
  constructor(parent) {
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  export class JsonbConditionCollector {
3
3
  parent;
4
4
  constructor(parent) {
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  export class NetworkConditionCollector {
3
3
  parent;
4
4
  constructor(parent) {
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  export class RangeConditionCollector {
3
3
  parent;
4
4
  constructor(parent) {
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  import { RelqBuilderError } from "../errors/relq-errors.js";
3
3
  export class CopyToBuilder {
4
4
  tableName;
@@ -22,7 +22,7 @@ import { ExplainBuilder } from "../explain/explain-builder.js";
22
22
  import { ListenBuilder, UnlistenBuilder, NotifyBuilder } from "../pubsub/listen-notify-builder.js";
23
23
  import { VacuumBuilder, AnalyzeBuilder } from "../maintenance/vacuum-builder.js";
24
24
  import { CopyToBuilder, CopyFromBuilder } from "../copy/copy-builder.js";
25
- import format from "../../addons/pg-format.js";
25
+ import format from "../addon/pg-format/index.js";
26
26
  export class TypedSelectBuilder {
27
27
  builder;
28
28
  constructor(builder) {
@@ -14,7 +14,7 @@ import { validatePoolConfig, formatPoolConfig, getSmartPoolDefaults } from "../u
14
14
  import { RelqEnvironmentError, RelqConfigError, RelqQueryError, RelqConnectionError, parsePostgresError } from "../errors/relq-errors.js";
15
15
  import { randomLimit } from "../types/pagination-types.js";
16
16
  import { deserializeValue, serializeValue } from "../utils/type-coercion.js";
17
- import Cursor from "../../addons/pg-cursor.js";
17
+ import Cursor from "../addon/pg-cursor/index.js";
18
18
  const INTERNAL = Symbol('relq-internal');
19
19
  let PgPool = null;
20
20
  let PgClient = null;
@@ -40,7 +40,7 @@ function registerGlobalCleanupHandlers() {
40
40
  async function loadPg() {
41
41
  if (!PgPool || !PgClient) {
42
42
  try {
43
- const pg = await import("../addon/pg.js");
43
+ const pg = await import("../addon/pg/index.js");
44
44
  PgPool = pg.Pool;
45
45
  PgClient = pg.Client;
46
46
  return { Pool: pg.Pool, Client: pg.Client };
@@ -1,4 +1,4 @@
1
- import format from "../../addons/pg-format.js";
1
+ import format from "../addon/pg-format/index.js";
2
2
  import { ConditionCollector, buildConditionsSQL, buildConditionSQL } from "../condition/condition-collector.js";
3
3
  export class CountBuilder {
4
4
  tableName;