@proofkit/fmodata
Version:
FileMaker OData API client
143 lines (142 loc) • 10.6 kB
TypeScript
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 {};