opusdev/vector-similarity-api
1
1import { MongoInvalidArgumentError } from './error';2 3/** @public */4export type SortDirection =5 | 16 | -17 | 'asc'8 | 'desc'9 | 'ascending'10 | 'descending'11 | { readonly $meta: string };12 13/** @public */14export type Sort =15 | string16 | Exclude<SortDirection, { readonly $meta: string }>17 | ReadonlyArray<string>18 | { readonly [key: string]: SortDirection }19 | ReadonlyMap<string, SortDirection>20 | ReadonlyArray<readonly [string, SortDirection]>21 | readonly [string, SortDirection];22 23/** Below stricter types were created for sort that correspond with type that the cmd takes */24 25/** @public */26export type SortDirectionForCmd = 1 | -1 | { $meta: string };27 28/** @public */29export type SortForCmd = Map<string, SortDirectionForCmd>;30 31/** @internal */32type SortPairForCmd = [string, SortDirectionForCmd];33 34/** @internal */35function prepareDirection(direction: any = 1): SortDirectionForCmd {36 const value = `${direction}`.toLowerCase();37 if (isMeta(direction)) return direction;38 switch (value) {39 case 'ascending':40 case 'asc':41 case '1':42 return 1;43 case 'descending':44 case 'desc':45 case '-1':46 return -1;47 default:48 throw new MongoInvalidArgumentError(`Invalid sort direction: ${JSON.stringify(direction)}`);49 }50}51 52/** @internal */53function isMeta(t: SortDirection): t is { $meta: string } {54 return typeof t === 'object' && t != null && '$meta' in t && typeof t.$meta === 'string';55}56 57/** @internal */58function isPair(t: Sort): t is readonly [string, SortDirection] {59 if (Array.isArray(t) && t.length === 2) {60 try {61 prepareDirection(t[1]);62 return true;63 } catch {64 return false;65 }66 }67 return false;68}69 70function isDeep(t: Sort): t is ReadonlyArray<readonly [string, SortDirection]> {71 return Array.isArray(t) && Array.isArray(t[0]);72}73 74function isMap(t: Sort): t is ReadonlyMap<string, SortDirection> {75 return t instanceof Map && t.size > 0;76}77 78function isReadonlyArray<T>(value: any): value is readonly T[] {79 return Array.isArray(value);80}81 82/** @internal */83function pairToMap(v: readonly [string, SortDirection]): SortForCmd {84 return new Map([[`${v[0]}`, prepareDirection([v[1]])]]);85}86 87/** @internal */88function deepToMap(t: ReadonlyArray<readonly [string, SortDirection]>): SortForCmd {89 const sortEntries: SortPairForCmd[] = t.map(([k, v]) => [`${k}`, prepareDirection(v)]);90 return new Map(sortEntries);91}92 93/** @internal */94function stringsToMap(t: ReadonlyArray<string>): SortForCmd {95 const sortEntries: SortPairForCmd[] = t.map(key => [`${key}`, 1]);96 return new Map(sortEntries);97}98 99/** @internal */100function objectToMap(t: { readonly [key: string]: SortDirection }): SortForCmd {101 const sortEntries: SortPairForCmd[] = Object.entries(t).map(([k, v]) => [102 `${k}`,103 prepareDirection(v)104 ]);105 return new Map(sortEntries);106}107 108/** @internal */109function mapToMap(t: ReadonlyMap<string, SortDirection>): SortForCmd {110 const sortEntries: SortPairForCmd[] = Array.from(t).map(([k, v]) => [111 `${k}`,112 prepareDirection(v)113 ]);114 return new Map(sortEntries);115}116 117/** converts a Sort type into a type that is valid for the server (SortForCmd) */118export function formatSort(119 sort: Sort | undefined,120 direction?: SortDirection121): SortForCmd | undefined {122 if (sort == null) return undefined;123 124 if (typeof sort === 'string') return new Map([[sort, prepareDirection(direction)]]); // 'fieldName'125 126 if (typeof sort !== 'object') {127 throw new MongoInvalidArgumentError(128 `Invalid sort format: ${JSON.stringify(sort)} Sort must be a valid object`129 );130 }131 132 if (!isReadonlyArray(sort)) {133 if (isMap(sort)) return mapToMap(sort); // Map<fieldName, SortDirection>134 if (Object.keys(sort).length) return objectToMap(sort); // { [fieldName: string]: SortDirection }135 return undefined;136 }137 if (!sort.length) return undefined;138 if (isDeep(sort)) return deepToMap(sort); // [ [fieldName, sortDir], [fieldName, sortDir] ... ]139 if (isPair(sort)) return pairToMap(sort); // [ fieldName, sortDir ]140 return stringsToMap(sort); // [ fieldName, fieldName ]141}142 