@xylex-group/athena 2.7.0 → 2.8.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.
Files changed (36) hide show
  1. package/README.md +210 -17
  2. package/dist/browser.cjs +1253 -401
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.cts +8 -7
  5. package/dist/browser.d.ts +8 -7
  6. package/dist/browser.js +1247 -402
  7. package/dist/browser.js.map +1 -1
  8. package/dist/cli/index.cjs +1285 -451
  9. package/dist/cli/index.cjs.map +1 -1
  10. package/dist/cli/index.d.cts +3 -3
  11. package/dist/cli/index.d.ts +3 -3
  12. package/dist/cli/index.js +1285 -451
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +1921 -698
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +8 -7
  17. package/dist/index.d.ts +8 -7
  18. package/dist/index.js +1915 -699
  19. package/dist/index.js.map +1 -1
  20. package/dist/{model-form-AKYrgede.d.ts → model-form-DMed05gE.d.cts} +347 -82
  21. package/dist/{model-form-ehfqLuG7.d.cts → model-form-DXPlOnlI.d.ts} +347 -82
  22. package/dist/{pipeline-BUsR9XlO.d.ts → pipeline-CkMnhwPI.d.ts} +1 -1
  23. package/dist/{pipeline-BfCWSRYl.d.cts → pipeline-D4sJRKqN.d.cts} +1 -1
  24. package/dist/{react-email-BQzmXBDE.d.cts → react-email-DZhDDlEl.d.cts} +121 -8
  25. package/dist/{react-email-BrVRp80B.d.ts → react-email-Lrz9A-BW.d.ts} +121 -8
  26. package/dist/react.cjs +1 -1
  27. package/dist/react.cjs.map +1 -1
  28. package/dist/react.d.cts +4 -4
  29. package/dist/react.d.ts +4 -4
  30. package/dist/react.js +1 -1
  31. package/dist/react.js.map +1 -1
  32. package/dist/{types-BSIsyss1.d.cts → types-BzY6fETM.d.ts} +47 -5
  33. package/dist/{types-t_TVqnmp.d.ts → types-CAtTGGoz.d.cts} +47 -5
  34. package/dist/{types-BsyRW49r.d.cts → types-vikz9YIO.d.cts} +23 -1
  35. package/dist/{types-BsyRW49r.d.ts → types-vikz9YIO.d.ts} +23 -1
  36. package/package.json +3 -2
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var zod = require('zod');
3
4
  var fs = require('fs');
4
5
  var path = require('path');
5
6
  var url = require('url');
@@ -805,7 +806,7 @@ var getCookieCache = async (request, config) => {
805
806
 
806
807
  // package.json
807
808
  var package_default = {
808
- version: "2.7.0"
809
+ version: "2.8.0"
809
810
  };
810
811
 
811
812
  // src/sdk-version.ts
@@ -3122,7 +3123,7 @@ function normalizeAthenaError(resultOrError, context) {
3122
3123
  const details = resultOrError.errorDetails;
3123
3124
  const message2 = messageFromUnknownError(resultOrError.error) ?? details?.message ?? `Athena ${context?.operation ?? operationFromDetails(details) ?? "request"} failed`;
3124
3125
  const operation = context?.operation ?? operationFromDetails(details);
3125
- const table = context?.table ?? extractTable(message2);
3126
+ const table2 = context?.table ?? extractTable(message2);
3126
3127
  const constraint = extractConstraint(message2);
3127
3128
  const gatewayCode = details?.code ?? gatewayCodeFromUnknownError(resultOrError.error);
3128
3129
  const kind2 = classifyKind(resultOrError.status, gatewayCode, message2);
@@ -3135,7 +3136,7 @@ function normalizeAthenaError(resultOrError, context) {
3135
3136
  retryable: isRetryable(kind2, resultOrError.status),
3136
3137
  status: resultOrError.status,
3137
3138
  constraint,
3138
- table,
3139
+ table: table2,
3139
3140
  operation,
3140
3141
  message: message2,
3141
3142
  raw: resultOrError.raw
@@ -3144,7 +3145,7 @@ function normalizeAthenaError(resultOrError, context) {
3144
3145
  if (isAthenaGatewayError(resultOrError)) {
3145
3146
  const details = resultOrError.toDetails();
3146
3147
  const operation = context?.operation ?? operationFromDetails(details);
3147
- const table = context?.table ?? extractTable(resultOrError.message);
3148
+ const table2 = context?.table ?? extractTable(resultOrError.message);
3148
3149
  const constraint = extractConstraint(resultOrError.message);
3149
3150
  const kind2 = classifyKind(resultOrError.status, resultOrError.code, resultOrError.message);
3150
3151
  const code = toAthenaErrorCode(kind2, resultOrError.status, resultOrError.code);
@@ -3156,7 +3157,7 @@ function normalizeAthenaError(resultOrError, context) {
3156
3157
  retryable: isRetryable(kind2, resultOrError.status),
3157
3158
  status: resultOrError.status,
3158
3159
  constraint,
3159
- table,
3160
+ table: table2,
3160
3161
  operation,
3161
3162
  message: resultOrError.message,
3162
3163
  raw: resultOrError
@@ -3352,23 +3353,24 @@ async function withRetry(config, fn) {
3352
3353
  // src/db/module.ts
3353
3354
  function createDbModule(input) {
3354
3355
  const db = {
3355
- from(table, options) {
3356
- return input.from(table, options);
3357
- },
3358
- select(table, columns, options) {
3359
- return input.from(table).select(columns, options);
3356
+ from: input.from,
3357
+ select(table2, first, second) {
3358
+ if (first && typeof first === "object" && !Array.isArray(first)) {
3359
+ return input.from(table2).select(void 0, first);
3360
+ }
3361
+ return input.from(table2).select(first, second);
3360
3362
  },
3361
- insert(table, values, options) {
3362
- return Array.isArray(values) ? input.from(table).insert(values, options) : input.from(table).insert(values, options);
3363
+ insert(table2, values, options) {
3364
+ return Array.isArray(values) ? input.from(table2).insert(values, options) : input.from(table2).insert(values, options);
3363
3365
  },
3364
- upsert(table, values, options) {
3365
- return Array.isArray(values) ? input.from(table).upsert(values, options) : input.from(table).upsert(values, options);
3366
+ upsert(table2, values, options) {
3367
+ return Array.isArray(values) ? input.from(table2).upsert(values, options) : input.from(table2).upsert(values, options);
3366
3368
  },
3367
- update(table, values, options) {
3368
- return input.from(table).update(values, options);
3369
+ update(table2, values, options) {
3370
+ return input.from(table2).update(values, options);
3369
3371
  },
3370
- delete(table, options) {
3371
- return input.from(table).delete(options);
3372
+ delete(table2, options) {
3373
+ return input.from(table2).delete(options);
3372
3374
  },
3373
3375
  rpc(fn, args, options) {
3374
3376
  return input.rpc(fn, args, options);
@@ -4037,6 +4039,15 @@ function appendQuery(path, query) {
4037
4039
  function storagePath(path) {
4038
4040
  return path;
4039
4041
  }
4042
+ function resolveStorageEndpointPath(endpoint, runtimeOptions) {
4043
+ if (!runtimeOptions?.stripBasePath) {
4044
+ return endpoint;
4045
+ }
4046
+ const [pathname, queryText] = String(endpoint).split("?", 2);
4047
+ const trimmedPathname = pathname.startsWith("/storage/") ? pathname.slice("/storage".length) : pathname === "/storage" ? "/" : pathname;
4048
+ const resolvedPath = trimmedPathname.startsWith("/") ? trimmedPathname : `/${trimmedPathname}`;
4049
+ return storagePath(queryText ? `${resolvedPath}?${queryText}` : resolvedPath);
4050
+ }
4040
4051
  function withPathParam(path, name, value) {
4041
4052
  return path.replace(`{${name}}`, encodeURIComponent(value));
4042
4053
  }
@@ -4075,8 +4086,8 @@ async function callStorageEndpoint(gateway, endpoint, method, envelope, payload,
4075
4086
  let url;
4076
4087
  let headers;
4077
4088
  try {
4078
- const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : gateway.baseUrl;
4079
- url = buildAthenaGatewayUrl(baseUrl, endpoint);
4089
+ const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : runtimeOptions?.baseUrl ? normalizeAthenaGatewayBaseUrl(runtimeOptions.baseUrl) : gateway.baseUrl;
4090
+ url = buildAthenaGatewayUrl(baseUrl, resolveStorageEndpointPath(endpoint, runtimeOptions));
4080
4091
  headers = gateway.buildHeaders(options);
4081
4092
  } catch (error) {
4082
4093
  return rejectStorageError(
@@ -4200,8 +4211,8 @@ async function callStorageBinaryEndpoint(gateway, endpoint, method, options, run
4200
4211
  let url;
4201
4212
  let headers;
4202
4213
  try {
4203
- const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : gateway.baseUrl;
4204
- url = buildAthenaGatewayUrl(baseUrl, endpoint);
4214
+ const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : runtimeOptions?.baseUrl ? normalizeAthenaGatewayBaseUrl(runtimeOptions.baseUrl) : gateway.baseUrl;
4215
+ url = buildAthenaGatewayUrl(baseUrl, resolveStorageEndpointPath(endpoint, runtimeOptions));
4205
4216
  headers = gateway.buildHeaders(options);
4206
4217
  } catch (error) {
4207
4218
  return rejectStorageError(
@@ -4362,8 +4373,8 @@ async function callStorageUploadBinaryEndpoint(gateway, endpoint, body, options,
4362
4373
  let url;
4363
4374
  let headers;
4364
4375
  try {
4365
- const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : gateway.baseUrl;
4366
- url = buildAthenaGatewayUrl(baseUrl, endpoint);
4376
+ const baseUrl = options?.baseUrl ? normalizeAthenaGatewayBaseUrl(options.baseUrl) : runtimeOptions?.baseUrl ? normalizeAthenaGatewayBaseUrl(runtimeOptions.baseUrl) : gateway.baseUrl;
4377
+ url = buildAthenaGatewayUrl(baseUrl, resolveStorageEndpointPath(endpoint, runtimeOptions));
4367
4378
  headers = gateway.buildHeaders(options);
4368
4379
  } catch (error) {
4369
4380
  return rejectStorageError(
@@ -4487,6 +4498,7 @@ async function callStorageUploadBinaryEndpoint(gateway, endpoint, body, options,
4487
4498
  return parsedBody.parsed.data;
4488
4499
  }
4489
4500
  function createStorageModule(gateway, runtimeOptions) {
4501
+ const resolvedRuntimeOptions = runtimeOptions;
4490
4502
  const callRaw = (path, method, payload, options) => callStorageEndpoint(
4491
4503
  gateway,
4492
4504
  storagePath(path),
@@ -4494,7 +4506,7 @@ function createStorageModule(gateway, runtimeOptions) {
4494
4506
  "raw",
4495
4507
  payload,
4496
4508
  options,
4497
- runtimeOptions
4509
+ resolvedRuntimeOptions
4498
4510
  );
4499
4511
  const callAthena2 = (path, method, payload, options) => callStorageEndpoint(
4500
4512
  gateway,
@@ -4503,7 +4515,7 @@ function createStorageModule(gateway, runtimeOptions) {
4503
4515
  "athena",
4504
4516
  payload,
4505
4517
  options,
4506
- runtimeOptions
4518
+ resolvedRuntimeOptions
4507
4519
  );
4508
4520
  const base = {
4509
4521
  listStorageCatalogs(options) {
@@ -4545,7 +4557,7 @@ function createStorageModule(gateway, runtimeOptions) {
4545
4557
  withPathParam("/storage/files/{file_id}/proxy", "file_id", fileId),
4546
4558
  query
4547
4559
  );
4548
- return callStorageBinaryEndpoint(gateway, storagePath(path), "GET", options, runtimeOptions);
4560
+ return callStorageBinaryEndpoint(gateway, storagePath(path), "GET", options, resolvedRuntimeOptions);
4549
4561
  },
4550
4562
  updateStorageFile(fileId, input, options) {
4551
4563
  return callAthena2(withPathParam("/storage/files/{file_id}", "file_id", fileId), "PATCH", input, options);
@@ -4592,7 +4604,7 @@ function createStorageModule(gateway, runtimeOptions) {
4592
4604
  storagePath(withPathParam("/storage/files/{file_id}/upload", "file_id", fileId)),
4593
4605
  body,
4594
4606
  options,
4595
- runtimeOptions
4607
+ resolvedRuntimeOptions
4596
4608
  );
4597
4609
  },
4598
4610
  search(input, options) {
@@ -4788,6 +4800,176 @@ function createStorageModule(gateway, runtimeOptions) {
4788
4800
  };
4789
4801
  }
4790
4802
 
4803
+ // src/client-builder.ts
4804
+ var DEFAULT_BACKEND = { type: "athena" };
4805
+ function toBackendConfig(value) {
4806
+ if (!value) return DEFAULT_BACKEND;
4807
+ return typeof value === "string" ? { type: value } : value;
4808
+ }
4809
+ function mergeHeaders(current, next) {
4810
+ return {
4811
+ ...current ?? {},
4812
+ ...next
4813
+ };
4814
+ }
4815
+ function mergeAuthClientConfig(current, next) {
4816
+ const merged = {
4817
+ ...current ?? {},
4818
+ ...next
4819
+ };
4820
+ if (current?.headers || next.headers) {
4821
+ merged.headers = mergeHeaders(current?.headers, next.headers ?? {});
4822
+ }
4823
+ return merged;
4824
+ }
4825
+ function mergeExperimentalOptions(current, next) {
4826
+ const merged = {
4827
+ ...current ?? {},
4828
+ ...next
4829
+ };
4830
+ if (current?.traceQueries && typeof current.traceQueries === "object" && next.traceQueries && typeof next.traceQueries === "object") {
4831
+ merged.traceQueries = {
4832
+ ...current.traceQueries,
4833
+ ...next.traceQueries
4834
+ };
4835
+ }
4836
+ if (current?.storage || next.storage) {
4837
+ merged.storage = {
4838
+ ...current?.storage ?? {},
4839
+ ...next.storage ?? {}
4840
+ };
4841
+ }
4842
+ return merged;
4843
+ }
4844
+ function resolveBuilderReturn(builder, storageEnabled, strictEnabled) {
4845
+ return builder;
4846
+ }
4847
+ var AthenaClientBuilderImpl = class {
4848
+ constructor(buildClient) {
4849
+ this.buildClient = buildClient;
4850
+ }
4851
+ rootUrl;
4852
+ apiKey;
4853
+ backendConfig = DEFAULT_BACKEND;
4854
+ clientName;
4855
+ defaultHeaders;
4856
+ authConfig;
4857
+ dbUrlOverride;
4858
+ gatewayUrlOverride;
4859
+ authUrlOverride;
4860
+ storageUrlOverride;
4861
+ experimentalOptions;
4862
+ url(url) {
4863
+ this.rootUrl = url;
4864
+ return this;
4865
+ }
4866
+ key(apiKey) {
4867
+ this.apiKey = apiKey;
4868
+ return this;
4869
+ }
4870
+ backend(backend) {
4871
+ this.backendConfig = toBackendConfig(backend);
4872
+ return this;
4873
+ }
4874
+ client(clientName) {
4875
+ this.clientName = clientName;
4876
+ return this;
4877
+ }
4878
+ headers(headers) {
4879
+ this.defaultHeaders = headers;
4880
+ return this;
4881
+ }
4882
+ auth(config) {
4883
+ this.authConfig = mergeAuthClientConfig(this.authConfig, config);
4884
+ return this;
4885
+ }
4886
+ experimental(options) {
4887
+ this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options);
4888
+ if (options.athenaStorageBackend && options.typecheckColumns) {
4889
+ return resolveBuilderReturn(this);
4890
+ }
4891
+ if (options.athenaStorageBackend) {
4892
+ return resolveBuilderReturn(this);
4893
+ }
4894
+ if (options.typecheckColumns) {
4895
+ return resolveBuilderReturn(this);
4896
+ }
4897
+ return this;
4898
+ }
4899
+ options(options) {
4900
+ if (options.client !== void 0) {
4901
+ this.clientName = options.client;
4902
+ }
4903
+ if (options.backend !== void 0) {
4904
+ this.backendConfig = toBackendConfig(options.backend);
4905
+ }
4906
+ if (options.headers !== void 0) {
4907
+ this.defaultHeaders = mergeHeaders(this.defaultHeaders, options.headers);
4908
+ }
4909
+ if (options.auth !== void 0) {
4910
+ this.authConfig = mergeAuthClientConfig(this.authConfig, options.auth);
4911
+ }
4912
+ if (options.db?.url !== void 0 && options.db.url !== null) {
4913
+ this.dbUrlOverride = options.db.url;
4914
+ }
4915
+ if (options.gateway?.url !== void 0 && options.gateway.url !== null) {
4916
+ this.gatewayUrlOverride = options.gateway.url;
4917
+ }
4918
+ if (options.dbUrl !== void 0 && options.dbUrl !== null) {
4919
+ this.dbUrlOverride = options.dbUrl;
4920
+ }
4921
+ if (options.gatewayUrl !== void 0 && options.gatewayUrl !== null) {
4922
+ this.gatewayUrlOverride = options.gatewayUrl;
4923
+ }
4924
+ if (options.authUrl !== void 0 && options.authUrl !== null) {
4925
+ this.authUrlOverride = options.authUrl;
4926
+ }
4927
+ if (options.storage?.url !== void 0 && options.storage.url !== null) {
4928
+ this.storageUrlOverride = options.storage.url;
4929
+ }
4930
+ if (options.storageUrl !== void 0 && options.storageUrl !== null) {
4931
+ this.storageUrlOverride = options.storageUrl;
4932
+ }
4933
+ if (options.experimental !== void 0) {
4934
+ this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options.experimental);
4935
+ }
4936
+ if (options.experimental?.athenaStorageBackend && options.experimental.typecheckColumns) {
4937
+ return resolveBuilderReturn(this);
4938
+ }
4939
+ if (options.experimental?.athenaStorageBackend) {
4940
+ return resolveBuilderReturn(this);
4941
+ }
4942
+ if (options.experimental?.typecheckColumns) {
4943
+ return resolveBuilderReturn(this);
4944
+ }
4945
+ return this;
4946
+ }
4947
+ build() {
4948
+ if (!this.rootUrl && !this.dbUrlOverride && !this.gatewayUrlOverride || !this.apiKey) {
4949
+ throw new Error(
4950
+ "AthenaClient requires key plus either .url() or a db/gateway override before .build()"
4951
+ );
4952
+ }
4953
+ return this.buildClient({
4954
+ url: this.rootUrl,
4955
+ key: this.apiKey,
4956
+ client: this.clientName,
4957
+ backend: this.backendConfig,
4958
+ headers: this.defaultHeaders,
4959
+ db: this.dbUrlOverride ? { url: this.dbUrlOverride } : void 0,
4960
+ gateway: this.gatewayUrlOverride ? { url: this.gatewayUrlOverride } : void 0,
4961
+ auth: this.authConfig,
4962
+ authUrl: this.authUrlOverride,
4963
+ storage: this.storageUrlOverride ? { url: this.storageUrlOverride } : void 0,
4964
+ storageUrl: this.storageUrlOverride,
4965
+ experimental: this.experimentalOptions
4966
+ });
4967
+ }
4968
+ };
4969
+ function createAthenaClientBuilder(buildClient) {
4970
+ return new AthenaClientBuilderImpl(buildClient);
4971
+ }
4972
+
4791
4973
  // src/query-ast.ts
4792
4974
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
4793
4975
  var FILTER_OPERATORS = /* @__PURE__ */ new Set([
@@ -5410,161 +5592,258 @@ function createSelectTransportPlan(input) {
5410
5592
  };
5411
5593
  }
5412
5594
 
5413
- // src/client.ts
5414
- var DEFAULT_COLUMNS = "*";
5415
- var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
5416
- var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
5417
- var QUERY_TRACE_STACK_SKIP_PATTERNS = [
5418
- "src\\client.ts",
5419
- "src/client.ts",
5420
- "dist\\client.",
5421
- "dist/client.",
5422
- "node_modules\\@xylex-group\\athena",
5423
- "node_modules/@xylex-group/athena",
5424
- "node:internal",
5425
- "internal/process"
5426
- ];
5427
- function formatResult(response) {
5428
- const result = {
5429
- data: response.data ?? null,
5430
- error: null,
5431
- errorDetails: response.errorDetails ?? null,
5432
- status: response.status,
5433
- statusText: response.statusText ?? null,
5434
- raw: response.raw
5595
+ // src/query-debug-ast.ts
5596
+ var ATHENA_DEBUG_AST_KEY = "__athenaDebugAst";
5597
+ function cloneConditions(conditions) {
5598
+ return conditions.map((condition) => ({ ...condition }));
5599
+ }
5600
+ function cloneTableBuilderStateAst(state) {
5601
+ return {
5602
+ conditions: cloneConditions(state.conditions),
5603
+ limit: state.limit,
5604
+ offset: state.offset,
5605
+ order: state.order ? { ...state.order } : void 0,
5606
+ currentPage: state.currentPage,
5607
+ pageSize: state.pageSize,
5608
+ totalPages: state.totalPages
5435
5609
  };
5436
- if (response.count !== void 0) {
5437
- result.count = response.count;
5610
+ }
5611
+ function cloneRpcBuilderStateAst(state) {
5612
+ return {
5613
+ filters: state.filters.map((filter) => ({ ...filter })),
5614
+ limit: state.limit,
5615
+ offset: state.offset,
5616
+ order: state.order ? { ...state.order } : void 0
5617
+ };
5618
+ }
5619
+ function toSelectTransportAst(plan) {
5620
+ if (plan.kind === "query") {
5621
+ return {
5622
+ mode: "typed-query",
5623
+ endpoint: "/gateway/query",
5624
+ payload: plan.payload
5625
+ };
5438
5626
  }
5439
- return result;
5627
+ return {
5628
+ mode: plan.payload.select !== void 0 ? "structured-fetch" : "compiled-fetch",
5629
+ endpoint: "/gateway/fetch",
5630
+ payload: plan.payload
5631
+ };
5440
5632
  }
5441
- var EXPERIMENTAL_READ_RETRY_CONFIG = {
5442
- retries: 2,
5443
- baseDelayMs: 100,
5444
- maxDelayMs: 1e3,
5445
- backoff: "exponential",
5446
- jitter: true
5447
- };
5448
- function attachNormalizedError(result, normalizedError) {
5449
- Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
5450
- value: normalizedError,
5451
- enumerable: false,
5452
- configurable: true,
5453
- writable: false
5454
- });
5633
+ function resolveDebugTableName(tableName) {
5634
+ return tableName ?? "__unknown_table__";
5455
5635
  }
5456
- function createResultFormatter(experimental) {
5457
- return (response, context) => {
5458
- const result = formatResult(response);
5459
- if (response.error == null && response.errorDetails == null) {
5460
- return result;
5636
+ function buildSelectDebugAst(input) {
5637
+ return {
5638
+ version: 1,
5639
+ kind: "select",
5640
+ tableName: input.tableName,
5641
+ input: {
5642
+ columns: input.columns,
5643
+ state: cloneTableBuilderStateAst(input.state)
5644
+ },
5645
+ transport: toSelectTransportAst(input.plan)
5646
+ };
5647
+ }
5648
+ function buildFindManyCompiledDebugAst(input) {
5649
+ return {
5650
+ version: 1,
5651
+ kind: "findMany",
5652
+ tableName: input.tableName,
5653
+ input: {
5654
+ select: input.options.select,
5655
+ where: input.options.where,
5656
+ orderBy: input.options.orderBy,
5657
+ limit: input.options.limit
5658
+ },
5659
+ compiled: {
5660
+ columns: input.compiledColumns,
5661
+ baseState: cloneTableBuilderStateAst(input.baseState),
5662
+ executionState: cloneTableBuilderStateAst(input.executionState)
5663
+ },
5664
+ transport: planToFindManyTransport(input.plan)
5665
+ };
5666
+ }
5667
+ function buildFindManyDirectDebugAst(input) {
5668
+ return {
5669
+ version: 1,
5670
+ kind: "findMany",
5671
+ tableName: input.tableName,
5672
+ input: {
5673
+ select: input.options.select,
5674
+ where: input.options.where,
5675
+ orderBy: input.options.orderBy,
5676
+ limit: input.options.limit
5677
+ },
5678
+ compiled: {
5679
+ columns: input.compiledColumns,
5680
+ baseState: cloneTableBuilderStateAst(input.baseState),
5681
+ executionState: cloneTableBuilderStateAst(input.executionState)
5682
+ },
5683
+ transport: {
5684
+ mode: "direct-ast-fetch",
5685
+ endpoint: "/gateway/fetch",
5686
+ payload: input.payload
5461
5687
  }
5462
- const normalizedError = normalizeAthenaError(
5463
- {
5464
- ...result,
5465
- error: response.error ?? response.errorDetails?.message ?? null
5466
- },
5467
- context
5468
- );
5469
- result.error = createResultError(response, result, normalizedError);
5470
- attachNormalizedError(result, normalizedError);
5471
- return result;
5472
5688
  };
5473
5689
  }
5474
- async function executeExperimentalRead(experimental, runner) {
5475
- if (!experimental?.retryReads) {
5476
- return runner();
5690
+ function planToFindManyTransport(plan) {
5691
+ if (plan.kind === "query") {
5692
+ return {
5693
+ mode: "compiled-query",
5694
+ endpoint: "/gateway/query",
5695
+ payload: plan.payload
5696
+ };
5477
5697
  }
5478
- let lastRetryableResult;
5479
- let lastRetrySignal = null;
5480
- try {
5481
- return await withRetry(
5482
- {
5483
- ...EXPERIMENTAL_READ_RETRY_CONFIG,
5484
- shouldRetry: (error) => error === lastRetrySignal || normalizeAthenaError(error).retryable
5485
- },
5486
- async () => {
5487
- const result = await runner();
5488
- if (result.error?.retryable) {
5489
- lastRetryableResult = result;
5490
- lastRetrySignal = result.error;
5491
- throw lastRetrySignal;
5492
- }
5493
- return result;
5494
- }
5495
- );
5496
- } catch (error) {
5497
- if (lastRetryableResult && error === lastRetrySignal) {
5498
- return lastRetryableResult;
5698
+ return {
5699
+ mode: plan.payload.select !== void 0 ? "structured-fetch" : "compiled-fetch",
5700
+ endpoint: "/gateway/fetch",
5701
+ payload: plan.payload
5702
+ };
5703
+ }
5704
+ function buildInsertDebugAst(payload) {
5705
+ return {
5706
+ version: 1,
5707
+ kind: "insert",
5708
+ tableName: payload.table_name,
5709
+ input: {
5710
+ values: payload.insert_body,
5711
+ returning: payload.columns,
5712
+ count: payload.count,
5713
+ head: payload.head,
5714
+ defaultToNull: payload.default_to_null
5715
+ },
5716
+ transport: {
5717
+ mode: "insert",
5718
+ endpoint: "/gateway/insert",
5719
+ payload
5499
5720
  }
5500
- throw error;
5501
- }
5721
+ };
5502
5722
  }
5503
- function isRecord9(value) {
5504
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5723
+ function buildUpsertDebugAst(payload) {
5724
+ return {
5725
+ version: 1,
5726
+ kind: "upsert",
5727
+ tableName: payload.table_name,
5728
+ input: {
5729
+ values: payload.insert_body,
5730
+ updateBody: payload.update_body,
5731
+ onConflict: payload.on_conflict,
5732
+ returning: payload.columns,
5733
+ count: payload.count,
5734
+ head: payload.head,
5735
+ defaultToNull: payload.default_to_null
5736
+ },
5737
+ transport: {
5738
+ mode: "upsert",
5739
+ endpoint: "/gateway/insert",
5740
+ payload
5741
+ }
5742
+ };
5505
5743
  }
5506
- function firstNonEmptyString2(...values) {
5507
- for (const value of values) {
5508
- if (typeof value === "string" && value.trim().length > 0) {
5509
- return value.trim();
5744
+ function buildUpdateDebugAst(input) {
5745
+ return {
5746
+ version: 1,
5747
+ kind: "update",
5748
+ tableName: resolveDebugTableName(input.payload.table_name),
5749
+ input: {
5750
+ values: input.payload.set,
5751
+ state: cloneTableBuilderStateAst(input.state),
5752
+ returning: input.payload.columns
5753
+ },
5754
+ transport: {
5755
+ mode: "update",
5756
+ endpoint: "/gateway/update",
5757
+ payload: input.payload
5510
5758
  }
5511
- }
5512
- return void 0;
5759
+ };
5513
5760
  }
5514
- function resolveStructuredErrorPayload2(raw) {
5515
- if (!isRecord9(raw)) return null;
5516
- return isRecord9(raw.error) ? raw.error : raw;
5761
+ function buildDeleteDebugAst(input) {
5762
+ return {
5763
+ version: 1,
5764
+ kind: "delete",
5765
+ tableName: input.payload.table_name,
5766
+ input: {
5767
+ resourceId: input.payload.resource_id,
5768
+ state: cloneTableBuilderStateAst(input.state),
5769
+ returning: input.payload.columns
5770
+ },
5771
+ transport: {
5772
+ mode: "delete",
5773
+ endpoint: "/gateway/delete",
5774
+ payload: input.payload
5775
+ }
5776
+ };
5517
5777
  }
5518
- function resolveStructuredErrorDetails(payload, message) {
5519
- if (!payload || !("details" in payload)) {
5520
- return null;
5778
+ function buildRpcDebugAst(input) {
5779
+ return {
5780
+ version: 1,
5781
+ kind: "rpc",
5782
+ functionName: input.functionName,
5783
+ input: {
5784
+ args: input.args,
5785
+ select: input.selectedColumns,
5786
+ state: cloneRpcBuilderStateAst(input.state)
5787
+ },
5788
+ transport: {
5789
+ mode: input.endpoint === "/gateway/rpc" ? "rpc-post" : "rpc-get",
5790
+ endpoint: input.endpoint,
5791
+ payload: input.payload
5792
+ }
5793
+ };
5794
+ }
5795
+ function buildRawQueryDebugAst(query) {
5796
+ return {
5797
+ version: 1,
5798
+ kind: "query",
5799
+ input: {
5800
+ query
5801
+ },
5802
+ transport: {
5803
+ mode: "raw-query",
5804
+ endpoint: "/gateway/query",
5805
+ payload: {
5806
+ query
5807
+ }
5808
+ }
5809
+ };
5810
+ }
5811
+ function attachAthenaDebugAst(target, ast) {
5812
+ if (!ast) {
5813
+ return;
5521
5814
  }
5522
- const details = payload.details;
5523
- if (details == null) {
5524
- return null;
5815
+ if (!target || typeof target !== "object" && typeof target !== "function") {
5816
+ return;
5525
5817
  }
5526
- if (typeof details === "string" && details.trim() === message.trim()) {
5818
+ Object.defineProperty(target, ATHENA_DEBUG_AST_KEY, {
5819
+ value: ast,
5820
+ enumerable: false,
5821
+ configurable: true,
5822
+ writable: false
5823
+ });
5824
+ }
5825
+ function getAthenaDebugAst(value) {
5826
+ if (!value || typeof value !== "object" && typeof value !== "function") {
5527
5827
  return null;
5528
5828
  }
5529
- return details;
5530
- }
5531
- function createResultError(response, result, normalized) {
5532
- const rawRecord = isRecord9(response.raw) ? response.raw : null;
5533
- const payload = resolveStructuredErrorPayload2(response.raw);
5534
- const message = firstNonEmptyString2(
5535
- response.error,
5536
- payload?.message,
5537
- payload?.error,
5538
- payload?.details,
5539
- response.errorDetails?.message,
5540
- normalized.message
5541
- ) ?? normalized.message;
5542
- const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
5543
- const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
5544
- const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
5545
- const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
5546
- return {
5547
- message,
5548
- code,
5549
- athenaCode: normalized.code,
5550
- gatewayCode: response.errorDetails?.code ?? null,
5551
- kind: normalized.kind,
5552
- category: normalized.category,
5553
- retryable: normalized.retryable,
5554
- details,
5555
- hint,
5556
- status: result.status,
5557
- statusText,
5558
- constraint: normalized.constraint,
5559
- table: normalized.table,
5560
- operation: normalized.operation,
5561
- endpoint: response.errorDetails?.endpoint,
5562
- method: response.errorDetails?.method,
5563
- requestId: response.errorDetails?.requestId,
5564
- cause: response.errorDetails?.cause,
5565
- raw: result.raw
5566
- };
5829
+ return value[ATHENA_DEBUG_AST_KEY] ?? null;
5567
5830
  }
5831
+
5832
+ // src/query-tracing.ts
5833
+ var QUERY_TRACE_STACK_SKIP_PATTERNS = [
5834
+ "src\\client.ts",
5835
+ "src/client.ts",
5836
+ "src\\query-tracing.ts",
5837
+ "src/query-tracing.ts",
5838
+ "dist\\client.",
5839
+ "dist/client.",
5840
+ "dist\\query-tracing.",
5841
+ "dist/query-tracing.",
5842
+ "node_modules\\@xylex-group\\athena",
5843
+ "node_modules/@xylex-group/athena",
5844
+ "node:internal",
5845
+ "internal/process"
5846
+ ];
5568
5847
  function parseQueryTraceCallsiteFrame(frame) {
5569
5848
  const trimmed = frame.trim();
5570
5849
  if (!trimmed) {
@@ -5669,6 +5948,7 @@ function createQueryTracer(experimental) {
5669
5948
  functionName: context.functionName,
5670
5949
  sql: context.sql,
5671
5950
  payload: context.payload,
5951
+ ast: context.ast,
5672
5952
  options: context.options,
5673
5953
  callsite,
5674
5954
  outcome: {
@@ -5691,6 +5971,7 @@ function createQueryTracer(experimental) {
5691
5971
  functionName: context.functionName,
5692
5972
  sql: context.sql,
5693
5973
  payload: context.payload,
5974
+ ast: context.ast,
5694
5975
  options: context.options,
5695
5976
  callsite,
5696
5977
  thrownError: error
@@ -5699,20 +5980,196 @@ function createQueryTracer(experimental) {
5699
5980
  };
5700
5981
  }
5701
5982
  async function executeWithQueryTrace(tracer, context, runner, callsiteOverride) {
5702
- if (!tracer) {
5703
- return runner();
5704
- }
5705
- const callsite = callsiteOverride ?? tracer.captureCallsite();
5706
- const startedAt = Date.now();
5983
+ const callsite = tracer ? callsiteOverride ?? tracer.captureCallsite() : null;
5984
+ const startedAt = tracer ? Date.now() : 0;
5707
5985
  try {
5708
5986
  const result = await runner();
5709
- tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
5987
+ attachAthenaDebugAst(result, context.ast);
5988
+ if (tracer) {
5989
+ tracer.publishSuccess(context, result, Date.now() - startedAt, callsite);
5990
+ }
5991
+ return result;
5992
+ } catch (error) {
5993
+ attachAthenaDebugAst(error, context.ast);
5994
+ if (tracer) {
5995
+ tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
5996
+ }
5997
+ throw error;
5998
+ }
5999
+ }
6000
+
6001
+ // src/schema/model-target.ts
6002
+ function normalizeOptionalName(value) {
6003
+ const normalized = value?.trim();
6004
+ return normalized ? normalized : void 0;
6005
+ }
6006
+ function isAthenaModelTarget(value) {
6007
+ if (!value || typeof value !== "object") {
6008
+ return false;
6009
+ }
6010
+ const candidate = value;
6011
+ return Boolean(candidate.meta && Array.isArray(candidate.meta.primaryKey));
6012
+ }
6013
+ function resolveAthenaModelTargetTableName(target, options = {}) {
6014
+ const explicitTableName = normalizeOptionalName(target.meta.tableName);
6015
+ if (explicitTableName) {
6016
+ return explicitTableName;
6017
+ }
6018
+ const schemaName = normalizeOptionalName(target.meta.schema ?? options.fallbackSchema);
6019
+ const modelName = normalizeOptionalName(target.meta.model ?? options.fallbackModel);
6020
+ if (!modelName) {
6021
+ throw new Error(
6022
+ "Athena model target is missing meta.model or meta.tableName. Provide one of those before calling from(model)."
6023
+ );
6024
+ }
6025
+ return schemaName ? `${schemaName}.${modelName}` : modelName;
6026
+ }
6027
+
6028
+ // src/client.ts
6029
+ var DEFAULT_COLUMNS = "*";
6030
+ var SAFE_CAST_PATTERN = /^[a-z_][a-z0-9_]*(?:\[\])?$/i;
6031
+ var ATHENA_NORMALIZED_ERROR_KEY = "__athenaNormalizedError";
6032
+ function formatResult(response) {
6033
+ const result = {
6034
+ data: response.data ?? null,
6035
+ error: null,
6036
+ errorDetails: response.errorDetails ?? null,
6037
+ status: response.status,
6038
+ statusText: response.statusText ?? null,
6039
+ raw: response.raw
6040
+ };
6041
+ if (response.count !== void 0) {
6042
+ result.count = response.count;
6043
+ }
6044
+ return result;
6045
+ }
6046
+ var EXPERIMENTAL_READ_RETRY_CONFIG = {
6047
+ retries: 2,
6048
+ baseDelayMs: 100,
6049
+ maxDelayMs: 1e3,
6050
+ backoff: "exponential",
6051
+ jitter: true
6052
+ };
6053
+ function attachNormalizedError(result, normalizedError) {
6054
+ Object.defineProperty(result, ATHENA_NORMALIZED_ERROR_KEY, {
6055
+ value: normalizedError,
6056
+ enumerable: false,
6057
+ configurable: true,
6058
+ writable: false
6059
+ });
6060
+ }
6061
+ function createResultFormatter(experimental) {
6062
+ return (response, context) => {
6063
+ const result = formatResult(response);
6064
+ if (response.error == null && response.errorDetails == null) {
6065
+ return result;
6066
+ }
6067
+ const normalizedError = normalizeAthenaError(
6068
+ {
6069
+ ...result,
6070
+ error: response.error ?? response.errorDetails?.message ?? null
6071
+ },
6072
+ context
6073
+ );
6074
+ result.error = createResultError(response, result, normalizedError);
6075
+ attachNormalizedError(result, normalizedError);
5710
6076
  return result;
6077
+ };
6078
+ }
6079
+ async function executeExperimentalRead(experimental, runner) {
6080
+ if (!experimental?.retryReads) {
6081
+ return runner();
6082
+ }
6083
+ let lastRetryableResult;
6084
+ let lastRetrySignal = null;
6085
+ try {
6086
+ return await withRetry(
6087
+ {
6088
+ ...EXPERIMENTAL_READ_RETRY_CONFIG,
6089
+ shouldRetry: (error) => error === lastRetrySignal || normalizeAthenaError(error).retryable
6090
+ },
6091
+ async () => {
6092
+ const result = await runner();
6093
+ if (result.error?.retryable) {
6094
+ lastRetryableResult = result;
6095
+ lastRetrySignal = result.error;
6096
+ throw lastRetrySignal;
6097
+ }
6098
+ return result;
6099
+ }
6100
+ );
5711
6101
  } catch (error) {
5712
- tracer.publishFailure(context, error, Date.now() - startedAt, callsite);
6102
+ if (lastRetryableResult && error === lastRetrySignal) {
6103
+ return lastRetryableResult;
6104
+ }
5713
6105
  throw error;
5714
6106
  }
5715
6107
  }
6108
+ function isRecord9(value) {
6109
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6110
+ }
6111
+ function firstNonEmptyString2(...values) {
6112
+ for (const value of values) {
6113
+ if (typeof value === "string" && value.trim().length > 0) {
6114
+ return value.trim();
6115
+ }
6116
+ }
6117
+ return void 0;
6118
+ }
6119
+ function resolveStructuredErrorPayload2(raw) {
6120
+ if (!isRecord9(raw)) return null;
6121
+ return isRecord9(raw.error) ? raw.error : raw;
6122
+ }
6123
+ function resolveStructuredErrorDetails(payload, message) {
6124
+ if (!payload || !("details" in payload)) {
6125
+ return null;
6126
+ }
6127
+ const details = payload.details;
6128
+ if (details == null) {
6129
+ return null;
6130
+ }
6131
+ if (typeof details === "string" && details.trim() === message.trim()) {
6132
+ return null;
6133
+ }
6134
+ return details;
6135
+ }
6136
+ function createResultError(response, result, normalized) {
6137
+ const rawRecord = isRecord9(response.raw) ? response.raw : null;
6138
+ const payload = resolveStructuredErrorPayload2(response.raw);
6139
+ const message = firstNonEmptyString2(
6140
+ response.error,
6141
+ payload?.message,
6142
+ payload?.error,
6143
+ payload?.details,
6144
+ response.errorDetails?.message,
6145
+ normalized.message
6146
+ ) ?? normalized.message;
6147
+ const statusText = firstNonEmptyString2(response.statusText, rawRecord?.statusText) ?? null;
6148
+ const hint = firstNonEmptyString2(payload?.hint, response.errorDetails?.hint) ?? null;
6149
+ const code = firstNonEmptyString2(payload?.code) ?? normalized.code;
6150
+ const details = resolveStructuredErrorDetails(payload, message) ?? response.errorDetails?.cause ?? null;
6151
+ return {
6152
+ message,
6153
+ code,
6154
+ athenaCode: normalized.code,
6155
+ gatewayCode: response.errorDetails?.code ?? null,
6156
+ kind: normalized.kind,
6157
+ category: normalized.category,
6158
+ retryable: normalized.retryable,
6159
+ details,
6160
+ hint,
6161
+ status: result.status,
6162
+ statusText,
6163
+ constraint: normalized.constraint,
6164
+ table: normalized.table,
6165
+ operation: normalized.operation,
6166
+ endpoint: response.errorDetails?.endpoint,
6167
+ method: response.errorDetails?.method,
6168
+ requestId: response.errorDetails?.requestId,
6169
+ cause: response.errorDetails?.cause,
6170
+ raw: result.raw
6171
+ };
6172
+ }
5716
6173
  function toSingleResult(response) {
5717
6174
  const payload = response.data;
5718
6175
  const singleData = Array.isArray(payload) ? payload.length ? payload[0] : null : payload ?? null;
@@ -5740,6 +6197,15 @@ function asAthenaJsonObject(value) {
5740
6197
  function asAthenaJsonObjectArray(values) {
5741
6198
  return values;
5742
6199
  }
6200
+ function normalizeSelectColumnsInput(columns) {
6201
+ if (columns === void 0) {
6202
+ return void 0;
6203
+ }
6204
+ if (typeof columns === "string") {
6205
+ return columns;
6206
+ }
6207
+ return [...columns];
6208
+ }
5743
6209
  function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer, initialCallsite) {
5744
6210
  let selectedColumns = defaultColumns === null ? void 0 : defaultColumns;
5745
6211
  let selectedOptions;
@@ -5749,25 +6215,29 @@ function createMutationQuery(executor, defaultColumns = DEFAULT_COLUMNS, tracer,
5749
6215
  const payloadColumns = columns ?? selectedColumns;
5750
6216
  const payloadOptions = options ?? selectedOptions;
5751
6217
  if (!promise) {
5752
- promise = executor(payloadColumns, payloadOptions, callsiteStore.resolve(callsite));
6218
+ promise = executor(
6219
+ normalizeSelectColumnsInput(payloadColumns),
6220
+ payloadOptions,
6221
+ callsiteStore.resolve(callsite)
6222
+ );
5753
6223
  }
5754
6224
  return promise;
5755
6225
  };
5756
6226
  const mutationQuery = {
5757
- select(columns = selectedColumns, options) {
6227
+ select(columns, options) {
5758
6228
  selectedColumns = columns;
5759
6229
  selectedOptions = options ?? selectedOptions;
5760
6230
  return run(columns, options, captureTraceCallsite(tracer));
5761
6231
  },
5762
- returning(columns = selectedColumns, options) {
6232
+ returning(columns, options) {
5763
6233
  return mutationQuery.select(columns, options);
5764
6234
  },
5765
- single(columns = selectedColumns, options) {
6235
+ single(columns, options) {
5766
6236
  selectedColumns = columns;
5767
6237
  selectedOptions = options ?? selectedOptions;
5768
6238
  return run(columns, options, captureTraceCallsite(tracer)).then(toSingleResult);
5769
6239
  },
5770
- maybeSingle(columns = selectedColumns, options) {
6240
+ maybeSingle(columns, options) {
5771
6241
  return mutationQuery.single(columns, options);
5772
6242
  },
5773
6243
  then(onfulfilled, onrejected) {
@@ -6324,7 +6794,10 @@ function createFilterMethods(state, addCondition, self) {
6324
6794
  }
6325
6795
  function toRpcSelect(columns) {
6326
6796
  if (!columns) return void 0;
6327
- return Array.isArray(columns) ? columns.join(",") : columns;
6797
+ if (typeof columns === "string") {
6798
+ return columns;
6799
+ }
6800
+ return columns.join(",");
6328
6801
  }
6329
6802
  function createRpcFilterMethods(filters, self) {
6330
6803
  const addFilter = (operator, column, value) => {
@@ -6373,7 +6846,7 @@ function createRpcFilterMethods(filters, self) {
6373
6846
  }
6374
6847
  };
6375
6848
  }
6376
- function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite) {
6849
+ function createRpcBuilder(functionName, args, baseOptions, client, formatGatewayResult, tracer, initialCallsite, debugAstEnabled = false) {
6377
6850
  const state = {
6378
6851
  filters: []
6379
6852
  };
@@ -6383,6 +6856,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6383
6856
  const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
6384
6857
  const executeRpc = async (columns, options, callsite) => {
6385
6858
  const mergedOptions = mergeOptions(baseOptions, options);
6859
+ const normalizedSelectedColumns = normalizeSelectColumnsInput(columns);
6386
6860
  const payload = {
6387
6861
  function: functionName,
6388
6862
  args,
@@ -6397,6 +6871,14 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6397
6871
  };
6398
6872
  const endpoint = mergedOptions?.get ? `/rpc/${functionName}` : "/gateway/rpc";
6399
6873
  const sql = buildRpcDebugSql(payload);
6874
+ const debugAst = debugAstEnabled ? buildRpcDebugAst({
6875
+ functionName,
6876
+ args,
6877
+ selectedColumns: normalizedSelectedColumns,
6878
+ state,
6879
+ payload,
6880
+ endpoint
6881
+ }) : void 0;
6400
6882
  return executeWithQueryTrace(
6401
6883
  tracer,
6402
6884
  {
@@ -6405,6 +6887,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6405
6887
  functionName,
6406
6888
  sql,
6407
6889
  payload,
6890
+ ast: debugAst,
6408
6891
  options: mergedOptions
6409
6892
  },
6410
6893
  async () => {
@@ -6425,7 +6908,7 @@ function createRpcBuilder(functionName, args, baseOptions, client, formatGateway
6425
6908
  const builder = {};
6426
6909
  const filterMethods = createRpcFilterMethods(state.filters, builder);
6427
6910
  Object.assign(builder, filterMethods, {
6428
- select(columns = selectedColumns, options) {
6911
+ select(columns, options) {
6429
6912
  selectedColumns = columns;
6430
6913
  selectedOptions = options ?? selectedOptions;
6431
6914
  return run(columns, options, captureTraceCallsite(tracer));
@@ -6470,6 +6953,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6470
6953
  const state = {
6471
6954
  conditions: []
6472
6955
  };
6956
+ const debugAstEnabled = Boolean(experimental?.debugAst);
6473
6957
  const addCondition = (operator, column, value, hints) => {
6474
6958
  const condition = { operator };
6475
6959
  if (column) {
@@ -6513,15 +6997,27 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6513
6997
  addCondition,
6514
6998
  builder
6515
6999
  );
6516
- const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite) => {
7000
+ const runSelect = async (columns = DEFAULT_COLUMNS, options, executionState = snapshotState(), callsite, debugAstFactory) => {
7001
+ const runtimeColumns = normalizeSelectColumnsInput(columns) ?? DEFAULT_COLUMNS;
6517
7002
  const resolvedTableName = resolveTableNameForCall(tableName, options?.schema);
6518
7003
  const plan = createSelectTransportPlan({
6519
7004
  tableName: resolvedTableName,
6520
- columns,
7005
+ columns: runtimeColumns,
6521
7006
  state: executionState,
6522
7007
  options,
6523
7008
  buildTypedSelectQuery
6524
7009
  });
7010
+ const debugAst = debugAstEnabled ? debugAstFactory?.({
7011
+ tableName: resolvedTableName,
7012
+ columns: runtimeColumns,
7013
+ executionState,
7014
+ plan
7015
+ }) ?? buildSelectDebugAst({
7016
+ tableName: resolvedTableName,
7017
+ columns: runtimeColumns,
7018
+ state: executionState,
7019
+ plan
7020
+ }) : void 0;
6525
7021
  if (plan.kind === "query") {
6526
7022
  return executeExperimentalRead(
6527
7023
  experimental,
@@ -6533,6 +7029,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6533
7029
  table: resolvedTableName,
6534
7030
  sql: plan.query,
6535
7031
  payload: plan.payload,
7032
+ ast: debugAst,
6536
7033
  options
6537
7034
  },
6538
7035
  async () => {
@@ -6557,6 +7054,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6557
7054
  table: resolvedTableName,
6558
7055
  sql,
6559
7056
  payload: plan.payload,
7057
+ ast: debugAst,
6560
7058
  options
6561
7059
  },
6562
7060
  async () => {
@@ -6570,7 +7068,11 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6570
7068
  const createSelectChain = (columns, options, initialCallsite) => {
6571
7069
  const chain = {};
6572
7070
  const callsiteStore = createTraceCallsiteStore(tracer, initialCallsite);
6573
- const filterMethods2 = createFilterMethods(state, addCondition, chain);
7071
+ const filterMethods2 = createFilterMethods(
7072
+ state,
7073
+ addCondition,
7074
+ chain
7075
+ );
6574
7076
  Object.assign(chain, filterMethods2, {
6575
7077
  async single(cols, opts) {
6576
7078
  const r = await runSelect(
@@ -6657,6 +7159,14 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6657
7159
  limit: executionState.limit,
6658
7160
  order: executionState.order
6659
7161
  });
7162
+ const debugAst = debugAstEnabled ? buildFindManyDirectDebugAst({
7163
+ tableName: resolvedTableName,
7164
+ options,
7165
+ compiledColumns: columns,
7166
+ baseState,
7167
+ executionState,
7168
+ payload
7169
+ }) : void 0;
6660
7170
  return executeExperimentalRead(
6661
7171
  experimental,
6662
7172
  () => executeWithQueryTrace(
@@ -6666,7 +7176,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6666
7176
  endpoint: "/gateway/fetch",
6667
7177
  table: resolvedTableName,
6668
7178
  sql,
6669
- payload
7179
+ payload,
7180
+ ast: debugAst
6670
7181
  },
6671
7182
  async () => {
6672
7183
  const response = await client.fetchGateway(
@@ -6682,8 +7193,16 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6682
7193
  columns,
6683
7194
  void 0,
6684
7195
  executionState,
6685
- callsite
6686
- );
7196
+ callsite,
7197
+ debugAstEnabled ? ({ tableName: resolvedTableName, executionState: tracedState, plan }) => buildFindManyCompiledDebugAst({
7198
+ tableName: resolvedTableName,
7199
+ options,
7200
+ compiledColumns: columns,
7201
+ baseState,
7202
+ executionState: tracedState,
7203
+ plan
7204
+ }) : void 0
7205
+ );
6687
7206
  },
6688
7207
  insert(values, options) {
6689
7208
  const mutationCallsite = captureTraceCallsite(tracer);
@@ -6702,6 +7221,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6702
7221
  payload.default_to_null = mergedOptions.defaultToNull;
6703
7222
  }
6704
7223
  const sql = buildInsertDebugSql(payload);
7224
+ const debugAst = debugAstEnabled ? buildInsertDebugAst(payload) : void 0;
6705
7225
  return executeWithQueryTrace(
6706
7226
  tracer,
6707
7227
  {
@@ -6710,6 +7230,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6710
7230
  table: resolvedTableName,
6711
7231
  sql,
6712
7232
  payload,
7233
+ ast: debugAst,
6713
7234
  options: mergedOptions
6714
7235
  },
6715
7236
  async () => {
@@ -6735,6 +7256,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6735
7256
  payload.default_to_null = mergedOptions.defaultToNull;
6736
7257
  }
6737
7258
  const sql = buildInsertDebugSql(payload);
7259
+ const debugAst = debugAstEnabled ? buildInsertDebugAst(payload) : void 0;
6738
7260
  return executeWithQueryTrace(
6739
7261
  tracer,
6740
7262
  {
@@ -6743,6 +7265,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6743
7265
  table: resolvedTableName,
6744
7266
  sql,
6745
7267
  payload,
7268
+ ast: debugAst,
6746
7269
  options: mergedOptions
6747
7270
  },
6748
7271
  async () => {
@@ -6773,6 +7296,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6773
7296
  payload.default_to_null = mergedOptions.defaultToNull;
6774
7297
  }
6775
7298
  const sql = buildInsertDebugSql(payload);
7299
+ const debugAst = debugAstEnabled ? buildUpsertDebugAst(payload) : void 0;
6776
7300
  return executeWithQueryTrace(
6777
7301
  tracer,
6778
7302
  {
@@ -6781,6 +7305,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6781
7305
  table: resolvedTableName,
6782
7306
  sql,
6783
7307
  payload,
7308
+ ast: debugAst,
6784
7309
  options: mergedOptions
6785
7310
  },
6786
7311
  async () => {
@@ -6808,6 +7333,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6808
7333
  payload.default_to_null = mergedOptions.defaultToNull;
6809
7334
  }
6810
7335
  const sql = buildInsertDebugSql(payload);
7336
+ const debugAst = debugAstEnabled ? buildUpsertDebugAst(payload) : void 0;
6811
7337
  return executeWithQueryTrace(
6812
7338
  tracer,
6813
7339
  {
@@ -6816,6 +7342,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6816
7342
  table: resolvedTableName,
6817
7343
  sql,
6818
7344
  payload,
7345
+ ast: debugAst,
6819
7346
  options: mergedOptions
6820
7347
  },
6821
7348
  async () => {
@@ -6830,7 +7357,8 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6830
7357
  update(values, options) {
6831
7358
  const mutationCallsite = captureTraceCallsite(tracer);
6832
7359
  const executeUpdate = async (columns, selectOptions, callsite) => {
6833
- const filters = state.conditions.length ? [...state.conditions] : void 0;
7360
+ const executionState = snapshotState();
7361
+ const filters = executionState.conditions.length ? [...executionState.conditions] : void 0;
6834
7362
  const mergedOptions = mergeOptions(options, selectOptions);
6835
7363
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
6836
7364
  const payload = {
@@ -6839,12 +7367,16 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6839
7367
  conditions: filters,
6840
7368
  strip_nulls: mergedOptions?.stripNulls ?? true
6841
7369
  };
6842
- if (state.order) payload.sort_by = state.order;
6843
- if (state.currentPage !== void 0) payload.current_page = state.currentPage;
6844
- if (state.pageSize !== void 0) payload.page_size = state.pageSize;
6845
- if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
7370
+ if (executionState.order) payload.sort_by = executionState.order;
7371
+ if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
7372
+ if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
7373
+ if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
6846
7374
  if (columns) payload.columns = columns;
6847
7375
  const sql = buildUpdateDebugSql(payload);
7376
+ const debugAst = debugAstEnabled ? buildUpdateDebugAst({
7377
+ state: executionState,
7378
+ payload
7379
+ }) : void 0;
6848
7380
  return executeWithQueryTrace(
6849
7381
  tracer,
6850
7382
  {
@@ -6853,6 +7385,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6853
7385
  table: resolvedTableName,
6854
7386
  sql,
6855
7387
  payload,
7388
+ ast: debugAst,
6856
7389
  options: mergedOptions
6857
7390
  },
6858
7391
  async () => {
@@ -6876,6 +7409,11 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6876
7409
  }
6877
7410
  const mutationCallsite = captureTraceCallsite(tracer);
6878
7411
  const executeDelete = async (columns, selectOptions, callsite) => {
7412
+ const executionState = snapshotState();
7413
+ const debugState = {
7414
+ ...executionState,
7415
+ conditions: filters ? filters.map((condition) => ({ ...condition })) : []
7416
+ };
6879
7417
  const mergedOptions = mergeOptions(options, selectOptions);
6880
7418
  const resolvedTableName = resolveTableNameForCall(tableName, mergedOptions?.schema);
6881
7419
  const payload = {
@@ -6883,12 +7421,16 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6883
7421
  resource_id: resourceId,
6884
7422
  conditions: filters
6885
7423
  };
6886
- if (state.order) payload.sort_by = state.order;
6887
- if (state.currentPage !== void 0) payload.current_page = state.currentPage;
6888
- if (state.pageSize !== void 0) payload.page_size = state.pageSize;
6889
- if (state.totalPages !== void 0) payload.total_pages = state.totalPages;
7424
+ if (executionState.order) payload.sort_by = executionState.order;
7425
+ if (executionState.currentPage !== void 0) payload.current_page = executionState.currentPage;
7426
+ if (executionState.pageSize !== void 0) payload.page_size = executionState.pageSize;
7427
+ if (executionState.totalPages !== void 0) payload.total_pages = executionState.totalPages;
6890
7428
  if (columns) payload.columns = columns;
6891
7429
  const sql = buildDeleteDebugSql(payload);
7430
+ const debugAst = debugAstEnabled ? buildDeleteDebugAst({
7431
+ state: debugState,
7432
+ payload
7433
+ }) : void 0;
6892
7434
  return executeWithQueryTrace(
6893
7435
  tracer,
6894
7436
  {
@@ -6897,6 +7439,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6897
7439
  table: resolvedTableName,
6898
7440
  sql,
6899
7441
  payload,
7442
+ ast: debugAst,
6900
7443
  options: mergedOptions
6901
7444
  },
6902
7445
  async () => {
@@ -6924,6 +7467,7 @@ function createTableBuilder(tableName, client, formatGatewayResult, tracer, expe
6924
7467
  return builder;
6925
7468
  }
6926
7469
  function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
7470
+ const debugAstEnabled = Boolean(experimental?.debugAst);
6927
7471
  return async function query(query, options) {
6928
7472
  const normalizedQuery = query.trim();
6929
7473
  if (!normalizedQuery) {
@@ -6940,6 +7484,7 @@ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
6940
7484
  endpoint: "/gateway/query",
6941
7485
  sql: normalizedQuery,
6942
7486
  payload,
7487
+ ast: debugAstEnabled ? buildRawQueryDebugAst(normalizedQuery) : void 0,
6943
7488
  options
6944
7489
  },
6945
7490
  async () => {
@@ -6951,6 +7496,63 @@ function createQueryBuilder(client, formatGatewayResult, experimental, tracer) {
6951
7496
  );
6952
7497
  };
6953
7498
  }
7499
+ function resolveClientServiceBaseUrl(value, label) {
7500
+ if (value === void 0 || value === null) {
7501
+ return void 0;
7502
+ }
7503
+ return normalizeAthenaGatewayBaseUrl(value, { label });
7504
+ }
7505
+ function appendServicePath(baseUrl, segment) {
7506
+ const normalizedBaseUrl = normalizeAthenaGatewayBaseUrl(baseUrl, { label: "Athena public base URL" });
7507
+ return `${normalizedBaseUrl}/${segment.replace(/^\/+/, "")}`;
7508
+ }
7509
+ function resolveServiceUrlOverride(value, label) {
7510
+ return resolveClientServiceBaseUrl(value, label);
7511
+ }
7512
+ function resolveServiceUrls(config) {
7513
+ const baseUrl = resolveClientServiceBaseUrl(config.url, "Athena public base URL");
7514
+ return {
7515
+ dbUrl: resolveServiceUrlOverride(config.db?.url, "Athena DB base URL") ?? resolveServiceUrlOverride(config.gateway?.url, "Athena gateway base URL") ?? resolveServiceUrlOverride(config.dbUrl, "Athena DB base URL") ?? resolveServiceUrlOverride(config.gatewayUrl, "Athena gateway base URL") ?? (baseUrl ? appendServicePath(baseUrl, "db") : void 0),
7516
+ authUrl: resolveServiceUrlOverride(config.auth?.url, "Athena auth base URL") ?? resolveServiceUrlOverride(config.auth?.baseUrl, "Athena auth base URL") ?? resolveServiceUrlOverride(config.authUrl, "Athena auth base URL") ?? (baseUrl ? appendServicePath(baseUrl, "auth") : void 0),
7517
+ storageUrl: resolveServiceUrlOverride(config.storage?.url, "Athena storage base URL") ?? resolveServiceUrlOverride(config.storageUrl, "Athena storage base URL") ?? (baseUrl ? appendServicePath(baseUrl, "storage") : void 0)
7518
+ };
7519
+ }
7520
+ function normalizeAuthClientConfig(auth, defaultBaseUrl) {
7521
+ if (!auth && defaultBaseUrl === void 0) {
7522
+ return void 0;
7523
+ }
7524
+ const { url, ...rest } = auth ?? {};
7525
+ const normalized = {
7526
+ ...rest
7527
+ };
7528
+ const resolvedBaseUrl = resolveClientServiceBaseUrl(
7529
+ url ?? rest.baseUrl ?? defaultBaseUrl,
7530
+ "Athena auth base URL"
7531
+ );
7532
+ if (resolvedBaseUrl !== void 0) {
7533
+ normalized.baseUrl = resolvedBaseUrl;
7534
+ }
7535
+ return normalized;
7536
+ }
7537
+ function resolveCreateClientConfig(config) {
7538
+ const resolvedUrls = resolveServiceUrls(config);
7539
+ if (!resolvedUrls.dbUrl) {
7540
+ throw new Error(
7541
+ "Athena DB base URL is required. Pass createClient(url, key) for a unified root, or set db.url / gateway.url / gatewayUrl explicitly."
7542
+ );
7543
+ }
7544
+ return {
7545
+ baseUrl: resolvedUrls.dbUrl,
7546
+ apiKey: config.key,
7547
+ client: config.client,
7548
+ backend: toBackendConfig(config.backend),
7549
+ headers: config.headers,
7550
+ auth: config.auth,
7551
+ authUrl: resolvedUrls.authUrl,
7552
+ storageUrl: resolvedUrls.storageUrl,
7553
+ experimental: config.experimental
7554
+ };
7555
+ }
6954
7556
  function createClientFromConfig(config) {
6955
7557
  const gatewayHeaders = {
6956
7558
  ...config.headers ?? {}
@@ -6967,14 +7569,31 @@ function createClientFromConfig(config) {
6967
7569
  });
6968
7570
  const formatGatewayResult = createResultFormatter(config.experimental);
6969
7571
  const queryTracer = createQueryTracer(config.experimental);
6970
- const auth = createAuthClient(config.auth);
6971
- const from = (table, options) => createTableBuilder(
6972
- resolveTableNameForCall(table, options?.schema),
6973
- gateway,
6974
- formatGatewayResult,
6975
- queryTracer,
6976
- config.experimental
6977
- );
7572
+ const auth = createAuthClient(normalizeAuthClientConfig(config.auth, config.authUrl));
7573
+ function from(tableOrModel, options) {
7574
+ if (isAthenaModelTarget(tableOrModel)) {
7575
+ if (options?.schema !== void 0) {
7576
+ throw new Error(
7577
+ "from(model) does not accept a schema override because the model already defines its target."
7578
+ );
7579
+ }
7580
+ return createTableBuilder(
7581
+ resolveAthenaModelTargetTableName(tableOrModel),
7582
+ gateway,
7583
+ formatGatewayResult,
7584
+ queryTracer,
7585
+ config.experimental
7586
+ );
7587
+ }
7588
+ const resolvedTableName = resolveTableNameForCall(tableOrModel, options?.schema);
7589
+ return createTableBuilder(
7590
+ resolvedTableName,
7591
+ gateway,
7592
+ formatGatewayResult,
7593
+ queryTracer,
7594
+ config.experimental
7595
+ );
7596
+ }
6978
7597
  const rpc = (fn, args, options) => {
6979
7598
  const normalizedFn = fn.trim();
6980
7599
  if (!normalizedFn) {
@@ -6987,10 +7606,16 @@ function createClientFromConfig(config) {
6987
7606
  gateway,
6988
7607
  formatGatewayResult,
6989
7608
  queryTracer,
6990
- captureTraceCallsite(queryTracer)
7609
+ captureTraceCallsite(queryTracer),
7610
+ Boolean(config.experimental?.debugAst)
6991
7611
  );
6992
7612
  };
6993
- const query = createQueryBuilder(gateway, formatGatewayResult, config.experimental, queryTracer);
7613
+ const query = createQueryBuilder(
7614
+ gateway,
7615
+ formatGatewayResult,
7616
+ config.experimental,
7617
+ queryTracer
7618
+ );
6994
7619
  const db = createDbModule({ from, rpc, query });
6995
7620
  const sdkClient = {
6996
7621
  from,
@@ -7003,148 +7628,53 @@ function createClientFromConfig(config) {
7003
7628
  if (config.experimental?.athenaStorageBackend) {
7004
7629
  const storageClient = {
7005
7630
  ...sdkClient,
7006
- storage: createStorageModule(gateway, config.experimental.storage)
7631
+ storage: createStorageModule(gateway, {
7632
+ ...config.experimental.storage,
7633
+ ...config.storageUrl ? {
7634
+ baseUrl: config.storageUrl,
7635
+ stripBasePath: true
7636
+ } : {}
7637
+ })
7007
7638
  };
7008
7639
  return storageClient;
7009
7640
  }
7010
7641
  return sdkClient;
7011
7642
  }
7012
- var DEFAULT_BACKEND = { type: "athena" };
7013
- function toBackendConfig(b) {
7014
- if (!b) return DEFAULT_BACKEND;
7015
- return typeof b === "string" ? { type: b } : b;
7016
- }
7017
- function mergeAuthClientConfig(current, next) {
7018
- const merged = {
7019
- ...current ?? {},
7020
- ...next
7021
- };
7022
- if (current?.headers || next.headers) {
7023
- merged.headers = {
7024
- ...current?.headers ?? {},
7025
- ...next.headers ?? {}
7026
- };
7027
- }
7028
- return merged;
7029
- }
7030
- function mergeExperimentalOptions(current, next) {
7031
- const merged = {
7032
- ...current ?? {},
7033
- ...next
7034
- };
7035
- if (current?.traceQueries && typeof current.traceQueries === "object" && next.traceQueries && typeof next.traceQueries === "object") {
7036
- merged.traceQueries = {
7037
- ...current.traceQueries,
7038
- ...next.traceQueries
7039
- };
7040
- }
7041
- if (current?.storage || next.storage) {
7042
- merged.storage = {
7043
- ...current?.storage ?? {},
7044
- ...next.storage ?? {}
7045
- };
7046
- }
7047
- return merged;
7048
- }
7049
- var AthenaClientBuilderImpl = class {
7050
- baseUrl;
7051
- apiKey;
7052
- backendConfig = DEFAULT_BACKEND;
7053
- clientName;
7054
- defaultHeaders;
7055
- authConfig;
7056
- experimentalOptions;
7057
- url(url) {
7058
- this.baseUrl = url;
7059
- return this;
7060
- }
7061
- key(apiKey) {
7062
- this.apiKey = apiKey;
7063
- return this;
7064
- }
7065
- backend(backend) {
7066
- this.backendConfig = toBackendConfig(backend);
7067
- return this;
7068
- }
7069
- client(clientName) {
7070
- this.clientName = clientName;
7071
- return this;
7072
- }
7073
- headers(headers) {
7074
- this.defaultHeaders = headers;
7075
- return this;
7076
- }
7077
- auth(config) {
7078
- this.authConfig = mergeAuthClientConfig(this.authConfig, config);
7079
- return this;
7080
- }
7081
- experimental(options) {
7082
- this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options);
7083
- return options.athenaStorageBackend ? this : this;
7084
- }
7085
- options(options) {
7086
- if (options.client !== void 0) {
7087
- this.clientName = options.client;
7088
- }
7089
- if (options.backend !== void 0) {
7090
- this.backendConfig = toBackendConfig(options.backend);
7091
- }
7092
- if (options.headers !== void 0) {
7093
- this.defaultHeaders = {
7094
- ...this.defaultHeaders ?? {},
7095
- ...options.headers
7096
- };
7097
- }
7098
- if (options.auth !== void 0) {
7099
- this.authConfig = mergeAuthClientConfig(this.authConfig, options.auth);
7100
- }
7101
- if (options.experimental !== void 0) {
7102
- this.experimentalOptions = mergeExperimentalOptions(this.experimentalOptions, options.experimental);
7103
- }
7104
- return options.experimental?.athenaStorageBackend ? this : this;
7105
- }
7106
- build() {
7107
- if (!this.baseUrl || !this.apiKey) {
7108
- throw new Error("AthenaClient requires url and key; call .url() and .key() before .build()");
7109
- }
7110
- return createClientFromConfig({
7111
- baseUrl: this.baseUrl,
7112
- apiKey: this.apiKey,
7113
- client: this.clientName,
7114
- backend: this.backendConfig,
7115
- headers: this.defaultHeaders,
7116
- auth: this.authConfig,
7117
- experimental: this.experimentalOptions
7118
- });
7119
- }
7120
- };
7121
- var AthenaClient = class _AthenaClient {
7643
+ var AthenaClient = class {
7122
7644
  /** Create a fluent builder for a strongly-typed Athena SDK client. */
7123
7645
  static builder() {
7124
- return new AthenaClientBuilderImpl();
7646
+ return createAthenaClientBuilder((config) => createClientFromConfig(resolveCreateClientConfig(config)));
7125
7647
  }
7126
7648
  /** Build a client from process environment variables. */
7127
7649
  static fromEnvironment() {
7128
- const url = process.env.ATHENA_URL ?? process.env.ATHENA_GATEWAY_URL;
7650
+ const url = process.env.ATHENA_URL;
7651
+ const gatewayUrl = process.env.ATHENA_DB_URL ?? process.env.ATHENA_GATEWAY_URL;
7652
+ const authUrl = process.env.ATHENA_AUTH_URL;
7653
+ const storageUrl = process.env.ATHENA_STORAGE_URL;
7129
7654
  const key = process.env.ATHENA_API_KEY ?? process.env.ATHENA_GATEWAY_API_KEY;
7130
- if (!url || !key) {
7655
+ if (!url && !gatewayUrl || !key) {
7131
7656
  throw new Error(
7132
- "ATHENA_URL and ATHENA_API_KEY (or ATHENA_GATEWAY_URL and ATHENA_GATEWAY_API_KEY) are required"
7657
+ "ATHENA_API_KEY plus ATHENA_URL or ATHENA_GATEWAY_URL (optionally ATHENA_DB_URL, ATHENA_AUTH_URL, ATHENA_STORAGE_URL) are required"
7133
7658
  );
7134
7659
  }
7135
- return _AthenaClient.builder().url(url).key(key).build();
7660
+ return createClient({
7661
+ url,
7662
+ gatewayUrl,
7663
+ authUrl,
7664
+ storageUrl,
7665
+ key
7666
+ });
7136
7667
  }
7137
7668
  };
7138
- function createClient(url, apiKey, options) {
7139
- return createClientFromConfig({
7140
- baseUrl: url,
7141
- apiKey,
7142
- client: options?.client,
7143
- backend: toBackendConfig(options?.backend),
7144
- headers: options?.headers,
7145
- auth: options?.auth,
7146
- experimental: options?.experimental
7147
- });
7669
+ function createClient(configOrUrl, apiKey, options) {
7670
+ if (typeof configOrUrl === "string") {
7671
+ return createClientFromConfig(resolveCreateClientConfig({
7672
+ url: configOrUrl,
7673
+ key: apiKey ?? "",
7674
+ ...options
7675
+ }));
7676
+ }
7677
+ return createClientFromConfig(resolveCreateClientConfig(configOrUrl));
7148
7678
  }
7149
7679
 
7150
7680
  // src/gateway/types.ts
@@ -7169,57 +7699,428 @@ function defineRegistry(databases) {
7169
7699
  return databases;
7170
7700
  }
7171
7701
 
7172
- // src/schema/typed-client.ts
7173
- var TenantHeaderMapper = class {
7174
- constructor(tenantKeyMap) {
7175
- this.tenantKeyMap = tenantKeyMap;
7702
+ // src/schema/model-form.ts
7703
+ function resolveNullishValue(mode) {
7704
+ if (mode === "undefined") return void 0;
7705
+ if (mode === "null") return null;
7706
+ return "";
7707
+ }
7708
+ function isRecord10(value) {
7709
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7710
+ }
7711
+ function isNullableColumn(model, key) {
7712
+ const nullable = model.meta.nullable;
7713
+ return nullable?.[key] === true;
7714
+ }
7715
+ function toModelFormDefaults(model, values, options) {
7716
+ const source = values;
7717
+ if (!isRecord10(source)) {
7718
+ return {};
7176
7719
  }
7177
- apply(baseHeaders, tenantContext) {
7178
- const headers = {
7179
- ...baseHeaders ?? {}
7180
- };
7181
- for (const [tenantKey, headerName] of Object.entries(this.tenantKeyMap)) {
7182
- const tenantValue = tenantContext[tenantKey];
7183
- if (tenantValue === void 0 || tenantValue === null) {
7184
- continue;
7185
- }
7186
- headers[headerName] = String(tenantValue);
7720
+ const mode = options?.nullishMode ?? "empty-string";
7721
+ const nullishValue = resolveNullishValue(mode);
7722
+ const result = {};
7723
+ for (const [key, value] of Object.entries(source)) {
7724
+ if (value === null && isNullableColumn(model, key)) {
7725
+ result[key] = nullishValue;
7726
+ continue;
7187
7727
  }
7188
- return Object.keys(headers).length > 0 ? headers : void 0;
7189
- }
7190
- };
7191
- var RegistryNavigator = class {
7192
- constructor(registry) {
7193
- this.registry = registry;
7728
+ result[key] = value;
7194
7729
  }
7195
- resolveModel(database, schema, model) {
7196
- const databaseDef = this.registry[database];
7197
- if (!databaseDef) {
7198
- throw new Error(`Unknown database "${database}"`);
7199
- }
7200
- const schemaDef = databaseDef.schemas[schema];
7201
- if (!schemaDef) {
7202
- throw new Error(`Unknown schema "${schema}" in database "${database}"`);
7730
+ return result;
7731
+ }
7732
+ function toModelPayload(model, formValues, options) {
7733
+ const emptyStringAsNull = options?.emptyStringAsNull ?? true;
7734
+ const stripUndefined = options?.stripUndefined ?? true;
7735
+ const result = {};
7736
+ for (const [key, rawValue] of Object.entries(formValues)) {
7737
+ if (rawValue === void 0 && stripUndefined) {
7738
+ continue;
7203
7739
  }
7204
- const modelDef = schemaDef.models[model];
7205
- if (!modelDef) {
7206
- throw new Error(`Unknown model "${model}" in schema "${schema}"`);
7740
+ if (emptyStringAsNull && rawValue === "" && isNullableColumn(model, key)) {
7741
+ result[key] = null;
7742
+ continue;
7207
7743
  }
7208
- return modelDef;
7744
+ result[key] = rawValue;
7209
7745
  }
7210
- resolveTableName(schema, model, modelDef) {
7211
- if (modelDef.meta.tableName) {
7212
- return modelDef.meta.tableName;
7746
+ return result;
7747
+ }
7748
+ function createModelFormAdapter(model) {
7749
+ return {
7750
+ model,
7751
+ toDefaults(values, options) {
7752
+ return toModelFormDefaults(model, values, options);
7753
+ },
7754
+ toInsert(values, options) {
7755
+ return toModelPayload(model, values, options);
7756
+ },
7757
+ toUpdate(values, options) {
7758
+ return toModelPayload(model, values, options);
7759
+ }
7760
+ };
7761
+ }
7762
+
7763
+ // src/schema/table-columns.ts
7764
+ var COLUMN_CONFIG = /* @__PURE__ */ Symbol("athena.column.config");
7765
+ function createColumnBuilder(config) {
7766
+ return {
7767
+ [COLUMN_CONFIG]: config,
7768
+ optional() {
7769
+ return createColumnBuilder({
7770
+ ...config,
7771
+ nullable: true
7772
+ });
7773
+ },
7774
+ from(columnName) {
7775
+ return createColumnBuilder({
7776
+ ...config,
7777
+ columnName
7778
+ });
7779
+ },
7780
+ defaulted() {
7781
+ return createColumnBuilder({
7782
+ ...config,
7783
+ hasDefault: true
7784
+ });
7785
+ },
7786
+ generated() {
7787
+ return createColumnBuilder({
7788
+ ...config,
7789
+ isGenerated: true
7790
+ });
7213
7791
  }
7214
- const schemaName = modelDef.meta.schema ?? schema;
7215
- const modelName = modelDef.meta.model ?? model;
7216
- return `${schemaName}.${modelName}`;
7792
+ };
7793
+ }
7794
+ function isColumnBuilder(value) {
7795
+ return value !== null && typeof value === "object" && COLUMN_CONFIG in value;
7796
+ }
7797
+ function getColumnConfig(column) {
7798
+ return column[COLUMN_CONFIG];
7799
+ }
7800
+ function string() {
7801
+ return createColumnBuilder({
7802
+ kind: "string",
7803
+ nullable: false,
7804
+ hasDefault: false,
7805
+ isGenerated: false
7806
+ });
7807
+ }
7808
+ function number() {
7809
+ return createColumnBuilder({
7810
+ kind: "number",
7811
+ nullable: false,
7812
+ hasDefault: false,
7813
+ isGenerated: false
7814
+ });
7815
+ }
7816
+ function boolean() {
7817
+ return createColumnBuilder({
7818
+ kind: "boolean",
7819
+ nullable: false,
7820
+ hasDefault: false,
7821
+ isGenerated: false
7822
+ });
7823
+ }
7824
+ function json(schema) {
7825
+ return createColumnBuilder({
7826
+ kind: "json",
7827
+ nullable: false,
7828
+ hasDefault: false,
7829
+ isGenerated: false,
7830
+ jsonSchema: schema
7831
+ });
7832
+ }
7833
+ function enumeration(values) {
7834
+ if (values.length === 0) {
7835
+ throw new Error("enumeration() requires at least one value");
7217
7836
  }
7218
- };
7219
- var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
7220
- registry;
7221
- tenantKeyMap;
7222
- tenantContext;
7837
+ return createColumnBuilder({
7838
+ kind: "enumeration",
7839
+ nullable: false,
7840
+ hasDefault: false,
7841
+ isGenerated: false,
7842
+ enumValues: values
7843
+ });
7844
+ }
7845
+
7846
+ // src/schema/table-schemas.ts
7847
+ function isScalarFormKind(kind) {
7848
+ return kind === "string" || kind === "number" || kind === "boolean" || kind === "enumeration";
7849
+ }
7850
+ function createBaseSchema(column) {
7851
+ const config = getColumnConfig(column);
7852
+ switch (config.kind) {
7853
+ case "boolean":
7854
+ return zod.z.boolean();
7855
+ case "number":
7856
+ return zod.z.number();
7857
+ case "json":
7858
+ return config.jsonSchema ?? zod.z.unknown();
7859
+ case "enumeration":
7860
+ if (!config.enumValues || config.enumValues.length === 0) {
7861
+ return zod.z.string();
7862
+ }
7863
+ return zod.z.enum(config.enumValues);
7864
+ case "string":
7865
+ default:
7866
+ return zod.z.string();
7867
+ }
7868
+ }
7869
+ function applyNullable(schema, column) {
7870
+ const config = getColumnConfig(column);
7871
+ return config.nullable ? schema.nullable() : schema;
7872
+ }
7873
+ function applyInsertOptional(schema, column) {
7874
+ const config = getColumnConfig(column);
7875
+ return config.nullable || config.hasDefault ? schema.optional() : schema;
7876
+ }
7877
+ function createFormFieldSchema(column) {
7878
+ const config = getColumnConfig(column);
7879
+ const base = createBaseSchema(column);
7880
+ let schema;
7881
+ if (config.nullable && isScalarFormKind(config.kind)) {
7882
+ schema = zod.z.union([base, zod.z.literal("")]).transform((value) => value === "" ? null : value);
7883
+ } else {
7884
+ schema = applyNullable(base, column);
7885
+ }
7886
+ if (config.nullable || config.hasDefault) {
7887
+ schema = schema.optional();
7888
+ }
7889
+ return schema;
7890
+ }
7891
+ function buildTableSchemaBundle(model, columns) {
7892
+ const rowShape = {};
7893
+ const insertShape = {};
7894
+ const updateShape = {};
7895
+ const formShape = {};
7896
+ for (const [columnName, column] of Object.entries(columns)) {
7897
+ const config = getColumnConfig(column);
7898
+ const base = createBaseSchema(column);
7899
+ rowShape[columnName] = applyNullable(base, column);
7900
+ if (config.isGenerated) {
7901
+ continue;
7902
+ }
7903
+ insertShape[columnName] = applyInsertOptional(applyNullable(base, column), column);
7904
+ updateShape[columnName] = applyNullable(base, column).optional();
7905
+ formShape[columnName] = createFormFieldSchema(column);
7906
+ }
7907
+ const rowSchema = zod.z.object(rowShape);
7908
+ const insertSchema = zod.z.object(insertShape);
7909
+ const updateSchema = zod.z.object(updateShape);
7910
+ const formSchema = zod.z.object(formShape).transform((value) => toModelPayload(model, value));
7911
+ return {
7912
+ row: rowSchema,
7913
+ insert: insertSchema,
7914
+ update: updateSchema,
7915
+ form: formSchema
7916
+ };
7917
+ }
7918
+
7919
+ // src/schema/table-builder.ts
7920
+ function assertColumnRecord(columns) {
7921
+ for (const [columnName, column] of Object.entries(columns)) {
7922
+ if (!isColumnBuilder(column)) {
7923
+ throw new Error(`Invalid column definition for "${columnName}"`);
7924
+ }
7925
+ }
7926
+ }
7927
+ function normalizeMappedNameInput(mappedName) {
7928
+ const normalized = mappedName.trim();
7929
+ if (!normalized) {
7930
+ throw new Error("table.from() requires a non-empty table name");
7931
+ }
7932
+ return normalized;
7933
+ }
7934
+ function normalizeSchemaNameInput(schemaName) {
7935
+ const normalized = schemaName.trim();
7936
+ if (!normalized) {
7937
+ throw new Error("table.schema() requires a non-empty schema name");
7938
+ }
7939
+ if (normalized.includes(".")) {
7940
+ throw new Error(
7941
+ 'table.schema() expects a schema name without dots. Use .schema("schema").from("table") or .from("schema.table").'
7942
+ );
7943
+ }
7944
+ return normalized;
7945
+ }
7946
+ function resolveTableTarget(logicalName, mappedName, explicitSchemaName) {
7947
+ const physicalName = (mappedName ?? logicalName).trim();
7948
+ if (!physicalName) {
7949
+ throw new Error("table() requires a non-empty name");
7950
+ }
7951
+ const firstDot = physicalName.indexOf(".");
7952
+ const lastDot = physicalName.lastIndexOf(".");
7953
+ if (firstDot > 0 && firstDot === lastDot) {
7954
+ const inlineSchema = physicalName.slice(0, firstDot).trim();
7955
+ const inlineModel = physicalName.slice(firstDot + 1).trim();
7956
+ if (!inlineSchema || !inlineModel) {
7957
+ throw new Error('table.from() schema-qualified names must look like "schema.table"');
7958
+ }
7959
+ if (explicitSchemaName && explicitSchemaName !== inlineSchema) {
7960
+ throw new Error(
7961
+ `table schema "${explicitSchemaName}" conflicts with mapped table "${physicalName}"`
7962
+ );
7963
+ }
7964
+ return {
7965
+ schema: explicitSchemaName ?? inlineSchema,
7966
+ model: inlineModel,
7967
+ qualifiedName: `${explicitSchemaName ?? inlineSchema}.${inlineModel}`
7968
+ };
7969
+ }
7970
+ if (explicitSchemaName) {
7971
+ return {
7972
+ schema: explicitSchemaName,
7973
+ model: physicalName,
7974
+ qualifiedName: `${explicitSchemaName}.${physicalName}`
7975
+ };
7976
+ }
7977
+ return {
7978
+ model: physicalName,
7979
+ qualifiedName: physicalName
7980
+ };
7981
+ }
7982
+ function toColumnMetadata(column) {
7983
+ const config = getColumnConfig(column);
7984
+ return {
7985
+ kind: config.kind,
7986
+ columnName: config.columnName,
7987
+ nullable: config.nullable,
7988
+ hasDefault: config.hasDefault,
7989
+ isGenerated: config.isGenerated,
7990
+ enumValues: config.enumValues
7991
+ };
7992
+ }
7993
+ function buildNullableMap(columns) {
7994
+ return Object.fromEntries(
7995
+ Object.entries(columns).map(([columnName, column]) => [columnName, getColumnConfig(column).nullable])
7996
+ );
7997
+ }
7998
+ function buildColumnMetadataMap(columns) {
7999
+ return Object.fromEntries(
8000
+ Object.entries(columns).map(([columnName, column]) => [columnName, toColumnMetadata(column)])
8001
+ );
8002
+ }
8003
+ function finalizeTable(name, mappedName, schemaName, columns, primaryKey) {
8004
+ const target = resolveTableTarget(name, mappedName, schemaName);
8005
+ const model = defineModel({
8006
+ meta: {
8007
+ schema: target.schema,
8008
+ model: target.model,
8009
+ primaryKey: [...primaryKey],
8010
+ nullable: buildNullableMap(columns),
8011
+ columns: buildColumnMetadataMap(columns)
8012
+ }
8013
+ });
8014
+ const schemas = buildTableSchemaBundle(model, columns);
8015
+ return Object.assign(model, {
8016
+ kind: "table",
8017
+ name,
8018
+ mappedName,
8019
+ schemaName: target.schema,
8020
+ tableName: target.model,
8021
+ qualifiedName: target.qualifiedName,
8022
+ columns,
8023
+ schemas
8024
+ });
8025
+ }
8026
+ function createColumnsBuilder(name, mappedName, schemaName, columns) {
8027
+ assertColumnRecord(columns);
8028
+ return {
8029
+ name,
8030
+ mappedName,
8031
+ schemaName,
8032
+ columns,
8033
+ from(tableName) {
8034
+ const normalizedTableName = normalizeMappedNameInput(tableName);
8035
+ resolveTableTarget(name, normalizedTableName, schemaName);
8036
+ return createColumnsBuilder(name, normalizedTableName, schemaName, columns);
8037
+ },
8038
+ schema(nextSchemaName) {
8039
+ const normalizedSchemaName = normalizeSchemaNameInput(nextSchemaName);
8040
+ resolveTableTarget(name, mappedName, normalizedSchemaName);
8041
+ return createColumnsBuilder(name, mappedName, normalizedSchemaName, columns);
8042
+ },
8043
+ primaryKey(...keys) {
8044
+ return finalizeTable(name, mappedName, schemaName, columns, keys);
8045
+ }
8046
+ };
8047
+ }
8048
+ function createTableBuilder2(name, mappedName, schemaName) {
8049
+ return {
8050
+ name,
8051
+ mappedName,
8052
+ schemaName,
8053
+ from(tableName) {
8054
+ const normalizedTableName = normalizeMappedNameInput(tableName);
8055
+ resolveTableTarget(name, normalizedTableName, schemaName);
8056
+ return createTableBuilder2(name, normalizedTableName, schemaName);
8057
+ },
8058
+ schema(nextSchemaName) {
8059
+ const normalizedSchemaName = normalizeSchemaNameInput(nextSchemaName);
8060
+ resolveTableTarget(name, mappedName, normalizedSchemaName);
8061
+ return createTableBuilder2(name, mappedName, normalizedSchemaName);
8062
+ },
8063
+ columns(columns) {
8064
+ return createColumnsBuilder(name, mappedName, schemaName, columns);
8065
+ }
8066
+ };
8067
+ }
8068
+ function table(name) {
8069
+ if (!name.trim()) {
8070
+ throw new Error("table() requires a non-empty name");
8071
+ }
8072
+ return createTableBuilder2(name, void 0, void 0);
8073
+ }
8074
+
8075
+ // src/schema/typed-client.ts
8076
+ var TenantHeaderMapper = class {
8077
+ constructor(tenantKeyMap) {
8078
+ this.tenantKeyMap = tenantKeyMap;
8079
+ }
8080
+ apply(baseHeaders, tenantContext) {
8081
+ const headers = {
8082
+ ...baseHeaders ?? {}
8083
+ };
8084
+ for (const [tenantKey, headerName] of Object.entries(this.tenantKeyMap)) {
8085
+ const tenantValue = tenantContext[tenantKey];
8086
+ if (tenantValue === void 0 || tenantValue === null) {
8087
+ continue;
8088
+ }
8089
+ headers[headerName] = String(tenantValue);
8090
+ }
8091
+ return Object.keys(headers).length > 0 ? headers : void 0;
8092
+ }
8093
+ };
8094
+ var RegistryNavigator = class {
8095
+ constructor(registry) {
8096
+ this.registry = registry;
8097
+ }
8098
+ resolveModel(database, schema, model) {
8099
+ const databaseDef = this.registry[database];
8100
+ if (!databaseDef) {
8101
+ throw new Error(`Unknown database "${database}"`);
8102
+ }
8103
+ const schemaDef = databaseDef.schemas[schema];
8104
+ if (!schemaDef) {
8105
+ throw new Error(`Unknown schema "${schema}" in database "${database}"`);
8106
+ }
8107
+ const modelDef = schemaDef.models[model];
8108
+ if (!modelDef) {
8109
+ throw new Error(`Unknown model "${model}" in schema "${schema}"`);
8110
+ }
8111
+ return modelDef;
8112
+ }
8113
+ resolveTableName(schema, model, modelDef) {
8114
+ return resolveAthenaModelTargetTableName(modelDef, {
8115
+ fallbackSchema: schema,
8116
+ fallbackModel: model
8117
+ });
8118
+ }
8119
+ };
8120
+ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
8121
+ registry;
8122
+ tenantKeyMap;
8123
+ tenantContext;
7223
8124
  db;
7224
8125
  baseClient;
7225
8126
  registryNavigator;
@@ -7240,17 +8141,20 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
7240
8141
  this.clientOptions = {
7241
8142
  backend: input.options?.backend,
7242
8143
  client: input.options?.client,
7243
- headers: input.options?.headers
8144
+ headers: input.options?.headers,
8145
+ experimental: input.options?.experimental
7244
8146
  };
7245
8147
  this.baseClient = createClient(this.url, this.apiKey, {
7246
8148
  backend: this.clientOptions.backend,
7247
8149
  client: this.clientOptions.client,
7248
- headers: this.tenantHeaderMapper.apply(this.clientOptions.headers, tenantContext)
8150
+ headers: this.tenantHeaderMapper.apply(this.clientOptions.headers, tenantContext),
8151
+ experimental: this.clientOptions.experimental
7249
8152
  });
7250
8153
  this.db = this.baseClient.db;
7251
8154
  }
7252
- from(table, options) {
7253
- return this.baseClient.from(table, options);
8155
+ from(tableOrModel, options) {
8156
+ const from = this.baseClient.from;
8157
+ return from(tableOrModel, options);
7254
8158
  }
7255
8159
  rpc(fn, args, options) {
7256
8160
  return this.baseClient.rpc(fn, args, options);
@@ -7272,7 +8176,8 @@ var TypedAthenaClientImpl = class _TypedAthenaClientImpl {
7272
8176
  tenantContext: {
7273
8177
  ...this.tenantContext,
7274
8178
  ...context ?? {}
7275
- }
8179
+ },
8180
+ experimental: this.clientOptions.experimental
7276
8181
  }
7277
8182
  });
7278
8183
  }
@@ -7378,8 +8283,8 @@ var POSTGRES_CATALOG_SQL = {
7378
8283
  ORDER BY sn.nspname, sc.relname, con.conname;
7379
8284
  `
7380
8285
  };
7381
- function tableKey(schema, table) {
7382
- return `${schema}.${table}`;
8286
+ function tableKey(schema, table2) {
8287
+ return `${schema}.${table2}`;
7383
8288
  }
7384
8289
  function relationKey(...parts) {
7385
8290
  const base = parts.join("_").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
@@ -7490,8 +8395,8 @@ var PostgresCatalogSnapshotAssembler = class {
7490
8395
  schemas = {};
7491
8396
  addColumnRows(columnRows, enumMap) {
7492
8397
  for (const row of columnRows) {
7493
- const table = this.ensureTable(row.schema_name, row.table_name);
7494
- table.columns[row.column_name] = {
8398
+ const table2 = this.ensureTable(row.schema_name, row.table_name);
8399
+ table2.columns[row.column_name] = {
7495
8400
  name: row.column_name,
7496
8401
  dataType: row.data_type,
7497
8402
  udtName: row.udt_name,
@@ -7507,12 +8412,12 @@ var PostgresCatalogSnapshotAssembler = class {
7507
8412
  }
7508
8413
  addPrimaryKeyRows(primaryKeyRows) {
7509
8414
  for (const row of primaryKeyRows) {
7510
- const table = this.ensureTable(row.schema_name, row.table_name);
8415
+ const table2 = this.ensureTable(row.schema_name, row.table_name);
7511
8416
  const primaryKeyColumns = coerceStringArray(row.columns);
7512
8417
  row.columns = primaryKeyColumns;
7513
- table.primaryKey = primaryKeyColumns;
8418
+ table2.primaryKey = primaryKeyColumns;
7514
8419
  for (const columnName of primaryKeyColumns) {
7515
- const column = table.columns[columnName];
8420
+ const column = table2.columns[columnName];
7516
8421
  if (column) {
7517
8422
  column.isPrimaryKey = true;
7518
8423
  }
@@ -7628,14 +8533,14 @@ var PostgresCatalogSnapshotAssembler = class {
7628
8533
  }
7629
8534
  return schema.tables[tableName];
7630
8535
  }
7631
- upsertRelation(table, baseKey, relation) {
8536
+ upsertRelation(table2, baseKey, relation) {
7632
8537
  let key = baseKey;
7633
8538
  let suffix = 2;
7634
- while (table.relations[key]) {
8539
+ while (table2.relations[key]) {
7635
8540
  key = `${baseKey}_${suffix}`;
7636
8541
  suffix += 1;
7637
8542
  }
7638
- table.relations[key] = relation;
8543
+ table2.relations[key] = relation;
7639
8544
  }
7640
8545
  };
7641
8546
 
@@ -7726,67 +8631,6 @@ function createPostgresIntrospectionProvider(options) {
7726
8631
  return new PostgresIntrospectionProvider(options);
7727
8632
  }
7728
8633
 
7729
- // src/schema/model-form.ts
7730
- function resolveNullishValue(mode) {
7731
- if (mode === "undefined") return void 0;
7732
- if (mode === "null") return null;
7733
- return "";
7734
- }
7735
- function isRecord10(value) {
7736
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7737
- }
7738
- function isNullableColumn(model, key) {
7739
- const nullable = model.meta.nullable;
7740
- return nullable?.[key] === true;
7741
- }
7742
- function toModelFormDefaults(model, values, options) {
7743
- const source = values;
7744
- if (!isRecord10(source)) {
7745
- return {};
7746
- }
7747
- const mode = options?.nullishMode ?? "empty-string";
7748
- const nullishValue = resolveNullishValue(mode);
7749
- const result = {};
7750
- for (const [key, value] of Object.entries(source)) {
7751
- if (value === null && isNullableColumn(model, key)) {
7752
- result[key] = nullishValue;
7753
- continue;
7754
- }
7755
- result[key] = value;
7756
- }
7757
- return result;
7758
- }
7759
- function toModelPayload(model, formValues, options) {
7760
- const emptyStringAsNull = options?.emptyStringAsNull ?? true;
7761
- const stripUndefined = options?.stripUndefined ?? true;
7762
- const result = {};
7763
- for (const [key, rawValue] of Object.entries(formValues)) {
7764
- if (rawValue === void 0 && stripUndefined) {
7765
- continue;
7766
- }
7767
- if (emptyStringAsNull && rawValue === "" && isNullableColumn(model, key)) {
7768
- result[key] = null;
7769
- continue;
7770
- }
7771
- result[key] = rawValue;
7772
- }
7773
- return result;
7774
- }
7775
- function createModelFormAdapter(model) {
7776
- return {
7777
- model,
7778
- toDefaults(values, options) {
7779
- return toModelFormDefaults(model, values, options);
7780
- },
7781
- toInsert(values, options) {
7782
- return toModelPayload(model, values, options);
7783
- },
7784
- toUpdate(values, options) {
7785
- return toModelPayload(model, values, options);
7786
- }
7787
- };
7788
- }
7789
-
7790
8634
  // src/generator/schema-selection.ts
7791
8635
  var DEFAULT_POSTGRES_SCHEMAS = ["public"];
7792
8636
  function collectSchemaNames(input) {
@@ -7832,6 +8676,7 @@ var DEFAULT_TARGETS = {
7832
8676
  database: "athena/relations.ts",
7833
8677
  registry: "athena/config.ts"
7834
8678
  };
8679
+ var DEFAULT_OUTPUT_FORMAT = "define-model";
7835
8680
  var DEFAULT_NAMING = {
7836
8681
  modelType: "pascal",
7837
8682
  modelConst: "camel",
@@ -7847,6 +8692,9 @@ var DEFAULT_EXPERIMENTAL_FLAGS = {
7847
8692
  postgresGatewayIntrospection: false,
7848
8693
  scyllaProviderContracts: true
7849
8694
  };
8695
+ var DEFAULT_INTERNAL_CONFIG = {
8696
+ schemaVersion: 1
8697
+ };
7850
8698
  var PROJECT_ENV_FILENAMES = [".env", ".env.local"];
7851
8699
  var DIRECT_CONNECTION_STRING_ENV_KEYS = [
7852
8700
  "ATHENA_GENERATOR_PG_URL",
@@ -7863,6 +8711,27 @@ var GATEWAY_API_KEY_ENV_KEYS = [
7863
8711
  "ATHENA_GATEWAY_API_KEY",
7864
8712
  "ATHENA_GENERATOR_API_KEY"
7865
8713
  ];
8714
+ var GENERATOR_SCHEMA_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMAS"];
8715
+ var OUTPUT_FORMAT_ENV_KEYS = ["ATHENA_GENERATOR_OUTPUT_FORMAT"];
8716
+ var MODEL_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_TARGET"];
8717
+ var SCHEMA_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMA_TARGET"];
8718
+ var DATABASE_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_DATABASE_TARGET"];
8719
+ var REGISTRY_TARGET_ENV_KEYS = ["ATHENA_GENERATOR_REGISTRY_TARGET"];
8720
+ var PLACEHOLDER_MAP_ENV_KEYS = ["ATHENA_GENERATOR_PLACEHOLDER_MAP"];
8721
+ var MODEL_TYPE_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_TYPE", "ATHENA_GENERATOR_MODEL_STYLE"];
8722
+ var MODEL_CONST_ENV_KEYS = ["ATHENA_GENERATOR_MODEL_CONST"];
8723
+ var SCHEMA_CONST_ENV_KEYS = ["ATHENA_GENERATOR_SCHEMA_CONST"];
8724
+ var DATABASE_CONST_ENV_KEYS = ["ATHENA_GENERATOR_DATABASE_CONST"];
8725
+ var REGISTRY_CONST_ENV_KEYS = ["ATHENA_GENERATOR_REGISTRY_CONST"];
8726
+ var EMIT_RELATIONS_ENV_KEYS = ["ATHENA_GENERATOR_EMIT_RELATIONS"];
8727
+ var EMIT_REGISTRY_ENV_KEYS = ["ATHENA_GENERATOR_EMIT_REGISTRY"];
8728
+ var GATEWAY_BACKEND_ENV_KEYS = ["ATHENA_GENERATOR_BACKEND"];
8729
+ var GATEWAY_EXPERIMENTAL_ENV_KEYS = ["ATHENA_GENERATOR_GATEWAY_EXPERIMENTAL"];
8730
+ var SCYLLA_PROVIDER_CONTRACTS_ENV_KEYS = ["ATHENA_GENERATOR_SCYLLA_PROVIDER_CONTRACTS"];
8731
+ var ENV_ONLY_CONFIG_PATH = "[environment defaults]";
8732
+ var NAMING_STYLE_VALUES = ["preserve", "camel", "pascal", "snake", "kebab"];
8733
+ var OUTPUT_FORMAT_VALUES = ["define-model", "table-builder"];
8734
+ var BACKEND_TYPE_VALUES = ["athena", "postgrest", "postgresql", "scylladb"];
7866
8735
  function normalizeRawEnvValue(rawValue) {
7867
8736
  if (rawValue.startsWith('"') && rawValue.endsWith('"') && rawValue.length >= 2) {
7868
8737
  const inner = rawValue.slice(1, -1);
@@ -7954,6 +8823,50 @@ function resolveFallbackValue(fallbackKeys) {
7954
8823
  }
7955
8824
  return void 0;
7956
8825
  }
8826
+ function normalizeOneOfValue(rawValue, allowedValues, envKeys) {
8827
+ if (!rawValue) {
8828
+ return void 0;
8829
+ }
8830
+ if (allowedValues.includes(rawValue)) {
8831
+ return rawValue;
8832
+ }
8833
+ throw new Error(
8834
+ `Generator config env vars ${envKeys.join(", ")} must resolve to one of: ${allowedValues.join(", ")}. Received: ${rawValue}.`
8835
+ );
8836
+ }
8837
+ function resolveOptionalOneOf(envKeys, allowedValues) {
8838
+ return normalizeOneOfValue(resolveFallbackValue(envKeys), allowedValues, envKeys);
8839
+ }
8840
+ function resolveOptionalBoolean(envKeys) {
8841
+ const rawValue = resolveFallbackValue(envKeys);
8842
+ return rawValue === void 0 ? void 0 : parseBooleanFlag2(rawValue, false);
8843
+ }
8844
+ function resolveOptionalJson(envKeys) {
8845
+ const rawValue = resolveFallbackValue(envKeys);
8846
+ if (rawValue === void 0) {
8847
+ return void 0;
8848
+ }
8849
+ try {
8850
+ return JSON.parse(rawValue);
8851
+ } catch (error) {
8852
+ const message = error instanceof Error ? error.message : String(error);
8853
+ throw new Error(
8854
+ `Generator config env vars ${envKeys.join(", ")} must contain valid JSON. ${message}`
8855
+ );
8856
+ }
8857
+ }
8858
+ function deriveDatabaseNameFromConnectionString(connectionString) {
8859
+ try {
8860
+ const parsedUrl = new URL(connectionString);
8861
+ if (!POSTGRES_PROTOCOLS.has(parsedUrl.protocol)) {
8862
+ return void 0;
8863
+ }
8864
+ const pathname = parsedUrl.pathname.replace(/^\/+/, "").trim();
8865
+ return pathname.length > 0 ? decodeURIComponent(pathname) : void 0;
8866
+ } catch {
8867
+ return void 0;
8868
+ }
8869
+ }
7957
8870
  function normalizeOptionalString(value, fallbackKeys) {
7958
8871
  if (typeof value === "string") {
7959
8872
  const trimmed = value.trim();
@@ -8027,12 +8940,13 @@ function normalizeExperimentalFlags(input) {
8027
8940
  }
8028
8941
  function normalizeOutputConfig(output) {
8029
8942
  return {
8943
+ format: output?.format ?? DEFAULT_OUTPUT_FORMAT,
8030
8944
  targets: {
8031
8945
  ...DEFAULT_TARGETS,
8032
- ...output.targets ?? {}
8946
+ ...output?.targets ?? {}
8033
8947
  },
8034
8948
  placeholderMap: {
8035
- ...output.placeholderMap ?? {}
8949
+ ...output?.placeholderMap ?? {}
8036
8950
  }
8037
8951
  };
8038
8952
  }
@@ -8043,7 +8957,7 @@ function normalizeProviderConfig(provider) {
8043
8957
  "provider.connectionString",
8044
8958
  DIRECT_CONNECTION_STRING_ENV_KEYS
8045
8959
  );
8046
- const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS);
8960
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS) ?? deriveDatabaseNameFromConnectionString(connectionString);
8047
8961
  return {
8048
8962
  ...provider,
8049
8963
  connectionString: applyPostgresPasswordFallback(connectionString),
@@ -8062,11 +8976,7 @@ function normalizeProviderConfig(provider) {
8062
8976
  "provider.apiKey",
8063
8977
  GATEWAY_API_KEY_ENV_KEYS
8064
8978
  );
8065
- const database = normalizeRequiredString(
8066
- provider.database,
8067
- "provider.database",
8068
- POSTGRES_DATABASE_ENV_KEYS
8069
- );
8979
+ const database = normalizeOptionalString(provider.database, POSTGRES_DATABASE_ENV_KEYS) ?? "postgres";
8070
8980
  return {
8071
8981
  ...provider,
8072
8982
  gatewayUrl,
@@ -8075,6 +8985,26 @@ function normalizeProviderConfig(provider) {
8075
8985
  schemas: normalizeSchemaSelection(provider.schemas)
8076
8986
  };
8077
8987
  }
8988
+ if (provider.kind === "scylla" && provider.mode === "direct") {
8989
+ if (!provider.contactPoints?.length) {
8990
+ throw new Error(
8991
+ "Generator config is missing provider.contactPoints for scylla direct mode."
8992
+ );
8993
+ }
8994
+ const keyspace = normalizeOptionalString(provider.keyspace, []);
8995
+ if (!keyspace) {
8996
+ throw new Error(
8997
+ "Generator config is missing provider.keyspace for scylla direct mode."
8998
+ );
8999
+ }
9000
+ return {
9001
+ kind: "scylla",
9002
+ mode: "direct",
9003
+ contactPoints: provider.contactPoints.slice(),
9004
+ keyspace,
9005
+ datacenter: normalizeOptionalString(provider.datacenter, [])
9006
+ };
9007
+ }
8078
9008
  return provider;
8079
9009
  }
8080
9010
  function isAthenaGeneratorConfig(value) {
@@ -8082,7 +9012,7 @@ function isAthenaGeneratorConfig(value) {
8082
9012
  return false;
8083
9013
  }
8084
9014
  const record = value;
8085
- return Boolean(record.provider && typeof record.provider === "object") && Boolean(record.output && typeof record.output === "object");
9015
+ return Boolean(record.provider && typeof record.provider === "object") && (record.output === void 0 || typeof record.output === "object");
8086
9016
  }
8087
9017
  function normalizeGeneratorConfig(input) {
8088
9018
  return {
@@ -8093,7 +9023,10 @@ function normalizeGeneratorConfig(input) {
8093
9023
  ...input.naming ?? {}
8094
9024
  },
8095
9025
  features: normalizeFeatureFlags(input.features),
8096
- experimental: normalizeExperimentalFlags(input.experimental)
9026
+ experimental: normalizeExperimentalFlags(input.experimental),
9027
+ internal: {
9028
+ ...DEFAULT_INTERNAL_CONFIG
9029
+ }
8097
9030
  };
8098
9031
  }
8099
9032
  function defineGeneratorConfig(config) {
@@ -8150,44 +9083,151 @@ function importConfigModule(moduleSpecifier) {
8150
9083
  );
8151
9084
  return runtimeImport(moduleSpecifier);
8152
9085
  }
8153
- async function loadGeneratorConfig(options = {}) {
8154
- const cwd = options.cwd ?? process.cwd();
8155
- const restoreProjectEnv = applyProjectEnv(cwd);
8156
- const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
8157
- if (!resolvedPath) {
8158
- throw new Error(
8159
- `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}`
8160
- );
8161
- }
8162
- try {
8163
- const moduleUrl = url.pathToFileURL(resolvedPath);
8164
- const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
8165
- const rawConfig = extractConfigExport(module);
8166
- return {
8167
- configPath: resolvedPath,
8168
- config: normalizeGeneratorConfig(rawConfig)
8169
- };
8170
- } finally {
8171
- restoreProjectEnv();
9086
+ function buildEnvironmentOutputConfig() {
9087
+ const format = resolveOptionalOneOf(OUTPUT_FORMAT_ENV_KEYS, OUTPUT_FORMAT_VALUES);
9088
+ const modelTarget = resolveFallbackValue(MODEL_TARGET_ENV_KEYS);
9089
+ const schemaTarget = resolveFallbackValue(SCHEMA_TARGET_ENV_KEYS);
9090
+ const databaseTarget = resolveFallbackValue(DATABASE_TARGET_ENV_KEYS);
9091
+ const registryTarget = resolveFallbackValue(REGISTRY_TARGET_ENV_KEYS);
9092
+ const placeholderMap = resolveOptionalJson(PLACEHOLDER_MAP_ENV_KEYS);
9093
+ if (format === void 0 && modelTarget === void 0 && schemaTarget === void 0 && databaseTarget === void 0 && registryTarget === void 0 && placeholderMap === void 0) {
9094
+ return void 0;
8172
9095
  }
9096
+ return {
9097
+ format,
9098
+ targets: {
9099
+ ...modelTarget ? { model: modelTarget } : {},
9100
+ ...schemaTarget ? { schema: schemaTarget } : {},
9101
+ ...databaseTarget ? { database: databaseTarget } : {},
9102
+ ...registryTarget ? { registry: registryTarget } : {}
9103
+ },
9104
+ placeholderMap
9105
+ };
8173
9106
  }
8174
-
8175
- // src/generator/env.ts
8176
- function readEnvStringValue2(key) {
8177
- if (typeof process === "undefined" || !process.env) {
9107
+ function buildEnvironmentNamingConfig() {
9108
+ const modelType = resolveOptionalOneOf(MODEL_TYPE_ENV_KEYS, NAMING_STYLE_VALUES);
9109
+ const modelConst = resolveOptionalOneOf(MODEL_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
9110
+ const schemaConst = resolveOptionalOneOf(SCHEMA_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
9111
+ const databaseConst = resolveOptionalOneOf(DATABASE_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
9112
+ const registryConst = resolveOptionalOneOf(REGISTRY_CONST_ENV_KEYS, NAMING_STYLE_VALUES);
9113
+ if (modelType === void 0 && modelConst === void 0 && schemaConst === void 0 && databaseConst === void 0 && registryConst === void 0) {
8178
9114
  return void 0;
8179
9115
  }
8180
- const value = process.env[key];
8181
- if (typeof value !== "string") {
9116
+ return {
9117
+ ...modelType ? { modelType } : {},
9118
+ ...modelConst ? { modelConst } : {},
9119
+ ...schemaConst ? { schemaConst } : {},
9120
+ ...databaseConst ? { databaseConst } : {},
9121
+ ...registryConst ? { registryConst } : {}
9122
+ };
9123
+ }
9124
+ function buildEnvironmentFeatureFlags() {
9125
+ const emitRelations = resolveOptionalBoolean(EMIT_RELATIONS_ENV_KEYS);
9126
+ const emitRegistry = resolveOptionalBoolean(EMIT_REGISTRY_ENV_KEYS);
9127
+ if (emitRelations === void 0 && emitRegistry === void 0) {
8182
9128
  return void 0;
8183
9129
  }
8184
- const trimmed = value.trim();
8185
- return trimmed.length > 0 ? trimmed : void 0;
9130
+ return {
9131
+ ...emitRelations !== void 0 ? { emitRelations } : {},
9132
+ ...emitRegistry !== void 0 ? { emitRegistry } : {}
9133
+ };
8186
9134
  }
8187
- function throwMissingEnvVar(key) {
8188
- throw new Error(
8189
- `Generator config env var ${key} is missing or empty. Set ${key} or provide a default value.`
8190
- );
9135
+ function buildEnvironmentExperimentalFlags() {
9136
+ const postgresGatewayIntrospection = resolveOptionalBoolean(GATEWAY_EXPERIMENTAL_ENV_KEYS);
9137
+ const scyllaProviderContracts = resolveOptionalBoolean(SCYLLA_PROVIDER_CONTRACTS_ENV_KEYS);
9138
+ if (postgresGatewayIntrospection === void 0 && scyllaProviderContracts === void 0) {
9139
+ return void 0;
9140
+ }
9141
+ return {
9142
+ ...postgresGatewayIntrospection !== void 0 ? { postgresGatewayIntrospection } : {},
9143
+ ...scyllaProviderContracts !== void 0 ? { scyllaProviderContracts } : {}
9144
+ };
9145
+ }
9146
+ function buildEnvironmentProviderConfig() {
9147
+ const directConnectionString = resolveFallbackValue(DIRECT_CONNECTION_STRING_ENV_KEYS);
9148
+ if (directConnectionString) {
9149
+ return {
9150
+ kind: "postgres",
9151
+ mode: "direct",
9152
+ connectionString: directConnectionString,
9153
+ database: normalizeOptionalString(void 0, POSTGRES_DATABASE_ENV_KEYS),
9154
+ schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS))
9155
+ };
9156
+ }
9157
+ const gatewayUrl = resolveFallbackValue(GATEWAY_URL_ENV_KEYS);
9158
+ const apiKey = resolveFallbackValue(GATEWAY_API_KEY_ENV_KEYS);
9159
+ if (gatewayUrl && apiKey) {
9160
+ const backend = resolveOptionalOneOf(GATEWAY_BACKEND_ENV_KEYS, BACKEND_TYPE_VALUES);
9161
+ return {
9162
+ kind: "postgres",
9163
+ mode: "gateway",
9164
+ gatewayUrl,
9165
+ apiKey,
9166
+ database: normalizeOptionalString(void 0, POSTGRES_DATABASE_ENV_KEYS),
9167
+ schemas: normalizeSchemaSelection(resolveFallbackValue(GENERATOR_SCHEMA_ENV_KEYS)),
9168
+ backend
9169
+ };
9170
+ }
9171
+ return void 0;
9172
+ }
9173
+ function createEnvironmentGeneratorConfig() {
9174
+ const provider = buildEnvironmentProviderConfig();
9175
+ if (!provider) {
9176
+ return void 0;
9177
+ }
9178
+ return {
9179
+ provider,
9180
+ output: buildEnvironmentOutputConfig(),
9181
+ naming: buildEnvironmentNamingConfig(),
9182
+ features: buildEnvironmentFeatureFlags(),
9183
+ experimental: buildEnvironmentExperimentalFlags()
9184
+ };
9185
+ }
9186
+ async function loadGeneratorConfig(options = {}) {
9187
+ const cwd = options.cwd ?? process.cwd();
9188
+ const restoreProjectEnv = applyProjectEnv(cwd);
9189
+ try {
9190
+ const resolvedPath = options.configPath ? path.resolve(cwd, options.configPath) : findGeneratorConfigPath(cwd);
9191
+ if (!resolvedPath) {
9192
+ const environmentConfig = createEnvironmentGeneratorConfig();
9193
+ if (environmentConfig) {
9194
+ return {
9195
+ configPath: ENV_ONLY_CONFIG_PATH,
9196
+ config: normalizeGeneratorConfig(environmentConfig)
9197
+ };
9198
+ }
9199
+ throw new Error(
9200
+ `No generator config found in ${cwd}. Expected one of: ${DEFAULT_CONFIG_CANDIDATES.join(", ")}. To run without a config file, set DATABASE_URL (direct mode) or ATHENA_URL + ATHENA_API_KEY (gateway mode).`
9201
+ );
9202
+ }
9203
+ const moduleUrl = url.pathToFileURL(resolvedPath);
9204
+ const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
9205
+ const rawConfig = extractConfigExport(module);
9206
+ return {
9207
+ configPath: resolvedPath,
9208
+ config: normalizeGeneratorConfig(rawConfig)
9209
+ };
9210
+ } finally {
9211
+ restoreProjectEnv();
9212
+ }
9213
+ }
9214
+
9215
+ // src/generator/env.ts
9216
+ function readEnvStringValue2(key) {
9217
+ if (typeof process === "undefined" || !process.env) {
9218
+ return void 0;
9219
+ }
9220
+ const value = process.env[key];
9221
+ if (typeof value !== "string") {
9222
+ return void 0;
9223
+ }
9224
+ const trimmed = value.trim();
9225
+ return trimmed.length > 0 ? trimmed : void 0;
9226
+ }
9227
+ function throwMissingEnvVar(key) {
9228
+ throw new Error(
9229
+ `Generator config env var ${key} is missing or empty. Set ${key} or provide a default value.`
9230
+ );
8191
9231
  }
8192
9232
  function resolveEnvValue(key, options, resolver) {
8193
9233
  const rawValue = readEnvStringValue2(key);
@@ -8380,59 +9420,6 @@ function escapeStringLiteral(value) {
8380
9420
  return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
8381
9421
  }
8382
9422
 
8383
- // src/generator/placeholders.ts
8384
- function createStyleTokens(prefix, value) {
8385
- return {
8386
- [prefix]: value,
8387
- [`${prefix}_camel`]: applyNamingStyle(value, "camel"),
8388
- [`${prefix}_pascal`]: applyNamingStyle(value, "pascal"),
8389
- [`${prefix}_snake`]: applyNamingStyle(value, "snake"),
8390
- [`${prefix}_kebab`]: applyNamingStyle(value, "kebab")
8391
- };
8392
- }
8393
- function renderTemplate(template, tokenMap) {
8394
- return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_match, token) => {
8395
- if (!(token in tokenMap)) {
8396
- throw new Error(`Unknown placeholder token "${token}" in template "${template}"`);
8397
- }
8398
- return tokenMap[token];
8399
- });
8400
- }
8401
- function resolvePlaceholderMap(baseTokens, outputConfig) {
8402
- const resolved = {
8403
- ...baseTokens
8404
- };
8405
- const reservedTokenKeys = new Set(Object.keys(baseTokens));
8406
- const entries = Object.entries(outputConfig.placeholderMap ?? {});
8407
- for (let index = 0; index < entries.length; index += 1) {
8408
- const [key, value] = entries[index];
8409
- if (reservedTokenKeys.has(key)) {
8410
- continue;
8411
- }
8412
- let current = value;
8413
- for (let depth = 0; depth < 8; depth += 1) {
8414
- const next = renderTemplate(current, resolved);
8415
- if (next === current) {
8416
- break;
8417
- }
8418
- current = next;
8419
- }
8420
- resolved[key] = current;
8421
- }
8422
- return resolved;
8423
- }
8424
- function renderOutputPath(template, context, outputConfig) {
8425
- const baseTokens = {
8426
- provider: context.provider,
8427
- kind: context.kind,
8428
- ...createStyleTokens("database", context.database),
8429
- ...createStyleTokens("schema", context.schema),
8430
- ...createStyleTokens("model", context.model)
8431
- };
8432
- const tokens = resolvePlaceholderMap(baseTokens, outputConfig);
8433
- return renderTemplate(template, tokens);
8434
- }
8435
-
8436
9423
  // src/generator/postgres-type-mapping.ts
8437
9424
  var NUMBER_TYPES = /* @__PURE__ */ new Set([
8438
9425
  "int2",
@@ -8549,7 +9536,60 @@ function resolvePostgresColumnType(column) {
8549
9536
  return wrapArrayType(baseType, column.arrayDimensions);
8550
9537
  }
8551
9538
 
8552
- // src/generator/renderer.ts
9539
+ // src/generator/placeholders.ts
9540
+ function createStyleTokens(prefix, value) {
9541
+ return {
9542
+ [prefix]: value,
9543
+ [`${prefix}_camel`]: applyNamingStyle(value, "camel"),
9544
+ [`${prefix}_pascal`]: applyNamingStyle(value, "pascal"),
9545
+ [`${prefix}_snake`]: applyNamingStyle(value, "snake"),
9546
+ [`${prefix}_kebab`]: applyNamingStyle(value, "kebab")
9547
+ };
9548
+ }
9549
+ function renderTemplate(template, tokenMap) {
9550
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_match, token) => {
9551
+ if (!(token in tokenMap)) {
9552
+ throw new Error(`Unknown placeholder token "${token}" in template "${template}"`);
9553
+ }
9554
+ return tokenMap[token];
9555
+ });
9556
+ }
9557
+ function resolvePlaceholderMap(baseTokens, outputConfig) {
9558
+ const resolved = {
9559
+ ...baseTokens
9560
+ };
9561
+ const reservedTokenKeys = new Set(Object.keys(baseTokens));
9562
+ const entries = Object.entries(outputConfig.placeholderMap ?? {});
9563
+ for (let index = 0; index < entries.length; index += 1) {
9564
+ const [key, value] = entries[index];
9565
+ if (reservedTokenKeys.has(key)) {
9566
+ continue;
9567
+ }
9568
+ let current = value;
9569
+ for (let depth = 0; depth < 8; depth += 1) {
9570
+ const next = renderTemplate(current, resolved);
9571
+ if (next === current) {
9572
+ break;
9573
+ }
9574
+ current = next;
9575
+ }
9576
+ resolved[key] = current;
9577
+ }
9578
+ return resolved;
9579
+ }
9580
+ function renderOutputPath(template, context, outputConfig) {
9581
+ const baseTokens = {
9582
+ provider: context.provider,
9583
+ kind: context.kind,
9584
+ ...createStyleTokens("database", context.database),
9585
+ ...createStyleTokens("schema", context.schema),
9586
+ ...createStyleTokens("model", context.model)
9587
+ };
9588
+ const tokens = resolvePlaceholderMap(baseTokens, outputConfig);
9589
+ return renderTemplate(template, tokens);
9590
+ }
9591
+
9592
+ // src/generator/render-shared.ts
8553
9593
  function normalizePath(pathValue) {
8554
9594
  return pathValue.replace(/\\/g, "/");
8555
9595
  }
@@ -8562,11 +9602,13 @@ function toModuleImportPath(fromFile, targetFile) {
8562
9602
  );
8563
9603
  return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
8564
9604
  }
9605
+ function resolveOutputPath(target, tokens, config) {
9606
+ return normalizePath(renderOutputPath(target, tokens, config.output));
9607
+ }
8565
9608
  function renderObjectKey(key) {
8566
- const escaped = escapeTypePropertyName(key);
8567
- return escaped.startsWith("'") ? escaped : escaped;
9609
+ return escapeTypePropertyName(key);
8568
9610
  }
8569
- function renderRelation(relation) {
9611
+ function renderRelationLiteral(relation) {
8570
9612
  const through = relation.through ? `,
8571
9613
  through: {
8572
9614
  schema: ${escapeStringLiteral(relation.through.schema)},
@@ -8582,54 +9624,12 @@ function renderRelation(relation) {
8582
9624
  targetColumns: [${relation.targetColumns.map((value) => escapeStringLiteral(value)).join(", ")}]${through}
8583
9625
  }`;
8584
9626
  }
8585
- function renderModelArtifact(snapshot, descriptor, config) {
8586
- const columnLines = Object.values(descriptor.table.columns).map((column) => {
8587
- const propertyName = escapeTypePropertyName(column.name);
8588
- const baseType = resolvePostgresColumnType(column);
8589
- const isOptional = column.isNullable;
8590
- const typeWithNullability = column.isNullable ? `${baseType} | null` : baseType;
8591
- return ` ${propertyName}${isOptional ? "?" : ""}: ${typeWithNullability}`;
8592
- }).join("\n");
8593
- const nullableLines = Object.values(descriptor.table.columns).map((column) => ` ${renderObjectKey(column.name)}: ${column.isNullable ? "true" : "false"}`).join(",\n");
8594
- const relationEntries = Object.entries(descriptor.table.relations);
8595
- const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
8596
- relations: {
8597
- ${relationEntries.map(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelation(relationValue)}`).join(",\n")}
8598
- }` : "";
8599
- const content = `import { defineModel } from '@xylex-group/athena'
8600
-
8601
- export interface ${descriptor.rowTypeName} {
8602
- ${columnLines}
8603
- }
8604
-
8605
- export type ${descriptor.insertTypeName} = Partial<${descriptor.rowTypeName}>
8606
- export type ${descriptor.updateTypeName} = Partial<${descriptor.insertTypeName}>
8607
-
8608
- export const ${descriptor.modelConstName} = defineModel<${descriptor.rowTypeName}, ${descriptor.insertTypeName}, ${descriptor.updateTypeName}>({
8609
- meta: {
8610
- database: ${escapeStringLiteral(snapshot.database)},
8611
- schema: ${escapeStringLiteral(descriptor.schemaName)},
8612
- model: ${escapeStringLiteral(descriptor.tableName)},
8613
- tableName: ${escapeStringLiteral(`${descriptor.schemaName}.${descriptor.tableName}`)},
8614
- primaryKey: [${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")}],
8615
- nullable: {
8616
- ${nullableLines}
8617
- }${relationBlock}
8618
- }
8619
- })
8620
- `;
8621
- return {
8622
- kind: "model",
8623
- path: descriptor.filePath,
8624
- content
8625
- };
8626
- }
8627
9627
  function renderSchemaArtifact(descriptor) {
8628
9628
  const importLines = descriptor.models.map((modelDescriptor) => {
8629
9629
  const importPath = toModuleImportPath(descriptor.filePath, modelDescriptor.filePath);
8630
- return `import { ${modelDescriptor.modelConstName} } from '${importPath}'`;
9630
+ return `import { ${modelDescriptor.exportConstName} } from '${importPath}'`;
8631
9631
  }).join("\n");
8632
- const modelEntries = descriptor.models.map((modelDescriptor) => ` ${renderObjectKey(modelDescriptor.tableName)}: ${modelDescriptor.modelConstName}`).join(",\n");
9632
+ const modelEntries = descriptor.models.map((modelDescriptor) => ` ${renderObjectKey(modelDescriptor.tableName)}: ${modelDescriptor.exportConstName}`).join(",\n");
8633
9633
  const content = `import { defineSchema } from '@xylex-group/athena'
8634
9634
  ${importLines ? `
8635
9635
  ${importLines}
@@ -8664,11 +9664,18 @@ ${schemaEntries}
8664
9664
  content
8665
9665
  };
8666
9666
  }
8667
- function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName) {
9667
+ function renderRegistryArtifact(registryPath, databasePath, databaseConstName, registryConstName, databaseName, generatedAt, outputFormat, schemaVersion) {
8668
9668
  const databaseImportPath = toModuleImportPath(registryPath, databasePath);
8669
9669
  const content = `import { defineRegistry } from '@xylex-group/athena'
8670
9670
  import { ${databaseConstName} } from '${databaseImportPath}'
8671
9671
 
9672
+ export const __athena_schema_meta = {
9673
+ schemaVersion: ${schemaVersion},
9674
+ generatedAt: ${escapeStringLiteral(generatedAt)},
9675
+ database: ${escapeStringLiteral(databaseName)},
9676
+ outputFormat: ${escapeStringLiteral(outputFormat)},
9677
+ } as const
9678
+
8672
9679
  export const ${registryConstName} = defineRegistry({
8673
9680
  ${renderObjectKey(databaseName)}: ${databaseConstName}
8674
9681
  })
@@ -8747,123 +9754,332 @@ function scopeDuplicateDescriptorPathsBySchema(descriptors) {
8747
9754
  }
8748
9755
  return nextDescriptors;
8749
9756
  }
8750
- var ArtifactComposer = class {
8751
- constructor(snapshot, config) {
8752
- this.snapshot = snapshot;
8753
- this.config = config;
8754
- }
8755
- compose() {
8756
- const providerName = this.snapshot.backend;
8757
- const databaseName = this.snapshot.database;
8758
- const modelDescriptors = [];
8759
- for (const schemaName of Object.keys(this.snapshot.schemas).sort()) {
8760
- const schema = this.snapshot.schemas[schemaName];
8761
- for (const tableName of Object.keys(schema.tables).sort()) {
8762
- const table = schema.tables[tableName];
8763
- const rowTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Row`;
8764
- const insertTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Insert`;
8765
- const updateTypeName = `${toSafeIdentifier(`${schemaName} ${tableName}`, this.config.naming.modelType, "Model")}Update`;
8766
- const modelConstName = `${toSafeIdentifier(`${schemaName} ${tableName} model`, this.config.naming.modelConst, "model")}`;
8767
- const modelPath = normalizePath(
8768
- renderOutputPath(this.config.output.targets.model, {
8769
- provider: providerName,
8770
- kind: "model",
8771
- database: databaseName,
8772
- schema: schemaName,
8773
- model: tableName
8774
- }, this.config.output)
8775
- );
8776
- modelDescriptors.push({
9757
+ function composeGeneratorArtifacts(input) {
9758
+ const { snapshot, config, createModelDescriptor, renderModelArtifact: renderModelArtifact3 } = input;
9759
+ const providerName = snapshot.backend;
9760
+ const databaseName = snapshot.database;
9761
+ const modelDescriptors = [];
9762
+ for (const schemaName of Object.keys(snapshot.schemas).sort()) {
9763
+ const schema = snapshot.schemas[schemaName];
9764
+ for (const tableName of Object.keys(schema.tables).sort()) {
9765
+ modelDescriptors.push(
9766
+ createModelDescriptor({
9767
+ providerName,
9768
+ databaseName,
8777
9769
  schemaName,
8778
9770
  tableName,
8779
- filePath: modelPath,
8780
- rowTypeName,
8781
- insertTypeName,
8782
- updateTypeName,
8783
- modelConstName,
8784
- table
8785
- });
8786
- }
8787
- }
8788
- const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
8789
- let schemaDescriptors = Object.keys(this.snapshot.schemas).sort().map((schemaName) => {
8790
- const schemaPath = normalizePath(
8791
- renderOutputPath(this.config.output.targets.schema, {
8792
- provider: providerName,
8793
- kind: "schema",
8794
- database: databaseName,
8795
- schema: schemaName,
8796
- model: "index"
8797
- }, this.config.output)
9771
+ table: schema.tables[tableName]
9772
+ })
8798
9773
  );
8799
- return {
8800
- schemaName,
8801
- filePath: schemaPath,
8802
- schemaConstName: toSafeIdentifier(
8803
- `${schemaName} schema`,
8804
- this.config.naming.schemaConst,
8805
- "schema"
8806
- ),
8807
- models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
8808
- };
8809
- });
8810
- schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
8811
- const databasePath = normalizePath(
8812
- renderOutputPath(this.config.output.targets.database, {
9774
+ }
9775
+ }
9776
+ const scopedModelDescriptors = scopeDuplicateDescriptorPathsBySchema(modelDescriptors);
9777
+ let schemaDescriptors = Object.keys(snapshot.schemas).sort().map((schemaName) => ({
9778
+ schemaName,
9779
+ filePath: resolveOutputPath(
9780
+ config.output.targets.schema,
9781
+ {
9782
+ provider: providerName,
9783
+ kind: "schema",
9784
+ database: databaseName,
9785
+ schema: schemaName,
9786
+ model: "index"
9787
+ },
9788
+ config
9789
+ ),
9790
+ schemaConstName: toSafeIdentifier(
9791
+ `${schemaName} schema`,
9792
+ config.naming.schemaConst,
9793
+ "schema"
9794
+ ),
9795
+ models: scopedModelDescriptors.filter((model) => model.schemaName === schemaName)
9796
+ }));
9797
+ schemaDescriptors = scopeDuplicateDescriptorPathsBySchema(schemaDescriptors);
9798
+ const databaseDescriptor = {
9799
+ filePath: resolveOutputPath(
9800
+ config.output.targets.database,
9801
+ {
8813
9802
  provider: providerName,
8814
9803
  kind: "database",
8815
9804
  database: databaseName,
8816
9805
  schema: "index",
8817
9806
  model: "index"
8818
- }, this.config.output)
9807
+ },
9808
+ config
9809
+ ),
9810
+ databaseConstName: toSafeIdentifier(
9811
+ `${databaseName} database`,
9812
+ config.naming.databaseConst,
9813
+ "database"
9814
+ ),
9815
+ schemas: schemaDescriptors
9816
+ };
9817
+ const files = [];
9818
+ for (const modelDescriptor of scopedModelDescriptors) {
9819
+ files.push(renderModelArtifact3(modelDescriptor));
9820
+ }
9821
+ for (const schemaDescriptor of schemaDescriptors) {
9822
+ files.push(renderSchemaArtifact(schemaDescriptor));
9823
+ }
9824
+ files.push(renderDatabaseArtifact(databaseDescriptor));
9825
+ if (config.features.emitRegistry) {
9826
+ const registryPath = resolveOutputPath(
9827
+ config.output.targets.registry,
9828
+ {
9829
+ provider: providerName,
9830
+ kind: "registry",
9831
+ database: databaseName,
9832
+ schema: "index",
9833
+ model: "index"
9834
+ },
9835
+ config
9836
+ );
9837
+ files.push(
9838
+ renderRegistryArtifact(
9839
+ registryPath,
9840
+ databaseDescriptor.filePath,
9841
+ databaseDescriptor.databaseConstName,
9842
+ toSafeIdentifier("registry", config.naming.registryConst, "registry"),
9843
+ databaseName,
9844
+ snapshot.generatedAt,
9845
+ config.output.format,
9846
+ config.internal.schemaVersion
9847
+ )
8819
9848
  );
8820
- const databaseDescriptor = {
8821
- filePath: databasePath,
8822
- databaseConstName: toSafeIdentifier(
8823
- `${databaseName} database`,
8824
- this.config.naming.databaseConst,
8825
- "database"
8826
- ),
8827
- schemas: schemaDescriptors
8828
- };
8829
- const files = [];
8830
- for (const modelDescriptor of scopedModelDescriptors) {
8831
- files.push(renderModelArtifact(this.snapshot, modelDescriptor, this.config));
8832
- }
8833
- for (const schemaDescriptor of schemaDescriptors) {
8834
- files.push(renderSchemaArtifact(schemaDescriptor));
8835
- }
8836
- files.push(renderDatabaseArtifact(databaseDescriptor));
8837
- if (this.config.features.emitRegistry) {
8838
- const registryPath = normalizePath(
8839
- renderOutputPath(this.config.output.targets.registry, {
8840
- provider: providerName,
8841
- kind: "registry",
8842
- database: databaseName,
8843
- schema: "index",
8844
- model: "index"
8845
- }, this.config.output)
8846
- );
8847
- files.push(
8848
- renderRegistryArtifact(
8849
- registryPath,
8850
- databaseDescriptor.filePath,
8851
- databaseDescriptor.databaseConstName,
8852
- toSafeIdentifier("registry", this.config.naming.registryConst, "registry"),
8853
- databaseName
8854
- )
8855
- );
8856
- }
8857
- assertNoDuplicatePaths(files);
8858
- return {
8859
- snapshot: this.snapshot,
8860
- files
8861
- };
8862
9849
  }
8863
- };
9850
+ assertNoDuplicatePaths(files);
9851
+ return {
9852
+ snapshot,
9853
+ files
9854
+ };
9855
+ }
9856
+
9857
+ // src/generator/table-builder-renderer.ts
9858
+ var SAFE_NUMBER_TYPES = /* @__PURE__ */ new Set([
9859
+ "int2",
9860
+ "int4",
9861
+ "float4",
9862
+ "float8",
9863
+ "smallint",
9864
+ "integer",
9865
+ "real",
9866
+ "double precision"
9867
+ ]);
9868
+ var JSON_TYPES = /* @__PURE__ */ new Set(["json", "jsonb"]);
9869
+ var BOOLEAN_TYPES = /* @__PURE__ */ new Set(["bool", "boolean"]);
9870
+ var STRING_TYPES = /* @__PURE__ */ new Set([
9871
+ "int8",
9872
+ "bigint",
9873
+ "serial8",
9874
+ "bigserial",
9875
+ "numeric",
9876
+ "decimal",
9877
+ "money",
9878
+ "bytea"
9879
+ ]);
9880
+ function normalizeTypeLabel2(column) {
9881
+ const preferred = (column.udtName || column.dataType).toLowerCase().trim();
9882
+ if (column.arrayDimensions > 0 && preferred.startsWith("_")) {
9883
+ return preferred.slice(1);
9884
+ }
9885
+ return preferred;
9886
+ }
9887
+ function renderColumnBuilder(column) {
9888
+ const label = normalizeTypeLabel2(column);
9889
+ let helper;
9890
+ let expression;
9891
+ if (column.typeKind === "enum" && column.enumValues && column.enumValues.length > 0) {
9892
+ helper = "enumeration";
9893
+ expression = `enumeration([${column.enumValues.map((value) => escapeStringLiteral(value)).join(", ")}] as const)`;
9894
+ } else if (column.arrayDimensions > 0 || JSON_TYPES.has(label) || column.typeKind === "composite") {
9895
+ helper = "json";
9896
+ expression = `json<${resolvePostgresColumnType(column)}>()`;
9897
+ } else if (BOOLEAN_TYPES.has(label)) {
9898
+ helper = "boolean";
9899
+ expression = "boolean()";
9900
+ } else if (SAFE_NUMBER_TYPES.has(label)) {
9901
+ helper = "number";
9902
+ expression = "number()";
9903
+ } else if (STRING_TYPES.has(label)) {
9904
+ helper = "string";
9905
+ expression = "string()";
9906
+ } else {
9907
+ helper = "string";
9908
+ expression = "string()";
9909
+ }
9910
+ if (column.isNullable) {
9911
+ expression = `${expression}.optional()`;
9912
+ }
9913
+ if (column.hasDefault) {
9914
+ expression = `${expression}.defaulted()`;
9915
+ }
9916
+ if (column.isGenerated) {
9917
+ expression = `${expression}.generated()`;
9918
+ }
9919
+ return { helper, expression };
9920
+ }
9921
+ function renderModelArtifact(descriptor, config) {
9922
+ const helperImports = /* @__PURE__ */ new Set(["table"]);
9923
+ const columnLines = Object.entries(descriptor.table.columns).map(([columnName, column]) => {
9924
+ const propertyName = escapeTypePropertyName(columnName);
9925
+ const rendered = renderColumnBuilder(column);
9926
+ helperImports.add(rendered.helper);
9927
+ return ` ${propertyName}: ${rendered.expression}`;
9928
+ }).join(",\n");
9929
+ const helperImportLine = Array.from(helperImports).sort().join(", ");
9930
+ const rowSchemaConstName = `${descriptor.tableConstName}_row_schema`;
9931
+ const insertSchemaConstName = `${descriptor.tableConstName}_insert_schema`;
9932
+ const updateSchemaConstName = `${descriptor.tableConstName}_update_schema`;
9933
+ const formSchemaConstName = `${descriptor.tableConstName}_form_schema`;
9934
+ const relationEntries = Object.entries(descriptor.table.relations);
9935
+ const relationsAssignment = config.features.emitRelations && relationEntries.length > 0 ? `
9936
+ Object.assign(${descriptor.tableConstName}.meta, {
9937
+ relations: {
9938
+ ${relationEntries.map(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
9939
+ }
9940
+ })
9941
+ ` : "";
9942
+ const content = `import { ${helperImportLine} } from '@xylex-group/athena'
9943
+ import type { FormValuesOf, InsertOf, RowOf, UpdateOf } from '@xylex-group/athena'
9944
+
9945
+ export const ${descriptor.tableConstName} = table(${escapeStringLiteral(descriptor.tableName)})
9946
+ .schema(${escapeStringLiteral(descriptor.schemaName)})
9947
+ .columns({
9948
+ ${columnLines}
9949
+ })
9950
+ .primaryKey(${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")})
9951
+ ${relationsAssignment ? `${relationsAssignment}` : ""}
9952
+ export type ${descriptor.rowTypeName} = RowOf<typeof ${descriptor.tableConstName}>
9953
+ export type ${descriptor.insertTypeName} = InsertOf<typeof ${descriptor.tableConstName}>
9954
+ export type ${descriptor.updateTypeName} = UpdateOf<typeof ${descriptor.tableConstName}>
9955
+ export type ${descriptor.formValuesTypeName} = FormValuesOf<typeof ${descriptor.tableConstName}>
9956
+
9957
+ export const ${rowSchemaConstName} = ${descriptor.tableConstName}.schemas.row
9958
+ export const ${insertSchemaConstName} = ${descriptor.tableConstName}.schemas.insert
9959
+ export const ${updateSchemaConstName} = ${descriptor.tableConstName}.schemas.update
9960
+ export const ${formSchemaConstName} = ${descriptor.tableConstName}.schemas.form
9961
+ `;
9962
+ return {
9963
+ kind: "model",
9964
+ path: descriptor.filePath,
9965
+ content
9966
+ };
9967
+ }
9968
+ function generateTableBuilderArtifactsFromSnapshot(snapshot, config) {
9969
+ const normalizedConfig = "internal" in config ? config : normalizeGeneratorConfig(config);
9970
+ return composeGeneratorArtifacts({
9971
+ snapshot,
9972
+ config: normalizedConfig,
9973
+ createModelDescriptor({ providerName, databaseName, schemaName, tableName, table: table2 }) {
9974
+ const tableConstName = toSafeIdentifier(tableName, "preserve", "table");
9975
+ return {
9976
+ schemaName,
9977
+ tableName,
9978
+ filePath: resolveOutputPath(
9979
+ normalizedConfig.output.targets.model,
9980
+ {
9981
+ provider: providerName,
9982
+ kind: "model",
9983
+ database: databaseName,
9984
+ schema: schemaName,
9985
+ model: tableName
9986
+ },
9987
+ normalizedConfig
9988
+ ),
9989
+ rowTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Row`,
9990
+ insertTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Insert`,
9991
+ updateTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Update`,
9992
+ formValuesTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}FormValues`,
9993
+ tableConstName,
9994
+ exportConstName: tableConstName,
9995
+ table: table2
9996
+ };
9997
+ },
9998
+ renderModelArtifact: (descriptor) => renderModelArtifact(descriptor, normalizedConfig)
9999
+ });
10000
+ }
10001
+
10002
+ // src/generator/renderer.ts
10003
+ function renderModelArtifact2(databaseName, descriptor, config) {
10004
+ const columnLines = Object.values(descriptor.table.columns).map((column) => {
10005
+ const propertyName = escapeTypePropertyName(column.name);
10006
+ const baseType = resolvePostgresColumnType(column);
10007
+ const isOptional = column.isNullable;
10008
+ const typeWithNullability = column.isNullable ? `${baseType} | null` : baseType;
10009
+ return ` ${propertyName}${isOptional ? "?" : ""}: ${typeWithNullability}`;
10010
+ }).join("\n");
10011
+ const nullableLines = Object.values(descriptor.table.columns).map((column) => ` ${renderObjectKey(column.name)}: ${column.isNullable ? "true" : "false"}`).join(",\n");
10012
+ const relationEntries = Object.entries(descriptor.table.relations);
10013
+ const relationBlock = config.features.emitRelations && relationEntries.length > 0 ? `,
10014
+ relations: {
10015
+ ${relationEntries.map(([relationKey2, relationValue]) => ` ${renderObjectKey(relationKey2)}: ${renderRelationLiteral(relationValue)}`).join(",\n")}
10016
+ }` : "";
10017
+ const content = `import { defineModel } from '@xylex-group/athena'
10018
+
10019
+ export interface ${descriptor.rowTypeName} {
10020
+ ${columnLines}
10021
+ }
10022
+
10023
+ export type ${descriptor.insertTypeName} = Partial<${descriptor.rowTypeName}>
10024
+ export type ${descriptor.updateTypeName} = Partial<${descriptor.insertTypeName}>
10025
+
10026
+ export const ${descriptor.modelConstName} = defineModel<${descriptor.rowTypeName}, ${descriptor.insertTypeName}, ${descriptor.updateTypeName}>({
10027
+ meta: {
10028
+ database: ${escapeStringLiteral(databaseName)},
10029
+ schema: ${escapeStringLiteral(descriptor.schemaName)},
10030
+ model: ${escapeStringLiteral(descriptor.tableName)},
10031
+ tableName: ${escapeStringLiteral(`${descriptor.schemaName}.${descriptor.tableName}`)},
10032
+ primaryKey: [${descriptor.table.primaryKey.map((value) => escapeStringLiteral(value)).join(", ")}],
10033
+ nullable: {
10034
+ ${nullableLines}
10035
+ }${relationBlock}
10036
+ }
10037
+ })
10038
+ `;
10039
+ return {
10040
+ kind: "model",
10041
+ path: descriptor.filePath,
10042
+ content
10043
+ };
10044
+ }
8864
10045
  function generateArtifactsFromSnapshot(snapshot, config) {
8865
- const normalizedConfig = "naming" in config && "features" in config && "experimental" in config ? config : normalizeGeneratorConfig(config);
8866
- return new ArtifactComposer(snapshot, normalizedConfig).compose();
10046
+ const normalizedConfig = "internal" in config ? config : normalizeGeneratorConfig(config);
10047
+ if (normalizedConfig.output.format === "table-builder") {
10048
+ return generateTableBuilderArtifactsFromSnapshot(snapshot, normalizedConfig);
10049
+ }
10050
+ return composeGeneratorArtifacts({
10051
+ snapshot,
10052
+ config: normalizedConfig,
10053
+ createModelDescriptor({ providerName, databaseName, schemaName, tableName, table: table2 }) {
10054
+ const modelConstName = toSafeIdentifier(
10055
+ `${schemaName} ${tableName} model`,
10056
+ normalizedConfig.naming.modelConst,
10057
+ "model"
10058
+ );
10059
+ return {
10060
+ schemaName,
10061
+ tableName,
10062
+ filePath: resolveOutputPath(
10063
+ normalizedConfig.output.targets.model,
10064
+ {
10065
+ provider: providerName,
10066
+ kind: "model",
10067
+ database: databaseName,
10068
+ schema: schemaName,
10069
+ model: tableName
10070
+ },
10071
+ normalizedConfig
10072
+ ),
10073
+ rowTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Row`,
10074
+ insertTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Insert`,
10075
+ updateTypeName: `${toSafeIdentifier(`${schemaName} ${tableName}`, normalizedConfig.naming.modelType, "Model")}Update`,
10076
+ modelConstName,
10077
+ exportConstName: modelConstName,
10078
+ table: table2
10079
+ };
10080
+ },
10081
+ renderModelArtifact: (descriptor) => renderModelArtifact2(snapshot.database, descriptor, normalizedConfig)
10082
+ });
8867
10083
  }
8868
10084
 
8869
10085
  // src/generator/providers.ts
@@ -9453,6 +10669,7 @@ exports.Backend = Backend;
9453
10669
  exports.DEFAULT_POSTGRES_SCHEMAS = DEFAULT_POSTGRES_SCHEMAS;
9454
10670
  exports.assertInt = assertInt;
9455
10671
  exports.athenaAuth = athenaAuth;
10672
+ exports.boolean = boolean;
9456
10673
  exports.coerceInt = coerceInt;
9457
10674
  exports.createAthenaStorageError = createAthenaStorageError;
9458
10675
  exports.createAuthClient = createAuthClient;
@@ -9468,17 +10685,21 @@ exports.defineGeneratorConfig = defineGeneratorConfig;
9468
10685
  exports.defineModel = defineModel;
9469
10686
  exports.defineRegistry = defineRegistry;
9470
10687
  exports.defineSchema = defineSchema;
10688
+ exports.enumeration = enumeration;
9471
10689
  exports.findGeneratorConfigPath = findGeneratorConfigPath;
9472
10690
  exports.generateArtifactsFromSnapshot = generateArtifactsFromSnapshot;
9473
10691
  exports.generatorEnv = generatorEnv;
10692
+ exports.getAthenaDebugAst = getAthenaDebugAst;
9474
10693
  exports.identifier = identifier;
9475
10694
  exports.isAthenaGatewayError = isAthenaGatewayError;
9476
10695
  exports.isOk = isOk;
10696
+ exports.json = json;
9477
10697
  exports.loadGeneratorConfig = loadGeneratorConfig;
9478
10698
  exports.normalizeAthenaError = normalizeAthenaError;
9479
10699
  exports.normalizeAthenaGatewayBaseUrl = normalizeAthenaGatewayBaseUrl;
9480
10700
  exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
9481
10701
  exports.normalizeSchemaSelection = normalizeSchemaSelection;
10702
+ exports.number = number;
9482
10703
  exports.parseBooleanFlag = parseBooleanFlag2;
9483
10704
  exports.renderAthenaReactEmail = renderAthenaReactEmail;
9484
10705
  exports.requireAffected = requireAffected;
@@ -9488,6 +10709,8 @@ exports.resolvePostgresColumnType = resolvePostgresColumnType;
9488
10709
  exports.resolveProviderSchemas = resolveProviderSchemas;
9489
10710
  exports.runSchemaGenerator = runSchemaGenerator;
9490
10711
  exports.storageSdkManifest = storageSdkManifest;
10712
+ exports.string = string;
10713
+ exports.table = table;
9491
10714
  exports.toModelFormDefaults = toModelFormDefaults;
9492
10715
  exports.toModelPayload = toModelPayload;
9493
10716
  exports.unwrap = unwrap;