silverbullet/plug-api/lib/parser_query.test.ts

460 lines
9.4 KiB
TypeScript
Raw Normal View History

import { parse } from "$common/markdown_parser/parse_tree.ts";
2024-07-30 23:33:33 +08:00
import { type AST, collectNodesOfType, parseTreeToAST } from "./tree.ts";
2024-07-30 23:24:17 +08:00
import { assert, assertEquals } from "@std/assert";
import { astToKvQuery } from "./parse_query.ts";
import { languageFor } from "$common/languages.ts";
function wrapQueryParse(query: string): AST | null {
const tree = parse(languageFor("query")!, query);
// console.log("tree", tree);
// Check for no ambiguitiies
if (collectNodesOfType(tree, "⚠").length > 0) {
console.error("Parse error:", JSON.stringify(tree, null, 2));
assert(false);
}
return parseTreeToAST(tree.children![0]);
}
Deno.test("Test query parser", () => {
// const query = ;
// console.log("query", query);
assertEquals(
astToKvQuery(wrapQueryParse(`page where name = "test"`)!),
{
querySource: "page",
filter: ["=", ["attr", "name"], ["string", "test"]],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where true`)!),
{
querySource: "page",
filter: ["boolean", true],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where .`)!),
{
querySource: "page",
filter: ["attr"],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where name = "hello"`)!),
{
querySource: "page",
filter: ["=", ["attr", "name"], [
"string",
"hello",
]],
},
);
assertEquals(
astToKvQuery(wrapQueryParse("page where `name`")!),
{
querySource: "page",
filter: ["attr", "name"],
},
);
assertEquals(
astToKvQuery(wrapQueryParse("page where `something`.`name`")!),
{
querySource: "page",
filter: ["attr", ["attr", "something"], "name"],
},
);
assertEquals(
astToKvQuery(wrapQueryParse("page select 10 as `something`, `name`")!),
{
querySource: "page",
select: [{ name: "something", expr: ["number", 10] }, { name: "name" }],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where @page`)!),
{
querySource: "page",
filter: ["global", "page"],
},
);
// Comment check
assertEquals(
astToKvQuery(
wrapQueryParse(`page # comment`)!,
),
{
querySource: "page",
},
);
// Nested query check
assertEquals(
astToKvQuery(
wrapQueryParse(`page select {page} as p`)!,
),
{
querySource: "page",
select: [{
expr: ["query", { querySource: "page" }],
name: "p",
}],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where not true`)!),
{
querySource: "page",
filter: ["not", ["boolean", true]],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where !isSomething`)!),
{
querySource: "page",
filter: ["not", ["attr", "isSomething"]],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where name =~ /test/`)!),
{
querySource: "page",
filter: ["=~", ["attr", "name"], ["regexp", "test", "i"]],
},
);
assertEquals(
astToKvQuery(wrapQueryParse(`page where parent.name = "test"`)!),
{
querySource: "page",
filter: ["=", ["attr", ["attr", "parent"], "name"], ["string", "test"]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where name = [[my page]]`)!,
),
{
querySource: "page",
filter: ["=", ["attr", "name"], [
"pageref",
"my page",
]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where name = {"name": "Pete", "age": 27}`)!,
),
{
querySource: "page",
filter: ["=", ["attr", "name"], ["object", [
["name", ["string", "Pete"]],
["age", ["number", 27]],
]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where json({})`)!,
),
{
querySource: "page",
filter: ["call", "json", [["object", []]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where name = [1, 2, 3]`)!,
),
{
querySource: "page",
filter: ["=", ["attr", "name"], ["array", [["number", 1], ["number", 2], [
"number",
3,
]]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where name = []`)!,
),
{
querySource: "page",
filter: ["=", ["attr", "name"], ["array", []]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where name = "test" and age > 20`)!,
),
{
querySource: "page",
filter: ["and", ["=", ["attr", "name"], ["string", "test"]], [">", [
"attr",
"age",
], ["number", 20]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where name = "test" and age > 20 or done = true`)!,
),
{
querySource: "page",
filter: ["or", ["and", ["=", ["attr", "name"], ["string", "test"]], [
">",
[
"attr",
"age",
],
["number", 20],
]], ["=", ["attr", "done"], ["boolean", true]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where (age <= 20) or task.done = null`)!,
),
{
querySource: "page",
filter: ["or", ["<=", ["attr", "age"], ["number", 20]], [
"=",
[
"attr",
[
"attr",
"task",
],
"done",
],
["null"],
]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task order by lastModified asc`)!,
),
{
querySource: "task",
orderBy: [{ expr: ["attr", "lastModified"], desc: false }],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task order by lastModified`)!,
),
{
querySource: "task",
orderBy: [{ expr: ["attr", "lastModified"], desc: false }],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task order by lastModified desc, name, age asc`)!,
),
{
querySource: "task",
orderBy: [{ expr: ["attr", "lastModified"], desc: true }, {
expr: ["attr", "name"],
desc: false,
}, { expr: ["attr", "age"], desc: false }],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task order by lastModified desc limit 5`)!,
),
{
querySource: "task",
orderBy: [{ expr: ["attr", "lastModified"], desc: true }],
limit: ["number", 5],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task select name, lastModified + 20 as modified`)!,
),
{
querySource: "task",
select: [{ name: "name" }, {
name: "modified",
expr: ["+", ["attr", "lastModified"], ["number", 20]],
}],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task render [[my/page]]`)!,
),
{
querySource: "task",
render: "my/page",
2023-10-30 21:15:12 +08:00
renderAll: false,
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task render each [[my/page]]`)!,
),
{
querySource: "task",
render: "my/page",
renderAll: false,
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task render all [[my/page]]`)!,
),
{
querySource: "task",
render: "my/page",
renderAll: true,
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task where name in ["hello", 1]`)!,
),
{
querySource: "task",
filter: ["in", ["attr", "name"], ["array", [["string", "hello"], [
"number",
1,
]]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task where myCall().thing`)!,
),
{
querySource: "task",
filter: ["attr", ["call", "myCall", []], "thing"],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task select today() as today2`)!,
),
{
querySource: "task",
select: [{
name: "today2",
expr: ["call", "today", []],
}],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`task select today(1, 2, 3) as today`)!,
),
{
querySource: "task",
select: [{
name: "today",
expr: ["call", "today", [["number", 1], ["number", 2], ["number", 3]]],
}],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page select 8 > 3 ? "yes" : "no" as truth`)!,
),
{
querySource: "page",
select: [{
name: "truth",
expr: ["?", [">", ["number", 8], ["number", 3]], ["string", "yes"], [
"string",
"no",
]],
}],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where myCall(-3) > 4 - 2`)!,
),
{
querySource: "page",
filter: [">", ["call", "myCall", [["-", ["number", 3]]]], ["-", [
"number",
4,
], ["number", 2]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where 1 * 2 - 3`)!,
),
{
querySource: "page",
filter: ["-", ["*", ["number", 1], ["number", 2]], ["number", 3]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where 1*-2`)!,
),
{
querySource: "page",
filter: ["*", ["number", 1], ["-", ["number", 2]]],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where 10.2`)!,
),
{
querySource: "page",
filter: ["number", 10.2],
},
);
assertEquals(
astToKvQuery(
wrapQueryParse(`page where 10.2 > 2.2`)!,
),
{
querySource: "page",
filter: [">", ["number", 10.2], ["number", 2.2]],
},
);
});