@proofkit/fmodata 0.1.0-alpha.6 → 0.1.0-alpha.7

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 (61) hide show
  1. package/README.md +333 -3
  2. package/dist/esm/client/batch-builder.d.ts +54 -0
  3. package/dist/esm/client/batch-builder.js +179 -0
  4. package/dist/esm/client/batch-builder.js.map +1 -0
  5. package/dist/esm/client/batch-request.d.ts +61 -0
  6. package/dist/esm/client/batch-request.js +252 -0
  7. package/dist/esm/client/batch-request.js.map +1 -0
  8. package/dist/esm/client/database.d.ts +43 -11
  9. package/dist/esm/client/database.js +64 -10
  10. package/dist/esm/client/database.js.map +1 -1
  11. package/dist/esm/client/delete-builder.d.ts +21 -2
  12. package/dist/esm/client/delete-builder.js +76 -9
  13. package/dist/esm/client/delete-builder.js.map +1 -1
  14. package/dist/esm/client/entity-set.d.ts +15 -4
  15. package/dist/esm/client/entity-set.js +23 -7
  16. package/dist/esm/client/entity-set.js.map +1 -1
  17. package/dist/esm/client/filemaker-odata.d.ts +11 -5
  18. package/dist/esm/client/filemaker-odata.js +46 -14
  19. package/dist/esm/client/filemaker-odata.js.map +1 -1
  20. package/dist/esm/client/insert-builder.d.ts +38 -3
  21. package/dist/esm/client/insert-builder.js +195 -9
  22. package/dist/esm/client/insert-builder.js.map +1 -1
  23. package/dist/esm/client/query-builder.d.ts +19 -3
  24. package/dist/esm/client/query-builder.js +193 -17
  25. package/dist/esm/client/query-builder.js.map +1 -1
  26. package/dist/esm/client/record-builder.d.ts +17 -2
  27. package/dist/esm/client/record-builder.js +87 -5
  28. package/dist/esm/client/record-builder.js.map +1 -1
  29. package/dist/esm/client/response-processor.d.ts +38 -0
  30. package/dist/esm/client/schema-manager.d.ts +57 -0
  31. package/dist/esm/client/schema-manager.js +132 -0
  32. package/dist/esm/client/schema-manager.js.map +1 -0
  33. package/dist/esm/client/update-builder.d.ts +34 -11
  34. package/dist/esm/client/update-builder.js +119 -19
  35. package/dist/esm/client/update-builder.js.map +1 -1
  36. package/dist/esm/errors.d.ts +14 -1
  37. package/dist/esm/errors.js +26 -0
  38. package/dist/esm/errors.js.map +1 -1
  39. package/dist/esm/index.d.ts +3 -2
  40. package/dist/esm/index.js +3 -1
  41. package/dist/esm/transform.d.ts +9 -0
  42. package/dist/esm/transform.js +7 -0
  43. package/dist/esm/transform.js.map +1 -1
  44. package/dist/esm/types.d.ts +69 -1
  45. package/package.json +1 -1
  46. package/src/client/batch-builder.ts +265 -0
  47. package/src/client/batch-request.ts +485 -0
  48. package/src/client/database.ts +106 -52
  49. package/src/client/delete-builder.ts +116 -14
  50. package/src/client/entity-set.ts +80 -6
  51. package/src/client/filemaker-odata.ts +65 -19
  52. package/src/client/insert-builder.ts +296 -18
  53. package/src/client/query-builder.ts +278 -17
  54. package/src/client/record-builder.ts +119 -11
  55. package/src/client/response-processor.ts +103 -0
  56. package/src/client/schema-manager.ts +246 -0
  57. package/src/client/update-builder.ts +195 -37
  58. package/src/errors.ts +33 -1
  59. package/src/index.ts +13 -0
  60. package/src/transform.ts +19 -6
  61. package/src/types.ts +89 -1
@@ -2,7 +2,7 @@ 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
4
  import { QueryBuilder } from "./query-builder.js";
5
- import { transformTableName, transformFieldNamesToIds } from "../transform.js";
5
+ import { getTableIdentifiers, transformFieldNamesToIds } from "../transform.js";
6
6
  class UpdateBuilder {
7
7
  constructor(config) {
8
8
  __publicField(this, "tableName");
@@ -10,15 +10,19 @@ class UpdateBuilder {
10
10
  __publicField(this, "context");
11
11
  __publicField(this, "occurrence");
12
12
  __publicField(this, "data");
13
+ __publicField(this, "returnPreference");
14
+ __publicField(this, "databaseUseEntityIds");
13
15
  this.occurrence = config.occurrence;
14
16
  this.tableName = config.tableName;
15
17
  this.databaseName = config.databaseName;
16
18
  this.context = config.context;
17
19
  this.data = config.data;
20
+ this.returnPreference = config.returnPreference;
21
+ this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;
18
22
  }
19
23
  /**
20
24
  * Update a single record by ID
21
- * Returns the count of updated records (0 or 1)
25
+ * Returns updated count by default, or full record if returnFullRecord was set to true
22
26
  */
23
27
  byId(id) {
24
28
  return new ExecutableUpdateBuilder({
@@ -28,12 +32,14 @@ class UpdateBuilder {
28
32
  context: this.context,
29
33
  data: this.data,
30
34
  mode: "byId",
31
- recordId: id
35
+ recordId: id,
36
+ returnPreference: this.returnPreference,
37
+ databaseUseEntityIds: this.databaseUseEntityIds
32
38
  });
33
39
  }
34
40
  /**
35
41
  * Update records matching a filter query
36
- * Returns the count of updated records
42
+ * Returns updated count by default, or full record if returnFullRecord was set to true
37
43
  * @param fn Callback that receives a QueryBuilder for building the filter
38
44
  */
39
45
  where(fn) {
@@ -51,7 +57,9 @@ class UpdateBuilder {
51
57
  context: this.context,
52
58
  data: this.data,
53
59
  mode: "byFilter",
54
- queryBuilder: configuredBuilder
60
+ queryBuilder: configuredBuilder,
61
+ returnPreference: this.returnPreference,
62
+ databaseUseEntityIds: this.databaseUseEntityIds
55
63
  });
56
64
  }
57
65
  }
@@ -65,6 +73,8 @@ class ExecutableUpdateBuilder {
65
73
  __publicField(this, "mode");
66
74
  __publicField(this, "recordId");
67
75
  __publicField(this, "queryBuilder");
76
+ __publicField(this, "returnPreference");
77
+ __publicField(this, "databaseUseEntityIds");
68
78
  this.occurrence = config.occurrence;
69
79
  this.tableName = config.tableName;
70
80
  this.databaseName = config.databaseName;
@@ -73,11 +83,46 @@ class ExecutableUpdateBuilder {
73
83
  this.mode = config.mode;
74
84
  this.recordId = config.recordId;
75
85
  this.queryBuilder = config.queryBuilder;
86
+ this.returnPreference = config.returnPreference;
87
+ this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;
88
+ }
89
+ /**
90
+ * Helper to merge database-level useEntityIds with per-request options
91
+ */
92
+ mergeExecuteOptions(options) {
93
+ return {
94
+ ...options,
95
+ useEntityIds: (options == null ? void 0 : options.useEntityIds) ?? this.databaseUseEntityIds
96
+ };
97
+ }
98
+ /**
99
+ * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name
100
+ * @param useEntityIds - Optional override for entity ID usage
101
+ */
102
+ getTableId(useEntityIds) {
103
+ var _a, _b;
104
+ if (!this.occurrence) {
105
+ return this.tableName;
106
+ }
107
+ const contextDefault = ((_b = (_a = this.context)._getUseEntityIds) == null ? void 0 : _b.call(_a)) ?? false;
108
+ const shouldUseIds = useEntityIds ?? contextDefault;
109
+ if (shouldUseIds) {
110
+ const identifiers = getTableIdentifiers(this.occurrence);
111
+ if (!identifiers.id) {
112
+ throw new Error(
113
+ `useEntityIds is true but TableOccurrence "${identifiers.name}" does not have an fmtId defined`
114
+ );
115
+ }
116
+ return identifiers.id;
117
+ }
118
+ return this.occurrence.getTableName();
76
119
  }
77
120
  async execute(options) {
78
121
  var _a;
79
- const tableId = this.occurrence ? transformTableName(this.occurrence) : this.tableName;
80
- const transformedData = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) ? transformFieldNamesToIds(this.data, this.occurrence.baseTable) : this.data;
122
+ const mergedOptions = this.mergeExecuteOptions(options);
123
+ const tableId = this.getTableId(mergedOptions.useEntityIds);
124
+ const shouldUseIds = mergedOptions.useEntityIds ?? false;
125
+ const transformedData = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) && shouldUseIds ? transformFieldNamesToIds(this.data, this.occurrence.baseTable) : this.data;
81
126
  let url;
82
127
  if (this.mode === "byId") {
83
128
  url = `/${this.databaseName}/${tableId}('${this.recordId}')`;
@@ -89,30 +134,44 @@ class ExecutableUpdateBuilder {
89
134
  const queryParams = queryString.startsWith(`/${tableId}`) ? queryString.slice(`/${tableId}`.length) : queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
90
135
  url = `/${this.databaseName}/${tableId}${queryParams}`;
91
136
  }
137
+ const headers = {
138
+ "Content-Type": "application/json"
139
+ };
140
+ if (this.returnPreference === "representation") {
141
+ headers["Prefer"] = "return=representation";
142
+ }
92
143
  const result = await this.context._makeRequest(url, {
93
144
  method: "PATCH",
94
- headers: {
95
- "Content-Type": "application/json"
96
- },
145
+ headers,
97
146
  body: JSON.stringify(transformedData),
98
- ...options
147
+ ...mergedOptions
99
148
  });
100
149
  if (result.error) {
101
150
  return { data: void 0, error: result.error };
102
151
  }
103
152
  const response = result.data;
104
- let updatedCount = 0;
105
- if (typeof response === "number") {
106
- updatedCount = response;
107
- } else if (response && typeof response === "object") {
108
- updatedCount = response.updatedCount || 0;
153
+ if (this.returnPreference === "representation") {
154
+ return {
155
+ data: response,
156
+ error: void 0
157
+ };
158
+ } else {
159
+ let updatedCount = 0;
160
+ if (typeof response === "number") {
161
+ updatedCount = response;
162
+ } else if (response && typeof response === "object") {
163
+ updatedCount = response.updatedCount || 0;
164
+ }
165
+ return {
166
+ data: { updatedCount },
167
+ error: void 0
168
+ };
109
169
  }
110
- return { data: { updatedCount }, error: void 0 };
111
170
  }
112
171
  getRequestConfig() {
113
172
  var _a;
114
- const tableId = this.occurrence ? transformTableName(this.occurrence) : this.tableName;
115
- const transformedData = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) ? transformFieldNamesToIds(this.data, this.occurrence.baseTable) : this.data;
173
+ const tableId = this.getTableId(this.databaseUseEntityIds);
174
+ const transformedData = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) && this.databaseUseEntityIds ? transformFieldNamesToIds(this.data, this.occurrence.baseTable) : this.data;
116
175
  let url;
117
176
  if (this.mode === "byId") {
118
177
  url = `/${this.databaseName}/${tableId}('${this.recordId}')`;
@@ -130,6 +189,47 @@ class ExecutableUpdateBuilder {
130
189
  body: JSON.stringify(transformedData)
131
190
  };
132
191
  }
192
+ toRequest(baseUrl) {
193
+ const config = this.getRequestConfig();
194
+ const fullUrl = `${baseUrl}${config.url}`;
195
+ return new Request(fullUrl, {
196
+ method: config.method,
197
+ headers: {
198
+ "Content-Type": "application/json",
199
+ Accept: "application/json"
200
+ },
201
+ body: config.body
202
+ });
203
+ }
204
+ async processResponse(response, options) {
205
+ const text = await response.text();
206
+ if (!text || text.trim() === "") {
207
+ const affectedRows = response.headers.get("fmodata.affected_rows");
208
+ const updatedCount = affectedRows ? parseInt(affectedRows, 10) : 1;
209
+ return {
210
+ data: { updatedCount },
211
+ error: void 0
212
+ };
213
+ }
214
+ const rawResponse = JSON.parse(text);
215
+ if (this.returnPreference === "representation") {
216
+ return {
217
+ data: rawResponse,
218
+ error: void 0
219
+ };
220
+ } else {
221
+ let updatedCount = 0;
222
+ if (typeof rawResponse === "number") {
223
+ updatedCount = rawResponse;
224
+ } else if (rawResponse && typeof rawResponse === "object") {
225
+ updatedCount = rawResponse.updatedCount || 0;
226
+ }
227
+ return {
228
+ data: { updatedCount },
229
+ error: void 0
230
+ };
231
+ }
232
+ }
133
233
  }
134
234
  export {
135
235
  ExecutableUpdateBuilder,
@@ -1 +1 @@
1
- {"version":3,"file":"update-builder.js","sources":["../../../src/client/update-builder.ts"],"sourcesContent":["import type {\n ExecutionContext,\n ExecutableBuilder,\n Result,\n WithSystemFields,\n} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport {\n transformFieldNamesToIds,\n transformTableName,\n} from \"../transform\";\n\n/**\n * Initial update builder returned from EntitySet.update(data)\n * Requires calling .byId() or .where() before .execute() is available\n */\nexport class UpdateBuilder<\n T extends Record<string, any>,\n BT extends BaseTable<any, any, any, any>,\n> {\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private data: Partial<T>;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n data: Partial<T>;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.data = config.data;\n }\n\n /**\n * Update a single record by ID\n * Returns the count of updated records (0 or 1)\n */\n byId(id: string | number): ExecutableUpdateBuilder<T, true> {\n return new ExecutableUpdateBuilder<T, true>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: this.data,\n mode: \"byId\",\n recordId: id,\n });\n }\n\n /**\n * Update records matching a filter query\n * Returns the count of updated records\n * @param fn Callback that receives a QueryBuilder for building the filter\n */\n where(\n fn: (\n q: QueryBuilder<WithSystemFields<T>>,\n ) => QueryBuilder<WithSystemFields<T>>,\n ): ExecutableUpdateBuilder<T, true> {\n // Create a QueryBuilder for the user to configure\n const queryBuilder = new QueryBuilder<\n WithSystemFields<T>,\n keyof WithSystemFields<T>,\n false,\n false,\n undefined\n >({\n occurrence: undefined,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Let the user configure it\n const configuredBuilder = fn(queryBuilder);\n\n return new ExecutableUpdateBuilder<T, true>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: this.data,\n mode: \"byFilter\",\n queryBuilder: configuredBuilder,\n });\n }\n}\n\n/**\n * Executable update builder - has execute() method\n * Returned after calling .byId() or .where()\n * Both modes return the count of updated records\n */\nexport class ExecutableUpdateBuilder<\n T extends Record<string, any>,\n IsByFilter extends boolean,\n> implements ExecutableBuilder<{ updatedCount: number }>\n{\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private data: Partial<T>;\n private mode: \"byId\" | \"byFilter\";\n private recordId?: string | number;\n private queryBuilder?: QueryBuilder<any>;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n data: Partial<T>;\n mode: \"byId\" | \"byFilter\";\n recordId?: string | number;\n queryBuilder?: QueryBuilder<any>;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.data = config.data;\n this.mode = config.mode;\n this.recordId = config.recordId;\n this.queryBuilder = config.queryBuilder;\n }\n\n async execute(\n options?: RequestInit & FFetchOptions,\n ): Promise<Result<{ updatedCount: number }>> {\n // Transform table name to FMTID if using entity IDs\n const tableId = this.occurrence\n ? transformTableName(this.occurrence)\n : this.tableName;\n\n // Transform field names to FMFIDs if using entity IDs\n const transformedData = this.occurrence?.baseTable\n ? transformFieldNamesToIds(this.data, this.occurrence.baseTable)\n : this.data;\n\n let url: string;\n\n if (this.mode === \"byId\") {\n // Update single record by ID: PATCH /{database}/{table}('id')\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n // Update by filter: PATCH /{database}/{table}?$filter=...\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based update\");\n }\n\n // Get the query string from the configured QueryBuilder\n const queryString = this.queryBuilder.getQueryString();\n // The query string will have the tableId already transformed by QueryBuilder\n // Remove the leading \"/\" and table name from the query string as we'll build our own URL\n const queryParams = queryString.startsWith(`/${tableId}`)\n ? queryString.slice(`/${tableId}`.length)\n : queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n // Make PATCH request with JSON body\n const result = await this.context._makeRequest(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(transformedData),\n ...options,\n });\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n const response = result.data;\n\n // Both byId and byFilter return affected row count\n let updatedCount = 0;\n\n if (typeof response === \"number\") {\n updatedCount = response;\n } else if (response && typeof response === \"object\") {\n // Check if the response has a count property (fallback)\n updatedCount = (response as any).updatedCount || 0;\n }\n\n return { data: { updatedCount }, error: undefined };\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n // Transform table name to FMTID if using entity IDs\n const tableId = this.occurrence\n ? transformTableName(this.occurrence)\n : this.tableName;\n\n // Transform field names to FMFIDs if using entity IDs\n const transformedData = this.occurrence?.baseTable\n ? transformFieldNamesToIds(this.data, this.occurrence.baseTable)\n : this.data;\n\n let url: string;\n\n if (this.mode === \"byId\") {\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based update\");\n }\n\n const queryString = this.queryBuilder.getQueryString();\n const queryParams = queryString.startsWith(`/${tableId}`)\n ? queryString.slice(`/${tableId}`.length)\n : queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n return {\n method: \"PATCH\",\n url,\n body: JSON.stringify(transformedData),\n };\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update-builder.js","sources":["../../../src/client/update-builder.ts"],"sourcesContent":["import type {\n ExecutionContext,\n ExecutableBuilder,\n Result,\n WithSystemFields,\n ExecuteOptions,\n} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport {\n transformFieldNamesToIds,\n transformTableName,\n getTableIdentifiers,\n} from \"../transform\";\n\n/**\n * Initial update builder returned from EntitySet.update(data)\n * Requires calling .byId() or .where() before .execute() is available\n */\nexport class UpdateBuilder<\n T extends Record<string, any>,\n BT extends BaseTable<any, any, any, any>,\n ReturnPreference extends \"minimal\" | \"representation\" = \"minimal\",\n> {\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private data: Partial<T>;\n private returnPreference: ReturnPreference;\n\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n data: Partial<T>;\n returnPreference: ReturnPreference;\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.data = config.data;\n this.returnPreference = config.returnPreference;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n }\n\n /**\n * Update a single record by ID\n * Returns updated count by default, or full record if returnFullRecord was set to true\n */\n byId(\n id: string | number,\n ): ExecutableUpdateBuilder<T, true, ReturnPreference> {\n return new ExecutableUpdateBuilder<T, true, ReturnPreference>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: this.data,\n mode: \"byId\",\n recordId: id,\n returnPreference: this.returnPreference,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n\n /**\n * Update records matching a filter query\n * Returns updated count by default, or full record if returnFullRecord was set to true\n * @param fn Callback that receives a QueryBuilder for building the filter\n */\n where(\n fn: (\n q: QueryBuilder<WithSystemFields<T>>,\n ) => QueryBuilder<WithSystemFields<T>>,\n ): ExecutableUpdateBuilder<T, true, ReturnPreference> {\n // Create a QueryBuilder for the user to configure\n const queryBuilder = new QueryBuilder<\n WithSystemFields<T>,\n keyof WithSystemFields<T>,\n false,\n false,\n undefined\n >({\n occurrence: undefined,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Let the user configure it\n const configuredBuilder = fn(queryBuilder);\n\n return new ExecutableUpdateBuilder<T, true, ReturnPreference>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: this.data,\n mode: \"byFilter\",\n queryBuilder: configuredBuilder,\n returnPreference: this.returnPreference,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n}\n\n/**\n * Executable update builder - has execute() method\n * Returned after calling .byId() or .where()\n * Can return either updated count or full record based on returnFullRecord option\n */\nexport class ExecutableUpdateBuilder<\n T extends Record<string, any>,\n IsByFilter extends boolean,\n ReturnPreference extends \"minimal\" | \"representation\" = \"minimal\",\n> implements\n ExecutableBuilder<\n ReturnPreference extends \"minimal\" ? { updatedCount: number } : T\n >\n{\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private data: Partial<T>;\n private mode: \"byId\" | \"byFilter\";\n private recordId?: string | number;\n private queryBuilder?: QueryBuilder<any>;\n private returnPreference: ReturnPreference;\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n data: Partial<T>;\n mode: \"byId\" | \"byFilter\";\n recordId?: string | number;\n queryBuilder?: QueryBuilder<any>;\n returnPreference: ReturnPreference;\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.data = config.data;\n this.mode = config.mode;\n this.recordId = config.recordId;\n this.queryBuilder = config.queryBuilder;\n this.returnPreference = config.returnPreference;\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 async execute(\n options?: RequestInit & FFetchOptions & { useEntityIds?: boolean },\n ): Promise<\n Result<ReturnPreference extends \"minimal\" ? { updatedCount: number } : T>\n > {\n // Merge database-level useEntityIds with per-request options\n const mergedOptions = this.mergeExecuteOptions(options);\n\n // Get table identifier with override support\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n\n // Transform field names to FMFIDs if using entity IDs\n // Only transform if useEntityIds resolves to true (respects per-request override)\n const shouldUseIds = mergedOptions.useEntityIds ?? false;\n\n const transformedData =\n this.occurrence?.baseTable && shouldUseIds\n ? transformFieldNamesToIds(this.data, this.occurrence.baseTable)\n : this.data;\n\n let url: string;\n\n if (this.mode === \"byId\") {\n // Update single record by ID: PATCH /{database}/{table}('id')\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n // Update by filter: PATCH /{database}/{table}?$filter=...\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based update\");\n }\n\n // Get the query string from the configured QueryBuilder\n const queryString = this.queryBuilder.getQueryString();\n // The query string will have the tableId already transformed by QueryBuilder\n // Remove the leading \"/\" and table name from the query string as we'll build our own URL\n const queryParams = queryString.startsWith(`/${tableId}`)\n ? queryString.slice(`/${tableId}`.length)\n : queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n // Set Prefer header based on returnPreference\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this.returnPreference === \"representation\") {\n headers[\"Prefer\"] = \"return=representation\";\n }\n\n // Make PATCH request with JSON body\n const result = await this.context._makeRequest(url, {\n method: \"PATCH\",\n headers,\n body: JSON.stringify(transformedData),\n ...mergedOptions,\n });\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n const response = result.data;\n\n // Handle based on return preference\n if (this.returnPreference === \"representation\") {\n // Return the full updated record\n return {\n data: response as ReturnPreference extends \"minimal\"\n ? { updatedCount: number }\n : T,\n error: undefined,\n };\n } else {\n // Return updated count (minimal)\n let updatedCount = 0;\n\n if (typeof response === \"number\") {\n updatedCount = response;\n } else if (response && typeof response === \"object\") {\n // Check if the response has a count property (fallback)\n updatedCount = (response as any).updatedCount || 0;\n }\n\n return {\n data: { updatedCount } as ReturnPreference extends \"minimal\"\n ? { updatedCount: number }\n : T,\n error: undefined,\n };\n }\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n // For batch operations, use database-level setting (no per-request override available here)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n\n // Transform field names to FMFIDs if using entity IDs\n const transformedData =\n this.occurrence?.baseTable && this.databaseUseEntityIds\n ? transformFieldNamesToIds(this.data, this.occurrence.baseTable)\n : this.data;\n\n let url: string;\n\n if (this.mode === \"byId\") {\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based update\");\n }\n\n const queryString = this.queryBuilder.getQueryString();\n const queryParams = queryString.startsWith(`/${tableId}`)\n ? queryString.slice(`/${tableId}`.length)\n : queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n return {\n method: \"PATCH\",\n url,\n body: JSON.stringify(transformedData),\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 body: config.body,\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<ReturnPreference extends \"minimal\" ? { updatedCount: number } : T>\n > {\n // Check for empty response (204 No Content)\n const text = await response.text();\n if (!text || text.trim() === \"\") {\n // For 204 No Content, check the fmodata.affected_rows header\n const affectedRows = response.headers.get(\"fmodata.affected_rows\");\n const updatedCount = affectedRows ? parseInt(affectedRows, 10) : 1;\n return {\n data: { updatedCount } as ReturnPreference extends \"minimal\"\n ? { updatedCount: number }\n : T,\n error: undefined,\n };\n }\n\n const rawResponse = JSON.parse(text);\n\n // Handle based on return preference\n if (this.returnPreference === \"representation\") {\n // Return the full updated record\n return {\n data: rawResponse as ReturnPreference extends \"minimal\"\n ? { updatedCount: number }\n : T,\n error: undefined,\n };\n } else {\n // Return updated count (minimal)\n let updatedCount = 0;\n\n if (typeof rawResponse === \"number\") {\n updatedCount = rawResponse;\n } else if (rawResponse && typeof rawResponse === \"object\") {\n // Check if the response has a count property (fallback)\n updatedCount = (rawResponse as any).updatedCount || 0;\n }\n\n return {\n data: { updatedCount } as ReturnPreference extends \"minimal\"\n ? { updatedCount: number }\n : T,\n error: undefined,\n };\n }\n }\n}\n"],"names":[],"mappings":";;;;;AAqBO,MAAM,cAIX;AAAA,EAUA,YAAY,QAQT;AAjBK;AACA;AACA;AACA;AACA;AACA;AAEA;AAWN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AACtB,SAAK,OAAO,OAAO;AACnB,SAAK,mBAAmB,OAAO;AAC1B,SAAA,uBAAuB,OAAO,wBAAwB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7D,KACE,IACoD;AACpD,WAAO,IAAI,wBAAmD;AAAA,MAC5D,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,MAAM;AAAA,MACN,UAAU;AAAA,MACV,kBAAkB,KAAK;AAAA,MACvB,sBAAsB,KAAK;AAAA,IAAA,CAC5B;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQH,MACE,IAGoD;AAE9C,UAAA,eAAe,IAAI,aAMvB;AAAA,MACA,YAAY;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAGK,UAAA,oBAAoB,GAAG,YAAY;AAEzC,WAAO,IAAI,wBAAmD;AAAA,MAC5D,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,MAAM;AAAA,MACN,cAAc;AAAA,MACd,kBAAkB,KAAK;AAAA,MACvB,sBAAsB,KAAK;AAAA,IAAA,CAC5B;AAAA,EAAA;AAEL;AAOO,MAAM,wBAQb;AAAA,EAYE,YAAY,QAWT;AAtBK;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AACtB,SAAK,OAAO,OAAO;AACnB,SAAK,OAAO,OAAO;AACnB,SAAK,WAAW,OAAO;AACvB,SAAK,eAAe,OAAO;AAC3B,SAAK,mBAAmB,OAAO;AAC1B,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,MAAM,QACJ,SAGA;;AAEM,UAAA,gBAAgB,KAAK,oBAAoB,OAAO;AAGtD,UAAM,UAAU,KAAK,WAAW,cAAc,YAAY;AAIpD,UAAA,eAAe,cAAc,gBAAgB;AAEnD,UAAM,oBACJ,UAAK,eAAL,mBAAiB,cAAa,eAC1B,yBAAyB,KAAK,MAAM,KAAK,WAAW,SAAS,IAC7D,KAAK;AAEP,QAAA;AAEA,QAAA,KAAK,SAAS,QAAQ;AAExB,YAAM,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAA,IAAA,OACnD;AAED,UAAA,CAAC,KAAK,cAAc;AAChB,cAAA,IAAI,MAAM,mDAAmD;AAAA,MAAA;AAI/D,YAAA,cAAc,KAAK,aAAa,eAAe;AAGrD,YAAM,cAAc,YAAY,WAAW,IAAI,OAAO,EAAE,IACpD,YAAY,MAAM,IAAI,OAAO,GAAG,MAAM,IACtC,YAAY,WAAW,IAAI,KAAK,SAAS,EAAE,IACzC,YAAY,MAAM,IAAI,KAAK,SAAS,GAAG,MAAM,IAC7C;AAEN,YAAM,IAAI,KAAK,YAAY,IAAI,OAAO,GAAG,WAAW;AAAA,IAAA;AAItD,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,IAClB;AAEI,QAAA,KAAK,qBAAqB,kBAAkB;AAC9C,cAAQ,QAAQ,IAAI;AAAA,IAAA;AAItB,UAAM,SAAS,MAAM,KAAK,QAAQ,aAAa,KAAK;AAAA,MAClD,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,KAAK,UAAU,eAAe;AAAA,MACpC,GAAG;AAAA,IAAA,CACJ;AAED,QAAI,OAAO,OAAO;AAChB,aAAO,EAAE,MAAM,QAAW,OAAO,OAAO,MAAM;AAAA,IAAA;AAGhD,UAAM,WAAW,OAAO;AAGpB,QAAA,KAAK,qBAAqB,kBAAkB;AAEvC,aAAA;AAAA,QACL,MAAM;AAAA,QAGN,OAAO;AAAA,MACT;AAAA,IAAA,OACK;AAEL,UAAI,eAAe;AAEf,UAAA,OAAO,aAAa,UAAU;AACjB,uBAAA;AAAA,MACN,WAAA,YAAY,OAAO,aAAa,UAAU;AAEnD,uBAAgB,SAAiB,gBAAgB;AAAA,MAAA;AAG5C,aAAA;AAAA,QACL,MAAM,EAAE,aAAa;AAAA,QAGrB,OAAO;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,mBAAgE;;AAE9D,UAAM,UAAU,KAAK,WAAW,KAAK,oBAAoB;AAGzD,UAAM,oBACJ,UAAK,eAAL,mBAAiB,cAAa,KAAK,uBAC/B,yBAAyB,KAAK,MAAM,KAAK,WAAW,SAAS,IAC7D,KAAK;AAEP,QAAA;AAEA,QAAA,KAAK,SAAS,QAAQ;AACxB,YAAM,IAAI,KAAK,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ;AAAA,IAAA,OACnD;AACD,UAAA,CAAC,KAAK,cAAc;AAChB,cAAA,IAAI,MAAM,mDAAmD;AAAA,MAAA;AAG/D,YAAA,cAAc,KAAK,aAAa,eAAe;AACrD,YAAM,cAAc,YAAY,WAAW,IAAI,OAAO,EAAE,IACpD,YAAY,MAAM,IAAI,OAAO,GAAG,MAAM,IACtC,YAAY,WAAW,IAAI,KAAK,SAAS,EAAE,IACzC,YAAY,MAAM,IAAI,KAAK,SAAS,GAAG,MAAM,IAC7C;AAEN,YAAM,IAAI,KAAK,YAAY,IAAI,OAAO,GAAG,WAAW;AAAA,IAAA;AAG/C,WAAA;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,KAAK,UAAU,eAAe;AAAA,IACtC;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,MACV;AAAA,MACA,MAAM,OAAO;AAAA,IAAA,CACd;AAAA,EAAA;AAAA,EAGH,MAAM,gBACJ,UACA,SAGA;AAEM,UAAA,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,QAAQ,KAAK,KAAA,MAAW,IAAI;AAE/B,YAAM,eAAe,SAAS,QAAQ,IAAI,uBAAuB;AACjE,YAAM,eAAe,eAAe,SAAS,cAAc,EAAE,IAAI;AAC1D,aAAA;AAAA,QACL,MAAM,EAAE,aAAa;AAAA,QAGrB,OAAO;AAAA,MACT;AAAA,IAAA;AAGI,UAAA,cAAc,KAAK,MAAM,IAAI;AAG/B,QAAA,KAAK,qBAAqB,kBAAkB;AAEvC,aAAA;AAAA,QACL,MAAM;AAAA,QAGN,OAAO;AAAA,MACT;AAAA,IAAA,OACK;AAEL,UAAI,eAAe;AAEf,UAAA,OAAO,gBAAgB,UAAU;AACpB,uBAAA;AAAA,MACN,WAAA,eAAe,OAAO,gBAAgB,UAAU;AAEzD,uBAAgB,YAAoB,gBAAgB;AAAA,MAAA;AAG/C,aAAA;AAAA,QACL,MAAM,EAAE,aAAa;AAAA,QAGrB,OAAO;AAAA,MACT;AAAA,IAAA;AAAA,EACF;AAEJ;"}
@@ -27,6 +27,13 @@ export declare class ODataError extends FMODataError {
27
27
  readonly details?: any;
28
28
  constructor(url: string, message: string, code?: string, details?: any);
29
29
  }
30
+ export declare class SchemaLockedError extends FMODataError {
31
+ readonly kind: "SchemaLockedError";
32
+ readonly url: string;
33
+ readonly code: string;
34
+ readonly details?: any;
35
+ constructor(url: string, message: string, details?: any);
36
+ }
30
37
  export declare class ValidationError extends FMODataError {
31
38
  readonly kind: "ValidationError";
32
39
  readonly field?: string;
@@ -50,11 +57,17 @@ export declare class RecordCountMismatchError extends FMODataError {
50
57
  readonly received: number;
51
58
  constructor(expected: number | "one" | "at-most-one", received: number);
52
59
  }
60
+ export declare class InvalidLocationHeaderError extends FMODataError {
61
+ readonly kind: "InvalidLocationHeaderError";
62
+ readonly locationHeader?: string;
63
+ constructor(message: string, locationHeader?: string);
64
+ }
53
65
  export declare function isHTTPError(error: unknown): error is HTTPError;
54
66
  export declare function isValidationError(error: unknown): error is ValidationError;
55
67
  export declare function isODataError(error: unknown): error is ODataError;
68
+ export declare function isSchemaLockedError(error: unknown): error is SchemaLockedError;
56
69
  export declare function isResponseStructureError(error: unknown): error is ResponseStructureError;
57
70
  export declare function isRecordCountMismatchError(error: unknown): error is RecordCountMismatchError;
58
71
  export declare function isFMODataError(error: unknown): error is FMODataError;
59
72
  export type { TimeoutError, AbortError, NetworkError, RetryLimitError, CircuitOpenError, } from '@fetchkit/ffetch';
60
- export type FMODataErrorType = import('@fetchkit/ffetch').TimeoutError | import('@fetchkit/ffetch').AbortError | import('@fetchkit/ffetch').NetworkError | import('@fetchkit/ffetch').RetryLimitError | import('@fetchkit/ffetch').CircuitOpenError | HTTPError | ODataError | ValidationError | ResponseStructureError | RecordCountMismatchError;
73
+ export type FMODataErrorType = import('@fetchkit/ffetch').TimeoutError | import('@fetchkit/ffetch').AbortError | import('@fetchkit/ffetch').NetworkError | import('@fetchkit/ffetch').RetryLimitError | import('@fetchkit/ffetch').CircuitOpenError | HTTPError | ODataError | SchemaLockedError | ValidationError | ResponseStructureError | RecordCountMismatchError | InvalidLocationHeaderError;
@@ -51,6 +51,18 @@ class ODataError extends FMODataError {
51
51
  this.details = details;
52
52
  }
53
53
  }
54
+ class SchemaLockedError extends FMODataError {
55
+ constructor(url, message, details) {
56
+ super(`OData error: ${message}`);
57
+ __publicField(this, "kind", "SchemaLockedError");
58
+ __publicField(this, "url");
59
+ __publicField(this, "code");
60
+ __publicField(this, "details");
61
+ this.url = url;
62
+ this.code = "303";
63
+ this.details = details;
64
+ }
65
+ }
54
66
  class ValidationError extends FMODataError {
55
67
  constructor(message, issues, options) {
56
68
  super(
@@ -87,6 +99,14 @@ class RecordCountMismatchError extends FMODataError {
87
99
  this.received = received;
88
100
  }
89
101
  }
102
+ class InvalidLocationHeaderError extends FMODataError {
103
+ constructor(message, locationHeader) {
104
+ super(message);
105
+ __publicField(this, "kind", "InvalidLocationHeaderError");
106
+ __publicField(this, "locationHeader");
107
+ this.locationHeader = locationHeader;
108
+ }
109
+ }
90
110
  function isHTTPError(error) {
91
111
  return error instanceof HTTPError;
92
112
  }
@@ -96,6 +116,9 @@ function isValidationError(error) {
96
116
  function isODataError(error) {
97
117
  return error instanceof ODataError;
98
118
  }
119
+ function isSchemaLockedError(error) {
120
+ return error instanceof SchemaLockedError;
121
+ }
99
122
  function isResponseStructureError(error) {
100
123
  return error instanceof ResponseStructureError;
101
124
  }
@@ -108,15 +131,18 @@ function isFMODataError(error) {
108
131
  export {
109
132
  FMODataError,
110
133
  HTTPError,
134
+ InvalidLocationHeaderError,
111
135
  ODataError,
112
136
  RecordCountMismatchError,
113
137
  ResponseStructureError,
138
+ SchemaLockedError,
114
139
  ValidationError,
115
140
  isFMODataError,
116
141
  isHTTPError,
117
142
  isODataError,
118
143
  isRecordCountMismatchError,
119
144
  isResponseStructureError,
145
+ isSchemaLockedError,
120
146
  isValidationError
121
147
  };
122
148
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sources":["../../src/errors.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Base class for all fmodata errors\n */\nexport abstract class FMODataError extends Error {\n abstract readonly kind: string;\n readonly timestamp: Date;\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = this.constructor.name;\n this.timestamp = new Date();\n }\n}\n\n// ============================================\n// HTTP Errors (with status codes)\n// ============================================\n\nexport class HTTPError extends FMODataError {\n readonly kind = \"HTTPError\" as const;\n readonly url: string;\n readonly status: number;\n readonly statusText: string;\n readonly response?: any;\n\n constructor(url: string, status: number, statusText: string, response?: any) {\n super(`HTTP ${status} ${statusText} for ${url}`);\n this.url = url;\n this.status = status;\n this.statusText = statusText;\n this.response = response;\n }\n\n // Helper methods for common status checks\n is4xx(): boolean {\n return this.status >= 400 && this.status < 500;\n }\n\n is5xx(): boolean {\n return this.status >= 500 && this.status < 600;\n }\n\n isNotFound(): boolean {\n return this.status === 404;\n }\n\n isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n isForbidden(): boolean {\n return this.status === 403;\n }\n}\n\n// ============================================\n// OData Specific Errors\n// ============================================\n\nexport class ODataError extends FMODataError {\n readonly kind = \"ODataError\" as const;\n readonly url: string;\n readonly code?: string;\n readonly details?: any;\n\n constructor(url: string, message: string, code?: string, details?: any) {\n super(`OData error: ${message}`);\n this.url = url;\n this.code = code;\n this.details = details;\n }\n}\n\n// ============================================\n// Validation Errors\n// ============================================\n\nexport class ValidationError extends FMODataError {\n readonly kind = \"ValidationError\" as const;\n readonly field?: string;\n readonly issues: readonly StandardSchemaV1.Issue[];\n readonly value?: unknown;\n\n constructor(\n message: string,\n issues: readonly StandardSchemaV1.Issue[],\n options?: {\n field?: string;\n value?: unknown;\n cause?: Error[\"cause\"];\n },\n ) {\n super(\n message,\n options?.cause !== undefined ? { cause: options.cause } : undefined,\n );\n this.field = options?.field;\n this.issues = issues;\n this.value = options?.value;\n }\n}\n\nexport class ResponseStructureError extends FMODataError {\n readonly kind = \"ResponseStructureError\" as const;\n readonly expected: string;\n readonly received: any;\n\n constructor(expected: string, received: any) {\n super(`Invalid response structure: expected ${expected}`);\n this.expected = expected;\n this.received = received;\n }\n}\n\nexport class RecordCountMismatchError extends FMODataError {\n readonly kind = \"RecordCountMismatchError\" as const;\n readonly expected: number | \"one\" | \"at-most-one\";\n readonly received: number;\n\n constructor(expected: number | \"one\" | \"at-most-one\", received: number) {\n const expectedStr = typeof expected === \"number\" ? expected : expected;\n super(`Expected ${expectedStr} record(s), but received ${received}`);\n this.expected = expected;\n this.received = received;\n }\n}\n\n// ============================================\n// Type Guards\n// ============================================\n\nexport function isHTTPError(error: unknown): error is HTTPError {\n return error instanceof HTTPError;\n}\n\nexport function isValidationError(error: unknown): error is ValidationError {\n return error instanceof ValidationError;\n}\n\nexport function isODataError(error: unknown): error is ODataError {\n return error instanceof ODataError;\n}\n\nexport function isResponseStructureError(\n error: unknown,\n): error is ResponseStructureError {\n return error instanceof ResponseStructureError;\n}\n\nexport function isRecordCountMismatchError(\n error: unknown,\n): error is RecordCountMismatchError {\n return error instanceof RecordCountMismatchError;\n}\n\nexport function isFMODataError(error: unknown): error is FMODataError {\n return error instanceof FMODataError;\n}\n\n// ============================================\n// Union type for all possible errors\n// ============================================\n\n// Re-export ffetch errors (they'll be imported from @fetchkit/ffetch)\nexport type {\n TimeoutError,\n AbortError,\n NetworkError,\n RetryLimitError,\n CircuitOpenError,\n} from \"@fetchkit/ffetch\";\n\nexport type FMODataErrorType =\n | import(\"@fetchkit/ffetch\").TimeoutError\n | import(\"@fetchkit/ffetch\").AbortError\n | import(\"@fetchkit/ffetch\").NetworkError\n | import(\"@fetchkit/ffetch\").RetryLimitError\n | import(\"@fetchkit/ffetch\").CircuitOpenError\n | HTTPError\n | ODataError\n | ValidationError\n | ResponseStructureError\n | RecordCountMismatchError;\n"],"names":[],"mappings":";;;AAKO,MAAe,qBAAqB,MAAM;AAAA,EAI/C,YAAY,SAAiB,SAAwB;AACnD,UAAM,SAAS,OAAO;AAHf;AAIF,SAAA,OAAO,KAAK,YAAY;AACxB,SAAA,gCAAgB,KAAK;AAAA,EAAA;AAE9B;AAMO,MAAM,kBAAkB,aAAa;AAAA,EAO1C,YAAY,KAAa,QAAgB,YAAoB,UAAgB;AAC3E,UAAM,QAAQ,MAAM,IAAI,UAAU,QAAQ,GAAG,EAAE;AAPxC,gCAAO;AACP;AACA;AACA;AACA;AAIP,SAAK,MAAM;AACX,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAAA;AAAA;AAAA,EAIlB,QAAiB;AACf,WAAO,KAAK,UAAU,OAAO,KAAK,SAAS;AAAA,EAAA;AAAA,EAG7C,QAAiB;AACf,WAAO,KAAK,UAAU,OAAO,KAAK,SAAS;AAAA,EAAA;AAAA,EAG7C,aAAsB;AACpB,WAAO,KAAK,WAAW;AAAA,EAAA;AAAA,EAGzB,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EAAA;AAAA,EAGzB,cAAuB;AACrB,WAAO,KAAK,WAAW;AAAA,EAAA;AAE3B;AAMO,MAAM,mBAAmB,aAAa;AAAA,EAM3C,YAAY,KAAa,SAAiB,MAAe,SAAe;AAChE,UAAA,gBAAgB,OAAO,EAAE;AANxB,gCAAO;AACP;AACA;AACA;AAIP,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EAAA;AAEnB;AAMO,MAAM,wBAAwB,aAAa;AAAA,EAMhD,YACE,SACA,QACA,SAKA;AACA;AAAA,MACE;AAAA,OACA,mCAAS,WAAU,SAAY,EAAE,OAAO,QAAQ,UAAU;AAAA,IAC5D;AAjBO,gCAAO;AACP;AACA;AACA;AAeP,SAAK,QAAQ,mCAAS;AACtB,SAAK,SAAS;AACd,SAAK,QAAQ,mCAAS;AAAA,EAAA;AAE1B;AAEO,MAAM,+BAA+B,aAAa;AAAA,EAKvD,YAAY,UAAkB,UAAe;AACrC,UAAA,wCAAwC,QAAQ,EAAE;AALjD,gCAAO;AACP;AACA;AAIP,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAAA;AAEpB;AAEO,MAAM,iCAAiC,aAAa;AAAA,EAKzD,YAAY,UAA0C,UAAkB;AACtE,UAAM,cAAc,OAAO,aAAa,WAAW,WAAW;AAC9D,UAAM,YAAY,WAAW,4BAA4B,QAAQ,EAAE;AAN5D,gCAAO;AACP;AACA;AAKP,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAAA;AAEpB;AAMO,SAAS,YAAY,OAAoC;AAC9D,SAAO,iBAAiB;AAC1B;AAEO,SAAS,kBAAkB,OAA0C;AAC1E,SAAO,iBAAiB;AAC1B;AAEO,SAAS,aAAa,OAAqC;AAChE,SAAO,iBAAiB;AAC1B;AAEO,SAAS,yBACd,OACiC;AACjC,SAAO,iBAAiB;AAC1B;AAEO,SAAS,2BACd,OACmC;AACnC,SAAO,iBAAiB;AAC1B;AAEO,SAAS,eAAe,OAAuC;AACpE,SAAO,iBAAiB;AAC1B;"}
1
+ {"version":3,"file":"errors.js","sources":["../../src/errors.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Base class for all fmodata errors\n */\nexport abstract class FMODataError extends Error {\n abstract readonly kind: string;\n readonly timestamp: Date;\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = this.constructor.name;\n this.timestamp = new Date();\n }\n}\n\n// ============================================\n// HTTP Errors (with status codes)\n// ============================================\n\nexport class HTTPError extends FMODataError {\n readonly kind = \"HTTPError\" as const;\n readonly url: string;\n readonly status: number;\n readonly statusText: string;\n readonly response?: any;\n\n constructor(url: string, status: number, statusText: string, response?: any) {\n super(`HTTP ${status} ${statusText} for ${url}`);\n this.url = url;\n this.status = status;\n this.statusText = statusText;\n this.response = response;\n }\n\n // Helper methods for common status checks\n is4xx(): boolean {\n return this.status >= 400 && this.status < 500;\n }\n\n is5xx(): boolean {\n return this.status >= 500 && this.status < 600;\n }\n\n isNotFound(): boolean {\n return this.status === 404;\n }\n\n isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n isForbidden(): boolean {\n return this.status === 403;\n }\n}\n\n// ============================================\n// OData Specific Errors\n// ============================================\n\nexport class ODataError extends FMODataError {\n readonly kind = \"ODataError\" as const;\n readonly url: string;\n readonly code?: string;\n readonly details?: any;\n\n constructor(url: string, message: string, code?: string, details?: any) {\n super(`OData error: ${message}`);\n this.url = url;\n this.code = code;\n this.details = details;\n }\n}\n\nexport class SchemaLockedError extends FMODataError {\n readonly kind = \"SchemaLockedError\" as const;\n readonly url: string;\n readonly code: string;\n readonly details?: any;\n\n constructor(url: string, message: string, details?: any) {\n super(`OData error: ${message}`);\n this.url = url;\n this.code = \"303\";\n this.details = details;\n }\n}\n\n// ============================================\n// Validation Errors\n// ============================================\n\nexport class ValidationError extends FMODataError {\n readonly kind = \"ValidationError\" as const;\n readonly field?: string;\n readonly issues: readonly StandardSchemaV1.Issue[];\n readonly value?: unknown;\n\n constructor(\n message: string,\n issues: readonly StandardSchemaV1.Issue[],\n options?: {\n field?: string;\n value?: unknown;\n cause?: Error[\"cause\"];\n },\n ) {\n super(\n message,\n options?.cause !== undefined ? { cause: options.cause } : undefined,\n );\n this.field = options?.field;\n this.issues = issues;\n this.value = options?.value;\n }\n}\n\nexport class ResponseStructureError extends FMODataError {\n readonly kind = \"ResponseStructureError\" as const;\n readonly expected: string;\n readonly received: any;\n\n constructor(expected: string, received: any) {\n super(`Invalid response structure: expected ${expected}`);\n this.expected = expected;\n this.received = received;\n }\n}\n\nexport class RecordCountMismatchError extends FMODataError {\n readonly kind = \"RecordCountMismatchError\" as const;\n readonly expected: number | \"one\" | \"at-most-one\";\n readonly received: number;\n\n constructor(expected: number | \"one\" | \"at-most-one\", received: number) {\n const expectedStr = typeof expected === \"number\" ? expected : expected;\n super(`Expected ${expectedStr} record(s), but received ${received}`);\n this.expected = expected;\n this.received = received;\n }\n}\n\nexport class InvalidLocationHeaderError extends FMODataError {\n readonly kind = \"InvalidLocationHeaderError\" as const;\n readonly locationHeader?: string;\n\n constructor(message: string, locationHeader?: string) {\n super(message);\n this.locationHeader = locationHeader;\n }\n}\n\n// ============================================\n// Type Guards\n// ============================================\n\nexport function isHTTPError(error: unknown): error is HTTPError {\n return error instanceof HTTPError;\n}\n\nexport function isValidationError(error: unknown): error is ValidationError {\n return error instanceof ValidationError;\n}\n\nexport function isODataError(error: unknown): error is ODataError {\n return error instanceof ODataError;\n}\n\nexport function isSchemaLockedError(\n error: unknown,\n): error is SchemaLockedError {\n return error instanceof SchemaLockedError;\n}\n\nexport function isResponseStructureError(\n error: unknown,\n): error is ResponseStructureError {\n return error instanceof ResponseStructureError;\n}\n\nexport function isRecordCountMismatchError(\n error: unknown,\n): error is RecordCountMismatchError {\n return error instanceof RecordCountMismatchError;\n}\n\nexport function isFMODataError(error: unknown): error is FMODataError {\n return error instanceof FMODataError;\n}\n\n// ============================================\n// Union type for all possible errors\n// ============================================\n\n// Re-export ffetch errors (they'll be imported from @fetchkit/ffetch)\nexport type {\n TimeoutError,\n AbortError,\n NetworkError,\n RetryLimitError,\n CircuitOpenError,\n} from \"@fetchkit/ffetch\";\n\nexport type FMODataErrorType =\n | import(\"@fetchkit/ffetch\").TimeoutError\n | import(\"@fetchkit/ffetch\").AbortError\n | import(\"@fetchkit/ffetch\").NetworkError\n | import(\"@fetchkit/ffetch\").RetryLimitError\n | import(\"@fetchkit/ffetch\").CircuitOpenError\n | HTTPError\n | ODataError\n | SchemaLockedError\n | ValidationError\n | ResponseStructureError\n | RecordCountMismatchError\n | InvalidLocationHeaderError;\n"],"names":[],"mappings":";;;AAKO,MAAe,qBAAqB,MAAM;AAAA,EAI/C,YAAY,SAAiB,SAAwB;AACnD,UAAM,SAAS,OAAO;AAHf;AAIF,SAAA,OAAO,KAAK,YAAY;AACxB,SAAA,gCAAgB,KAAK;AAAA,EAAA;AAE9B;AAMO,MAAM,kBAAkB,aAAa;AAAA,EAO1C,YAAY,KAAa,QAAgB,YAAoB,UAAgB;AAC3E,UAAM,QAAQ,MAAM,IAAI,UAAU,QAAQ,GAAG,EAAE;AAPxC,gCAAO;AACP;AACA;AACA;AACA;AAIP,SAAK,MAAM;AACX,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAAA;AAAA;AAAA,EAIlB,QAAiB;AACf,WAAO,KAAK,UAAU,OAAO,KAAK,SAAS;AAAA,EAAA;AAAA,EAG7C,QAAiB;AACf,WAAO,KAAK,UAAU,OAAO,KAAK,SAAS;AAAA,EAAA;AAAA,EAG7C,aAAsB;AACpB,WAAO,KAAK,WAAW;AAAA,EAAA;AAAA,EAGzB,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EAAA;AAAA,EAGzB,cAAuB;AACrB,WAAO,KAAK,WAAW;AAAA,EAAA;AAE3B;AAMO,MAAM,mBAAmB,aAAa;AAAA,EAM3C,YAAY,KAAa,SAAiB,MAAe,SAAe;AAChE,UAAA,gBAAgB,OAAO,EAAE;AANxB,gCAAO;AACP;AACA;AACA;AAIP,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EAAA;AAEnB;AAEO,MAAM,0BAA0B,aAAa;AAAA,EAMlD,YAAY,KAAa,SAAiB,SAAe;AACjD,UAAA,gBAAgB,OAAO,EAAE;AANxB,gCAAO;AACP;AACA;AACA;AAIP,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EAAA;AAEnB;AAMO,MAAM,wBAAwB,aAAa;AAAA,EAMhD,YACE,SACA,QACA,SAKA;AACA;AAAA,MACE;AAAA,OACA,mCAAS,WAAU,SAAY,EAAE,OAAO,QAAQ,UAAU;AAAA,IAC5D;AAjBO,gCAAO;AACP;AACA;AACA;AAeP,SAAK,QAAQ,mCAAS;AACtB,SAAK,SAAS;AACd,SAAK,QAAQ,mCAAS;AAAA,EAAA;AAE1B;AAEO,MAAM,+BAA+B,aAAa;AAAA,EAKvD,YAAY,UAAkB,UAAe;AACrC,UAAA,wCAAwC,QAAQ,EAAE;AALjD,gCAAO;AACP;AACA;AAIP,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAAA;AAEpB;AAEO,MAAM,iCAAiC,aAAa;AAAA,EAKzD,YAAY,UAA0C,UAAkB;AACtE,UAAM,cAAc,OAAO,aAAa,WAAW,WAAW;AAC9D,UAAM,YAAY,WAAW,4BAA4B,QAAQ,EAAE;AAN5D,gCAAO;AACP;AACA;AAKP,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAAA;AAEpB;AAEO,MAAM,mCAAmC,aAAa;AAAA,EAI3D,YAAY,SAAiB,gBAAyB;AACpD,UAAM,OAAO;AAJN,gCAAO;AACP;AAIP,SAAK,iBAAiB;AAAA,EAAA;AAE1B;AAMO,SAAS,YAAY,OAAoC;AAC9D,SAAO,iBAAiB;AAC1B;AAEO,SAAS,kBAAkB,OAA0C;AAC1E,SAAO,iBAAiB;AAC1B;AAEO,SAAS,aAAa,OAAqC;AAChE,SAAO,iBAAiB;AAC1B;AAEO,SAAS,oBACd,OAC4B;AAC5B,SAAO,iBAAiB;AAC1B;AAEO,SAAS,yBACd,OACiC;AACjC,SAAO,iBAAiB;AAC1B;AAEO,SAAS,2BACd,OACmC;AACnC,SAAO,iBAAiB;AAC1B;AAEO,SAAS,eAAe,OAAuC;AACpE,SAAO,iBAAiB;AAC1B;"}
@@ -3,8 +3,9 @@ export { TableOccurrence, createTableOccurrence, TableOccurrenceWithIds, createT
3
3
  export { FMServerConnection } from './client/filemaker-odata.js';
4
4
  export type { Database } from './client/database.js';
5
5
  export type { EntitySet } from './client/entity-set.js';
6
- export type { Result, InferSchemaType, InsertData, UpdateData, ODataRecordMetadata, } from './types.js';
6
+ export type { SchemaManager, Field, StringField, NumericField, DateField, TimeField, TimestampField, ContainerField, } from './client/schema-manager.js';
7
+ export type { Result, InferSchemaType, InsertData, UpdateData, ODataRecordMetadata, Metadata, } from './types.js';
7
8
  export type { Filter, TypedFilter, FieldFilter, StringOperators, NumberOperators, BooleanOperators, DateOperators, LogicalFilter, } from './filter-types.js';
8
9
  export { TimeoutError, AbortError, NetworkError, RetryLimitError, CircuitOpenError, } from '@fetchkit/ffetch';
9
- export { FMODataError, HTTPError, ODataError, ValidationError, ResponseStructureError, RecordCountMismatchError, isHTTPError, isValidationError, isODataError, isResponseStructureError, isRecordCountMismatchError, isFMODataError, } from './errors.js';
10
+ export { FMODataError, HTTPError, ODataError, SchemaLockedError, ValidationError, ResponseStructureError, RecordCountMismatchError, isHTTPError, isValidationError, isODataError, isSchemaLockedError, isResponseStructureError, isRecordCountMismatchError, isFMODataError, } from './errors.js';
10
11
  export type { FMODataErrorType } from './errors.js';
package/dist/esm/index.js CHANGED
@@ -2,7 +2,7 @@ import { BaseTable, BaseTableWithIds } from "./client/base-table.js";
2
2
  import { TableOccurrence, TableOccurrenceWithIds, createTableOccurrence, createTableOccurrenceWithIds } from "./client/table-occurrence.js";
3
3
  import { FMServerConnection } from "./client/filemaker-odata.js";
4
4
  import { AbortError, CircuitOpenError, NetworkError, RetryLimitError, TimeoutError } from "@fetchkit/ffetch";
5
- import { FMODataError, HTTPError, ODataError, RecordCountMismatchError, ResponseStructureError, ValidationError, isFMODataError, isHTTPError, isODataError, isRecordCountMismatchError, isResponseStructureError, isValidationError } from "./errors.js";
5
+ import { FMODataError, HTTPError, ODataError, RecordCountMismatchError, ResponseStructureError, SchemaLockedError, ValidationError, isFMODataError, isHTTPError, isODataError, isRecordCountMismatchError, isResponseStructureError, isSchemaLockedError, isValidationError } from "./errors.js";
6
6
  export {
7
7
  AbortError,
8
8
  BaseTable,
@@ -16,6 +16,7 @@ export {
16
16
  RecordCountMismatchError,
17
17
  ResponseStructureError,
18
18
  RetryLimitError,
19
+ SchemaLockedError,
19
20
  TableOccurrence,
20
21
  TableOccurrenceWithIds,
21
22
  TimeoutError,
@@ -27,6 +28,7 @@ export {
27
28
  isODataError,
28
29
  isRecordCountMismatchError,
29
30
  isResponseStructureError,
31
+ isSchemaLockedError,
30
32
  isValidationError
31
33
  };
32
34
  //# sourceMappingURL=index.js.map
@@ -27,6 +27,15 @@ export declare function transformFieldName(fieldName: string, baseTable: BaseTab
27
27
  * @returns The FMTID or table name
28
28
  */
29
29
  export declare function transformTableName(occurrence: TableOccurrence<any, any, any, any>): string;
30
+ /**
31
+ * Gets both table name and ID from an occurrence
32
+ * @param occurrence - TableOccurrence instance
33
+ * @returns Object with name (always present) and id (may be undefined if not using IDs)
34
+ */
35
+ export declare function getTableIdentifiers(occurrence: TableOccurrence<any, any, any, any>): {
36
+ name: string;
37
+ id: string | undefined;
38
+ };
30
39
  /**
31
40
  * Transforms response data by converting field IDs back to field names recursively.
32
41
  * Handles both single records and arrays of records, as well as nested expand relationships.
@@ -15,6 +15,12 @@ function transformFieldName(fieldName, baseTable) {
15
15
  function transformTableName(occurrence) {
16
16
  return occurrence.getTableId();
17
17
  }
18
+ function getTableIdentifiers(occurrence) {
19
+ return {
20
+ name: occurrence.getTableName(),
21
+ id: occurrence.isUsingTableId() ? occurrence.getTableId() : void 0
22
+ };
23
+ }
18
24
  function transformResponseFields(data, baseTable, expandConfigs) {
19
25
  if (!baseTable.isUsingFieldIds()) {
20
26
  return data;
@@ -97,6 +103,7 @@ function transformOrderByField(orderByString, baseTable) {
97
103
  return direction ? `${fieldId} ${direction}` : fieldId;
98
104
  }
99
105
  export {
106
+ getTableIdentifiers,
100
107
  transformFieldName,
101
108
  transformFieldNamesArray,
102
109
  transformFieldNamesToIds,
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","sources":["../../src/transform.ts"],"sourcesContent":["import type { BaseTable } from \"./client/base-table\";\nimport type { TableOccurrence } from \"./client/table-occurrence\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Transforms field names to FileMaker field IDs (FMFID) in an object\n * @param data - Object with field names as keys\n * @param baseTable - BaseTable instance to get field IDs from\n * @returns Object with FMFID keys instead of field names\n */\nexport function transformFieldNamesToIds<T extends Record<string, any>>(\n data: T,\n baseTable: BaseTable<any, any, any, any>,\n): Record<string, any> {\n if (!baseTable.isUsingFieldIds()) {\n return data;\n }\n\n const transformed: Record<string, any> = {};\n for (const [fieldName, value] of Object.entries(data)) {\n const fieldId = baseTable.getFieldId(fieldName as any);\n transformed[fieldId] = value;\n }\n return transformed;\n}\n\n/**\n * Transforms FileMaker field IDs (FMFID) to field names in an object\n * @param data - Object with FMFID keys\n * @param baseTable - BaseTable instance to get field names from\n * @returns Object with field names as keys instead of FMFIDs\n */\nexport function transformFieldIdsToNames<T extends Record<string, any>>(\n data: T,\n baseTable: BaseTable<any, any, any, any>,\n): Record<string, any> {\n if (!baseTable.isUsingFieldIds()) {\n return data;\n }\n\n const transformed: Record<string, any> = {};\n for (const [key, value] of Object.entries(data)) {\n // Check if this is an OData metadata field (starts with @)\n if (key.startsWith(\"@\")) {\n transformed[key] = value;\n continue;\n }\n \n const fieldName = baseTable.getFieldName(key);\n transformed[fieldName] = value;\n }\n return transformed;\n}\n\n/**\n * Transforms a field name to FMFID or returns the field name if not using IDs\n * @param fieldName - The field name to transform\n * @param baseTable - BaseTable instance to get field ID from\n * @returns The FMFID or field name\n */\nexport function transformFieldName(\n fieldName: string,\n baseTable: BaseTable<any, any, any, any>,\n): string {\n return baseTable.getFieldId(fieldName as any);\n}\n\n/**\n * Transforms a table occurrence name to FMTID or returns the name if not using IDs\n * @param occurrence - TableOccurrence instance to get table ID from\n * @returns The FMTID or table name\n */\nexport function transformTableName(\n occurrence: TableOccurrence<any, any, any, any>,\n): string {\n return occurrence.getTableId();\n}\n\n/**\n * Transforms response data by converting field IDs back to field names recursively.\n * Handles both single records and arrays of records, as well as nested expand relationships.\n * \n * @param data - Response data from FileMaker (can be single record, array, or wrapped in value property)\n * @param baseTable - BaseTable instance for the main table\n * @param expandConfigs - Configuration for expanded relations (optional)\n * @returns Transformed data with field names instead of IDs\n */\nexport function transformResponseFields(\n data: any,\n baseTable: BaseTable<any, any, any, any>,\n expandConfigs?: Array<{\n relation: string;\n occurrence?: TableOccurrence<any, any, any, any>;\n }>,\n): any {\n if (!baseTable.isUsingFieldIds()) {\n return data;\n }\n\n // Handle null/undefined\n if (data === null || data === undefined) {\n return data;\n }\n\n // Handle OData list response with value array\n if (data.value && Array.isArray(data.value)) {\n return {\n ...data,\n value: data.value.map((record: any) =>\n transformSingleRecord(record, baseTable, expandConfigs),\n ),\n };\n }\n\n // Handle array of records\n if (Array.isArray(data)) {\n return data.map((record) =>\n transformSingleRecord(record, baseTable, expandConfigs),\n );\n }\n\n // Handle single record\n return transformSingleRecord(data, baseTable, expandConfigs);\n}\n\n/**\n * Transforms a single record, converting field IDs to names and handling nested expands\n */\nfunction transformSingleRecord(\n record: any,\n baseTable: BaseTable<any, any, any, any>,\n expandConfigs?: Array<{\n relation: string;\n occurrence?: TableOccurrence<any, any, any, any>;\n }>,\n): any {\n if (!record || typeof record !== \"object\") {\n return record;\n }\n\n const transformed: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(record)) {\n // Preserve OData metadata fields\n if (key.startsWith(\"@\")) {\n transformed[key] = value;\n continue;\n }\n\n // Check if this is an expanded relation (by relation name)\n let expandConfig = expandConfigs?.find((ec) => ec.relation === key);\n \n // If not found by relation name, check if this key is a FMTID\n // (FileMaker returns expanded relations with FMTID keys when using entity IDs)\n if (!expandConfig && key.startsWith(\"FMTID:\")) {\n expandConfig = expandConfigs?.find(\n (ec) =>\n ec.occurrence &&\n ec.occurrence.isUsingTableId() &&\n ec.occurrence.getTableId() === key,\n );\n }\n \n if (expandConfig && expandConfig.occurrence) {\n // Transform the expanded relation data recursively\n // Use the relation name (not the FMTID) as the key\n const relationKey = expandConfig.relation;\n \n if (Array.isArray(value)) {\n transformed[relationKey] = value.map((nestedRecord) =>\n transformSingleRecord(\n nestedRecord,\n expandConfig.occurrence!.baseTable,\n undefined, // Don't pass nested expand configs for now\n ),\n );\n } else if (value && typeof value === \"object\") {\n transformed[relationKey] = transformSingleRecord(\n value,\n expandConfig.occurrence.baseTable,\n undefined,\n );\n } else {\n transformed[relationKey] = value;\n }\n continue;\n }\n\n // Transform field ID to field name\n const fieldName = baseTable.getFieldName(key);\n transformed[fieldName] = value;\n }\n\n return transformed;\n}\n\n/**\n * Transforms an array of field names to FMFIDs\n * @param fieldNames - Array of field names\n * @param baseTable - BaseTable instance to get field IDs from\n * @returns Array of FMFIDs or field names\n */\nexport function transformFieldNamesArray(\n fieldNames: string[],\n baseTable: BaseTable<any, any, any, any>,\n): string[] {\n if (!baseTable.isUsingFieldIds()) {\n return fieldNames;\n }\n\n return fieldNames.map((fieldName) => baseTable.getFieldId(fieldName as any));\n}\n\n/**\n * Transforms a field name in an orderBy string (e.g., \"name desc\" -> \"FMFID:1 desc\")\n * @param orderByString - The orderBy string (field name with optional asc/desc)\n * @param baseTable - BaseTable instance to get field ID from\n * @returns Transformed orderBy string with FMFID\n */\nexport function transformOrderByField(\n orderByString: string,\n baseTable: BaseTable<any, any, any, any>,\n): string {\n if (!baseTable.isUsingFieldIds()) {\n return orderByString;\n }\n\n // Parse the orderBy string to extract field name and direction\n const parts = orderByString.trim().split(/\\s+/);\n const fieldName = parts[0];\n const direction = parts[1]; // \"asc\" or \"desc\" or undefined\n\n const fieldId = baseTable.getFieldId(fieldName as any);\n return direction ? `${fieldId} ${direction}` : fieldId;\n}\n\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transform.js","sources":["../../src/transform.ts"],"sourcesContent":["import type { BaseTable } from \"./client/base-table\";\nimport type { TableOccurrence } from \"./client/table-occurrence\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Transforms field names to FileMaker field IDs (FMFID) in an object\n * @param data - Object with field names as keys\n * @param baseTable - BaseTable instance to get field IDs from\n * @returns Object with FMFID keys instead of field names\n */\nexport function transformFieldNamesToIds<T extends Record<string, any>>(\n data: T,\n baseTable: BaseTable<any, any, any, any>,\n): Record<string, any> {\n if (!baseTable.isUsingFieldIds()) {\n return data;\n }\n\n const transformed: Record<string, any> = {};\n for (const [fieldName, value] of Object.entries(data)) {\n const fieldId = baseTable.getFieldId(fieldName as any);\n transformed[fieldId] = value;\n }\n return transformed;\n}\n\n/**\n * Transforms FileMaker field IDs (FMFID) to field names in an object\n * @param data - Object with FMFID keys\n * @param baseTable - BaseTable instance to get field names from\n * @returns Object with field names as keys instead of FMFIDs\n */\nexport function transformFieldIdsToNames<T extends Record<string, any>>(\n data: T,\n baseTable: BaseTable<any, any, any, any>,\n): Record<string, any> {\n if (!baseTable.isUsingFieldIds()) {\n return data;\n }\n\n const transformed: Record<string, any> = {};\n for (const [key, value] of Object.entries(data)) {\n // Check if this is an OData metadata field (starts with @)\n if (key.startsWith(\"@\")) {\n transformed[key] = value;\n continue;\n }\n\n const fieldName = baseTable.getFieldName(key);\n transformed[fieldName] = value;\n }\n return transformed;\n}\n\n/**\n * Transforms a field name to FMFID or returns the field name if not using IDs\n * @param fieldName - The field name to transform\n * @param baseTable - BaseTable instance to get field ID from\n * @returns The FMFID or field name\n */\nexport function transformFieldName(\n fieldName: string,\n baseTable: BaseTable<any, any, any, any>,\n): string {\n return baseTable.getFieldId(fieldName as any);\n}\n\n/**\n * Transforms a table occurrence name to FMTID or returns the name if not using IDs\n * @param occurrence - TableOccurrence instance to get table ID from\n * @returns The FMTID or table name\n */\nexport function transformTableName(\n occurrence: TableOccurrence<any, any, any, any>,\n): string {\n return occurrence.getTableId();\n}\n\n/**\n * Gets both table name and ID from an occurrence\n * @param occurrence - TableOccurrence instance\n * @returns Object with name (always present) and id (may be undefined if not using IDs)\n */\nexport function getTableIdentifiers(\n occurrence: TableOccurrence<any, any, any, any>,\n): { name: string; id: string | undefined } {\n return {\n name: occurrence.getTableName(),\n id: occurrence.isUsingTableId() ? occurrence.getTableId() : undefined,\n };\n}\n\n/**\n * Transforms response data by converting field IDs back to field names recursively.\n * Handles both single records and arrays of records, as well as nested expand relationships.\n *\n * @param data - Response data from FileMaker (can be single record, array, or wrapped in value property)\n * @param baseTable - BaseTable instance for the main table\n * @param expandConfigs - Configuration for expanded relations (optional)\n * @returns Transformed data with field names instead of IDs\n */\nexport function transformResponseFields(\n data: any,\n baseTable: BaseTable<any, any, any, any>,\n expandConfigs?: Array<{\n relation: string;\n occurrence?: TableOccurrence<any, any, any, any>;\n }>,\n): any {\n if (!baseTable.isUsingFieldIds()) {\n return data;\n }\n\n // Handle null/undefined\n if (data === null || data === undefined) {\n return data;\n }\n\n // Handle OData list response with value array\n if (data.value && Array.isArray(data.value)) {\n return {\n ...data,\n value: data.value.map((record: any) =>\n transformSingleRecord(record, baseTable, expandConfigs),\n ),\n };\n }\n\n // Handle array of records\n if (Array.isArray(data)) {\n return data.map((record) =>\n transformSingleRecord(record, baseTable, expandConfigs),\n );\n }\n\n // Handle single record\n return transformSingleRecord(data, baseTable, expandConfigs);\n}\n\n/**\n * Transforms a single record, converting field IDs to names and handling nested expands\n */\nfunction transformSingleRecord(\n record: any,\n baseTable: BaseTable<any, any, any, any>,\n expandConfigs?: Array<{\n relation: string;\n occurrence?: TableOccurrence<any, any, any, any>;\n }>,\n): any {\n if (!record || typeof record !== \"object\") {\n return record;\n }\n\n const transformed: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(record)) {\n // Preserve OData metadata fields\n if (key.startsWith(\"@\")) {\n transformed[key] = value;\n continue;\n }\n\n // Check if this is an expanded relation (by relation name)\n let expandConfig = expandConfigs?.find((ec) => ec.relation === key);\n\n // If not found by relation name, check if this key is a FMTID\n // (FileMaker returns expanded relations with FMTID keys when using entity IDs)\n if (!expandConfig && key.startsWith(\"FMTID:\")) {\n expandConfig = expandConfigs?.find(\n (ec) =>\n ec.occurrence &&\n ec.occurrence.isUsingTableId() &&\n ec.occurrence.getTableId() === key,\n );\n }\n\n if (expandConfig && expandConfig.occurrence) {\n // Transform the expanded relation data recursively\n // Use the relation name (not the FMTID) as the key\n const relationKey = expandConfig.relation;\n\n if (Array.isArray(value)) {\n transformed[relationKey] = value.map((nestedRecord) =>\n transformSingleRecord(\n nestedRecord,\n expandConfig.occurrence!.baseTable,\n undefined, // Don't pass nested expand configs for now\n ),\n );\n } else if (value && typeof value === \"object\") {\n transformed[relationKey] = transformSingleRecord(\n value,\n expandConfig.occurrence.baseTable,\n undefined,\n );\n } else {\n transformed[relationKey] = value;\n }\n continue;\n }\n\n // Transform field ID to field name\n const fieldName = baseTable.getFieldName(key);\n transformed[fieldName] = value;\n }\n\n return transformed;\n}\n\n/**\n * Transforms an array of field names to FMFIDs\n * @param fieldNames - Array of field names\n * @param baseTable - BaseTable instance to get field IDs from\n * @returns Array of FMFIDs or field names\n */\nexport function transformFieldNamesArray(\n fieldNames: string[],\n baseTable: BaseTable<any, any, any, any>,\n): string[] {\n if (!baseTable.isUsingFieldIds()) {\n return fieldNames;\n }\n\n return fieldNames.map((fieldName) => baseTable.getFieldId(fieldName as any));\n}\n\n/**\n * Transforms a field name in an orderBy string (e.g., \"name desc\" -> \"FMFID:1 desc\")\n * @param orderByString - The orderBy string (field name with optional asc/desc)\n * @param baseTable - BaseTable instance to get field ID from\n * @returns Transformed orderBy string with FMFID\n */\nexport function transformOrderByField(\n orderByString: string,\n baseTable: BaseTable<any, any, any, any>,\n): string {\n if (!baseTable.isUsingFieldIds()) {\n return orderByString;\n }\n\n // Parse the orderBy string to extract field name and direction\n const parts = orderByString.trim().split(/\\s+/);\n const fieldName = parts[0];\n const direction = parts[1]; // \"asc\" or \"desc\" or undefined\n\n const fieldId = baseTable.getFieldId(fieldName as any);\n return direction ? `${fieldId} ${direction}` : fieldId;\n}\n"],"names":[],"mappings":"AAUgB,SAAA,yBACd,MACA,WACqB;AACjB,MAAA,CAAC,UAAU,mBAAmB;AACzB,WAAA;AAAA,EAAA;AAGT,QAAM,cAAmC,CAAC;AAC1C,aAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAA,UAAU,UAAU,WAAW,SAAgB;AACrD,gBAAY,OAAO,IAAI;AAAA,EAAA;AAElB,SAAA;AACT;AAoCgB,SAAA,mBACd,WACA,WACQ;AACD,SAAA,UAAU,WAAW,SAAgB;AAC9C;AAOO,SAAS,mBACd,YACQ;AACR,SAAO,WAAW,WAAW;AAC/B;AAOO,SAAS,oBACd,YAC0C;AACnC,SAAA;AAAA,IACL,MAAM,WAAW,aAAa;AAAA,IAC9B,IAAI,WAAW,eAAmB,IAAA,WAAW,eAAe;AAAA,EAC9D;AACF;AAWgB,SAAA,wBACd,MACA,WACA,eAIK;AACD,MAAA,CAAC,UAAU,mBAAmB;AACzB,WAAA;AAAA,EAAA;AAIL,MAAA,SAAS,QAAQ,SAAS,QAAW;AAChC,WAAA;AAAA,EAAA;AAIT,MAAI,KAAK,SAAS,MAAM,QAAQ,KAAK,KAAK,GAAG;AACpC,WAAA;AAAA,MACL,GAAG;AAAA,MACH,OAAO,KAAK,MAAM;AAAA,QAAI,CAAC,WACrB,sBAAsB,QAAQ,WAAW,aAAa;AAAA,MAAA;AAAA,IAE1D;AAAA,EAAA;AAIE,MAAA,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK;AAAA,MAAI,CAAC,WACf,sBAAsB,QAAQ,WAAW,aAAa;AAAA,IACxD;AAAA,EAAA;AAIK,SAAA,sBAAsB,MAAM,WAAW,aAAa;AAC7D;AAKA,SAAS,sBACP,QACA,WACA,eAIK;AACL,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AAClC,WAAA;AAAA,EAAA;AAGT,QAAM,cAAmC,CAAC;AAE1C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAE7C,QAAA,IAAI,WAAW,GAAG,GAAG;AACvB,kBAAY,GAAG,IAAI;AACnB;AAAA,IAAA;AAIF,QAAI,eAAe,+CAAe,KAAK,CAAC,OAAO,GAAG,aAAa;AAI/D,QAAI,CAAC,gBAAgB,IAAI,WAAW,QAAQ,GAAG;AAC7C,qBAAe,+CAAe;AAAA,QAC5B,CAAC,OACC,GAAG,cACH,GAAG,WAAW,eAAA,KACd,GAAG,WAAW,iBAAiB;AAAA;AAAA,IACnC;AAGE,QAAA,gBAAgB,aAAa,YAAY;AAG3C,YAAM,cAAc,aAAa;AAE7B,UAAA,MAAM,QAAQ,KAAK,GAAG;AACZ,oBAAA,WAAW,IAAI,MAAM;AAAA,UAAI,CAAC,iBACpC;AAAA,YACE;AAAA,YACA,aAAa,WAAY;AAAA,YACzB;AAAA;AAAA,UAAA;AAAA,QAEJ;AAAA,MACS,WAAA,SAAS,OAAO,UAAU,UAAU;AAC7C,oBAAY,WAAW,IAAI;AAAA,UACzB;AAAA,UACA,aAAa,WAAW;AAAA,UACxB;AAAA,QACF;AAAA,MAAA,OACK;AACL,oBAAY,WAAW,IAAI;AAAA,MAAA;AAE7B;AAAA,IAAA;AAII,UAAA,YAAY,UAAU,aAAa,GAAG;AAC5C,gBAAY,SAAS,IAAI;AAAA,EAAA;AAGpB,SAAA;AACT;AAQgB,SAAA,yBACd,YACA,WACU;AACN,MAAA,CAAC,UAAU,mBAAmB;AACzB,WAAA;AAAA,EAAA;AAGT,SAAO,WAAW,IAAI,CAAC,cAAc,UAAU,WAAW,SAAgB,CAAC;AAC7E;AAQgB,SAAA,sBACd,eACA,WACQ;AACJ,MAAA,CAAC,UAAU,mBAAmB;AACzB,WAAA;AAAA,EAAA;AAIT,QAAM,QAAQ,cAAc,KAAK,EAAE,MAAM,KAAK;AACxC,QAAA,YAAY,MAAM,CAAC;AACnB,QAAA,YAAY,MAAM,CAAC;AAEnB,QAAA,UAAU,UAAU,WAAW,SAAgB;AACrD,SAAO,YAAY,GAAG,OAAO,IAAI,SAAS,KAAK;AACjD;"}
@@ -13,11 +13,28 @@ export interface ExecutableBuilder<T> {
13
13
  url: string;
14
14
  body?: any;
15
15
  };
16
+ /**
17
+ * Convert this builder to a native Request object for batch processing.
18
+ * @param baseUrl - The base URL for the OData service
19
+ * @returns A native Request object
20
+ */
21
+ toRequest(baseUrl: string): Request;
22
+ /**
23
+ * Process a raw Response object into a typed Result.
24
+ * This allows builders to apply their own validation and transformation logic.
25
+ * @param response - The native Response object from the batch operation
26
+ * @param options - Optional execution options (e.g., skipValidation, includeODataAnnotations)
27
+ * @returns A typed Result with the builder's expected return type
28
+ */
29
+ processResponse(response: Response, options?: ExecuteOptions): Promise<Result<T>>;
16
30
  }
17
31
  export interface ExecutionContext {
18
- _makeRequest<T>(url: string, options?: RequestInit & FFetchOptions): Promise<Result<T>>;
32
+ _makeRequest<T>(url: string, options?: RequestInit & FFetchOptions & {
33
+ useEntityIds?: boolean;
34
+ }): Promise<Result<T>>;
19
35
  _setUseEntityIds?(useEntityIds: boolean): void;
20
36
  _getUseEntityIds?(): boolean;
37
+ _getBaseUrl?(): string;
21
38
  }
22
39
  export type InferSchemaType<Schema extends Record<string, StandardSchemaV1>> = {
23
40
  [K in keyof Schema]: Schema[K] extends StandardSchemaV1<any, infer Output> ? Output : never;
@@ -70,6 +87,10 @@ export type UpdateData<BT> = BT extends import('./client/base-table.js').BaseTab
70
87
  export type ExecuteOptions = {
71
88
  includeODataAnnotations?: boolean;
72
89
  skipValidation?: boolean;
90
+ /**
91
+ * Overrides the default behavior of the database to use entity IDs (rather than field names) in THIS REQUEST ONLY
92
+ */
93
+ useEntityIds?: boolean;
73
94
  };
74
95
  export type ConditionallyWithODataAnnotations<T, IncludeODataAnnotations extends boolean> = IncludeODataAnnotations extends true ? T & {
75
96
  "@id": string;
@@ -80,4 +101,51 @@ export type ExtractSchemaFromOccurrence<Occ> = Occ extends {
80
101
  schema: infer S;
81
102
  };
82
103
  } ? S extends Record<string, StandardSchemaV1> ? S : Record<string, StandardSchemaV1> : Record<string, StandardSchemaV1>;
104
+ export type GenericFieldMetadata = {
105
+ $Nullable?: boolean;
106
+ "@Index"?: boolean;
107
+ "@Calculation"?: boolean;
108
+ "@Summary"?: boolean;
109
+ "@Global"?: boolean;
110
+ "@Org.OData.Core.V1.Permissions"?: "Org.OData.Core.V1.Permission@Read";
111
+ };
112
+ export type StringFieldMetadata = GenericFieldMetadata & {
113
+ $Type: "Edm.String";
114
+ $DefaultValue?: "USER" | "USERNAME" | "CURRENT_USER";
115
+ $MaxLength?: number;
116
+ };
117
+ export type DecimalFieldMetadata = GenericFieldMetadata & {
118
+ $Type: "Edm.Decimal";
119
+ "@AutoGenerated"?: boolean;
120
+ };
121
+ export type DateFieldMetadata = GenericFieldMetadata & {
122
+ $Type: "Edm.Date";
123
+ $DefaultValue?: "CURDATE" | "CURRENT_DATE";
124
+ };
125
+ export type TimeOfDayFieldMetadata = GenericFieldMetadata & {
126
+ $Type: "Edm.TimeOfDay";
127
+ $DefaultValue?: "CURTIME" | "CURRENT_TIME";
128
+ };
129
+ export type DateTimeOffsetFieldMetadata = GenericFieldMetadata & {
130
+ $Type: "Edm.Date";
131
+ $DefaultValue?: "CURTIMESTAMP" | "CURRENT_TIMESTAMP";
132
+ "@VersionId"?: boolean;
133
+ };
134
+ export type StreamFieldMetadata = {
135
+ $Type: "Edm.Stream";
136
+ $Nullable?: boolean;
137
+ "@EnclosedPath": string;
138
+ "@ExternalOpenPath": string;
139
+ "@ExternalSecurePath"?: string;
140
+ };
141
+ export type FieldMetadata = StringFieldMetadata | DecimalFieldMetadata | DateFieldMetadata | TimeOfDayFieldMetadata | DateTimeOffsetFieldMetadata | StreamFieldMetadata;
142
+ export type EntityType = {
143
+ $Kind: "EntityType";
144
+ $Key: string[];
145
+ } & Record<string, FieldMetadata>;
146
+ export type EntitySet = {
147
+ $Kind: "EntitySet";
148
+ $Type: string;
149
+ };
150
+ export type Metadata = Record<string, EntityType | EntitySet>;
83
151
  export {};