@appixar/xpg 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/core.test.d.ts +2 -0
- package/dist/__tests__/core.test.d.ts.map +1 -0
- package/dist/__tests__/core.test.js +228 -0
- package/dist/__tests__/core.test.js.map +1 -0
- package/dist/builder.d.ts +23 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +262 -0
- package/dist/builder.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +119 -0
- package/dist/cli.js.map +1 -0
- package/dist/configLoader.d.ts +22 -0
- package/dist/configLoader.d.ts.map +1 -0
- package/dist/configLoader.js +97 -0
- package/dist/configLoader.js.map +1 -0
- package/dist/defaultNormalizer.d.ts +29 -0
- package/dist/defaultNormalizer.d.ts.map +1 -0
- package/dist/defaultNormalizer.js +124 -0
- package/dist/defaultNormalizer.js.map +1 -0
- package/dist/diffEngine.d.ts +21 -0
- package/dist/diffEngine.d.ts.map +1 -0
- package/dist/diffEngine.js +233 -0
- package/dist/diffEngine.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +63 -0
- package/dist/logger.js.map +1 -0
- package/dist/pgService.d.ts +42 -0
- package/dist/pgService.d.ts.map +1 -0
- package/dist/pgService.js +219 -0
- package/dist/pgService.js.map +1 -0
- package/dist/schemaParser.d.ts +10 -0
- package/dist/schemaParser.d.ts.map +1 -0
- package/dist/schemaParser.js +118 -0
- package/dist/schemaParser.js.map +1 -0
- package/dist/sqlGenerator.d.ts +18 -0
- package/dist/sqlGenerator.d.ts.map +1 -0
- package/dist/sqlGenerator.js +104 -0
- package/dist/sqlGenerator.js.map +1 -0
- package/dist/typeDictionary.d.ts +2 -0
- package/dist/typeDictionary.d.ts.map +1 -0
- package/dist/typeDictionary.js +27 -0
- package/dist/typeDictionary.js.map +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
- package/xpg.config.yml-sample +42 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// x-postgres — Diff engine
|
|
3
|
+
// ─────────────────────────────────────────────
|
|
4
|
+
// Compares live DB state vs YAML schema and generates
|
|
5
|
+
// minimal ALTER statements. Port of PHP updateTable().
|
|
6
|
+
import { POSTGRES_TYPE_DICTIONARY } from './typeDictionary.js';
|
|
7
|
+
import { buildDefaultClause, normalizeDbDefaultForCompare } from './defaultNormalizer.js';
|
|
8
|
+
import * as log from './logger.js';
|
|
9
|
+
/**
|
|
10
|
+
* Generate ALTER statements to bring a live table in sync with YAML schema.
|
|
11
|
+
*/
|
|
12
|
+
export function generateUpdateTable(ctx) {
|
|
13
|
+
const { table, schema, currentColumns, existingIndexes, existingUniques, mute } = ctx;
|
|
14
|
+
const queries = [];
|
|
15
|
+
if (!mute)
|
|
16
|
+
log.header(`∴ ${table}`, 'blue');
|
|
17
|
+
const { fields, individualIndexes, compositeIndexes, compositeUniqueIndexes } = schema;
|
|
18
|
+
// ─── Existing index/constraint names ───
|
|
19
|
+
const existingIndexNames = existingIndexes.map(i => i.indexname);
|
|
20
|
+
const existingUniqueNames = existingUniques.map(u => u.conname);
|
|
21
|
+
// ─── Expected index/constraint names ───
|
|
22
|
+
const expectedIndexes = [];
|
|
23
|
+
const expectedUniqueNames = [];
|
|
24
|
+
for (const field of individualIndexes) {
|
|
25
|
+
expectedIndexes.push(`${table}_${field}_idx`);
|
|
26
|
+
}
|
|
27
|
+
for (const indexName of Object.keys(compositeIndexes)) {
|
|
28
|
+
expectedIndexes.push(`${table}_${indexName}_idx`);
|
|
29
|
+
}
|
|
30
|
+
for (const indexName of Object.keys(compositeUniqueIndexes)) {
|
|
31
|
+
expectedIndexes.push(`${table}_${indexName}_unique_idx`);
|
|
32
|
+
}
|
|
33
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
34
|
+
if (v.key === 'UNI') {
|
|
35
|
+
expectedUniqueNames.push(`${table}_${k}_unique`);
|
|
36
|
+
expectedIndexes.push(`${table}_${k}_unique`);
|
|
37
|
+
}
|
|
38
|
+
if (v.key === 'PRI') {
|
|
39
|
+
expectedIndexes.push(`${table}_pkey`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// ─── 1. DROP columns no longer in YAML ───
|
|
43
|
+
for (const column of Object.keys(currentColumns)) {
|
|
44
|
+
if (!fields[column]) {
|
|
45
|
+
const sql = `ALTER TABLE "${table}" DROP COLUMN "${column}";`;
|
|
46
|
+
queries.push({ sql, mini: `DROP COLUMN "${table}"."${column}" ...`, color: 'yellow' });
|
|
47
|
+
if (!mute)
|
|
48
|
+
log.say(`→ ${sql}`, 'yellow');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ─── 2. DROP orphaned UNIQUE constraints ───
|
|
52
|
+
for (const uniqueName of existingUniqueNames) {
|
|
53
|
+
if (!expectedUniqueNames.includes(uniqueName)) {
|
|
54
|
+
const sql = `ALTER TABLE "${table}" DROP CONSTRAINT "${uniqueName}";`;
|
|
55
|
+
queries.push({ sql, mini: `DROP CONSTRAINT "${uniqueName}" ...`, color: 'yellow' });
|
|
56
|
+
if (!mute)
|
|
57
|
+
log.say(`→ ${sql}`, 'yellow');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// ─── 3. DROP orphaned indexes ───
|
|
61
|
+
for (const indexName of existingIndexNames) {
|
|
62
|
+
if (!expectedIndexes.includes(indexName)) {
|
|
63
|
+
const sql = `DROP INDEX IF EXISTS "${indexName}";`;
|
|
64
|
+
queries.push({ sql, mini: `DROP INDEX "${indexName}" ...`, color: 'yellow' });
|
|
65
|
+
if (!mute)
|
|
66
|
+
log.say(`→ ${sql}`, 'yellow');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ─── 4. ADD new columns ───
|
|
70
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
71
|
+
if (!currentColumns[k]) {
|
|
72
|
+
const typeUpper = v.type;
|
|
73
|
+
let defaultClause = '';
|
|
74
|
+
if (!typeUpper.includes('SERIAL')) {
|
|
75
|
+
defaultClause = buildDefaultClause(v.defaultValue, typeUpper);
|
|
76
|
+
}
|
|
77
|
+
const sql = `ALTER TABLE "${table}" ADD COLUMN "${k}" ${typeUpper} ${v.nullable} ${defaultClause} ${v.extra};`.replace(/\s+/g, ' ').trim();
|
|
78
|
+
queries.push({ sql, mini: `ADD COLUMN "${table}"."${k}" ...`, color: 'cyan' });
|
|
79
|
+
if (!mute)
|
|
80
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ─── 5. ALTER column TYPE if changed ───
|
|
84
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
85
|
+
if (!currentColumns[k])
|
|
86
|
+
continue;
|
|
87
|
+
const typeMatch = v.type.match(/^(\w+)(?:\((\d+(?:,\d+)?)\))?$/);
|
|
88
|
+
const configBaseType = typeMatch ? typeMatch[1] : v.type.split('(')[0];
|
|
89
|
+
const configLength = typeMatch && typeMatch[2] ? typeMatch[2] : null;
|
|
90
|
+
const mappedConfigType = POSTGRES_TYPE_DICTIONARY[configBaseType] ?? configBaseType.toLowerCase();
|
|
91
|
+
const dbType = currentColumns[k].data_type.toLowerCase();
|
|
92
|
+
const dbLength = currentColumns[k].character_maximum_length;
|
|
93
|
+
if (mappedConfigType !== dbType) {
|
|
94
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" TYPE ${v.type};`;
|
|
95
|
+
queries.push({ sql, mini: `ALTER TYPE "${table}"."${k}" → ${v.type} ...`, color: 'cyan' });
|
|
96
|
+
if (!mute)
|
|
97
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
98
|
+
}
|
|
99
|
+
else if (configLength !== null) {
|
|
100
|
+
// For numeric/decimal, compare precision+scale from numeric_precision/numeric_scale
|
|
101
|
+
const isNumericType = ['numeric', 'decimal'].includes(dbType) || ['NUMERIC', 'DECIMAL'].includes(configBaseType);
|
|
102
|
+
if (isNumericType) {
|
|
103
|
+
const dbPrecision = currentColumns[k].numeric_precision;
|
|
104
|
+
const dbScale = currentColumns[k].numeric_scale;
|
|
105
|
+
const [cfgPrecision, cfgScale] = configLength.split(',');
|
|
106
|
+
const precisionMismatch = dbPrecision !== null && String(dbPrecision) !== cfgPrecision;
|
|
107
|
+
const scaleMismatch = cfgScale && dbScale !== null && String(dbScale) !== cfgScale;
|
|
108
|
+
if (precisionMismatch || scaleMismatch) {
|
|
109
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" TYPE ${v.type};`;
|
|
110
|
+
queries.push({ sql, mini: `ALTER TYPE "${table}"."${k}" → ${v.type} ...`, color: 'cyan' });
|
|
111
|
+
if (!mute)
|
|
112
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else if (dbLength !== null && String(dbLength) !== configLength.split(',')[0]) {
|
|
116
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" TYPE ${v.type};`;
|
|
117
|
+
queries.push({ sql, mini: `ALTER TYPE "${table}"."${k}" → ${v.type} ...`, color: 'cyan' });
|
|
118
|
+
if (!mute)
|
|
119
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// ─── 6. SET/DROP DEFAULT ───
|
|
124
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
125
|
+
if (!currentColumns[k])
|
|
126
|
+
continue;
|
|
127
|
+
const typeUpper = v.type;
|
|
128
|
+
const dbDefaultRaw = currentColumns[k].column_default ?? '';
|
|
129
|
+
// Skip SERIAL defaults (auto nextval)
|
|
130
|
+
if (typeUpper.includes('SERIAL'))
|
|
131
|
+
continue;
|
|
132
|
+
// Skip PRI fields that have nextval (legacy serial)
|
|
133
|
+
if (v.key === 'PRI' && dbDefaultRaw.toLowerCase().includes('nextval('))
|
|
134
|
+
continue;
|
|
135
|
+
const configDefaultClause = buildDefaultClause(v.defaultValue, typeUpper);
|
|
136
|
+
let configDefaultSql = '';
|
|
137
|
+
if (configDefaultClause) {
|
|
138
|
+
configDefaultSql = configDefaultClause.substring('DEFAULT '.length).trim();
|
|
139
|
+
}
|
|
140
|
+
const dbDefaultNorm = normalizeDbDefaultForCompare(dbDefaultRaw);
|
|
141
|
+
const cfgDefaultNorm = normalizeDbDefaultForCompare(configDefaultSql);
|
|
142
|
+
// YAML has no default but DB does → DROP
|
|
143
|
+
if (cfgDefaultNorm === '' && dbDefaultNorm !== '') {
|
|
144
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" DROP DEFAULT;`;
|
|
145
|
+
queries.push({ sql, mini: `DROP DEFAULT "${table}"."${k}" ...`, color: 'cyan' });
|
|
146
|
+
if (!mute)
|
|
147
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// YAML has default but differs from DB → SET
|
|
151
|
+
if (cfgDefaultNorm !== '' && dbDefaultNorm !== cfgDefaultNorm) {
|
|
152
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" SET DEFAULT ${configDefaultSql};`;
|
|
153
|
+
queries.push({ sql, mini: `SET DEFAULT "${table}"."${k}" ...`, color: 'cyan' });
|
|
154
|
+
if (!mute)
|
|
155
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// ─── 6b. ALTER NULL/NOT NULL if changed ───
|
|
159
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
160
|
+
if (!currentColumns[k])
|
|
161
|
+
continue;
|
|
162
|
+
// Skip SERIAL (always NOT NULL implicitly)
|
|
163
|
+
if (v.type.includes('SERIAL'))
|
|
164
|
+
continue;
|
|
165
|
+
if (v.nullable === '')
|
|
166
|
+
continue; // no constraint specified (e.g. id)
|
|
167
|
+
const dbNullable = currentColumns[k].is_nullable; // 'YES' or 'NO'
|
|
168
|
+
const yamlWantsNotNull = v.nullable === 'NOT NULL';
|
|
169
|
+
const dbIsNotNull = dbNullable === 'NO';
|
|
170
|
+
if (yamlWantsNotNull && !dbIsNotNull) {
|
|
171
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" SET NOT NULL;`;
|
|
172
|
+
queries.push({ sql, mini: `SET NOT NULL "${table}"."${k}" ...`, color: 'cyan' });
|
|
173
|
+
if (!mute)
|
|
174
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
175
|
+
}
|
|
176
|
+
else if (!yamlWantsNotNull && dbIsNotNull) {
|
|
177
|
+
const sql = `ALTER TABLE "${table}" ALTER COLUMN "${k}" DROP NOT NULL;`;
|
|
178
|
+
queries.push({ sql, mini: `DROP NOT NULL "${table}"."${k}" ...`, color: 'cyan' });
|
|
179
|
+
if (!mute)
|
|
180
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ─── 7. CREATE missing individual indexes ───
|
|
184
|
+
for (const field of individualIndexes) {
|
|
185
|
+
const indexName = `${table}_${field}_idx`;
|
|
186
|
+
if (!existingIndexNames.includes(indexName)) {
|
|
187
|
+
const sql = `CREATE INDEX CONCURRENTLY "${indexName}" ON "${table}" ("${field}");`;
|
|
188
|
+
queries.push({ sql, mini: `ADD INDEX "${indexName}" ...`, color: 'cyan' });
|
|
189
|
+
if (!mute)
|
|
190
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// ─── 8. CREATE missing composite indexes ───
|
|
194
|
+
for (const [indexName, columns] of Object.entries(compositeIndexes)) {
|
|
195
|
+
const fullName = `${table}_${indexName}_idx`;
|
|
196
|
+
if (!existingIndexNames.includes(fullName)) {
|
|
197
|
+
const colsStr = columns.map(c => `"${c}"`).join(', ');
|
|
198
|
+
const sql = `CREATE INDEX CONCURRENTLY "${fullName}" ON "${table}" (${colsStr});`;
|
|
199
|
+
queries.push({ sql, mini: `ADD INDEX "${fullName}" ...`, color: 'cyan' });
|
|
200
|
+
if (!mute)
|
|
201
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ─── 9. CREATE missing composite unique indexes ───
|
|
205
|
+
for (const [indexName, columns] of Object.entries(compositeUniqueIndexes)) {
|
|
206
|
+
const fullName = `${table}_${indexName}_unique_idx`;
|
|
207
|
+
if (!existingIndexNames.includes(fullName)) {
|
|
208
|
+
const colsStr = columns.map(c => `"${c}"`).join(', ');
|
|
209
|
+
const sql = `CREATE UNIQUE INDEX CONCURRENTLY "${fullName}" ON "${table}" (${colsStr});`;
|
|
210
|
+
queries.push({ sql, mini: `ADD UNIQUE INDEX "${fullName}" ...`, color: 'cyan' });
|
|
211
|
+
if (!mute)
|
|
212
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// ─── 10. CREATE missing UNIQUE constraints ───
|
|
216
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
217
|
+
if (v.key === 'UNI') {
|
|
218
|
+
const uniqueName = `${table}_${k}_unique`;
|
|
219
|
+
if (!existingUniqueNames.includes(uniqueName)) {
|
|
220
|
+
const sql = `ALTER TABLE "${table}" ADD CONSTRAINT "${uniqueName}" UNIQUE ("${k}");`;
|
|
221
|
+
queries.push({ sql, mini: `ADD UNIQUE "${uniqueName}" ...`, color: 'cyan' });
|
|
222
|
+
if (!mute)
|
|
223
|
+
log.say(`→ ${sql}`, 'cyan');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ─── Status ───
|
|
228
|
+
if (queries.length === 0 && !mute) {
|
|
229
|
+
log.say('✓ Table is up to date');
|
|
230
|
+
}
|
|
231
|
+
return queries;
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=diffEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diffEngine.js","sourceRoot":"","sources":["../src/diffEngine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { PgService } from './pgService.js';
|
|
2
|
+
export { up, up as migrate, type BuilderOptions, type MigrationResult } from './builder.js';
|
|
3
|
+
export { parseSchema } from './schemaParser.js';
|
|
4
|
+
export { loadConfig } from './configLoader.js';
|
|
5
|
+
export { generateCreateTable, generateDropTable, generateCreateDatabase } from './sqlGenerator.js';
|
|
6
|
+
export { generateUpdateTable } from './diffEngine.js';
|
|
7
|
+
export { normalizeDefaultSql, buildDefaultClause, normalizeDbDefaultForCompare } from './defaultNormalizer.js';
|
|
8
|
+
export { POSTGRES_TYPE_DICTIONARY } from './typeDictionary.js';
|
|
9
|
+
export * as logger from './logger.js';
|
|
10
|
+
export type { FieldDefinition, ParsedSchema, DbNodeConfig, CustomFieldDef, PostgresConfig, DbColumnInfo, QueuedQuery, TenantKeysConfig, LogColor, } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC/G,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAGtC,YAAY,EACR,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,cAAc,EACd,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,QAAQ,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// x-postgres — Public API exports
|
|
3
|
+
// ─────────────────────────────────────────────
|
|
4
|
+
// Use these exports when importing x-postgres as
|
|
5
|
+
// a library in Next.js or other Node.js projects.
|
|
6
|
+
export { PgService } from './pgService.js';
|
|
7
|
+
export { up, up as migrate } from './builder.js';
|
|
8
|
+
export { parseSchema } from './schemaParser.js';
|
|
9
|
+
export { loadConfig } from './configLoader.js';
|
|
10
|
+
export { generateCreateTable, generateDropTable, generateCreateDatabase } from './sqlGenerator.js';
|
|
11
|
+
export { generateUpdateTable } from './diffEngine.js';
|
|
12
|
+
export { normalizeDefaultSql, buildDefaultClause, normalizeDbDefaultForCompare } from './defaultNormalizer.js';
|
|
13
|
+
export { POSTGRES_TYPE_DICTIONARY } from './typeDictionary.js';
|
|
14
|
+
export * as logger from './logger.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,kCAAkC;AAClC,gDAAgD;AAChD,iDAAiD;AACjD,kDAAkD;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,OAAO,EAA6C,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAC/G,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LogColor } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Print a section header with a separator line.
|
|
4
|
+
*/
|
|
5
|
+
export declare function header(text: string, color?: LogColor): void;
|
|
6
|
+
/**
|
|
7
|
+
* Print a message, optionally colored.
|
|
8
|
+
*/
|
|
9
|
+
export declare function say(text: string, color?: LogColor): void;
|
|
10
|
+
/**
|
|
11
|
+
* Print a success message (green).
|
|
12
|
+
*/
|
|
13
|
+
export declare function success(text: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Print a warning message (yellow).
|
|
16
|
+
*/
|
|
17
|
+
export declare function warn(text: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Print an error message (red).
|
|
20
|
+
*/
|
|
21
|
+
export declare function error(text: string): void;
|
|
22
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqB3C;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,QAAkB,GAAG,IAAI,CAMpE;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAMxD;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAExC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// x-postgres — Logger
|
|
3
|
+
// ─────────────────────────────────────────────
|
|
4
|
+
// Terminal output utilities with color support.
|
|
5
|
+
// Respects NO_COLOR env and --no-color flag.
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
/**
|
|
8
|
+
* Check if color output is disabled.
|
|
9
|
+
* Respects NO_COLOR standard (https://no-color.org/) and --no-color CLI flag.
|
|
10
|
+
*/
|
|
11
|
+
function isColorDisabled() {
|
|
12
|
+
return 'NO_COLOR' in process.env || process.argv.includes('--no-color');
|
|
13
|
+
}
|
|
14
|
+
const colorFns = {
|
|
15
|
+
green: (s) => isColorDisabled() ? s : chalk.green(s),
|
|
16
|
+
yellow: (s) => isColorDisabled() ? s : chalk.yellow(s),
|
|
17
|
+
cyan: (s) => isColorDisabled() ? s : chalk.cyan(s),
|
|
18
|
+
gray: (s) => isColorDisabled() ? s : chalk.gray(s),
|
|
19
|
+
red: (s) => isColorDisabled() ? s : chalk.red(s),
|
|
20
|
+
magenta: (s) => isColorDisabled() ? s : chalk.magenta(s),
|
|
21
|
+
blue: (s) => isColorDisabled() ? s : chalk.blue(s),
|
|
22
|
+
white: (s) => isColorDisabled() ? s : chalk.white(s),
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Print a section header with a separator line.
|
|
26
|
+
*/
|
|
27
|
+
export function header(text, color = 'green') {
|
|
28
|
+
const line = '━'.repeat(50);
|
|
29
|
+
const colorize = colorFns[color] ?? colorFns.green;
|
|
30
|
+
console.log(colorize(line));
|
|
31
|
+
console.log(colorize(text));
|
|
32
|
+
console.log(colorize(line));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Print a message, optionally colored.
|
|
36
|
+
*/
|
|
37
|
+
export function say(text, color) {
|
|
38
|
+
if (color && colorFns[color]) {
|
|
39
|
+
console.log(colorFns[color](text));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.log(text);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Print a success message (green).
|
|
47
|
+
*/
|
|
48
|
+
export function success(text) {
|
|
49
|
+
say(text, 'green');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Print a warning message (yellow).
|
|
53
|
+
*/
|
|
54
|
+
export function warn(text) {
|
|
55
|
+
say(text, 'yellow');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Print an error message (red).
|
|
59
|
+
*/
|
|
60
|
+
export function error(text) {
|
|
61
|
+
say(text, 'red');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import pg from 'pg';
|
|
2
|
+
import type { DbNodeConfig } from './types.js';
|
|
3
|
+
interface PgServiceOptions {
|
|
4
|
+
/** Cluster name (key in POSTGRES.DB config) */
|
|
5
|
+
cluster?: string;
|
|
6
|
+
/** Force primary (write) node */
|
|
7
|
+
primary?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class PgService {
|
|
10
|
+
private clusterName;
|
|
11
|
+
private writeNode;
|
|
12
|
+
private readNodes;
|
|
13
|
+
private forcePrimary;
|
|
14
|
+
error: string | null;
|
|
15
|
+
constructor(clusterConf: DbNodeConfig | DbNodeConfig[], clusterName: string, options?: PgServiceOptions);
|
|
16
|
+
private getWritePool;
|
|
17
|
+
private getReadPool;
|
|
18
|
+
/**
|
|
19
|
+
* Create a barebone admin connection (without database name).
|
|
20
|
+
* Used for CREATE DATABASE operations.
|
|
21
|
+
*/
|
|
22
|
+
getAdminPool(): pg.Pool;
|
|
23
|
+
/**
|
|
24
|
+
* Execute a SQL query with optional named parameters.
|
|
25
|
+
* Automatically routes to read or write pool.
|
|
26
|
+
*/
|
|
27
|
+
query<T extends Record<string, unknown> = Record<string, unknown>>(sql: string, params?: Record<string, unknown>): Promise<T[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Insert a row into a table. Returns the last insert id (if available).
|
|
30
|
+
*/
|
|
31
|
+
insert(table: string, data: Record<string, unknown>): Promise<string | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Update rows in a table. Returns the number of affected rows.
|
|
34
|
+
*/
|
|
35
|
+
update(table: string, data: Record<string, unknown>, condition: Record<string, unknown> | string): Promise<number>;
|
|
36
|
+
/**
|
|
37
|
+
* Close all connection pools.
|
|
38
|
+
*/
|
|
39
|
+
static closeAll(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=pgService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pgService.d.ts","sourceRoot":"","sources":["../src/pgService.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,UAAU,gBAAgB;IACtB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAuED,qBAAa,SAAS;IAClB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,YAAY,CAAU;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAG/B,WAAW,EAAE,YAAY,GAAG,YAAY,EAAE,EAC1C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,gBAAqB;IASlC,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,WAAW;IAOnB;;;OAGG;IACH,YAAY,IAAI,EAAE,CAAC,IAAI;IAuBvB;;;OAGG;IACG,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,CAAC,EAAE,CAAC;IA+Bf;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsBlF;;OAEG;IACG,MAAM,CACR,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAC5C,OAAO,CAAC,MAAM,CAAC;IAuClB;;OAEG;WACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOzC"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// x-postgres — PgService
|
|
3
|
+
// ─────────────────────────────────────────────
|
|
4
|
+
// PostgreSQL connection & query service.
|
|
5
|
+
// Port of PHP PgService with read/write splitting,
|
|
6
|
+
// multi-cluster, and connection pooling via pg.Pool.
|
|
7
|
+
import pg from 'pg';
|
|
8
|
+
const { Pool } = pg;
|
|
9
|
+
// Pool registry — keyed by connection string to avoid duplicates
|
|
10
|
+
// while still being manageable per PgService instance.
|
|
11
|
+
const poolRegistry = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the read and write node configs from a cluster config entry.
|
|
14
|
+
*/
|
|
15
|
+
function resolveCluster(clusterConf) {
|
|
16
|
+
// Single-node cluster
|
|
17
|
+
if (!Array.isArray(clusterConf)) {
|
|
18
|
+
return { writeNode: clusterConf, readNodes: [clusterConf] };
|
|
19
|
+
}
|
|
20
|
+
let writeNode = null;
|
|
21
|
+
const readNodes = [];
|
|
22
|
+
for (const node of clusterConf) {
|
|
23
|
+
if (node.TYPE === 'write') {
|
|
24
|
+
writeNode = node;
|
|
25
|
+
}
|
|
26
|
+
else if (node.TYPE === 'read') {
|
|
27
|
+
// Support multiple hosts per read node
|
|
28
|
+
const hosts = Array.isArray(node.HOST) ? node.HOST : [node.HOST];
|
|
29
|
+
for (const host of hosts) {
|
|
30
|
+
readNodes.push({ ...node, HOST: host });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (!writeNode)
|
|
35
|
+
throw new Error('No write node found in cluster');
|
|
36
|
+
if (readNodes.length === 0)
|
|
37
|
+
readNodes.push(writeNode);
|
|
38
|
+
return { writeNode, readNodes };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get or create a connection pool for a specific node.
|
|
42
|
+
*/
|
|
43
|
+
function getPool(node, key) {
|
|
44
|
+
if (poolRegistry.has(key))
|
|
45
|
+
return poolRegistry.get(key);
|
|
46
|
+
const host = Array.isArray(node.HOST) ? node.HOST[0] : node.HOST;
|
|
47
|
+
const pool = new Pool({
|
|
48
|
+
host,
|
|
49
|
+
port: typeof node.PORT === 'string' ? parseInt(node.PORT, 10) : node.PORT,
|
|
50
|
+
database: node.NAME,
|
|
51
|
+
user: node.USER,
|
|
52
|
+
password: node.PASS,
|
|
53
|
+
max: 10,
|
|
54
|
+
idleTimeoutMillis: 30000,
|
|
55
|
+
});
|
|
56
|
+
pool.on('error', (err) => {
|
|
57
|
+
console.error(`[x-postgres] Pool error (${key}):`, err.message);
|
|
58
|
+
});
|
|
59
|
+
poolRegistry.set(key, pool);
|
|
60
|
+
return pool;
|
|
61
|
+
}
|
|
62
|
+
const READ_COMMANDS = ['SELECT', 'SHOW', 'EXPLAIN', 'WITH'];
|
|
63
|
+
function isReadOnly(sql) {
|
|
64
|
+
const first = sql.trim().split(/\s+/)[0].toUpperCase();
|
|
65
|
+
return READ_COMMANDS.includes(first);
|
|
66
|
+
}
|
|
67
|
+
export class PgService {
|
|
68
|
+
constructor(clusterConf, clusterName, options = {}) {
|
|
69
|
+
this.error = null;
|
|
70
|
+
this.clusterName = clusterName;
|
|
71
|
+
this.forcePrimary = options.primary ?? false;
|
|
72
|
+
const { writeNode, readNodes } = resolveCluster(clusterConf);
|
|
73
|
+
this.writeNode = writeNode;
|
|
74
|
+
this.readNodes = readNodes;
|
|
75
|
+
}
|
|
76
|
+
getWritePool() {
|
|
77
|
+
return getPool(this.writeNode, `${this.clusterName}:write`);
|
|
78
|
+
}
|
|
79
|
+
getReadPool() {
|
|
80
|
+
if (this.forcePrimary)
|
|
81
|
+
return this.getWritePool();
|
|
82
|
+
// Random read replica selection
|
|
83
|
+
const idx = Math.floor(Math.random() * this.readNodes.length);
|
|
84
|
+
return getPool(this.readNodes[idx], `${this.clusterName}:read:${idx}`);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Create a barebone admin connection (without database name).
|
|
88
|
+
* Used for CREATE DATABASE operations.
|
|
89
|
+
*/
|
|
90
|
+
getAdminPool() {
|
|
91
|
+
const node = this.writeNode;
|
|
92
|
+
const key = `${this.clusterName}:admin`;
|
|
93
|
+
if (poolRegistry.has(key))
|
|
94
|
+
return poolRegistry.get(key);
|
|
95
|
+
const host = Array.isArray(node.HOST) ? node.HOST[0] : node.HOST;
|
|
96
|
+
const pool = new Pool({
|
|
97
|
+
host,
|
|
98
|
+
port: typeof node.PORT === 'string' ? parseInt(node.PORT, 10) : node.PORT,
|
|
99
|
+
database: 'postgres', // connect to default db for admin
|
|
100
|
+
user: node.USER,
|
|
101
|
+
password: node.PASS,
|
|
102
|
+
max: 2,
|
|
103
|
+
});
|
|
104
|
+
pool.on('error', (err) => {
|
|
105
|
+
console.error(`[x-postgres] Admin pool error:`, err.message);
|
|
106
|
+
});
|
|
107
|
+
poolRegistry.set(key, pool);
|
|
108
|
+
return pool;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Execute a SQL query with optional named parameters.
|
|
112
|
+
* Automatically routes to read or write pool.
|
|
113
|
+
*/
|
|
114
|
+
async query(sql, params) {
|
|
115
|
+
const pool = isReadOnly(sql) && !this.forcePrimary
|
|
116
|
+
? this.getReadPool()
|
|
117
|
+
: this.getWritePool();
|
|
118
|
+
try {
|
|
119
|
+
// Convert named params :key to $N positional params
|
|
120
|
+
let pgSql = sql;
|
|
121
|
+
const values = [];
|
|
122
|
+
if (params && Object.keys(params).length > 0) {
|
|
123
|
+
let paramIndex = 0;
|
|
124
|
+
// Use negative lookbehind to avoid matching ::typecast syntax
|
|
125
|
+
pgSql = sql.replace(/(?<!:):([a-zA-Z_]\w*)/g, (_match, key) => {
|
|
126
|
+
if (params[key] !== undefined) {
|
|
127
|
+
paramIndex++;
|
|
128
|
+
values.push(params[key]);
|
|
129
|
+
return `$${paramIndex}`;
|
|
130
|
+
}
|
|
131
|
+
return _match;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const result = await pool.query(pgSql, values.length > 0 ? values : undefined);
|
|
135
|
+
return result.rows;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
this.error = err.message;
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Insert a row into a table. Returns the last insert id (if available).
|
|
144
|
+
*/
|
|
145
|
+
async insert(table, data) {
|
|
146
|
+
const pool = this.getWritePool();
|
|
147
|
+
const keys = Object.keys(data);
|
|
148
|
+
const cols = keys.map(k => `"${k}"`).join(', ');
|
|
149
|
+
const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ');
|
|
150
|
+
const values = keys.map(k => {
|
|
151
|
+
const v = data[k];
|
|
152
|
+
if (v === 'NULL' || v === 'null' || v === '')
|
|
153
|
+
return null;
|
|
154
|
+
return v;
|
|
155
|
+
});
|
|
156
|
+
const sql = `INSERT INTO "${table}" (${cols}) VALUES (${placeholders}) RETURNING *`;
|
|
157
|
+
try {
|
|
158
|
+
const result = await pool.query(sql, values);
|
|
159
|
+
return result.rows[0]?.id ?? null;
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
this.error = err.message;
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Update rows in a table. Returns the number of affected rows.
|
|
168
|
+
*/
|
|
169
|
+
async update(table, data, condition) {
|
|
170
|
+
const pool = this.getWritePool();
|
|
171
|
+
const vals = [];
|
|
172
|
+
let idx = 0;
|
|
173
|
+
// SET clause
|
|
174
|
+
const setClauses = Object.entries(data).map(([k, v]) => {
|
|
175
|
+
if (v === 'NULL' || v === 'null' || v === '')
|
|
176
|
+
return `"${k}" = NULL`;
|
|
177
|
+
idx++;
|
|
178
|
+
vals.push(v);
|
|
179
|
+
return `"${k}" = $${idx}`;
|
|
180
|
+
});
|
|
181
|
+
// WHERE clause
|
|
182
|
+
let whereClause;
|
|
183
|
+
if (typeof condition === 'string') {
|
|
184
|
+
whereClause = condition;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
const whereParts = Object.entries(condition).map(([k, v]) => {
|
|
188
|
+
if (v === 'NULL')
|
|
189
|
+
return `"${k}" IS NULL`;
|
|
190
|
+
if (v === '')
|
|
191
|
+
return `"${k}" = ''`;
|
|
192
|
+
idx++;
|
|
193
|
+
vals.push(v);
|
|
194
|
+
return `"${k}" = $${idx}`;
|
|
195
|
+
});
|
|
196
|
+
whereClause = whereParts.join(' AND ');
|
|
197
|
+
}
|
|
198
|
+
const sql = `UPDATE "${table}" SET ${setClauses.join(', ')} WHERE ${whereClause}`;
|
|
199
|
+
try {
|
|
200
|
+
const result = await pool.query(sql, vals);
|
|
201
|
+
return result.rowCount ?? 0;
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
this.error = err.message;
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Close all connection pools.
|
|
210
|
+
*/
|
|
211
|
+
static async closeAll() {
|
|
212
|
+
const entries = Array.from(poolRegistry.entries());
|
|
213
|
+
for (const [key, pool] of entries) {
|
|
214
|
+
await pool.end();
|
|
215
|
+
poolRegistry.delete(key);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=pgService.js.map
|