diff --git a/apps/roam/src/utils/getDiscourseContextResults.ts b/apps/roam/src/utils/getDiscourseContextResults.ts index 2bc2df3a8..0389bd576 100644 --- a/apps/roam/src/utils/getDiscourseContextResults.ts +++ b/apps/roam/src/utils/getDiscourseContextResults.ts @@ -7,6 +7,9 @@ import getDiscourseRelations, { DiscourseRelation, } from "./getDiscourseRelations"; import { Selection } from "./types"; +import { getSetting } from "./extensionSettings"; +import { ANY_RELATION_REGEX } from "./deriveDiscourseNodeAttribute"; +import { use } from "cytoscape"; const resultCache: Record>> = {}; const CACHE_TIMEOUT = 1000 * 60 * 5; @@ -57,6 +60,18 @@ const buildSelections = ({ text: `node:${conditionUid}-Anchor`, }); } + if (ANY_RELATION_REGEX.test(r.label)) { + selections.push({ + uid: window.roamAlphaAPI.util.generateUID(), + label: "relationUid", + text: "hasSchema", + }); + selections.push({ + uid: window.roamAlphaAPI.util.generateUID(), + label: "effectiveSource", + text: "effectiveSource", + }); + } return selections; }; @@ -183,6 +198,10 @@ const getDiscourseContextResults = async ({ const discourseNode = findDiscourseNode(targetUid); if (!discourseNode) return []; + const useReifiedRelations = getSetting( + "use-reified-relations", + false, + ); const nodeType = discourseNode?.type; const nodeTextByType = Object.fromEntries( nodes.map(({ type, text }) => [type, text]), @@ -214,9 +233,24 @@ const getDiscourseContextResults = async ({ }); const relationsWithComplement = Array.from(uniqueRelations.values()); + const queryRelations = useReifiedRelations + ? [ + { + r: { + id: "null", + complement: "Has Any Relation To", + label: "Has Any Relation To", + triples: [], + source: "*", + destination: "*", + }, + complement: false, + }, + ] + : relationsWithComplement; const context = { nodes, relations }; - const queryConfigs = relationsWithComplement.map((relation) => + const queryConfigs = queryRelations.map((relation) => buildQueryConfig({ args, targetUid, @@ -229,12 +263,40 @@ const getDiscourseContextResults = async ({ }), ); - const resultsWithRelation = await executeQueries( + let resultsWithRelation = await executeQueries( queryConfigs, targetUid, nodeTextByType, onResult, ); + if ( + useReifiedRelations && + resultsWithRelation.length > 0 && + resultsWithRelation[0].results.length > 0 + ) { + const byRel: Record = {}; + const results = resultsWithRelation[0].results; + resultsWithRelation = []; + for (const r of results) { + const relKey = `${r.relationUid}-${r.effectiveSource !== targetUid}`; + byRel[relKey] = byRel[relKey] || []; + byRel[relKey].push(r); + } + resultsWithRelation = Object.entries(byRel).map(([ruid, results]) => ({ + relation: { + id: ruid, + label: ruid.endsWith("-false") + ? uniqueRelations.get(ruid)!.r.label + : uniqueRelations.get(ruid)!.r.complement, + isComplement: ruid.endsWith("-false"), + text: ruid.endsWith("-false") + ? uniqueRelations.get(ruid)!.r.label + : uniqueRelations.get(ruid)!.r.complement, + target: targetUid, + }, + results, + })); + } const groupedResults = Object.fromEntries( resultsWithRelation.map((r) => [ r.relation.text, diff --git a/apps/roam/src/utils/predefinedSelections.ts b/apps/roam/src/utils/predefinedSelections.ts index 89a2209ff..5c9f6ac9d 100644 --- a/apps/roam/src/utils/predefinedSelections.ts +++ b/apps/roam/src/utils/predefinedSelections.ts @@ -30,6 +30,8 @@ const NODE_TEST = /^node:(\s*[^:]+\s*)(:.*)?$/i; const ACTION_TEST = /^action:\s*([^:]+)\s*(?::(.*))?$/i; const DATE_FORMAT_TEST = /^date-format\(([^,)]+),([^,)]+)\)$/i; const MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; +const HAS_SCHEMA_TEST = /^hasSchema$/; +const EFFECTIVE_SOURCE_TEST = /^effectiveSource$/; const getArgValue = (key: string, result: QueryResult) => { if (/^today$/i.test(key)) return new Date(); @@ -285,6 +287,26 @@ const predefinedSelections: PredefinedSelection[] = [ }, suggestions: EDIT_BY_SUGGESTIONS, }, + { + test: HAS_SCHEMA_TEST, + pull: ({ match, returnNode, where }) => { + return "?relSchema"; + }, + mapper: (r, key) => { + // not sure here? + return "?relSchema"; + }, + }, + { + test: EFFECTIVE_SOURCE_TEST, + pull: ({ match, returnNode, where }) => { + return "?relSource"; + }, + mapper: (r, key) => { + // not sure here? + return "?relSource"; + }, + }, { test: NODE_TEST, pull: ({ match, returnNode, where }) => { @@ -367,9 +389,7 @@ const predefinedSelections: PredefinedSelection[] = [ (c): c is QBClause => c.type === "clause" && c.target === selectedVar, ); if (introducedCondition?.relation === "references") { - const sourceUid = result[ - `${introducedCondition.source}-uid` - ] as string; + const sourceUid = result[`${introducedCondition.source}-uid`]; if (sourceUid) { const blockText = getTextByBlockUid(sourceUid); await updateBlock({ diff --git a/apps/roam/src/utils/registerDiscourseDatalogTranslators.ts b/apps/roam/src/utils/registerDiscourseDatalogTranslators.ts index fafb2bdcb..549fc4728 100644 --- a/apps/roam/src/utils/registerDiscourseDatalogTranslators.ts +++ b/apps/roam/src/utils/registerDiscourseDatalogTranslators.ts @@ -818,6 +818,8 @@ const registerDiscourseDatalogTranslators = () => { [ { from: source, to: source }, { from: target, to: target }, + { from: "relSchema", to: "relSchema" }, + { from: "relSource", to: "relSource" }, { from: true, to: (v) => `${uid}-${v}` }, ], clauses,