UNPKG

nukak-browser

Version:

flexible and efficient ORM, with declarative JSON syntax and smart type-safety

749 lines (733 loc) 25.6 kB
type Type<T> = new (...args: unknown[]) => T; type BooleanLike = boolean | 0 | 1; type MongoId = { toHexString: () => string; }; type Scalar = string | number | boolean | bigint | Date | RegExp | Buffer | MongoId; type ExpandScalar<T> = null | (T extends Date ? Date | string : T); type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: unknown[]) => infer U ? U : T extends Promise<infer U> ? U : T; type QueryOptions = { /** * use or omit `softDelete` attribute. */ softDelete?: boolean; /** * prefix the query with this. */ prefix?: string; /** * automatically infer the prefix for the query. */ autoPrefix?: boolean; }; /** * query selection as an array. */ type QuerySelectArray<E> = (Key<E> | QueryRaw)[]; /** * query selection as a map. */ type QuerySelectMap<E> = QuerySelectFieldMap<E> | QuerySelectRelationMap<E>; /** * query selection. */ type QuerySelect<E> = QuerySelectArray<E> | QuerySelectMap<E>; /** * query selection of fields as a map. */ type QuerySelectFieldMap<E> = { [K in FieldKey<E>]?: BooleanLike; }; /** * query conflict paths map. */ type QueryConflictPathsMap<E> = { [K in FieldKey<E>]?: true; }; /** * query conflict paths. */ type QueryConflictPaths<E> = QueryConflictPathsMap<E>; /** * query selection of relations as a map. */ type QuerySelectRelationMap<E> = { [K in RelationKey<E>]?: BooleanLike | Key<Unpacked<E[K]>>[] | QuerySelectRelationOptions<E[K]>; }; /** * options to select a relation. */ type QuerySelectRelationOptions<E> = (E extends unknown[] ? Query<Unpacked<E>> : QueryUnique<Unpacked<E>>) & { $required?: boolean; }; /** * options for full-text-search operator. */ type QueryTextSearchOptions<E> = { /** * text to search for. */ $value: string; /** * list of fields to search on. */ $fields?: FieldKey<E>[]; }; /** * comparison by fields. */ type QueryWhereFieldMap<E> = { [K in FieldKey<E>]?: QueryWhereFieldValue<E[K]>; }; /** * complex operators. */ type QueryWhereMap<E> = QueryWhereFieldMap<E> & QueryWhereRootOperator<E>; type QueryWhereRootOperator<E> = { /** * joins query clauses with a logical `AND`, returns records that match all the clauses. */ $and?: QueryWhereArray<E>; /** * joins query clauses with a logical `OR`, returns records that match any of the clauses. */ $or?: QueryWhereArray<E>; /** * joins query clauses with a logical `AND`, returns records that do not match all the clauses. */ $not?: QueryWhereArray<E>; /** * joins query clauses with a logical `OR`, returns records that do not match any of the clauses. */ $nor?: QueryWhereArray<E>; /** * whether the specified fields match against a full-text search of the given string. */ $text?: QueryTextSearchOptions<E>; /** * whether the record exists in the given sub-query. */ $exists?: QueryRaw; /** * whether the record does not exists in the given sub-query. */ $nexists?: QueryRaw; }; type QueryWhereFieldOperatorMap<T> = { /** * whether a value is equal to the given value. */ $eq?: ExpandScalar<T>; /** * whether a value is not equal to the given value. */ $ne?: ExpandScalar<T>; /** * negates the given comparison. */ $not?: QueryWhereFieldValue<T>; /** * whether a value is less than the given value. */ $lt?: ExpandScalar<T>; /** * whether a value is less than or equal to the given value. */ $lte?: ExpandScalar<T>; /** * whether a value is greater than the given value. */ $gt?: ExpandScalar<T>; /** * whether a value is greater than or equal to the given value. */ $gte?: ExpandScalar<T>; /** * whether a string begins with the given string (case sensitive). */ $startsWith?: string; /** * whether a string begins with the given string (case insensitive). */ $istartsWith?: string; /** * whether a string ends with the given string (case sensitive). */ $endsWith?: string; /** * whether a string ends with the given string (case insensitive). */ $iendsWith?: string; /** * whether a string is contained within the given string (case sensitive). */ $includes?: string; /** * whether a string is contained within the given string (case insensitive). */ $iincludes?: string; /** * whether a string fulfills the given pattern (case sensitive). */ $like?: string; /** * whether a string fulfills the given pattern (case insensitive). */ $ilike?: string; /** * whether a string matches the given regular expression. */ $regex?: string; /** * whether a value matches any of the given values. */ $in?: ExpandScalar<T>[]; /** * whether a value does not match any of the given values. */ $nin?: ExpandScalar<T>[]; }; /** * Value for a field comparison. */ type QueryWhereFieldValue<T> = T | T[] | QueryWhereFieldOperatorMap<T> | QueryRaw; /** * query single filter. */ type QueryWhereSingle<E> = IdValue<E> | IdValue<E>[] | QueryWhereMap<E> | QueryRaw; /** * query filter array. */ type QueryWhereArray<E> = QueryWhereSingle<E>[]; /** * query filter. */ type QueryWhere<E> = QueryWhereSingle<E> | QueryWhereArray<E>; /** * direction for the sort. */ type QuerySortDirection = -1 | 1 | 'asc' | 'desc'; /** * sort by tuples */ type QuerySortTuples<E> = [FieldKey<E>, QuerySortDirection][]; /** * sort by objects. */ type QuerySortObjects<E> = { field: FieldKey<E>; sort: QuerySortDirection; }[]; /** * sort by fields. */ type QuerySortFieldMap<E> = { [K in FieldKey<E>]?: QuerySortDirection; }; /** * sort by relations fields. */ type QuerySortRelationMap<E> = { [K in RelationKey<E>]?: QuerySortMap<Unpacked<E[K]>>; }; /** * sort by map. */ type QuerySortMap<E> = QuerySortFieldMap<E> | QuerySortRelationMap<E>; /** * sort options. */ type QuerySort<E> = QuerySortMap<E> | QuerySortTuples<E> | QuerySortObjects<E>; /** * pager options. */ type QueryPager = { /** * Index from where start the search */ $skip?: number; /** * Max number of records to retrieve */ $limit?: number; }; /** * search options. */ type QuerySearch<E> = { /** * filtering options. */ $where?: QueryWhere<E>; /** * sorting options. */ $sort?: QuerySort<E>; } & QueryPager; /** * query options. */ type Query<E> = { /** * selection options. */ $select?: QuerySelect<E>; } & QuerySearch<E>; /** * options to get a single record. */ type QueryOne<E> = Omit<Query<E>, '$limit'>; /** * options to get an unique record. */ type QueryUnique<E> = Pick<QueryOne<E>, '$select' | '$where'>; /** * options for the `raw` function. */ type QueryRawFnOptions = { /** * the current dialect. */ dialect?: QueryDialect; /** * the prefix. */ prefix?: string; /** * the escaped prefix. */ escapedPrefix?: string; /** * the query context. */ ctx?: QueryContext; }; /** * a `raw` function */ type QueryRawFn = (opts?: QueryRawFnOptions) => void | Scalar; declare class QueryRaw { readonly value: Scalar | QueryRawFn; readonly alias?: string; constructor(value: Scalar | QueryRawFn, alias?: string); } interface QueryContext { append(sql: string): this; addValue(value: unknown): this; pushValue(value: unknown): this; readonly sql: string; readonly values: unknown[]; } interface QueryDialect { /** * obtains the records matching the given search parameters. * @param ctx the query context * @param entity the target entity * @param q the criteria options * @param opts the query options */ find<E>(ctx: QueryContext, entity: Type<E>, q: Query<E>, opts?: QueryOptions): void; /** * counts the number of records matching the given search parameters. * @param ctx the query context * @param entity the target entity * @param q the criteria options * @param opts the query options */ count<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): void; /** * insert records. * @param ctx the query context * @param entity the target entity * @param payload the payload * @param opts the query options */ insert<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void; /** * update records. * @param ctx the query context * @param entity the target entity * @param q the criteria options * @param payload * @param opts the query options */ update<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, payload: E, opts?: QueryOptions): void; /** * upsert records. * @param ctx the query context * @param entity the target entity * @param conflictPaths the conflict paths * @param payload */ upsert<E>(ctx: QueryContext, entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E): void; /** * delete records. * @param ctx the query context * @param entity the target entity * @param q the criteria options * @param opts the query options */ delete<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): void; /** * escape an identifier. * @param val the value to be escaped * @param forbidQualified don't escape dots * @param addDot use a dot as suffix */ escapeId(val: string, forbidQualified?: boolean, addDot?: boolean): string; /** * escape a value. * @param val the value to escape */ escape(val: unknown): string; /** * add a value to the query. * @param values the values array * @param value the value to add */ addValue(values: unknown[], value: unknown): string; /** * create a new query context. */ createContext(): QueryContext; } /** * Allow to customize the name of the property that identifies an entity */ declare const idKey: unique symbol; /** * Infers the key names of an entity */ type Key<E> = keyof E & string; /** * Infers the field names of an entity */ type FieldKey<E> = { readonly [K in keyof E]: E[K] extends Scalar ? K : never; }[Key<E>]; /** * Infers the relation names of an entity */ type RelationKey<E> = { readonly [K in keyof E]: E[K] extends Scalar ? never : K; }[Key<E>]; /** * Infers the name of the key identifier on an entity */ type IdKey<E> = E extends { [idKey]?: infer K; } ? K & FieldKey<E> : E extends { _id?: unknown; } ? '_id' & FieldKey<E> : E extends { id?: unknown; } ? 'id' & FieldKey<E> : E extends { uuid?: unknown; } ? 'uuid' & FieldKey<E> : FieldKey<E>; /** * Infers the value of the key identifier on an entity */ type IdValue<E> = E[IdKey<E>]; /** * A `querier` allows to interact with the datasource to perform persistence operations on any entity. */ interface UniversalQuerier { /** * obtains the record with the given primary key. * @param entity the target entity * @param id the primary key value * @param q the additional criteria options * @return the record */ findOneById<E>(entity: Type<E>, id: IdValue<E>, q?: QueryOne<E>): Promise<unknown>; /** * obtains the first record matching the given search parameters. * @param entity the target entity * @param q the criteria options * @return the record */ findOne<E>(entity: Type<E>, q: QueryOne<E>): Promise<unknown>; /** * obtains the records matching the given search parameters. * @param entity the target entity * @param q the criteria options * @return the records */ findMany<E>(entity: Type<E>, q: Query<E>): Promise<unknown>; /** * obtains the records matching the given search parameters, * also counts the number of matches ignoring pagination. * @param entity the target entity * @param q the criteria options * @return the records and the count */ findManyAndCount<E>(entity: Type<E>, q: Query<E>): Promise<unknown>; /** * counts the number of records matching the given search parameters. * @param entity the target entity * @param q the search options * @return the count */ count<E>(entity: Type<E>, q: QuerySearch<E>): Promise<unknown>; /** * inserts a record. * @param entity the entity to persist on * @param payload the data to be persisted * @return the ID */ insertOne<E>(entity: Type<E>, payload: E): Promise<unknown>; /** * Inserts many records. * @param entity the entity to persist on * @param payload the data to be persisted * @return the IDs */ insertMany?<E>(entity: Type<E>, payload: E[]): Promise<unknown>; /** * updates a record partially. * @param entity the entity to persist on * @param id the primary key of the record to be updated * @param payload the data to be persisted * @return the number of affected records */ updateOneById<E>(entity: Type<E>, id: IdValue<E>, payload: E): Promise<unknown>; /** * updates many records partially. * @param entity the entity to persist on * @param q the criteria to look for the records * @param payload the data to be persisted * @return the number of affected records */ updateMany?<E>(entity: Type<E>, q: QuerySearch<E>, payload: E): Promise<unknown>; /** * Insert or update a record given a search criteria. * @param entity the entity to persist on * @param conflictPaths the keys to use for the unique search * @param payload the data to be persisted * @return void */ upsertOne?<E>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E): Promise<unknown>; /** * insert or update a record. * @param entity the entity to persist on * @param payload the data to be persisted * @return the ID */ saveOne<E>(entity: Type<E>, payload: E): Promise<unknown>; /** * Insert or update records. * @param entity the entity to persist on * @param payload the data to be persisted * @return the IDs */ saveMany?<E>(entity: Type<E>, payload: E[]): Promise<unknown>; /** * delete or SoftDelete a record. * @param entity the entity to persist on * @param id the primary key of the record * @return the number of affected records */ deleteOneById<E>(entity: Type<E>, id: IdValue<E>, opts?: QueryOptions): Promise<unknown>; /** * delete or SoftDelete records. * @param entity the entity to persist on * @param q the criteria to look for the records * @return the number of affected records */ deleteMany<E>(entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): Promise<unknown>; /** * get a repository for the given entity. * @param entity the entity to get the repository for * @return the repository */ getRepository<E>(entity: Type<E>): UniversalRepository<E>; } /** * A `repository` allows to interact with the datasource to perform persistence operations on a specific entity. */ type UniversalRepository<E> = { /** * the `entity` class to which this `repository` is linked to. */ readonly entity: Type<E>; /** * the `querier` instance to which this `repository` is linked to. */ readonly querier: UniversalQuerier; /** * obtains the record with the given primary key. * @param id the primary key value * @param q the criteria options */ findOneById(id: IdValue<E>, q?: QueryOne<E>): Promise<unknown>; /** * obtains the first record matching the given search parameters. * @param q the criteria options */ findOne(q: QueryOne<E>): Promise<unknown>; /** * obtains the records matching the given search parameters. * @param q the criteria options */ findMany(q: Query<E>): Promise<unknown>; /** * obtains the records matching the given search parameters, * also counts the number of matches ignoring pagination. * @param q the criteria options */ findManyAndCount(q: Query<E>): Promise<unknown>; /** * counts the number of records matching the given search parameters. * @param q the search options */ count(q: QuerySearch<E>): Promise<unknown>; /** * inserts a record. * @param payload the data to be persisted */ insertOne(payload: E): Promise<unknown>; /** * Inserts many records. * @param entity the entity to persist on * @param payload the data to be persisted */ insertMany?(payload: E[]): Promise<unknown>; /** * updates a record partially. * @param id the primary key of the record to be updated * @param payload the data to be persisted */ updateOneById(id: IdValue<E>, payload: E): Promise<unknown>; /** * updates many records partially. * @param qm the criteria to look for the records * @param payload the data to be persisted */ updateMany?(qm: QuerySearch<E>, payload: E): Promise<unknown>; /** * Insert or update a record given a search criteria. * @param conflictPaths the keys to use for the unique search. * @param payload the data to insert or update. */ upsertOne?(conflictPaths: QueryConflictPaths<E>, payload: E): Promise<unknown>; /** * Insert or update a record. * @param payload the data to be persisted */ saveOne(payload: E): Promise<unknown>; /** * insert or update records. * @param payload the data to be persisted */ saveMany?(payload: E[]): Promise<unknown>; /** * delete or SoftDelete a record. * @param id the primary key of the record */ deleteOneById(id: IdValue<E>, opts?: QueryOptions): Promise<unknown>; /** * delete or SoftDelete records. * @param qm the criteria to look for the records */ deleteMany(qm: QuerySearch<E>, opts?: QueryOptions): Promise<unknown>; }; type RequestSuccessResponse<E> = { data: E; count?: number; }; type RequestErrorResponse = { readonly error: { readonly message: string; readonly code: number; }; }; type RequestOptions = { silent?: boolean; }; type RequestFindOptions = RequestOptions & { count?: boolean; }; type RequestBaseNotification = { readonly opts?: RequestOptions; }; type RequestSuccessNotification = { readonly phase: 'start' | 'success' | 'complete'; } & RequestBaseNotification; type RequestErrorNotification = { readonly phase: 'error'; } & RequestErrorResponse & RequestBaseNotification; type RequestNotification = RequestSuccessNotification | RequestErrorNotification; type RequestCallback = (msg: RequestNotification) => any; interface ClientRepository<E> extends UniversalRepository<E> { findOneById(id: IdValue<E>, q?: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findOne(qm: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findMany(qm: Query<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E[]>>; findManyAndCount(qm: Query<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E[]>>; count(qm?: QuerySearch<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<number>>; insertOne(payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; saveOne(payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteOneById(id: IdValue<E>, opts?: QueryOptions & RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteMany(qm: QuerySearch<E>, opts?: QueryOptions & RequestOptions): Promise<RequestSuccessResponse<IdValue<E>[]>>; } interface ClientQuerier extends UniversalQuerier { findOneById<E>(entity: Type<E>, id: IdValue<E>, q?: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findOne<E>(entity: Type<E>, q: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findMany<E>(entity: Type<E>, q: Query<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E[]>>; findManyAndCount<E>(entity: Type<E>, q: Query<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E[]>>; count<E>(entity: Type<E>, q?: QuerySearch<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<number>>; insertOne<E>(entity: Type<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; updateOneById<E>(entity: Type<E>, id: IdValue<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; saveOne<E>(entity: Type<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteOneById<E>(entity: Type<E>, id: IdValue<E>, opts?: QueryOptions & RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteMany<E>(entity: Type<E>, qm: QuerySearch<E>, opts?: QueryOptions & RequestOptions): Promise<RequestSuccessResponse<IdValue<E>[]>>; getRepository<E>(entity: Type<E>): ClientRepository<E>; } type ClientQuerierPool = { getQuerier(): ClientQuerier; }; declare function notify(notification: RequestNotification): void; declare function on(cb: RequestCallback): () => void; declare function get<T>(url: string, opts?: RequestOptions): Promise<RequestSuccessResponse<T>>; declare function post<T>(url: string, payload: unknown, opts?: RequestOptions): Promise<RequestSuccessResponse<T>>; declare function patch<T>(url: string, payload: unknown, opts?: RequestOptions): Promise<RequestSuccessResponse<T>>; declare function put<T>(url: string, payload: unknown, opts?: RequestOptions): Promise<RequestSuccessResponse<T>>; declare function remove<T>(url: string, opts?: RequestOptions): Promise<RequestSuccessResponse<T>>; declare function setQuerierPool<T extends ClientQuerierPool>(pool: T): void; declare function getQuerierPool(): ClientQuerierPool; declare function getQuerier(): ClientQuerier; declare class GenericClientRepository<E> implements ClientRepository<E> { readonly entity: Type<E>; readonly querier: ClientQuerier; constructor(entity: Type<E>, querier: ClientQuerier); findOneById(id: IdValue<E>, q?: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findOne(q: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findMany(q: Query<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E[]>>; findManyAndCount(q: Query<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E[]>>; count(qm?: QuerySearch<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<number>>; insertOne(payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; updateOneById(id: IdValue<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; saveOne(payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteOneById(id: IdValue<E>, opts?: QueryOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteMany(qm: QuerySearch<E>, opts?: QueryOptions): Promise<RequestSuccessResponse<IdValue<E>[]>>; } declare class HttpQuerier implements ClientQuerier { readonly basePath: string; constructor(basePath: string); findOneById<E>(entity: Type<E>, id: IdValue<E>, q?: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findOne<E>(entity: Type<E>, q: QueryOne<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<E>>; findMany<E>(entity: Type<E>, q: Query<E>, opts?: RequestFindOptions): Promise<RequestSuccessResponse<E[]>>; findManyAndCount<E>(entity: Type<E>, q: Query<E>, opts?: RequestFindOptions): Promise<RequestSuccessResponse<E[]>>; count<E>(entity: Type<E>, q: QuerySearch<E>, opts?: RequestOptions): Promise<RequestSuccessResponse<number>>; insertOne<E>(entity: Type<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<any>>; updateOneById<E>(entity: Type<E>, id: IdValue<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; saveOne<E>(entity: Type<E>, payload: E, opts?: RequestOptions): Promise<RequestSuccessResponse<any>> | Promise<{ data: E[IdKey<E>]; }>; deleteOneById<E>(entity: Type<E>, id: IdValue<E>, opts?: QueryOptions & RequestOptions): Promise<RequestSuccessResponse<IdValue<E>>>; deleteMany<E>(entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions & RequestOptions): Promise<RequestSuccessResponse<IdValue<E>[]>>; getRepository<E>(entity: Type<E>): ClientRepository<E>; getBasePath<E>(entity: Type<E>): string; } declare function stringifyQueryParameter(key: string, value?: unknown, useQuestionMark?: boolean): string; declare function stringifyQuery(query: object): string; export { GenericClientRepository, HttpQuerier, get, getQuerier, getQuerierPool, notify, on, patch, post, put, remove, setQuerierPool, stringifyQuery, stringifyQueryParameter }; export type { ClientQuerier, ClientQuerierPool, ClientRepository, RequestCallback, RequestErrorResponse, RequestFindOptions, RequestNotification, RequestOptions, RequestSuccessResponse };