import { parse } from "$common/markdown_parser/parse_tree.ts"; import { type AST, collectNodesOfType, parseTreeToAST } from "./tree.ts"; 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", 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]], }, ); });