@proofkit/fmodata 0.1.0-alpha.0 → 0.1.0-alpha.10

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 (75) hide show
  1. package/README.md +1624 -18
  2. package/dist/esm/client/base-table.d.ts +117 -5
  3. package/dist/esm/client/base-table.js +43 -5
  4. package/dist/esm/client/base-table.js.map +1 -1
  5. package/dist/esm/client/batch-builder.d.ts +54 -0
  6. package/dist/esm/client/batch-builder.js +179 -0
  7. package/dist/esm/client/batch-builder.js.map +1 -0
  8. package/dist/esm/client/batch-request.d.ts +61 -0
  9. package/dist/esm/client/batch-request.js +252 -0
  10. package/dist/esm/client/batch-request.js.map +1 -0
  11. package/dist/esm/client/database.d.ts +55 -6
  12. package/dist/esm/client/database.js +118 -15
  13. package/dist/esm/client/database.js.map +1 -1
  14. package/dist/esm/client/delete-builder.d.ts +21 -2
  15. package/dist/esm/client/delete-builder.js +96 -32
  16. package/dist/esm/client/delete-builder.js.map +1 -1
  17. package/dist/esm/client/entity-set.d.ts +25 -11
  18. package/dist/esm/client/entity-set.js +31 -11
  19. package/dist/esm/client/entity-set.js.map +1 -1
  20. package/dist/esm/client/filemaker-odata.d.ts +23 -4
  21. package/dist/esm/client/filemaker-odata.js +124 -29
  22. package/dist/esm/client/filemaker-odata.js.map +1 -1
  23. package/dist/esm/client/insert-builder.d.ts +38 -3
  24. package/dist/esm/client/insert-builder.js +231 -34
  25. package/dist/esm/client/insert-builder.js.map +1 -1
  26. package/dist/esm/client/query-builder.d.ts +27 -6
  27. package/dist/esm/client/query-builder.js +457 -210
  28. package/dist/esm/client/query-builder.js.map +1 -1
  29. package/dist/esm/client/record-builder.d.ts +96 -9
  30. package/dist/esm/client/record-builder.js +378 -39
  31. package/dist/esm/client/record-builder.js.map +1 -1
  32. package/dist/esm/client/response-processor.d.ts +38 -0
  33. package/dist/esm/client/schema-manager.d.ts +57 -0
  34. package/dist/esm/client/schema-manager.js +132 -0
  35. package/dist/esm/client/schema-manager.js.map +1 -0
  36. package/dist/esm/client/table-occurrence.d.ts +48 -1
  37. package/dist/esm/client/table-occurrence.js +29 -2
  38. package/dist/esm/client/table-occurrence.js.map +1 -1
  39. package/dist/esm/client/update-builder.d.ts +34 -11
  40. package/dist/esm/client/update-builder.js +135 -31
  41. package/dist/esm/client/update-builder.js.map +1 -1
  42. package/dist/esm/errors.d.ts +73 -0
  43. package/dist/esm/errors.js +148 -0
  44. package/dist/esm/errors.js.map +1 -0
  45. package/dist/esm/index.d.ts +10 -3
  46. package/dist/esm/index.js +28 -5
  47. package/dist/esm/index.js.map +1 -1
  48. package/dist/esm/transform.d.ts +65 -0
  49. package/dist/esm/transform.js +114 -0
  50. package/dist/esm/transform.js.map +1 -0
  51. package/dist/esm/types.d.ts +89 -5
  52. package/dist/esm/validation.d.ts +6 -3
  53. package/dist/esm/validation.js +104 -33
  54. package/dist/esm/validation.js.map +1 -1
  55. package/package.json +10 -1
  56. package/src/client/base-table.ts +158 -8
  57. package/src/client/batch-builder.ts +265 -0
  58. package/src/client/batch-request.ts +485 -0
  59. package/src/client/database.ts +175 -18
  60. package/src/client/delete-builder.ts +149 -48
  61. package/src/client/entity-set.ts +114 -23
  62. package/src/client/filemaker-odata.ts +179 -35
  63. package/src/client/insert-builder.ts +350 -40
  64. package/src/client/query-builder.ts +616 -237
  65. package/src/client/query-builder.ts.bak +1457 -0
  66. package/src/client/record-builder.ts +692 -65
  67. package/src/client/response-processor.ts +103 -0
  68. package/src/client/schema-manager.ts +246 -0
  69. package/src/client/table-occurrence.ts +78 -3
  70. package/src/client/update-builder.ts +235 -49
  71. package/src/errors.ts +217 -0
  72. package/src/index.ts +59 -2
  73. package/src/transform.ts +249 -0
  74. package/src/types.ts +201 -35
  75. package/src/validation.ts +120 -36
@@ -3,6 +3,8 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import buildQuery from "odata-query";
5
5
  import { validateSingleResponse, validateListResponse } from "../validation.js";
6
+ import { RecordCountMismatchError } from "../errors.js";
7
+ import { getTableIdentifiers, transformFieldName, transformOrderByField, transformFieldNamesArray, transformResponseFields } from "../transform.js";
6
8
  class QueryBuilder {
7
9
  constructor(config) {
8
10
  __publicField(this, "queryOptions", {});
@@ -18,10 +20,21 @@ class QueryBuilder {
18
20
  __publicField(this, "navigateRelation");
19
21
  __publicField(this, "navigateSourceTableName");
20
22
  __publicField(this, "navigateBaseRelation");
23
+ __publicField(this, "databaseUseEntityIds");
21
24
  this.occurrence = config.occurrence;
22
25
  this.tableName = config.tableName;
23
26
  this.databaseName = config.databaseName;
24
27
  this.context = config.context;
28
+ this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;
29
+ }
30
+ /**
31
+ * Helper to merge database-level useEntityIds with per-request options
32
+ */
33
+ mergeExecuteOptions(options) {
34
+ return {
35
+ ...options,
36
+ useEntityIds: (options == null ? void 0 : options.useEntityIds) === void 0 ? this.databaseUseEntityIds : options.useEntityIds
37
+ };
25
38
  }
26
39
  /**
27
40
  * Helper to conditionally strip OData annotations based on options
@@ -33,13 +46,36 @@ class QueryBuilder {
33
46
  const { "@id": _id, "@editLink": _editLink, ...rest } = data;
34
47
  return rest;
35
48
  }
49
+ /**
50
+ * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name
51
+ * @param useEntityIds - Optional override for entity ID usage
52
+ */
53
+ getTableId(useEntityIds) {
54
+ var _a, _b;
55
+ if (!this.occurrence) {
56
+ return this.tableName;
57
+ }
58
+ const contextDefault = ((_b = (_a = this.context)._getUseEntityIds) == null ? void 0 : _b.call(_a)) ?? false;
59
+ const shouldUseIds = useEntityIds ?? contextDefault;
60
+ if (shouldUseIds) {
61
+ const identifiers = getTableIdentifiers(this.occurrence);
62
+ if (!identifiers.id) {
63
+ throw new Error(
64
+ `useEntityIds is true but TableOccurrence "${identifiers.name}" does not have an fmtId defined`
65
+ );
66
+ }
67
+ return identifiers.id;
68
+ }
69
+ return this.occurrence.getTableName();
70
+ }
36
71
  select(...fields) {
37
72
  const uniqueFields = [...new Set(fields)];
38
73
  const newBuilder = new QueryBuilder({
39
74
  occurrence: this.occurrence,
40
75
  tableName: this.tableName,
41
76
  databaseName: this.databaseName,
42
- context: this.context
77
+ context: this.context,
78
+ databaseUseEntityIds: this.databaseUseEntityIds
43
79
  });
44
80
  newBuilder.queryOptions = {
45
81
  ...this.queryOptions,
@@ -62,6 +98,7 @@ class QueryBuilder {
62
98
  * - Shorthand values are handled by odata-query
63
99
  */
64
100
  transformFilter(filter) {
101
+ var _a;
65
102
  if (typeof filter === "string") {
66
103
  return filter;
67
104
  }
@@ -84,12 +121,13 @@ class QueryBuilder {
84
121
  const result = {};
85
122
  const andConditions = [];
86
123
  for (const [field, value] of Object.entries(filter)) {
124
+ const fieldId = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) ? transformFieldName(field, this.occurrence.baseTable) : field;
87
125
  if (Array.isArray(value)) {
88
126
  if (value.length === 1) {
89
- result[field] = value[0];
127
+ result[fieldId] = value[0];
90
128
  } else {
91
129
  for (const op of value) {
92
- andConditions.push({ [field]: op });
130
+ andConditions.push({ [fieldId]: op });
93
131
  }
94
132
  }
95
133
  } else if (value && typeof value === "object" && !(value instanceof Date) && !Array.isArray(value)) {
@@ -107,12 +145,12 @@ class QueryBuilder {
107
145
  ];
108
146
  const isOperatorObject = operatorKeys.some((key) => key in value);
109
147
  if (isOperatorObject) {
110
- result[field] = value;
148
+ result[fieldId] = value;
111
149
  } else {
112
- result[field] = value;
150
+ result[fieldId] = value;
113
151
  }
114
152
  } else {
115
- result[field] = value;
153
+ result[fieldId] = value;
116
154
  }
117
155
  }
118
156
  if (andConditions.length > 0) {
@@ -129,7 +167,21 @@ class QueryBuilder {
129
167
  return this;
130
168
  }
131
169
  orderBy(orderBy) {
132
- this.queryOptions.orderBy = orderBy;
170
+ var _a;
171
+ if (((_a = this.occurrence) == null ? void 0 : _a.baseTable) && orderBy) {
172
+ if (Array.isArray(orderBy)) {
173
+ this.queryOptions.orderBy = orderBy.map(
174
+ (field) => transformOrderByField(String(field), this.occurrence.baseTable)
175
+ );
176
+ } else {
177
+ this.queryOptions.orderBy = transformOrderByField(
178
+ String(orderBy),
179
+ this.occurrence.baseTable
180
+ );
181
+ }
182
+ } else {
183
+ this.queryOptions.orderBy = orderBy;
184
+ }
133
185
  return this;
134
186
  }
135
187
  top(count) {
@@ -142,13 +194,18 @@ class QueryBuilder {
142
194
  }
143
195
  /**
144
196
  * Formats select fields for use in query strings.
197
+ * - Transforms field names to FMFIDs if using entity IDs
145
198
  * - Wraps "id" fields in double quotes
146
199
  * - URL-encodes special characters but preserves spaces
147
200
  */
148
- formatSelectFields(select) {
201
+ formatSelectFields(select, baseTable) {
149
202
  if (!select) return "";
150
203
  const selectFieldsArray = Array.isArray(select) ? select : [select];
151
- return selectFieldsArray.map((field) => {
204
+ const transformedFields = baseTable ? transformFieldNamesArray(
205
+ selectFieldsArray.map((f) => String(f)),
206
+ baseTable
207
+ ) : selectFieldsArray.map((f) => String(f));
208
+ return transformedFields.map((field) => {
152
209
  if (field === "id") return `"id"`;
153
210
  const encodedField = encodeURIComponent(String(field));
154
211
  return encodedField.replace(/%20/g, " ");
@@ -168,6 +225,9 @@ class QueryBuilder {
168
225
  relation: config.relation,
169
226
  targetSchema,
170
227
  targetOccurrence,
228
+ targetBaseTable: targetOccurrence == null ? void 0 : targetOccurrence.baseTable,
229
+ occurrence: targetOccurrence,
230
+ // Add occurrence for transformation
171
231
  selectedFields,
172
232
  nestedExpands: void 0
173
233
  // TODO: Handle nested expands if needed
@@ -177,18 +237,25 @@ class QueryBuilder {
177
237
  /**
178
238
  * Builds OData expand query string from expand configurations.
179
239
  * Handles nested expands recursively.
240
+ * Transforms relation names to FMTIDs if using entity IDs.
180
241
  */
181
242
  buildExpandString(configs) {
182
243
  if (configs.length === 0) {
183
244
  return "";
184
245
  }
185
246
  return configs.map((config) => {
247
+ var _a;
248
+ const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[config.relation];
249
+ const relationName = targetOccurrence && targetOccurrence.isUsingTableId() ? targetOccurrence.getTableId() : config.relation;
186
250
  if (!config.options || Object.keys(config.options).length === 0) {
187
- return config.relation;
251
+ return relationName;
188
252
  }
189
253
  const parts = [];
190
254
  if (config.options.select) {
191
- const selectFields = this.formatSelectFields(config.options.select);
255
+ const selectFields = this.formatSelectFields(
256
+ config.options.select,
257
+ targetOccurrence == null ? void 0 : targetOccurrence.baseTable
258
+ );
192
259
  parts.push(`$select=${selectFields}`);
193
260
  }
194
261
  if (config.options.filter) {
@@ -214,9 +281,9 @@ class QueryBuilder {
214
281
  }
215
282
  }
216
283
  if (parts.length === 0) {
217
- return config.relation;
284
+ return relationName;
218
285
  }
219
- return `${config.relation}(${parts.join(";")})`;
286
+ return `${relationName}(${parts.join(";")})`;
220
287
  }).join(",");
221
288
  }
222
289
  expand(relation, callback) {
@@ -227,7 +294,8 @@ class QueryBuilder {
227
294
  occurrence: targetOccurrence,
228
295
  tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relation,
229
296
  databaseName: this.databaseName,
230
- context: this.context
297
+ context: this.context,
298
+ databaseUseEntityIds: this.databaseUseEntityIds
231
299
  });
232
300
  const typedBuilder = targetBuilder;
233
301
  const configuredBuilder = callback(typedBuilder);
@@ -257,7 +325,8 @@ class QueryBuilder {
257
325
  occurrence: this.occurrence,
258
326
  tableName: this.tableName,
259
327
  databaseName: this.databaseName,
260
- context: this.context
328
+ context: this.context,
329
+ databaseUseEntityIds: this.databaseUseEntityIds
261
330
  });
262
331
  newBuilder.queryOptions = { ...this.queryOptions };
263
332
  newBuilder.expandConfigs = [...this.expandConfigs];
@@ -275,7 +344,8 @@ class QueryBuilder {
275
344
  occurrence: this.occurrence,
276
345
  tableName: this.tableName,
277
346
  databaseName: this.databaseName,
278
- context: this.context
347
+ context: this.context,
348
+ databaseUseEntityIds: this.databaseUseEntityIds
279
349
  });
280
350
  newBuilder.queryOptions = { ...this.queryOptions };
281
351
  newBuilder.expandConfigs = [...this.expandConfigs];
@@ -293,7 +363,8 @@ class QueryBuilder {
293
363
  occurrence: this.occurrence,
294
364
  tableName: this.tableName,
295
365
  databaseName: this.databaseName,
296
- context: this.context
366
+ context: this.context,
367
+ databaseUseEntityIds: this.databaseUseEntityIds
297
368
  });
298
369
  newBuilder.queryOptions = { ...this.queryOptions, count: true };
299
370
  newBuilder.expandConfigs = [...this.expandConfigs];
@@ -307,200 +378,144 @@ class QueryBuilder {
307
378
  return newBuilder;
308
379
  }
309
380
  async execute(options) {
310
- var _a, _b, _c, _d, _e, _f;
311
- try {
312
- const queryOptionsWithoutExpand = { ...this.queryOptions };
313
- delete queryOptionsWithoutExpand.expand;
314
- if (queryOptionsWithoutExpand.select) {
315
- queryOptionsWithoutExpand.select = this.formatSelectFields(
316
- queryOptionsWithoutExpand.select
317
- );
381
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
382
+ const queryOptionsWithoutExpand = { ...this.queryOptions };
383
+ delete queryOptionsWithoutExpand.expand;
384
+ const mergedOptions = this.mergeExecuteOptions(options);
385
+ if (queryOptionsWithoutExpand.select) {
386
+ queryOptionsWithoutExpand.select = this.formatSelectFields(
387
+ queryOptionsWithoutExpand.select,
388
+ (_a = this.occurrence) == null ? void 0 : _a.baseTable
389
+ );
390
+ }
391
+ let queryString = buildQuery(queryOptionsWithoutExpand);
392
+ const expandString = this.buildExpandString(this.expandConfigs);
393
+ if (expandString) {
394
+ const separator = queryString.includes("?") ? "&" : "?";
395
+ queryString = `${queryString}${separator}$expand=${expandString}`;
396
+ }
397
+ if (this.isNavigate && this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
398
+ let url;
399
+ if (this.navigateBaseRelation) {
400
+ url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
401
+ } else {
402
+ url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
318
403
  }
319
- let queryString = buildQuery(queryOptionsWithoutExpand);
320
- const expandString = this.buildExpandString(this.expandConfigs);
321
- if (expandString) {
322
- const separator = queryString.includes("?") ? "&" : "?";
323
- queryString = `${queryString}${separator}$expand=${expandString}`;
404
+ const result2 = await this.context._makeRequest(url, mergedOptions);
405
+ if (result2.error) {
406
+ return { data: void 0, error: result2.error };
324
407
  }
325
- if (this.isNavigate && this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
326
- let url;
327
- if (this.navigateBaseRelation) {
328
- url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
329
- } else {
330
- url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;
331
- }
332
- const response2 = await this.context._makeRequest(url, options);
333
- if ((options == null ? void 0 : options.skipValidation) === true) {
334
- const resp = response2;
335
- if (this.singleMode !== false) {
336
- const records = resp.value ?? [resp];
337
- const count = Array.isArray(records) ? records.length : 1;
338
- if (count > 1) {
339
- return {
340
- data: void 0,
341
- error: new Error(
342
- `Expected ${this.singleMode === "exact" ? "exactly one" : "at most one"} record, but received ${count}`
343
- )
344
- };
345
- }
346
- if (count === 0) {
347
- if (this.singleMode === "exact") {
348
- return {
349
- data: void 0,
350
- error: new Error(
351
- "Expected exactly one record, but received none"
352
- )
353
- };
354
- }
355
- return { data: null, error: void 0 };
356
- }
357
- const record = Array.isArray(records) ? records[0] : records;
358
- const stripped = this.stripODataAnnotationsIfNeeded(
359
- record,
360
- options
361
- );
362
- return { data: stripped, error: void 0 };
363
- } else {
364
- const records = resp.value ?? [];
365
- const stripped = records.map(
366
- (record) => this.stripODataAnnotationsIfNeeded(record, options)
367
- );
368
- return { data: stripped, error: void 0 };
369
- }
370
- }
371
- const schema2 = (_b = (_a = this.occurrence) == null ? void 0 : _a.baseTable) == null ? void 0 : _b.schema;
372
- const selectedFields2 = this.queryOptions.select;
373
- const expandValidationConfigs2 = this.buildExpandValidationConfigs(
408
+ let response2 = result2.data;
409
+ const shouldUseIds2 = mergedOptions.useEntityIds ?? false;
410
+ if (((_b = this.occurrence) == null ? void 0 : _b.baseTable) && shouldUseIds2) {
411
+ const expandValidationConfigs3 = this.buildExpandValidationConfigs(
374
412
  this.expandConfigs
375
413
  );
414
+ response2 = transformResponseFields(
415
+ response2,
416
+ this.occurrence.baseTable,
417
+ expandValidationConfigs3
418
+ );
419
+ }
420
+ if ((options == null ? void 0 : options.skipValidation) === true) {
421
+ const resp = response2;
376
422
  if (this.singleMode !== false) {
377
- const validation = await validateSingleResponse(
378
- response2,
379
- schema2,
380
- selectedFields2,
381
- expandValidationConfigs2,
382
- this.singleMode
383
- );
384
- if (!validation.valid) {
385
- return { data: void 0, error: validation.error };
386
- }
387
- const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
388
- return { data: stripped, error: void 0 };
389
- } else {
390
- const validation = await validateListResponse(
391
- response2,
392
- schema2,
393
- selectedFields2,
394
- expandValidationConfigs2
395
- );
396
- if (!validation.valid) {
397
- return { data: void 0, error: validation.error };
423
+ const records = resp.value ?? [resp];
424
+ const count = Array.isArray(records) ? records.length : 1;
425
+ if (count > 1) {
426
+ return {
427
+ data: void 0,
428
+ error: new RecordCountMismatchError(
429
+ this.singleMode === "exact" ? "one" : "at-most-one",
430
+ count
431
+ )
432
+ };
398
433
  }
399
- const stripped = validation.data.map(
400
- (record) => this.stripODataAnnotationsIfNeeded(record, options)
401
- );
402
- return { data: stripped, error: void 0 };
403
- }
404
- }
405
- if (this.isNavigate && !this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
406
- const response2 = await this.context._makeRequest(
407
- `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`,
408
- options
409
- );
410
- if ((options == null ? void 0 : options.skipValidation) === true) {
411
- const resp = response2;
412
- if (this.singleMode !== false) {
413
- const records = resp.value ?? [resp];
414
- const count = Array.isArray(records) ? records.length : 1;
415
- if (count > 1) {
434
+ if (count === 0) {
435
+ if (this.singleMode === "exact") {
416
436
  return {
417
437
  data: void 0,
418
- error: new Error(
419
- `Expected ${this.singleMode === "exact" ? "exactly one" : "at most one"} record, but received ${count}`
420
- )
438
+ error: new RecordCountMismatchError("one", 0)
421
439
  };
422
440
  }
423
- if (count === 0) {
424
- if (this.singleMode === "exact") {
425
- return {
426
- data: void 0,
427
- error: new Error(
428
- "Expected exactly one record, but received none"
429
- )
430
- };
431
- }
432
- return { data: null, error: void 0 };
433
- }
434
- const record = Array.isArray(records) ? records[0] : records;
435
- const stripped = this.stripODataAnnotationsIfNeeded(
436
- record,
437
- options
438
- );
439
- return { data: stripped, error: void 0 };
440
- } else {
441
- const records = resp.value ?? [];
442
- const stripped = records.map(
443
- (record) => this.stripODataAnnotationsIfNeeded(record, options)
444
- );
445
- return { data: stripped, error: void 0 };
446
- }
447
- }
448
- const schema2 = (_d = (_c = this.occurrence) == null ? void 0 : _c.baseTable) == null ? void 0 : _d.schema;
449
- const selectedFields2 = this.queryOptions.select;
450
- const expandValidationConfigs2 = this.buildExpandValidationConfigs(
451
- this.expandConfigs
452
- );
453
- if (this.singleMode !== false) {
454
- const validation = await validateSingleResponse(
455
- response2,
456
- schema2,
457
- selectedFields2,
458
- expandValidationConfigs2,
459
- this.singleMode
460
- );
461
- if (!validation.valid) {
462
- return { data: void 0, error: validation.error };
441
+ return { data: null, error: void 0 };
463
442
  }
464
- const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
443
+ const record = Array.isArray(records) ? records[0] : records;
444
+ const stripped = this.stripODataAnnotationsIfNeeded(record, options);
465
445
  return { data: stripped, error: void 0 };
466
446
  } else {
467
- const validation = await validateListResponse(
468
- response2,
469
- schema2,
470
- selectedFields2,
471
- expandValidationConfigs2
472
- );
473
- if (!validation.valid) {
474
- return { data: void 0, error: validation.error };
475
- }
476
- const stripped = validation.data.map(
447
+ const records = resp.value ?? [];
448
+ const stripped = records.map(
477
449
  (record) => this.stripODataAnnotationsIfNeeded(record, options)
478
450
  );
479
451
  return { data: stripped, error: void 0 };
480
452
  }
481
453
  }
482
- if (this.isCountMode) {
483
- const result = await this.context._makeRequest(
484
- `/${this.databaseName}/${this.tableName}/$count${queryString}`,
485
- options
454
+ const schema2 = (_d = (_c = this.occurrence) == null ? void 0 : _c.baseTable) == null ? void 0 : _d.schema;
455
+ const selectedFields2 = this.queryOptions.select;
456
+ const expandValidationConfigs2 = this.buildExpandValidationConfigs(
457
+ this.expandConfigs
458
+ );
459
+ if (this.singleMode !== false) {
460
+ const validation = await validateSingleResponse(
461
+ response2,
462
+ schema2,
463
+ selectedFields2,
464
+ expandValidationConfigs2,
465
+ this.singleMode
466
+ );
467
+ if (!validation.valid) {
468
+ return { data: void 0, error: validation.error };
469
+ }
470
+ const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
471
+ return { data: stripped, error: void 0 };
472
+ } else {
473
+ const validation = await validateListResponse(
474
+ response2,
475
+ schema2,
476
+ selectedFields2,
477
+ expandValidationConfigs2
478
+ );
479
+ if (!validation.valid) {
480
+ return { data: void 0, error: validation.error };
481
+ }
482
+ const stripped = validation.data.map(
483
+ (record) => this.stripODataAnnotationsIfNeeded(record, options)
486
484
  );
487
- const count = typeof result === "string" ? Number(result) : result;
488
- return { data: count, error: void 0 };
485
+ return { data: stripped, error: void 0 };
489
486
  }
490
- const response = await this.context._makeRequest(
491
- `/${this.databaseName}/${this.tableName}${queryString}`,
492
- options
487
+ }
488
+ if (this.isNavigate && !this.navigateRecordId && this.navigateRelation && this.navigateSourceTableName) {
489
+ const result2 = await this.context._makeRequest(
490
+ `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`,
491
+ mergedOptions
493
492
  );
493
+ if (result2.error) {
494
+ return { data: void 0, error: result2.error };
495
+ }
496
+ let response2 = result2.data;
497
+ const shouldUseIds2 = mergedOptions.useEntityIds ?? false;
498
+ if (((_e = this.occurrence) == null ? void 0 : _e.baseTable) && shouldUseIds2) {
499
+ const expandValidationConfigs3 = this.buildExpandValidationConfigs(
500
+ this.expandConfigs
501
+ );
502
+ response2 = transformResponseFields(
503
+ response2,
504
+ this.occurrence.baseTable,
505
+ expandValidationConfigs3
506
+ );
507
+ }
494
508
  if ((options == null ? void 0 : options.skipValidation) === true) {
495
- const resp = response;
509
+ const resp = response2;
496
510
  if (this.singleMode !== false) {
497
511
  const records = resp.value ?? [resp];
498
512
  const count = Array.isArray(records) ? records.length : 1;
499
513
  if (count > 1) {
500
514
  return {
501
515
  data: void 0,
502
- error: new Error(
503
- `Expected ${this.singleMode === "exact" ? "exactly one" : "at most one"} record, but received ${count}`
516
+ error: new RecordCountMismatchError(
517
+ this.singleMode === "exact" ? "one" : "at-most-one",
518
+ count
504
519
  )
505
520
  };
506
521
  }
@@ -508,9 +523,7 @@ class QueryBuilder {
508
523
  if (this.singleMode === "exact") {
509
524
  return {
510
525
  data: void 0,
511
- error: new Error(
512
- "Expected exactly one record, but received none"
513
- )
526
+ error: new RecordCountMismatchError("one", 0)
514
527
  };
515
528
  }
516
529
  return { data: null, error: void 0 };
@@ -526,33 +539,30 @@ class QueryBuilder {
526
539
  return { data: stripped, error: void 0 };
527
540
  }
528
541
  }
529
- const schema = (_f = (_e = this.occurrence) == null ? void 0 : _e.baseTable) == null ? void 0 : _f.schema;
530
- const selectedFields = this.queryOptions.select;
531
- const expandValidationConfigs = this.buildExpandValidationConfigs(
542
+ const schema2 = (_g = (_f = this.occurrence) == null ? void 0 : _f.baseTable) == null ? void 0 : _g.schema;
543
+ const selectedFields2 = this.queryOptions.select;
544
+ const expandValidationConfigs2 = this.buildExpandValidationConfigs(
532
545
  this.expandConfigs
533
546
  );
534
547
  if (this.singleMode !== false) {
535
548
  const validation = await validateSingleResponse(
536
- response,
537
- schema,
538
- selectedFields,
539
- expandValidationConfigs,
549
+ response2,
550
+ schema2,
551
+ selectedFields2,
552
+ expandValidationConfigs2,
540
553
  this.singleMode
541
554
  );
542
555
  if (!validation.valid) {
543
556
  return { data: void 0, error: validation.error };
544
557
  }
545
558
  const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
546
- return {
547
- data: stripped,
548
- error: void 0
549
- };
559
+ return { data: stripped, error: void 0 };
550
560
  } else {
551
561
  const validation = await validateListResponse(
552
- response,
553
- schema,
554
- selectedFields,
555
- expandValidationConfigs
562
+ response2,
563
+ schema2,
564
+ selectedFields2,
565
+ expandValidationConfigs2
556
566
  );
557
567
  if (!validation.valid) {
558
568
  return { data: void 0, error: validation.error };
@@ -560,24 +570,123 @@ class QueryBuilder {
560
570
  const stripped = validation.data.map(
561
571
  (record) => this.stripODataAnnotationsIfNeeded(record, options)
562
572
  );
563
- return {
564
- data: stripped,
565
- error: void 0
566
- };
573
+ return { data: stripped, error: void 0 };
574
+ }
575
+ }
576
+ if (this.isCountMode) {
577
+ const tableId2 = this.getTableId(mergedOptions.useEntityIds);
578
+ const result2 = await this.context._makeRequest(
579
+ `/${this.databaseName}/${tableId2}/$count${queryString}`,
580
+ mergedOptions
581
+ );
582
+ if (result2.error) {
583
+ return { data: void 0, error: result2.error };
584
+ }
585
+ const count = typeof result2.data === "string" ? Number(result2.data) : result2.data;
586
+ return { data: count, error: void 0 };
587
+ }
588
+ const tableId = this.getTableId(mergedOptions.useEntityIds);
589
+ const result = await this.context._makeRequest(
590
+ `/${this.databaseName}/${tableId}${queryString}`,
591
+ mergedOptions
592
+ );
593
+ if (result.error) {
594
+ return { data: void 0, error: result.error };
595
+ }
596
+ let response = result.data;
597
+ const shouldUseIds = mergedOptions.useEntityIds ?? false;
598
+ if (((_h = this.occurrence) == null ? void 0 : _h.baseTable) && shouldUseIds) {
599
+ const expandValidationConfigs2 = this.buildExpandValidationConfigs(
600
+ this.expandConfigs
601
+ );
602
+ response = transformResponseFields(
603
+ response,
604
+ this.occurrence.baseTable,
605
+ expandValidationConfigs2
606
+ );
607
+ }
608
+ if ((options == null ? void 0 : options.skipValidation) === true) {
609
+ const resp = response;
610
+ if (this.singleMode !== false) {
611
+ const records = resp.value ?? [resp];
612
+ const count = Array.isArray(records) ? records.length : 1;
613
+ if (count > 1) {
614
+ return {
615
+ data: void 0,
616
+ error: new RecordCountMismatchError(
617
+ this.singleMode === "exact" ? "one" : "at-most-one",
618
+ count
619
+ )
620
+ };
621
+ }
622
+ if (count === 0) {
623
+ if (this.singleMode === "exact") {
624
+ return {
625
+ data: void 0,
626
+ error: new RecordCountMismatchError("one", 0)
627
+ };
628
+ }
629
+ return { data: null, error: void 0 };
630
+ }
631
+ const record = Array.isArray(records) ? records[0] : records;
632
+ const stripped = this.stripODataAnnotationsIfNeeded(record, options);
633
+ return { data: stripped, error: void 0 };
634
+ } else {
635
+ const records = resp.value ?? [];
636
+ const stripped = records.map(
637
+ (record) => this.stripODataAnnotationsIfNeeded(record, options)
638
+ );
639
+ return { data: stripped, error: void 0 };
640
+ }
641
+ }
642
+ const schema = (_j = (_i = this.occurrence) == null ? void 0 : _i.baseTable) == null ? void 0 : _j.schema;
643
+ const selectedFields = this.queryOptions.select;
644
+ const expandValidationConfigs = this.buildExpandValidationConfigs(
645
+ this.expandConfigs
646
+ );
647
+ if (this.singleMode !== false) {
648
+ const validation = await validateSingleResponse(
649
+ response,
650
+ schema,
651
+ selectedFields,
652
+ expandValidationConfigs,
653
+ this.singleMode
654
+ );
655
+ if (!validation.valid) {
656
+ return { data: void 0, error: validation.error };
567
657
  }
568
- } catch (error) {
658
+ const stripped = validation.data ? this.stripODataAnnotationsIfNeeded(validation.data, options) : null;
569
659
  return {
570
- data: void 0,
571
- error: error instanceof Error ? error : new Error(String(error))
660
+ data: stripped,
661
+ error: void 0
662
+ };
663
+ } else {
664
+ const validation = await validateListResponse(
665
+ response,
666
+ schema,
667
+ selectedFields,
668
+ expandValidationConfigs
669
+ );
670
+ if (!validation.valid) {
671
+ return { data: void 0, error: validation.error };
672
+ }
673
+ const stripped = validation.data.map(
674
+ (record) => this.stripODataAnnotationsIfNeeded(record, options)
675
+ );
676
+ return {
677
+ data: stripped,
678
+ error: void 0
572
679
  };
573
680
  }
574
681
  }
575
682
  getQueryString() {
683
+ var _a;
576
684
  const queryOptionsWithoutExpand = { ...this.queryOptions };
577
685
  delete queryOptionsWithoutExpand.expand;
578
686
  if (queryOptionsWithoutExpand.select) {
579
687
  queryOptionsWithoutExpand.select = this.formatSelectFields(
580
- queryOptionsWithoutExpand.select
688
+ queryOptionsWithoutExpand.select,
689
+ (_a = this.occurrence) == null ? void 0 : _a.baseTable
581
690
  );
582
691
  }
583
692
  let queryParams = buildQuery(queryOptionsWithoutExpand);
@@ -610,11 +719,13 @@ class QueryBuilder {
610
719
  return `/${this.tableName}${queryParams}`;
611
720
  }
612
721
  getRequestConfig() {
722
+ var _a;
613
723
  const queryOptionsWithoutExpand = { ...this.queryOptions };
614
724
  delete queryOptionsWithoutExpand.expand;
615
725
  if (queryOptionsWithoutExpand.select) {
616
726
  queryOptionsWithoutExpand.select = this.formatSelectFields(
617
- queryOptionsWithoutExpand.select
727
+ queryOptionsWithoutExpand.select,
728
+ (_a = this.occurrence) == null ? void 0 : _a.baseTable
618
729
  );
619
730
  }
620
731
  let queryString = buildQuery(queryOptionsWithoutExpand);
@@ -642,6 +753,142 @@ class QueryBuilder {
642
753
  url
643
754
  };
644
755
  }
756
+ toRequest(baseUrl) {
757
+ const config = this.getRequestConfig();
758
+ const fullUrl = `${baseUrl}${config.url}`;
759
+ return new Request(fullUrl, {
760
+ method: config.method,
761
+ headers: {
762
+ "Content-Type": "application/json",
763
+ Accept: "application/json"
764
+ }
765
+ });
766
+ }
767
+ async processResponse(response, options) {
768
+ var _a, _b, _c;
769
+ if (response.status === 204) {
770
+ if (this.singleMode !== false) {
771
+ if (this.singleMode === "maybe") {
772
+ return { data: null, error: void 0 };
773
+ }
774
+ return {
775
+ data: void 0,
776
+ error: new RecordCountMismatchError("one", 0)
777
+ };
778
+ }
779
+ return { data: [], error: void 0 };
780
+ }
781
+ let rawData;
782
+ try {
783
+ rawData = await response.json();
784
+ } catch (err) {
785
+ if (err instanceof SyntaxError && response.status === 204) {
786
+ return { data: [], error: void 0 };
787
+ }
788
+ return {
789
+ data: void 0,
790
+ error: {
791
+ name: "ResponseParseError",
792
+ message: `Failed to parse response JSON: ${err instanceof Error ? err.message : "Unknown error"}`,
793
+ timestamp: /* @__PURE__ */ new Date()
794
+ }
795
+ };
796
+ }
797
+ if (!rawData) {
798
+ return {
799
+ data: void 0,
800
+ error: {
801
+ name: "ResponseError",
802
+ message: "Response body was empty or null",
803
+ timestamp: /* @__PURE__ */ new Date()
804
+ }
805
+ };
806
+ }
807
+ const shouldUseIds = (options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds;
808
+ let transformedData = rawData;
809
+ if (((_a = this.occurrence) == null ? void 0 : _a.baseTable) && shouldUseIds) {
810
+ const expandValidationConfigs2 = this.buildExpandValidationConfigs(
811
+ this.expandConfigs
812
+ );
813
+ transformedData = transformResponseFields(
814
+ rawData,
815
+ this.occurrence.baseTable,
816
+ expandValidationConfigs2
817
+ );
818
+ }
819
+ if ((options == null ? void 0 : options.skipValidation) === true) {
820
+ const resp = transformedData;
821
+ if (this.singleMode !== false) {
822
+ const records = resp.value ?? [resp];
823
+ const count = Array.isArray(records) ? records.length : 1;
824
+ if (count > 1) {
825
+ return {
826
+ data: void 0,
827
+ error: new RecordCountMismatchError(
828
+ this.singleMode === "exact" ? "one" : "at-most-one",
829
+ count
830
+ )
831
+ };
832
+ }
833
+ if (count === 0) {
834
+ if (this.singleMode === "exact") {
835
+ return {
836
+ data: void 0,
837
+ error: new RecordCountMismatchError("one", 0)
838
+ };
839
+ }
840
+ return { data: null, error: void 0 };
841
+ }
842
+ const record = Array.isArray(records) ? records[0] : records;
843
+ const stripped2 = this.stripODataAnnotationsIfNeeded(record, options);
844
+ return { data: stripped2, error: void 0 };
845
+ } else {
846
+ const records = resp.value ?? [];
847
+ const stripped2 = records.map(
848
+ (record) => this.stripODataAnnotationsIfNeeded(record, options)
849
+ );
850
+ return { data: stripped2, error: void 0 };
851
+ }
852
+ }
853
+ const schema = (_c = (_b = this.occurrence) == null ? void 0 : _b.baseTable) == null ? void 0 : _c.schema;
854
+ const selectedFields = this.queryOptions.select;
855
+ const expandValidationConfigs = this.buildExpandValidationConfigs(
856
+ this.expandConfigs
857
+ );
858
+ if (this.singleMode !== false) {
859
+ const validation2 = await validateSingleResponse(
860
+ transformedData,
861
+ schema,
862
+ selectedFields,
863
+ expandValidationConfigs,
864
+ this.singleMode
865
+ );
866
+ if (!validation2.valid) {
867
+ return { data: void 0, error: validation2.error };
868
+ }
869
+ if (validation2.data === null) {
870
+ return { data: null, error: void 0 };
871
+ }
872
+ const stripped2 = this.stripODataAnnotationsIfNeeded(
873
+ validation2.data,
874
+ options
875
+ );
876
+ return { data: stripped2, error: void 0 };
877
+ }
878
+ const validation = await validateListResponse(
879
+ transformedData,
880
+ schema,
881
+ selectedFields,
882
+ expandValidationConfigs
883
+ );
884
+ if (!validation.valid) {
885
+ return { data: void 0, error: validation.error };
886
+ }
887
+ const stripped = validation.data.map(
888
+ (record) => this.stripODataAnnotationsIfNeeded(record, options)
889
+ );
890
+ return { data: stripped, error: void 0 };
891
+ }
645
892
  }
646
893
  export {
647
894
  QueryBuilder