import { Shape, ShapeType } from '../shapes/Shape.js'; import { TestNode } from '../utils/TraceShape.js'; import { PropertyShape } from '../shapes/SHACL.js'; import { ShapeSet } from '../collections/ShapeSet.js'; import { CoreSet } from '../collections/CoreSet.js'; import { LinkedComponent, LinkedSetComponent } from '../utils/LinkedComponent.js'; import { CoreMap } from '../collections/CoreMap.js'; import { NodeReferenceValue, Prettify, QueryFactory, ShapeReferenceValue } from './QueryFactory.js'; import { NamedNode } from '../models.js'; /** * ################################### * #### TYPES FOR QUERY BUILDING #### * ################################### */ export type JSPrimitive = JSNonNullPrimitive | null | undefined; export type JSNonNullPrimitive = string | number | boolean | Date; export type SingleResult = ResultType extends Array ? R : ResultType extends Set ? R : ResultType; /** * All the possible types that a regular get/set method of a Shape can return */ export type AccessorReturnValue = Shape | ShapeSet | JSPrimitive | TestNode; export type WhereClause = Evaluation | ((s: ToQueryBuilderObject) => Evaluation); export type QueryBuildFn = (p: ToQueryBuilderObject, q: SelectQueryFactory) => ResponseType; export type QueryWrapperObject = { [key: string]: SelectQueryFactory; }; export type CustomQueryObject = { [key: string]: QueryPath; }; export type SelectPath = QueryPath[] | CustomQueryObject; export type SortByPath = { paths: QueryPath[]; direction: 'ASC' | 'DESC'; }; /** * A LinkedQuery is used to build a query, when complete it can be turned into a LinkedQueryObject * that is used to send across the network as it can be serialized to JSON * @todo add | UpdateQuery and others */ export interface LinkedQuery { type: string; } export type SubQueryPaths = SelectPath; /** * A QueryPath is an array of QuerySteps, representing the path of properties that were requested to reach a certain value */ export type QueryPath = (QueryStep | SubQueryPaths)[] | WherePath; /** * A plain JS object that represents a LinkedQuery created by a Shape.select(...) call * It can be sent across the network. * @see LinkedQuery */ export interface SelectQuery extends LinkedQuery { select: SelectPath; where?: WherePath; sortBy?: SortByPath; subject?: S | QResult; limit?: number; offset?: number; shape?: ShapeType; singleResult?: boolean; } /** * Much like a querypath, except it can only contain QuerySteps */ export type QueryPropertyPath = QueryStep[]; /** * A QueryStep is a single step in a query path * It contains the property that was requested, and optionally a where clause */ export type QueryStep = PropertyQueryStep | SizeStep | CustomQueryObject | ShapeReferenceValue; export type SizeStep = { count: QueryPropertyPath; label?: string; }; export type PropertyQueryStep = { property: PropertyShape; where?: WherePath; }; export type WhereAndOr = { firstPath: WherePath; andOr: AndOrQueryToken[]; }; /** * A WhereQuery is a (sub)query that is used to filter down the results of its parent query * Hence it extends LinkedQuery and can do anything a normal query can */ export type AndOrQueryToken = { and?: WherePath; or?: WherePath; }; export declare enum WhereMethods { EQUALS = "=", SOME = "some", EVERY = "every" } /** * Maps all the return types of get/set methods of a Shape and maps their return types to QueryBuilderObjects */ export type QueryShapeProps = { [P in keyof T]: ToQueryBuilderObject, P>; }; /** * This type states that the ShapeSet has access to the same methods as the shape of all the items in the set * (this is enabled with the QueryShapeSet.proxifyShapeSet method) * Each value of the shape is converted to a QueryBuilderObject */ export type QueryShapeSetProps = { [P in keyof Shape]: ToQueryBuilderObject; }; /** * ShapeSets are converted to QueryShapeSets, but also inherit all the properties of the shape that each item in the set has (with converted result types) */ export type QShapeSet = QueryShapeSet & QueryShapeSetProps, ShapeSetType>; /** * Shapes are converted to QueryShapes, but also inherit all the properties of the shape (with converted result types) */ export type QShape = QueryShape & QueryShapeProps; export type ToQueryBuilderObject = T extends ShapeSet ? QShapeSet : T extends Shape ? QShape : T extends string | number | Date | boolean ? ToQueryPrimitive : T extends Array ? AT extends Date | string | number ? QueryPrimitiveSet> : AT extends boolean ? QueryBoolean : AT[] : T extends NamedNode ? QShape : QueryBuilderObject; export type ToQueryPrimitive = T extends string ? QueryString : T extends number ? QueryNumber : T extends Date ? QueryDate : T extends boolean ? QueryBoolean : never; export type WherePath = WhereEvaluationPath | WhereAndOr; export type WhereEvaluationPath = { path: QueryPropertyPath; method: WhereMethods; args: QueryArg[]; }; /** * An argument can be a direct reference to a node, a js primitive (boolean,number), a path to resolve (like from a query context variables) * Or a wherePath in the case of some() or every() (e.g. x.where(x.friends.some(f => f.age > 18) -> the argument is a wherePath) */ export type QueryArg = NodeReferenceValue | JSNonNullPrimitive | ArgPath | WherePath; export type ArgPath = { path: QueryPropertyPath; subject: ShapeReferenceValue; }; export type ComponentQueryPath = (QueryStep | SubQueryPaths)[] | WherePath; /** * ################################### * #### QUERY RESULT TYPES #### * ################################### */ export type NodeResultMap = CoreMap>; export type QResult = Object & { id: string; }; export type QueryProps> = Q extends SelectQueryFactory ? QueryResponseToResultType : never; export type QueryControllerProps = { query?: QueryController; }; export type QueryController = { nextPage: () => void; previousPage: () => void; setLimit: (limit: number) => void; setPage: (page: number) => void; }; export type PatchedQueryPromise = { where(validation: WhereClause): PatchedQueryPromise; limit(lim: number): PatchedQueryPromise; sortBy(sortParam: any, direction?: 'ASC' | 'DESC'): PatchedQueryPromise; one(): PatchedQueryPromise, ShapeType>; } & Promise; export type GetCustomObjectKeys = T extends QueryWrapperObject ? { [P in keyof T]: T[P] extends SelectQueryFactory ? ToQueryResultSet : never; } : []; export type QueryIndividualResultType> = T extends SelectQueryFactory ? QueryResponseToResultType : null; export type ToQueryResultSet = T extends SelectQueryFactory ? QueryResponseToResultType[] : null; /** * MAIN ENTRY to convert the response of a query into a result object */ export type QueryResponseToResultType = T extends QueryBuilderObject ? GetQueryObjectResultType : T extends SelectQueryFactory ? GetNestedQueryResultType : T extends Array ? UnionToIntersection> : T extends Evaluation ? boolean : T extends Object ? QResult>> : never; /** * Turns a QueryBuilderObject into a plain JS object * @param QV the query value type * @param SubProperties to add extra properties into the result object (used to merge arrays into objects for example) * @param SourceOverwrite if the source of the query value should be overwritten */ export type GetQueryObjectResultType = QV extends SetSize ? SetSizeToQueryResult : QV extends QueryPrimitive ? CreateQResult : QV extends QueryShape ? CreateQResult : QV extends BoundComponent ? GetQueryObjectResultType : QV extends QueryShapeSet ? CreateShapeSetQResult : QV extends QueryPrimitiveSet> ? GetQueryObjectResultType : QV extends Array ? UnionToIntersection> : QV extends QueryBoolean ? 'bool' : never; export type GetShapesResultTypeWithSource = QueryResponseToResultType; export type SetSizeToQueryResult = Source extends QueryShapeSet ? HasName extends false ? CreateQResult : number : number; /** * If the source is an object (it extends shape) * then the result is a plain JS Object, with Property as its key, with type Value */ export type CreateQResult = Source extends QueryShape ? ParentSource extends null ? HasName extends true ? Value : Value extends null ? QResult; } & SubProperties> : QResult; }> : CreateQResult; } & SubProperties>, SourceProperty, {}, HasName> : Source extends QueryShapeSet ? CreateQResult; }>[], SourceProperty, {}, HasName> : Value extends Shape ? QResult : NormaliseBoolean; type NormaliseBoolean = [T] extends [boolean] ? boolean : T; export type CreateShapeSetQResult = Source extends QueryShape ? [ HasName, ParentSource ] extends [true, null] ? CreateQResult[] : QResult[]; }> : Source extends QueryShapeSet ? CreateQResult[]; }>[], SourceProperty, {}, HasName> : CreateQResult; /** * Ignores the source and property, and returns the converted value */ export type ObjectToPlainResult = { [P in keyof T]: QueryResponseToResultType; }; export type GetSource = Overwrite extends null ? Source : Overwrite; type GetNestedQueryResultType = Source extends QueryBuilderObject ? GetQueryObjectResultType> : QueryResponseToResultType[]; type UnionToIntersection = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never; export type GetQueryResponseType = Q extends SelectQueryFactory ? ResponseType : Q; export type GetQueryShapeType = Q extends SelectQueryFactory ? ShapeType : never; export type QueryResponseToEndValues = T extends SetSize ? number[] : T extends SelectQueryFactory ? QueryResponseToEndValues[] : T extends QueryShapeSet ? ShapeSet : T extends QueryShape ? ShapeType : T extends QueryString ? string[] : T extends Array ? Array> : T extends Evaluation ? boolean[] : T; /** * ################################### * #### QUERY BUILDING CLASSES #### * ################################### */ export declare class QueryBuilderObject { property?: PropertyShape; subject?: QueryShape | QueryShapeSet | QueryPrimitiveSet; wherePath?: WherePath; protected originalValue?: OriginalValue; protected source: Source; protected prop: Property; constructor(property?: PropertyShape, subject?: QueryShape | QueryShapeSet | QueryPrimitiveSet); /** * Converts an original value into a query value * @param originalValue * @param requestedPropertyShape the property shape that is connected to the get accessor that returned the original value */ static convertOriginal(originalValue: AccessorReturnValue, property: PropertyShape, subject: QueryShape | QueryShapeSet | QueryShape): QueryBuilderObject; /** * Create a Query Builder Object based on the requested PropertyShape */ static generatePathValue(property: PropertyShape, subject: QueryShape | QueryShapeSet | QueryShape): QueryBuilderObject; static getOriginalSource(endValue: ShapeSet | Shape[] | QueryPrimitiveSet): ShapeSet; static getOriginalSource(endValue: Shape): Shape; static getOriginalSource(endValue: QueryString): Shape | string; static getOriginalSource(endValue: string[] | QueryBuilderObject): Shape | ShapeSet; getOriginalValue(): OriginalValue; getPropertyStep(): QueryStep; preloadFor(component: LinkedComponent | LinkedSetComponent): BoundComponent; limit(lim: number): void; /** * Returns the path of properties that were requested to reach this value */ getPropertyPath(currentPath?: QueryPropertyPath): QueryPropertyPath; } export declare class QueryShapeSet extends QueryBuilderObject, Source, Property> { queryShapes: CoreSet; private proxy; constructor(_originalValue?: ShapeSet, property?: PropertyShape, subject?: QueryShape | QueryShapeSet); static create(originalValue: ShapeSet, property: PropertyShape, subject: QueryShape | QueryShapeSet): any; static proxifyShapeSet(queryShapeSet: QueryShapeSet): any; as(shape: ShapeClass): QShapeSet, Source, Property>; add(item: any): void; concat(other: QueryShapeSet): QueryShapeSet; filter(filterFn: any): QueryShapeSet; setSource(val: boolean): void; getOriginalValue(): ShapeSet; callPropertyShapeAccessor(propertyShape: PropertyShape): QueryShapeSet | QueryPrimitiveSet; size(): SetSize; where(validation: WhereClause): this; select(subQueryFn: QueryBuildFn): SelectQueryFactory>; some(validation: WhereClause): SetEvaluation; every(validation: WhereClause): SetEvaluation; private someOrEvery; } export declare class QueryShape extends QueryBuilderObject { originalValue: S; isSource: boolean; private proxy; constructor(originalValue: S, property?: PropertyShape, subject?: QueryShape | QueryShapeSet); get id(): any; static create(original: Shape, property?: PropertyShape, subject?: QueryShape | QueryShapeSet): any; private static proxifyQueryShape; as(shape: ShapeClass): QShape, Source, Property>; equals(otherValue: NodeReferenceValue | QShape): Evaluation; select(subQueryFn: QueryBuildFn): SelectQueryFactory>; } export declare class BoundComponent extends QueryBuilderObject { originalValue: LinkedComponent | LinkedSetComponent; source: Source; constructor(originalValue: LinkedComponent | LinkedSetComponent, source: Source); getParentQueryFactory(): SelectQueryFactory; getPropertyPath(): QueryPropertyPath; } export declare class Evaluation { value: QueryBuilderObject | QueryPrimitiveSet; method: WhereMethods; args: QueryArg[]; private _andOr; constructor(value: QueryBuilderObject | QueryPrimitiveSet, method: WhereMethods, args: QueryArg[]); getPropertyPath(): WherePath; processArgs(): QueryArg[]; getWherePath(): WherePath; and(subQuery: WhereClause): this; or(subQuery: WhereClause): this; } declare class SetEvaluation extends Evaluation { } /** * The class that is used for when JS primitives are converted to a QueryValue * This is extended by QueryString, QueryNumber, QueryBoolean, etc */ export declare abstract class QueryPrimitive extends QueryBuilderObject { originalValue?: T; property?: PropertyShape; subject?: QueryShape | QueryShapeSet | QueryPrimitiveSet; constructor(originalValue?: T, property?: PropertyShape, subject?: QueryShape | QueryShapeSet | QueryPrimitiveSet); equals(otherValue: JSPrimitive | QueryBuilderObject): Evaluation; where(validation: WhereClause): this; } export declare class QueryString extends QueryPrimitive { } export declare class QueryDate extends QueryPrimitive { } export declare class QueryNumber extends QueryPrimitive { } export declare class QueryBoolean extends QueryPrimitive { } export declare class QueryPrimitiveSet = null> extends QueryBuilderObject { originalValue?: JSNonNullPrimitive[]; property?: PropertyShape; subject?: QueryShapeSet | QueryShape; contents: CoreSet; constructor(originalValue?: JSNonNullPrimitive[], property?: PropertyShape, subject?: QueryShapeSet | QueryShape, items?: any); add(item: any): void; values(): QPrimitive[]; createNew(...args: any[]): this; equals(other: any): Evaluation; getPropertyStep(): QueryStep; getPropertyPath(): QueryPropertyPath; size(): SetSize; } export declare var onQueriesReady: (callback: any) => void; export declare class SelectQueryFactory extends QueryFactory { shape: ShapeType; private queryBuildFn?; subject?: S | ShapeSet | QResult; /** * The returned value when the query was initially run. * Will likely be an array or object or query values that can be used to trace back which methods/accessors were used in the query. * @private */ traceResponse: ResponseType; sortResponse: any; sortDirection: string; parentQueryPath: QueryPath; singleResult: boolean; private limit; private offset; private wherePath; private initPromise; debugStack: string; constructor(shape: ShapeType, queryBuildFn?: QueryBuildFn, subject?: S | ShapeSet | QResult); setLimit(limit: number): void; getLimit(): number; setOffset(offset: number): void; getOffset(): number; setSubject(subject: any): this; where(validation: WhereClause): this; exec(): Promise[]>; /** * Turns the LinkedQuery into a SelectQuery, which is a plain JS object that can be serialized to JSON */ getQueryObject(): SelectQuery; getSubject(): { id: string; } | S | ShapeSet; /** * Returns an array of query paths * A single query can request multiple things in multiple "query paths" (For example this is using 2 paths: Shape.select(p => [p.name, p.friends.name])) * Each query path is returned as array of the property paths requested, with potential where clauses (together called a QueryStep) */ getQueryPaths(response?: ResponseType): CustomQueryObject | QueryPath[]; isValidSetResult(qResults: QResult[]): boolean; isValidResult(qResult: QResult): boolean; clone(): SelectQueryFactory; /** * Makes a clone of the query template, sets the subject and executes the query * @param subject */ execFor(subject: any): Promise[]>; patchResultPromise(p: Promise): PatchedQueryPromise; sortBy(sortFn: QueryBuildFn, direction: any): this; private init; private initialized; /** * Returns the dummy shape instance who's properties can be accessed freely inside a queryBuildFn * It is used to trace the properties that are accessed in the queryBuildFn * @private */ private getQueryShape; private getSortByPath; private isValidQueryPathsResult; private isValidQueryPathResult; private isValidQueryStepResult; private isValidCustomObjectResult; } export declare class SetSize extends QueryNumber { subject: QueryShapeSet | QueryShape | QueryPrimitiveSet; countable?: QueryBuilderObject; label?: string; constructor(subject: QueryShapeSet | QueryShape | QueryPrimitiveSet, countable?: QueryBuilderObject, label?: string); as(label: string): this; getPropertyPath(): QueryPropertyPath; } /** * A sub query that is used to filter results * i.e p.friends.where(f => //LinkedWhereQuery here) */ export declare class LinkedWhereQuery extends SelectQueryFactory { getResponse(): Evaluation; getWherePath(): WherePath; } export {};