Skip to content

Commit f3637d0

Browse files
committed
eng-1044: Experiment with slow vs fast local queries
1 parent d3ff3a8 commit f3637d0

File tree

1 file changed

+63
-4
lines changed

1 file changed

+63
-4
lines changed

apps/roam/src/utils/fireQuery.ts

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import predefinedSelections, {
1414
import { DEFAULT_RETURN_NODE } from "./parseQuery";
1515
import { DiscourseNode } from "./getDiscourseNodes";
1616
import { DiscourseRelation } from "./getDiscourseRelations";
17+
import type { json } from "./getBlockProps";
1718
import nanoid from "nanoid";
1819

1920
export type QueryArgs = {
@@ -315,6 +316,29 @@ export const fireQuerySync = (args: FireQueryArgs): QueryResult[] => {
315316
}));
316317
};
317318

319+
const PROP_NAME_RE = /:[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+\b/g;
320+
const PULL_RE = /\(pull [^)]+\)/g;
321+
322+
const renamePropsInResult = (
323+
result: json | null,
324+
mapping: Record<string, string>,
325+
): json | null => {
326+
const rename = (x: json | null): json | null => {
327+
if (Array.isArray(x)) return x.map(rename);
328+
if (x === null || x === undefined) return x;
329+
if (typeof x === "object") {
330+
return Object.fromEntries(
331+
Object.entries(x as object).map(([k, v]) => [
332+
mapping[k] || k,
333+
rename(v),
334+
]),
335+
);
336+
}
337+
return x;
338+
};
339+
return rename(result);
340+
};
341+
318342
const fireQuery: FireQuery = async (_args) => {
319343
const { isCustomEnabled, customNode, local, ...args } = _args;
320344

@@ -349,11 +373,46 @@ const fireQuery: FireQuery = async (_args) => {
349373
}
350374

351375
let queryResults: unknown[][] = [];
376+
// NOTE: The slow path (async.q with property remapping) is intentionally disabled
377+
// but preserved for potential future use pending comprehensive query testing.
378+
// We have seen some errors in (fast) backend queries, but not so far in local fast ones.
379+
const preferSlow = false;
352380
if (local) {
353-
queryResults = await window.roamAlphaAPI.data.async.fast.q(
354-
query,
355-
...inputs,
356-
);
381+
let useSlow = preferSlow;
382+
let propNamesSub: Record<string, string> | undefined;
383+
if (preferSlow) {
384+
// keeping this code in case it turns out the fast results are more fragile than the slow ones
385+
// TODO: Remove when we have a more comprehensive test suite.
386+
const pulls = [...query.matchAll(PULL_RE)].map((r) => r[0]);
387+
if (pulls.length > 0) {
388+
// pull in base async query (vs fast or backend) returns non-namespaced names,
389+
// so there are a few possibilities of conflict,
390+
// namely: {log,version,window}/id; {graph,user}/settings; {block,user}/uid; {create,edit}/time
391+
// So look for collisions in property names in pull part of query.
392+
const propNames = new Set(
393+
[...pulls.join(" ").matchAll(PROP_NAME_RE)].map((m) => m[0]),
394+
);
395+
propNamesSub = Object.fromEntries(
396+
[...propNames].map((n) => [n.split("/")[1], n]),
397+
);
398+
useSlow = Object.keys(propNamesSub).length === propNames.size;
399+
}
400+
}
401+
if (useSlow) {
402+
// no name conflict, safe to use async query
403+
// BUT it returns non-namespaced names, so substitute prop names back
404+
queryResults = await window.roamAlphaAPI.data.async.q(query, ...inputs);
405+
if (propNamesSub !== undefined)
406+
queryResults = renamePropsInResult(
407+
queryResults as json,
408+
propNamesSub,
409+
) as unknown[][];
410+
} else {
411+
queryResults = await window.roamAlphaAPI.data.async.fast.q(
412+
query,
413+
...inputs,
414+
);
415+
}
357416
} else {
358417
queryResults = await window.roamAlphaAPI.data.backend.q(query, ...inputs);
359418
}

0 commit comments

Comments
 (0)