Skip to content

Commit b79de13

Browse files
authored
ENG-904 - Added isACandidateCallback to registerDiscourseDatalogTranslators for handling discourse node candidates. (#458)
* Added isACandidateCallback to registerDiscourseDatalogTranslators for handling discourse node candidates. * toVar * Refactor registerDiscourseDatalogTranslators to utilize getTitleDatalog for improved data pattern handling and streamline node filtering with early returns. * Update registerDiscourseDatalogTranslators to use optional chaining for targetNodeTag retrieval, enhancing robustness against undefined values.
1 parent 64c6942 commit b79de13

3 files changed

Lines changed: 83 additions & 3 deletions

File tree

apps/roam/src/utils/compileDatalog.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import type {
66

77
const indent = (n: number) => "".padStart(n * 2, " ");
88

9-
const toVar = (v = "undefined") => v.replace(/[\s"()[\]{}/\\^@,~`]/g, "");
9+
export const toVar = (v = "undefined") =>
10+
v.replace(/[\s"()[\]{}/\\^@,~`]/g, "");
1011

1112
const compileDatalog = (
1213
d: DatalogClause | DatalogArgument | DatalogBinding,

apps/roam/src/utils/conditionToDatalog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const regexRePatternValue = (str: string) => {
2929
? `"(?i)${str.slice(1, -2).replace(/\\/g, "\\\\")}"`
3030
: `"${str.slice(1, -1).replace(/\\/g, "\\\\")}"`;
3131
};
32-
const getTitleDatalog = ({
32+
export const getTitleDatalog = ({
3333
source,
3434
target,
3535
uid,

apps/roam/src/utils/registerDiscourseDatalogTranslators.ts

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,23 @@ import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTit
55
import getSubTree from "roamjs-components/util/getSubTree";
66
import discourseNodeFormatToDatalog from "./discourseNodeFormatToDatalog";
77
import conditionToDatalog, {
8+
getTitleDatalog,
89
registerDatalogTranslator,
910
} from "./conditionToDatalog";
1011
import { ANY_RELATION_REGEX } from "./deriveDiscourseNodeAttribute";
11-
import getDiscourseNodes, { excludeDefaultNodes } from "./getDiscourseNodes";
12+
import getDiscourseNodes, {
13+
excludeDefaultNodes,
14+
type DiscourseNode,
15+
} from "./getDiscourseNodes";
1216
import getDiscourseRelations from "./getDiscourseRelations";
1317
import matchDiscourseNode from "./matchDiscourseNode";
1418
import replaceDatalogVariables from "./replaceDatalogVariables";
1519
import parseQuery from "./parseQuery";
1620
import { fireQuerySync, getWhereClauses } from "./fireQuery";
21+
import { toVar } from "./compileDatalog";
22+
23+
const hasTag = (node: DiscourseNode): node is DiscourseNode & { tag: string } =>
24+
!!node.tag;
1725

1826
const collectVariables = (
1927
clauses: (DatalogClause | DatalogAndClause)[],
@@ -45,6 +53,7 @@ const ANY_DISCOURSE_NODE = "Any Discourse Node";
4553
const registerDiscourseDatalogTranslators = () => {
4654
const discourseRelations = getDiscourseRelations();
4755
const discourseNodes = getDiscourseNodes(discourseRelations);
56+
4857
const isACallback: Parameters<
4958
typeof registerDatalogTranslator
5059
>[0]["callback"] = ({ source, target }) => {
@@ -89,6 +98,64 @@ const registerDiscourseDatalogTranslators = () => {
8998
})
9099
: [];
91100
};
101+
const isACandidateCallback: Parameters<
102+
typeof registerDatalogTranslator
103+
>[0]["callback"] = ({ source, target }) => {
104+
const nodeByTypeOrText = Object.fromEntries([
105+
...discourseNodes.map((n) => [n.type, n] as const),
106+
...discourseNodes.map((n) => [n.text, n] as const),
107+
]);
108+
109+
if (target === ANY_DISCOURSE_NODE) {
110+
const nodesWithTags = discourseNodes.filter(hasTag);
111+
if (nodesWithTags.length === 0) return [];
112+
return [
113+
{
114+
type: "or-join-clause" as const,
115+
variables: [{ type: "variable" as const, value: source }],
116+
clauses: nodesWithTags.map((node) => {
117+
const variableRef = `${toVar(node.tag)}-ref`;
118+
return {
119+
type: "and-clause" as const,
120+
clauses: [
121+
{
122+
type: "data-pattern" as const,
123+
arguments: [
124+
{ type: "variable" as const, value: source },
125+
{ type: "constant" as const, value: ":block/refs" },
126+
{
127+
type: "variable" as const,
128+
value: variableRef,
129+
},
130+
],
131+
},
132+
...getTitleDatalog({ source: variableRef, target: node.tag }),
133+
],
134+
};
135+
}),
136+
},
137+
];
138+
}
139+
140+
const targetNodeTag = nodeByTypeOrText[target]?.tag;
141+
if (!targetNodeTag) return [];
142+
const variableRef = `${toVar(targetNodeTag)}-ref`;
143+
144+
return [
145+
{
146+
type: "data-pattern" as const,
147+
arguments: [
148+
{ type: "variable" as const, value: source },
149+
{ type: "constant" as const, value: ":block/refs" },
150+
{
151+
type: "variable" as const,
152+
value: variableRef,
153+
},
154+
],
155+
},
156+
...getTitleDatalog({ source: variableRef, target: targetNodeTag }),
157+
];
158+
};
92159
const unregisters = new Set<() => void>();
93160
unregisters.add(
94161
registerDatalogTranslator({
@@ -100,6 +167,18 @@ const registerDiscourseDatalogTranslators = () => {
100167
placeholder: "Enter a discourse node",
101168
}),
102169
);
170+
171+
unregisters.add(
172+
registerDatalogTranslator({
173+
key: "is a candidate",
174+
callback: isACandidateCallback,
175+
targetOptions: discourseNodes
176+
.filter((d) => d.tag)
177+
.map((d) => d.text)
178+
.concat(ANY_DISCOURSE_NODE),
179+
placeholder: "Enter a discourse node",
180+
}),
181+
);
103182
unregisters.add(
104183
registerDatalogTranslator({
105184
key: "self",

0 commit comments

Comments
 (0)