@xylex-group/athena 1.6.2 → 1.9.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.
@@ -1,5 +1,5 @@
1
- import { r as runSchemaGenerator } from '../pipeline-CA2aexDl.cjs';
2
- import '../types-v6UyGg-x.cjs';
1
+ import { r as runSchemaGenerator } from '../pipeline-C-cN0ACi.cjs';
2
+ import '../types-BnzoaNRC.cjs';
3
3
 
4
4
  interface GenerateCommand {
5
5
  command: 'generate';
@@ -1,5 +1,5 @@
1
- import { r as runSchemaGenerator } from '../pipeline-BQzpSLD3.js';
2
- import '../types-v6UyGg-x.js';
1
+ import { r as runSchemaGenerator } from '../pipeline-CQgV-Yfo.js';
2
+ import '../types-BnzoaNRC.js';
3
3
 
4
4
  interface GenerateCommand {
5
5
  command: 'generate';
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,8 +329,8 @@ var DEFAULT_CONFIG_CANDIDATES = [
298
329
  ".athena.config.js"
299
330
  ];
300
331
  var DEFAULT_TARGETS = {
301
- model: "athena/models/{model_kebab}.ts",
302
- schema: "athena/schema.ts",
332
+ model: "athena/models/{schema_kebab}/{model_kebab}.ts",
333
+ schema: "athena/schemas/{schema_kebab}.ts",
303
334
  database: "athena/relations.ts",
304
335
  registry: "athena/config.ts"
305
336
  };
@@ -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 Set();
591
+ const seen = /* @__PURE__ */ new Map();
552
592
  for (const file of files) {
553
- if (seen.has(file.path)) {
554
- throw new Error(`Generator output collision detected for path: ${file.path}`);
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.add(file.path);
603
+ seen.set(file.path, file);
557
604
  }
558
605
  }
559
606
  var ArtifactComposer = class {
@@ -1182,6 +1229,12 @@ function mergeOptions(...options) {
1182
1229
  return { ...acc, ...next };
1183
1230
  }, void 0);
1184
1231
  }
1232
+ function asAthenaJsonObject(value) {
1233
+ return value;
1234
+ }
1235
+ function asAthenaJsonObjectArray(values) {
1236
+ return values;
1237
+ }
1185
1238
  function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS) {
1186
1239
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
1187
1240
  let selectedOptions;
@@ -1270,6 +1323,22 @@ function buildSelectColumnsClause(columns) {
1270
1323
  }
1271
1324
  return quoteSelectColumnsExpression(columns);
1272
1325
  }
1326
+ function resolveTableNameForCall(tableName, schema) {
1327
+ if (!schema) return tableName;
1328
+ const normalizedSchema = schema.trim();
1329
+ if (!normalizedSchema) {
1330
+ throw new Error("schema option must be a non-empty string");
1331
+ }
1332
+ if (tableName.includes(".")) {
1333
+ if (tableName.startsWith(`${normalizedSchema}.`)) {
1334
+ return tableName;
1335
+ }
1336
+ throw new Error(
1337
+ `schema option "${normalizedSchema}" conflicts with schema-qualified table "${tableName}"`
1338
+ );
1339
+ }
1340
+ return `${normalizedSchema}.${tableName}`;
1341
+ }
1273
1342
  function conditionToSqlClause(condition) {
1274
1343
  if (!condition.column) return null;
1275
1344
  const column = withCast(quoteQualifiedIdentifier(condition.column), condition.column_cast);
@@ -1349,23 +1418,27 @@ function buildTypedSelectQuery(input) {
1349
1418
  function createFilterMethods(state, addCondition, self) {
1350
1419
  return {
1351
1420
  eq(column, value) {
1352
- if (shouldUseUuidTextComparison(column, value)) {
1353
- addCondition("eq", column, value, { columnCast: "text" });
1421
+ const columnName = String(column);
1422
+ if (shouldUseUuidTextComparison(columnName, value)) {
1423
+ addCondition("eq", columnName, value, { columnCast: "text" });
1354
1424
  } else {
1355
- addCondition("eq", column, value);
1425
+ addCondition("eq", columnName, value);
1356
1426
  }
1357
1427
  return self;
1358
1428
  },
1359
1429
  eqCast(column, value, cast) {
1360
- addCondition("eq", column, value, { valueCast: cast });
1430
+ addCondition("eq", String(column), value, { valueCast: cast });
1361
1431
  return self;
1362
1432
  },
1363
1433
  eqUuid(column, value) {
1364
- addCondition("eq", column, value, { valueCast: "uuid" });
1434
+ addCondition("eq", String(column), value, { valueCast: "uuid" });
1365
1435
  return self;
1366
1436
  },
1367
1437
  match(filters) {
1368
1438
  Object.entries(filters).forEach(([column, value]) => {
1439
+ if (value === void 0) {
1440
+ return;
1441
+ }
1369
1442
  if (shouldUseUuidTextComparison(column, value)) {
1370
1443
  addCondition("eq", column, value, { columnCast: "text" });
1371
1444
  } else {
@@ -1401,60 +1474,61 @@ function createFilterMethods(state, addCondition, self) {
1401
1474
  },
1402
1475
  order(column, options) {
1403
1476
  state.order = {
1404
- field: column,
1477
+ field: String(column),
1405
1478
  direction: options?.ascending === false ? "descending" : "ascending"
1406
1479
  };
1407
1480
  return self;
1408
1481
  },
1409
1482
  gt(column, value) {
1410
- addCondition("gt", column, value);
1483
+ addCondition("gt", String(column), value);
1411
1484
  return self;
1412
1485
  },
1413
1486
  gte(column, value) {
1414
- addCondition("gte", column, value);
1487
+ addCondition("gte", String(column), value);
1415
1488
  return self;
1416
1489
  },
1417
1490
  lt(column, value) {
1418
- addCondition("lt", column, value);
1491
+ addCondition("lt", String(column), value);
1419
1492
  return self;
1420
1493
  },
1421
1494
  lte(column, value) {
1422
- addCondition("lte", column, value);
1495
+ addCondition("lte", String(column), value);
1423
1496
  return self;
1424
1497
  },
1425
1498
  neq(column, value) {
1426
- addCondition("neq", column, value);
1499
+ addCondition("neq", String(column), value);
1427
1500
  return self;
1428
1501
  },
1429
1502
  like(column, value) {
1430
- addCondition("like", column, value);
1503
+ addCondition("like", String(column), value);
1431
1504
  return self;
1432
1505
  },
1433
1506
  ilike(column, value) {
1434
- addCondition("ilike", column, value);
1507
+ addCondition("ilike", String(column), value);
1435
1508
  return self;
1436
1509
  },
1437
1510
  is(column, value) {
1438
- addCondition("is", column, value);
1511
+ addCondition("is", String(column), value);
1439
1512
  return self;
1440
1513
  },
1441
1514
  in(column, values) {
1442
- addCondition("in", column, values);
1515
+ addCondition("in", String(column), values);
1443
1516
  return self;
1444
1517
  },
1445
1518
  contains(column, values) {
1446
- addCondition("contains", column, values);
1519
+ addCondition("contains", String(column), values);
1447
1520
  return self;
1448
1521
  },
1449
1522
  containedBy(column, values) {
1450
- addCondition("containedBy", column, values);
1523
+ addCondition("containedBy", String(column), values);
1451
1524
  return self;
1452
1525
  },
1453
1526
  not(columnOrExpression, operator, value) {
1527
+ const expression = String(columnOrExpression);
1454
1528
  if (operator != null && value !== void 0) {
1455
- addCondition("not", void 0, `${columnOrExpression}.${operator}.${stringifyFilterValue(value)}`);
1529
+ addCondition("not", void 0, `${expression}.${operator}.${stringifyFilterValue(value)}`);
1456
1530
  } else {
1457
- addCondition("not", void 0, columnOrExpression);
1531
+ addCondition("not", void 0, expression);
1458
1532
  }
1459
1533
  return self;
1460
1534
  },
@@ -1624,15 +1698,20 @@ function createTableBuilder(tableName, client) {
1624
1698
  state.conditions.push(condition);
1625
1699
  };
1626
1700
  const builder = {};
1627
- const filterMethods = createFilterMethods(state, addCondition, builder);
1701
+ const filterMethods = createFilterMethods(
1702
+ state,
1703
+ addCondition,
1704
+ builder
1705
+ );
1628
1706
  const runSelect = async (columns = DEFAULT_COLUMNS, options) => {
1707
+ const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
1629
1708
  const conditions = state.conditions.length ? state.conditions.map((condition) => ({ ...condition })) : void 0;
1630
1709
  const hasTypedEqualityComparison = conditions?.some(
1631
1710
  (condition) => condition.operator === "eq" && (condition.value_cast !== void 0 || condition.column_cast !== void 0)
1632
1711
  ) ?? false;
1633
1712
  if (hasTypedEqualityComparison && !options?.head && !options?.count && conditions) {
1634
1713
  const query = buildTypedSelectQuery({
1635
- tableName,
1714
+ tableName: resolvedTableName,
1636
1715
  columns,
1637
1716
  conditions,
1638
1717
  limit: state.limit,
@@ -1647,7 +1726,7 @@ function createTableBuilder(tableName, client) {
1647
1726
  }
1648
1727
  }
1649
1728
  const payload = {
1650
- table_name: tableName,
1729
+ table_name: resolvedTableName,
1651
1730
  columns,
1652
1731
  conditions,
1653
1732
  limit: state.limit,
@@ -1704,9 +1783,10 @@ function createTableBuilder(tableName, client) {
1704
1783
  if (Array.isArray(values)) {
1705
1784
  const executeInsertMany = async (columns, selectOptions) => {
1706
1785
  const mergedOptions = mergeOptions(options, selectOptions);
1786
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1707
1787
  const payload = {
1708
- table_name: tableName,
1709
- insert_body: values
1788
+ table_name: resolvedTableName,
1789
+ insert_body: asAthenaJsonObjectArray(values)
1710
1790
  };
1711
1791
  if (columns) payload.columns = columns;
1712
1792
  if (mergedOptions?.count) payload.count = mergedOptions.count;
@@ -1721,9 +1801,10 @@ function createTableBuilder(tableName, client) {
1721
1801
  }
1722
1802
  const executeInsertOne = async (columns, selectOptions) => {
1723
1803
  const mergedOptions = mergeOptions(options, selectOptions);
1804
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1724
1805
  const payload = {
1725
- table_name: tableName,
1726
- insert_body: values
1806
+ table_name: resolvedTableName,
1807
+ insert_body: asAthenaJsonObject(values)
1727
1808
  };
1728
1809
  if (columns) payload.columns = columns;
1729
1810
  if (mergedOptions?.count) payload.count = mergedOptions.count;
@@ -1740,10 +1821,11 @@ function createTableBuilder(tableName, client) {
1740
1821
  if (Array.isArray(values)) {
1741
1822
  const executeUpsertMany = async (columns, selectOptions) => {
1742
1823
  const mergedOptions = mergeOptions(options, selectOptions);
1824
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1743
1825
  const payload = {
1744
- table_name: tableName,
1745
- insert_body: values,
1746
- update_body: options?.updateBody ? options.updateBody : void 0
1826
+ table_name: resolvedTableName,
1827
+ insert_body: asAthenaJsonObjectArray(values),
1828
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1747
1829
  };
1748
1830
  if (columns) payload.columns = columns;
1749
1831
  if (options?.onConflict) payload.on_conflict = options.onConflict;
@@ -1759,10 +1841,11 @@ function createTableBuilder(tableName, client) {
1759
1841
  }
1760
1842
  const executeUpsertOne = async (columns, selectOptions) => {
1761
1843
  const mergedOptions = mergeOptions(options, selectOptions);
1844
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1762
1845
  const payload = {
1763
- table_name: tableName,
1764
- insert_body: values,
1765
- update_body: options?.updateBody ? options.updateBody : void 0
1846
+ table_name: resolvedTableName,
1847
+ insert_body: asAthenaJsonObject(values),
1848
+ update_body: options?.updateBody ? asAthenaJsonObject(options.updateBody) : void 0
1766
1849
  };
1767
1850
  if (columns) payload.columns = columns;
1768
1851
  if (options?.onConflict) payload.on_conflict = options.onConflict;
@@ -1780,9 +1863,10 @@ function createTableBuilder(tableName, client) {
1780
1863
  const executeUpdate = async (columns, selectOptions) => {
1781
1864
  const filters = state.conditions.length ? [...state.conditions] : void 0;
1782
1865
  const mergedOptions = mergeOptions(options, selectOptions);
1866
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1783
1867
  const payload = {
1784
- table_name: tableName,
1785
- set: values,
1868
+ table_name: resolvedTableName,
1869
+ set: asAthenaJsonObject(values),
1786
1870
  conditions: filters,
1787
1871
  strip_nulls: mergedOptions?.stripNulls ?? true
1788
1872
  };
@@ -1808,8 +1892,9 @@ function createTableBuilder(tableName, client) {
1808
1892
  }
1809
1893
  const executeDelete = async (columns, selectOptions) => {
1810
1894
  const mergedOptions = mergeOptions(options, selectOptions);
1895
+ const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
1811
1896
  const payload = {
1812
- table_name: tableName,
1897
+ table_name: resolvedTableName,
1813
1898
  resource_id: resourceId,
1814
1899
  conditions: filters
1815
1900
  };
@@ -2109,8 +2194,21 @@ function coerceStringArray(value) {
2109
2194
  }
2110
2195
  return [];
2111
2196
  }
2197
+ function normalizePostgresCatalogSchemas(schemas) {
2198
+ const normalized = [];
2199
+ const seen = /* @__PURE__ */ new Set();
2200
+ for (const value of schemas ?? []) {
2201
+ const schema = value.trim();
2202
+ if (!schema || seen.has(schema)) {
2203
+ continue;
2204
+ }
2205
+ seen.add(schema);
2206
+ normalized.push(schema);
2207
+ }
2208
+ return normalized.length > 0 ? normalized : ["public"];
2209
+ }
2112
2210
  function buildSchemaArrayLiteral(schemas) {
2113
- const normalized = schemas.length > 0 ? schemas : ["public"];
2211
+ const normalized = normalizePostgresCatalogSchemas(schemas);
2114
2212
  const literals = normalized.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
2115
2213
  return `ARRAY[${literals}]`;
2116
2214
  }
@@ -2309,12 +2407,14 @@ var PostgresIntrospectionProvider = class {
2309
2407
  backend = "postgresql";
2310
2408
  connectionString;
2311
2409
  database;
2410
+ schemas;
2312
2411
  constructor(options) {
2313
2412
  this.connectionString = options.connectionString;
2314
2413
  this.database = options.database ?? "postgres";
2414
+ this.schemas = normalizePostgresCatalogSchemas(options.schemas);
2315
2415
  }
2316
2416
  async inspect(options) {
2317
- const schemas = options?.schemas && options.schemas.length > 0 ? options.schemas : ["public"];
2417
+ const schemas = options?.schemas && options.schemas.length > 0 ? normalizePostgresCatalogSchemas(options.schemas) : this.schemas;
2318
2418
  const pool = new Pool({
2319
2419
  connectionString: this.connectionString
2320
2420
  });
@@ -2386,11 +2486,13 @@ var AthenaGatewayPostgresIntrospectionProvider = class {
2386
2486
  type: this.config.backend ?? "postgresql"
2387
2487
  }
2388
2488
  });
2489
+ this.schemas = normalizeSchemaSelection(this.config.schemas);
2389
2490
  }
2390
2491
  backend = "postgresql";
2391
2492
  client;
2493
+ schemas;
2392
2494
  async inspect(options) {
2393
- const schemas = options?.schemas && options.schemas.length > 0 ? options.schemas : this.config.schemas && this.config.schemas.length > 0 ? this.config.schemas : ["public"];
2495
+ const schemas = options?.schemas && options.schemas.length > 0 ? normalizeSchemaSelection(options.schemas) : this.schemas;
2394
2496
  const catalogClient = new AthenaGatewayCatalogClient(this.client);
2395
2497
  const queries = buildGatewayCatalogQueries(schemas);
2396
2498
  const [columnRows, enumMap, primaryKeyRows, foreignKeyRows] = await Promise.all([
@@ -2426,7 +2528,8 @@ var ScyllaIntrospectionProvider = class {
2426
2528
  function createPostgresProvider(config) {
2427
2529
  return createPostgresIntrospectionProvider({
2428
2530
  connectionString: config.connectionString,
2429
- database: config.database
2531
+ database: config.database,
2532
+ schemas: normalizeSchemaSelection(config.schemas)
2430
2533
  });
2431
2534
  }
2432
2535
  function resolveGeneratorProvider(providerConfig, experimentalFlags) {
@@ -2448,12 +2551,6 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
2448
2551
  }
2449
2552
 
2450
2553
  // src/generator/pipeline.ts
2451
- function extractProviderSchemas(providerConfig) {
2452
- if (!("schemas" in providerConfig) || !providerConfig.schemas || providerConfig.schemas.length === 0) {
2453
- return void 0;
2454
- }
2455
- return providerConfig.schemas;
2456
- }
2457
2554
  async function writeArtifacts(files, cwd) {
2458
2555
  const writtenFiles = [];
2459
2556
  for (const file of files) {
@@ -2473,7 +2570,7 @@ async function runSchemaGenerator(options = {}) {
2473
2570
  const { configPath, config } = await loadGeneratorConfig(configOptions);
2474
2571
  const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
2475
2572
  const snapshot = await provider.inspect({
2476
- schemas: extractProviderSchemas(config.provider)
2573
+ schemas: resolveProviderSchemas(config.provider)
2477
2574
  });
2478
2575
  const generated = generateArtifactsFromSnapshot(snapshot, config);
2479
2576
  const writtenFiles = options.dryRun ? [] : await writeArtifacts(generated.files, cwd);