1
0
silverbullet/plugs/core/materialized_queries.ts

100 lines
3.3 KiB
TypeScript
Raw Normal View History

2022-03-29 15:02:28 +00:00
import { syscall } from "../lib/syscall";
export const queryRegex =
/(<!--\s*#query\s+(?<table>\w+)\s*(filter\s+["'](?<filter>[^"']+)["'])?\s*(group by\s+(?<groupBy>\w+))?\s*-->)(.+?)(<!--\s*#end\s*-->)/gs;
export function whiteOutQueries(text: string): string {
return text.replaceAll(queryRegex, (match) =>
new Array(match.length + 1).join(" ")
);
}
async function replaceAsync(
str: string,
regex: RegExp,
asyncFn: (match: string, ...args: any[]) => Promise<string>
) {
const promises: Promise<string>[] = [];
str.replace(regex, (match: string, ...args: any[]): string => {
const promise = asyncFn(match, ...args);
promises.push(promise);
return "";
});
const data = await Promise.all(promises);
return str.replace(regex, () => data.shift()!);
}
export async function updateMaterializedQueriesCommand() {
await syscall(
"system.invokeFunctionOnServer",
"updateMaterializedQueriesOnPage",
await syscall("editor.getCurrentPage")
);
2022-03-31 15:25:34 +00:00
await syscall("editor.reloadPage");
await syscall("editor.flashNotification", "Updated materialized queries");
2022-03-29 15:02:28 +00:00
}
// Called from client, running on server
export async function updateMaterializedQueriesOnPage(pageName: string) {
let { text } = await syscall("space.readPage", pageName);
text = await replaceAsync(text, queryRegex, async (match, ...args) => {
let { table, filter, groupBy } = args[args.length - 1];
const startQuery = args[0];
const endQuery = args[args.length - 4];
let results = [];
switch (table) {
case "task":
for (let {
key,
page,
value: { task, complete, children },
} of await syscall("index.scanPrefixGlobal", "task:")) {
2022-03-29 15:02:28 +00:00
let [, pos] = key.split(":");
if (!filter || (filter && task.includes(filter))) {
results.push(
2022-03-31 15:25:34 +00:00
`* [${complete ? "x" : " "}] [[${page}@${pos}]] ${task}`
2022-03-29 15:02:28 +00:00
);
if (children) {
results.push(children.join("\n"));
}
}
}
return `${startQuery}\n${results.join("\n")}\n${endQuery}`;
2022-03-31 15:25:34 +00:00
case "link":
let uniqueLinks = new Set<string>();
for (let {key, page, value: name} of await syscall(
"index.scanPrefixGlobal",
`pl:${pageName}:`
)) {
let [, pos] = key.split(":");
if (!filter || (filter && name.includes(filter))) {
uniqueLinks.add(name);
}
}
for (const uniqueResult of uniqueLinks) {
results.push(`* [[${uniqueResult}]]`);
}
return `${startQuery}\n${results.sort().join("\n")}\n${endQuery}`;
2022-03-29 15:02:28 +00:00
case "item":
for (let {
key,
page,
2022-03-31 15:25:34 +00:00
value: {item, children},
} of await syscall("index.scanPrefixGlobal", "it:")) {
2022-03-29 15:02:28 +00:00
let [, pos] = key.split(":");
if (!filter || (filter && item.includes(filter))) {
results.push(`* [[${page}@${pos}]] ${item}`);
if (children) {
results.push(children.join("\n"));
}
}
}
return `${startQuery}\n${results.join("\n")}\n${endQuery}`;
default:
return match;
}
});
// console.log("New text", text);
await syscall("space.writePage", pageName, text);
}