@proofkit/fmodata 0.1.0-alpha.8 → 0.1.0-beta.23

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 (163) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +651 -449
  3. package/dist/esm/client/batch-builder.d.ts +10 -9
  4. package/dist/esm/client/batch-builder.js +119 -56
  5. package/dist/esm/client/batch-builder.js.map +1 -1
  6. package/dist/esm/client/batch-request.js +16 -21
  7. package/dist/esm/client/batch-request.js.map +1 -1
  8. package/dist/esm/client/builders/default-select.d.ts +10 -0
  9. package/dist/esm/client/builders/default-select.js +41 -0
  10. package/dist/esm/client/builders/default-select.js.map +1 -0
  11. package/dist/esm/client/builders/expand-builder.d.ts +45 -0
  12. package/dist/esm/client/builders/expand-builder.js +185 -0
  13. package/dist/esm/client/builders/expand-builder.js.map +1 -0
  14. package/dist/esm/client/builders/index.d.ts +9 -0
  15. package/dist/esm/client/builders/query-string-builder.d.ts +18 -0
  16. package/dist/esm/client/builders/query-string-builder.js +21 -0
  17. package/dist/esm/client/builders/query-string-builder.js.map +1 -0
  18. package/dist/esm/client/builders/response-processor.d.ts +43 -0
  19. package/dist/esm/client/builders/response-processor.js +175 -0
  20. package/dist/esm/client/builders/response-processor.js.map +1 -0
  21. package/dist/esm/client/builders/select-mixin.d.ts +25 -0
  22. package/dist/esm/client/builders/select-mixin.js +28 -0
  23. package/dist/esm/client/builders/select-mixin.js.map +1 -0
  24. package/dist/esm/client/builders/select-utils.d.ts +18 -0
  25. package/dist/esm/client/builders/select-utils.js +30 -0
  26. package/dist/esm/client/builders/select-utils.js.map +1 -0
  27. package/dist/esm/client/builders/shared-types.d.ts +40 -0
  28. package/dist/esm/client/builders/table-utils.d.ts +35 -0
  29. package/dist/esm/client/builders/table-utils.js +44 -0
  30. package/dist/esm/client/builders/table-utils.js.map +1 -0
  31. package/dist/esm/client/database.d.ts +34 -22
  32. package/dist/esm/client/database.js +48 -84
  33. package/dist/esm/client/database.js.map +1 -1
  34. package/dist/esm/client/delete-builder.d.ts +25 -30
  35. package/dist/esm/client/delete-builder.js +45 -30
  36. package/dist/esm/client/delete-builder.js.map +1 -1
  37. package/dist/esm/client/entity-set.d.ts +35 -43
  38. package/dist/esm/client/entity-set.js +110 -52
  39. package/dist/esm/client/entity-set.js.map +1 -1
  40. package/dist/esm/client/error-parser.d.ts +12 -0
  41. package/dist/esm/client/error-parser.js +25 -0
  42. package/dist/esm/client/error-parser.js.map +1 -0
  43. package/dist/esm/client/filemaker-odata.d.ts +26 -7
  44. package/dist/esm/client/filemaker-odata.js +65 -42
  45. package/dist/esm/client/filemaker-odata.js.map +1 -1
  46. package/dist/esm/client/insert-builder.d.ts +19 -24
  47. package/dist/esm/client/insert-builder.js +94 -58
  48. package/dist/esm/client/insert-builder.js.map +1 -1
  49. package/dist/esm/client/query/expand-builder.d.ts +35 -0
  50. package/dist/esm/client/query/index.d.ts +4 -0
  51. package/dist/esm/client/query/query-builder.d.ts +132 -0
  52. package/dist/esm/client/query/query-builder.js +456 -0
  53. package/dist/esm/client/query/query-builder.js.map +1 -0
  54. package/dist/esm/client/query/response-processor.d.ts +25 -0
  55. package/dist/esm/client/query/types.d.ts +77 -0
  56. package/dist/esm/client/query/url-builder.d.ts +71 -0
  57. package/dist/esm/client/query/url-builder.js +100 -0
  58. package/dist/esm/client/query/url-builder.js.map +1 -0
  59. package/dist/esm/client/query-builder.d.ts +2 -115
  60. package/dist/esm/client/record-builder.d.ts +108 -36
  61. package/dist/esm/client/record-builder.js +284 -119
  62. package/dist/esm/client/record-builder.js.map +1 -1
  63. package/dist/esm/client/response-processor.d.ts +4 -9
  64. package/dist/esm/client/sanitize-json.d.ts +35 -0
  65. package/dist/esm/client/sanitize-json.js +27 -0
  66. package/dist/esm/client/sanitize-json.js.map +1 -0
  67. package/dist/esm/client/schema-manager.d.ts +5 -5
  68. package/dist/esm/client/schema-manager.js +45 -31
  69. package/dist/esm/client/schema-manager.js.map +1 -1
  70. package/dist/esm/client/update-builder.d.ts +34 -40
  71. package/dist/esm/client/update-builder.js +99 -58
  72. package/dist/esm/client/update-builder.js.map +1 -1
  73. package/dist/esm/client/webhook-builder.d.ts +126 -0
  74. package/dist/esm/client/webhook-builder.js +189 -0
  75. package/dist/esm/client/webhook-builder.js.map +1 -0
  76. package/dist/esm/errors.d.ts +19 -2
  77. package/dist/esm/errors.js +39 -4
  78. package/dist/esm/errors.js.map +1 -1
  79. package/dist/esm/index.d.ts +10 -8
  80. package/dist/esm/index.js +40 -10
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/esm/logger.d.ts +47 -0
  83. package/dist/esm/logger.js +69 -0
  84. package/dist/esm/logger.js.map +1 -0
  85. package/dist/esm/logger.test.d.ts +1 -0
  86. package/dist/esm/orm/column.d.ts +62 -0
  87. package/dist/esm/orm/column.js +63 -0
  88. package/dist/esm/orm/column.js.map +1 -0
  89. package/dist/esm/orm/field-builders.d.ts +164 -0
  90. package/dist/esm/orm/field-builders.js +158 -0
  91. package/dist/esm/orm/field-builders.js.map +1 -0
  92. package/dist/esm/orm/index.d.ts +5 -0
  93. package/dist/esm/orm/operators.d.ts +173 -0
  94. package/dist/esm/orm/operators.js +260 -0
  95. package/dist/esm/orm/operators.js.map +1 -0
  96. package/dist/esm/orm/table.d.ts +355 -0
  97. package/dist/esm/orm/table.js +202 -0
  98. package/dist/esm/orm/table.js.map +1 -0
  99. package/dist/esm/transform.d.ts +20 -21
  100. package/dist/esm/transform.js +44 -45
  101. package/dist/esm/transform.js.map +1 -1
  102. package/dist/esm/types.d.ts +96 -30
  103. package/dist/esm/types.js +7 -0
  104. package/dist/esm/types.js.map +1 -0
  105. package/dist/esm/validation.d.ts +22 -12
  106. package/dist/esm/validation.js +132 -85
  107. package/dist/esm/validation.js.map +1 -1
  108. package/package.json +28 -20
  109. package/src/client/batch-builder.ts +153 -89
  110. package/src/client/batch-request.ts +25 -41
  111. package/src/client/builders/default-select.ts +75 -0
  112. package/src/client/builders/expand-builder.ts +246 -0
  113. package/src/client/builders/index.ts +11 -0
  114. package/src/client/builders/query-string-builder.ts +46 -0
  115. package/src/client/builders/response-processor.ts +279 -0
  116. package/src/client/builders/select-mixin.ts +65 -0
  117. package/src/client/builders/select-utils.ts +59 -0
  118. package/src/client/builders/shared-types.ts +45 -0
  119. package/src/client/builders/table-utils.ts +83 -0
  120. package/src/client/database.ts +89 -183
  121. package/src/client/delete-builder.ts +74 -84
  122. package/src/client/entity-set.ts +266 -293
  123. package/src/client/error-parser.ts +41 -0
  124. package/src/client/filemaker-odata.ts +98 -66
  125. package/src/client/insert-builder.ts +157 -118
  126. package/src/client/query/expand-builder.ts +160 -0
  127. package/src/client/query/index.ts +14 -0
  128. package/src/client/query/query-builder.ts +729 -0
  129. package/src/client/query/response-processor.ts +226 -0
  130. package/src/client/query/types.ts +126 -0
  131. package/src/client/query/url-builder.ts +151 -0
  132. package/src/client/query-builder.ts +10 -1455
  133. package/src/client/record-builder.ts +575 -240
  134. package/src/client/response-processor.ts +15 -42
  135. package/src/client/sanitize-json.ts +64 -0
  136. package/src/client/schema-manager.ts +61 -76
  137. package/src/client/update-builder.ts +161 -143
  138. package/src/client/webhook-builder.ts +265 -0
  139. package/src/errors.ts +49 -16
  140. package/src/index.ts +99 -54
  141. package/src/logger.test.ts +34 -0
  142. package/src/logger.ts +116 -0
  143. package/src/orm/column.ts +106 -0
  144. package/src/orm/field-builders.ts +250 -0
  145. package/src/orm/index.ts +61 -0
  146. package/src/orm/operators.ts +473 -0
  147. package/src/orm/table.ts +741 -0
  148. package/src/transform.ts +90 -70
  149. package/src/types.ts +154 -113
  150. package/src/validation.ts +200 -115
  151. package/dist/esm/client/base-table.d.ts +0 -125
  152. package/dist/esm/client/base-table.js +0 -57
  153. package/dist/esm/client/base-table.js.map +0 -1
  154. package/dist/esm/client/query-builder.js +0 -896
  155. package/dist/esm/client/query-builder.js.map +0 -1
  156. package/dist/esm/client/table-occurrence.d.ts +0 -72
  157. package/dist/esm/client/table-occurrence.js +0 -74
  158. package/dist/esm/client/table-occurrence.js.map +0 -1
  159. package/dist/esm/filter-types.d.ts +0 -76
  160. package/src/client/base-table.ts +0 -166
  161. package/src/client/query-builder.ts.bak +0 -1457
  162. package/src/client/table-occurrence.ts +0 -175
  163. package/src/filter-types.ts +0 -97
@@ -1,36 +1,56 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { getTableIdentifiers, transformTableName, transformResponseFields } from "../transform.js";
5
- import { QueryBuilder } from "./query-builder.js";
6
- import { validateSingleResponse } from "../validation.js";
4
+ import { createLogger } from "../logger.js";
5
+ import { getTableName, getNavigationPaths } from "../orm/table.js";
6
+ import { ExpandBuilder } from "./builders/expand-builder.js";
7
+ import { buildSelectExpandQueryString } from "./builders/query-string-builder.js";
8
+ import { processODataResponse, getSchemaFromTable } from "./builders/response-processor.js";
9
+ import { processSelectWithRenames } from "./builders/select-mixin.js";
10
+ import { mergeExecuteOptions, resolveTableId, createODataRequest } from "./builders/table-utils.js";
11
+ import { parseErrorResponse } from "./error-parser.js";
12
+ import { QueryBuilder } from "./query/query-builder.js";
13
+ import { safeJsonParse } from "./sanitize-json.js";
7
14
  class RecordBuilder {
8
15
  constructor(config) {
9
- __publicField(this, "occurrence");
10
- __publicField(this, "tableName");
16
+ __publicField(this, "table");
11
17
  __publicField(this, "databaseName");
12
18
  __publicField(this, "context");
13
19
  __publicField(this, "recordId");
14
20
  __publicField(this, "operation");
15
21
  __publicField(this, "operationParam");
22
+ // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration
23
+ __publicField(this, "operationColumn");
16
24
  __publicField(this, "isNavigateFromEntitySet");
17
25
  __publicField(this, "navigateRelation");
18
26
  __publicField(this, "navigateSourceTableName");
19
27
  __publicField(this, "databaseUseEntityIds");
20
- this.occurrence = config.occurrence;
21
- this.tableName = config.tableName;
28
+ __publicField(this, "databaseIncludeSpecialColumns");
29
+ // Properties for select/expand support
30
+ __publicField(this, "selectedFields");
31
+ __publicField(this, "expandConfigs", []);
32
+ // Mapping from field names to output keys (for renamed fields in select)
33
+ __publicField(this, "fieldMapping");
34
+ // System columns requested via select() second argument
35
+ __publicField(this, "systemColumns");
36
+ __publicField(this, "logger");
37
+ var _a, _b;
38
+ this.table = config.occurrence;
22
39
  this.databaseName = config.databaseName;
23
40
  this.context = config.context;
24
41
  this.recordId = config.recordId;
25
42
  this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;
43
+ this.databaseIncludeSpecialColumns = config.databaseIncludeSpecialColumns ?? false;
44
+ this.logger = ((_b = (_a = config.context) == null ? void 0 : _a._getLogger) == null ? void 0 : _b.call(_a)) ?? createLogger();
26
45
  }
27
46
  /**
28
- * Helper to merge database-level useEntityIds with per-request options
47
+ * Helper to merge database-level useEntityIds and includeSpecialColumns with per-request options
29
48
  */
30
49
  mergeExecuteOptions(options) {
50
+ const merged = mergeExecuteOptions(options, this.databaseUseEntityIds);
31
51
  return {
32
- ...options,
33
- useEntityIds: (options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds
52
+ ...merged,
53
+ includeSpecialColumns: (options == null ? void 0 : options.includeSpecialColumns) ?? this.databaseIncludeSpecialColumns
34
54
  };
35
55
  }
36
56
  /**
@@ -38,63 +58,209 @@ class RecordBuilder {
38
58
  * @param useEntityIds - Optional override for entity ID usage
39
59
  */
40
60
  getTableId(useEntityIds) {
41
- var _a, _b;
42
- if (!this.occurrence) {
43
- return this.tableName;
44
- }
45
- const contextDefault = ((_b = (_a = this.context)._getUseEntityIds) == null ? void 0 : _b.call(_a)) ?? false;
46
- const shouldUseIds = useEntityIds ?? contextDefault;
47
- if (shouldUseIds) {
48
- const identifiers = getTableIdentifiers(this.occurrence);
49
- if (!identifiers.id) {
50
- throw new Error(
51
- `useEntityIds is true but TableOccurrence "${identifiers.name}" does not have an fmtId defined`
52
- );
53
- }
54
- return identifiers.id;
61
+ if (!this.table) {
62
+ throw new Error("Table occurrence is required");
55
63
  }
56
- return this.occurrence.getTableName();
64
+ return resolveTableId(this.table, getTableName(this.table), this.context, useEntityIds);
57
65
  }
58
- getSingleField(field) {
66
+ /**
67
+ * Creates a new RecordBuilder with modified configuration.
68
+ * Used by select() to create new instances.
69
+ */
70
+ cloneWithChanges(changes) {
59
71
  const newBuilder = new RecordBuilder({
60
- occurrence: this.occurrence,
61
- tableName: this.tableName,
72
+ occurrence: this.table,
62
73
  databaseName: this.databaseName,
63
74
  context: this.context,
64
- recordId: this.recordId
75
+ recordId: this.recordId,
76
+ databaseUseEntityIds: this.databaseUseEntityIds,
77
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
65
78
  });
66
- newBuilder.operation = "getSingleField";
67
- newBuilder.operationParam = field.toString();
68
- newBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;
69
- newBuilder.navigateRelation = this.navigateRelation;
70
- newBuilder.navigateSourceTableName = this.navigateSourceTableName;
79
+ const mutableBuilder = newBuilder;
80
+ mutableBuilder.selectedFields = changes.selectedFields ?? this.selectedFields;
81
+ mutableBuilder.fieldMapping = changes.fieldMapping ?? this.fieldMapping;
82
+ mutableBuilder.systemColumns = changes.systemColumns !== void 0 ? changes.systemColumns : this.systemColumns;
83
+ mutableBuilder.expandConfigs = [...this.expandConfigs];
84
+ mutableBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;
85
+ mutableBuilder.navigateRelation = this.navigateRelation;
86
+ mutableBuilder.navigateSourceTableName = this.navigateSourceTableName;
87
+ mutableBuilder.operationColumn = this.operationColumn;
71
88
  return newBuilder;
72
89
  }
73
- // Implementation
74
- navigate(relationName) {
75
- var _a;
76
- const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[relationName];
90
+ // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration
91
+ getSingleField(column) {
92
+ const tableName = getTableName(this.table);
93
+ if (!column.isFromTable(tableName)) {
94
+ throw new Error(`Column ${column.toString()} is not from table ${tableName}`);
95
+ }
96
+ const newBuilder = new RecordBuilder({
97
+ occurrence: this.table,
98
+ databaseName: this.databaseName,
99
+ context: this.context,
100
+ recordId: this.recordId,
101
+ databaseUseEntityIds: this.databaseUseEntityIds,
102
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
103
+ });
104
+ const mutableBuilder = newBuilder;
105
+ mutableBuilder.operation = "getSingleField";
106
+ mutableBuilder.operationColumn = column;
107
+ mutableBuilder.operationParam = column.getFieldIdentifier(this.databaseUseEntityIds);
108
+ mutableBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;
109
+ mutableBuilder.navigateRelation = this.navigateRelation;
110
+ mutableBuilder.navigateSourceTableName = this.navigateSourceTableName;
111
+ return newBuilder;
112
+ }
113
+ /**
114
+ * Select fields using column references.
115
+ * Allows renaming fields by using different keys in the object.
116
+ * Container fields cannot be selected and will cause a type error.
117
+ *
118
+ * @example
119
+ * db.from(contacts).get("uuid").select({
120
+ * name: contacts.name,
121
+ * userEmail: contacts.email // renamed!
122
+ * })
123
+ *
124
+ * @example
125
+ * // Include system columns (ROWID, ROWMODID) when using select()
126
+ * db.from(contacts).get("uuid").select(
127
+ * { name: contacts.name },
128
+ * { ROWID: true, ROWMODID: true }
129
+ * )
130
+ *
131
+ * @param fields - Object mapping output keys to column references (container fields excluded)
132
+ * @param systemColumns - Optional object to request system columns (ROWID, ROWMODID)
133
+ * @returns RecordBuilder with updated selected fields
134
+ */
135
+ select(fields, systemColumns) {
136
+ const tableName = getTableName(this.table);
137
+ const { selectedFields, fieldMapping } = processSelectWithRenames(fields, tableName, this.logger);
138
+ const finalSelectedFields = [...selectedFields];
139
+ if (systemColumns == null ? void 0 : systemColumns.ROWID) {
140
+ finalSelectedFields.push("ROWID");
141
+ }
142
+ if (systemColumns == null ? void 0 : systemColumns.ROWMODID) {
143
+ finalSelectedFields.push("ROWMODID");
144
+ }
145
+ return this.cloneWithChanges({
146
+ selectedFields: finalSelectedFields,
147
+ fieldMapping: Object.keys(fieldMapping).length > 0 ? fieldMapping : void 0,
148
+ // biome-ignore lint/suspicious/noExplicitAny: Type assertion for generic type parameter
149
+ systemColumns
150
+ // biome-ignore lint/suspicious/noExplicitAny: Type assertion for complex generic return type
151
+ });
152
+ }
153
+ /**
154
+ * Expand a navigation property to include related records.
155
+ * Supports nested select, filter, orderBy, and expand operations.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * // Simple expand with FMTable object
160
+ * const contact = await db.from(contacts).get("uuid").expand(users).execute();
161
+ *
162
+ * // Expand with select
163
+ * const contact = await db.from(contacts).get("uuid")
164
+ * .expand(users, b => b.select({ username: users.username, email: users.email }))
165
+ * .execute();
166
+ * ```
167
+ */
168
+ expand(targetTable, callback) {
169
+ const newBuilder = new RecordBuilder({
170
+ occurrence: this.table,
171
+ databaseName: this.databaseName,
172
+ context: this.context,
173
+ recordId: this.recordId,
174
+ databaseUseEntityIds: this.databaseUseEntityIds,
175
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
176
+ });
177
+ const mutableBuilder = newBuilder;
178
+ mutableBuilder.selectedFields = this.selectedFields;
179
+ mutableBuilder.fieldMapping = this.fieldMapping;
180
+ mutableBuilder.systemColumns = this.systemColumns;
181
+ mutableBuilder.expandConfigs = [...this.expandConfigs];
182
+ mutableBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;
183
+ mutableBuilder.navigateRelation = this.navigateRelation;
184
+ mutableBuilder.navigateSourceTableName = this.navigateSourceTableName;
185
+ mutableBuilder.operationColumn = this.operationColumn;
186
+ const expandBuilder = new ExpandBuilder(this.databaseUseEntityIds, this.logger);
187
+ const expandConfig = expandBuilder.processExpand(
188
+ targetTable,
189
+ this.table ?? void 0,
190
+ callback,
191
+ () => (
192
+ // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any QueryBuilder configuration
193
+ new QueryBuilder({
194
+ occurrence: targetTable,
195
+ databaseName: this.databaseName,
196
+ context: this.context,
197
+ databaseUseEntityIds: this.databaseUseEntityIds,
198
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
199
+ })
200
+ )
201
+ );
202
+ mutableBuilder.expandConfigs.push(expandConfig);
203
+ return newBuilder;
204
+ }
205
+ // biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration
206
+ navigate(targetTable) {
207
+ const relationName = getTableName(targetTable);
208
+ if (this.table) {
209
+ const navigationPaths = getNavigationPaths(this.table);
210
+ if (navigationPaths && !navigationPaths.includes(relationName)) {
211
+ this.logger.warn(
212
+ `Cannot navigate to "${relationName}". Valid navigation paths: ${navigationPaths.length > 0 ? navigationPaths.join(", ") : "none"}`
213
+ );
214
+ }
215
+ }
77
216
  const builder = new QueryBuilder({
78
- occurrence: targetOccurrence,
79
- tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relationName,
217
+ occurrence: targetTable,
80
218
  databaseName: this.databaseName,
81
- context: this.context
219
+ context: this.context,
220
+ databaseUseEntityIds: this.databaseUseEntityIds,
221
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
82
222
  });
83
- const relationId = targetOccurrence ? transformTableName(targetOccurrence) : relationName;
84
- builder.isNavigate = true;
85
- builder.navigateRecordId = this.recordId;
86
- builder.navigateRelation = relationId;
223
+ const relationId = relationName;
224
+ let sourceTableName;
225
+ let baseRelation;
87
226
  if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
88
- builder.navigateSourceTableName = this.navigateSourceTableName;
89
- builder.navigateBaseRelation = this.navigateRelation;
227
+ sourceTableName = this.navigateSourceTableName;
228
+ baseRelation = this.navigateRelation;
90
229
  } else {
91
- const sourceTableId = this.occurrence ? transformTableName(this.occurrence) : this.tableName;
92
- builder.navigateSourceTableName = sourceTableId;
230
+ if (!this.table) {
231
+ throw new Error("Table occurrence is required for navigation");
232
+ }
233
+ sourceTableName = resolveTableId(this.table, getTableName(this.table), this.context, this.databaseUseEntityIds);
93
234
  }
235
+ builder.navigation = {
236
+ recordId: this.recordId,
237
+ relation: relationId,
238
+ sourceTableName,
239
+ baseRelation
240
+ };
241
+ builder.navigation = {
242
+ recordId: this.recordId,
243
+ relation: relationId,
244
+ sourceTableName,
245
+ baseRelation
246
+ };
94
247
  return builder;
95
248
  }
249
+ /**
250
+ * Builds the complete query string including $select and $expand parameters.
251
+ */
252
+ buildQueryString(includeSpecialColumns, useEntityIds) {
253
+ includeSpecialColumns ?? this.databaseIncludeSpecialColumns;
254
+ const finalUseEntityIds = useEntityIds ?? this.databaseUseEntityIds;
255
+ return buildSelectExpandQueryString({
256
+ selectedFields: this.selectedFields,
257
+ expandConfigs: this.expandConfigs,
258
+ table: this.table,
259
+ useEntityIds: finalUseEntityIds,
260
+ logger: this.logger
261
+ });
262
+ }
96
263
  async execute(options) {
97
- var _a, _b, _c;
98
264
  let url;
99
265
  if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
100
266
  url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;
@@ -102,47 +268,37 @@ class RecordBuilder {
102
268
  const tableId = this.getTableId((options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds);
103
269
  url = `/${this.databaseName}/${tableId}('${this.recordId}')`;
104
270
  }
271
+ const mergedOptions = this.mergeExecuteOptions(options);
105
272
  if (this.operation === "getSingleField" && this.operationParam) {
106
273
  url += `/${this.operationParam}`;
274
+ } else {
275
+ const queryString = this.buildQueryString(mergedOptions.includeSpecialColumns, mergedOptions.useEntityIds);
276
+ url += queryString;
107
277
  }
108
- const mergedOptions = this.mergeExecuteOptions(options);
109
278
  const result = await this.context._makeRequest(url, mergedOptions);
110
279
  if (result.error) {
111
280
  return { data: void 0, error: result.error };
112
281
  }
113
- let response = result.data;
282
+ const response = result.data;
114
283
  if (this.operation === "getSingleField") {
115
284
  const fieldResponse = response;
116
285
  return { data: fieldResponse.value, error: void 0 };
117
286
  }
118
- const shouldUseIds = mergedOptions.useEntityIds ?? false;
119
- if (((_a = this.occurrence) == null ? void 0 : _a.baseTable) && shouldUseIds) {
120
- response = transformResponseFields(
121
- response,
122
- this.occurrence.baseTable,
123
- void 0
124
- // No expand configs for simple get
125
- );
126
- }
127
- const schema = (_c = (_b = this.occurrence) == null ? void 0 : _b.baseTable) == null ? void 0 : _c.schema;
128
- const validation = await validateSingleResponse(
129
- response,
130
- schema,
131
- void 0,
132
- // No selected fields for record.get()
133
- void 0,
134
- // No expand configs
135
- "exact"
136
- // Expect exactly one record
137
- );
138
- if (!validation.valid) {
139
- return { data: void 0, error: validation.error };
140
- }
141
- if (validation.data === null) {
142
- return { data: null, error: void 0 };
143
- }
144
- return { data: validation.data, error: void 0 };
287
+ const expandBuilder = new ExpandBuilder(mergedOptions.useEntityIds ?? false, this.logger);
288
+ const expandValidationConfigs = expandBuilder.buildValidationConfigs(this.expandConfigs);
289
+ return processODataResponse(response, {
290
+ table: this.table,
291
+ schema: getSchemaFromTable(this.table),
292
+ singleMode: "exact",
293
+ selectedFields: this.selectedFields,
294
+ expandValidationConfigs,
295
+ skipValidation: options == null ? void 0 : options.skipValidation,
296
+ useEntityIds: mergedOptions.useEntityIds,
297
+ includeSpecialColumns: mergedOptions.includeSpecialColumns,
298
+ fieldMapping: this.fieldMapping
299
+ });
145
300
  }
301
+ // biome-ignore lint/suspicious/noExplicitAny: Request body can be any JSON-serializable value
146
302
  getRequestConfig() {
147
303
  let url;
148
304
  if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
@@ -151,60 +307,69 @@ class RecordBuilder {
151
307
  const tableId = this.getTableId(this.databaseUseEntityIds);
152
308
  url = `/${this.databaseName}/${tableId}('${this.recordId}')`;
153
309
  }
154
- if (this.operation === "getSingleField" && this.operationParam) {
310
+ if (this.operation === "getSingleField" && this.operationColumn) {
311
+ url += `/${this.operationColumn.getFieldIdentifier(this.databaseUseEntityIds)}`;
312
+ } else if (this.operation === "getSingleField" && this.operationParam) {
155
313
  url += `/${this.operationParam}`;
314
+ } else {
315
+ const queryString = this.buildQueryString();
316
+ url += queryString;
156
317
  }
157
318
  return {
158
319
  method: "GET",
159
320
  url
160
321
  };
161
322
  }
162
- toRequest(baseUrl) {
323
+ /**
324
+ * Returns the query string for this record builder (for testing purposes).
325
+ */
326
+ getQueryString(options) {
327
+ const useEntityIds = (options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds;
328
+ let path;
329
+ if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
330
+ path = `/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;
331
+ } else {
332
+ const tableId = this.getTableId(useEntityIds);
333
+ path = `/${tableId}('${this.recordId}')`;
334
+ }
335
+ if (this.operation === "getSingleField" && this.operationColumn) {
336
+ return `${path}/${this.operationColumn.getFieldIdentifier(useEntityIds)}`;
337
+ }
338
+ if (this.operation === "getSingleField" && this.operationParam) {
339
+ return `${path}/${this.operationParam}`;
340
+ }
341
+ const queryString = this.buildQueryString(void 0, useEntityIds);
342
+ return `${path}${queryString}`;
343
+ }
344
+ toRequest(baseUrl, options) {
163
345
  const config = this.getRequestConfig();
164
- const fullUrl = `${baseUrl}${config.url}`;
165
- return new Request(fullUrl, {
166
- method: config.method,
167
- headers: {
168
- "Content-Type": "application/json",
169
- Accept: "application/json"
170
- }
171
- });
346
+ return createODataRequest(baseUrl, config, options);
172
347
  }
173
348
  async processResponse(response, options) {
174
- var _a, _b, _c;
175
- const rawResponse = await response.json();
349
+ if (!response.ok) {
350
+ const tableName = this.table ? getTableName(this.table) : "unknown";
351
+ const error = await parseErrorResponse(response, response.url || `/${this.databaseName}/${tableName}`);
352
+ return { data: void 0, error };
353
+ }
354
+ const rawResponse = await safeJsonParse(response);
176
355
  if (this.operation === "getSingleField") {
177
356
  const fieldResponse = rawResponse;
178
357
  return { data: fieldResponse.value, error: void 0 };
179
358
  }
180
- const shouldUseIds = (options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds;
181
- let transformedResponse = rawResponse;
182
- if (((_a = this.occurrence) == null ? void 0 : _a.baseTable) && shouldUseIds) {
183
- transformedResponse = transformResponseFields(
184
- rawResponse,
185
- this.occurrence.baseTable,
186
- void 0
187
- // No expand configs for simple get
188
- );
189
- }
190
- const schema = (_c = (_b = this.occurrence) == null ? void 0 : _b.baseTable) == null ? void 0 : _c.schema;
191
- const validation = await validateSingleResponse(
192
- transformedResponse,
193
- schema,
194
- void 0,
195
- // No selected fields for record.get()
196
- void 0,
197
- // No expand configs
198
- "exact"
199
- // Expect exactly one record
200
- );
201
- if (!validation.valid) {
202
- return { data: void 0, error: validation.error };
203
- }
204
- if (validation.data === null) {
205
- return { data: null, error: void 0 };
206
- }
207
- return { data: validation.data, error: void 0 };
359
+ const mergedOptions = this.mergeExecuteOptions(options);
360
+ const expandBuilder = new ExpandBuilder(mergedOptions.useEntityIds ?? false, this.logger);
361
+ const expandValidationConfigs = expandBuilder.buildValidationConfigs(this.expandConfigs);
362
+ return processODataResponse(rawResponse, {
363
+ table: this.table,
364
+ schema: getSchemaFromTable(this.table),
365
+ singleMode: "exact",
366
+ selectedFields: this.selectedFields,
367
+ expandValidationConfigs,
368
+ skipValidation: options == null ? void 0 : options.skipValidation,
369
+ useEntityIds: mergedOptions.useEntityIds,
370
+ includeSpecialColumns: mergedOptions.includeSpecialColumns,
371
+ fieldMapping: this.fieldMapping
372
+ });
208
373
  }
209
374
  }
210
375
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"record-builder.js","sources":["../../../src/client/record-builder.ts"],"sourcesContent":["import type {\n ExecutionContext,\n ExecutableBuilder,\n Result,\n ODataRecordMetadata,\n ODataFieldResponse,\n InferSchemaType,\n ExecuteOptions,\n} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { transformTableName, transformResponseFields, getTableIdentifiers } from \"../transform\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { validateSingleResponse } from \"../validation\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport { StandardSchemaV1 } from \"@standard-schema/spec\";\n// import type { z } from \"zod/v4\";\n\n// Helper type to extract schema from a TableOccurrence\ntype ExtractSchemaFromOccurrence<O> =\n O extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<infer S, any, any, any>\n ? S\n : never\n : never;\n\n// Helper type to extract navigation relation names from an occurrence\ntype ExtractNavigationNames<\n O extends TableOccurrence<any, any, any, any> | undefined,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? keyof Nav\n : never\n : never;\n\n// Helper type to resolve a navigation item (handles both direct and lazy-loaded)\ntype ResolveNavigationItem<T> = T extends () => infer R ? R : T;\n\n// Helper type to find target occurrence by relation name\ntype FindNavigationTarget<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Name extends string,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Name extends keyof Nav\n ? ResolveNavigationItem<Nav[Name]>\n : never\n : never;\n\nexport class RecordBuilder<\n T extends Record<string, any>,\n IsSingleField extends boolean = false,\n FieldKey extends keyof T = keyof T,\n Occ extends TableOccurrence<any, any, any, any> | undefined =\n | TableOccurrence<any, any, any, any>\n | undefined,\n> implements\n ExecutableBuilder<\n IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata\n >\n{\n private occurrence?: Occ;\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private recordId: string | number;\n private operation?: \"getSingleField\" | \"navigate\";\n private operationParam?: string;\n private isNavigateFromEntitySet?: boolean;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n recordId: string | number;\n databaseUseEntityIds?: boolean;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.recordId = config.recordId;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n }\n\n /**\n * Helper to merge database-level useEntityIds with per-request options\n */\n private mergeExecuteOptions(\n options?: RequestInit & FFetchOptions & ExecuteOptions,\n ): RequestInit & FFetchOptions & { useEntityIds?: boolean } {\n // If useEntityIds is not set in options, use the database-level setting\n return {\n ...options,\n useEntityIds: options?.useEntityIds ?? this.databaseUseEntityIds,\n };\n }\n\n /**\n * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name\n * @param useEntityIds - Optional override for entity ID usage\n */\n private getTableId(useEntityIds?: boolean): string {\n if (!this.occurrence) {\n return this.tableName;\n }\n\n const contextDefault = this.context._getUseEntityIds?.() ?? false;\n const shouldUseIds = useEntityIds ?? contextDefault;\n\n if (shouldUseIds) {\n const identifiers = getTableIdentifiers(this.occurrence);\n if (!identifiers.id) {\n throw new Error(\n `useEntityIds is true but TableOccurrence \"${identifiers.name}\" does not have an fmtId defined`\n );\n }\n return identifiers.id;\n }\n\n return this.occurrence.getTableName();\n }\n\n getSingleField<K extends keyof T>(field: K): RecordBuilder<T, true, K, Occ> {\n const newBuilder = new RecordBuilder<T, true, K, Occ>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n });\n newBuilder.operation = \"getSingleField\";\n newBuilder.operationParam = field.toString();\n // Preserve navigation context\n newBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n return newBuilder;\n }\n\n // Overload for valid relation names - returns typed QueryBuilder\n navigate<RelationName extends ExtractNavigationNames<Occ>>(\n relationName: RelationName,\n ): QueryBuilder<\n ExtractSchemaFromOccurrence<\n FindNavigationTarget<Occ, RelationName>\n > extends Record<string, StandardSchemaV1>\n ? InferSchemaType<\n ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>>\n >\n : Record<string, any>\n >;\n // Overload for arbitrary strings - returns generic QueryBuilder with system fields\n navigate(\n relationName: string,\n ): QueryBuilder<{ ROWID: number; ROWMODID: number; [key: string]: any }>;\n // Implementation\n navigate(relationName: string): QueryBuilder<any> {\n // Use the target occurrence if available, otherwise allow untyped navigation\n // (useful when types might be incomplete)\n const targetOccurrence = this.occurrence?.navigation[relationName];\n const builder = new QueryBuilder<any>({\n occurrence: targetOccurrence,\n tableName: targetOccurrence?.name ?? relationName,\n databaseName: this.databaseName,\n context: this.context,\n });\n // Store the navigation info - we'll use it in execute\n // Transform relation name to FMTID if using entity IDs\n const relationId = targetOccurrence\n ? transformTableName(targetOccurrence)\n : relationName;\n\n (builder as any).isNavigate = true;\n (builder as any).navigateRecordId = this.recordId;\n (builder as any).navigateRelation = relationId;\n\n // If this RecordBuilder came from a navigated EntitySet, we need to preserve that base path\n if (\n this.isNavigateFromEntitySet &&\n this.navigateSourceTableName &&\n this.navigateRelation\n ) {\n // Build the base path: /sourceTable/relation('recordId')/newRelation\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n (builder as any).navigateBaseRelation = this.navigateRelation;\n } else {\n // Normal record navigation: /tableName('recordId')/relation\n // Transform source table name to FMTID if using entity IDs\n const sourceTableId = this.occurrence\n ? transformTableName(this.occurrence)\n : this.tableName;\n (builder as any).navigateSourceTableName = sourceTableId;\n }\n\n return builder;\n }\n\n async execute(\n options?: RequestInit & FFetchOptions & { useEntityIds?: boolean },\n ): Promise<\n Result<IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata>\n > {\n let url: string;\n\n // Build the base URL depending on whether this came from a navigated EntitySet\n if (\n this.isNavigateFromEntitySet &&\n this.navigateSourceTableName &&\n this.navigateRelation\n ) {\n // From navigated EntitySet: /sourceTable/relation('recordId')\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;\n } else {\n // Normal record: /tableName('recordId') - use FMTID if configured\n const tableId = this.getTableId(options?.useEntityIds ?? this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n url += `/${this.operationParam}`;\n }\n\n const mergedOptions = this.mergeExecuteOptions(options);\n const result = await this.context._makeRequest(url, mergedOptions);\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n let response = result.data;\n\n // Handle single field operation\n if (this.operation === \"getSingleField\") {\n // Single field returns a JSON object with @context and value\n const fieldResponse = response as ODataFieldResponse<T>;\n return { data: fieldResponse.value as any, error: undefined };\n }\n\n // Transform response field IDs back to names if using entity IDs\n // Only transform if useEntityIds resolves to true (respects per-request override)\n const shouldUseIds = mergedOptions.useEntityIds ?? false;\n \n if (this.occurrence?.baseTable && shouldUseIds) {\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n undefined, // No expand configs for simple get\n );\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n\n // Validate the single record response\n const validation = await validateSingleResponse<any>(\n response,\n schema,\n undefined, // No selected fields for record.get()\n undefined, // No expand configs\n \"exact\", // Expect exactly one record\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n // Handle null response\n if (validation.data === null) {\n return { data: null as any, error: undefined };\n }\n\n return { data: validation.data, error: undefined };\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n let url: string;\n\n // Build the base URL depending on whether this came from a navigated EntitySet\n if (\n this.isNavigateFromEntitySet &&\n this.navigateSourceTableName &&\n this.navigateRelation\n ) {\n // From navigated EntitySet: /sourceTable/relation('recordId')\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;\n } else {\n // For batch operations, use database-level setting (no per-request override available here)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n url += `/${this.operationParam}`;\n }\n\n return {\n method: \"GET\",\n url,\n };\n }\n\n toRequest(baseUrl: string): Request {\n const config = this.getRequestConfig();\n const fullUrl = `${baseUrl}${config.url}`;\n\n return new Request(fullUrl, {\n method: config.method,\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata>\n > {\n const rawResponse = await response.json();\n\n // Handle single field operation\n if (this.operation === \"getSingleField\") {\n // Single field returns a JSON object with @context and value\n const fieldResponse = rawResponse as ODataFieldResponse<T>;\n return { data: fieldResponse.value as any, error: undefined };\n }\n\n // Transform response field IDs back to names if using entity IDs\n // Only transform if useEntityIds resolves to true (respects per-request override)\n const shouldUseIds = options?.useEntityIds ?? this.databaseUseEntityIds;\n \n let transformedResponse = rawResponse;\n if (this.occurrence?.baseTable && shouldUseIds) {\n transformedResponse = transformResponseFields(\n rawResponse,\n this.occurrence.baseTable,\n undefined, // No expand configs for simple get\n );\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n\n // Validate the single record response\n const validation = await validateSingleResponse<any>(\n transformedResponse,\n schema,\n undefined, // No selected fields for record.get()\n undefined, // No expand configs\n \"exact\", // Expect exactly one record\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n // Handle null response\n if (validation.data === null) {\n return { data: null as any, error: undefined };\n }\n\n return { data: validation.data, error: undefined };\n }\n}\n"],"names":[],"mappings":";;;;;;AAkDO,MAAM,cAWb;AAAA,EAcE,YAAY,QAOT;AApBK;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAUN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AACtB,SAAK,WAAW,OAAO;AAClB,SAAA,uBAAuB,OAAO,wBAAwB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMrD,oBACN,SAC0D;AAEnD,WAAA;AAAA,MACL,GAAG;AAAA,MACH,eAAc,mCAAS,iBAAgB,KAAK;AAAA,IAC9C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOM,WAAW,cAAgC;;AAC7C,QAAA,CAAC,KAAK,YAAY;AACpB,aAAO,KAAK;AAAA,IAAA;AAGd,UAAM,mBAAiB,gBAAK,SAAQ,qBAAb,gCAAqC;AAC5D,UAAM,eAAe,gBAAgB;AAErC,QAAI,cAAc;AACV,YAAA,cAAc,oBAAoB,KAAK,UAAU;AACnD,UAAA,CAAC,YAAY,IAAI;AACnB,cAAM,IAAI;AAAA,UACR,6CAA6C,YAAY,IAAI;AAAA,QAC/D;AAAA,MAAA;AAEF,aAAO,YAAY;AAAA,IAAA;AAGd,WAAA,KAAK,WAAW,aAAa;AAAA,EAAA;AAAA,EAGtC,eAAkC,OAA0C;AACpE,UAAA,aAAa,IAAI,cAA+B;AAAA,MACpD,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,IAAA,CAChB;AACD,eAAW,YAAY;AACZ,eAAA,iBAAiB,MAAM,SAAS;AAE3C,eAAW,0BAA0B,KAAK;AAC1C,eAAW,mBAAmB,KAAK;AACnC,eAAW,0BAA0B,KAAK;AACnC,WAAA;AAAA,EAAA;AAAA;AAAA,EAoBT,SAAS,cAAyC;;AAGhD,UAAM,oBAAmB,UAAK,eAAL,mBAAiB,WAAW;AAC/C,UAAA,UAAU,IAAI,aAAkB;AAAA,MACpC,YAAY;AAAA,MACZ,YAAW,qDAAkB,SAAQ;AAAA,MACrC,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAGD,UAAM,aAAa,mBACf,mBAAmB,gBAAgB,IACnC;AAEH,YAAgB,aAAa;AAC7B,YAAgB,mBAAmB,KAAK;AACxC,YAAgB,mBAAmB;AAGpC,QACE,KAAK,2BACL,KAAK,2BACL,KAAK,kBACL;AAEC,cAAgB,0BAA0B,KAAK;AAC/C,cAAgB,uBAAuB,KAAK;AAAA,IAAA,OACxC;AAGL,YAAM,gBAAgB,KAAK,aACvB,mBAAmB,KAAK,UAAU,IAClC,KAAK;AACR,cAAgB,0BAA0B;AAAA,IAAA;AAGtC,WAAA;AAAA,EAAA;AAAA,EAGT,MAAM,QACJ,SAGA;;AACI,QAAA;AAGJ,QACE,KAAK,2BACL,KAAK,2BACL,KAAK,kBACL;AAEM,YAAA,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,IAAI,KAAK,gBAAgB,KAAK,KAAK,QAAQ;AAAA,IAAA,OACjG;AAEL,YAAM,UAAU,KAAK,YAAW,mCAAS,iBAAgB,KAAK,oBAAoB;AAClF,YAAM,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAA,IAAA;AAG1D,QAAI,KAAK,cAAc,oBAAoB,KAAK,gBAAgB;AACvD,aAAA,IAAI,KAAK,cAAc;AAAA,IAAA;AAG1B,UAAA,gBAAgB,KAAK,oBAAoB,OAAO;AACtD,UAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,KAAK,aAAa;AAEjE,QAAI,OAAO,OAAO;AAChB,aAAO,EAAE,MAAM,QAAW,OAAO,OAAO,MAAM;AAAA,IAAA;AAGhD,QAAI,WAAW,OAAO;AAGlB,QAAA,KAAK,cAAc,kBAAkB;AAEvC,YAAM,gBAAgB;AACtB,aAAO,EAAE,MAAM,cAAc,OAAc,OAAO,OAAU;AAAA,IAAA;AAKxD,UAAA,eAAe,cAAc,gBAAgB;AAE/C,UAAA,UAAK,eAAL,mBAAiB,cAAa,cAAc;AACnC,iBAAA;AAAA,QACT;AAAA,QACA,KAAK,WAAW;AAAA,QAChB;AAAA;AAAA,MACF;AAAA,IAAA;AAII,UAAA,UAAS,gBAAK,eAAL,mBAAiB,cAAjB,mBAA4B;AAG3C,UAAM,aAAa,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,IACF;AAEI,QAAA,CAAC,WAAW,OAAO;AACrB,aAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,IAAA;AAIhD,QAAA,WAAW,SAAS,MAAM;AAC5B,aAAO,EAAE,MAAM,MAAa,OAAO,OAAU;AAAA,IAAA;AAG/C,WAAO,EAAE,MAAM,WAAW,MAAM,OAAO,OAAU;AAAA,EAAA;AAAA,EAGnD,mBAAgE;AAC1D,QAAA;AAGJ,QACE,KAAK,2BACL,KAAK,2BACL,KAAK,kBACL;AAEM,YAAA,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,IAAI,KAAK,gBAAgB,KAAK,KAAK,QAAQ;AAAA,IAAA,OACjG;AAEL,YAAM,UAAU,KAAK,WAAW,KAAK,oBAAoB;AACzD,YAAM,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAA,IAAA;AAG1D,QAAI,KAAK,cAAc,oBAAoB,KAAK,gBAAgB;AACvD,aAAA,IAAI,KAAK,cAAc;AAAA,IAAA;AAGzB,WAAA;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAAA,EAGF,UAAU,SAA0B;AAC5B,UAAA,SAAS,KAAK,iBAAiB;AACrC,UAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG;AAEhC,WAAA,IAAI,QAAQ,SAAS;AAAA,MAC1B,QAAQ,OAAO;AAAA,MACf,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MAAA;AAAA,IACV,CACD;AAAA,EAAA;AAAA,EAGH,MAAM,gBACJ,UACA,SAGA;;AACM,UAAA,cAAc,MAAM,SAAS,KAAK;AAGpC,QAAA,KAAK,cAAc,kBAAkB;AAEvC,YAAM,gBAAgB;AACtB,aAAO,EAAE,MAAM,cAAc,OAAc,OAAO,OAAU;AAAA,IAAA;AAKxD,UAAA,gBAAe,mCAAS,iBAAgB,KAAK;AAEnD,QAAI,sBAAsB;AACtB,UAAA,UAAK,eAAL,mBAAiB,cAAa,cAAc;AACxB,4BAAA;AAAA,QACpB;AAAA,QACA,KAAK,WAAW;AAAA,QAChB;AAAA;AAAA,MACF;AAAA,IAAA;AAII,UAAA,UAAS,gBAAK,eAAL,mBAAiB,cAAjB,mBAA4B;AAG3C,UAAM,aAAa,MAAM;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,IACF;AAEI,QAAA,CAAC,WAAW,OAAO;AACrB,aAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,IAAA;AAIhD,QAAA,WAAW,SAAS,MAAM;AAC5B,aAAO,EAAE,MAAM,MAAa,OAAO,OAAU;AAAA,IAAA;AAG/C,WAAO,EAAE,MAAM,WAAW,MAAM,OAAO,OAAU;AAAA,EAAA;AAErD;"}
1
+ {"version":3,"file":"record-builder.js","sources":["../../../src/client/record-builder.ts"],"sourcesContent":["/** biome-ignore-all lint/complexity/noBannedTypes: Empty object type represents no expands by default */\nimport type { FFetchOptions } from \"@fetchkit/ffetch\";\nimport { createLogger, type InternalLogger } from \"../logger\";\nimport type { Column } from \"../orm/column\";\nimport type { ExtractTableName, FMTable, InferSchemaOutputFromFMTable, ValidExpandTarget } from \"../orm/table\";\nimport { getNavigationPaths, getTableName } from \"../orm/table\";\nimport type {\n ConditionallyWithODataAnnotations,\n ConditionallyWithSpecialColumns,\n ExecutableBuilder,\n ExecuteMethodOptions,\n ExecuteOptions,\n ExecutionContext,\n NormalizeIncludeSpecialColumns,\n ODataFieldResponse,\n Result,\n} from \"../types\";\nimport {\n buildSelectExpandQueryString,\n createODataRequest,\n ExpandBuilder,\n type ExpandConfig,\n type ExpandedRelations,\n getSchemaFromTable,\n mergeExecuteOptions,\n processODataResponse,\n processSelectWithRenames,\n resolveTableId,\n} from \"./builders/index\";\nimport { parseErrorResponse } from \"./error-parser\";\nimport type { ResolveExpandedRelations, SystemColumnsFromOption, SystemColumnsOption } from \"./query/types\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { safeJsonParse } from \"./sanitize-json\";\n\n/**\n * Extract the value type from a Column.\n * This uses the phantom type stored in Column to get the actual value type.\n */\n// biome-ignore lint/suspicious/noExplicitAny: Required for type inference with infer\ntype ExtractColumnType<C> = C extends Column<infer T, any> ? T : never;\n\n/**\n * Map a select object to its return type.\n * For each key in the select object, extract the type from the corresponding Column.\n */\ntype MapSelectToReturnType<\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n TSelect extends Record<string, Column<any, any, any, any>>,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any schema shape\n _TSchema extends Record<string, any>,\n> = {\n [K in keyof TSelect]: ExtractColumnType<TSelect[K]>;\n};\n\n// Return type for RecordBuilder execute\nexport type RecordReturnType<\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any schema shape\n Schema extends Record<string, any>,\n IsSingleField extends boolean,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n FieldColumn extends Column<any, any, any, any> | undefined,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration, accepts any FMTable\n Selected extends keyof Schema | Record<string, Column<any, any, ExtractTableName<FMTable<any, any>>>>,\n Expands extends ExpandedRelations,\n SystemCols extends SystemColumnsOption | undefined = undefined,\n> = IsSingleField extends true\n ? // biome-ignore lint/suspicious/noExplicitAny: Required for type inference with infer\n FieldColumn extends Column<infer TOutput, any, any, any>\n ? TOutput\n : never\n : // Use tuple wrapping [Selected] extends [...] to prevent distribution over unions\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n [Selected] extends [Record<string, Column<any, any, any, any>>]\n ? MapSelectToReturnType<Selected, Schema> & ResolveExpandedRelations<Expands> & SystemColumnsFromOption<SystemCols>\n : // Use tuple wrapping to prevent distribution over union of keys\n [Selected] extends [keyof Schema]\n ? Pick<Schema, Selected> & ResolveExpandedRelations<Expands> & SystemColumnsFromOption<SystemCols>\n : never;\n\nexport class RecordBuilder<\n // biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration, default allows untyped tables\n Occ extends FMTable<any, any> = FMTable<any, any>,\n IsSingleField extends boolean = false,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n FieldColumn extends Column<any, any, any, any> | undefined = undefined,\n Selected extends\n | keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n | Record<string, Column<any, any, ExtractTableName<NonNullable<Occ>>>> = keyof InferSchemaOutputFromFMTable<\n NonNullable<Occ>\n >,\n Expands extends ExpandedRelations = {},\n DatabaseIncludeSpecialColumns extends boolean = false,\n SystemCols extends SystemColumnsOption | undefined = undefined,\n> implements\n ExecutableBuilder<\n RecordReturnType<\n InferSchemaOutputFromFMTable<NonNullable<Occ>>,\n IsSingleField,\n FieldColumn,\n Selected,\n Expands,\n SystemCols\n >\n >\n{\n private readonly table: Occ;\n private readonly databaseName: string;\n private readonly context: ExecutionContext;\n private readonly recordId: string | number;\n private readonly operation?: \"getSingleField\" | \"navigate\";\n private readonly operationParam?: string;\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n private readonly operationColumn?: Column<any, any, any, any>;\n private readonly isNavigateFromEntitySet?: boolean;\n private readonly navigateRelation?: string;\n private readonly navigateSourceTableName?: string;\n\n private readonly databaseUseEntityIds: boolean;\n private readonly databaseIncludeSpecialColumns: boolean;\n\n // Properties for select/expand support\n private readonly selectedFields?: string[];\n private readonly expandConfigs: ExpandConfig[] = [];\n // Mapping from field names to output keys (for renamed fields in select)\n private readonly fieldMapping?: Record<string, string>;\n // System columns requested via select() second argument\n private readonly systemColumns?: SystemColumnsOption;\n\n private readonly logger: InternalLogger;\n\n constructor(config: {\n occurrence: Occ;\n databaseName: string;\n context: ExecutionContext;\n recordId: string | number;\n databaseUseEntityIds?: boolean;\n databaseIncludeSpecialColumns?: boolean;\n }) {\n this.table = config.occurrence;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.recordId = config.recordId;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n this.databaseIncludeSpecialColumns = config.databaseIncludeSpecialColumns ?? false;\n this.logger = config.context?._getLogger?.() ?? createLogger();\n }\n\n /**\n * Helper to merge database-level useEntityIds and includeSpecialColumns with per-request options\n */\n private mergeExecuteOptions(options?: RequestInit & FFetchOptions & ExecuteOptions): RequestInit &\n FFetchOptions & {\n useEntityIds?: boolean;\n includeSpecialColumns?: boolean;\n } {\n const merged = mergeExecuteOptions(options, this.databaseUseEntityIds);\n return {\n ...merged,\n includeSpecialColumns: options?.includeSpecialColumns ?? this.databaseIncludeSpecialColumns,\n };\n }\n\n /**\n * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name\n * @param useEntityIds - Optional override for entity ID usage\n */\n private getTableId(useEntityIds?: boolean): string {\n if (!this.table) {\n throw new Error(\"Table occurrence is required\");\n }\n return resolveTableId(this.table, getTableName(this.table), this.context, useEntityIds);\n }\n\n /**\n * Creates a new RecordBuilder with modified configuration.\n * Used by select() to create new instances.\n */\n private cloneWithChanges<\n NewSelected extends\n | keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n | Record<string, Column<any, any, ExtractTableName<NonNullable<Occ>>>> = Selected,\n NewSystemCols extends SystemColumnsOption | undefined = SystemCols,\n >(changes: {\n selectedFields?: string[];\n fieldMapping?: Record<string, string>;\n systemColumns?: NewSystemCols;\n }): RecordBuilder<Occ, false, FieldColumn, NewSelected, Expands, DatabaseIncludeSpecialColumns, NewSystemCols> {\n const newBuilder = new RecordBuilder<\n Occ,\n false,\n FieldColumn,\n NewSelected,\n Expands,\n DatabaseIncludeSpecialColumns,\n NewSystemCols\n >({\n occurrence: this.table,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,\n });\n // Use type assertion to allow assignment to readonly properties on new instance\n\n // biome-ignore lint/suspicious/noExplicitAny: Mutation of readonly properties for builder pattern\n const mutableBuilder = newBuilder as any;\n mutableBuilder.selectedFields = changes.selectedFields ?? this.selectedFields;\n mutableBuilder.fieldMapping = changes.fieldMapping ?? this.fieldMapping;\n mutableBuilder.systemColumns = changes.systemColumns !== undefined ? changes.systemColumns : this.systemColumns;\n mutableBuilder.expandConfigs = [...this.expandConfigs];\n // Preserve navigation context\n mutableBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n mutableBuilder.navigateRelation = this.navigateRelation;\n mutableBuilder.navigateSourceTableName = this.navigateSourceTableName;\n mutableBuilder.operationColumn = this.operationColumn;\n return newBuilder;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n getSingleField<TColumn extends Column<any, any, ExtractTableName<NonNullable<Occ>>, any>>(\n column: TColumn,\n ): RecordBuilder<\n Occ,\n true,\n TColumn,\n keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>,\n {},\n DatabaseIncludeSpecialColumns\n > {\n // Runtime validation: ensure column is from the correct table\n const tableName = getTableName(this.table);\n if (!column.isFromTable(tableName)) {\n throw new Error(`Column ${column.toString()} is not from table ${tableName}`);\n }\n\n const newBuilder = new RecordBuilder<\n Occ,\n true,\n TColumn,\n keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>,\n {},\n DatabaseIncludeSpecialColumns\n >({\n occurrence: this.table,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,\n });\n // Use type assertion to allow assignment to readonly properties on new instance\n\n // biome-ignore lint/suspicious/noExplicitAny: Mutation of readonly properties for builder pattern\n const mutableBuilder = newBuilder as any;\n mutableBuilder.operation = \"getSingleField\";\n mutableBuilder.operationColumn = column;\n mutableBuilder.operationParam = column.getFieldIdentifier(this.databaseUseEntityIds);\n // Preserve navigation context\n mutableBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n mutableBuilder.navigateRelation = this.navigateRelation;\n mutableBuilder.navigateSourceTableName = this.navigateSourceTableName;\n return newBuilder;\n }\n\n /**\n * Select fields using column references.\n * Allows renaming fields by using different keys in the object.\n * Container fields cannot be selected and will cause a type error.\n *\n * @example\n * db.from(contacts).get(\"uuid\").select({\n * name: contacts.name,\n * userEmail: contacts.email // renamed!\n * })\n *\n * @example\n * // Include system columns (ROWID, ROWMODID) when using select()\n * db.from(contacts).get(\"uuid\").select(\n * { name: contacts.name },\n * { ROWID: true, ROWMODID: true }\n * )\n *\n * @param fields - Object mapping output keys to column references (container fields excluded)\n * @param systemColumns - Optional object to request system columns (ROWID, ROWMODID)\n * @returns RecordBuilder with updated selected fields\n */\n select<\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n TSelect extends Record<string, Column<any, any, ExtractTableName<Occ>, false>>,\n TSystemCols extends SystemColumnsOption = {},\n >(\n fields: TSelect,\n systemColumns?: TSystemCols,\n ): RecordBuilder<Occ, false, FieldColumn, TSelect, Expands, DatabaseIncludeSpecialColumns, TSystemCols> {\n const tableName = getTableName(this.table);\n const { selectedFields, fieldMapping } = processSelectWithRenames(fields, tableName, this.logger);\n\n // Add system columns to selectedFields if requested\n const finalSelectedFields = [...selectedFields];\n if (systemColumns?.ROWID) {\n finalSelectedFields.push(\"ROWID\");\n }\n if (systemColumns?.ROWMODID) {\n finalSelectedFields.push(\"ROWMODID\");\n }\n\n return this.cloneWithChanges({\n selectedFields: finalSelectedFields,\n fieldMapping: Object.keys(fieldMapping).length > 0 ? fieldMapping : undefined,\n // biome-ignore lint/suspicious/noExplicitAny: Type assertion for generic type parameter\n systemColumns: systemColumns as any,\n // biome-ignore lint/suspicious/noExplicitAny: Type assertion for complex generic return type\n }) as any;\n }\n\n /**\n * Expand a navigation property to include related records.\n * Supports nested select, filter, orderBy, and expand operations.\n *\n * @example\n * ```typescript\n * // Simple expand with FMTable object\n * const contact = await db.from(contacts).get(\"uuid\").expand(users).execute();\n *\n * // Expand with select\n * const contact = await db.from(contacts).get(\"uuid\")\n * .expand(users, b => b.select({ username: users.username, email: users.email }))\n * .execute();\n * ```\n */\n expand<\n // biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration\n TargetTable extends FMTable<any, any>,\n TSelected extends\n | keyof InferSchemaOutputFromFMTable<TargetTable>\n | Record<\n string,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n Column<any, any, ExtractTableName<TargetTable>>\n > = keyof InferSchemaOutputFromFMTable<TargetTable>,\n TNestedExpands extends ExpandedRelations = {},\n >(\n targetTable: ValidExpandTarget<Occ, TargetTable>,\n callback?: (\n builder: QueryBuilder<TargetTable, keyof InferSchemaOutputFromFMTable<TargetTable>, false, false, {}>,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any QueryBuilder configuration\n ) => QueryBuilder<TargetTable, TSelected, any, any, TNestedExpands>,\n ): RecordBuilder<\n Occ,\n false,\n FieldColumn,\n Selected,\n Expands & {\n [K in ExtractTableName<TargetTable>]: {\n schema: InferSchemaOutputFromFMTable<TargetTable>;\n selected: TSelected;\n nested: TNestedExpands;\n };\n },\n DatabaseIncludeSpecialColumns,\n SystemCols\n > {\n // Create new builder with updated types\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any ExpandedRelations\n const newBuilder = new RecordBuilder<Occ, false, FieldColumn, Selected, any, DatabaseIncludeSpecialColumns>({\n occurrence: this.table,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,\n });\n\n // Use type assertion to allow assignment to readonly properties on new instance\n // biome-ignore lint/suspicious/noExplicitAny: Mutation of readonly properties for builder pattern\n const mutableBuilder = newBuilder as any;\n // Copy existing state\n mutableBuilder.selectedFields = this.selectedFields;\n mutableBuilder.fieldMapping = this.fieldMapping;\n mutableBuilder.systemColumns = this.systemColumns;\n mutableBuilder.expandConfigs = [...this.expandConfigs];\n mutableBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n mutableBuilder.navigateRelation = this.navigateRelation;\n mutableBuilder.navigateSourceTableName = this.navigateSourceTableName;\n mutableBuilder.operationColumn = this.operationColumn;\n\n // Use ExpandBuilder.processExpand to handle the expand logic\n const expandBuilder = new ExpandBuilder(this.databaseUseEntityIds, this.logger);\n type TargetBuilder = QueryBuilder<TargetTable, keyof InferSchemaOutputFromFMTable<TargetTable>, false, false, {}>;\n const expandConfig = expandBuilder.processExpand<TargetTable, TargetBuilder>(\n targetTable,\n this.table ?? undefined,\n callback as ((builder: TargetBuilder) => TargetBuilder) | undefined,\n () =>\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any QueryBuilder configuration\n new QueryBuilder<TargetTable, any, any, any, any, DatabaseIncludeSpecialColumns, undefined>({\n occurrence: targetTable,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,\n }),\n );\n\n mutableBuilder.expandConfigs.push(expandConfig);\n // biome-ignore lint/suspicious/noExplicitAny: Type assertion needed as expand changes generic parameters in complex way that TypeScript cannot infer\n return newBuilder as any;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration\n navigate<TargetTable extends FMTable<any, any>>(\n targetTable: ValidExpandTarget<Occ, TargetTable>,\n ): QueryBuilder<\n TargetTable,\n keyof InferSchemaOutputFromFMTable<TargetTable>,\n false,\n false,\n {},\n DatabaseIncludeSpecialColumns,\n undefined\n > {\n // Extract name and validate\n const relationName = getTableName(targetTable);\n\n // Runtime validation: Check if relation name is in navigationPaths\n if (this.table) {\n const navigationPaths = getNavigationPaths(this.table);\n if (navigationPaths && !navigationPaths.includes(relationName)) {\n this.logger.warn(\n `Cannot navigate to \"${relationName}\". Valid navigation paths: ${navigationPaths.length > 0 ? navigationPaths.join(\", \") : \"none\"}`,\n );\n }\n }\n\n // Create QueryBuilder with target table\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any QueryBuilder configuration\n const builder = new QueryBuilder<TargetTable, any, any, any, any, DatabaseIncludeSpecialColumns, undefined>({\n occurrence: targetTable,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,\n });\n\n // Store the navigation info - we'll use it in execute\n // Use relation name as-is (entity ID handling is done in QueryBuilder)\n const relationId = relationName;\n\n // If this RecordBuilder came from a navigated EntitySet, we need to preserve that base path\n let sourceTableName: string;\n let baseRelation: string | undefined;\n if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {\n // Build the base path: /sourceTable/relation('recordId')/newRelation\n sourceTableName = this.navigateSourceTableName;\n baseRelation = this.navigateRelation;\n } else {\n // Normal record navigation: /tableName('recordId')/relation\n // Use table ID if available, otherwise table name\n if (!this.table) {\n throw new Error(\"Table occurrence is required for navigation\");\n }\n sourceTableName = resolveTableId(this.table, getTableName(this.table), this.context, this.databaseUseEntityIds);\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Mutation of readonly properties for builder pattern\n (builder as any).navigation = {\n recordId: this.recordId,\n relation: relationId,\n sourceTableName,\n baseRelation,\n };\n // biome-ignore lint/suspicious/noExplicitAny: Mutation of readonly properties for builder pattern\n (builder as any).navigation = {\n recordId: this.recordId,\n relation: relationId,\n sourceTableName,\n baseRelation,\n };\n\n return builder;\n }\n\n /**\n * Builds the complete query string including $select and $expand parameters.\n */\n private buildQueryString(includeSpecialColumns?: boolean, useEntityIds?: boolean): string {\n // Use merged includeSpecialColumns if provided, otherwise use database-level default\n const finalIncludeSpecialColumns = includeSpecialColumns ?? this.databaseIncludeSpecialColumns;\n // Use merged useEntityIds if provided, otherwise use database-level default\n const finalUseEntityIds = useEntityIds ?? this.databaseUseEntityIds;\n\n return buildSelectExpandQueryString({\n selectedFields: this.selectedFields,\n expandConfigs: this.expandConfigs,\n table: this.table,\n useEntityIds: finalUseEntityIds,\n logger: this.logger,\n includeSpecialColumns: finalIncludeSpecialColumns,\n });\n }\n\n async execute<EO extends ExecuteOptions>(\n options?: ExecuteMethodOptions<EO>,\n ): Promise<\n Result<\n ConditionallyWithODataAnnotations<\n ConditionallyWithSpecialColumns<\n RecordReturnType<\n InferSchemaOutputFromFMTable<NonNullable<Occ>>,\n IsSingleField,\n FieldColumn,\n Selected,\n Expands,\n SystemCols\n >,\n // Use the merged value: if explicitly provided in options, use that; otherwise use database default\n NormalizeIncludeSpecialColumns<EO[\"includeSpecialColumns\"], DatabaseIncludeSpecialColumns>,\n // Check if select was applied: if Selected is Record (object select) or a subset of keys, select was applied\n IsSingleField extends true\n ? false // Single field operations don't include special columns\n : // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration\n Selected extends Record<string, Column<any, any, any>>\n ? true\n : Selected extends keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>\n ? false\n : true\n >,\n EO[\"includeODataAnnotations\"] extends true ? true : false\n >\n >\n > {\n let url: string;\n\n // Build the base URL depending on whether this came from a navigated EntitySet\n if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {\n // From navigated EntitySet: /sourceTable/relation('recordId')\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;\n } else {\n // Normal record: /tableName('recordId') - use FMTID if configured\n const tableId = this.getTableId(options?.useEntityIds ?? this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n }\n\n const mergedOptions = this.mergeExecuteOptions(options);\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n url += `/${this.operationParam}`;\n } else {\n // Add query string for select/expand (only when not getting a single field)\n const queryString = this.buildQueryString(mergedOptions.includeSpecialColumns, mergedOptions.useEntityIds);\n url += queryString;\n }\n const result = await this.context._makeRequest(url, mergedOptions);\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n const response = result.data;\n\n // Handle single field operation\n if (this.operation === \"getSingleField\") {\n // Single field returns a JSON object with @context and value\n // The type is extracted from the Column stored in FieldColumn generic\n // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API\n const fieldResponse = response as ODataFieldResponse<any>;\n // biome-ignore lint/suspicious/noExplicitAny: Type assertion for generic type extraction\n return { data: fieldResponse.value as any, error: undefined };\n }\n\n // Use shared response processor\n const expandBuilder = new ExpandBuilder(mergedOptions.useEntityIds ?? false, this.logger);\n const expandValidationConfigs = expandBuilder.buildValidationConfigs(this.expandConfigs);\n\n return processODataResponse(response, {\n table: this.table,\n schema: getSchemaFromTable(this.table),\n singleMode: \"exact\",\n selectedFields: this.selectedFields,\n expandValidationConfigs,\n skipValidation: options?.skipValidation,\n useEntityIds: mergedOptions.useEntityIds,\n includeSpecialColumns: mergedOptions.includeSpecialColumns,\n fieldMapping: this.fieldMapping,\n });\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Request body can be any JSON-serializable value\n getRequestConfig(): { method: string; url: string; body?: any } {\n let url: string;\n\n // Build the base URL depending on whether this came from a navigated EntitySet\n if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {\n // From navigated EntitySet: /sourceTable/relation('recordId')\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;\n } else {\n // For batch operations, use database-level setting (no per-request override available here)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationColumn) {\n // Use the column's getFieldIdentifier to support entity IDs\n url += `/${this.operationColumn.getFieldIdentifier(this.databaseUseEntityIds)}`;\n } else if (this.operation === \"getSingleField\" && this.operationParam) {\n // Fallback for backwards compatibility (shouldn't happen in normal flow)\n url += `/${this.operationParam}`;\n } else {\n // Add query string for select/expand (only when not getting a single field)\n const queryString = this.buildQueryString();\n url += queryString;\n }\n\n return {\n method: \"GET\",\n url,\n };\n }\n\n /**\n * Returns the query string for this record builder (for testing purposes).\n */\n getQueryString(options?: { useEntityIds?: boolean }): string {\n const useEntityIds = options?.useEntityIds ?? this.databaseUseEntityIds;\n let path: string;\n\n // Build the path depending on navigation context\n if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {\n path = `/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;\n } else {\n // Use getTableId to respect entity ID settings (same as getRequestConfig)\n const tableId = this.getTableId(useEntityIds);\n path = `/${tableId}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationColumn) {\n return `${path}/${this.operationColumn.getFieldIdentifier(useEntityIds)}`;\n }\n if (this.operation === \"getSingleField\" && this.operationParam) {\n // Fallback for backwards compatibility (shouldn't happen in normal flow)\n return `${path}/${this.operationParam}`;\n }\n\n const queryString = this.buildQueryString(undefined, useEntityIds);\n return `${path}${queryString}`;\n }\n\n toRequest(baseUrl: string, options?: ExecuteOptions): Request {\n const config = this.getRequestConfig();\n return createODataRequest(baseUrl, config, options);\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<\n RecordReturnType<\n InferSchemaOutputFromFMTable<NonNullable<Occ>>,\n IsSingleField,\n FieldColumn,\n Selected,\n Expands,\n SystemCols\n >\n >\n > {\n // Check for error responses (important for batch operations)\n if (!response.ok) {\n const tableName = this.table ? getTableName(this.table) : \"unknown\";\n const error = await parseErrorResponse(response, response.url || `/${this.databaseName}/${tableName}`);\n return { data: undefined, error };\n }\n\n // Use safeJsonParse to handle FileMaker's invalid JSON with unquoted ? values\n const rawResponse = await safeJsonParse(response);\n\n // Handle single field operation\n if (this.operation === \"getSingleField\") {\n // Single field returns a JSON object with @context and value\n // The type is extracted from the Column stored in FieldColumn generic\n // biome-ignore lint/suspicious/noExplicitAny: Type parameter inferred from FieldColumn generic\n const fieldResponse = rawResponse as ODataFieldResponse<any>;\n // biome-ignore lint/suspicious/noExplicitAny: Type parameter inferred from FieldColumn generic\n return { data: fieldResponse.value as any, error: undefined };\n }\n\n // Use shared response processor\n const mergedOptions = this.mergeExecuteOptions(options);\n const expandBuilder = new ExpandBuilder(mergedOptions.useEntityIds ?? false, this.logger);\n const expandValidationConfigs = expandBuilder.buildValidationConfigs(this.expandConfigs);\n\n return processODataResponse(rawResponse, {\n table: this.table,\n schema: getSchemaFromTable(this.table),\n singleMode: \"exact\",\n selectedFields: this.selectedFields,\n expandValidationConfigs,\n skipValidation: options?.skipValidation,\n useEntityIds: mergedOptions.useEntityIds,\n includeSpecialColumns: mergedOptions.includeSpecialColumns,\n fieldMapping: this.fieldMapping,\n });\n }\n}\n"],"names":[],"mappings":"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"}