@proofkit/fmodata 0.1.0-alpha.12 → 0.1.0-alpha.13
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.
- package/LICENSE.md +21 -0
- package/dist/esm/client/query-builder.js +7 -4
- package/dist/esm/client/query-builder.js.map +1 -1
- package/dist/esm/client/record-builder.js +3 -2
- package/dist/esm/client/record-builder.js.map +1 -1
- package/package.json +17 -17
- package/src/client/query-builder.ts +16 -9
- package/src/client/record-builder.ts +4 -2
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Proof+Geist
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -115,7 +115,8 @@ class QueryBuilder {
|
|
|
115
115
|
const result = {};
|
|
116
116
|
const andConditions = [];
|
|
117
117
|
for (const [field, value] of Object.entries(filter)) {
|
|
118
|
-
const
|
|
118
|
+
const shouldTransform = ((_a = this.occurrence) == null ? void 0 : _a.baseTable) && this.databaseUseEntityIds;
|
|
119
|
+
const fieldId = shouldTransform ? transformFieldName(field, this.occurrence.baseTable) : field;
|
|
119
120
|
if (Array.isArray(value)) {
|
|
120
121
|
if (value.length === 1) {
|
|
121
122
|
result[fieldId] = value[0];
|
|
@@ -192,10 +193,11 @@ class QueryBuilder {
|
|
|
192
193
|
* - Wraps "id" fields in double quotes
|
|
193
194
|
* - URL-encodes special characters but preserves spaces
|
|
194
195
|
*/
|
|
195
|
-
formatSelectFields(select, baseTable) {
|
|
196
|
+
formatSelectFields(select, baseTable, useEntityIds) {
|
|
196
197
|
if (!select) return "";
|
|
197
198
|
const selectFieldsArray = Array.isArray(select) ? select : [select];
|
|
198
|
-
const
|
|
199
|
+
const shouldTransform = baseTable && (useEntityIds ?? this.databaseUseEntityIds);
|
|
200
|
+
const transformedFields = shouldTransform ? transformFieldNamesArray(
|
|
199
201
|
selectFieldsArray.map((f) => String(f)),
|
|
200
202
|
baseTable
|
|
201
203
|
) : selectFieldsArray.map((f) => String(f));
|
|
@@ -240,7 +242,8 @@ class QueryBuilder {
|
|
|
240
242
|
return configs.map((config) => {
|
|
241
243
|
var _a;
|
|
242
244
|
const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[config.relation];
|
|
243
|
-
const
|
|
245
|
+
const shouldUseTableId = this.databaseUseEntityIds && (targetOccurrence == null ? void 0 : targetOccurrence.isUsingTableId());
|
|
246
|
+
const relationName = shouldUseTableId ? targetOccurrence.getTableId() : config.relation;
|
|
244
247
|
if (!config.options || Object.keys(config.options).length === 0) {
|
|
245
248
|
return relationName;
|
|
246
249
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-builder.js","sources":["../../../src/client/query-builder.ts"],"sourcesContent":["import { QueryOptions } from \"odata-query\";\nimport buildQuery from \"odata-query\";\nimport type {\n ExecutionContext,\n ExecutableBuilder,\n WithSystemFields,\n Result,\n InferSchemaType,\n ExecuteOptions,\n ConditionallyWithODataAnnotations,\n ExtractSchemaFromOccurrence,\n} from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport type { Filter } from \"../filter-types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { validateListResponse, validateSingleResponse } from \"../validation\";\nimport { RecordCountMismatchError } from \"../errors\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport {\n transformFieldNamesArray,\n transformFieldName,\n transformOrderByField,\n transformResponseFields,\n getTableIdentifiers,\n} from \"../transform\";\nimport { safeJsonParse } from \"./sanitize-json\";\n\n/**\n * Default maximum number of records to return in a list query.\n * This prevents stack overflow issues with large datasets while still\n * allowing substantial data retrieval. Users can override with .top().\n */\nconst DEFAULT_TOP = 1000;\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 & string\n : never\n : never;\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 ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? Nav[Name]\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >;\n\n// Helper type to get the inferred schema type from a target occurrence\ntype GetTargetSchemaType<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Rel extends string,\n> = [FindNavigationTarget<O, Rel>] extends [\n TableOccurrence<infer BT, any, any, any>,\n]\n ? [BT] extends [BaseTable<infer S, any, any, any>]\n ? [S] extends [Record<string, StandardSchemaV1>]\n ? InferSchemaType<S>\n : Record<string, any>\n : Record<string, any>\n : Record<string, any>;\n\n// Internal type for expand configuration\ntype ExpandConfig = {\n relation: string;\n options?: Partial<QueryOptions<any>>;\n};\n\n// Type to represent expanded relations\nexport type ExpandedRelations = Record<string, { schema: any; selected: any }>;\n\nexport type QueryReturnType<\n T extends Record<string, any>,\n Selected extends keyof T,\n SingleMode extends \"exact\" | \"maybe\" | false,\n IsCount extends boolean,\n Expands extends ExpandedRelations,\n> = IsCount extends true\n ? number\n : SingleMode extends \"exact\"\n ? Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n }\n : SingleMode extends \"maybe\"\n ?\n | (Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n })\n | null\n : (Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n })[];\n\nexport class QueryBuilder<\n T extends Record<string, any>,\n Selected extends keyof T = keyof T,\n SingleMode extends \"exact\" | \"maybe\" | false = false,\n IsCount extends boolean = false,\n Occ extends TableOccurrence<any, any, any, any> | undefined = undefined,\n Expands extends ExpandedRelations = {},\n> implements\n ExecutableBuilder<\n QueryReturnType<T, Selected, SingleMode, IsCount, Expands>\n >\n{\n private queryOptions: Partial<QueryOptions<T>> = {};\n private expandConfigs: ExpandConfig[] = [];\n private singleMode: SingleMode = false as SingleMode;\n private isCountMode = false as IsCount;\n private occurrence?: Occ;\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private isNavigate?: boolean;\n private navigateRecordId?: string | number;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n private navigateBaseRelation?: string;\n private navigateBasePath?: string; // Full base path for chained entity set navigations\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\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.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:\n options?.useEntityIds === undefined\n ? this.databaseUseEntityIds\n : options.useEntityIds,\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 select<K extends keyof T>(\n ...fields: K[]\n ): QueryBuilder<T, K, SingleMode, IsCount, Occ, Expands> {\n const uniqueFields = [...new Set(fields)];\n const newBuilder = new QueryBuilder<\n T,\n K,\n SingleMode,\n IsCount,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = {\n ...this.queryOptions,\n select: uniqueFields as string[],\n };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = this.singleMode;\n newBuilder.isCountMode = this.isCountMode;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n /**\n * Transforms our filter format to odata-query's expected format\n * - Arrays of operators are converted to AND conditions\n * - Single operator objects pass through as-is\n * - Shorthand values are handled by odata-query\n */\n private transformFilter(\n filter: Filter<ExtractSchemaFromOccurrence<Occ>>,\n ): QueryOptions<T>[\"filter\"] {\n if (typeof filter === \"string\") {\n // Raw string filters pass through\n return filter;\n }\n\n if (Array.isArray(filter)) {\n // Array of filters - odata-query handles this as implicit AND\n return filter.map((f) => this.transformFilter(f as any)) as any;\n }\n\n // Check if it's a logical filter (and/or/not)\n if (\"and\" in filter || \"or\" in filter || \"not\" in filter) {\n const result: any = {};\n if (\"and\" in filter && Array.isArray(filter.and)) {\n result.and = filter.and.map((f: any) => this.transformFilter(f));\n }\n if (\"or\" in filter && Array.isArray(filter.or)) {\n result.or = filter.or.map((f: any) => this.transformFilter(f));\n }\n if (\"not\" in filter && filter.not) {\n result.not = this.transformFilter(filter.not as any);\n }\n return result;\n }\n\n // Transform field filters\n const result: any = {};\n const andConditions: any[] = [];\n\n for (const [field, value] of Object.entries(filter)) {\n // Transform field name to FMFID if using entity IDs\n const fieldId = this.occurrence?.baseTable\n ? transformFieldName(field, this.occurrence.baseTable)\n : field;\n\n if (Array.isArray(value)) {\n // Array of operators - convert to AND conditions\n if (value.length === 1) {\n // Single operator in array - unwrap it\n result[fieldId] = value[0];\n } else {\n // Multiple operators - combine with AND\n // Create separate conditions for each operator\n for (const op of value) {\n andConditions.push({ [fieldId]: op });\n }\n }\n } else if (\n value &&\n typeof value === \"object\" &&\n !(value instanceof Date) &&\n !Array.isArray(value)\n ) {\n // Check if it's an operator object (has operator keys like eq, gt, etc.)\n const operatorKeys = [\n \"eq\",\n \"ne\",\n \"gt\",\n \"ge\",\n \"lt\",\n \"le\",\n \"contains\",\n \"startswith\",\n \"endswith\",\n \"in\",\n ];\n const isOperatorObject = operatorKeys.some((key) => key in value);\n\n if (isOperatorObject) {\n // Single operator object - pass through\n result[fieldId] = value;\n } else {\n // Regular object - might be nested filter, pass through\n result[fieldId] = value;\n }\n } else {\n // Primitive value (shorthand) - pass through\n result[fieldId] = value;\n }\n }\n\n // If we have AND conditions from arrays, combine them\n if (andConditions.length > 0) {\n if (Object.keys(result).length > 0) {\n // We have both regular fields and array-derived AND conditions\n // Combine everything with AND\n return { and: [...andConditions, result] };\n } else {\n // Only array-derived AND conditions\n return { and: andConditions };\n }\n }\n\n return result;\n }\n\n filter(\n filter: Filter<ExtractSchemaFromOccurrence<Occ>>,\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n // Transform our filter format to odata-query's expected format\n this.queryOptions.filter = this.transformFilter(filter) as any;\n return this;\n }\n\n orderBy(\n orderBy: QueryOptions<T>[\"orderBy\"],\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n // Transform field names to FMFIDs if using entity IDs\n if (this.occurrence?.baseTable && orderBy) {\n if (Array.isArray(orderBy)) {\n this.queryOptions.orderBy = orderBy.map((field) =>\n transformOrderByField(String(field), this.occurrence!.baseTable),\n );\n } else {\n this.queryOptions.orderBy = transformOrderByField(\n String(orderBy),\n this.occurrence.baseTable,\n );\n }\n } else {\n this.queryOptions.orderBy = orderBy;\n }\n return this;\n }\n\n top(\n count: number,\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n this.queryOptions.top = count;\n return this;\n }\n\n skip(\n count: number,\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n this.queryOptions.skip = count;\n return this;\n }\n\n /**\n * Formats select fields for use in query strings.\n * - Transforms field names to FMFIDs if using entity IDs\n * - Wraps \"id\" fields in double quotes\n * - URL-encodes special characters but preserves spaces\n */\n private formatSelectFields(\n select: QueryOptions<any>[\"select\"],\n baseTable?: BaseTable<any, any, any, any>,\n ): string {\n if (!select) return \"\";\n const selectFieldsArray = Array.isArray(select) ? select : [select];\n\n // Transform to field IDs if using entity IDs\n const transformedFields = baseTable\n ? transformFieldNamesArray(\n selectFieldsArray.map((f) => String(f)),\n baseTable,\n )\n : selectFieldsArray.map((f) => String(f));\n\n return transformedFields\n .map((field) => {\n if (field === \"id\") return `\"id\"`;\n const encodedField = encodeURIComponent(String(field));\n return encodedField.replace(/%20/g, \" \");\n })\n .join(\",\");\n }\n\n /**\n * Builds expand validation configs from internal expand configurations.\n * These are used to validate expanded navigation properties.\n */\n private buildExpandValidationConfigs(\n configs: ExpandConfig[],\n ): import(\"../validation\").ExpandValidationConfig[] {\n return configs.map((config) => {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n const targetSchema = targetOccurrence?.baseTable?.schema;\n\n // Extract selected fields from options\n const selectedFields = config.options?.select\n ? Array.isArray(config.options.select)\n ? config.options.select.map((f) => String(f))\n : [String(config.options.select)]\n : undefined;\n\n return {\n relation: config.relation,\n targetSchema: targetSchema,\n targetOccurrence: targetOccurrence,\n targetBaseTable: targetOccurrence?.baseTable,\n occurrence: targetOccurrence, // Add occurrence for transformation\n selectedFields: selectedFields,\n nestedExpands: undefined, // TODO: Handle nested expands if needed\n };\n });\n }\n\n /**\n * Builds OData expand query string from expand configurations.\n * Handles nested expands recursively.\n * Transforms relation names to FMTIDs if using entity IDs.\n */\n private buildExpandString(configs: ExpandConfig[]): string {\n if (configs.length === 0) {\n return \"\";\n }\n\n return configs\n .map((config) => {\n // Get target occurrence for this relation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n\n // When using entity IDs, use the target table's FMTID in the expand parameter\n // FileMaker expects FMTID in $expand when Prefer header is set\n const relationName =\n targetOccurrence && targetOccurrence.isUsingTableId()\n ? targetOccurrence.getTableId()\n : config.relation;\n\n if (!config.options || Object.keys(config.options).length === 0) {\n // Simple expand without options\n return relationName;\n }\n\n // Build query options for this expand\n const parts: string[] = [];\n\n if (config.options.select) {\n // Pass target base table for field transformation\n const selectFields = this.formatSelectFields(\n config.options.select,\n targetOccurrence?.baseTable,\n );\n parts.push(`$select=${selectFields}`);\n }\n\n if (config.options.filter) {\n // Filter should already be transformed by the nested builder\n // Use odata-query to build filter string\n const filterQuery = buildQuery({ filter: config.options.filter });\n const filterMatch = filterQuery.match(/\\$filter=([^&]+)/);\n if (filterMatch) {\n parts.push(`$filter=${filterMatch[1]}`);\n }\n }\n\n if (config.options.orderBy) {\n // OrderBy should already be transformed by the nested builder\n const orderByValue = Array.isArray(config.options.orderBy)\n ? config.options.orderBy.join(\",\")\n : config.options.orderBy;\n parts.push(`$orderby=${String(orderByValue)}`);\n }\n\n if (config.options.top !== undefined) {\n parts.push(`$top=${config.options.top}`);\n }\n\n if (config.options.skip !== undefined) {\n parts.push(`$skip=${config.options.skip}`);\n }\n\n // Handle nested expands (from expand configs)\n if (config.options.expand) {\n // If expand is a string, it's already been built\n if (typeof config.options.expand === \"string\") {\n parts.push(`$expand=${config.options.expand}`);\n }\n }\n\n if (parts.length === 0) {\n return relationName;\n }\n\n return `${relationName}(${parts.join(\";\")})`;\n })\n .join(\",\");\n }\n\n expand<\n Rel extends ExtractNavigationNames<Occ> | (string & {}),\n TargetOcc extends FindNavigationTarget<Occ, Rel> = FindNavigationTarget<\n Occ,\n Rel\n >,\n TargetSchema extends GetTargetSchemaType<Occ, Rel> = GetTargetSchemaType<\n Occ,\n Rel\n >,\n TargetSelected extends keyof TargetSchema = keyof TargetSchema,\n >(\n relation: Rel,\n callback?: (\n builder: QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >,\n ) => QueryBuilder<\n WithSystemFields<TargetSchema>,\n TargetSelected,\n any,\n any,\n any\n >,\n ): QueryBuilder<\n T,\n Selected,\n SingleMode,\n IsCount,\n Occ,\n Expands & {\n [K in Rel]: { schema: TargetSchema; selected: TargetSelected };\n }\n > {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[relation as string];\n\n // Helper function to get defaultSelect fields from target occurrence\n const getDefaultSelectFields = (): string[] | undefined => {\n if (!targetOccurrence) return undefined;\n const defaultSelect = targetOccurrence.defaultSelect;\n if (defaultSelect === \"schema\") {\n const schema = targetOccurrence.baseTable?.schema;\n if (schema) {\n return [...new Set(Object.keys(schema))];\n }\n } else if (Array.isArray(defaultSelect)) {\n return [...new Set(defaultSelect)];\n }\n // If \"all\", return undefined (no select restriction)\n return undefined;\n };\n\n if (callback) {\n // Create a new QueryBuilder for the target occurrence\n const targetBuilder = new QueryBuilder<any>({\n occurrence: targetOccurrence,\n tableName: targetOccurrence?.name ?? (relation as string),\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Cast to the expected type for the callback\n // At runtime, the builder is untyped (any), but at compile-time we enforce proper types\n const typedBuilder = targetBuilder as QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >;\n\n // Pass to callback and get configured builder\n const configuredBuilder = callback(typedBuilder);\n\n // Extract the builder's query options\n const expandOptions: Partial<QueryOptions<any>> = {\n ...configuredBuilder.queryOptions,\n };\n\n // If callback didn't provide select, apply defaultSelect from target occurrence\n if (!expandOptions.select) {\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n expandOptions.select = defaultFields;\n }\n }\n\n // If the configured builder has nested expands, we need to include them\n if (configuredBuilder.expandConfigs.length > 0) {\n // Build nested expand string from the configured builder's expand configs\n const nestedExpandString = this.buildExpandString(\n configuredBuilder.expandConfigs,\n );\n if (nestedExpandString) {\n // Add nested expand to options\n expandOptions.expand = nestedExpandString as any;\n }\n }\n\n const expandConfig: ExpandConfig = {\n relation: relation as string,\n options: expandOptions,\n };\n\n this.expandConfigs.push(expandConfig);\n } else {\n // Simple expand without callback - apply defaultSelect if available\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n this.expandConfigs.push({\n relation: relation as string,\n options: { select: defaultFields },\n });\n } else {\n this.expandConfigs.push({ relation: relation as string });\n }\n }\n\n return this as any;\n }\n\n single(): QueryBuilder<T, Selected, \"exact\", IsCount, Occ, Expands> {\n const newBuilder = new QueryBuilder<\n T,\n Selected,\n \"exact\",\n IsCount,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = { ...this.queryOptions };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = \"exact\";\n newBuilder.isCountMode = this.isCountMode;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n maybeSingle(): QueryBuilder<T, Selected, \"maybe\", IsCount, Occ, Expands> {\n const newBuilder = new QueryBuilder<\n T,\n Selected,\n \"maybe\",\n IsCount,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = { ...this.queryOptions };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = \"maybe\";\n newBuilder.isCountMode = this.isCountMode;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n count(): QueryBuilder<T, Selected, SingleMode, true, Occ, Expands> {\n const newBuilder = new QueryBuilder<\n T,\n Selected,\n SingleMode,\n true,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = { ...this.queryOptions, count: true };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = this.singleMode;\n newBuilder.isCountMode = true as true;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n async execute<EO extends ExecuteOptions>(\n options?: RequestInit & FFetchOptions & EO,\n ): Promise<\n Result<\n IsCount extends true\n ? number\n : SingleMode extends \"exact\"\n ? ConditionallyWithODataAnnotations<\n Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n },\n EO[\"includeODataAnnotations\"] extends true ? true : false\n >\n : SingleMode extends \"maybe\"\n ? ConditionallyWithODataAnnotations<\n Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n },\n EO[\"includeODataAnnotations\"] extends true ? true : false\n > | null\n : ConditionallyWithODataAnnotations<\n Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n },\n EO[\"includeODataAnnotations\"] extends true ? true : false\n >[]\n >\n > {\n // Build query without expand (we'll add it manually)\n const queryOptionsWithoutExpand = { ...this.queryOptions };\n delete queryOptionsWithoutExpand.expand;\n\n const mergedOptions = this.mergeExecuteOptions(options);\n\n // Format select fields before building query\n if (queryOptionsWithoutExpand.select) {\n queryOptionsWithoutExpand.select = this.formatSelectFields(\n queryOptionsWithoutExpand.select,\n this.occurrence?.baseTable,\n ) as any;\n }\n\n let queryString = buildQuery(queryOptionsWithoutExpand);\n\n // Build custom expand string\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n const separator = queryString.includes(\"?\") ? \"&\" : \"?\";\n queryString = `${queryString}${separator}$expand=${expandString}`;\n }\n\n // Handle navigation from RecordBuilder\n if (\n this.isNavigate &&\n this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n let url: string;\n if (this.navigateBaseRelation) {\n // Navigation from a navigated EntitySet: /sourceTable/baseRelation('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;\n } else {\n // Normal navigation: /sourceTable('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${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 let response = result.data;\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 const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = response as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n const records = resp.value ?? [];\n const stripped = records.map((record: any) => record);\n return { data: stripped as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as\n | (keyof T)[]\n | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n const validation = await validateSingleResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n } else {\n const validation = await validateListResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n }\n }\n\n // Handle navigation from EntitySet (without record ID)\n if (\n this.isNavigate &&\n !this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`,\n mergedOptions,\n );\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n let response = result.data;\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 const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = response as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n const records = resp.value ?? [];\n const stripped = records.map((record: any) => record);\n return { data: stripped as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as\n | (keyof T)[]\n | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n const validation = await validateSingleResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n } else {\n const validation = await validateListResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n }\n }\n\n // Handle $count endpoint\n if (this.isCountMode) {\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${tableId}/$count${queryString}`,\n mergedOptions,\n );\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n // OData returns count as a string, convert to number\n const count =\n typeof result.data === \"string\" ? Number(result.data) : result.data;\n return { data: count as number, error: undefined } as any;\n }\n\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${tableId}${queryString}`,\n mergedOptions,\n );\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n let response = result.data;\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 const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = response as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n // Handle list response structure\n const records = resp.value ?? [];\n return { data: records as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as (keyof T)[] | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n const validation = await validateSingleResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return {\n data: validation.data as any,\n error: undefined,\n };\n } else {\n const validation = await validateListResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return {\n data: validation.data as any,\n error: undefined,\n };\n }\n }\n\n getQueryString(): string {\n // Build query without expand (we'll add it manually)\n const queryOptionsWithoutExpand = { ...this.queryOptions };\n delete queryOptionsWithoutExpand.expand;\n\n // Format select fields before building query - buildQuery treats & as separator,\n // so we need to pre-encode special characters. buildQuery preserves encoded values.\n if (queryOptionsWithoutExpand.select) {\n queryOptionsWithoutExpand.select = this.formatSelectFields(\n queryOptionsWithoutExpand.select,\n this.occurrence?.baseTable,\n ) as any;\n }\n\n let queryParams = buildQuery(queryOptionsWithoutExpand);\n\n // Post-process: buildQuery encodes spaces as %20, but we want to preserve spaces\n // Replace %20 with spaces in the $select part\n if (this.queryOptions.select) {\n queryParams = queryParams.replace(\n /\\$select=([^&]*)/,\n (match, selectValue) => {\n return `$select=${selectValue.replace(/%20/g, \" \")}`;\n },\n );\n }\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n const separator = queryParams.includes(\"?\") ? \"&\" : \"?\";\n queryParams = `${queryParams}${separator}$expand=${expandString}`;\n }\n\n // Handle navigation from RecordBuilder (with record ID)\n if (\n this.isNavigate &&\n this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n let path: string;\n if (this.navigateBaseRelation) {\n // Navigation from a navigated EntitySet: /sourceTable/baseRelation('recordId')/relation\n path = `/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}`;\n } else {\n // Normal navigation: /sourceTableName('recordId')/relationName\n path = `/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}`;\n }\n // Append query params if any exist\n return queryParams ? `${path}${queryParams}` : path;\n }\n\n // Handle navigation from EntitySet (without record ID)\n if (\n this.isNavigate &&\n !this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n let path: string;\n if (this.navigateBasePath) {\n // Chained navigation: /basePath/relationName (basePath already includes intermediate segments)\n path = `/${this.navigateBasePath}/${this.navigateRelation}`;\n } else {\n // Single navigation: /sourceTableName/relationName\n path = `/${this.navigateSourceTableName}/${this.navigateRelation}`;\n }\n // Append query params if any exist\n return queryParams ? `${path}${queryParams}` : path;\n }\n\n // Default case: return table ID (respects entity ID settings) with query params\n const tableId = this.getTableId(this.databaseUseEntityIds);\n return `/${tableId}${queryParams}`;\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n // Build query without expand (we'll add it manually)\n const queryOptionsWithoutExpand = { ...this.queryOptions };\n delete queryOptionsWithoutExpand.expand;\n\n // Format select fields before building query\n if (queryOptionsWithoutExpand.select) {\n queryOptionsWithoutExpand.select = this.formatSelectFields(\n queryOptionsWithoutExpand.select,\n this.occurrence?.baseTable,\n ) as any;\n }\n\n let queryString = buildQuery(queryOptionsWithoutExpand);\n\n // Build custom expand string\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n const separator = queryString.includes(\"?\") ? \"&\" : \"?\";\n queryString = `${queryString}${separator}$expand=${expandString}`;\n }\n\n let url: string;\n\n // Handle navigation from RecordBuilder (with record ID)\n if (\n this.isNavigate &&\n this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n if (this.navigateBaseRelation) {\n // Navigation from a navigated EntitySet: /sourceTable/baseRelation('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;\n } else {\n // Normal navigation: /sourceTable('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;\n }\n } else if (\n this.isNavigate &&\n !this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n // Handle navigation from EntitySet (without record ID)\n if (this.navigateBasePath) {\n // Chained navigation: /basePath/relationName (basePath already includes intermediate segments)\n url = `/${this.databaseName}/${this.navigateBasePath}/${this.navigateRelation}${queryString}`;\n } else {\n // Single navigation: /sourceTableName/relationName\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`;\n }\n } else if (this.isCountMode) {\n // Use getTableId to respect entity ID settings (for batch operations)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}/$count${queryString}`;\n } else {\n // Use getTableId to respect entity ID settings (for batch operations)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}${queryString}`;\n }\n\n return {\n method: \"GET\",\n url,\n };\n }\n\n toRequest(baseUrl: string, options?: ExecuteOptions): 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: getAcceptHeader(options?.includeODataAnnotations),\n },\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<QueryReturnType<T, Selected, SingleMode, IsCount, Expands>>\n > {\n // Handle 204 No Content (shouldn't happen for queries, but handle it gracefully)\n if (response.status === 204) {\n // Return empty list for list queries, null for single queries\n if (this.singleMode !== false) {\n if (this.singleMode === \"maybe\") {\n return { data: null as any, error: undefined };\n }\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: [] as any, error: undefined };\n }\n\n // Parse the response body (using safeJsonParse to handle FileMaker's invalid JSON with unquoted ? values)\n let rawData;\n try {\n rawData = await safeJsonParse(response);\n } catch (err) {\n // Check if it's an empty body error (common with 204 responses)\n if (err instanceof SyntaxError && response.status === 204) {\n // Handled above, but just in case\n return { data: [] as any, error: undefined };\n }\n return {\n data: undefined,\n error: {\n name: \"ResponseParseError\",\n message: `Failed to parse response JSON: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n timestamp: new Date(),\n } as any,\n };\n }\n\n if (!rawData) {\n return {\n data: undefined,\n error: {\n name: \"ResponseError\",\n message: \"Response body was empty or null\",\n timestamp: new Date(),\n } as any,\n };\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 transformedData = rawData;\n if (this.occurrence?.baseTable && shouldUseIds) {\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n transformedData = transformResponseFields(\n rawData,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = transformedData as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n // Handle list response structure\n const records = resp.value ?? [];\n return { data: records as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as (keyof T)[] | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n // Single mode (one() or oneOrNull())\n const validation = await validateSingleResponse<T>(\n transformedData,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n if (validation.data === null) {\n return { data: null as any, error: undefined };\n }\n\n return { data: validation.data as any, error: undefined };\n }\n\n // List mode\n const validation = await validateListResponse<T>(\n transformedData,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n return { data: validation.data as any, error: undefined };\n }\n}\n"],"names":["result","_a","response","shouldUseIds","expandValidationConfigs","schema","selectedFields","tableId","validation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"query-builder.js","sources":["../../../src/client/query-builder.ts"],"sourcesContent":["import { QueryOptions } from \"odata-query\";\nimport buildQuery from \"odata-query\";\nimport type {\n ExecutionContext,\n ExecutableBuilder,\n WithSystemFields,\n Result,\n InferSchemaType,\n ExecuteOptions,\n ConditionallyWithODataAnnotations,\n ExtractSchemaFromOccurrence,\n} from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport type { Filter } from \"../filter-types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { validateListResponse, validateSingleResponse } from \"../validation\";\nimport { RecordCountMismatchError } from \"../errors\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport {\n transformFieldNamesArray,\n transformFieldName,\n transformOrderByField,\n transformResponseFields,\n getTableIdentifiers,\n} from \"../transform\";\nimport { safeJsonParse } from \"./sanitize-json\";\n\n/**\n * Default maximum number of records to return in a list query.\n * This prevents stack overflow issues with large datasets while still\n * allowing substantial data retrieval. Users can override with .top().\n */\nconst DEFAULT_TOP = 1000;\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 & string\n : never\n : never;\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 ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? Nav[Name]\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >;\n\n// Helper type to get the inferred schema type from a target occurrence\ntype GetTargetSchemaType<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Rel extends string,\n> = [FindNavigationTarget<O, Rel>] extends [\n TableOccurrence<infer BT, any, any, any>,\n]\n ? [BT] extends [BaseTable<infer S, any, any, any>]\n ? [S] extends [Record<string, StandardSchemaV1>]\n ? InferSchemaType<S>\n : Record<string, any>\n : Record<string, any>\n : Record<string, any>;\n\n// Internal type for expand configuration\ntype ExpandConfig = {\n relation: string;\n options?: Partial<QueryOptions<any>>;\n};\n\n// Type to represent expanded relations\nexport type ExpandedRelations = Record<string, { schema: any; selected: any }>;\n\nexport type QueryReturnType<\n T extends Record<string, any>,\n Selected extends keyof T,\n SingleMode extends \"exact\" | \"maybe\" | false,\n IsCount extends boolean,\n Expands extends ExpandedRelations,\n> = IsCount extends true\n ? number\n : SingleMode extends \"exact\"\n ? Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n }\n : SingleMode extends \"maybe\"\n ?\n | (Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n })\n | null\n : (Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n })[];\n\nexport class QueryBuilder<\n T extends Record<string, any>,\n Selected extends keyof T = keyof T,\n SingleMode extends \"exact\" | \"maybe\" | false = false,\n IsCount extends boolean = false,\n Occ extends TableOccurrence<any, any, any, any> | undefined = undefined,\n Expands extends ExpandedRelations = {},\n> implements\n ExecutableBuilder<\n QueryReturnType<T, Selected, SingleMode, IsCount, Expands>\n >\n{\n private queryOptions: Partial<QueryOptions<T>> = {};\n private expandConfigs: ExpandConfig[] = [];\n private singleMode: SingleMode = false as SingleMode;\n private isCountMode = false as IsCount;\n private occurrence?: Occ;\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private isNavigate?: boolean;\n private navigateRecordId?: string | number;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n private navigateBaseRelation?: string;\n private navigateBasePath?: string; // Full base path for chained entity set navigations\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\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.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:\n options?.useEntityIds === undefined\n ? this.databaseUseEntityIds\n : options.useEntityIds,\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 select<K extends keyof T>(\n ...fields: K[]\n ): QueryBuilder<T, K, SingleMode, IsCount, Occ, Expands> {\n const uniqueFields = [...new Set(fields)];\n const newBuilder = new QueryBuilder<\n T,\n K,\n SingleMode,\n IsCount,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = {\n ...this.queryOptions,\n select: uniqueFields as string[],\n };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = this.singleMode;\n newBuilder.isCountMode = this.isCountMode;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n /**\n * Transforms our filter format to odata-query's expected format\n * - Arrays of operators are converted to AND conditions\n * - Single operator objects pass through as-is\n * - Shorthand values are handled by odata-query\n */\n private transformFilter(\n filter: Filter<ExtractSchemaFromOccurrence<Occ>>,\n ): QueryOptions<T>[\"filter\"] {\n if (typeof filter === \"string\") {\n // Raw string filters pass through\n return filter;\n }\n\n if (Array.isArray(filter)) {\n // Array of filters - odata-query handles this as implicit AND\n return filter.map((f) => this.transformFilter(f as any)) as any;\n }\n\n // Check if it's a logical filter (and/or/not)\n if (\"and\" in filter || \"or\" in filter || \"not\" in filter) {\n const result: any = {};\n if (\"and\" in filter && Array.isArray(filter.and)) {\n result.and = filter.and.map((f: any) => this.transformFilter(f));\n }\n if (\"or\" in filter && Array.isArray(filter.or)) {\n result.or = filter.or.map((f: any) => this.transformFilter(f));\n }\n if (\"not\" in filter && filter.not) {\n result.not = this.transformFilter(filter.not as any);\n }\n return result;\n }\n\n // Transform field filters\n const result: any = {};\n const andConditions: any[] = [];\n\n for (const [field, value] of Object.entries(filter)) {\n // Transform field name to FMFID if using entity IDs AND the feature is enabled\n const shouldTransform =\n this.occurrence?.baseTable && this.databaseUseEntityIds;\n const fieldId = shouldTransform\n ? transformFieldName(field, this.occurrence!.baseTable)\n : field;\n\n if (Array.isArray(value)) {\n // Array of operators - convert to AND conditions\n if (value.length === 1) {\n // Single operator in array - unwrap it\n result[fieldId] = value[0];\n } else {\n // Multiple operators - combine with AND\n // Create separate conditions for each operator\n for (const op of value) {\n andConditions.push({ [fieldId]: op });\n }\n }\n } else if (\n value &&\n typeof value === \"object\" &&\n !(value instanceof Date) &&\n !Array.isArray(value)\n ) {\n // Check if it's an operator object (has operator keys like eq, gt, etc.)\n const operatorKeys = [\n \"eq\",\n \"ne\",\n \"gt\",\n \"ge\",\n \"lt\",\n \"le\",\n \"contains\",\n \"startswith\",\n \"endswith\",\n \"in\",\n ];\n const isOperatorObject = operatorKeys.some((key) => key in value);\n\n if (isOperatorObject) {\n // Single operator object - pass through\n result[fieldId] = value;\n } else {\n // Regular object - might be nested filter, pass through\n result[fieldId] = value;\n }\n } else {\n // Primitive value (shorthand) - pass through\n result[fieldId] = value;\n }\n }\n\n // If we have AND conditions from arrays, combine them\n if (andConditions.length > 0) {\n if (Object.keys(result).length > 0) {\n // We have both regular fields and array-derived AND conditions\n // Combine everything with AND\n return { and: [...andConditions, result] };\n } else {\n // Only array-derived AND conditions\n return { and: andConditions };\n }\n }\n\n return result;\n }\n\n filter(\n filter: Filter<ExtractSchemaFromOccurrence<Occ>>,\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n // Transform our filter format to odata-query's expected format\n this.queryOptions.filter = this.transformFilter(filter) as any;\n return this;\n }\n\n orderBy(\n orderBy: QueryOptions<T>[\"orderBy\"],\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n // Transform field names to FMFIDs if using entity IDs\n if (this.occurrence?.baseTable && orderBy) {\n if (Array.isArray(orderBy)) {\n this.queryOptions.orderBy = orderBy.map((field) =>\n transformOrderByField(String(field), this.occurrence!.baseTable),\n );\n } else {\n this.queryOptions.orderBy = transformOrderByField(\n String(orderBy),\n this.occurrence.baseTable,\n );\n }\n } else {\n this.queryOptions.orderBy = orderBy;\n }\n return this;\n }\n\n top(\n count: number,\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n this.queryOptions.top = count;\n return this;\n }\n\n skip(\n count: number,\n ): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands> {\n this.queryOptions.skip = count;\n return this;\n }\n\n /**\n * Formats select fields for use in query strings.\n * - Transforms field names to FMFIDs if using entity IDs\n * - Wraps \"id\" fields in double quotes\n * - URL-encodes special characters but preserves spaces\n */\n private formatSelectFields(\n select: QueryOptions<any>[\"select\"],\n baseTable?: BaseTable<any, any, any, any>,\n useEntityIds?: boolean,\n ): string {\n if (!select) return \"\";\n const selectFieldsArray = Array.isArray(select) ? select : [select];\n\n // Transform to field IDs if using entity IDs AND the feature is enabled\n const shouldTransform =\n baseTable && (useEntityIds ?? this.databaseUseEntityIds);\n const transformedFields = shouldTransform\n ? transformFieldNamesArray(\n selectFieldsArray.map((f) => String(f)),\n baseTable,\n )\n : selectFieldsArray.map((f) => String(f));\n\n return transformedFields\n .map((field) => {\n if (field === \"id\") return `\"id\"`;\n const encodedField = encodeURIComponent(String(field));\n return encodedField.replace(/%20/g, \" \");\n })\n .join(\",\");\n }\n\n /**\n * Builds expand validation configs from internal expand configurations.\n * These are used to validate expanded navigation properties.\n */\n private buildExpandValidationConfigs(\n configs: ExpandConfig[],\n ): import(\"../validation\").ExpandValidationConfig[] {\n return configs.map((config) => {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n const targetSchema = targetOccurrence?.baseTable?.schema;\n\n // Extract selected fields from options\n const selectedFields = config.options?.select\n ? Array.isArray(config.options.select)\n ? config.options.select.map((f) => String(f))\n : [String(config.options.select)]\n : undefined;\n\n return {\n relation: config.relation,\n targetSchema: targetSchema,\n targetOccurrence: targetOccurrence,\n targetBaseTable: targetOccurrence?.baseTable,\n occurrence: targetOccurrence, // Add occurrence for transformation\n selectedFields: selectedFields,\n nestedExpands: undefined, // TODO: Handle nested expands if needed\n };\n });\n }\n\n /**\n * Builds OData expand query string from expand configurations.\n * Handles nested expands recursively.\n * Transforms relation names to FMTIDs if using entity IDs.\n */\n private buildExpandString(configs: ExpandConfig[]): string {\n if (configs.length === 0) {\n return \"\";\n }\n\n return configs\n .map((config) => {\n // Get target occurrence for this relation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n\n // When using entity IDs, use the target table's FMTID in the expand parameter\n // FileMaker expects FMTID in $expand when Prefer header is set\n // Only use FMTID if databaseUseEntityIds is enabled\n const shouldUseTableId =\n this.databaseUseEntityIds && targetOccurrence?.isUsingTableId();\n const relationName = shouldUseTableId\n ? targetOccurrence!.getTableId()\n : config.relation;\n\n if (!config.options || Object.keys(config.options).length === 0) {\n // Simple expand without options\n return relationName;\n }\n\n // Build query options for this expand\n const parts: string[] = [];\n\n if (config.options.select) {\n // Pass target base table for field transformation\n const selectFields = this.formatSelectFields(\n config.options.select,\n targetOccurrence?.baseTable,\n );\n parts.push(`$select=${selectFields}`);\n }\n\n if (config.options.filter) {\n // Filter should already be transformed by the nested builder\n // Use odata-query to build filter string\n const filterQuery = buildQuery({ filter: config.options.filter });\n const filterMatch = filterQuery.match(/\\$filter=([^&]+)/);\n if (filterMatch) {\n parts.push(`$filter=${filterMatch[1]}`);\n }\n }\n\n if (config.options.orderBy) {\n // OrderBy should already be transformed by the nested builder\n const orderByValue = Array.isArray(config.options.orderBy)\n ? config.options.orderBy.join(\",\")\n : config.options.orderBy;\n parts.push(`$orderby=${String(orderByValue)}`);\n }\n\n if (config.options.top !== undefined) {\n parts.push(`$top=${config.options.top}`);\n }\n\n if (config.options.skip !== undefined) {\n parts.push(`$skip=${config.options.skip}`);\n }\n\n // Handle nested expands (from expand configs)\n if (config.options.expand) {\n // If expand is a string, it's already been built\n if (typeof config.options.expand === \"string\") {\n parts.push(`$expand=${config.options.expand}`);\n }\n }\n\n if (parts.length === 0) {\n return relationName;\n }\n\n return `${relationName}(${parts.join(\";\")})`;\n })\n .join(\",\");\n }\n\n expand<\n Rel extends ExtractNavigationNames<Occ> | (string & {}),\n TargetOcc extends FindNavigationTarget<Occ, Rel> = FindNavigationTarget<\n Occ,\n Rel\n >,\n TargetSchema extends GetTargetSchemaType<Occ, Rel> = GetTargetSchemaType<\n Occ,\n Rel\n >,\n TargetSelected extends keyof TargetSchema = keyof TargetSchema,\n >(\n relation: Rel,\n callback?: (\n builder: QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >,\n ) => QueryBuilder<\n WithSystemFields<TargetSchema>,\n TargetSelected,\n any,\n any,\n any\n >,\n ): QueryBuilder<\n T,\n Selected,\n SingleMode,\n IsCount,\n Occ,\n Expands & {\n [K in Rel]: { schema: TargetSchema; selected: TargetSelected };\n }\n > {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[relation as string];\n\n // Helper function to get defaultSelect fields from target occurrence\n const getDefaultSelectFields = (): string[] | undefined => {\n if (!targetOccurrence) return undefined;\n const defaultSelect = targetOccurrence.defaultSelect;\n if (defaultSelect === \"schema\") {\n const schema = targetOccurrence.baseTable?.schema;\n if (schema) {\n return [...new Set(Object.keys(schema))];\n }\n } else if (Array.isArray(defaultSelect)) {\n return [...new Set(defaultSelect)];\n }\n // If \"all\", return undefined (no select restriction)\n return undefined;\n };\n\n if (callback) {\n // Create a new QueryBuilder for the target occurrence\n const targetBuilder = new QueryBuilder<any>({\n occurrence: targetOccurrence,\n tableName: targetOccurrence?.name ?? (relation as string),\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Cast to the expected type for the callback\n // At runtime, the builder is untyped (any), but at compile-time we enforce proper types\n const typedBuilder = targetBuilder as QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >;\n\n // Pass to callback and get configured builder\n const configuredBuilder = callback(typedBuilder);\n\n // Extract the builder's query options\n const expandOptions: Partial<QueryOptions<any>> = {\n ...configuredBuilder.queryOptions,\n };\n\n // If callback didn't provide select, apply defaultSelect from target occurrence\n if (!expandOptions.select) {\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n expandOptions.select = defaultFields;\n }\n }\n\n // If the configured builder has nested expands, we need to include them\n if (configuredBuilder.expandConfigs.length > 0) {\n // Build nested expand string from the configured builder's expand configs\n const nestedExpandString = this.buildExpandString(\n configuredBuilder.expandConfigs,\n );\n if (nestedExpandString) {\n // Add nested expand to options\n expandOptions.expand = nestedExpandString as any;\n }\n }\n\n const expandConfig: ExpandConfig = {\n relation: relation as string,\n options: expandOptions,\n };\n\n this.expandConfigs.push(expandConfig);\n } else {\n // Simple expand without callback - apply defaultSelect if available\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n this.expandConfigs.push({\n relation: relation as string,\n options: { select: defaultFields },\n });\n } else {\n this.expandConfigs.push({ relation: relation as string });\n }\n }\n\n return this as any;\n }\n\n single(): QueryBuilder<T, Selected, \"exact\", IsCount, Occ, Expands> {\n const newBuilder = new QueryBuilder<\n T,\n Selected,\n \"exact\",\n IsCount,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = { ...this.queryOptions };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = \"exact\";\n newBuilder.isCountMode = this.isCountMode;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n maybeSingle(): QueryBuilder<T, Selected, \"maybe\", IsCount, Occ, Expands> {\n const newBuilder = new QueryBuilder<\n T,\n Selected,\n \"maybe\",\n IsCount,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = { ...this.queryOptions };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = \"maybe\";\n newBuilder.isCountMode = this.isCountMode;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n count(): QueryBuilder<T, Selected, SingleMode, true, Occ, Expands> {\n const newBuilder = new QueryBuilder<\n T,\n Selected,\n SingleMode,\n true,\n Occ,\n Expands\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.queryOptions = { ...this.queryOptions, count: true };\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.singleMode = this.singleMode;\n newBuilder.isCountMode = true as true;\n // Preserve navigation metadata\n newBuilder.isNavigate = this.isNavigate;\n newBuilder.navigateRecordId = this.navigateRecordId;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n newBuilder.navigateBaseRelation = this.navigateBaseRelation;\n return newBuilder;\n }\n\n async execute<EO extends ExecuteOptions>(\n options?: RequestInit & FFetchOptions & EO,\n ): Promise<\n Result<\n IsCount extends true\n ? number\n : SingleMode extends \"exact\"\n ? ConditionallyWithODataAnnotations<\n Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n },\n EO[\"includeODataAnnotations\"] extends true ? true : false\n >\n : SingleMode extends \"maybe\"\n ? ConditionallyWithODataAnnotations<\n Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n },\n EO[\"includeODataAnnotations\"] extends true ? true : false\n > | null\n : ConditionallyWithODataAnnotations<\n Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n },\n EO[\"includeODataAnnotations\"] extends true ? true : false\n >[]\n >\n > {\n // Build query without expand (we'll add it manually)\n const queryOptionsWithoutExpand = { ...this.queryOptions };\n delete queryOptionsWithoutExpand.expand;\n\n const mergedOptions = this.mergeExecuteOptions(options);\n\n // Format select fields before building query\n if (queryOptionsWithoutExpand.select) {\n queryOptionsWithoutExpand.select = this.formatSelectFields(\n queryOptionsWithoutExpand.select,\n this.occurrence?.baseTable,\n ) as any;\n }\n\n let queryString = buildQuery(queryOptionsWithoutExpand);\n\n // Build custom expand string\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n const separator = queryString.includes(\"?\") ? \"&\" : \"?\";\n queryString = `${queryString}${separator}$expand=${expandString}`;\n }\n\n // Handle navigation from RecordBuilder\n if (\n this.isNavigate &&\n this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n let url: string;\n if (this.navigateBaseRelation) {\n // Navigation from a navigated EntitySet: /sourceTable/baseRelation('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;\n } else {\n // Normal navigation: /sourceTable('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${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 let response = result.data;\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 const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = response as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n const records = resp.value ?? [];\n const stripped = records.map((record: any) => record);\n return { data: stripped as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as\n | (keyof T)[]\n | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n const validation = await validateSingleResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n } else {\n const validation = await validateListResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n }\n }\n\n // Handle navigation from EntitySet (without record ID)\n if (\n this.isNavigate &&\n !this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`,\n mergedOptions,\n );\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n let response = result.data;\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 const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = response as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n const records = resp.value ?? [];\n const stripped = records.map((record: any) => record);\n return { data: stripped as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as\n | (keyof T)[]\n | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n const validation = await validateSingleResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n } else {\n const validation = await validateListResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return { data: validation.data as any, error: undefined };\n }\n }\n\n // Handle $count endpoint\n if (this.isCountMode) {\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${tableId}/$count${queryString}`,\n mergedOptions,\n );\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n // OData returns count as a string, convert to number\n const count =\n typeof result.data === \"string\" ? Number(result.data) : result.data;\n return { data: count as number, error: undefined } as any;\n }\n\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${tableId}${queryString}`,\n mergedOptions,\n );\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n let response = result.data;\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 const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = response as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n // Handle list response structure\n const records = resp.value ?? [];\n return { data: records as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as (keyof T)[] | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n const validation = await validateSingleResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return {\n data: validation.data as any,\n error: undefined,\n };\n } else {\n const validation = await validateListResponse<T>(\n response,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n return {\n data: validation.data as any,\n error: undefined,\n };\n }\n }\n\n getQueryString(): string {\n // Build query without expand (we'll add it manually)\n const queryOptionsWithoutExpand = { ...this.queryOptions };\n delete queryOptionsWithoutExpand.expand;\n\n // Format select fields before building query - buildQuery treats & as separator,\n // so we need to pre-encode special characters. buildQuery preserves encoded values.\n if (queryOptionsWithoutExpand.select) {\n queryOptionsWithoutExpand.select = this.formatSelectFields(\n queryOptionsWithoutExpand.select,\n this.occurrence?.baseTable,\n ) as any;\n }\n\n let queryParams = buildQuery(queryOptionsWithoutExpand);\n\n // Post-process: buildQuery encodes spaces as %20, but we want to preserve spaces\n // Replace %20 with spaces in the $select part\n if (this.queryOptions.select) {\n queryParams = queryParams.replace(\n /\\$select=([^&]*)/,\n (match, selectValue) => {\n return `$select=${selectValue.replace(/%20/g, \" \")}`;\n },\n );\n }\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n const separator = queryParams.includes(\"?\") ? \"&\" : \"?\";\n queryParams = `${queryParams}${separator}$expand=${expandString}`;\n }\n\n // Handle navigation from RecordBuilder (with record ID)\n if (\n this.isNavigate &&\n this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n let path: string;\n if (this.navigateBaseRelation) {\n // Navigation from a navigated EntitySet: /sourceTable/baseRelation('recordId')/relation\n path = `/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}`;\n } else {\n // Normal navigation: /sourceTableName('recordId')/relationName\n path = `/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}`;\n }\n // Append query params if any exist\n return queryParams ? `${path}${queryParams}` : path;\n }\n\n // Handle navigation from EntitySet (without record ID)\n if (\n this.isNavigate &&\n !this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n let path: string;\n if (this.navigateBasePath) {\n // Chained navigation: /basePath/relationName (basePath already includes intermediate segments)\n path = `/${this.navigateBasePath}/${this.navigateRelation}`;\n } else {\n // Single navigation: /sourceTableName/relationName\n path = `/${this.navigateSourceTableName}/${this.navigateRelation}`;\n }\n // Append query params if any exist\n return queryParams ? `${path}${queryParams}` : path;\n }\n\n // Default case: return table ID (respects entity ID settings) with query params\n const tableId = this.getTableId(this.databaseUseEntityIds);\n return `/${tableId}${queryParams}`;\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n // Build query without expand (we'll add it manually)\n const queryOptionsWithoutExpand = { ...this.queryOptions };\n delete queryOptionsWithoutExpand.expand;\n\n // Format select fields before building query\n if (queryOptionsWithoutExpand.select) {\n queryOptionsWithoutExpand.select = this.formatSelectFields(\n queryOptionsWithoutExpand.select,\n this.occurrence?.baseTable,\n ) as any;\n }\n\n let queryString = buildQuery(queryOptionsWithoutExpand);\n\n // Build custom expand string\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n const separator = queryString.includes(\"?\") ? \"&\" : \"?\";\n queryString = `${queryString}${separator}$expand=${expandString}`;\n }\n\n let url: string;\n\n // Handle navigation from RecordBuilder (with record ID)\n if (\n this.isNavigate &&\n this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n if (this.navigateBaseRelation) {\n // Navigation from a navigated EntitySet: /sourceTable/baseRelation('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateBaseRelation}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;\n } else {\n // Normal navigation: /sourceTable('recordId')/relation\n url = `/${this.databaseName}/${this.navigateSourceTableName}('${this.navigateRecordId}')/${this.navigateRelation}${queryString}`;\n }\n } else if (\n this.isNavigate &&\n !this.navigateRecordId &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n // Handle navigation from EntitySet (without record ID)\n if (this.navigateBasePath) {\n // Chained navigation: /basePath/relationName (basePath already includes intermediate segments)\n url = `/${this.databaseName}/${this.navigateBasePath}/${this.navigateRelation}${queryString}`;\n } else {\n // Single navigation: /sourceTableName/relationName\n url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`;\n }\n } else if (this.isCountMode) {\n // Use getTableId to respect entity ID settings (for batch operations)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}/$count${queryString}`;\n } else {\n // Use getTableId to respect entity ID settings (for batch operations)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n url = `/${this.databaseName}/${tableId}${queryString}`;\n }\n\n return {\n method: \"GET\",\n url,\n };\n }\n\n toRequest(baseUrl: string, options?: ExecuteOptions): 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: getAcceptHeader(options?.includeODataAnnotations),\n },\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<QueryReturnType<T, Selected, SingleMode, IsCount, Expands>>\n > {\n // Handle 204 No Content (shouldn't happen for queries, but handle it gracefully)\n if (response.status === 204) {\n // Return empty list for list queries, null for single queries\n if (this.singleMode !== false) {\n if (this.singleMode === \"maybe\") {\n return { data: null as any, error: undefined };\n }\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: [] as any, error: undefined };\n }\n\n // Parse the response body (using safeJsonParse to handle FileMaker's invalid JSON with unquoted ? values)\n let rawData;\n try {\n rawData = await safeJsonParse(response);\n } catch (err) {\n // Check if it's an empty body error (common with 204 responses)\n if (err instanceof SyntaxError && response.status === 204) {\n // Handled above, but just in case\n return { data: [] as any, error: undefined };\n }\n return {\n data: undefined,\n error: {\n name: \"ResponseParseError\",\n message: `Failed to parse response JSON: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n timestamp: new Date(),\n } as any,\n };\n }\n\n if (!rawData) {\n return {\n data: undefined,\n error: {\n name: \"ResponseError\",\n message: \"Response body was empty or null\",\n timestamp: new Date(),\n } as any,\n };\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 transformedData = rawData;\n if (this.occurrence?.baseTable && shouldUseIds) {\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n transformedData = transformResponseFields(\n rawData,\n this.occurrence.baseTable,\n expandValidationConfigs,\n );\n }\n\n // Skip validation if requested\n if (options?.skipValidation === true) {\n const resp = transformedData as any;\n if (this.singleMode !== false) {\n const records = resp.value ?? [resp];\n const count = Array.isArray(records) ? records.length : 1;\n\n if (count > 1) {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\n this.singleMode === \"exact\" ? \"one\" : \"at-most-one\",\n count,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new RecordCountMismatchError(\"one\", 0),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n return { data: record as any, error: undefined };\n } else {\n // Handle list response structure\n const records = resp.value ?? [];\n return { data: records as any, error: undefined };\n }\n }\n\n // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n const selectedFields = this.queryOptions.select as (keyof T)[] | undefined;\n const expandValidationConfigs = this.buildExpandValidationConfigs(\n this.expandConfigs,\n );\n\n if (this.singleMode !== false) {\n // Single mode (one() or oneOrNull())\n const validation = await validateSingleResponse<T>(\n transformedData,\n schema,\n selectedFields,\n expandValidationConfigs,\n this.singleMode,\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n if (validation.data === null) {\n return { data: null as any, error: undefined };\n }\n\n return { data: validation.data as any, error: undefined };\n }\n\n // List mode\n const validation = await validateListResponse<T>(\n transformedData,\n schema,\n selectedFields,\n expandValidationConfigs,\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n return { data: validation.data as any, error: undefined };\n }\n}\n"],"names":["result","_a","response","shouldUseIds","expandValidationConfigs","schema","selectedFields","tableId","validation"],"mappings":"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"}
|
|
@@ -223,9 +223,10 @@ class RecordBuilder {
|
|
|
223
223
|
* - Wraps "id" fields in double quotes
|
|
224
224
|
* - URL-encodes special characters but preserves spaces
|
|
225
225
|
*/
|
|
226
|
-
formatSelectFields(select, baseTable) {
|
|
226
|
+
formatSelectFields(select, baseTable, useEntityIds) {
|
|
227
227
|
if (!select || select.length === 0) return "";
|
|
228
|
-
const
|
|
228
|
+
const shouldTransform = baseTable && (useEntityIds ?? this.databaseUseEntityIds);
|
|
229
|
+
const transformedFields = shouldTransform ? transformFieldNamesArray(select, baseTable) : select;
|
|
229
230
|
return transformedFields.map((field) => {
|
|
230
231
|
if (field === "id") return `"id"`;
|
|
231
232
|
const encodedField = encodeURIComponent(String(field));
|
|
@@ -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 WithSystemFields,\n ConditionallyWithODataAnnotations,\n} from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport {\n transformTableName,\n transformResponseFields,\n getTableIdentifiers,\n transformFieldNamesArray,\n} from \"../transform\";\nimport { safeJsonParse } from \"./sanitize-json\";\nimport { QueryBuilder } from \"./query-builder\";\nimport {\n validateSingleResponse,\n type ExpandValidationConfig,\n} from \"../validation\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { QueryOptions } from \"odata-query\";\nimport buildQuery from \"odata-query\";\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 & string\n : never\n : never;\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 ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? Nav[Name]\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >;\n\n// Helper type to get the inferred schema type from a target occurrence\ntype GetTargetSchemaType<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Rel extends string,\n> = [FindNavigationTarget<O, Rel>] extends [\n TableOccurrence<infer BT, any, any, any>,\n]\n ? [BT] extends [BaseTable<infer S, any, any, any>]\n ? [S] extends [Record<string, StandardSchemaV1>]\n ? InferSchemaType<S>\n : Record<string, any>\n : Record<string, any>\n : Record<string, any>;\n\n// Internal type for expand configuration\ntype ExpandConfig = {\n relation: string;\n options?: Partial<QueryOptions<any>>;\n};\n\n// Type to represent expanded relations\nexport type ExpandedRelations = Record<string, { schema: any; selected: any }>;\n\n// Return type for RecordBuilder execute\nexport type RecordReturnType<\n T extends Record<string, any>,\n IsSingleField extends boolean,\n FieldKey extends keyof T,\n Selected extends keyof T,\n Expands extends ExpandedRelations,\n> = IsSingleField extends true\n ? T[FieldKey]\n : Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n };\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 Selected extends keyof T = keyof T,\n Expands extends ExpandedRelations = {},\n> implements\n ExecutableBuilder<\n RecordReturnType<T, IsSingleField, FieldKey, Selected, Expands>\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 // New properties for select/expand support\n private selectedFields?: string[];\n private expandConfigs: ExpandConfig[] = [];\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>(\n field: K,\n ): RecordBuilder<T, true, K, Occ, keyof T, {}> {\n const newBuilder = new RecordBuilder<T, true, K, Occ, keyof T, {}>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\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 /**\n * Select specific fields to retrieve from the record.\n * Only the selected fields will be returned in the response.\n *\n * @example\n * ```typescript\n * const contact = await db.from(\"contacts\").get(\"uuid\").select(\"name\", \"email\").execute();\n * // contact.data has type { name: string; email: string }\n * ```\n */\n select<K extends keyof T>(\n ...fields: K[]\n ): RecordBuilder<T, false, FieldKey, Occ, K, Expands> {\n const uniqueFields = [...new Set(fields)];\n const newBuilder = new RecordBuilder<T, false, FieldKey, Occ, K, Expands>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.selectedFields = uniqueFields.map((f) => String(f));\n newBuilder.expandConfigs = [...this.expandConfigs];\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 /**\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\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\", \"email\"))\n * .execute();\n * ```\n */\n expand<\n Rel extends ExtractNavigationNames<Occ> | (string & {}),\n TargetOcc extends FindNavigationTarget<Occ, Rel> = FindNavigationTarget<\n Occ,\n Rel\n >,\n TargetSchema extends GetTargetSchemaType<Occ, Rel> = GetTargetSchemaType<\n Occ,\n Rel\n >,\n TargetSelected extends keyof TargetSchema = keyof TargetSchema,\n >(\n relation: Rel,\n callback?: (\n builder: QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >,\n ) => QueryBuilder<\n WithSystemFields<TargetSchema>,\n TargetSelected,\n any,\n any,\n any\n >,\n ): RecordBuilder<\n T,\n false,\n FieldKey,\n Occ,\n Selected,\n Expands & {\n [K in Rel]: { schema: TargetSchema; selected: TargetSelected };\n }\n > {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[relation as string];\n\n // Helper function to get defaultSelect fields from target occurrence\n const getDefaultSelectFields = (): string[] | undefined => {\n if (!targetOccurrence) return undefined;\n const defaultSelect = targetOccurrence.defaultSelect;\n if (defaultSelect === \"schema\") {\n const schema = targetOccurrence.baseTable?.schema;\n if (schema) {\n return [...new Set(Object.keys(schema))];\n }\n } else if (Array.isArray(defaultSelect)) {\n return [...new Set(defaultSelect)];\n }\n // If \"all\", return undefined (no select restriction)\n return undefined;\n };\n\n // Create new builder with updated types\n const newBuilder = new RecordBuilder<\n T,\n false,\n FieldKey,\n Occ,\n Selected,\n Expands & {\n [K in Rel]: { schema: TargetSchema; selected: TargetSelected };\n }\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Copy existing state\n newBuilder.selectedFields = this.selectedFields;\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n\n if (callback) {\n // Create a new QueryBuilder for the target occurrence\n const targetBuilder = new QueryBuilder<any>({\n occurrence: targetOccurrence,\n tableName: targetOccurrence?.name ?? (relation as string),\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Cast to the expected type for the callback\n // At runtime, the builder is untyped (any), but at compile-time we enforce proper types\n const typedBuilder = targetBuilder as QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >;\n\n // Pass to callback and get configured builder\n const configuredBuilder = callback(typedBuilder);\n\n // Extract the builder's query options\n const expandOptions: Partial<QueryOptions<any>> = {\n ...(configuredBuilder as any).queryOptions,\n };\n\n // If callback didn't provide select, apply defaultSelect from target occurrence\n if (!expandOptions.select) {\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n expandOptions.select = defaultFields;\n }\n }\n\n // If the configured builder has nested expands, we need to include them\n if ((configuredBuilder as any).expandConfigs?.length > 0) {\n // Build nested expand string from the configured builder's expand configs\n const nestedExpandString = this.buildExpandString(\n (configuredBuilder as any).expandConfigs,\n );\n if (nestedExpandString) {\n // Add nested expand to options\n expandOptions.expand = nestedExpandString as any;\n }\n }\n\n const expandConfig: ExpandConfig = {\n relation: relation as string,\n options: expandOptions,\n };\n\n newBuilder.expandConfigs.push(expandConfig);\n } else {\n // Simple expand without callback - apply defaultSelect if available\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n newBuilder.expandConfigs.push({\n relation: relation as string,\n options: { select: defaultFields },\n });\n } else {\n newBuilder.expandConfigs.push({ relation: relation as string });\n }\n }\n\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 /**\n * Formats select fields for use in query strings.\n * - Transforms field names to FMFIDs if using entity IDs\n * - Wraps \"id\" fields in double quotes\n * - URL-encodes special characters but preserves spaces\n */\n private formatSelectFields(\n select: string[] | undefined,\n baseTable?: BaseTable<any, any, any, any>,\n ): string {\n if (!select || select.length === 0) return \"\";\n\n // Transform to field IDs if using entity IDs\n const transformedFields = baseTable\n ? transformFieldNamesArray(select, baseTable)\n : select;\n\n return transformedFields\n .map((field) => {\n if (field === \"id\") return `\"id\"`;\n const encodedField = encodeURIComponent(String(field));\n return encodedField.replace(/%20/g, \" \");\n })\n .join(\",\");\n }\n\n /**\n * Builds expand validation configs from internal expand configurations.\n * These are used to validate expanded navigation properties.\n */\n private buildExpandValidationConfigs(\n configs: ExpandConfig[],\n ): ExpandValidationConfig[] {\n return configs.map((config) => {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n const targetSchema = targetOccurrence?.baseTable?.schema;\n\n // Extract selected fields from options\n const selectedFields = config.options?.select\n ? Array.isArray(config.options.select)\n ? config.options.select.map((f) => String(f))\n : [String(config.options.select)]\n : undefined;\n\n return {\n relation: config.relation,\n targetSchema: targetSchema,\n targetOccurrence: targetOccurrence,\n targetBaseTable: targetOccurrence?.baseTable,\n occurrence: targetOccurrence, // For transformation\n selectedFields: selectedFields,\n nestedExpands: undefined, // TODO: Handle nested expands if needed\n };\n });\n }\n\n /**\n * Builds OData expand query string from expand configurations.\n * Handles nested expands recursively.\n * Transforms relation names to FMTIDs if using entity IDs.\n */\n private buildExpandString(configs: ExpandConfig[]): string {\n if (configs.length === 0) {\n return \"\";\n }\n\n return configs\n .map((config) => {\n // Get target occurrence for this relation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n\n // When using entity IDs, use the target table's FMTID in the expand parameter\n // FileMaker expects FMTID in $expand when Prefer header is set\n const relationName =\n targetOccurrence && targetOccurrence.isUsingTableId?.()\n ? targetOccurrence.getTableId()\n : config.relation;\n\n if (!config.options || Object.keys(config.options).length === 0) {\n // Simple expand without options\n return relationName;\n }\n\n // Build query options for this expand\n const parts: string[] = [];\n\n if (config.options.select) {\n // Pass target base table for field transformation\n const selectFields = this.formatSelectFields(\n Array.isArray(config.options.select)\n ? config.options.select.map((f) => String(f))\n : [String(config.options.select)],\n targetOccurrence?.baseTable,\n );\n parts.push(`$select=${selectFields}`);\n }\n\n if (config.options.filter) {\n // Filter should already be transformed by the nested builder\n // Use odata-query to build filter string\n const filterQuery = buildQuery({ filter: config.options.filter });\n const filterMatch = filterQuery.match(/\\$filter=([^&]+)/);\n if (filterMatch) {\n parts.push(`$filter=${filterMatch[1]}`);\n }\n }\n\n if (config.options.orderBy) {\n const orderByQuery = buildQuery({ orderBy: config.options.orderBy });\n const orderByMatch = orderByQuery.match(/\\$orderby=([^&]+)/);\n if (orderByMatch) {\n parts.push(`$orderby=${orderByMatch[1]}`);\n }\n }\n\n if (config.options.top !== undefined) {\n parts.push(`$top=${config.options.top}`);\n }\n\n if (config.options.skip !== undefined) {\n parts.push(`$skip=${config.options.skip}`);\n }\n\n // Handle nested expand\n if (config.options.expand) {\n // Nested expand is already a string from buildExpandString\n parts.push(`$expand=${String(config.options.expand)}`);\n }\n\n if (parts.length === 0) {\n return relationName;\n }\n\n return `${relationName}(${parts.join(\";\")})`;\n })\n .join(\",\");\n }\n\n /**\n * Builds the complete query string including $select and $expand parameters.\n */\n private buildQueryString(): string {\n const parts: string[] = [];\n\n // Build $select\n if (this.selectedFields && this.selectedFields.length > 0) {\n const selectString = this.formatSelectFields(\n this.selectedFields,\n this.occurrence?.baseTable,\n );\n if (selectString) {\n parts.push(`$select=${selectString}`);\n }\n }\n\n // Build $expand\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n parts.push(`$expand=${expandString}`);\n }\n\n if (parts.length === 0) {\n return \"\";\n }\n\n return `?${parts.join(\"&\")}`;\n }\n\n\n async execute<EO extends ExecuteOptions>(\n options?: RequestInit & FFetchOptions & EO,\n ): Promise<\n Result<\n ConditionallyWithODataAnnotations<\n RecordReturnType<T, IsSingleField, FieldKey, Selected, Expands>,\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 (\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(\n options?.useEntityIds ?? this.databaseUseEntityIds,\n );\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n }\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();\n url += queryString;\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 // Build expand validation configs for transformation and validation\n const expandValidationConfigs =\n this.expandConfigs.length > 0\n ? this.buildExpandValidationConfigs(this.expandConfigs)\n : undefined;\n\n if (this.occurrence?.baseTable && shouldUseIds) {\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\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 this.selectedFields as (keyof T)[] | undefined,\n expandValidationConfigs,\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 as any, 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 } 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(): string {\n let path: string;\n\n // Build the path depending on navigation context\n if (\n this.isNavigateFromEntitySet &&\n this.navigateSourceTableName &&\n this.navigateRelation\n ) {\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(this.databaseUseEntityIds);\n path = `/${tableId}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n return `${path}/${this.operationParam}`;\n }\n\n const queryString = this.buildQueryString();\n return `${path}${queryString}`;\n }\n\n toRequest(baseUrl: string, options?: ExecuteOptions): 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: getAcceptHeader(options?.includeODataAnnotations),\n },\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<RecordReturnType<T, IsSingleField, FieldKey, Selected, Expands>>\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 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 // Build expand validation configs for transformation and validation\n const expandValidationConfigs =\n this.expandConfigs.length > 0\n ? this.buildExpandValidationConfigs(this.expandConfigs)\n : undefined;\n\n let transformedResponse = rawResponse;\n if (this.occurrence?.baseTable && shouldUseIds) {\n transformedResponse = transformResponseFields(\n rawResponse,\n this.occurrence.baseTable,\n expandValidationConfigs,\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 this.selectedFields as (keyof T)[] | undefined,\n expandValidationConfigs,\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 as any, error: undefined };\n }\n}\n"],"names":["_a"],"mappings":"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"}
|
|
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 WithSystemFields,\n ConditionallyWithODataAnnotations,\n} from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport {\n transformTableName,\n transformResponseFields,\n getTableIdentifiers,\n transformFieldNamesArray,\n} from \"../transform\";\nimport { safeJsonParse } from \"./sanitize-json\";\nimport { QueryBuilder } from \"./query-builder\";\nimport {\n validateSingleResponse,\n type ExpandValidationConfig,\n} from \"../validation\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { QueryOptions } from \"odata-query\";\nimport buildQuery from \"odata-query\";\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 & string\n : never\n : never;\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 ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? Nav[Name]\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >;\n\n// Helper type to get the inferred schema type from a target occurrence\ntype GetTargetSchemaType<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Rel extends string,\n> = [FindNavigationTarget<O, Rel>] extends [\n TableOccurrence<infer BT, any, any, any>,\n]\n ? [BT] extends [BaseTable<infer S, any, any, any>]\n ? [S] extends [Record<string, StandardSchemaV1>]\n ? InferSchemaType<S>\n : Record<string, any>\n : Record<string, any>\n : Record<string, any>;\n\n// Internal type for expand configuration\ntype ExpandConfig = {\n relation: string;\n options?: Partial<QueryOptions<any>>;\n};\n\n// Type to represent expanded relations\nexport type ExpandedRelations = Record<string, { schema: any; selected: any }>;\n\n// Return type for RecordBuilder execute\nexport type RecordReturnType<\n T extends Record<string, any>,\n IsSingleField extends boolean,\n FieldKey extends keyof T,\n Selected extends keyof T,\n Expands extends ExpandedRelations,\n> = IsSingleField extends true\n ? T[FieldKey]\n : Pick<T, Selected> & {\n [K in keyof Expands]: Pick<\n Expands[K][\"schema\"],\n Expands[K][\"selected\"]\n >[];\n };\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 Selected extends keyof T = keyof T,\n Expands extends ExpandedRelations = {},\n> implements\n ExecutableBuilder<\n RecordReturnType<T, IsSingleField, FieldKey, Selected, Expands>\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 // New properties for select/expand support\n private selectedFields?: string[];\n private expandConfigs: ExpandConfig[] = [];\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>(\n field: K,\n ): RecordBuilder<T, true, K, Occ, keyof T, {}> {\n const newBuilder = new RecordBuilder<T, true, K, Occ, keyof T, {}>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\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 /**\n * Select specific fields to retrieve from the record.\n * Only the selected fields will be returned in the response.\n *\n * @example\n * ```typescript\n * const contact = await db.from(\"contacts\").get(\"uuid\").select(\"name\", \"email\").execute();\n * // contact.data has type { name: string; email: string }\n * ```\n */\n select<K extends keyof T>(\n ...fields: K[]\n ): RecordBuilder<T, false, FieldKey, Occ, K, Expands> {\n const uniqueFields = [...new Set(fields)];\n const newBuilder = new RecordBuilder<T, false, FieldKey, Occ, K, Expands>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n newBuilder.selectedFields = uniqueFields.map((f) => String(f));\n newBuilder.expandConfigs = [...this.expandConfigs];\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 /**\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\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\", \"email\"))\n * .execute();\n * ```\n */\n expand<\n Rel extends ExtractNavigationNames<Occ> | (string & {}),\n TargetOcc extends FindNavigationTarget<Occ, Rel> = FindNavigationTarget<\n Occ,\n Rel\n >,\n TargetSchema extends GetTargetSchemaType<Occ, Rel> = GetTargetSchemaType<\n Occ,\n Rel\n >,\n TargetSelected extends keyof TargetSchema = keyof TargetSchema,\n >(\n relation: Rel,\n callback?: (\n builder: QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >,\n ) => QueryBuilder<\n WithSystemFields<TargetSchema>,\n TargetSelected,\n any,\n any,\n any\n >,\n ): RecordBuilder<\n T,\n false,\n FieldKey,\n Occ,\n Selected,\n Expands & {\n [K in Rel]: { schema: TargetSchema; selected: TargetSelected };\n }\n > {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[relation as string];\n\n // Helper function to get defaultSelect fields from target occurrence\n const getDefaultSelectFields = (): string[] | undefined => {\n if (!targetOccurrence) return undefined;\n const defaultSelect = targetOccurrence.defaultSelect;\n if (defaultSelect === \"schema\") {\n const schema = targetOccurrence.baseTable?.schema;\n if (schema) {\n return [...new Set(Object.keys(schema))];\n }\n } else if (Array.isArray(defaultSelect)) {\n return [...new Set(defaultSelect)];\n }\n // If \"all\", return undefined (no select restriction)\n return undefined;\n };\n\n // Create new builder with updated types\n const newBuilder = new RecordBuilder<\n T,\n false,\n FieldKey,\n Occ,\n Selected,\n Expands & {\n [K in Rel]: { schema: TargetSchema; selected: TargetSelected };\n }\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Copy existing state\n newBuilder.selectedFields = this.selectedFields;\n newBuilder.expandConfigs = [...this.expandConfigs];\n newBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n\n if (callback) {\n // Create a new QueryBuilder for the target occurrence\n const targetBuilder = new QueryBuilder<any>({\n occurrence: targetOccurrence,\n tableName: targetOccurrence?.name ?? (relation as string),\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Cast to the expected type for the callback\n // At runtime, the builder is untyped (any), but at compile-time we enforce proper types\n const typedBuilder = targetBuilder as QueryBuilder<\n TargetSchema,\n keyof TargetSchema,\n false,\n false,\n TargetOcc extends TableOccurrence<any, any, any, any>\n ? TargetOcc\n : undefined\n >;\n\n // Pass to callback and get configured builder\n const configuredBuilder = callback(typedBuilder);\n\n // Extract the builder's query options\n const expandOptions: Partial<QueryOptions<any>> = {\n ...(configuredBuilder as any).queryOptions,\n };\n\n // If callback didn't provide select, apply defaultSelect from target occurrence\n if (!expandOptions.select) {\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n expandOptions.select = defaultFields;\n }\n }\n\n // If the configured builder has nested expands, we need to include them\n if ((configuredBuilder as any).expandConfigs?.length > 0) {\n // Build nested expand string from the configured builder's expand configs\n const nestedExpandString = this.buildExpandString(\n (configuredBuilder as any).expandConfigs,\n );\n if (nestedExpandString) {\n // Add nested expand to options\n expandOptions.expand = nestedExpandString as any;\n }\n }\n\n const expandConfig: ExpandConfig = {\n relation: relation as string,\n options: expandOptions,\n };\n\n newBuilder.expandConfigs.push(expandConfig);\n } else {\n // Simple expand without callback - apply defaultSelect if available\n const defaultFields = getDefaultSelectFields();\n if (defaultFields) {\n newBuilder.expandConfigs.push({\n relation: relation as string,\n options: { select: defaultFields },\n });\n } else {\n newBuilder.expandConfigs.push({ relation: relation as string });\n }\n }\n\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 /**\n * Formats select fields for use in query strings.\n * - Transforms field names to FMFIDs if using entity IDs\n * - Wraps \"id\" fields in double quotes\n * - URL-encodes special characters but preserves spaces\n */\n private formatSelectFields(\n select: string[] | undefined,\n baseTable?: BaseTable<any, any, any, any>,\n useEntityIds?: boolean,\n ): string {\n if (!select || select.length === 0) return \"\";\n\n // Transform to field IDs if using entity IDs AND the feature is enabled\n const shouldTransform = baseTable && (useEntityIds ?? this.databaseUseEntityIds);\n const transformedFields = shouldTransform\n ? transformFieldNamesArray(select, baseTable)\n : select;\n\n return transformedFields\n .map((field) => {\n if (field === \"id\") return `\"id\"`;\n const encodedField = encodeURIComponent(String(field));\n return encodedField.replace(/%20/g, \" \");\n })\n .join(\",\");\n }\n\n /**\n * Builds expand validation configs from internal expand configurations.\n * These are used to validate expanded navigation properties.\n */\n private buildExpandValidationConfigs(\n configs: ExpandConfig[],\n ): ExpandValidationConfig[] {\n return configs.map((config) => {\n // Look up target occurrence from navigation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n const targetSchema = targetOccurrence?.baseTable?.schema;\n\n // Extract selected fields from options\n const selectedFields = config.options?.select\n ? Array.isArray(config.options.select)\n ? config.options.select.map((f) => String(f))\n : [String(config.options.select)]\n : undefined;\n\n return {\n relation: config.relation,\n targetSchema: targetSchema,\n targetOccurrence: targetOccurrence,\n targetBaseTable: targetOccurrence?.baseTable,\n occurrence: targetOccurrence, // For transformation\n selectedFields: selectedFields,\n nestedExpands: undefined, // TODO: Handle nested expands if needed\n };\n });\n }\n\n /**\n * Builds OData expand query string from expand configurations.\n * Handles nested expands recursively.\n * Transforms relation names to FMTIDs if using entity IDs.\n */\n private buildExpandString(configs: ExpandConfig[]): string {\n if (configs.length === 0) {\n return \"\";\n }\n\n return configs\n .map((config) => {\n // Get target occurrence for this relation\n const targetOccurrence = this.occurrence?.navigation[config.relation];\n\n // When using entity IDs, use the target table's FMTID in the expand parameter\n // FileMaker expects FMTID in $expand when Prefer header is set\n const relationName =\n targetOccurrence && targetOccurrence.isUsingTableId?.()\n ? targetOccurrence.getTableId()\n : config.relation;\n\n if (!config.options || Object.keys(config.options).length === 0) {\n // Simple expand without options\n return relationName;\n }\n\n // Build query options for this expand\n const parts: string[] = [];\n\n if (config.options.select) {\n // Pass target base table for field transformation\n const selectFields = this.formatSelectFields(\n Array.isArray(config.options.select)\n ? config.options.select.map((f) => String(f))\n : [String(config.options.select)],\n targetOccurrence?.baseTable,\n );\n parts.push(`$select=${selectFields}`);\n }\n\n if (config.options.filter) {\n // Filter should already be transformed by the nested builder\n // Use odata-query to build filter string\n const filterQuery = buildQuery({ filter: config.options.filter });\n const filterMatch = filterQuery.match(/\\$filter=([^&]+)/);\n if (filterMatch) {\n parts.push(`$filter=${filterMatch[1]}`);\n }\n }\n\n if (config.options.orderBy) {\n const orderByQuery = buildQuery({ orderBy: config.options.orderBy });\n const orderByMatch = orderByQuery.match(/\\$orderby=([^&]+)/);\n if (orderByMatch) {\n parts.push(`$orderby=${orderByMatch[1]}`);\n }\n }\n\n if (config.options.top !== undefined) {\n parts.push(`$top=${config.options.top}`);\n }\n\n if (config.options.skip !== undefined) {\n parts.push(`$skip=${config.options.skip}`);\n }\n\n // Handle nested expand\n if (config.options.expand) {\n // Nested expand is already a string from buildExpandString\n parts.push(`$expand=${String(config.options.expand)}`);\n }\n\n if (parts.length === 0) {\n return relationName;\n }\n\n return `${relationName}(${parts.join(\";\")})`;\n })\n .join(\",\");\n }\n\n /**\n * Builds the complete query string including $select and $expand parameters.\n */\n private buildQueryString(): string {\n const parts: string[] = [];\n\n // Build $select\n if (this.selectedFields && this.selectedFields.length > 0) {\n const selectString = this.formatSelectFields(\n this.selectedFields,\n this.occurrence?.baseTable,\n );\n if (selectString) {\n parts.push(`$select=${selectString}`);\n }\n }\n\n // Build $expand\n const expandString = this.buildExpandString(this.expandConfigs);\n if (expandString) {\n parts.push(`$expand=${expandString}`);\n }\n\n if (parts.length === 0) {\n return \"\";\n }\n\n return `?${parts.join(\"&\")}`;\n }\n\n\n async execute<EO extends ExecuteOptions>(\n options?: RequestInit & FFetchOptions & EO,\n ): Promise<\n Result<\n ConditionallyWithODataAnnotations<\n RecordReturnType<T, IsSingleField, FieldKey, Selected, Expands>,\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 (\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(\n options?.useEntityIds ?? this.databaseUseEntityIds,\n );\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n }\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();\n url += queryString;\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 // Build expand validation configs for transformation and validation\n const expandValidationConfigs =\n this.expandConfigs.length > 0\n ? this.buildExpandValidationConfigs(this.expandConfigs)\n : undefined;\n\n if (this.occurrence?.baseTable && shouldUseIds) {\n response = transformResponseFields(\n response,\n this.occurrence.baseTable,\n expandValidationConfigs,\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 this.selectedFields as (keyof T)[] | undefined,\n expandValidationConfigs,\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 as any, 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 } 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(): string {\n let path: string;\n\n // Build the path depending on navigation context\n if (\n this.isNavigateFromEntitySet &&\n this.navigateSourceTableName &&\n this.navigateRelation\n ) {\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(this.databaseUseEntityIds);\n path = `/${tableId}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n return `${path}/${this.operationParam}`;\n }\n\n const queryString = this.buildQueryString();\n return `${path}${queryString}`;\n }\n\n toRequest(baseUrl: string, options?: ExecuteOptions): 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: getAcceptHeader(options?.includeODataAnnotations),\n },\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<\n Result<RecordReturnType<T, IsSingleField, FieldKey, Selected, Expands>>\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 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 // Build expand validation configs for transformation and validation\n const expandValidationConfigs =\n this.expandConfigs.length > 0\n ? this.buildExpandValidationConfigs(this.expandConfigs)\n : undefined;\n\n let transformedResponse = rawResponse;\n if (this.occurrence?.baseTable && shouldUseIds) {\n transformedResponse = transformResponseFields(\n rawResponse,\n this.occurrence.baseTable,\n expandValidationConfigs,\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 this.selectedFields as (keyof T)[] | undefined,\n expandValidationConfigs,\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 as any, error: undefined };\n }\n}\n"],"names":["_a"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proofkit/fmodata",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.13",
|
|
4
4
|
"description": "FileMaker OData API client",
|
|
5
5
|
"repository": "git@github.com:proofgeist/proofkit.git",
|
|
6
6
|
"author": "Eric <37158449+eluce2@users.noreply.github.com>",
|
|
@@ -18,20 +18,6 @@
|
|
|
18
18
|
},
|
|
19
19
|
"./package.json": "./package.json"
|
|
20
20
|
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsc && vite build && publint --strict",
|
|
23
|
-
"build:watch": "tsc && vite build --watch",
|
|
24
|
-
"check-format": "prettier --check .",
|
|
25
|
-
"format": "prettier --write .",
|
|
26
|
-
"dev": "tsc --watch",
|
|
27
|
-
"test": "vitest run --typecheck",
|
|
28
|
-
"test:typecheck": "vitest run --typecheck",
|
|
29
|
-
"test:watch": "vitest --typecheck",
|
|
30
|
-
"test:e2e": "op inject -i op.env -o .env.local -f && vitest run tests/e2e.test.ts",
|
|
31
|
-
"capture": "op inject -i op.env -o .env.local -f && tsx scripts/capture-responses.ts",
|
|
32
|
-
"knip": "knip",
|
|
33
|
-
"pub:alpha": "bun run scripts/publish-alpha.ts"
|
|
34
|
-
},
|
|
35
21
|
"dependencies": {
|
|
36
22
|
"@fetchkit/ffetch": "^4.2.0",
|
|
37
23
|
"dotenv": "^16.5.0",
|
|
@@ -74,5 +60,19 @@
|
|
|
74
60
|
"odata",
|
|
75
61
|
"proofgeist",
|
|
76
62
|
"proofkit"
|
|
77
|
-
]
|
|
78
|
-
|
|
63
|
+
],
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "tsc && vite build && publint --strict",
|
|
66
|
+
"build:watch": "tsc && vite build --watch",
|
|
67
|
+
"check-format": "prettier --check .",
|
|
68
|
+
"format": "prettier --write .",
|
|
69
|
+
"dev": "tsc --watch",
|
|
70
|
+
"test": "vitest run --typecheck",
|
|
71
|
+
"test:typecheck": "vitest run --typecheck",
|
|
72
|
+
"test:watch": "vitest --typecheck",
|
|
73
|
+
"test:e2e": "op inject -i op.env -o .env.local -f && vitest run tests/e2e.test.ts",
|
|
74
|
+
"capture": "op inject -i op.env -o .env.local -f && tsx scripts/capture-responses.ts",
|
|
75
|
+
"knip": "knip",
|
|
76
|
+
"pub:alpha": "bun run scripts/publish-alpha.ts"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -282,9 +282,11 @@ export class QueryBuilder<
|
|
|
282
282
|
const andConditions: any[] = [];
|
|
283
283
|
|
|
284
284
|
for (const [field, value] of Object.entries(filter)) {
|
|
285
|
-
// Transform field name to FMFID if using entity IDs
|
|
286
|
-
const
|
|
287
|
-
|
|
285
|
+
// Transform field name to FMFID if using entity IDs AND the feature is enabled
|
|
286
|
+
const shouldTransform =
|
|
287
|
+
this.occurrence?.baseTable && this.databaseUseEntityIds;
|
|
288
|
+
const fieldId = shouldTransform
|
|
289
|
+
? transformFieldName(field, this.occurrence!.baseTable)
|
|
288
290
|
: field;
|
|
289
291
|
|
|
290
292
|
if (Array.isArray(value)) {
|
|
@@ -400,12 +402,15 @@ export class QueryBuilder<
|
|
|
400
402
|
private formatSelectFields(
|
|
401
403
|
select: QueryOptions<any>["select"],
|
|
402
404
|
baseTable?: BaseTable<any, any, any, any>,
|
|
405
|
+
useEntityIds?: boolean,
|
|
403
406
|
): string {
|
|
404
407
|
if (!select) return "";
|
|
405
408
|
const selectFieldsArray = Array.isArray(select) ? select : [select];
|
|
406
409
|
|
|
407
|
-
// Transform to field IDs if using entity IDs
|
|
408
|
-
const
|
|
410
|
+
// Transform to field IDs if using entity IDs AND the feature is enabled
|
|
411
|
+
const shouldTransform =
|
|
412
|
+
baseTable && (useEntityIds ?? this.databaseUseEntityIds);
|
|
413
|
+
const transformedFields = shouldTransform
|
|
409
414
|
? transformFieldNamesArray(
|
|
410
415
|
selectFieldsArray.map((f) => String(f)),
|
|
411
416
|
baseTable,
|
|
@@ -469,10 +474,12 @@ export class QueryBuilder<
|
|
|
469
474
|
|
|
470
475
|
// When using entity IDs, use the target table's FMTID in the expand parameter
|
|
471
476
|
// FileMaker expects FMTID in $expand when Prefer header is set
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
477
|
+
// Only use FMTID if databaseUseEntityIds is enabled
|
|
478
|
+
const shouldUseTableId =
|
|
479
|
+
this.databaseUseEntityIds && targetOccurrence?.isUsingTableId();
|
|
480
|
+
const relationName = shouldUseTableId
|
|
481
|
+
? targetOccurrence!.getTableId()
|
|
482
|
+
: config.relation;
|
|
476
483
|
|
|
477
484
|
if (!config.options || Object.keys(config.options).length === 0) {
|
|
478
485
|
// Simple expand without options
|
|
@@ -489,11 +489,13 @@ export class RecordBuilder<
|
|
|
489
489
|
private formatSelectFields(
|
|
490
490
|
select: string[] | undefined,
|
|
491
491
|
baseTable?: BaseTable<any, any, any, any>,
|
|
492
|
+
useEntityIds?: boolean,
|
|
492
493
|
): string {
|
|
493
494
|
if (!select || select.length === 0) return "";
|
|
494
495
|
|
|
495
|
-
// Transform to field IDs if using entity IDs
|
|
496
|
-
const
|
|
496
|
+
// Transform to field IDs if using entity IDs AND the feature is enabled
|
|
497
|
+
const shouldTransform = baseTable && (useEntityIds ?? this.databaseUseEntityIds);
|
|
498
|
+
const transformedFields = shouldTransform
|
|
497
499
|
? transformFieldNamesArray(select, baseTable)
|
|
498
500
|
: select;
|
|
499
501
|
|