From d0580a076631177b64d5facde09a4ad1fcd2f307 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Sun, 9 Nov 2025 21:21:49 -0500 Subject: [PATCH 1/3] 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 e1a40c32cbd1b527146e16abb7f679b9c6fd425a Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Wed, 10 Dec 2025 14:19:34 -0500 Subject: [PATCH 2/3] local migrations --- apps/roam/src/utils/fireQuery.ts | 1 - apps/roam/src/utils/getRelationData.ts | 18 ++++++++++++------ apps/roam/src/utils/migrateRelations.ts | 2 +- 3 files changed, 13 insertions(+), 8 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 199110f72..a3ef03ee7 100644 --- a/apps/roam/src/utils/getRelationData.ts +++ b/apps/roam/src/utils/getRelationData.ts @@ -5,10 +5,15 @@ import type { DiscourseRelation } from "./getDiscourseRelations"; // 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( @@ -23,6 +28,7 @@ export const getRelationDataUtil = async ( ? [] : fireQuery({ returnNode: sourceLabel, + local, conditions: [ { relation: s.label, @@ -50,13 +56,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; diff --git a/apps/roam/src/utils/migrateRelations.ts b/apps/roam/src/utils/migrateRelations.ts index a2937a274..1d95a4150 100644 --- a/apps/roam/src/utils/migrateRelations.ts +++ b/apps/roam/src/utils/migrateRelations.ts @@ -14,7 +14,7 @@ const migrateRelations = async (dryRun = false): Promise => { const authorized = getSetting("use-reified-relations"); if (!authorized) return 0; const processed = new Set(); - const relationData = await getRelationData(); + const relationData = await getRelationData(true); let numProcessed = 0; for (const rel of relationData) { const key = `${rel.source}:${rel.relUid}:${rel.target}`; From 204b73b4f372a06516d2fe26585d8982ae263ece Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Wed, 10 Dec 2025 14:28:35 -0500 Subject: [PATCH 3/3] 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 8f38724c8..eb582f270 100644 --- a/apps/roam/src/utils/getExportTypes.ts +++ b/apps/roam/src/utils/getExportTypes.ts @@ -374,7 +374,7 @@ const getExportTypes = ({ ); }; const getRelationData = () => - getRelationDataUtil(allRelations, nodeLabelByType); + getRelationDataUtil({ allRelations, nodeLabelByType, local: true }); const getJsonData = async () => { const grammar = allRelations.map(({ label, destination, source }) => ({