👁️
1/**
2 * Benchmarks for search parsing
3 *
4 * Run with: npm run bench
5 *
6 * Tests the hot path for interactive search-as-you-type.
7 */
8
9import { bench, describe } from "vitest";
10import { describeQuery, search } from "../index";
11import { tokenize } from "../lexer";
12import { parse } from "../parser";
13import type { SearchNode } from "../types";
14
15// Sample queries of varying complexity
16const QUERIES = {
17 simple: "lightning bolt",
18 field: "t:creature",
19 comparison: "mv<=3",
20 multiField: "t:creature mv<=3 c:red",
21 quoted: '"lightning bolt"',
22 exact: '!"Lightning Bolt"',
23 boolean: "t:creature OR t:instant",
24 complex: 't:creature mv<=3 (c:red OR c:blue) -t:legendary o:"deal damage"',
25 regex: "o:/deals? \\d+ damage/",
26 realWorld: "t:creature mv<=2 id<=ug o:counter",
27};
28
29describe("tokenize (lexer)", () => {
30 bench("simple name", () => {
31 tokenize(QUERIES.simple);
32 });
33
34 bench("single field", () => {
35 tokenize(QUERIES.field);
36 });
37
38 bench("multi-field query", () => {
39 tokenize(QUERIES.multiField);
40 });
41
42 bench("complex boolean", () => {
43 tokenize(QUERIES.complex);
44 });
45
46 bench("regex pattern", () => {
47 tokenize(QUERIES.regex);
48 });
49});
50
51describe("parse (lexer + parser)", () => {
52 bench("simple name", () => {
53 parse(QUERIES.simple);
54 });
55
56 bench("single field", () => {
57 parse(QUERIES.field);
58 });
59
60 bench("multi-field query", () => {
61 parse(QUERIES.multiField);
62 });
63
64 bench("complex boolean", () => {
65 parse(QUERIES.complex);
66 });
67
68 bench("real-world query", () => {
69 parse(QUERIES.realWorld);
70 });
71});
72
73describe("search (full pipeline)", () => {
74 bench("simple name", () => {
75 search(QUERIES.simple);
76 });
77
78 bench("single field", () => {
79 search(QUERIES.field);
80 });
81
82 bench("multi-field query", () => {
83 search(QUERIES.multiField);
84 });
85
86 bench("complex boolean", () => {
87 search(QUERIES.complex);
88 });
89
90 bench("real-world query", () => {
91 search(QUERIES.realWorld);
92 });
93});
94
95// Pre-parse ASTs for describe benchmarks
96function getAst(query: string): SearchNode {
97 const result = parse(query);
98 if (!result.ok) throw new Error(`Failed to parse: ${query}`);
99 return result.value;
100}
101
102const ASTS = {
103 simple: getAst(QUERIES.simple),
104 field: getAst(QUERIES.field),
105 multiField: getAst(QUERIES.multiField),
106 complex: getAst(QUERIES.complex),
107 realWorld: getAst(QUERIES.realWorld),
108};
109
110describe("describeQuery (AST to text)", () => {
111 bench("simple name", () => {
112 describeQuery(ASTS.simple);
113 });
114
115 bench("single field", () => {
116 describeQuery(ASTS.field);
117 });
118
119 bench("multi-field query", () => {
120 describeQuery(ASTS.multiField);
121 });
122
123 bench("complex boolean", () => {
124 describeQuery(ASTS.complex);
125 });
126
127 bench("real-world query", () => {
128 describeQuery(ASTS.realWorld);
129 });
130});