relq 1.0.2 → 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.
- package/dist/cjs/cli/commands/add.cjs +403 -27
- package/dist/cjs/cli/commands/branch.cjs +13 -23
- package/dist/cjs/cli/commands/checkout.cjs +16 -29
- package/dist/cjs/cli/commands/cherry-pick.cjs +3 -4
- package/dist/cjs/cli/commands/commit.cjs +21 -29
- package/dist/cjs/cli/commands/diff.cjs +28 -32
- package/dist/cjs/cli/commands/export.cjs +7 -7
- package/dist/cjs/cli/commands/fetch.cjs +15 -21
- package/dist/cjs/cli/commands/generate.cjs +28 -54
- package/dist/cjs/cli/commands/history.cjs +19 -40
- package/dist/cjs/cli/commands/import.cjs +34 -41
- package/dist/cjs/cli/commands/init.cjs +69 -59
- package/dist/cjs/cli/commands/introspect.cjs +4 -8
- package/dist/cjs/cli/commands/log.cjs +26 -32
- package/dist/cjs/cli/commands/merge.cjs +24 -41
- package/dist/cjs/cli/commands/migrate.cjs +12 -25
- package/dist/cjs/cli/commands/pull.cjs +216 -106
- package/dist/cjs/cli/commands/push.cjs +35 -75
- package/dist/cjs/cli/commands/remote.cjs +2 -1
- package/dist/cjs/cli/commands/reset.cjs +22 -43
- package/dist/cjs/cli/commands/resolve.cjs +12 -14
- package/dist/cjs/cli/commands/rollback.cjs +16 -38
- package/dist/cjs/cli/commands/stash.cjs +5 -7
- package/dist/cjs/cli/commands/status.cjs +5 -10
- package/dist/cjs/cli/commands/sync.cjs +30 -50
- package/dist/cjs/cli/commands/tag.cjs +3 -4
- package/dist/cjs/cli/index.cjs +72 -9
- package/dist/cjs/cli/utils/change-tracker.cjs +107 -3
- package/dist/cjs/cli/utils/cli-utils.cjs +217 -0
- package/dist/cjs/cli/utils/config-loader.cjs +34 -8
- package/dist/cjs/cli/utils/fast-introspect.cjs +109 -3
- package/dist/cjs/cli/utils/git-utils.cjs +42 -161
- package/dist/cjs/cli/utils/pool-manager.cjs +156 -0
- package/dist/cjs/cli/utils/project-root.cjs +56 -5
- package/dist/cjs/cli/utils/relqignore.cjs +1 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +47 -0
- package/dist/cjs/cli/utils/schema-comparator.cjs +301 -11
- package/dist/cjs/cli/utils/schema-diff.cjs +202 -1
- package/dist/cjs/cli/utils/schema-hash.cjs +2 -1
- package/dist/cjs/cli/utils/schema-introspect.cjs +7 -3
- package/dist/cjs/cli/utils/snapshot-manager.cjs +1 -0
- package/dist/cjs/cli/utils/spinner.cjs +14 -106
- package/dist/cjs/cli/utils/sql-generator.cjs +1 -1
- package/dist/cjs/cli/utils/type-generator.cjs +28 -16
- package/dist/config.d.ts +16 -25
- package/dist/esm/cli/commands/add.js +372 -29
- package/dist/esm/cli/commands/branch.js +14 -24
- package/dist/esm/cli/commands/checkout.js +16 -29
- package/dist/esm/cli/commands/cherry-pick.js +3 -4
- package/dist/esm/cli/commands/commit.js +22 -30
- package/dist/esm/cli/commands/diff.js +6 -10
- package/dist/esm/cli/commands/export.js +8 -8
- package/dist/esm/cli/commands/fetch.js +14 -20
- package/dist/esm/cli/commands/generate.js +28 -54
- package/dist/esm/cli/commands/history.js +11 -32
- package/dist/esm/cli/commands/import.js +35 -42
- package/dist/esm/cli/commands/init.js +65 -55
- package/dist/esm/cli/commands/introspect.js +4 -8
- package/dist/esm/cli/commands/log.js +6 -12
- package/dist/esm/cli/commands/merge.js +20 -37
- package/dist/esm/cli/commands/migrate.js +12 -25
- package/dist/esm/cli/commands/pull.js +204 -94
- package/dist/esm/cli/commands/push.js +21 -61
- package/dist/esm/cli/commands/remote.js +2 -1
- package/dist/esm/cli/commands/reset.js +16 -37
- package/dist/esm/cli/commands/resolve.js +13 -15
- package/dist/esm/cli/commands/rollback.js +16 -38
- package/dist/esm/cli/commands/stash.js +6 -8
- package/dist/esm/cli/commands/status.js +6 -11
- package/dist/esm/cli/commands/sync.js +30 -50
- package/dist/esm/cli/commands/tag.js +3 -4
- package/dist/esm/cli/index.js +72 -9
- package/dist/esm/cli/utils/change-tracker.js +107 -3
- package/dist/esm/cli/utils/cli-utils.js +169 -0
- package/dist/esm/cli/utils/config-loader.js +34 -8
- package/dist/esm/cli/utils/fast-introspect.js +109 -3
- package/dist/esm/cli/utils/git-utils.js +2 -124
- package/dist/esm/cli/utils/pool-manager.js +114 -0
- package/dist/esm/cli/utils/project-root.js +55 -5
- package/dist/esm/cli/utils/relqignore.js +1 -0
- package/dist/esm/cli/utils/repo-manager.js +42 -0
- package/dist/esm/cli/utils/schema-comparator.js +301 -11
- package/dist/esm/cli/utils/schema-diff.js +202 -1
- package/dist/esm/cli/utils/schema-hash.js +2 -1
- package/dist/esm/cli/utils/schema-introspect.js +7 -3
- package/dist/esm/cli/utils/snapshot-manager.js +1 -0
- package/dist/esm/cli/utils/spinner.js +1 -101
- package/dist/esm/cli/utils/sql-generator.js +1 -1
- package/dist/esm/cli/utils/type-generator.js +28 -16
- package/dist/index.d.ts +25 -8
- package/dist/schema-builder.d.ts +16 -6
- package/package.json +1 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.colors = void 0;
|
|
37
|
+
exports.createSpinner = createSpinner;
|
|
38
|
+
exports.fatal = fatal;
|
|
39
|
+
exports.error = error;
|
|
40
|
+
exports.warning = warning;
|
|
41
|
+
exports.hint = hint;
|
|
42
|
+
exports.success = success;
|
|
43
|
+
exports.confirm = confirm;
|
|
44
|
+
exports.select = select;
|
|
45
|
+
exports.formatBytes = formatBytes;
|
|
46
|
+
exports.formatDuration = formatDuration;
|
|
47
|
+
exports.progressBar = progressBar;
|
|
48
|
+
exports.requireInit = requireInit;
|
|
49
|
+
const readline = __importStar(require("readline"));
|
|
50
|
+
const isColorSupported = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
51
|
+
exports.colors = {
|
|
52
|
+
reset: '\x1b[0m',
|
|
53
|
+
red: (s) => isColorSupported ? `\x1b[31m${s}\x1b[0m` : s,
|
|
54
|
+
green: (s) => isColorSupported ? `\x1b[32m${s}\x1b[0m` : s,
|
|
55
|
+
yellow: (s) => isColorSupported ? `\x1b[33m${s}\x1b[0m` : s,
|
|
56
|
+
blue: (s) => isColorSupported ? `\x1b[34m${s}\x1b[0m` : s,
|
|
57
|
+
magenta: (s) => isColorSupported ? `\x1b[35m${s}\x1b[0m` : s,
|
|
58
|
+
cyan: (s) => isColorSupported ? `\x1b[36m${s}\x1b[0m` : s,
|
|
59
|
+
white: (s) => isColorSupported ? `\x1b[37m${s}\x1b[0m` : s,
|
|
60
|
+
gray: (s) => isColorSupported ? `\x1b[90m${s}\x1b[0m` : s,
|
|
61
|
+
bold: (s) => isColorSupported ? `\x1b[1m${s}\x1b[0m` : s,
|
|
62
|
+
dim: (s) => isColorSupported ? `\x1b[2m${s}\x1b[0m` : s,
|
|
63
|
+
muted: (s) => isColorSupported ? `\x1b[90m${s}\x1b[0m` : s,
|
|
64
|
+
success: (s) => isColorSupported ? `\x1b[32m${s}\x1b[0m` : s,
|
|
65
|
+
error: (s) => isColorSupported ? `\x1b[31m${s}\x1b[0m` : s,
|
|
66
|
+
warning: (s) => isColorSupported ? `\x1b[33m${s}\x1b[0m` : s,
|
|
67
|
+
info: (s) => isColorSupported ? `\x1b[34m${s}\x1b[0m` : s,
|
|
68
|
+
};
|
|
69
|
+
function createSpinner() {
|
|
70
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
71
|
+
let frameIndex = 0;
|
|
72
|
+
let interval = null;
|
|
73
|
+
let currentMessage = '';
|
|
74
|
+
let isSpinning = false;
|
|
75
|
+
const isTTY = process.stdout.isTTY;
|
|
76
|
+
const clearLine = () => {
|
|
77
|
+
if (isTTY)
|
|
78
|
+
process.stdout.write('\r\x1b[K');
|
|
79
|
+
};
|
|
80
|
+
const render = () => {
|
|
81
|
+
if (!isSpinning)
|
|
82
|
+
return;
|
|
83
|
+
clearLine();
|
|
84
|
+
process.stdout.write(`${exports.colors.cyan(frames[frameIndex])} ${currentMessage}`);
|
|
85
|
+
frameIndex = (frameIndex + 1) % frames.length;
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
start(message) {
|
|
89
|
+
if (isSpinning)
|
|
90
|
+
this.stop();
|
|
91
|
+
currentMessage = message;
|
|
92
|
+
isSpinning = true;
|
|
93
|
+
frameIndex = 0;
|
|
94
|
+
if (isTTY) {
|
|
95
|
+
interval = setInterval(render, 80);
|
|
96
|
+
render();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(`${message}...`);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
update(message) {
|
|
103
|
+
currentMessage = message;
|
|
104
|
+
},
|
|
105
|
+
succeed(message) {
|
|
106
|
+
this.stop();
|
|
107
|
+
console.log(message || currentMessage);
|
|
108
|
+
},
|
|
109
|
+
fail(message) {
|
|
110
|
+
this.stop();
|
|
111
|
+
},
|
|
112
|
+
info(message) {
|
|
113
|
+
this.stop();
|
|
114
|
+
console.log(message || currentMessage);
|
|
115
|
+
},
|
|
116
|
+
warn(message) {
|
|
117
|
+
this.stop();
|
|
118
|
+
warning(message || currentMessage);
|
|
119
|
+
},
|
|
120
|
+
stop() {
|
|
121
|
+
if (interval) {
|
|
122
|
+
clearInterval(interval);
|
|
123
|
+
interval = null;
|
|
124
|
+
}
|
|
125
|
+
if (isSpinning && isTTY) {
|
|
126
|
+
clearLine();
|
|
127
|
+
}
|
|
128
|
+
isSpinning = false;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function fatal(message, hintMessage) {
|
|
133
|
+
console.error(`${exports.colors.red('fatal:')} ${message}`);
|
|
134
|
+
if (hintMessage) {
|
|
135
|
+
hint(hintMessage);
|
|
136
|
+
}
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
function error(message, hintMessage) {
|
|
140
|
+
console.error(`${exports.colors.red('error:')} ${message}`);
|
|
141
|
+
if (hintMessage) {
|
|
142
|
+
hint(hintMessage);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function warning(message) {
|
|
146
|
+
console.error(`${exports.colors.yellow('warning:')} ${message}`);
|
|
147
|
+
}
|
|
148
|
+
function hint(message) {
|
|
149
|
+
console.error(`${exports.colors.yellow('hint:')} ${message}`);
|
|
150
|
+
}
|
|
151
|
+
function success(message) {
|
|
152
|
+
console.log(exports.colors.green(message));
|
|
153
|
+
}
|
|
154
|
+
function confirm(question, defaultYes = true) {
|
|
155
|
+
const rl = readline.createInterface({
|
|
156
|
+
input: process.stdin,
|
|
157
|
+
output: process.stdout,
|
|
158
|
+
});
|
|
159
|
+
const suffix = defaultYes ? '[Y/n]' : '[y/N]';
|
|
160
|
+
return new Promise((resolve) => {
|
|
161
|
+
rl.question(`${question} ${suffix} `, (answer) => {
|
|
162
|
+
rl.close();
|
|
163
|
+
const a = answer.trim().toLowerCase();
|
|
164
|
+
if (!a)
|
|
165
|
+
resolve(defaultYes);
|
|
166
|
+
else
|
|
167
|
+
resolve(a === 'y' || a === 'yes');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function select(question, options) {
|
|
172
|
+
const rl = readline.createInterface({
|
|
173
|
+
input: process.stdin,
|
|
174
|
+
output: process.stdout,
|
|
175
|
+
});
|
|
176
|
+
console.log(question);
|
|
177
|
+
options.forEach((opt, i) => {
|
|
178
|
+
console.log(` ${i + 1}) ${opt}`);
|
|
179
|
+
});
|
|
180
|
+
return new Promise((resolve) => {
|
|
181
|
+
rl.question(`Select [1-${options.length}]: `, (answer) => {
|
|
182
|
+
rl.close();
|
|
183
|
+
const num = parseInt(answer.trim(), 10);
|
|
184
|
+
if (num >= 1 && num <= options.length) {
|
|
185
|
+
resolve(num - 1);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
resolve(0);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function formatBytes(bytes) {
|
|
194
|
+
if (bytes < 1024)
|
|
195
|
+
return `${bytes} B`;
|
|
196
|
+
if (bytes < 1024 * 1024)
|
|
197
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
198
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
199
|
+
}
|
|
200
|
+
function formatDuration(ms) {
|
|
201
|
+
if (ms < 1000)
|
|
202
|
+
return `${ms}ms`;
|
|
203
|
+
if (ms < 60000)
|
|
204
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
205
|
+
return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
|
|
206
|
+
}
|
|
207
|
+
function progressBar(current, total, width = 30) {
|
|
208
|
+
const percentage = Math.min(100, Math.round((current / total) * 100));
|
|
209
|
+
const filled = Math.round((percentage / 100) * width);
|
|
210
|
+
const empty = width - filled;
|
|
211
|
+
return `${'#'.repeat(filled)}${'.'.repeat(empty)} ${percentage}%`;
|
|
212
|
+
}
|
|
213
|
+
function requireInit(isInitialized, projectRoot) {
|
|
214
|
+
if (!isInitialized) {
|
|
215
|
+
fatal('not a relq repository (or any of the parent directories): .relq', "run 'relq init' to initialize a repository");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -105,7 +105,7 @@ function validateConfig(config) {
|
|
|
105
105
|
if (!config.connection?.host && !config.connection?.url) {
|
|
106
106
|
errors.push('No database connection configured. Set connection in relq.config.ts or use DATABASE_* env vars.');
|
|
107
107
|
}
|
|
108
|
-
const hasSchemaPath = typeof config.schema === 'string';
|
|
108
|
+
const hasSchemaPath = typeof config.schema === 'string' && config.schema.length > 0;
|
|
109
109
|
const hasSchemaDir = typeof config.schema === 'object' && config.schema?.directory;
|
|
110
110
|
const hasTypeGenOutput = config.typeGeneration?.output;
|
|
111
111
|
const hasGenerateOutDir = config.generate?.outDir;
|
|
@@ -114,14 +114,40 @@ function validateConfig(config) {
|
|
|
114
114
|
}
|
|
115
115
|
return errors;
|
|
116
116
|
}
|
|
117
|
-
function requireValidConfig(config) {
|
|
117
|
+
async function requireValidConfig(config, options) {
|
|
118
118
|
const errors = validateConfig(config);
|
|
119
|
-
if (errors.length
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
if (errors.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
const colors = {
|
|
122
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
123
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
124
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
125
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
126
|
+
};
|
|
127
|
+
const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
|
|
128
|
+
if (options?.autoComplete !== false && isInteractive) {
|
|
129
|
+
try {
|
|
130
|
+
const { initCommand } = await Promise.resolve().then(() => __importStar(require("../commands/init.cjs")));
|
|
131
|
+
const { findProjectRoot } = await Promise.resolve().then(() => __importStar(require("./project-root.cjs")));
|
|
132
|
+
const projectRoot = findProjectRoot() || process.cwd();
|
|
133
|
+
const flags = {};
|
|
134
|
+
if (options?.calledFrom) {
|
|
135
|
+
flags['called-from'] = options.calledFrom;
|
|
136
|
+
}
|
|
137
|
+
await initCommand({ args: [], flags, config, projectRoot });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
process.exit(1);
|
|
123
142
|
}
|
|
124
|
-
console.error('\nRun "relq init" to create a configuration file.');
|
|
125
|
-
process.exit(1);
|
|
126
143
|
}
|
|
144
|
+
console.error('');
|
|
145
|
+
console.error(colors.red('error:') + ' Configuration errors:');
|
|
146
|
+
for (const error of errors) {
|
|
147
|
+
console.error(` ${colors.yellow('•')} ${error}`);
|
|
148
|
+
}
|
|
149
|
+
console.error('');
|
|
150
|
+
console.error(colors.yellow('hint:') + ` Run ${colors.cyan('relq init')} to create a configuration file or check your config settings.`);
|
|
151
|
+
console.error('');
|
|
152
|
+
process.exit(1);
|
|
127
153
|
}
|
|
@@ -34,6 +34,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.fastIntrospectDatabase = fastIntrospectDatabase;
|
|
37
|
+
function parseOptionsArray(options) {
|
|
38
|
+
if (!options)
|
|
39
|
+
return {};
|
|
40
|
+
const result = {};
|
|
41
|
+
for (const opt of options) {
|
|
42
|
+
const eqIdx = opt.indexOf('=');
|
|
43
|
+
if (eqIdx > 0) {
|
|
44
|
+
result[opt.substring(0, eqIdx)] = opt.substring(eqIdx + 1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
37
49
|
async function fastIntrospectDatabase(connection, onProgress, options) {
|
|
38
50
|
const { includeFunctions = false, includeTriggers = false } = options || {};
|
|
39
51
|
const { Pool } = await Promise.resolve().then(() => __importStar(require("../../addon/pg/index.cjs")));
|
|
@@ -254,7 +266,7 @@ async function fastIntrospectDatabase(connection, onProgress, options) {
|
|
|
254
266
|
const tables = [];
|
|
255
267
|
for (const row of tablesResult.rows) {
|
|
256
268
|
const tableName = row.table_name;
|
|
257
|
-
if (tableName.startsWith('_relq'))
|
|
269
|
+
if (tableName.startsWith('_relq') || tableName.startsWith('_kuery'))
|
|
258
270
|
continue;
|
|
259
271
|
tables.push({
|
|
260
272
|
name: tableName,
|
|
@@ -376,6 +388,99 @@ async function fastIntrospectDatabase(connection, onProgress, options) {
|
|
|
376
388
|
isEnabled: t.is_enabled,
|
|
377
389
|
}));
|
|
378
390
|
}
|
|
391
|
+
onProgress?.('fetching_collations');
|
|
392
|
+
const collationsResult = await pool.query(`
|
|
393
|
+
SELECT
|
|
394
|
+
c.collname as name,
|
|
395
|
+
n.nspname as schema,
|
|
396
|
+
c.collprovider as provider,
|
|
397
|
+
c.collcollate as lc_collate,
|
|
398
|
+
c.collctype as lc_ctype,
|
|
399
|
+
c.collisdeterministic as deterministic
|
|
400
|
+
FROM pg_collation c
|
|
401
|
+
JOIN pg_namespace n ON c.collnamespace = n.oid
|
|
402
|
+
WHERE n.nspname = 'public'
|
|
403
|
+
ORDER BY c.collname;
|
|
404
|
+
`);
|
|
405
|
+
const collations = collationsResult.rows.map(c => ({
|
|
406
|
+
name: c.name,
|
|
407
|
+
schema: c.schema,
|
|
408
|
+
provider: c.provider === 'i' ? 'icu' : c.provider === 'c' ? 'libc' : 'default',
|
|
409
|
+
lcCollate: c.lc_collate,
|
|
410
|
+
lcCtype: c.lc_ctype,
|
|
411
|
+
deterministic: c.deterministic,
|
|
412
|
+
}));
|
|
413
|
+
onProgress?.('fetching_foreign_servers');
|
|
414
|
+
const foreignServersResult = await pool.query(`
|
|
415
|
+
SELECT
|
|
416
|
+
s.srvname as name,
|
|
417
|
+
f.fdwname as fdw,
|
|
418
|
+
s.srvoptions as options
|
|
419
|
+
FROM pg_foreign_server s
|
|
420
|
+
JOIN pg_foreign_data_wrapper f ON s.srvfdw = f.oid
|
|
421
|
+
ORDER BY s.srvname;
|
|
422
|
+
`);
|
|
423
|
+
const foreignServers = foreignServersResult.rows.map(s => ({
|
|
424
|
+
name: s.name,
|
|
425
|
+
foreignDataWrapper: s.fdw,
|
|
426
|
+
options: parseOptionsArray(s.options),
|
|
427
|
+
}));
|
|
428
|
+
onProgress?.('fetching_foreign_tables');
|
|
429
|
+
const foreignTablesResult = await pool.query(`
|
|
430
|
+
SELECT
|
|
431
|
+
c.relname as name,
|
|
432
|
+
n.nspname as schema,
|
|
433
|
+
s.srvname as server_name,
|
|
434
|
+
ft.ftoptions as options
|
|
435
|
+
FROM pg_foreign_table ft
|
|
436
|
+
JOIN pg_class c ON ft.ftrelid = c.oid
|
|
437
|
+
JOIN pg_namespace n ON c.relnamespace = n.oid
|
|
438
|
+
JOIN pg_foreign_server s ON ft.ftserver = s.oid
|
|
439
|
+
WHERE n.nspname = 'public'
|
|
440
|
+
ORDER BY c.relname;
|
|
441
|
+
`);
|
|
442
|
+
const foreignTableNames = foreignTablesResult.rows.map(t => t.name);
|
|
443
|
+
let foreignTableColumns = new Map();
|
|
444
|
+
if (foreignTableNames.length > 0) {
|
|
445
|
+
const ftColsResult = await pool.query(`
|
|
446
|
+
SELECT
|
|
447
|
+
c.relname as table_name,
|
|
448
|
+
a.attname as column_name,
|
|
449
|
+
pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type
|
|
450
|
+
FROM pg_attribute a
|
|
451
|
+
JOIN pg_class c ON a.attrelid = c.oid
|
|
452
|
+
JOIN pg_namespace n ON c.relnamespace = n.oid
|
|
453
|
+
WHERE n.nspname = 'public'
|
|
454
|
+
AND c.relname = ANY($1)
|
|
455
|
+
AND a.attnum > 0
|
|
456
|
+
AND NOT a.attisdropped
|
|
457
|
+
ORDER BY c.relname, a.attnum;
|
|
458
|
+
`, [foreignTableNames]);
|
|
459
|
+
for (const row of ftColsResult.rows) {
|
|
460
|
+
const cols = foreignTableColumns.get(row.table_name) || [];
|
|
461
|
+
cols.push({ name: row.column_name, type: row.data_type });
|
|
462
|
+
foreignTableColumns.set(row.table_name, cols);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const foreignTables = foreignTablesResult.rows.map(t => ({
|
|
466
|
+
name: t.name,
|
|
467
|
+
schema: t.schema,
|
|
468
|
+
serverName: t.server_name,
|
|
469
|
+
columns: (foreignTableColumns.get(t.name) || []).map((c, i) => ({
|
|
470
|
+
name: c.name,
|
|
471
|
+
dataType: c.type,
|
|
472
|
+
isNullable: true,
|
|
473
|
+
defaultValue: null,
|
|
474
|
+
isPrimaryKey: false,
|
|
475
|
+
isUnique: false,
|
|
476
|
+
ordinalPosition: i + 1,
|
|
477
|
+
maxLength: null,
|
|
478
|
+
precision: null,
|
|
479
|
+
scale: null,
|
|
480
|
+
references: null,
|
|
481
|
+
})),
|
|
482
|
+
options: parseOptionsArray(t.options),
|
|
483
|
+
}));
|
|
379
484
|
onProgress?.('complete');
|
|
380
485
|
return {
|
|
381
486
|
tables,
|
|
@@ -383,12 +488,13 @@ async function fastIntrospectDatabase(connection, onProgress, options) {
|
|
|
383
488
|
domains: [],
|
|
384
489
|
compositeTypes: [],
|
|
385
490
|
sequences: [],
|
|
491
|
+
collations,
|
|
386
492
|
functions,
|
|
387
493
|
triggers,
|
|
388
494
|
policies: [],
|
|
389
495
|
partitions,
|
|
390
|
-
foreignServers
|
|
391
|
-
foreignTables
|
|
496
|
+
foreignServers,
|
|
497
|
+
foreignTables,
|
|
392
498
|
extensions,
|
|
393
499
|
};
|
|
394
500
|
}
|