@xylex-group/athena 1.6.1 → 1.7.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/README.md +77 -6
- package/bin/athena-js.js +74 -6
- package/dist/cli/index.cjs +233 -40
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +21 -2
- package/dist/cli/index.d.ts +21 -2
- package/dist/cli/index.js +232 -41
- package/dist/cli/index.js.map +1 -1
- package/dist/errors-BJGgjHcI.d.cts +31 -0
- package/dist/errors-Bcf5Sftv.d.ts +31 -0
- package/dist/index.cjs +638 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +266 -335
- package/dist/index.d.ts +266 -335
- package/dist/index.js +635 -27
- package/dist/index.js.map +1 -1
- package/dist/pipeline-BsKuBqmE.d.cts +343 -0
- package/dist/pipeline-xQSjGbqF.d.ts +343 -0
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/{errors-C4GJaFI_.d.cts → types-wPA1Z4vQ.d.cts} +1 -29
- package/dist/{errors-C4GJaFI_.d.ts → types-wPA1Z4vQ.d.ts} +1 -29
- package/package.json +1 -1
package/dist/cli/index.d.cts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
import { F as runSchemaGenerator } from '../pipeline-BsKuBqmE.cjs';
|
|
2
|
+
import '../types-wPA1Z4vQ.cjs';
|
|
3
|
+
|
|
4
|
+
interface GenerateCommand {
|
|
5
|
+
command: 'generate';
|
|
6
|
+
configPath?: string;
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface HelpCommand {
|
|
10
|
+
command: 'help';
|
|
11
|
+
topic: 'root' | 'generate';
|
|
12
|
+
}
|
|
13
|
+
type CliCommand = GenerateCommand | HelpCommand;
|
|
14
|
+
interface CliRuntime {
|
|
15
|
+
runGenerator?: typeof runSchemaGenerator;
|
|
16
|
+
log?: (message: string) => void;
|
|
17
|
+
}
|
|
18
|
+
declare function usage(topic?: HelpCommand['topic']): string;
|
|
19
|
+
declare function parseCommand(argv: string[]): CliCommand;
|
|
1
20
|
/**
|
|
2
21
|
* CLI entrypoint used by `bin/athena-js.js`.
|
|
3
22
|
*/
|
|
4
|
-
declare function runCLI(argv: string[]): Promise<void>;
|
|
23
|
+
declare function runCLI(argv: string[], runtime?: CliRuntime): Promise<void>;
|
|
5
24
|
|
|
6
|
-
export { runCLI };
|
|
25
|
+
export { type CliRuntime, parseCommand, runCLI, usage };
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
import { F as runSchemaGenerator } from '../pipeline-xQSjGbqF.js';
|
|
2
|
+
import '../types-wPA1Z4vQ.js';
|
|
3
|
+
|
|
4
|
+
interface GenerateCommand {
|
|
5
|
+
command: 'generate';
|
|
6
|
+
configPath?: string;
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface HelpCommand {
|
|
10
|
+
command: 'help';
|
|
11
|
+
topic: 'root' | 'generate';
|
|
12
|
+
}
|
|
13
|
+
type CliCommand = GenerateCommand | HelpCommand;
|
|
14
|
+
interface CliRuntime {
|
|
15
|
+
runGenerator?: typeof runSchemaGenerator;
|
|
16
|
+
log?: (message: string) => void;
|
|
17
|
+
}
|
|
18
|
+
declare function usage(topic?: HelpCommand['topic']): string;
|
|
19
|
+
declare function parseCommand(argv: string[]): CliCommand;
|
|
1
20
|
/**
|
|
2
21
|
* CLI entrypoint used by `bin/athena-js.js`.
|
|
3
22
|
*/
|
|
4
|
-
declare function runCLI(argv: string[]): Promise<void>;
|
|
23
|
+
declare function runCLI(argv: string[], runtime?: CliRuntime): Promise<void>;
|
|
5
24
|
|
|
6
|
-
export { runCLI };
|
|
25
|
+
export { type CliRuntime, parseCommand, runCLI, usage };
|
package/dist/cli/index.js
CHANGED
|
@@ -289,6 +289,37 @@ function resolvePostgresColumnType(column) {
|
|
|
289
289
|
}
|
|
290
290
|
return wrapArrayType(baseType, column.arrayDimensions);
|
|
291
291
|
}
|
|
292
|
+
|
|
293
|
+
// src/generator/schema-selection.ts
|
|
294
|
+
var DEFAULT_POSTGRES_SCHEMAS = ["public"];
|
|
295
|
+
function collectSchemaNames(input) {
|
|
296
|
+
if (!input) {
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
const values = typeof input === "string" ? [input] : input;
|
|
300
|
+
return values.flatMap((value) => String(value).split(","));
|
|
301
|
+
}
|
|
302
|
+
function normalizeSchemaSelection(input) {
|
|
303
|
+
const schemas = [];
|
|
304
|
+
const seen = /* @__PURE__ */ new Set();
|
|
305
|
+
for (const value of collectSchemaNames(input)) {
|
|
306
|
+
const schema = value.trim();
|
|
307
|
+
if (!schema || seen.has(schema)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
seen.add(schema);
|
|
311
|
+
schemas.push(schema);
|
|
312
|
+
}
|
|
313
|
+
return schemas.length > 0 ? schemas : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
314
|
+
}
|
|
315
|
+
function resolveProviderSchemas(providerConfig) {
|
|
316
|
+
if (providerConfig.kind === "postgres") {
|
|
317
|
+
return normalizeSchemaSelection(providerConfig.schemas);
|
|
318
|
+
}
|
|
319
|
+
return [...DEFAULT_POSTGRES_SCHEMAS];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/generator/config.ts
|
|
292
323
|
var DEFAULT_CONFIG_CANDIDATES = [
|
|
293
324
|
"athena.config.ts",
|
|
294
325
|
"athena.config.js",
|
|
@@ -298,10 +329,10 @@ var DEFAULT_CONFIG_CANDIDATES = [
|
|
|
298
329
|
".athena.config.js"
|
|
299
330
|
];
|
|
300
331
|
var DEFAULT_TARGETS = {
|
|
301
|
-
model: "
|
|
302
|
-
schema: "
|
|
303
|
-
database: "
|
|
304
|
-
registry: "
|
|
332
|
+
model: "athena/models/{schema_kebab}/{model_kebab}.ts",
|
|
333
|
+
schema: "athena/schemas/{schema_kebab}.ts",
|
|
334
|
+
database: "athena/relations.ts",
|
|
335
|
+
registry: "athena/config.ts"
|
|
305
336
|
};
|
|
306
337
|
var DEFAULT_NAMING = {
|
|
307
338
|
modelType: "pascal",
|
|
@@ -329,6 +360,15 @@ function normalizeOutputConfig(output) {
|
|
|
329
360
|
}
|
|
330
361
|
};
|
|
331
362
|
}
|
|
363
|
+
function normalizeProviderConfig(provider) {
|
|
364
|
+
if (provider.kind === "postgres") {
|
|
365
|
+
return {
|
|
366
|
+
...provider,
|
|
367
|
+
schemas: normalizeSchemaSelection(provider.schemas)
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
return provider;
|
|
371
|
+
}
|
|
332
372
|
function isAthenaGeneratorConfig(value) {
|
|
333
373
|
if (!value || typeof value !== "object") {
|
|
334
374
|
return false;
|
|
@@ -338,7 +378,7 @@ function isAthenaGeneratorConfig(value) {
|
|
|
338
378
|
}
|
|
339
379
|
function normalizeGeneratorConfig(input) {
|
|
340
380
|
return {
|
|
341
|
-
provider: input.provider,
|
|
381
|
+
provider: normalizeProviderConfig(input.provider),
|
|
342
382
|
output: normalizeOutputConfig(input.output),
|
|
343
383
|
naming: {
|
|
344
384
|
...DEFAULT_NAMING,
|
|
@@ -548,12 +588,19 @@ export const ${registryConstName} = defineRegistry({
|
|
|
548
588
|
};
|
|
549
589
|
}
|
|
550
590
|
function assertNoDuplicatePaths(files) {
|
|
551
|
-
const seen = /* @__PURE__ */ new
|
|
591
|
+
const seen = /* @__PURE__ */ new Map();
|
|
552
592
|
for (const file of files) {
|
|
553
|
-
|
|
554
|
-
|
|
593
|
+
const existing = seen.get(file.path);
|
|
594
|
+
if (existing) {
|
|
595
|
+
throw new Error(
|
|
596
|
+
[
|
|
597
|
+
`Generator output collision detected for path: ${file.path}`,
|
|
598
|
+
`Collision: ${existing.kind} and ${file.kind}.`,
|
|
599
|
+
"When syncing multiple schemas, include a schema placeholder such as {schema} or {schema_kebab} in model/schema output targets."
|
|
600
|
+
].join(" ")
|
|
601
|
+
);
|
|
555
602
|
}
|
|
556
|
-
seen.
|
|
603
|
+
seen.set(file.path, file);
|
|
557
604
|
}
|
|
558
605
|
}
|
|
559
606
|
var ArtifactComposer = class {
|
|
@@ -2057,8 +2104,73 @@ function toTypeKind(code) {
|
|
|
2057
2104
|
function escapeSqlLiteral(value) {
|
|
2058
2105
|
return value.replace(/'/g, "''");
|
|
2059
2106
|
}
|
|
2107
|
+
function parsePostgresArrayLiteral(text) {
|
|
2108
|
+
const body = text.slice(1, -1).trim();
|
|
2109
|
+
if (!body) return [];
|
|
2110
|
+
const values = [];
|
|
2111
|
+
let current = "";
|
|
2112
|
+
let inQuotes = false;
|
|
2113
|
+
let escaped = false;
|
|
2114
|
+
for (const char of body) {
|
|
2115
|
+
if (escaped) {
|
|
2116
|
+
current += char;
|
|
2117
|
+
escaped = false;
|
|
2118
|
+
continue;
|
|
2119
|
+
}
|
|
2120
|
+
if (char === "\\") {
|
|
2121
|
+
escaped = true;
|
|
2122
|
+
continue;
|
|
2123
|
+
}
|
|
2124
|
+
if (char === '"') {
|
|
2125
|
+
inQuotes = !inQuotes;
|
|
2126
|
+
continue;
|
|
2127
|
+
}
|
|
2128
|
+
if (char === "," && !inQuotes) {
|
|
2129
|
+
values.push(current);
|
|
2130
|
+
current = "";
|
|
2131
|
+
continue;
|
|
2132
|
+
}
|
|
2133
|
+
current += char;
|
|
2134
|
+
}
|
|
2135
|
+
values.push(current);
|
|
2136
|
+
return values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
2137
|
+
}
|
|
2138
|
+
function coerceStringArray(value) {
|
|
2139
|
+
if (Array.isArray(value)) {
|
|
2140
|
+
return value.map((item) => typeof item === "string" ? item : String(item)).map((item) => item.trim()).filter((item) => item.length > 0);
|
|
2141
|
+
}
|
|
2142
|
+
if (typeof value === "string") {
|
|
2143
|
+
const trimmed = value.trim();
|
|
2144
|
+
if (!trimmed) return [];
|
|
2145
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
2146
|
+
try {
|
|
2147
|
+
const parsed = JSON.parse(trimmed);
|
|
2148
|
+
return coerceStringArray(parsed);
|
|
2149
|
+
} catch {
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
2153
|
+
return parsePostgresArrayLiteral(trimmed);
|
|
2154
|
+
}
|
|
2155
|
+
return trimmed.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
2156
|
+
}
|
|
2157
|
+
return [];
|
|
2158
|
+
}
|
|
2159
|
+
function normalizePostgresCatalogSchemas(schemas) {
|
|
2160
|
+
const normalized = [];
|
|
2161
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2162
|
+
for (const value of schemas ?? []) {
|
|
2163
|
+
const schema = value.trim();
|
|
2164
|
+
if (!schema || seen.has(schema)) {
|
|
2165
|
+
continue;
|
|
2166
|
+
}
|
|
2167
|
+
seen.add(schema);
|
|
2168
|
+
normalized.push(schema);
|
|
2169
|
+
}
|
|
2170
|
+
return normalized.length > 0 ? normalized : ["public"];
|
|
2171
|
+
}
|
|
2060
2172
|
function buildSchemaArrayLiteral(schemas) {
|
|
2061
|
-
const normalized = schemas
|
|
2173
|
+
const normalized = normalizePostgresCatalogSchemas(schemas);
|
|
2062
2174
|
const literals = normalized.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
|
|
2063
2175
|
return `ARRAY[${literals}]`;
|
|
2064
2176
|
}
|
|
@@ -2096,8 +2208,10 @@ var PostgresCatalogSnapshotAssembler = class {
|
|
|
2096
2208
|
addPrimaryKeyRows(primaryKeyRows) {
|
|
2097
2209
|
for (const row of primaryKeyRows) {
|
|
2098
2210
|
const table = this.ensureTable(row.schema_name, row.table_name);
|
|
2099
|
-
|
|
2100
|
-
|
|
2211
|
+
const primaryKeyColumns = coerceStringArray(row.columns);
|
|
2212
|
+
row.columns = primaryKeyColumns;
|
|
2213
|
+
table.primaryKey = primaryKeyColumns;
|
|
2214
|
+
for (const columnName of primaryKeyColumns) {
|
|
2101
2215
|
const column = table.columns[columnName];
|
|
2102
2216
|
if (column) {
|
|
2103
2217
|
column.isPrimaryKey = true;
|
|
@@ -2109,23 +2223,27 @@ var PostgresCatalogSnapshotAssembler = class {
|
|
|
2109
2223
|
for (const row of foreignKeyRows) {
|
|
2110
2224
|
const sourceTable = this.ensureTable(row.source_schema, row.source_table);
|
|
2111
2225
|
const targetTable = this.ensureTable(row.target_schema, row.target_table);
|
|
2226
|
+
const sourceColumns = coerceStringArray(row.source_columns);
|
|
2227
|
+
const targetColumns = coerceStringArray(row.target_columns);
|
|
2228
|
+
row.source_columns = sourceColumns;
|
|
2229
|
+
row.target_columns = targetColumns;
|
|
2112
2230
|
const sourceRelationKind = row.source_is_unique ? "one-to-one" : "many-to-one";
|
|
2113
2231
|
this.upsertRelation(sourceTable, relationKey(row.constraint_name, row.target_table), {
|
|
2114
2232
|
name: row.constraint_name,
|
|
2115
2233
|
kind: sourceRelationKind,
|
|
2116
|
-
sourceColumns
|
|
2234
|
+
sourceColumns,
|
|
2117
2235
|
targetSchema: row.target_schema,
|
|
2118
2236
|
targetModel: row.target_table,
|
|
2119
|
-
targetColumns
|
|
2237
|
+
targetColumns
|
|
2120
2238
|
});
|
|
2121
2239
|
const targetRelationKind = row.source_is_unique ? "one-to-one" : "one-to-many";
|
|
2122
2240
|
this.upsertRelation(targetTable, relationKey(row.source_table), {
|
|
2123
2241
|
name: relationKey(row.source_table, row.constraint_name),
|
|
2124
2242
|
kind: targetRelationKind,
|
|
2125
|
-
sourceColumns:
|
|
2243
|
+
sourceColumns: targetColumns,
|
|
2126
2244
|
targetSchema: row.source_schema,
|
|
2127
2245
|
targetModel: row.source_table,
|
|
2128
|
-
targetColumns:
|
|
2246
|
+
targetColumns: sourceColumns
|
|
2129
2247
|
});
|
|
2130
2248
|
}
|
|
2131
2249
|
}
|
|
@@ -2251,12 +2369,14 @@ var PostgresIntrospectionProvider = class {
|
|
|
2251
2369
|
backend = "postgresql";
|
|
2252
2370
|
connectionString;
|
|
2253
2371
|
database;
|
|
2372
|
+
schemas;
|
|
2254
2373
|
constructor(options) {
|
|
2255
2374
|
this.connectionString = options.connectionString;
|
|
2256
2375
|
this.database = options.database ?? "postgres";
|
|
2376
|
+
this.schemas = normalizePostgresCatalogSchemas(options.schemas);
|
|
2257
2377
|
}
|
|
2258
2378
|
async inspect(options) {
|
|
2259
|
-
const schemas = options?.schemas && options.schemas.length > 0 ? options.schemas :
|
|
2379
|
+
const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
|
|
2260
2380
|
const pool = new Pool({
|
|
2261
2381
|
connectionString: this.connectionString
|
|
2262
2382
|
});
|
|
@@ -2328,11 +2448,13 @@ var AthenaGatewayPostgresIntrospectionProvider = class {
|
|
|
2328
2448
|
type: this.config.backend ?? "postgresql"
|
|
2329
2449
|
}
|
|
2330
2450
|
});
|
|
2451
|
+
this.schemas = normalizeSchemaSelection(this.config.schemas);
|
|
2331
2452
|
}
|
|
2332
2453
|
backend = "postgresql";
|
|
2333
2454
|
client;
|
|
2455
|
+
schemas;
|
|
2334
2456
|
async inspect(options) {
|
|
2335
|
-
const schemas = options?.schemas && options.schemas.length > 0 ? options.schemas : this.
|
|
2457
|
+
const schemas = options?.schemas && options.schemas.length > 0 ? normalizeSchemaSelection(options.schemas) : this.schemas;
|
|
2336
2458
|
const catalogClient = new AthenaGatewayCatalogClient(this.client);
|
|
2337
2459
|
const queries = buildGatewayCatalogQueries(schemas);
|
|
2338
2460
|
const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
|
|
@@ -2368,7 +2490,8 @@ var ScyllaIntrospectionProvider = class {
|
|
|
2368
2490
|
function createPostgresProvider(config) {
|
|
2369
2491
|
return createPostgresIntrospectionProvider({
|
|
2370
2492
|
connectionString: config.connectionString,
|
|
2371
|
-
database: config.database
|
|
2493
|
+
database: config.database,
|
|
2494
|
+
schemas: normalizeSchemaSelection(config.schemas)
|
|
2372
2495
|
});
|
|
2373
2496
|
}
|
|
2374
2497
|
function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
@@ -2390,12 +2513,6 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
2390
2513
|
}
|
|
2391
2514
|
|
|
2392
2515
|
// src/generator/pipeline.ts
|
|
2393
|
-
function extractProviderSchemas(providerConfig) {
|
|
2394
|
-
if (!("schemas" in providerConfig) || !providerConfig.schemas || providerConfig.schemas.length === 0) {
|
|
2395
|
-
return void 0;
|
|
2396
|
-
}
|
|
2397
|
-
return providerConfig.schemas;
|
|
2398
|
-
}
|
|
2399
2516
|
async function writeArtifacts(files, cwd) {
|
|
2400
2517
|
const writtenFiles = [];
|
|
2401
2518
|
for (const file of files) {
|
|
@@ -2415,7 +2532,7 @@ async function runSchemaGenerator(options = {}) {
|
|
|
2415
2532
|
const { configPath, config } = await loadGeneratorConfig(configOptions);
|
|
2416
2533
|
const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
|
|
2417
2534
|
const snapshot = await provider.inspect({
|
|
2418
|
-
schemas:
|
|
2535
|
+
schemas: resolveProviderSchemas(config.provider)
|
|
2419
2536
|
});
|
|
2420
2537
|
const generated = generateArtifactsFromSnapshot(snapshot, config);
|
|
2421
2538
|
const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);
|
|
@@ -2427,7 +2544,7 @@ async function runSchemaGenerator(options = {}) {
|
|
|
2427
2544
|
}
|
|
2428
2545
|
|
|
2429
2546
|
// src/cli/index.ts
|
|
2430
|
-
function
|
|
2547
|
+
function rootUsage() {
|
|
2431
2548
|
return [
|
|
2432
2549
|
"athena-js CLI",
|
|
2433
2550
|
"",
|
|
@@ -2436,12 +2553,42 @@ function usage() {
|
|
|
2436
2553
|
"",
|
|
2437
2554
|
"Examples:",
|
|
2438
2555
|
" athena-js generate",
|
|
2556
|
+
" athena-js generate --config ./athena.config.ts --dry-run",
|
|
2557
|
+
" athena-js generate --help"
|
|
2558
|
+
].join("\n");
|
|
2559
|
+
}
|
|
2560
|
+
function generateUsage() {
|
|
2561
|
+
return [
|
|
2562
|
+
"athena-js generate",
|
|
2563
|
+
"",
|
|
2564
|
+
"Usage:",
|
|
2565
|
+
" athena-js generate [--config <path>] [--dry-run]",
|
|
2566
|
+
"",
|
|
2567
|
+
"Options:",
|
|
2568
|
+
" --config <path> Explicit path to athena.config.ts or athena-js.config.ts",
|
|
2569
|
+
" --dry-run Build generated files in memory without writing them to disk",
|
|
2570
|
+
" -h, --help Show help for generate",
|
|
2571
|
+
"",
|
|
2572
|
+
"Examples:",
|
|
2573
|
+
" athena-js generate",
|
|
2439
2574
|
" athena-js generate --config ./athena.config.ts --dry-run"
|
|
2440
2575
|
].join("\n");
|
|
2441
2576
|
}
|
|
2577
|
+
function usage(topic = "root") {
|
|
2578
|
+
return topic === "generate" ? generateUsage() : rootUsage();
|
|
2579
|
+
}
|
|
2442
2580
|
function parseCommand(argv) {
|
|
2443
|
-
if (argv.length === 0 || argv[0] === "
|
|
2444
|
-
return { command: "help" };
|
|
2581
|
+
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
2582
|
+
return { command: "help", topic: "root" };
|
|
2583
|
+
}
|
|
2584
|
+
if (argv[0] === "help") {
|
|
2585
|
+
if (argv.length === 1) {
|
|
2586
|
+
return { command: "help", topic: "root" };
|
|
2587
|
+
}
|
|
2588
|
+
if (argv[1] === "generate") {
|
|
2589
|
+
return { command: "help", topic: "generate" };
|
|
2590
|
+
}
|
|
2591
|
+
throw new Error(`Unknown command "${argv[1]}".`);
|
|
2445
2592
|
}
|
|
2446
2593
|
const [command, ...rest] = argv;
|
|
2447
2594
|
if (command !== "generate") {
|
|
@@ -2451,13 +2598,16 @@ function parseCommand(argv) {
|
|
|
2451
2598
|
let dryRun = false;
|
|
2452
2599
|
for (let index = 0; index < rest.length; index += 1) {
|
|
2453
2600
|
const token = rest[index];
|
|
2601
|
+
if (token === "--help" || token === "-h") {
|
|
2602
|
+
return { command: "help", topic: "generate" };
|
|
2603
|
+
}
|
|
2454
2604
|
if (token === "--dry-run") {
|
|
2455
2605
|
dryRun = true;
|
|
2456
2606
|
continue;
|
|
2457
2607
|
}
|
|
2458
2608
|
if (token === "--config") {
|
|
2459
2609
|
const nextValue = rest[index + 1];
|
|
2460
|
-
if (!nextValue) {
|
|
2610
|
+
if (!nextValue || nextValue.startsWith("-")) {
|
|
2461
2611
|
throw new Error("Missing value for --config option.");
|
|
2462
2612
|
}
|
|
2463
2613
|
configPath = nextValue;
|
|
@@ -2472,29 +2622,70 @@ function parseCommand(argv) {
|
|
|
2472
2622
|
dryRun
|
|
2473
2623
|
};
|
|
2474
2624
|
}
|
|
2475
|
-
|
|
2625
|
+
function normalizeErrorMessage(error) {
|
|
2626
|
+
if (error instanceof Error) {
|
|
2627
|
+
return error.message;
|
|
2628
|
+
}
|
|
2629
|
+
if (typeof error === "string") {
|
|
2630
|
+
return error;
|
|
2631
|
+
}
|
|
2632
|
+
return "Unknown generator error.";
|
|
2633
|
+
}
|
|
2634
|
+
function extractMissingDatabaseName(message) {
|
|
2635
|
+
const match = message.match(/database "([^"]+)" does not exist/i);
|
|
2636
|
+
return match?.[1];
|
|
2637
|
+
}
|
|
2638
|
+
function isErrorWithCode(error) {
|
|
2639
|
+
return typeof error === "object" && error !== null && "code" in error;
|
|
2640
|
+
}
|
|
2641
|
+
function formatGeneratorError(error, configPath) {
|
|
2642
|
+
if (isErrorWithCode(error) && error.code === "3D000") {
|
|
2643
|
+
const message = normalizeErrorMessage(error);
|
|
2644
|
+
const databaseName = extractMissingDatabaseName(message);
|
|
2645
|
+
const databaseLabel = databaseName ? `PostgreSQL database "${databaseName}" does not exist` : "The target PostgreSQL database does not exist";
|
|
2646
|
+
const configLabel = configPath ? `config "${configPath}"` : "the resolved athena config";
|
|
2647
|
+
return new Error(
|
|
2648
|
+
[
|
|
2649
|
+
`${databaseLabel} (code 3D000).`,
|
|
2650
|
+
`Update provider.connectionString (and provider.database, if set) in ${configLabel}, or create that database before running generate.`
|
|
2651
|
+
].join("\n")
|
|
2652
|
+
);
|
|
2653
|
+
}
|
|
2654
|
+
if (error instanceof Error) {
|
|
2655
|
+
return error;
|
|
2656
|
+
}
|
|
2657
|
+
return new Error(normalizeErrorMessage(error));
|
|
2658
|
+
}
|
|
2659
|
+
async function runCLI(argv, runtime = {}) {
|
|
2660
|
+
const log = runtime.log ?? console.log;
|
|
2661
|
+
const runGenerator = runtime.runGenerator ?? runSchemaGenerator;
|
|
2476
2662
|
const parsed = parseCommand(argv);
|
|
2477
2663
|
if (parsed.command === "help") {
|
|
2478
|
-
|
|
2664
|
+
log(usage(parsed.topic));
|
|
2479
2665
|
return;
|
|
2480
2666
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2667
|
+
let result;
|
|
2668
|
+
try {
|
|
2669
|
+
result = await runGenerator({
|
|
2670
|
+
configPath: parsed.configPath,
|
|
2671
|
+
dryRun: parsed.dryRun
|
|
2672
|
+
});
|
|
2673
|
+
} catch (error) {
|
|
2674
|
+
throw formatGeneratorError(error, parsed.configPath);
|
|
2675
|
+
}
|
|
2485
2676
|
if (parsed.dryRun) {
|
|
2486
|
-
|
|
2677
|
+
log(`[dry-run] Generated ${result.files.length} files from ${result.configPath}`);
|
|
2487
2678
|
for (const file of result.files) {
|
|
2488
|
-
|
|
2679
|
+
log(` - ${file.path}`);
|
|
2489
2680
|
}
|
|
2490
2681
|
return;
|
|
2491
2682
|
}
|
|
2492
|
-
|
|
2683
|
+
log(`Generated ${result.writtenFiles.length} files from ${result.configPath}`);
|
|
2493
2684
|
for (const filePath of result.writtenFiles) {
|
|
2494
|
-
|
|
2685
|
+
log(` - ${filePath}`);
|
|
2495
2686
|
}
|
|
2496
2687
|
}
|
|
2497
2688
|
|
|
2498
|
-
export { runCLI };
|
|
2689
|
+
export { parseCommand, runCLI, usage };
|
|
2499
2690
|
//# sourceMappingURL=index.js.map
|
|
2500
2691
|
//# sourceMappingURL=index.js.map
|