UNPKG

@travetto/model-query

Version:

Datastore abstraction for advanced query support.

76 lines (70 loc) 2.65 kB
import { FieldConfig, Point } from '@travetto/schema'; import { Class, toConcrete } from '@travetto/runtime'; const st = (t: string | string[], isArr: boolean = false): Set<string> => new Set((Array.isArray(t) ? t : [t]).map(v => isArr ? `${v}[]` : v)); const basic = (types: Set<string>): Record<string, Set<string>> => ({ $ne: types, $eq: types, $exists: st('boolean') }); const scalar = (types: Set<string>): Record<string, Set<string>> => ({ $in: types, $nin: types }); const str = (): Record<string, Set<string>> => ({ $regex: st(['RegExp', 'string']) }); const comp = (types: Set<string>): Record<string, Set<string>> => ({ $lt: types, $lte: types, $gt: types, $gte: types }); const geo = (type: string): Record<string, Set<string>> => ({ $near: st(type), $maxDistance: st('number'), $unit: st('string'), $geoWithin: st(type, true), $geoIntersects: st(type, true) }); const PointImpl = toConcrete<Point>(); /** * Basic type support */ export class TypeUtil { /** * Mapping types to various operators */ static OPERATORS = { string: { ...basic(st('string')), ...scalar(st('string', true)), ...str() }, number: { ...basic(st('number')), ...scalar(st('number', true)), ...comp(st('number')) }, boolean: { ...basic(st('boolean')), ...scalar(st('boolean', true)) }, Date: { ...basic(st('Date')), ...scalar(st('Date', true)), ...comp(st(['string', 'Date'])) }, Point: { ...basic(st('Point')), ...geo('Point') } }; /** * Get declared type of a given field, only for primitive types */ static getDeclaredType(f: FieldConfig | Class): keyof typeof TypeUtil.OPERATORS | undefined { const type = 'type' in f ? f.type : f; switch (type) { case String: return 'string'; case Number: return 'number'; case Boolean: return 'boolean'; case Date: return 'Date'; case PointImpl: return 'Point'; default: { if ('type' in f && f.array) { return this.getDeclaredType(f.type); } } } } /** * Get the actual type of a given field, only for primitive types */ static getActualType(v: unknown): string { const type = typeof v; if (['string', 'number', 'boolean'].includes(type)) { return type; } else if (v instanceof RegExp) { return 'RegExp'; } else if (v instanceof Date) { return 'Date'; } else if (Array.isArray(v)) { const typeString: string = `${this.getActualType(v[0])}[]`; if (v.length === 2 && typeString === 'number[]') { return 'Point'; } else { return typeString; } } throw new Error(`Unknown type for ${v}`); } }