@proofkit/fmodata
Version:
FileMaker OData API client
116 lines (115 loc) • 7.4 kB
TypeScript
import { QueryOptions } from 'odata-query';
import { ExecutionContext, ExecutableBuilder, WithSystemFields, Result, InferSchemaType, ExecuteOptions, ConditionallyWithODataAnnotations, ExtractSchemaFromOccurrence } from '../types.js';
import { Filter } from '../filter-types.js';
import { TableOccurrence } from './table-occurrence.js';
import { BaseTable } from './base-table.js';
import { FFetchOptions } from '@fetchkit/ffetch';
import { StandardSchemaV1 } from '@standard-schema/spec';
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 & string : never : never;
type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
type FindNavigationTarget<O extends TableOccurrence<any, any, any, any> | undefined, Name extends string> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? Name extends keyof Nav ? ResolveNavigationItem<Nav[Name]> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any>;
type GetTargetSchemaType<O extends TableOccurrence<any, any, any, any> | undefined, Rel extends string> = [FindNavigationTarget<O, Rel>] extends [
TableOccurrence<infer BT, any, any, any>
] ? [BT] extends [BaseTable<infer S, any, any, any>] ? [S] extends [Record<string, StandardSchemaV1>] ? InferSchemaType<S> : Record<string, any> : Record<string, any> : Record<string, any>;
export type ExpandedRelations = Record<string, {
schema: any;
selected: any;
}>;
export type QueryReturnType<T extends Record<string, any>, Selected extends keyof T, SingleMode extends "exact" | "maybe" | false, IsCount extends boolean, Expands extends ExpandedRelations> = IsCount extends true ? number : SingleMode extends "exact" ? Pick<T, Selected> & {
[K in keyof Expands]: Pick<Expands[K]["schema"], Expands[K]["selected"]>[];
} : SingleMode extends "maybe" ? (Pick<T, Selected> & {
[K in keyof Expands]: Pick<Expands[K]["schema"], Expands[K]["selected"]>[];
}) | null : (Pick<T, Selected> & {
[K in keyof Expands]: Pick<Expands[K]["schema"], Expands[K]["selected"]>[];
})[];
export declare class QueryBuilder<T extends Record<string, any>, Selected extends keyof T = keyof T, SingleMode extends "exact" | "maybe" | false = false, IsCount extends boolean = false, Occ extends TableOccurrence<any, any, any, any> | undefined = undefined, Expands extends ExpandedRelations = {}> implements ExecutableBuilder<QueryReturnType<T, Selected, SingleMode, IsCount, Expands>> {
private queryOptions;
private expandConfigs;
private singleMode;
private isCountMode;
private occurrence?;
private tableName;
private databaseName;
private context;
private isNavigate?;
private navigateRecordId?;
private navigateRelation?;
private navigateSourceTableName?;
private navigateBaseRelation?;
private databaseUseEntityIds;
constructor(config: {
occurrence?: Occ;
tableName: string;
databaseName: string;
context: ExecutionContext;
databaseUseEntityIds?: boolean;
});
/**
* Helper to merge database-level useEntityIds with per-request options
*/
private mergeExecuteOptions;
/**
* Helper to conditionally strip OData annotations based on options
*/
private stripODataAnnotationsIfNeeded;
/**
* Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name
* @param useEntityIds - Optional override for entity ID usage
*/
private getTableId;
select<K extends keyof T>(...fields: K[]): QueryBuilder<T, K, SingleMode, IsCount, Occ, Expands>;
/**
* Transforms our filter format to odata-query's expected format
* - Arrays of operators are converted to AND conditions
* - Single operator objects pass through as-is
* - Shorthand values are handled by odata-query
*/
private transformFilter;
filter(filter: Filter<ExtractSchemaFromOccurrence<Occ>>): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands>;
orderBy(orderBy: QueryOptions<T>["orderBy"]): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands>;
top(count: number): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands>;
skip(count: number): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands>;
/**
* Formats select fields for use in query strings.
* - Transforms field names to FMFIDs if using entity IDs
* - Wraps "id" fields in double quotes
* - URL-encodes special characters but preserves spaces
*/
private formatSelectFields;
/**
* Builds expand validation configs from internal expand configurations.
* These are used to validate expanded navigation properties.
*/
private buildExpandValidationConfigs;
/**
* Builds OData expand query string from expand configurations.
* Handles nested expands recursively.
* Transforms relation names to FMTIDs if using entity IDs.
*/
private buildExpandString;
expand<Rel extends ExtractNavigationNames<Occ> | (string & {}), TargetOcc extends FindNavigationTarget<Occ, Rel> = FindNavigationTarget<Occ, Rel>, TargetSchema extends GetTargetSchemaType<Occ, Rel> = GetTargetSchemaType<Occ, Rel>, TargetSelected extends keyof TargetSchema = keyof TargetSchema>(relation: Rel, callback?: (builder: QueryBuilder<TargetSchema, keyof TargetSchema, false, false, TargetOcc extends TableOccurrence<any, any, any, any> ? TargetOcc : undefined>) => QueryBuilder<WithSystemFields<TargetSchema>, TargetSelected, any, any, any>): QueryBuilder<T, Selected, SingleMode, IsCount, Occ, Expands & {
[K in Rel]: {
schema: TargetSchema;
selected: TargetSelected;
};
}>;
single(): QueryBuilder<T, Selected, "exact", IsCount, Occ, Expands>;
maybeSingle(): QueryBuilder<T, Selected, "maybe", IsCount, Occ, Expands>;
count(): QueryBuilder<T, Selected, SingleMode, true, Occ, Expands>;
execute<EO extends ExecuteOptions>(options?: RequestInit & FFetchOptions & EO): Promise<Result<IsCount extends true ? number : SingleMode extends "exact" ? ConditionallyWithODataAnnotations<Pick<T, Selected> & {
[K in keyof Expands]: Pick<Expands[K]["schema"], Expands[K]["selected"]>[];
}, EO["includeODataAnnotations"] extends true ? true : false> : SingleMode extends "maybe" ? ConditionallyWithODataAnnotations<Pick<T, Selected> & {
[K in keyof Expands]: Pick<Expands[K]["schema"], Expands[K]["selected"]>[];
}, EO["includeODataAnnotations"] extends true ? true : false> | null : ConditionallyWithODataAnnotations<Pick<T, Selected> & {
[K in keyof Expands]: Pick<Expands[K]["schema"], Expands[K]["selected"]>[];
}, EO["includeODataAnnotations"] extends true ? true : false>[]>>;
getQueryString(): string;
getRequestConfig(): {
method: string;
url: string;
body?: any;
};
toRequest(baseUrl: string): Request;
processResponse(response: Response, options?: ExecuteOptions): Promise<Result<QueryReturnType<T, Selected, SingleMode, IsCount, Expands>>>;
}
export {};