src/utils/get-many-query-builder.ts
PromiseLike
Properties |
|
Methods |
Accessors |
constructor(result: DocumentWithId<T>[] | Promise<DocumentWithId[]>, queryCache: QueryCache<T>, queryKey: string)
|
||||||||||||
Defined in src/utils/get-many-query-builder.ts:19
|
||||||||||||
Parameters :
|
Private isResolved |
Type : boolean
|
Default value : false
|
Defined in src/utils/get-many-query-builder.ts:19
|
Private limitCount |
Type : number
|
Default value : Number.MAX_SAFE_INTEGER
|
Defined in src/utils/get-many-query-builder.ts:17
|
Private queryCache |
Type : QueryCache<T>
|
Defined in src/utils/get-many-query-builder.ts:9
|
Private queryKey |
Type : string
|
Defined in src/utils/get-many-query-builder.ts:11
|
Private result |
Type : DocumentWithId<T>[]
|
Default value : []
|
Defined in src/utils/get-many-query-builder.ts:5
|
Private Optional resultPromise |
Type : Promise<DocumentWithId[]>
|
Defined in src/utils/get-many-query-builder.ts:7
|
Private skipCount |
Type : number
|
Default value : 0
|
Defined in src/utils/get-many-query-builder.ts:15
|
Private sortConditions |
Type : Array<Record<T, "asc" | "desc">>
|
Default value : []
|
Defined in src/utils/get-many-query-builder.ts:13
|
Public catch | ||||||
catch(onrejected?: (reason?: any) => void)
|
||||||
Defined in src/utils/get-many-query-builder.ts:118
|
||||||
Type parameters :
|
||||||
Parameters :
Returns :
Promise<[] | TResult>
|
Public Async exec |
exec()
|
Defined in src/utils/get-many-query-builder.ts:63
|
Returns :
Promise<DocumentWithId[]>
|
Public finally | ||||||
finally(onfinally?: () => void)
|
||||||
Defined in src/utils/get-many-query-builder.ts:124
|
||||||
Parameters :
Returns :
Promise<DocumentWithId[]>
|
Public limit | ||||||
limit(limitCount: number)
|
||||||
Defined in src/utils/get-many-query-builder.ts:58
|
||||||
Parameters :
|
Private Async resolveResult |
resolveResult()
|
Defined in src/utils/get-many-query-builder.ts:37
|
Returns :
Promise<DocumentWithId[]>
|
Public skip | ||||||
skip(skipCount: number)
|
||||||
Defined in src/utils/get-many-query-builder.ts:53
|
||||||
Parameters :
|
Public sort | ||||||
sort(sortConditions?: Record
|
||||||
Defined in src/utils/get-many-query-builder.ts:45
|
||||||
Parameters :
|
Public then |
then(onfulfilled?: (value?: DocumentWithId
|
Defined in src/utils/get-many-query-builder.ts:111
|
Type parameters :
|
Returns :
Promise<TResult1 | TResult2>
|
undefined |
get()
|
Defined in src/utils/get-many-query-builder.ts:130
|
import { DocumentWithId } from '../types';
import { QueryCache } from './query-cache';
export class QueryBuilder<T> implements PromiseLike<DocumentWithId<T>[]> {
private result: DocumentWithId<T>[] = [];
private resultPromise?: Promise<DocumentWithId<T>[]>;
private queryCache: QueryCache<T>;
private queryKey: string;
private sortConditions: Array<Record<keyof T, 'asc' | 'desc'>> = [];
private skipCount: number = 0;
private limitCount: number = Number.MAX_SAFE_INTEGER;
private isResolved: boolean = false;
constructor(
result: DocumentWithId<T>[] | Promise<DocumentWithId<T>[]>,
queryCache: QueryCache<T>,
queryKey: string,
) {
if (result instanceof Promise) {
this.resultPromise = result;
} else {
this.result = result;
this.isResolved = true;
}
this.queryCache = queryCache;
this.queryKey = queryKey;
}
// Resolves the result if it's a promise, otherwise returns the result
private async resolveResult(): Promise<DocumentWithId<T>[]> {
if (!this.isResolved && this.resultPromise) {
this.result = await this.resultPromise;
this.isResolved = true;
}
return this.result;
}
public sort(sortConditions?: Record<keyof T, 'asc' | 'desc'> | Record<keyof T, 'asc' | 'desc'>[]): this {
if (sortConditions) {
// If sortConditions is an array, use it as is, otherwise wrap it in an array
this.sortConditions = Array.isArray(sortConditions) ? sortConditions : [sortConditions];
}
return this;
}
public skip(skipCount: number): this {
this.skipCount = skipCount;
return this;
}
public limit(limitCount: number): this {
this.limitCount = limitCount;
return this;
}
public async exec(): Promise<DocumentWithId<T>[]> {
const resolvedResult = await this.resolveResult();
// Apply sorting if needed
if (this.sortConditions.length > 0) {
resolvedResult.sort((a, b) => {
let comparisonResult = 0;
this.sortConditions.forEach((sortObj) => {
Object.entries(sortObj).forEach(([key, order]) => {
const typedKey = key as keyof T; // Ensure the key is treated as keyof T
const aValue = a[typedKey];
const bValue = b[typedKey];
// Skip undefined or null values
if (aValue === undefined || bValue === undefined || aValue === null || bValue === null) return;
if (aValue < bValue) {
comparisonResult = order === 'asc' ? -1 : 1;
return; // Exit inner loop after determining order
}
if (aValue > bValue) {
comparisonResult = order === 'asc' ? 1 : -1;
// Exit inner loop after determining order
}
});
// If a comparison has already been made, stop further comparisons
if (comparisonResult !== 0) {
// Exit outer loop if already determined
}
});
return comparisonResult;
});
}
// Apply pagination
const paginatedResult = resolvedResult.slice(this.skipCount, this.skipCount + this.limitCount);
// Cache the result only if it's different
if (JSON.stringify(this.result) !== JSON.stringify(paginatedResult)) {
this.queryCache.set(this.queryKey, paginatedResult);
}
return paginatedResult;
}
public then<TResult1 = DocumentWithId<T>[], TResult2 = never>(
onfulfilled?: (value: DocumentWithId<T>[]) => TResult1 | PromiseLike<TResult1>,
onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>,
): Promise<TResult1 | TResult2> {
return this.exec().then(onfulfilled, onrejected);
}
public catch<TResult = never>(
onrejected?: (reason: any) => TResult | PromiseLike<TResult>,
): Promise<DocumentWithId<T>[] | TResult> {
return this.exec().catch(onrejected);
}
public finally(onfinally?: () => void): Promise<DocumentWithId<T>[]> {
return this.exec().finally(onfinally);
}
// Mark the class as Promise-like for chaining purposes
// eslint-disable-next-line class-methods-use-this
get [Symbol.toStringTag](): string {
return 'Promise';
}
}
// Proxy to enable chaining and ensure correct promise-like behavior
export function createQueryBuilderProxy<T>(builder: QueryBuilder<T>): QueryBuilder<T> {
return new Proxy(builder, {
get(target, prop, receiver) {
const value = Reflect.get(target, prop, receiver);
if (typeof value === 'function') {
return (...args: any[]) => {
const result = value.apply(target, args);
return result instanceof QueryBuilder ? createQueryBuilderProxy(result) : result;
};
}
if (prop === 'then') {
return (...args: any[]) => builder.then(...args);
}
if (prop === 'catch') {
return (onrejected: (reason: any) => any) => builder.exec().catch(onrejected);
}
return builder.exec();
},
});
}