Path: blob/master/src/packages/frontend/client/query.ts
1503 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { is_array } from "@cocalc/util/misc";6import { validate_client_query } from "@cocalc/util/schema-validate";7import { CB } from "@cocalc/util/types/database";8import { ConatChangefeed } from "@cocalc/sync/table/changefeed-conat";9import { uuid } from "@cocalc/util/misc";1011declare const $: any; // jQuery1213export class QueryClient {14private client: any;15private changefeeds: { [id: string]: ConatChangefeed } = {};1617constructor(client: any) {18this.client = client;19}2021// This works like a normal async function when22// opts.cb is NOT specified. When opts.cb is specified,23// it works like a cb and returns nothing. For changefeeds24// you MUST specify opts.cb, but can always optionally do so.25query = async (opts: {26query: object;27options?: object[]; // if given must be an array of objects, e.g., [{limit:5}]28changes?: boolean;29timeout?: number; // ms30cb?: CB; // support old cb interface31}): Promise<any> => {32// Deprecation warnings:33for (const field of ["standby", "no_post", "ignore_response"]) {34if (opts[field] != null) {35console.trace(`WARNING: passing '${field}' to query is deprecated`);36}37}38if (opts.options != null && !is_array(opts.options)) {39// should never happen...40throw Error("options must be an array");41}42if (opts.changes) {43const { cb } = opts;44if (cb == null) {45throw Error("for changefeed, must specify opts.cb");46}47let changefeed;48try {49changefeed = new ConatChangefeed({50account_id: this.client.account_id,51query: opts.query,52options: opts.options,53});54// id for canceling this changefeed55const id = uuid();56const initval = await changefeed.connect();57const query = {58[Object.keys(opts.query)[0]]: initval,59};60this.changefeeds[id] = changefeed;61cb(undefined, { query, id });62changefeed.on("update", (change) => {63cb(undefined, change);64});65} catch (err) {66cb(`${err}`);67return;68}69} else {70try {71const err = validate_client_query(opts.query, this.client.account_id);72if (err) {73throw Error(err);74}75const query = await this.client.conat_client.hub.db.userQuery({76query: opts.query,77options: opts.options,78timeout: opts.timeout,79});8081if (opts.cb == null) {82return { query };83} else {84opts.cb(undefined, { query });85}86} catch (err) {87if (opts.cb == null) {88throw err;89} else {90opts.cb(err);91}92}93}94};9596// cancel a changefeed created above. This is ONLY used97// right now by the CRM code.98cancel = async (id: string): Promise<void> => {99this.changefeeds[id]?.close();100delete this.changefeeds[id];101};102}103104105