UNPKG

@proofkit/fmodata

Version:

FileMaker OData API client

143 lines (142 loc) 10.6 kB
import { Column } from '../orm/column.js'; import { ExtractTableName, FMTable, InferSchemaOutputFromFMTable, ValidExpandTarget } from '../orm/table.js'; import { FMODataLayer } from '../services.js'; import { ConditionallyWithODataAnnotations, ConditionallyWithSpecialColumns, ExecutableBuilder, ExecuteMethodOptions, ExecuteOptions, NormalizeIncludeSpecialColumns, Result } from '../types.js'; import { ExpandedRelations } from './builders/index.js'; import { RecordLocator } from './builders/mutation-helpers.js'; import { ResolveExpandedRelations, SystemColumnsFromOption, SystemColumnsOption } from './query/types.js'; import { QueryBuilder } from './query-builder.js'; /** * Extract the value type from a Column. * This uses the phantom type stored in Column to get the actual value type. */ type ExtractColumnType<C> = C extends Column<infer T, any> ? T : never; /** * Map a select object to its return type. * For each key in the select object, extract the type from the corresponding Column. */ type MapSelectToReturnType<TSelect extends Record<string, Column<any, any, any, any>>, _TSchema extends Record<string, any>> = { [K in keyof TSelect]: ExtractColumnType<TSelect[K]>; }; export type RecordReturnType<Schema extends Record<string, any>, IsSingleField extends boolean, FieldColumn extends Column<any, any, any, any> | undefined, Selected extends keyof Schema | Record<string, Column<any, any, ExtractTableName<FMTable<any, any>>>>, Expands extends ExpandedRelations, SystemCols extends SystemColumnsOption | undefined = undefined> = IsSingleField extends true ? FieldColumn extends Column<infer TOutput, any, any, any> ? TOutput : never : [ Selected ] extends [Record<string, Column<any, any, any, any>>] ? MapSelectToReturnType<Selected, Schema> & ResolveExpandedRelations<Expands> & SystemColumnsFromOption<SystemCols> : [ Selected ] extends [keyof Schema] ? Pick<Schema, Selected> & ResolveExpandedRelations<Expands> & SystemColumnsFromOption<SystemCols> : never; type RecordBuilderHasSelect<Occ extends FMTable<any, any>, IsSingleField extends boolean, Selected> = IsSingleField extends true ? false : Selected extends Record<string, Column<any, any, any>> ? true : Selected extends keyof InferSchemaOutputFromFMTable<NonNullable<Occ>> ? false : true; type ExecutableRecordBuilderReturn<Occ extends FMTable<any, any>, IsSingleField extends boolean, FieldColumn extends Column<any, any, any, any> | undefined, Selected extends keyof InferSchemaOutputFromFMTable<NonNullable<Occ>> | Record<string, Column<any, any, ExtractTableName<NonNullable<Occ>>>>, Expands extends ExpandedRelations, SystemCols extends SystemColumnsOption | undefined> = ConditionallyWithODataAnnotations<ConditionallyWithSpecialColumns<RecordReturnType<InferSchemaOutputFromFMTable<NonNullable<Occ>>, IsSingleField, FieldColumn, Selected, Expands, SystemCols>, true, RecordBuilderHasSelect<Occ, IsSingleField, Selected>>, true> | ConditionallyWithODataAnnotations<ConditionallyWithSpecialColumns<RecordReturnType<InferSchemaOutputFromFMTable<NonNullable<Occ>>, IsSingleField, FieldColumn, Selected, Expands, SystemCols>, true, RecordBuilderHasSelect<Occ, IsSingleField, Selected>>, false> | ConditionallyWithODataAnnotations<ConditionallyWithSpecialColumns<RecordReturnType<InferSchemaOutputFromFMTable<NonNullable<Occ>>, IsSingleField, FieldColumn, Selected, Expands, SystemCols>, false, RecordBuilderHasSelect<Occ, IsSingleField, Selected>>, true> | ConditionallyWithODataAnnotations<ConditionallyWithSpecialColumns<RecordReturnType<InferSchemaOutputFromFMTable<NonNullable<Occ>>, IsSingleField, FieldColumn, Selected, Expands, SystemCols>, false, RecordBuilderHasSelect<Occ, IsSingleField, Selected>>, false>; export declare class RecordBuilder<Occ extends FMTable<any, any> = FMTable<any, any>, IsSingleField extends boolean = false, FieldColumn extends Column<any, any, any, any> | undefined = undefined, Selected extends keyof InferSchemaOutputFromFMTable<NonNullable<Occ>> | Record<string, Column<any, any, ExtractTableName<NonNullable<Occ>>>> = keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>, Expands extends ExpandedRelations = {}, DatabaseIncludeSpecialColumns extends boolean = false, SystemCols extends SystemColumnsOption | undefined = undefined> implements ExecutableBuilder<ExecutableRecordBuilderReturn<Occ, IsSingleField, FieldColumn, Selected, Expands, SystemCols>> { private readonly table; private readonly recordLocator; private readonly operation?; private readonly operationParam?; private readonly operationColumn?; private readonly isNavigateFromEntitySet?; private readonly navigateRelation?; private readonly navigateRelationEntityId?; private readonly navigateSourceTableName?; private readonly navigateSourceTableEntityId?; private readState; private readonly layer; private readonly config; private readonly logger; private get selectedFields(); private set selectedFields(value); private get expandConfigs(); private set expandConfigs(value); private get fieldMapping(); private set fieldMapping(value); private get systemColumns(); private set systemColumns(value); constructor(config: { occurrence: Occ; layer: FMODataLayer; recordLocator: RecordLocator; }); /** * Helper to merge database-level useEntityIds and includeSpecialColumns with per-request options */ private mergeExecuteOptions; /** * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name * @param useEntityIds - Optional override for entity ID usage */ private getTableId; /** * Creates a new RecordBuilder with modified configuration. * Used by select() to create new instances. */ private cloneWithChanges; getSingleField<TColumn extends Column<any, any, ExtractTableName<NonNullable<Occ>>, any>>(column: TColumn): RecordBuilder<Occ, true, TColumn, keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>, {}, DatabaseIncludeSpecialColumns>; /** * Select fields using column references, or pass "all" to clear any defaultSelect and fetch all fields. * Allows renaming fields by using different keys in the object. * Container fields cannot be selected and will cause a type error. * * @example * db.from(contacts).get("uuid").select({ * name: contacts.name, * userEmail: contacts.email // renamed! * }) * * @example * // Include system columns (ROWID, ROWMODID) when using select() * db.from(contacts).get("uuid").select( * { name: contacts.name }, * { ROWID: true, ROWMODID: true } * ) * * @example * // Override defaultSelect to fetch all fields * db.from(contacts).get("uuid").select("all") * * @param fields - Object mapping output keys to column references (container fields excluded), or "all" to select all fields * @param systemColumns - Optional object to request system columns (ROWID, ROWMODID) * @returns RecordBuilder with updated selected fields */ select(fields: "all"): RecordBuilder<Occ, false, FieldColumn, keyof InferSchemaOutputFromFMTable<NonNullable<Occ>>, Expands, DatabaseIncludeSpecialColumns, undefined>; select<TSelect extends Record<string, Column<any, any, ExtractTableName<Occ>, false>>, TSystemCols extends SystemColumnsOption = {}>(fields: TSelect, systemColumns?: TSystemCols): RecordBuilder<Occ, false, FieldColumn, TSelect, Expands, DatabaseIncludeSpecialColumns, TSystemCols>; /** * Expand a navigation property to include related records. * Supports nested select, filter, orderBy, and expand operations. * * @example * ```typescript * // Simple expand with FMTable object * const contact = await db.from(contacts).get("uuid").expand(users).execute(); * * // Expand with select * const contact = await db.from(contacts).get("uuid") * .expand(users, b => b.select({ username: users.username, email: users.email })) * .execute(); * ``` */ expand<TargetTable extends FMTable<any, any>, TSelected extends keyof InferSchemaOutputFromFMTable<TargetTable> | Record<string, Column<any, any, ExtractTableName<TargetTable>>> = keyof InferSchemaOutputFromFMTable<TargetTable>, TNestedExpands extends ExpandedRelations = {}>(targetTable: ValidExpandTarget<Occ, TargetTable>, callback?: (builder: QueryBuilder<TargetTable, keyof InferSchemaOutputFromFMTable<TargetTable>, false, false, {}, false>) => QueryBuilder<TargetTable, TSelected, any, any, TNestedExpands, any, any>): RecordBuilder<Occ, false, FieldColumn, Selected, Expands & { [K in ExtractTableName<TargetTable>]: { schema: InferSchemaOutputFromFMTable<TargetTable>; selected: TSelected; nested: TNestedExpands; }; }, DatabaseIncludeSpecialColumns, SystemCols>; navigate<TargetTable extends FMTable<any, any>>(targetTable: ValidExpandTarget<Occ, TargetTable>): QueryBuilder<TargetTable, keyof InferSchemaOutputFromFMTable<TargetTable>, false, false, {}, false, DatabaseIncludeSpecialColumns, undefined>; /** * Builds the complete query string including $select and $expand parameters. */ private buildQueryString; private buildRecordResourcePath; execute<EO extends ExecuteOptions>(options?: ExecuteMethodOptions<EO>): Promise<Result<ConditionallyWithODataAnnotations<ConditionallyWithSpecialColumns<RecordReturnType<InferSchemaOutputFromFMTable<NonNullable<Occ>>, IsSingleField, FieldColumn, Selected, Expands, SystemCols>, NormalizeIncludeSpecialColumns<EO["includeSpecialColumns"], DatabaseIncludeSpecialColumns>, IsSingleField extends true ? false : Selected extends Record<string, Column<any, any, any>> ? true : Selected extends keyof InferSchemaOutputFromFMTable<NonNullable<Occ>> ? false : true>, EO["includeODataAnnotations"] extends true ? true : false>>>; getRequestConfig(): { method: string; url: string; body?: any; }; /** * Returns the query string for this record builder (for testing purposes). */ getQueryString(options?: { useEntityIds?: boolean; }): string; toRequest(baseUrl: string, options?: ExecuteOptions): Request; processResponse(response: Response, options?: ExecuteOptions): Promise<Result<RecordReturnType<InferSchemaOutputFromFMTable<NonNullable<Occ>>, IsSingleField, FieldColumn, Selected, Expands, SystemCols>>>; } export {};