UNPKG

@cocalc/database

Version:

CoCalc: code for working with our PostgreSQL database

91 lines (84 loc) 2.77 kB
import { OPERATORS, UserOrProjectQuery, isToOperand, SUPPORTED_TIME_UNITS, } from "@cocalc/util/schema"; import { quoteField } from "../postgres/schema/util"; import { is_object } from "@cocalc/util/misc"; export function queryIsCmp(val): false | string { if (!is_object(val)) { return false; } const keys = Object.keys(val); if (keys.length != 1) { return false; } if (OPERATORS.includes(keys[0] as any)) { return keys[0]; } return false; } // Additional where object condition imposed by user's get query export function userGetQueryFilter( user_query: object, client_query: UserOrProjectQuery<any> ): { [expr: string]: any } { if (client_query.get == null) { // no get queries allowed (this is mainly to make typescript happy below.) return {}; } // If the schema lists the value in a get query as 'null', then we remove it; // nulls means it was only there to be used by the initial where filter // part of the query. for (const field in client_query.get.fields) { const val = client_query.get.fields[field]; if (val === "null") { delete user_query[field]; } } const where: { [expr: string]: any } = {}; for (const field in user_query) { const val = user_query[field]; if (val == null) continue; if ( client_query.get.remove_from_query != null && client_query.get.remove_from_query.includes(field) ) { // do not include any field that explicitly excluded from the query continue; } if (!queryIsCmp(val)) { where[`${quoteField(field)} = $`] = val; continue; } // It's a comparison query, e.g., {field : {'<=' : 5}} for (let op in val) { const v = val[op]; if (op === "==") { // not in SQL, but natural for our clients to use it op = "="; } if (op.toLowerCase().startsWith("is")) { // hack to use same where format for now, since $ replacement // doesn't work for "foo IS ...". where[`${quoteField(field)} ${op} ${isToOperand(v)}`] = true; } else if ( is_object(v) && v["relative_time"] != null && SUPPORTED_TIME_UNITS.includes(v["unit"]) ) { const time = parseInt(v["relative_time"]); // ${v["unit"]} is safe because we checked that it is in SUPPORTED_TIME_UNITS above. // Also see https://stackoverflow.com/questions/7796657/using-a-variable-period-in-an-interval-in-postgres // for how we do this "interval" arithmetic. const int = `NOW() + $ * INTERVAL '1 ${v["unit"]}'`; const expr = `${quoteField(field)} ${op} (${int})`; where[expr] = time; } else { where[`${quoteField(field)} ${op} $`] = v; } } } return where; }