@proofkit/fmodata 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/esm/client/base-table.d.ts +13 -0
- package/dist/esm/client/base-table.js +19 -0
- package/dist/esm/client/base-table.js.map +1 -0
- package/dist/esm/client/database.d.ts +49 -0
- package/dist/esm/client/database.js +90 -0
- package/dist/esm/client/database.js.map +1 -0
- package/dist/esm/client/delete-builder.d.ts +61 -0
- package/dist/esm/client/delete-builder.js +121 -0
- package/dist/esm/client/delete-builder.js.map +1 -0
- package/dist/esm/client/entity-set.d.ts +43 -0
- package/dist/esm/client/entity-set.js +120 -0
- package/dist/esm/client/entity-set.js.map +1 -0
- package/dist/esm/client/filemaker-odata.d.ts +26 -0
- package/dist/esm/client/filemaker-odata.js +85 -0
- package/dist/esm/client/filemaker-odata.js.map +1 -0
- package/dist/esm/client/insert-builder.d.ts +23 -0
- package/dist/esm/client/insert-builder.js +69 -0
- package/dist/esm/client/insert-builder.js.map +1 -0
- package/dist/esm/client/query-builder.d.ts +94 -0
- package/dist/esm/client/query-builder.js +649 -0
- package/dist/esm/client/query-builder.js.map +1 -0
- package/dist/esm/client/record-builder.d.ts +43 -0
- package/dist/esm/client/record-builder.js +121 -0
- package/dist/esm/client/record-builder.js.map +1 -0
- package/dist/esm/client/table-occurrence.d.ts +25 -0
- package/dist/esm/client/table-occurrence.js +47 -0
- package/dist/esm/client/table-occurrence.js.map +1 -0
- package/dist/esm/client/update-builder.d.ts +69 -0
- package/dist/esm/client/update-builder.js +134 -0
- package/dist/esm/client/update-builder.js.map +1 -0
- package/dist/esm/filter-types.d.ts +76 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.d.ts +67 -0
- package/dist/esm/validation.d.ts +41 -0
- package/dist/esm/validation.js +270 -0
- package/dist/esm/validation.js.map +1 -0
- package/package.json +68 -0
- package/src/client/base-table.ts +25 -0
- package/src/client/database.ts +177 -0
- package/src/client/delete-builder.ts +193 -0
- package/src/client/entity-set.ts +310 -0
- package/src/client/filemaker-odata.ts +119 -0
- package/src/client/insert-builder.ts +93 -0
- package/src/client/query-builder.ts +1076 -0
- package/src/client/record-builder.ts +240 -0
- package/src/client/table-occurrence.ts +100 -0
- package/src/client/update-builder.ts +212 -0
- package/src/filter-types.ts +97 -0
- package/src/index.ts +17 -0
- package/src/types.ts +123 -0
- package/src/validation.ts +397 -0
|
@@ -0,0 +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 ODataRecordMetadata,\n Result,\n InferSchemaType,\n ExecuteOptions,\n ConditionallyWithODataAnnotations,\n ExtractSchemaFromOccurrence,\n} 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 { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport { z } from \"zod/v4\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\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 resolve a navigation item (handles both direct and lazy-loaded)\ntype ResolveNavigationItem<T> = T extends () => infer R ? R : T;\n\n// Helper type to find target occurrence by relation name\ntype FindNavigationTarget<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Name extends string,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? ResolveNavigationItem<Nav[Name]>\n : TableOccurrence<\n BaseTable<Record<string, z.ZodTypeAny>, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, z.ZodTypeAny>, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, z.ZodTypeAny>, 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>]\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\ntype ExpandedRelations = Record<string, { schema: any; selected: any }>;\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> {\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 constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n }\n\n /**\n * Helper to conditionally strip OData annotations based on options\n */\n private stripODataAnnotationsIfNeeded<T extends Record<string, any>>(\n data: T,\n options?: ExecuteOptions,\n ): T {\n // Only include annotations if explicitly requested\n if (options?.includeODataAnnotations === true) {\n return data;\n }\n\n // Strip OData annotations\n const { \"@id\": _id, \"@editLink\": _editLink, ...rest } = data;\n return rest as T;\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 });\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 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[field] = 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({ [field]: 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[field] = value;\n } else {\n // Regular object - might be nested filter, pass through\n result[field] = value;\n }\n } else {\n // Primitive value (shorthand) - pass through\n result[field] = 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 this.queryOptions.orderBy = orderBy;\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 * - Wraps \"id\" fields in double quotes\n * - URL-encodes special characters but preserves spaces\n */\n private formatSelectFields(select: QueryOptions<any>[\"select\"]): string {\n if (!select) return \"\";\n const selectFieldsArray = Array.isArray(select) ? select : [select];\n return selectFieldsArray\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 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 */\n private buildExpandString(configs: ExpandConfig[]): string {\n if (configs.length === 0) {\n return \"\";\n }\n\n return configs\n .map((config) => {\n if (!config.options || Object.keys(config.options).length === 0) {\n // Simple expand without options\n return config.relation;\n }\n\n // Build query options for this expand\n const parts: string[] = [];\n\n if (config.options.select) {\n const selectFields = this.formatSelectFields(config.options.select);\n parts.push(`$select=${selectFields}`);\n }\n\n if (config.options.filter) {\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 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 config.relation;\n }\n\n return `${config.relation}(${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 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 });\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 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\n this.expandConfigs.push({ relation: relation as string });\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 });\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 });\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 });\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 try {\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 ) 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 response = await this.context._makeRequest(url, options);\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 Error(\n `Expected ${this.singleMode === \"exact\" ? \"exactly one\" : \"at most one\"} record, but received ${count}`,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new Error(\n \"Expected exactly one record, but received none\",\n ),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n const stripped = this.stripODataAnnotationsIfNeeded(\n record,\n options,\n );\n return { data: stripped as any, error: undefined };\n } else {\n const records = resp.value ?? [];\n const stripped = records.map((record: any) =>\n this.stripODataAnnotationsIfNeeded(record, options),\n );\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 const stripped = validation.data\n ? this.stripODataAnnotationsIfNeeded(validation.data, options)\n : null;\n return { data: stripped 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 const stripped = validation.data.map((record) =>\n this.stripODataAnnotationsIfNeeded(record, options),\n );\n return { data: stripped 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 response = await this.context._makeRequest(\n `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`,\n options,\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 Error(\n `Expected ${this.singleMode === \"exact\" ? \"exactly one\" : \"at most one\"} record, but received ${count}`,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new Error(\n \"Expected exactly one record, but received none\",\n ),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n const stripped = this.stripODataAnnotationsIfNeeded(\n record,\n options,\n );\n return { data: stripped as any, error: undefined };\n } else {\n const records = resp.value ?? [];\n const stripped = records.map((record: any) =>\n this.stripODataAnnotationsIfNeeded(record, options),\n );\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 const stripped = validation.data\n ? this.stripODataAnnotationsIfNeeded(validation.data, options)\n : null;\n return { data: stripped 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 const stripped = validation.data.map((record) =>\n this.stripODataAnnotationsIfNeeded(record, options),\n );\n return { data: stripped as any, error: undefined };\n }\n }\n\n // Handle $count endpoint\n if (this.isCountMode) {\n const result = await this.context._makeRequest(\n `/${this.databaseName}/${this.tableName}/$count${queryString}`,\n options,\n );\n // OData returns count as a string, convert to number\n const count = typeof result === \"string\" ? Number(result) : result;\n return { data: count as number, error: undefined } as any;\n }\n\n const response = await this.context._makeRequest(\n `/${this.databaseName}/${this.tableName}${queryString}`,\n options,\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 Error(\n `Expected ${this.singleMode === \"exact\" ? \"exactly one\" : \"at most one\"} record, but received ${count}`,\n ),\n };\n }\n\n if (count === 0) {\n if (this.singleMode === \"exact\") {\n return {\n data: undefined,\n error: new Error(\n \"Expected exactly one record, but received none\",\n ),\n };\n }\n return { data: null as any, error: undefined };\n }\n\n const record = Array.isArray(records) ? records[0] : records;\n const stripped = this.stripODataAnnotationsIfNeeded(record, options);\n return { data: stripped as any, error: undefined };\n } else {\n // Handle list response structure\n const records = resp.value ?? [];\n const stripped = records.map((record: any) =>\n this.stripODataAnnotationsIfNeeded(record, options),\n );\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 const stripped = validation.data\n ? this.stripODataAnnotationsIfNeeded(validation.data, options)\n : null;\n return {\n data: stripped 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 const stripped = validation.data.map((record) =>\n this.stripODataAnnotationsIfNeeded(record, options),\n );\n return {\n data: stripped as any,\n error: undefined,\n };\n }\n } catch (error) {\n return {\n data: undefined,\n error: error instanceof Error ? error : new Error(String(error)),\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 ) 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 // Return the path portion: /sourceTableName/relationName\n const path = `/${this.navigateSourceTableName}/${this.navigateRelation}`;\n // Append query params if any exist\n return queryParams ? `${path}${queryParams}` : path;\n }\n\n // Default case: return table name with query params\n return `/${this.tableName}${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 ) 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 url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}${queryString}`;\n } else if (this.isCountMode) {\n url = `/${this.databaseName}/${this.tableName}/$count${queryString}`;\n } else {\n url = `/${this.databaseName}/${this.tableName}${queryString}`;\n }\n\n return {\n method: \"GET\",\n url,\n };\n }\n}\n"],"names":["result","response","schema","selectedFields","expandValidationConfigs"],"mappings":";;;;;AAqFO,MAAM,aAOX;AAAA,EAcA,YAAY,QAKT;AAlBK,wCAAyC,CAAC;AAC1C,yCAAgC,CAAC;AACjC,sCAAyB;AACzB,uCAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAON,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,8BACN,MACA,SACG;AAEC,SAAA,mCAAS,6BAA4B,MAAM;AACtC,aAAA;AAAA,IAAA;AAIT,UAAM,EAAE,OAAO,KAAK,aAAa,WAAW,GAAG,SAAS;AACjD,WAAA;AAAA,EAAA;AAAA,EAGT,UACK,QACoD;AACvD,UAAM,eAAe,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AAClC,UAAA,aAAa,IAAI,aAOrB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AACD,eAAW,eAAe;AAAA,MACxB,GAAG,KAAK;AAAA,MACR,QAAQ;AAAA,IACV;AACA,eAAW,gBAAgB,CAAC,GAAG,KAAK,aAAa;AACjD,eAAW,aAAa,KAAK;AAC7B,eAAW,cAAc,KAAK;AAE9B,eAAW,aAAa,KAAK;AAC7B,eAAW,mBAAmB,KAAK;AACnC,eAAW,mBAAmB,KAAK;AACnC,eAAW,0BAA0B,KAAK;AAC1C,eAAW,uBAAuB,KAAK;AAChC,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASD,gBACN,QAC2B;AACvB,QAAA,OAAO,WAAW,UAAU;AAEvB,aAAA;AAAA,IAAA;AAGL,QAAA,MAAM,QAAQ,MAAM,GAAG;AAEzB,aAAO,OAAO,IAAI,CAAC,MAAM,KAAK,gBAAgB,CAAQ,CAAC;AAAA,IAAA;AAIzD,QAAI,SAAS,UAAU,QAAQ,UAAU,SAAS,QAAQ;AACxD,YAAMA,UAAc,CAAC;AACrB,UAAI,SAAS,UAAU,MAAM,QAAQ,OAAO,GAAG,GAAG;AAChDA,gBAAO,MAAM,OAAO,IAAI,IAAI,CAAC,MAAW,KAAK,gBAAgB,CAAC,CAAC;AAAA,MAAA;AAEjE,UAAI,QAAQ,UAAU,MAAM,QAAQ,OAAO,EAAE,GAAG;AAC9CA,gBAAO,KAAK,OAAO,GAAG,IAAI,CAAC,MAAW,KAAK,gBAAgB,CAAC,CAAC;AAAA,MAAA;AAE3D,UAAA,SAAS,UAAU,OAAO,KAAK;AACjCA,gBAAO,MAAM,KAAK,gBAAgB,OAAO,GAAU;AAAA,MAAA;AAE9CA,aAAAA;AAAAA,IAAA;AAIT,UAAM,SAAc,CAAC;AACrB,UAAM,gBAAuB,CAAC;AAE9B,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,UAAA,MAAM,QAAQ,KAAK,GAAG;AAEpB,YAAA,MAAM,WAAW,GAAG;AAEf,iBAAA,KAAK,IAAI,MAAM,CAAC;AAAA,QAAA,OAClB;AAGL,qBAAW,MAAM,OAAO;AACtB,0BAAc,KAAK,EAAE,CAAC,KAAK,GAAG,IAAI;AAAA,UAAA;AAAA,QACpC;AAAA,MAGF,WAAA,SACA,OAAO,UAAU,YACjB,EAAE,iBAAiB,SACnB,CAAC,MAAM,QAAQ,KAAK,GACpB;AAEA,cAAM,eAAe;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,cAAM,mBAAmB,aAAa,KAAK,CAAC,QAAQ,OAAO,KAAK;AAEhE,YAAI,kBAAkB;AAEpB,iBAAO,KAAK,IAAI;AAAA,QAAA,OACX;AAEL,iBAAO,KAAK,IAAI;AAAA,QAAA;AAAA,MAClB,OACK;AAEL,eAAO,KAAK,IAAI;AAAA,MAAA;AAAA,IAClB;AAIE,QAAA,cAAc,SAAS,GAAG;AAC5B,UAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAGlC,eAAO,EAAE,KAAK,CAAC,GAAG,eAAe,MAAM,EAAE;AAAA,MAAA,OACpC;AAEE,eAAA,EAAE,KAAK,cAAc;AAAA,MAAA;AAAA,IAC9B;AAGK,WAAA;AAAA,EAAA;AAAA,EAGT,OACE,QAC8D;AAE9D,SAAK,aAAa,SAAS,KAAK,gBAAgB,MAAM;AAC/C,WAAA;AAAA,EAAA;AAAA,EAGT,QACE,SAC8D;AAC9D,SAAK,aAAa,UAAU;AACrB,WAAA;AAAA,EAAA;AAAA,EAGT,IACE,OAC8D;AAC9D,SAAK,aAAa,MAAM;AACjB,WAAA;AAAA,EAAA;AAAA,EAGT,KACE,OAC8D;AAC9D,SAAK,aAAa,OAAO;AAClB,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQD,mBAAmB,QAA6C;AAClE,QAAA,CAAC,OAAe,QAAA;AACpB,UAAM,oBAAoB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AAC3D,WAAA,kBACJ,IAAI,CAAC,UAAU;AACV,UAAA,UAAU,KAAa,QAAA;AAC3B,YAAM,eAAe,mBAAmB,OAAO,KAAK,CAAC;AAC9C,aAAA,aAAa,QAAQ,QAAQ,GAAG;AAAA,IAAA,CACxC,EACA,KAAK,GAAG;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOL,6BACN,SACkD;AAC3C,WAAA,QAAQ,IAAI,CAAC,WAAW;;AAE7B,YAAM,oBAAmB,UAAK,eAAL,mBAAiB,WAAW,OAAO;AACtD,YAAA,gBAAe,0DAAkB,cAAlB,mBAA6B;AAG5C,YAAA,mBAAiB,YAAO,YAAP,mBAAgB,UACnC,MAAM,QAAQ,OAAO,QAAQ,MAAM,IACjC,OAAO,QAAQ,OAAO,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAC1C,CAAC,OAAO,OAAO,QAAQ,MAAM,CAAC,IAChC;AAEG,aAAA;AAAA,QACL,UAAU,OAAO;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe;AAAA;AAAA,MACjB;AAAA,IAAA,CACD;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOK,kBAAkB,SAAiC;AACrD,QAAA,QAAQ,WAAW,GAAG;AACjB,aAAA;AAAA,IAAA;AAGF,WAAA,QACJ,IAAI,CAAC,WAAW;AACX,UAAA,CAAC,OAAO,WAAW,OAAO,KAAK,OAAO,OAAO,EAAE,WAAW,GAAG;AAE/D,eAAO,OAAO;AAAA,MAAA;AAIhB,YAAM,QAAkB,CAAC;AAErB,UAAA,OAAO,QAAQ,QAAQ;AACzB,cAAM,eAAe,KAAK,mBAAmB,OAAO,QAAQ,MAAM;AAC5D,cAAA,KAAK,WAAW,YAAY,EAAE;AAAA,MAAA;AAGlC,UAAA,OAAO,QAAQ,QAAQ;AAEzB,cAAM,cAAc,WAAW,EAAE,QAAQ,OAAO,QAAQ,QAAQ;AAC1D,cAAA,cAAc,YAAY,MAAM,kBAAkB;AACxD,YAAI,aAAa;AACf,gBAAM,KAAK,WAAW,YAAY,CAAC,CAAC,EAAE;AAAA,QAAA;AAAA,MACxC;AAGE,UAAA,OAAO,QAAQ,SAAS;AAC1B,cAAM,eAAe,MAAM,QAAQ,OAAO,QAAQ,OAAO,IACrD,OAAO,QAAQ,QAAQ,KAAK,GAAG,IAC/B,OAAO,QAAQ;AACnB,cAAM,KAAK,YAAY,OAAO,YAAY,CAAC,EAAE;AAAA,MAAA;AAG3C,UAAA,OAAO,QAAQ,QAAQ,QAAW;AACpC,cAAM,KAAK,QAAQ,OAAO,QAAQ,GAAG,EAAE;AAAA,MAAA;AAGrC,UAAA,OAAO,QAAQ,SAAS,QAAW;AACrC,cAAM,KAAK,SAAS,OAAO,QAAQ,IAAI,EAAE;AAAA,MAAA;AAIvC,UAAA,OAAO,QAAQ,QAAQ;AAEzB,YAAI,OAAO,OAAO,QAAQ,WAAW,UAAU;AAC7C,gBAAM,KAAK,WAAW,OAAO,QAAQ,MAAM,EAAE;AAAA,QAAA;AAAA,MAC/C;AAGE,UAAA,MAAM,WAAW,GAAG;AACtB,eAAO,OAAO;AAAA,MAAA;AAGhB,aAAO,GAAG,OAAO,QAAQ,IAAI,MAAM,KAAK,GAAG,CAAC;AAAA,IAAA,CAC7C,EACA,KAAK,GAAG;AAAA,EAAA;AAAA,EAGb,OAYE,UACA,UA0BA;;AAEA,UAAM,oBAAmB,UAAK,eAAL,mBAAiB,WAAW;AAErD,QAAI,UAAU;AAEN,YAAA,gBAAgB,IAAI,aAAkB;AAAA,QAC1C,YAAY;AAAA,QACZ,YAAW,qDAAkB,SAAS;AAAA,QACtC,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK;AAAA,MAAA,CACf;AAID,YAAM,eAAe;AAWf,YAAA,oBAAoB,SAAS,YAAY;AAG/C,YAAM,gBAA4C;AAAA,QAChD,GAAG,kBAAkB;AAAA,MACvB;AAGI,UAAA,kBAAkB,cAAc,SAAS,GAAG;AAE9C,cAAM,qBAAqB,KAAK;AAAA,UAC9B,kBAAkB;AAAA,QACpB;AACA,YAAI,oBAAoB;AAEtB,wBAAc,SAAS;AAAA,QAAA;AAAA,MACzB;AAGF,YAAM,eAA6B;AAAA,QACjC;AAAA,QACA,SAAS;AAAA,MACX;AAEK,WAAA,cAAc,KAAK,YAAY;AAAA,IAAA,OAC/B;AAEL,WAAK,cAAc,KAAK,EAAE,SAAA,CAA8B;AAAA,IAAA;AAGnD,WAAA;AAAA,EAAA;AAAA,EAGT,SAAoE;AAC5D,UAAA,aAAa,IAAI,aAOrB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AACD,eAAW,eAAe,EAAE,GAAG,KAAK,aAAa;AACjD,eAAW,gBAAgB,CAAC,GAAG,KAAK,aAAa;AACjD,eAAW,aAAa;AACxB,eAAW,cAAc,KAAK;AAE9B,eAAW,aAAa,KAAK;AAC7B,eAAW,mBAAmB,KAAK;AACnC,eAAW,mBAAmB,KAAK;AACnC,eAAW,0BAA0B,KAAK;AAC1C,eAAW,uBAAuB,KAAK;AAChC,WAAA;AAAA,EAAA;AAAA,EAGT,cAAyE;AACjE,UAAA,aAAa,IAAI,aAOrB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AACD,eAAW,eAAe,EAAE,GAAG,KAAK,aAAa;AACjD,eAAW,gBAAgB,CAAC,GAAG,KAAK,aAAa;AACjD,eAAW,aAAa;AACxB,eAAW,cAAc,KAAK;AAE9B,eAAW,aAAa,KAAK;AAC7B,eAAW,mBAAmB,KAAK;AACnC,eAAW,mBAAmB,KAAK;AACnC,eAAW,0BAA0B,KAAK;AAC1C,eAAW,uBAAuB,KAAK;AAChC,WAAA;AAAA,EAAA;AAAA,EAGT,QAAmE;AAC3D,UAAA,aAAa,IAAI,aAOrB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AACD,eAAW,eAAe,EAAE,GAAG,KAAK,cAAc,OAAO,KAAK;AAC9D,eAAW,gBAAgB,CAAC,GAAG,KAAK,aAAa;AACjD,eAAW,aAAa,KAAK;AAC7B,eAAW,cAAc;AAEzB,eAAW,aAAa,KAAK;AAC7B,eAAW,mBAAmB,KAAK;AACnC,eAAW,mBAAmB,KAAK;AACnC,eAAW,0BAA0B,KAAK;AAC1C,eAAW,uBAAuB,KAAK;AAChC,WAAA;AAAA,EAAA;AAAA,EAGT,MAAM,QACJ,SAmCA;;AACI,QAAA;AAEF,YAAM,4BAA4B,EAAE,GAAG,KAAK,aAAa;AACzD,aAAO,0BAA0B;AAGjC,UAAI,0BAA0B,QAAQ;AACpC,kCAA0B,SAAS,KAAK;AAAA,UACtC,0BAA0B;AAAA,QAC5B;AAAA,MAAA;AAGE,UAAA,cAAc,WAAW,yBAAyB;AAGtD,YAAM,eAAe,KAAK,kBAAkB,KAAK,aAAa;AAC9D,UAAI,cAAc;AAChB,cAAM,YAAY,YAAY,SAAS,GAAG,IAAI,MAAM;AACpD,sBAAc,GAAG,WAAW,GAAG,SAAS,WAAW,YAAY;AAAA,MAAA;AAIjE,UACE,KAAK,cACL,KAAK,oBACL,KAAK,oBACL,KAAK,yBACL;AACI,YAAA;AACJ,YAAI,KAAK,sBAAsB;AAE7B,gBAAM,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,IAAI,KAAK,oBAAoB,KAAK,KAAK,gBAAgB,MAAM,KAAK,gBAAgB,GAAG,WAAW;AAAA,QAAA,OACtJ;AAEL,gBAAM,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,KAAK,KAAK,gBAAgB,MAAM,KAAK,gBAAgB,GAAG,WAAW;AAAA,QAAA;AAEhI,cAAMC,YAAW,MAAM,KAAK,QAAQ,aAAa,KAAK,OAAO;AAGzD,aAAA,mCAAS,oBAAmB,MAAM;AACpC,gBAAM,OAAOA;AACT,cAAA,KAAK,eAAe,OAAO;AAC7B,kBAAM,UAAU,KAAK,SAAS,CAAC,IAAI;AACnC,kBAAM,QAAQ,MAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS;AAExD,gBAAI,QAAQ,GAAG;AACN,qBAAA;AAAA,gBACL,MAAM;AAAA,gBACN,OAAO,IAAI;AAAA,kBACT,YAAY,KAAK,eAAe,UAAU,gBAAgB,aAAa,yBAAyB,KAAK;AAAA,gBAAA;AAAA,cAEzG;AAAA,YAAA;AAGF,gBAAI,UAAU,GAAG;AACX,kBAAA,KAAK,eAAe,SAAS;AACxB,uBAAA;AAAA,kBACL,MAAM;AAAA,kBACN,OAAO,IAAI;AAAA,oBACT;AAAA,kBAAA;AAAA,gBAEJ;AAAA,cAAA;AAEF,qBAAO,EAAE,MAAM,MAAa,OAAO,OAAU;AAAA,YAAA;AAG/C,kBAAM,SAAS,MAAM,QAAQ,OAAO,IAAI,QAAQ,CAAC,IAAI;AACrD,kBAAM,WAAW,KAAK;AAAA,cACpB;AAAA,cACA;AAAA,YACF;AACA,mBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,UAAA,OAC5C;AACC,kBAAA,UAAU,KAAK,SAAS,CAAC;AAC/B,kBAAM,WAAW,QAAQ;AAAA,cAAI,CAAC,WAC5B,KAAK,8BAA8B,QAAQ,OAAO;AAAA,YACpD;AACA,mBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,UAAA;AAAA,QACnD;AAIIC,cAAAA,WAAS,gBAAK,eAAL,mBAAiB,cAAjB,mBAA4B;AACrCC,cAAAA,kBAAiB,KAAK,aAAa;AAGzC,cAAMC,2BAA0B,KAAK;AAAA,UACnC,KAAK;AAAA,QACP;AAEI,YAAA,KAAK,eAAe,OAAO;AAC7B,gBAAM,aAAa,MAAM;AAAA,YACvBH;AAAAA,YACAC;AAAAA,YACAC;AAAAA,YACAC;AAAAA,YACA,KAAK;AAAA,UACP;AACI,cAAA,CAAC,WAAW,OAAO;AACrB,mBAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,UAAA;AAE9C,gBAAA,WAAW,WAAW,OACxB,KAAK,8BAA8B,WAAW,MAAM,OAAO,IAC3D;AACJ,iBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,QAAA,OAC5C;AACL,gBAAM,aAAa,MAAM;AAAA,YACvBH;AAAAA,YACAC;AAAAA,YACAC;AAAAA,YACAC;AAAAA,UACF;AACI,cAAA,CAAC,WAAW,OAAO;AACrB,mBAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,UAAA;AAE9C,gBAAA,WAAW,WAAW,KAAK;AAAA,YAAI,CAAC,WACpC,KAAK,8BAA8B,QAAQ,OAAO;AAAA,UACpD;AACA,iBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,QAAA;AAAA,MACnD;AAKA,UAAA,KAAK,cACL,CAAC,KAAK,oBACN,KAAK,oBACL,KAAK,yBACL;AACMH,cAAAA,YAAW,MAAM,KAAK,QAAQ;AAAA,UAClC,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,IAAI,KAAK,gBAAgB,GAAG,WAAW;AAAA,UAC5F;AAAA,QACF;AAGI,aAAA,mCAAS,oBAAmB,MAAM;AACpC,gBAAM,OAAOA;AACT,cAAA,KAAK,eAAe,OAAO;AAC7B,kBAAM,UAAU,KAAK,SAAS,CAAC,IAAI;AACnC,kBAAM,QAAQ,MAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS;AAExD,gBAAI,QAAQ,GAAG;AACN,qBAAA;AAAA,gBACL,MAAM;AAAA,gBACN,OAAO,IAAI;AAAA,kBACT,YAAY,KAAK,eAAe,UAAU,gBAAgB,aAAa,yBAAyB,KAAK;AAAA,gBAAA;AAAA,cAEzG;AAAA,YAAA;AAGF,gBAAI,UAAU,GAAG;AACX,kBAAA,KAAK,eAAe,SAAS;AACxB,uBAAA;AAAA,kBACL,MAAM;AAAA,kBACN,OAAO,IAAI;AAAA,oBACT;AAAA,kBAAA;AAAA,gBAEJ;AAAA,cAAA;AAEF,qBAAO,EAAE,MAAM,MAAa,OAAO,OAAU;AAAA,YAAA;AAG/C,kBAAM,SAAS,MAAM,QAAQ,OAAO,IAAI,QAAQ,CAAC,IAAI;AACrD,kBAAM,WAAW,KAAK;AAAA,cACpB;AAAA,cACA;AAAA,YACF;AACA,mBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,UAAA,OAC5C;AACC,kBAAA,UAAU,KAAK,SAAS,CAAC;AAC/B,kBAAM,WAAW,QAAQ;AAAA,cAAI,CAAC,WAC5B,KAAK,8BAA8B,QAAQ,OAAO;AAAA,YACpD;AACA,mBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,UAAA;AAAA,QACnD;AAIIC,cAAAA,WAAS,gBAAK,eAAL,mBAAiB,cAAjB,mBAA4B;AACrCC,cAAAA,kBAAiB,KAAK,aAAa;AAGzC,cAAMC,2BAA0B,KAAK;AAAA,UACnC,KAAK;AAAA,QACP;AAEI,YAAA,KAAK,eAAe,OAAO;AAC7B,gBAAM,aAAa,MAAM;AAAA,YACvBH;AAAAA,YACAC;AAAAA,YACAC;AAAAA,YACAC;AAAAA,YACA,KAAK;AAAA,UACP;AACI,cAAA,CAAC,WAAW,OAAO;AACrB,mBAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,UAAA;AAE9C,gBAAA,WAAW,WAAW,OACxB,KAAK,8BAA8B,WAAW,MAAM,OAAO,IAC3D;AACJ,iBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,QAAA,OAC5C;AACL,gBAAM,aAAa,MAAM;AAAA,YACvBH;AAAAA,YACAC;AAAAA,YACAC;AAAAA,YACAC;AAAAA,UACF;AACI,cAAA,CAAC,WAAW,OAAO;AACrB,mBAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,UAAA;AAE9C,gBAAA,WAAW,WAAW,KAAK;AAAA,YAAI,CAAC,WACpC,KAAK,8BAA8B,QAAQ,OAAO;AAAA,UACpD;AACA,iBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,QAAA;AAAA,MACnD;AAIF,UAAI,KAAK,aAAa;AACd,cAAA,SAAS,MAAM,KAAK,QAAQ;AAAA,UAChC,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,UAAU,WAAW;AAAA,UAC5D;AAAA,QACF;AAEA,cAAM,QAAQ,OAAO,WAAW,WAAW,OAAO,MAAM,IAAI;AAC5D,eAAO,EAAE,MAAM,OAAiB,OAAO,OAAU;AAAA,MAAA;AAG7C,YAAA,WAAW,MAAM,KAAK,QAAQ;AAAA,QAClC,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,GAAG,WAAW;AAAA,QACrD;AAAA,MACF;AAGI,WAAA,mCAAS,oBAAmB,MAAM;AACpC,cAAM,OAAO;AACT,YAAA,KAAK,eAAe,OAAO;AAC7B,gBAAM,UAAU,KAAK,SAAS,CAAC,IAAI;AACnC,gBAAM,QAAQ,MAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS;AAExD,cAAI,QAAQ,GAAG;AACN,mBAAA;AAAA,cACL,MAAM;AAAA,cACN,OAAO,IAAI;AAAA,gBACT,YAAY,KAAK,eAAe,UAAU,gBAAgB,aAAa,yBAAyB,KAAK;AAAA,cAAA;AAAA,YAEzG;AAAA,UAAA;AAGF,cAAI,UAAU,GAAG;AACX,gBAAA,KAAK,eAAe,SAAS;AACxB,qBAAA;AAAA,gBACL,MAAM;AAAA,gBACN,OAAO,IAAI;AAAA,kBACT;AAAA,gBAAA;AAAA,cAEJ;AAAA,YAAA;AAEF,mBAAO,EAAE,MAAM,MAAa,OAAO,OAAU;AAAA,UAAA;AAG/C,gBAAM,SAAS,MAAM,QAAQ,OAAO,IAAI,QAAQ,CAAC,IAAI;AACrD,gBAAM,WAAW,KAAK,8BAA8B,QAAQ,OAAO;AACnE,iBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,QAAA,OAC5C;AAEC,gBAAA,UAAU,KAAK,SAAS,CAAC;AAC/B,gBAAM,WAAW,QAAQ;AAAA,YAAI,CAAC,WAC5B,KAAK,8BAA8B,QAAQ,OAAO;AAAA,UACpD;AACA,iBAAO,EAAE,MAAM,UAAiB,OAAO,OAAU;AAAA,QAAA;AAAA,MACnD;AAII,YAAA,UAAS,gBAAK,eAAL,mBAAiB,cAAjB,mBAA4B;AACrC,YAAA,iBAAiB,KAAK,aAAa;AAGzC,YAAM,0BAA0B,KAAK;AAAA,QACnC,KAAK;AAAA,MACP;AAEI,UAAA,KAAK,eAAe,OAAO;AAC7B,cAAM,aAAa,MAAM;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK;AAAA,QACP;AACI,YAAA,CAAC,WAAW,OAAO;AACrB,iBAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,QAAA;AAE9C,cAAA,WAAW,WAAW,OACxB,KAAK,8BAA8B,WAAW,MAAM,OAAO,IAC3D;AACG,eAAA;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,QACT;AAAA,MAAA,OACK;AACL,cAAM,aAAa,MAAM;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACI,YAAA,CAAC,WAAW,OAAO;AACrB,iBAAO,EAAE,MAAM,QAAW,OAAO,WAAW,MAAM;AAAA,QAAA;AAE9C,cAAA,WAAW,WAAW,KAAK;AAAA,UAAI,CAAC,WACpC,KAAK,8BAA8B,QAAQ,OAAO;AAAA,QACpD;AACO,eAAA;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,QACT;AAAA,MAAA;AAAA,aAEK,OAAO;AACP,aAAA;AAAA,QACL,MAAM;AAAA,QACN,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,MACjE;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,iBAAyB;AAEvB,UAAM,4BAA4B,EAAE,GAAG,KAAK,aAAa;AACzD,WAAO,0BAA0B;AAIjC,QAAI,0BAA0B,QAAQ;AACpC,gCAA0B,SAAS,KAAK;AAAA,QACtC,0BAA0B;AAAA,MAC5B;AAAA,IAAA;AAGE,QAAA,cAAc,WAAW,yBAAyB;AAIlD,QAAA,KAAK,aAAa,QAAQ;AAC5B,oBAAc,YAAY;AAAA,QACxB;AAAA,QACA,CAAC,OAAO,gBAAgB;AACtB,iBAAO,WAAW,YAAY,QAAQ,QAAQ,GAAG,CAAC;AAAA,QAAA;AAAA,MAEtD;AAAA,IAAA;AAEF,UAAM,eAAe,KAAK,kBAAkB,KAAK,aAAa;AAC9D,QAAI,cAAc;AAChB,YAAM,YAAY,YAAY,SAAS,GAAG,IAAI,MAAM;AACpD,oBAAc,GAAG,WAAW,GAAG,SAAS,WAAW,YAAY;AAAA,IAAA;AAIjE,QACE,KAAK,cACL,KAAK,oBACL,KAAK,oBACL,KAAK,yBACL;AACI,UAAA;AACJ,UAAI,KAAK,sBAAsB;AAEtB,eAAA,IAAI,KAAK,uBAAuB,IAAI,KAAK,oBAAoB,KAAK,KAAK,gBAAgB,MAAM,KAAK,gBAAgB;AAAA,MAAA,OACpH;AAEE,eAAA,IAAI,KAAK,uBAAuB,KAAK,KAAK,gBAAgB,MAAM,KAAK,gBAAgB;AAAA,MAAA;AAG9F,aAAO,cAAc,GAAG,IAAI,GAAG,WAAW,KAAK;AAAA,IAAA;AAK/C,QAAA,KAAK,cACL,CAAC,KAAK,oBACN,KAAK,oBACL,KAAK,yBACL;AAEA,YAAM,OAAO,IAAI,KAAK,uBAAuB,IAAI,KAAK,gBAAgB;AAEtE,aAAO,cAAc,GAAG,IAAI,GAAG,WAAW,KAAK;AAAA,IAAA;AAIjD,WAAO,IAAI,KAAK,SAAS,GAAG,WAAW;AAAA,EAAA;AAAA,EAGzC,mBAAgE;AAE9D,UAAM,4BAA4B,EAAE,GAAG,KAAK,aAAa;AACzD,WAAO,0BAA0B;AAGjC,QAAI,0BAA0B,QAAQ;AACpC,gCAA0B,SAAS,KAAK;AAAA,QACtC,0BAA0B;AAAA,MAC5B;AAAA,IAAA;AAGE,QAAA,cAAc,WAAW,yBAAyB;AAGtD,UAAM,eAAe,KAAK,kBAAkB,KAAK,aAAa;AAC9D,QAAI,cAAc;AAChB,YAAM,YAAY,YAAY,SAAS,GAAG,IAAI,MAAM;AACpD,oBAAc,GAAG,WAAW,GAAG,SAAS,WAAW,YAAY;AAAA,IAAA;AAG7D,QAAA;AAGJ,QACE,KAAK,cACL,KAAK,oBACL,KAAK,oBACL,KAAK,yBACL;AACA,UAAI,KAAK,sBAAsB;AAE7B,cAAM,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,IAAI,KAAK,oBAAoB,KAAK,KAAK,gBAAgB,MAAM,KAAK,gBAAgB,GAAG,WAAW;AAAA,MAAA,OACtJ;AAEL,cAAM,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,KAAK,KAAK,gBAAgB,MAAM,KAAK,gBAAgB,GAAG,WAAW;AAAA,MAAA;AAAA,IAChI,WAEA,KAAK,cACL,CAAC,KAAK,oBACN,KAAK,oBACL,KAAK,yBACL;AAEM,YAAA,IAAI,KAAK,YAAY,IAAI,KAAK,uBAAuB,IAAI,KAAK,gBAAgB,GAAG,WAAW;AAAA,IAAA,WACzF,KAAK,aAAa;AAC3B,YAAM,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,UAAU,WAAW;AAAA,IAAA,OAC7D;AACL,YAAM,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,GAAG,WAAW;AAAA,IAAA;AAGtD,WAAA;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ExecutionContext, ExecutableBuilder, Result, ODataRecordMetadata, InferSchemaType } from '../types.js';
|
|
2
|
+
import { TableOccurrence } from './table-occurrence.js';
|
|
3
|
+
import { BaseTable } from './base-table.js';
|
|
4
|
+
import { QueryBuilder } from './query-builder.js';
|
|
5
|
+
import { FFetchOptions } from '@fetchkit/ffetch';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any> ? S : never : never;
|
|
8
|
+
type ExtractNavigationNames<O extends TableOccurrence<any, any, any, any> | undefined> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? keyof Nav : never : never;
|
|
9
|
+
type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
|
|
10
|
+
type FindNavigationTarget<O extends TableOccurrence<any, any, any, any> | undefined, Name extends string> = O extends TableOccurrence<any, any, infer Nav, any> ? Name extends keyof Nav ? ResolveNavigationItem<Nav[Name]> : never : never;
|
|
11
|
+
export declare class RecordBuilder<T extends Record<string, any>, IsSingleField extends boolean = false, FieldKey extends keyof T = keyof T, Occ extends TableOccurrence<any, any, any, any> | undefined = TableOccurrence<any, any, any, any> | undefined> implements ExecutableBuilder<IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata> {
|
|
12
|
+
private occurrence?;
|
|
13
|
+
private tableName;
|
|
14
|
+
private databaseName;
|
|
15
|
+
private context;
|
|
16
|
+
private recordId;
|
|
17
|
+
private operation?;
|
|
18
|
+
private operationParam?;
|
|
19
|
+
private isNavigateFromEntitySet?;
|
|
20
|
+
private navigateRelation?;
|
|
21
|
+
private navigateSourceTableName?;
|
|
22
|
+
constructor(config: {
|
|
23
|
+
occurrence?: Occ;
|
|
24
|
+
tableName: string;
|
|
25
|
+
databaseName: string;
|
|
26
|
+
context: ExecutionContext;
|
|
27
|
+
recordId: string | number;
|
|
28
|
+
});
|
|
29
|
+
getSingleField<K extends keyof T>(field: K): RecordBuilder<T, true, K, Occ>;
|
|
30
|
+
navigate<RelationName extends ExtractNavigationNames<Occ>>(relationName: RelationName): QueryBuilder<ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>> extends Record<string, z.ZodType> ? InferSchemaType<ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>>> : Record<string, any>>;
|
|
31
|
+
navigate(relationName: string): QueryBuilder<{
|
|
32
|
+
ROWID: number;
|
|
33
|
+
ROWMODID: number;
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
}>;
|
|
36
|
+
execute(options?: RequestInit & FFetchOptions): Promise<Result<IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata>>;
|
|
37
|
+
getRequestConfig(): {
|
|
38
|
+
method: string;
|
|
39
|
+
url: string;
|
|
40
|
+
body?: any;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { QueryBuilder } from "./query-builder.js";
|
|
5
|
+
import { validateSingleResponse } from "../validation.js";
|
|
6
|
+
class RecordBuilder {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
__publicField(this, "occurrence");
|
|
9
|
+
__publicField(this, "tableName");
|
|
10
|
+
__publicField(this, "databaseName");
|
|
11
|
+
__publicField(this, "context");
|
|
12
|
+
__publicField(this, "recordId");
|
|
13
|
+
__publicField(this, "operation");
|
|
14
|
+
__publicField(this, "operationParam");
|
|
15
|
+
__publicField(this, "isNavigateFromEntitySet");
|
|
16
|
+
__publicField(this, "navigateRelation");
|
|
17
|
+
__publicField(this, "navigateSourceTableName");
|
|
18
|
+
this.occurrence = config.occurrence;
|
|
19
|
+
this.tableName = config.tableName;
|
|
20
|
+
this.databaseName = config.databaseName;
|
|
21
|
+
this.context = config.context;
|
|
22
|
+
this.recordId = config.recordId;
|
|
23
|
+
}
|
|
24
|
+
getSingleField(field) {
|
|
25
|
+
const newBuilder = new RecordBuilder({
|
|
26
|
+
occurrence: this.occurrence,
|
|
27
|
+
tableName: this.tableName,
|
|
28
|
+
databaseName: this.databaseName,
|
|
29
|
+
context: this.context,
|
|
30
|
+
recordId: this.recordId
|
|
31
|
+
});
|
|
32
|
+
newBuilder.operation = "getSingleField";
|
|
33
|
+
newBuilder.operationParam = field.toString();
|
|
34
|
+
newBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;
|
|
35
|
+
newBuilder.navigateRelation = this.navigateRelation;
|
|
36
|
+
newBuilder.navigateSourceTableName = this.navigateSourceTableName;
|
|
37
|
+
return newBuilder;
|
|
38
|
+
}
|
|
39
|
+
// Implementation
|
|
40
|
+
navigate(relationName) {
|
|
41
|
+
var _a;
|
|
42
|
+
const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[relationName];
|
|
43
|
+
const builder = new QueryBuilder({
|
|
44
|
+
occurrence: targetOccurrence,
|
|
45
|
+
tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relationName,
|
|
46
|
+
databaseName: this.databaseName,
|
|
47
|
+
context: this.context
|
|
48
|
+
});
|
|
49
|
+
builder.isNavigate = true;
|
|
50
|
+
builder.navigateRecordId = this.recordId;
|
|
51
|
+
builder.navigateRelation = relationName;
|
|
52
|
+
if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
|
|
53
|
+
builder.navigateSourceTableName = this.navigateSourceTableName;
|
|
54
|
+
builder.navigateBaseRelation = this.navigateRelation;
|
|
55
|
+
} else {
|
|
56
|
+
builder.navigateSourceTableName = this.tableName;
|
|
57
|
+
}
|
|
58
|
+
return builder;
|
|
59
|
+
}
|
|
60
|
+
async execute(options) {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
try {
|
|
63
|
+
let url;
|
|
64
|
+
if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
|
|
65
|
+
url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;
|
|
66
|
+
} else {
|
|
67
|
+
url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;
|
|
68
|
+
}
|
|
69
|
+
if (this.operation === "getSingleField" && this.operationParam) {
|
|
70
|
+
url += `/${this.operationParam}`;
|
|
71
|
+
}
|
|
72
|
+
const response = await this.context._makeRequest(url, options);
|
|
73
|
+
if (this.operation === "getSingleField") {
|
|
74
|
+
const fieldResponse = response;
|
|
75
|
+
return { data: fieldResponse.value, error: void 0 };
|
|
76
|
+
}
|
|
77
|
+
const schema = (_b = (_a = this.occurrence) == null ? void 0 : _a.baseTable) == null ? void 0 : _b.schema;
|
|
78
|
+
const validation = await validateSingleResponse(
|
|
79
|
+
response,
|
|
80
|
+
schema,
|
|
81
|
+
void 0,
|
|
82
|
+
// No selected fields for record.get()
|
|
83
|
+
void 0,
|
|
84
|
+
// No expand configs
|
|
85
|
+
"exact"
|
|
86
|
+
// Expect exactly one record
|
|
87
|
+
);
|
|
88
|
+
if (!validation.valid) {
|
|
89
|
+
return { data: void 0, error: validation.error };
|
|
90
|
+
}
|
|
91
|
+
if (validation.data === null) {
|
|
92
|
+
return { data: null, error: void 0 };
|
|
93
|
+
}
|
|
94
|
+
return { data: validation.data, error: void 0 };
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
data: void 0,
|
|
98
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
getRequestConfig() {
|
|
103
|
+
let url;
|
|
104
|
+
if (this.isNavigateFromEntitySet && this.navigateSourceTableName && this.navigateRelation) {
|
|
105
|
+
url = `/${this.databaseName}/${this.navigateSourceTableName}/${this.navigateRelation}('${this.recordId}')`;
|
|
106
|
+
} else {
|
|
107
|
+
url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;
|
|
108
|
+
}
|
|
109
|
+
if (this.operation === "getSingleField" && this.operationParam) {
|
|
110
|
+
url += `/${this.operationParam}`;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
method: "GET",
|
|
114
|
+
url
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
RecordBuilder
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=record-builder.js.map
|
|
@@ -0,0 +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} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { validateSingleResponse } from \"../validation\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport { z } from \"zod/v4\";\n\n// Helper type to extract schema from a TableOccurrence\ntype ExtractSchemaFromOccurrence<O> =\n O extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<infer S, any>\n ? S\n : never\n : never;\n\n// Helper type to extract navigation relation names from an occurrence\ntype ExtractNavigationNames<\n O extends TableOccurrence<any, any, any, any> | undefined,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? keyof Nav\n : never\n : never;\n\n// Helper type to resolve a navigation item (handles both direct and lazy-loaded)\ntype ResolveNavigationItem<T> = T extends () => infer R ? R : T;\n\n// Helper type to find target occurrence by relation name\ntype FindNavigationTarget<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Name extends string,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Name extends keyof Nav\n ? ResolveNavigationItem<Nav[Name]>\n : never\n : never;\n\nexport class RecordBuilder<\n T extends Record<string, any>,\n IsSingleField extends boolean = false,\n FieldKey extends keyof T = keyof T,\n Occ extends TableOccurrence<any, any, any, any> | undefined =\n | TableOccurrence<any, any, any, any>\n | undefined,\n> implements\n ExecutableBuilder<\n IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata\n >\n{\n private occurrence?: Occ;\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private recordId: string | number;\n private operation?: \"getSingleField\" | \"navigate\";\n private operationParam?: string;\n private isNavigateFromEntitySet?: boolean;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n\n constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n recordId: string | number;\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 }\n\n getSingleField<K extends keyof T>(field: K): RecordBuilder<T, true, K, Occ> {\n const newBuilder = new RecordBuilder<T, true, K, Occ>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: this.recordId,\n });\n newBuilder.operation = \"getSingleField\";\n newBuilder.operationParam = field.toString();\n // Preserve navigation context\n newBuilder.isNavigateFromEntitySet = this.isNavigateFromEntitySet;\n newBuilder.navigateRelation = this.navigateRelation;\n newBuilder.navigateSourceTableName = this.navigateSourceTableName;\n return newBuilder;\n }\n\n // Overload for valid relation names - returns typed QueryBuilder\n navigate<RelationName extends ExtractNavigationNames<Occ>>(\n relationName: RelationName,\n ): QueryBuilder<\n ExtractSchemaFromOccurrence<\n FindNavigationTarget<Occ, RelationName>\n > extends Record<string, z.ZodType>\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 (builder as any).isNavigate = true;\n (builder as any).navigateRecordId = this.recordId;\n (builder as any).navigateRelation = relationName;\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 (builder as any).navigateSourceTableName = this.tableName;\n }\n\n return builder;\n }\n\n async execute(\n options?: RequestInit & FFetchOptions,\n ): Promise<\n Result<IsSingleField extends true ? T[FieldKey] : T & ODataRecordMetadata>\n > {\n try {\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')\n url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n url += `/${this.operationParam}`;\n }\n\n const response = await this.context._makeRequest(url, options);\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 // Get schema from occurrence if available\n const schema = this.occurrence?.baseTable?.schema;\n\n // Validate the single record response\n const validation = await validateSingleResponse<any>(\n response,\n schema,\n undefined, // No selected fields for record.get()\n undefined, // No expand configs\n \"exact\", // Expect exactly one record\n );\n\n if (!validation.valid) {\n return { data: undefined, error: validation.error };\n }\n\n // Handle null response\n if (validation.data === null) {\n return { data: null as any, error: undefined };\n }\n\n return { data: validation.data, error: undefined };\n } catch (error) {\n return {\n data: undefined,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\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 // Normal record: /tableName('recordId')\n url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;\n }\n\n if (this.operation === \"getSingleField\" && this.operationParam) {\n url += `/${this.operationParam}`;\n }\n\n return {\n method: \"GET\",\n url,\n };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseTable } from './base-table.js';
|
|
2
|
+
type ExtractSchema<BT> = BT extends BaseTable<infer S, any, any, any> ? S : never;
|
|
3
|
+
type ResolveNavigation<T> = {
|
|
4
|
+
[K in keyof T]: T[K] extends () => infer R ? R : T[K];
|
|
5
|
+
};
|
|
6
|
+
export declare class TableOccurrence<BT extends BaseTable<any, any, any, any> = any, Name extends string = string, Nav extends Record<string, TableOccurrence<any, any, any, any> | (() => TableOccurrence<any, any, any, any>)> = {}, DefSelect extends "all" | "schema" | readonly (keyof ExtractSchema<BT>)[] = "schema"> {
|
|
7
|
+
readonly name: Name;
|
|
8
|
+
readonly baseTable: BT;
|
|
9
|
+
private _navigationConfig;
|
|
10
|
+
readonly navigation: ResolveNavigation<Nav>;
|
|
11
|
+
readonly defaultSelect: DefSelect;
|
|
12
|
+
constructor(config: {
|
|
13
|
+
readonly name: Name;
|
|
14
|
+
readonly baseTable: BT;
|
|
15
|
+
readonly navigation?: Nav;
|
|
16
|
+
readonly defaultSelect?: DefSelect;
|
|
17
|
+
});
|
|
18
|
+
addNavigation<NewNav extends Record<string, TableOccurrence<any, any, any, any> | (() => TableOccurrence<any, any, any, any>)>>(nav: NewNav): TableOccurrence<BT, Name, Nav & NewNav, DefSelect>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createTableOccurrence<const Name extends string, BT extends BaseTable<any, any, any, any>, DefSelect extends "all" | "schema" | readonly (keyof ExtractSchema<BT>)[] = "schema">(config: {
|
|
21
|
+
name: Name;
|
|
22
|
+
baseTable: BT;
|
|
23
|
+
defaultSelect?: DefSelect;
|
|
24
|
+
}): TableOccurrence<BT, Name, {}, DefSelect>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
function createNavigationGetters(navConfig) {
|
|
5
|
+
const result = {};
|
|
6
|
+
for (const key in navConfig) {
|
|
7
|
+
Object.defineProperty(result, key, {
|
|
8
|
+
get() {
|
|
9
|
+
const navItem = navConfig[key];
|
|
10
|
+
return typeof navItem === "function" ? navItem() : navItem;
|
|
11
|
+
},
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
class TableOccurrence {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
__publicField(this, "name");
|
|
21
|
+
__publicField(this, "baseTable");
|
|
22
|
+
__publicField(this, "_navigationConfig");
|
|
23
|
+
__publicField(this, "navigation");
|
|
24
|
+
__publicField(this, "defaultSelect");
|
|
25
|
+
this.name = config.name;
|
|
26
|
+
this.baseTable = config.baseTable;
|
|
27
|
+
this._navigationConfig = config.navigation ?? {};
|
|
28
|
+
this.defaultSelect = config.defaultSelect ?? "schema";
|
|
29
|
+
this.navigation = createNavigationGetters(this._navigationConfig);
|
|
30
|
+
}
|
|
31
|
+
addNavigation(nav) {
|
|
32
|
+
return new TableOccurrence({
|
|
33
|
+
name: this.name,
|
|
34
|
+
baseTable: this.baseTable,
|
|
35
|
+
navigation: { ...this._navigationConfig, ...nav },
|
|
36
|
+
defaultSelect: this.defaultSelect
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function createTableOccurrence(config) {
|
|
41
|
+
return new TableOccurrence(config);
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
TableOccurrence,
|
|
45
|
+
createTableOccurrence
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=table-occurrence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-occurrence.js","sources":["../../../src/client/table-occurrence.ts"],"sourcesContent":["import { BaseTable } from \"./base-table\";\n\n// Helper type to extract schema from BaseTable\ntype ExtractSchema<BT> =\n BT extends BaseTable<infer S, any, any, any> ? S : never;\n\n// Helper type to resolve navigation functions to their return types\ntype ResolveNavigation<T> = {\n [K in keyof T]: T[K] extends () => infer R ? R : T[K];\n};\n\n// Helper to create a getter-based navigation object\nfunction createNavigationGetters<\n Nav extends Record<\n string,\n | TableOccurrence<any, any, any, any>\n | (() => TableOccurrence<any, any, any, any>)\n >,\n>(navConfig: Nav): ResolveNavigation<Nav> {\n const result: any = {};\n\n for (const key in navConfig) {\n Object.defineProperty(result, key, {\n get() {\n const navItem = navConfig[key];\n return typeof navItem === \"function\" ? navItem() : navItem;\n },\n enumerable: true,\n configurable: true,\n });\n }\n\n return result as ResolveNavigation<Nav>;\n}\n\nexport class TableOccurrence<\n BT extends BaseTable<any, any, any, any> = any,\n Name extends string = string,\n Nav extends Record<\n string,\n | TableOccurrence<any, any, any, any>\n | (() => TableOccurrence<any, any, any, any>)\n > = {},\n DefSelect extends\n | \"all\"\n | \"schema\"\n | readonly (keyof ExtractSchema<BT>)[] = \"schema\",\n> {\n public readonly name: Name;\n public readonly baseTable: BT;\n private _navigationConfig: Nav;\n public readonly navigation: ResolveNavigation<Nav>;\n public readonly defaultSelect: DefSelect;\n\n constructor(config: {\n readonly name: Name;\n readonly baseTable: BT;\n readonly navigation?: Nav;\n readonly defaultSelect?: DefSelect;\n }) {\n this.name = config.name;\n this.baseTable = config.baseTable;\n this._navigationConfig = (config.navigation ?? {}) as Nav;\n this.defaultSelect = (config.defaultSelect ?? \"schema\") as DefSelect;\n\n // Create navigation getters that lazily resolve functions\n this.navigation = createNavigationGetters(this._navigationConfig);\n }\n\n addNavigation<\n NewNav extends Record<\n string,\n | TableOccurrence<any, any, any, any>\n | (() => TableOccurrence<any, any, any, any>)\n >,\n >(nav: NewNav): TableOccurrence<BT, Name, Nav & NewNav, DefSelect> {\n return new TableOccurrence({\n name: this.name,\n baseTable: this.baseTable,\n navigation: { ...this._navigationConfig, ...nav } as Nav & NewNav,\n defaultSelect: this.defaultSelect,\n });\n }\n}\n\n// Helper function to create TableOccurrence with proper type inference\nexport function createTableOccurrence<\n const Name extends string,\n BT extends BaseTable<any, any, any, any>,\n DefSelect extends\n | \"all\"\n | \"schema\"\n | readonly (keyof ExtractSchema<BT>)[] = \"schema\",\n>(config: {\n name: Name;\n baseTable: BT;\n defaultSelect?: DefSelect;\n}): TableOccurrence<BT, Name, {}, DefSelect> {\n return new TableOccurrence(config);\n}\n"],"names":[],"mappings":";;;AAYA,SAAS,wBAMP,WAAwC;AACxC,QAAM,SAAc,CAAC;AAErB,aAAW,OAAO,WAAW;AACpB,WAAA,eAAe,QAAQ,KAAK;AAAA,MACjC,MAAM;AACE,cAAA,UAAU,UAAU,GAAG;AAC7B,eAAO,OAAO,YAAY,aAAa,QAAY,IAAA;AAAA,MACrD;AAAA,MACA,YAAY;AAAA,MACZ,cAAc;AAAA,IAAA,CACf;AAAA,EAAA;AAGI,SAAA;AACT;AAEO,MAAM,gBAYX;AAAA,EAOA,YAAY,QAKT;AAXa;AACA;AACR;AACQ;AACA;AAQd,SAAK,OAAO,OAAO;AACnB,SAAK,YAAY,OAAO;AACnB,SAAA,oBAAqB,OAAO,cAAc,CAAC;AAC3C,SAAA,gBAAiB,OAAO,iBAAiB;AAGzC,SAAA,aAAa,wBAAwB,KAAK,iBAAiB;AAAA,EAAA;AAAA,EAGlE,cAME,KAAiE;AACjE,WAAO,IAAI,gBAAgB;AAAA,MACzB,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,YAAY,EAAE,GAAG,KAAK,mBAAmB,GAAG,IAAI;AAAA,MAChD,eAAe,KAAK;AAAA,IAAA,CACrB;AAAA,EAAA;AAEL;AAGO,SAAS,sBAOd,QAI2C;AACpC,SAAA,IAAI,gBAAgB,MAAM;AACnC;"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ExecutionContext, ExecutableBuilder, Result, WithSystemFields } from '../types.js';
|
|
2
|
+
import { TableOccurrence } from './table-occurrence.js';
|
|
3
|
+
import { BaseTable } from './base-table.js';
|
|
4
|
+
import { QueryBuilder } from './query-builder.js';
|
|
5
|
+
import { FFetchOptions } from '@fetchkit/ffetch';
|
|
6
|
+
/**
|
|
7
|
+
* Initial update builder returned from EntitySet.update(data)
|
|
8
|
+
* Requires calling .byId() or .where() before .execute() is available
|
|
9
|
+
*/
|
|
10
|
+
export declare class UpdateBuilder<T extends Record<string, any>, BT extends BaseTable<any, any, any, any>> {
|
|
11
|
+
private tableName;
|
|
12
|
+
private databaseName;
|
|
13
|
+
private context;
|
|
14
|
+
private occurrence?;
|
|
15
|
+
private data;
|
|
16
|
+
constructor(config: {
|
|
17
|
+
occurrence?: TableOccurrence<any, any, any, any>;
|
|
18
|
+
tableName: string;
|
|
19
|
+
databaseName: string;
|
|
20
|
+
context: ExecutionContext;
|
|
21
|
+
data: Partial<T>;
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Update a single record by ID
|
|
25
|
+
* Returns the count of updated records (0 or 1)
|
|
26
|
+
*/
|
|
27
|
+
byId(id: string | number): ExecutableUpdateBuilder<T, true>;
|
|
28
|
+
/**
|
|
29
|
+
* Update records matching a filter query
|
|
30
|
+
* Returns the count of updated records
|
|
31
|
+
* @param fn Callback that receives a QueryBuilder for building the filter
|
|
32
|
+
*/
|
|
33
|
+
where(fn: (q: QueryBuilder<WithSystemFields<T>>) => QueryBuilder<WithSystemFields<T>>): ExecutableUpdateBuilder<T, true>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Executable update builder - has execute() method
|
|
37
|
+
* Returned after calling .byId() or .where()
|
|
38
|
+
* Both modes return the count of updated records
|
|
39
|
+
*/
|
|
40
|
+
export declare class ExecutableUpdateBuilder<T extends Record<string, any>, IsByFilter extends boolean> implements ExecutableBuilder<{
|
|
41
|
+
updatedCount: number;
|
|
42
|
+
}> {
|
|
43
|
+
private tableName;
|
|
44
|
+
private databaseName;
|
|
45
|
+
private context;
|
|
46
|
+
private occurrence?;
|
|
47
|
+
private data;
|
|
48
|
+
private mode;
|
|
49
|
+
private recordId?;
|
|
50
|
+
private queryBuilder?;
|
|
51
|
+
constructor(config: {
|
|
52
|
+
occurrence?: TableOccurrence<any, any, any, any>;
|
|
53
|
+
tableName: string;
|
|
54
|
+
databaseName: string;
|
|
55
|
+
context: ExecutionContext;
|
|
56
|
+
data: Partial<T>;
|
|
57
|
+
mode: "byId" | "byFilter";
|
|
58
|
+
recordId?: string | number;
|
|
59
|
+
queryBuilder?: QueryBuilder<any>;
|
|
60
|
+
});
|
|
61
|
+
execute(options?: RequestInit & FFetchOptions): Promise<Result<{
|
|
62
|
+
updatedCount: number;
|
|
63
|
+
}>>;
|
|
64
|
+
getRequestConfig(): {
|
|
65
|
+
method: string;
|
|
66
|
+
url: string;
|
|
67
|
+
body?: any;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { QueryBuilder } from "./query-builder.js";
|
|
5
|
+
class UpdateBuilder {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
__publicField(this, "tableName");
|
|
8
|
+
__publicField(this, "databaseName");
|
|
9
|
+
__publicField(this, "context");
|
|
10
|
+
__publicField(this, "occurrence");
|
|
11
|
+
__publicField(this, "data");
|
|
12
|
+
this.occurrence = config.occurrence;
|
|
13
|
+
this.tableName = config.tableName;
|
|
14
|
+
this.databaseName = config.databaseName;
|
|
15
|
+
this.context = config.context;
|
|
16
|
+
this.data = config.data;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Update a single record by ID
|
|
20
|
+
* Returns the count of updated records (0 or 1)
|
|
21
|
+
*/
|
|
22
|
+
byId(id) {
|
|
23
|
+
return new ExecutableUpdateBuilder({
|
|
24
|
+
occurrence: this.occurrence,
|
|
25
|
+
tableName: this.tableName,
|
|
26
|
+
databaseName: this.databaseName,
|
|
27
|
+
context: this.context,
|
|
28
|
+
data: this.data,
|
|
29
|
+
mode: "byId",
|
|
30
|
+
recordId: id
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Update records matching a filter query
|
|
35
|
+
* Returns the count of updated records
|
|
36
|
+
* @param fn Callback that receives a QueryBuilder for building the filter
|
|
37
|
+
*/
|
|
38
|
+
where(fn) {
|
|
39
|
+
const queryBuilder = new QueryBuilder({
|
|
40
|
+
occurrence: void 0,
|
|
41
|
+
tableName: this.tableName,
|
|
42
|
+
databaseName: this.databaseName,
|
|
43
|
+
context: this.context
|
|
44
|
+
});
|
|
45
|
+
const configuredBuilder = fn(queryBuilder);
|
|
46
|
+
return new ExecutableUpdateBuilder({
|
|
47
|
+
occurrence: this.occurrence,
|
|
48
|
+
tableName: this.tableName,
|
|
49
|
+
databaseName: this.databaseName,
|
|
50
|
+
context: this.context,
|
|
51
|
+
data: this.data,
|
|
52
|
+
mode: "byFilter",
|
|
53
|
+
queryBuilder: configuredBuilder
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
class ExecutableUpdateBuilder {
|
|
58
|
+
constructor(config) {
|
|
59
|
+
__publicField(this, "tableName");
|
|
60
|
+
__publicField(this, "databaseName");
|
|
61
|
+
__publicField(this, "context");
|
|
62
|
+
__publicField(this, "occurrence");
|
|
63
|
+
__publicField(this, "data");
|
|
64
|
+
__publicField(this, "mode");
|
|
65
|
+
__publicField(this, "recordId");
|
|
66
|
+
__publicField(this, "queryBuilder");
|
|
67
|
+
this.occurrence = config.occurrence;
|
|
68
|
+
this.tableName = config.tableName;
|
|
69
|
+
this.databaseName = config.databaseName;
|
|
70
|
+
this.context = config.context;
|
|
71
|
+
this.data = config.data;
|
|
72
|
+
this.mode = config.mode;
|
|
73
|
+
this.recordId = config.recordId;
|
|
74
|
+
this.queryBuilder = config.queryBuilder;
|
|
75
|
+
}
|
|
76
|
+
async execute(options) {
|
|
77
|
+
try {
|
|
78
|
+
let url;
|
|
79
|
+
if (this.mode === "byId") {
|
|
80
|
+
url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;
|
|
81
|
+
} else {
|
|
82
|
+
if (!this.queryBuilder) {
|
|
83
|
+
throw new Error("Query builder is required for filter-based update");
|
|
84
|
+
}
|
|
85
|
+
const queryString = this.queryBuilder.getQueryString();
|
|
86
|
+
const queryParams = queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
|
|
87
|
+
url = `/${this.databaseName}/${this.tableName}${queryParams}`;
|
|
88
|
+
}
|
|
89
|
+
const response = await this.context._makeRequest(url, {
|
|
90
|
+
method: "PATCH",
|
|
91
|
+
headers: {
|
|
92
|
+
"Content-Type": "application/json"
|
|
93
|
+
},
|
|
94
|
+
body: JSON.stringify(this.data),
|
|
95
|
+
...options
|
|
96
|
+
});
|
|
97
|
+
let updatedCount = 0;
|
|
98
|
+
if (typeof response === "number") {
|
|
99
|
+
updatedCount = response;
|
|
100
|
+
} else if (response && typeof response === "object") {
|
|
101
|
+
updatedCount = response.updatedCount || 0;
|
|
102
|
+
}
|
|
103
|
+
return { data: { updatedCount }, error: void 0 };
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
data: void 0,
|
|
107
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getRequestConfig() {
|
|
112
|
+
let url;
|
|
113
|
+
if (this.mode === "byId") {
|
|
114
|
+
url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;
|
|
115
|
+
} else {
|
|
116
|
+
if (!this.queryBuilder) {
|
|
117
|
+
throw new Error("Query builder is required for filter-based update");
|
|
118
|
+
}
|
|
119
|
+
const queryString = this.queryBuilder.getQueryString();
|
|
120
|
+
const queryParams = queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
|
|
121
|
+
url = `/${this.databaseName}/${this.tableName}${queryParams}`;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
method: "PATCH",
|
|
125
|
+
url,
|
|
126
|
+
body: JSON.stringify(this.data)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
ExecutableUpdateBuilder,
|
|
132
|
+
UpdateBuilder
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=update-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-builder.js","sources":["../../../src/client/update-builder.ts"],"sourcesContent":["import type {\n ExecutionContext,\n ExecutableBuilder,\n Result,\n WithSystemFields,\n} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport type { BaseTable } from \"./base-table\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\n\n/**\n * Initial update builder returned from EntitySet.update(data)\n * Requires calling .byId() or .where() before .execute() is available\n */\nexport class UpdateBuilder<\n T extends Record<string, any>,\n BT extends BaseTable<any, any, any, any>,\n> {\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private data: Partial<T>;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n data: Partial<T>;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.data = config.data;\n }\n\n /**\n * Update a single record by ID\n * Returns the count of updated records (0 or 1)\n */\n byId(id: string | number): ExecutableUpdateBuilder<T, true> {\n return new ExecutableUpdateBuilder<T, true>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: this.data,\n mode: \"byId\",\n recordId: id,\n });\n }\n\n /**\n * Update records matching a filter query\n * Returns the count of updated records\n * @param fn Callback that receives a QueryBuilder for building the filter\n */\n where(\n fn: (\n q: QueryBuilder<WithSystemFields<T>>,\n ) => QueryBuilder<WithSystemFields<T>>,\n ): ExecutableUpdateBuilder<T, true> {\n // Create a QueryBuilder for the user to configure\n const queryBuilder = new QueryBuilder<\n WithSystemFields<T>,\n keyof WithSystemFields<T>,\n false,\n false,\n undefined\n >({\n occurrence: undefined,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Let the user configure it\n const configuredBuilder = fn(queryBuilder);\n\n return new ExecutableUpdateBuilder<T, true>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: this.data,\n mode: \"byFilter\",\n queryBuilder: configuredBuilder,\n });\n }\n}\n\n/**\n * Executable update builder - has execute() method\n * Returned after calling .byId() or .where()\n * Both modes return the count of updated records\n */\nexport class ExecutableUpdateBuilder<\n T extends Record<string, any>,\n IsByFilter extends boolean,\n> implements ExecutableBuilder<{ updatedCount: number }>\n{\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private data: Partial<T>;\n private mode: \"byId\" | \"byFilter\";\n private recordId?: string | number;\n private queryBuilder?: QueryBuilder<any>;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n data: Partial<T>;\n mode: \"byId\" | \"byFilter\";\n recordId?: string | number;\n queryBuilder?: QueryBuilder<any>;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.data = config.data;\n this.mode = config.mode;\n this.recordId = config.recordId;\n this.queryBuilder = config.queryBuilder;\n }\n\n async execute(\n options?: RequestInit & FFetchOptions,\n ): Promise<Result<{ updatedCount: number }>> {\n try {\n let url: string;\n\n if (this.mode === \"byId\") {\n // Update single record by ID: PATCH /{database}/{table}('id')\n url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;\n } else {\n // Update by filter: PATCH /{database}/{table}?$filter=...\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based update\");\n }\n\n // Get the query string from the configured QueryBuilder\n const queryString = this.queryBuilder.getQueryString();\n // Remove the leading \"/\" from the query string as we'll build our own URL\n const queryParams = queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${this.tableName}${queryParams}`;\n }\n\n // Make PATCH request with JSON body\n const response = await this.context._makeRequest(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(this.data),\n ...options,\n });\n\n // Both byId and byFilter return affected row count\n let updatedCount = 0;\n\n if (typeof response === \"number\") {\n updatedCount = response;\n } else if (response && typeof response === \"object\") {\n // Check if the response has a count property (fallback)\n updatedCount = (response as any).updatedCount || 0;\n }\n\n return { data: { updatedCount }, error: undefined };\n } catch (error) {\n return {\n data: undefined,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n let url: string;\n\n if (this.mode === \"byId\") {\n url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;\n } else {\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based update\");\n }\n\n const queryString = this.queryBuilder.getQueryString();\n const queryParams = queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${this.tableName}${queryParams}`;\n }\n\n return {\n method: \"PATCH\",\n url,\n body: JSON.stringify(this.data),\n };\n }\n}\n"],"names":[],"mappings":"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"}
|