UNPKG

@naturalcycles/datastore-lib

Version:

Opinionated library to work with Google Datastore, implements CommonDB

68 lines (54 loc) 1.94 kB
import type { PropertyFilter, Query } from '@google-cloud/datastore' import type { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib' import type { ObjectWithId, StringMap } from '@naturalcycles/js-lib/types' const FNAME_MAP: StringMap = { id: '__key__', } const OP_MAP: Partial<Record<DBQueryFilterOperator, string>> = { '==': '=', in: 'IN', 'not-in': 'NOT_IN', } export function dbQueryToDatastoreQuery<ROW extends ObjectWithId>( dbQuery: Readonly<DBQuery<ROW>>, emptyQuery: Query, propertyFilterClass: typeof PropertyFilter, ): Query { let q = emptyQuery // filter for (const f of dbQuery._filters) { // keeping "previous syntax" commented out // (q, f) => q.filter(f.name as string, OP_MAP[f.op] || (f.op as any), f.val), // Datastore doesn't allow `undefined` as filter value. // We don't want to throw on it, so instead we'll replace it with valid value of `null`. // `a > null` will return anything that's indexed // `a < null` should return nothing // `a == null` will return just that - rows with null values let { op, val } = f if (val === undefined) val = null q = q.filter(new propertyFilterClass(f.name as string, OP_MAP[op] || (op as any), val)) } // limit q = q.limit(dbQuery._limitValue || 0) // order for (const ord of dbQuery._orders) { q = q.order(ord.name as string, { descending: ord.descending }) } // select if (dbQuery._selectedFieldNames) { const fields = (dbQuery._selectedFieldNames as string[]).map(f => FNAME_MAP[f] || f) // Datastore requires you to specify at least one column, so if empty array is passed - it'll include __key__ at least if (!fields.length) { fields.push('__key__') } q = q.select(fields) } // cursor if (dbQuery._startCursor) { q = q.start(dbQuery._startCursor) } if (dbQuery._endCursor) { q = q.end(dbQuery._endCursor) } return q }