From 343609d7ff12bc10cc459265d9614e87c3774674 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Sun, 9 Nov 2025 21:21:49 -0500 Subject: [PATCH 1/4] eng-1044: experiments wip --- apps/roam/src/utils/fireQuery.ts | 47 ++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/apps/roam/src/utils/fireQuery.ts b/apps/roam/src/utils/fireQuery.ts index d07f03cfa..bd1defae2 100644 --- a/apps/roam/src/utils/fireQuery.ts +++ b/apps/roam/src/utils/fireQuery.ts @@ -14,6 +14,7 @@ import predefinedSelections, { import { DEFAULT_RETURN_NODE } from "./parseQuery"; import { DiscourseNode } from "./getDiscourseNodes"; import { DiscourseRelation } from "./getDiscourseRelations"; +import type { json } from "./getBlockProps"; import nanoid from "nanoid"; export type QueryArgs = { @@ -30,6 +31,7 @@ type RelationInQuery = { export type FireQueryArgs = QueryArgs & { isCustomEnabled?: boolean; customNode?: string; + local?: boolean; context?: { relationsInQuery?: RelationInQuery[]; customNodes?: DiscourseNode[]; @@ -314,8 +316,10 @@ export const fireQuerySync = (args: FireQueryArgs): QueryResult[] => { })); }; +const PROP_NAME_RE = new RegExp(/\:\w+\/\w+\b/, "g"); + const fireQuery: FireQuery = async (_args) => { - const { isCustomEnabled, customNode, ...args } = _args; + const { isCustomEnabled, customNode, local, ...args } = _args; const { query, formatResult, inputs } = isCustomEnabled ? { @@ -347,11 +351,42 @@ const fireQuery: FireQuery = async (_args) => { console.groupEnd(); } - //@ts-ignore - todo add async q to roamjs-components - const queryResults = await window.roamAlphaAPI.data.backend.q( - query, - ...inputs, - ); + let queryResults: unknown[][] = []; + console.log("local", local); + if (local) { + // look for propNames in query. Could consider looking only in pull when that exists. + const propNames = new Set( + [...query.matchAll(PROP_NAME_RE)].map((m) => m[0]), + ); + const propNamesSub: Record = Object.fromEntries( + [...propNames].map((n) => [n.split("/")[1], n]), + ); + if (Object.keys(propNamesSub).length === propNames.size) { + // no name conflict, safe to use async query + // BUT it returns non-namespaced names, so substitute prop names back + queryResults = await window.roamAlphaAPI.data.async.q(query, ...inputs); + const renameProps = (x: json | null): json | null => { + if (Array.isArray(x)) return x.map(renameProps); + if (x === null || x === undefined) return x; + if (typeof x === "object") { + return Object.fromEntries( + Object.entries(x as object).map(([k, v]) => [ + propNamesSub[k] || k, + renameProps(v), // eslint-disable-line @typescript-eslint/no-unsafe-argument + ]), + ); + } + return x; + }; + queryResults = renameProps(queryResults as json) as unknown[][]; + } else { + // more janky but safer + queryResults = window.roamAlphaAPI.data.fast.q(query, ...inputs); + } + } else { + // eslint-disable-next-line @typescript-eslint/await-thenable + queryResults = await window.roamAlphaAPI.data.backend.q(query, ...inputs); // ts-ignore + } if (nodeEnv === "development") { console.timeEnd(`Query - ${queryId}`); From e52936078d8bcc9baa96b56fa846841aab0bc53b Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Wed, 10 Dec 2025 14:19:34 -0500 Subject: [PATCH 2/4] local migrations --- apps/roam/src/utils/fireQuery.ts | 1 - apps/roam/src/utils/getRelationData.ts | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/roam/src/utils/fireQuery.ts b/apps/roam/src/utils/fireQuery.ts index bd1defae2..b0c772c34 100644 --- a/apps/roam/src/utils/fireQuery.ts +++ b/apps/roam/src/utils/fireQuery.ts @@ -352,7 +352,6 @@ const fireQuery: FireQuery = async (_args) => { } let queryResults: unknown[][] = []; - console.log("local", local); if (local) { // look for propNames in query. Could consider looking only in pull when that exists. const propNames = new Set( diff --git a/apps/roam/src/utils/getRelationData.ts b/apps/roam/src/utils/getRelationData.ts index b1311d75d..a0b436c93 100644 --- a/apps/roam/src/utils/getRelationData.ts +++ b/apps/roam/src/utils/getRelationData.ts @@ -6,10 +6,15 @@ import internalError from "./internalError"; // lifted from getExportTypes -export const getRelationDataUtil = async ( - allRelations: DiscourseRelation[], - nodeLabelByType: Record, -) => +export const getRelationDataUtil = async ({ + allRelations, + nodeLabelByType, + local, +}: { + allRelations: DiscourseRelation[]; + nodeLabelByType: Record; + local?: boolean; +}) => Promise.all( allRelations .filter( @@ -24,6 +29,7 @@ export const getRelationDataUtil = async ( ? [] : fireQuery({ returnNode: sourceLabel, + local, conditions: [ { relation: s.label, @@ -60,13 +66,13 @@ export const getRelationDataUtil = async ( }), ).then((r) => r.flat()); -const getRelationData = async () => { +const getRelationData = async (local?: boolean) => { const allRelations = getDiscourseRelations(); const allNodes = getDiscourseNodes(allRelations); const nodeLabelByType = Object.fromEntries( allNodes.map((a) => [a.type, a.text]), ); - return await getRelationDataUtil(allRelations, nodeLabelByType); + return await getRelationDataUtil({ allRelations, nodeLabelByType, local }); }; export default getRelationData; From 4f30769c10efa7a0fd4ee18fe91ea18032c78a90 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Wed, 10 Dec 2025 14:28:35 -0500 Subject: [PATCH 3/4] correction, coderabbit nits --- apps/roam/src/utils/fireQuery.ts | 40 +++++++++++++++++---------- apps/roam/src/utils/getExportTypes.ts | 2 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/roam/src/utils/fireQuery.ts b/apps/roam/src/utils/fireQuery.ts index b0c772c34..a922f43d9 100644 --- a/apps/roam/src/utils/fireQuery.ts +++ b/apps/roam/src/utils/fireQuery.ts @@ -316,7 +316,27 @@ export const fireQuerySync = (args: FireQueryArgs): QueryResult[] => { })); }; -const PROP_NAME_RE = new RegExp(/\:\w+\/\w+\b/, "g"); +const PROP_NAME_RE = /:\w+\/\w+\b/g; + +const renamePropsInResult = ( + result: json | null, + mapping: Record, +): json | null => { + const rename = (x: json | null): json | null => { + if (Array.isArray(x)) return x.map(rename); + if (x === null || x === undefined) return x; + if (typeof x === "object") { + return Object.fromEntries( + Object.entries(x as object).map(([k, v]) => [ + mapping[k] || k, + rename(v), + ]), + ); + } + return x; + }; + return rename(result); +}; const fireQuery: FireQuery = async (_args) => { const { isCustomEnabled, customNode, local, ...args } = _args; @@ -364,20 +384,10 @@ const fireQuery: FireQuery = async (_args) => { // no name conflict, safe to use async query // BUT it returns non-namespaced names, so substitute prop names back queryResults = await window.roamAlphaAPI.data.async.q(query, ...inputs); - const renameProps = (x: json | null): json | null => { - if (Array.isArray(x)) return x.map(renameProps); - if (x === null || x === undefined) return x; - if (typeof x === "object") { - return Object.fromEntries( - Object.entries(x as object).map(([k, v]) => [ - propNamesSub[k] || k, - renameProps(v), // eslint-disable-line @typescript-eslint/no-unsafe-argument - ]), - ); - } - return x; - }; - queryResults = renameProps(queryResults as json) as unknown[][]; + queryResults = renamePropsInResult( + queryResults as json, + propNamesSub, + ) as unknown[][]; } else { // more janky but safer queryResults = window.roamAlphaAPI.data.fast.q(query, ...inputs); diff --git a/apps/roam/src/utils/getExportTypes.ts b/apps/roam/src/utils/getExportTypes.ts index 6f6e19b99..3287ba820 100644 --- a/apps/roam/src/utils/getExportTypes.ts +++ b/apps/roam/src/utils/getExportTypes.ts @@ -375,7 +375,7 @@ const getExportTypes = ({ ); }; const getRelationData = () => - getRelationDataUtil(allRelations, nodeLabelByType); + getRelationDataUtil({ allRelations, nodeLabelByType, local: true }); const getJsonData = async () => { const grammar = allRelations.map(({ label, destination, source }) => ({ From ede4f1337150e4e7fb9fb1795c6972e0b0bd5d0c Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Mon, 22 Dec 2025 15:12:33 -0500 Subject: [PATCH 4/4] getRelationData locally in migration --- apps/roam/src/utils/migrateRelations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/roam/src/utils/migrateRelations.ts b/apps/roam/src/utils/migrateRelations.ts index 59c2f799b..41cba8014 100644 --- a/apps/roam/src/utils/migrateRelations.ts +++ b/apps/roam/src/utils/migrateRelations.ts @@ -20,7 +20,7 @@ const migrateRelations = async (dryRun = false): Promise => { await new Promise((resolve) => setTimeout(resolve, 150)); try { const processed = new Set(); - const relationData = await getRelationData(); + const relationData = await getRelationData(true); for (const rel of relationData) { const key = `${rel.source}:${rel.relUid}:${rel.target}`; if (processed.has(key)) continue;