1
0

Query code refactor

This commit is contained in:
Zef Hemel 2022-07-06 12:18:47 +02:00
parent 05edbfe305
commit fcf712ccc7
6 changed files with 107 additions and 118 deletions

View File

@ -1,22 +0,0 @@
Some things I want to work on:
* [ ] Persistent recent commands (saved between sessions)
* [ ] Add ==marker== syntax
* [ ] Two finger tap gesture to bring up command palette
* [ ] Change indent level command
* [ ] Keyboard shortcuts for specific notes (e.g. `index` note)
* [ ] RevealJS slides plug
* [ ] Pinned notes and actions?
* [ ] Template for deadline, with 📅 emoji and perhaps defaulting to today?
* [ ] Use webauthn https://www.npmjs.com/package/webauthn
* [ ] Proper sign up and login
* [ ] Data store pagination API
* [ ] Hashtag plug:
* Higlighting
* Page indexing/item indexing
* Tag completion
* Query providers: ht-page ht-item
* [ ] Extract `MarkdownEditor` component.
* REST API safeguards:
* [ ] PUT page with `If-Last-Modified-Before` type header. Rejects if not matching. Client creates a revision, navigates to it.
* [ ] Put retries exponential back off

View File

@ -114,6 +114,13 @@ export async function quickNoteCommand() {
await navigate(pageName); await navigate(pageName);
} }
export async function dailyNoteCommand() {
let isoDate = new Date().toISOString();
let date = isoDate.split("T")[0];
let pageName = `📅 ${date}`;
await navigate(pageName);
}
export async function insertTemplateText(cmdDef: any) { export async function insertTemplateText(cmdDef: any) {
let cursorPos = await getCursor(); let cursorPos = await getCursor();
let page = await getCurrentPage(); let page = await getCurrentPage();

View File

@ -1,5 +1,6 @@
import { expect, test } from "@jest/globals"; import { expect, test } from "@jest/globals";
import { applyQuery, parseQuery } from "./engine"; import { applyQuery } from "./engine";
import { parseQuery } from "./parser";
test("Test parser", () => { test("Test parser", () => {
let parsedBasicQuery = parseQuery(`page`); let parsedBasicQuery = parseQuery(`page`);

View File

@ -1,108 +1,17 @@
import { import { collectNodesOfType, ParseTree } from "@silverbulletmd/common/tree";
collectNodesOfType,
findNodeOfType,
ParseTree,
replaceNodesMatching,
} from "@silverbulletmd/common/tree";
import { lezerToParseTree } from "@silverbulletmd/common/parse_tree";
import Handlebars from "handlebars"; import Handlebars from "handlebars";
import YAML from "yaml"; import YAML from "yaml";
// @ts-ignore
import { parser } from "./parse-query";
import { readPage } from "@silverbulletmd/plugos-silverbullet-syscall/space"; import { readPage } from "@silverbulletmd/plugos-silverbullet-syscall/space";
import { niceDate } from "../core/dates"; import { niceDate } from "../core/dates";
import { ParsedQuery } from "./parser";
export type QueryProviderEvent = { export type QueryProviderEvent = {
query: ParsedQuery; query: ParsedQuery;
pageName: string; pageName: string;
}; };
export type Filter = { export function valueNodeToVal(valNode: ParseTree): any {
op: string;
prop: string;
value: any;
};
export type ParsedQuery = {
table: string;
orderBy?: string;
orderDesc?: boolean;
limit?: number;
filter: Filter[];
select?: string[];
render?: string;
};
export function parseQuery(query: string): ParsedQuery {
let n = lezerToParseTree(query, parser.parse(query).topNode);
// Clean the tree a bit
replaceNodesMatching(n, (n) => {
if (!n.type) {
let trimmed = n.text!.trim();
if (!trimmed) {
return null;
}
n.text = trimmed;
}
});
// console.log("Parsed", JSON.stringify(n, null, 2));
let queryNode = n.children![0];
let parsedQuery: ParsedQuery = {
table: queryNode.children![0].children![0].text!,
filter: [],
};
let orderByNode = findNodeOfType(queryNode, "OrderClause");
if (orderByNode) {
let nameNode = findNodeOfType(orderByNode, "Name");
parsedQuery.orderBy = nameNode!.children![0].text!;
let orderNode = findNodeOfType(orderByNode, "Order");
parsedQuery.orderDesc = orderNode
? orderNode.children![0].text! === "desc"
: false;
}
let limitNode = findNodeOfType(queryNode, "LimitClause");
if (limitNode) {
let nameNode = findNodeOfType(limitNode, "Number");
parsedQuery.limit = valueNodeToVal(nameNode!);
}
let filterNodes = collectNodesOfType(queryNode, "FilterExpr");
for (let filterNode of filterNodes) {
let val: any = undefined;
let valNode = filterNode.children![2].children![0];
val = valueNodeToVal(valNode);
let f: Filter = {
prop: filterNode.children![0].children![0].text!,
op: filterNode.children![1].text!,
value: val,
};
parsedQuery.filter.push(f);
}
let selectNode = findNodeOfType(queryNode, "SelectClause");
if (selectNode) {
// console.log("Select node", JSON.stringify(selectNode));
parsedQuery.select = [];
collectNodesOfType(selectNode, "Name").forEach((t) => {
parsedQuery.select!.push(t.children![0].text!);
});
// let nameNode = findNodeOfType(selectNode, "Number");
// parsedQuery.limit = +nameNode!.children![0].text!;
}
let renderNode = findNodeOfType(queryNode, "RenderClause");
if (renderNode) {
let renderNameNode = findNodeOfType(renderNode, "String");
parsedQuery.render = valueNodeToVal(renderNameNode!);
}
// console.log(JSON.stringify(queryNode, null, 2));
return parsedQuery;
}
function valueNodeToVal(valNode: ParseTree): any {
switch (valNode.type) { switch (valNode.type) {
case "Number": case "Number":
return +valNode.children![0].text!; return +valNode.children![0].text!;

View File

@ -10,7 +10,8 @@ import {
writePage, writePage,
} from "@silverbulletmd/plugos-silverbullet-syscall/space"; } from "@silverbulletmd/plugos-silverbullet-syscall/space";
import { invokeFunction } from "@silverbulletmd/plugos-silverbullet-syscall/system"; import { invokeFunction } from "@silverbulletmd/plugos-silverbullet-syscall/system";
import { parseQuery, renderQuery } from "./engine"; import { renderQuery } from "./engine";
import { parseQuery } from "./parser";
import { replaceTemplateVars } from "../core/template"; import { replaceTemplateVars } from "../core/template";
import { jsonToMDTable, queryRegex } from "./util"; import { jsonToMDTable, queryRegex } from "./util";
import { dispatch } from "@plugos/plugos-syscall/event"; import { dispatch } from "@plugos/plugos-syscall/event";

View File

@ -0,0 +1,93 @@
import {
collectNodesOfType,
findNodeOfType,
replaceNodesMatching,
} from "@silverbulletmd/common/tree";
import { lezerToParseTree } from "@silverbulletmd/common/parse_tree";
import { valueNodeToVal } from "./engine";
// @ts-ignore
import { parser } from "./parse-query";
export type Filter = {
op: string;
prop: string;
value: any;
};
export type ParsedQuery = {
table: string;
orderBy?: string;
orderDesc?: boolean;
limit?: number;
filter: Filter[];
select?: string[];
render?: string;
};
export function parseQuery(query: string): ParsedQuery {
let n = lezerToParseTree(query, parser.parse(query).topNode);
// Clean the tree a bit
replaceNodesMatching(n, (n) => {
if (!n.type) {
let trimmed = n.text!.trim();
if (!trimmed) {
return null;
}
n.text = trimmed;
}
});
// console.log("Parsed", JSON.stringify(n, null, 2));
let queryNode = n.children![0];
let parsedQuery: ParsedQuery = {
table: queryNode.children![0].children![0].text!,
filter: [],
};
let orderByNode = findNodeOfType(queryNode, "OrderClause");
if (orderByNode) {
let nameNode = findNodeOfType(orderByNode, "Name");
parsedQuery.orderBy = nameNode!.children![0].text!;
let orderNode = findNodeOfType(orderByNode, "Order");
parsedQuery.orderDesc = orderNode
? orderNode.children![0].text! === "desc"
: false;
}
let limitNode = findNodeOfType(queryNode, "LimitClause");
if (limitNode) {
let nameNode = findNodeOfType(limitNode, "Number");
parsedQuery.limit = valueNodeToVal(nameNode!);
}
let filterNodes = collectNodesOfType(queryNode, "FilterExpr");
for (let filterNode of filterNodes) {
let val: any = undefined;
let valNode = filterNode.children![2].children![0];
val = valueNodeToVal(valNode);
let f: Filter = {
prop: filterNode.children![0].children![0].text!,
op: filterNode.children![1].text!,
value: val,
};
parsedQuery.filter.push(f);
}
let selectNode = findNodeOfType(queryNode, "SelectClause");
if (selectNode) {
// console.log("Select node", JSON.stringify(selectNode));
parsedQuery.select = [];
collectNodesOfType(selectNode, "Name").forEach((t) => {
parsedQuery.select!.push(t.children![0].text!);
});
// let nameNode = findNodeOfType(selectNode, "Number");
// parsedQuery.limit = +nameNode!.children![0].text!;
}
let renderNode = findNodeOfType(queryNode, "RenderClause");
if (renderNode) {
let renderNameNode = findNodeOfType(renderNode, "String");
parsedQuery.render = valueNodeToVal(renderNameNode!);
}
// console.log(JSON.stringify(queryNode, null, 2));
return parsedQuery;
}