diff --git a/js/httpql/src/index.spec.ts b/js/httpql/src/index.spec.ts index 9c5a32e..67594cc 100644 --- a/js/httpql/src/index.spec.ts +++ b/js/httpql/src/index.spec.ts @@ -19,9 +19,9 @@ type Test = const readFile = (path: string) => { return fs.readFileSync( join(fileURLToPath(import.meta.url), "../../../../tests/httpql", path), - "utf-8" + "utf-8", ); -} +}; describe("httpql", () => { describe("ast", () => { @@ -57,9 +57,7 @@ describe("httpql", () => { for (const c of cases) { it(`Case ${c}`, () => { const input = readFile(`regex/${c}/input.httpql`); - const test: Test = JSON.parse( - readFile(`regex/${c}/test.json`).trim(), - ); + const test: Test = JSON.parse(readFile(`regex/${c}/test.json`).trim()); const query = deserialize(input); if (test.expect === "err") { @@ -78,9 +76,7 @@ describe("httpql", () => { for (const c of cases) { it(`Case ${c}`, () => { const input = readFile(`string/${c}/input.httpql`); - const test: Test = JSON.parse( - readFile(`string/${c}/test.json`).trim(), - ); + const test: Test = JSON.parse(readFile(`string/${c}/test.json`).trim()); const query = deserialize(input); if (test.expect === "err") { diff --git a/js/streamql/src/deserialize/clause.preset.ts b/js/streamql/src/deserialize/clause.preset.ts new file mode 100644 index 0000000..e3f06a7 --- /dev/null +++ b/js/streamql/src/deserialize/clause.preset.ts @@ -0,0 +1,32 @@ +import type { SyntaxNode } from "@lezer/common"; +import { err, ok, type Result } from "neverthrow"; + +import { InvalidQuery, type StreamQLError } from "../errors.js"; +import { terms } from "../parser/index.js"; +import type { ExprPreset } from "../primitives.js"; +import { getChildString, isPresent } from "../utils.js"; + +import { deserializeString } from "./string.js"; + +export const deserializePresetClause = ( + node: SyntaxNode, + doc: string, +): Result => { + const nameNode = node.getChild(terms.PresetNameExpression); + if (isPresent(nameNode)) { + return deserializeString(nameNode, doc).map(({ value }) => { + return { + name: value, + }; + }); + } + + const aliasStr = getChildString(node, terms.PresetAliasExpression, doc); + if (isPresent(aliasStr)) { + return ok({ + alias: aliasStr, + }); + } + + return err(new InvalidQuery()); +}; diff --git a/js/streamql/src/deserialize/clause.ts b/js/streamql/src/deserialize/clause.ts index 98d1100..1750e37 100644 --- a/js/streamql/src/deserialize/clause.ts +++ b/js/streamql/src/deserialize/clause.ts @@ -6,6 +6,7 @@ import { terms } from "../parser/index.js"; import { type Query } from "../primitives.js"; import { isPresent } from "../utils.js"; +import { deserializePresetClause } from "./clause.preset.js"; import { deserializeStreamClause } from "./clause.stream.js"; import { deserializeWsClause } from "./clause.websocket.js"; @@ -13,6 +14,13 @@ export const deserializeClause = ( node: SyntaxNode, doc: string, ): Result => { + const presetClause = node.getChild(terms.PresetClause); + if (isPresent(presetClause)) { + return deserializePresetClause(presetClause, doc).map((preset) => ({ + preset, + })); + } + const streamClause = node.getChild(terms.StreamClause); if (isPresent(streamClause)) { return deserializeStreamClause(streamClause, doc).map((stream) => ({ diff --git a/js/streamql/src/deserialize/index.spec.ts b/js/streamql/src/deserialize/index.spec.ts index bad0dd5..50d15f9 100644 --- a/js/streamql/src/deserialize/index.spec.ts +++ b/js/streamql/src/deserialize/index.spec.ts @@ -244,4 +244,27 @@ describe("deserialize", () => { ], }); }); + it("should parse StreamQL preset alias expression", () => { + const query = "preset:my-preset"; + + const filter = deserialize(query)._unsafeUnwrap(); + + expect(filter).to.deep.equal({ + preset: { + alias: "my-preset", + }, + }); + }); + + it("should parse StreamQL preset name expression", () => { + const query = 'preset:"My preset"'; + + const filter = deserialize(query)._unsafeUnwrap(); + + expect(filter).to.deep.equal({ + preset: { + name: "My preset", + }, + }); + }); }); diff --git a/js/streamql/src/index.spec.ts b/js/streamql/src/index.spec.ts index 581175b..78e30bb 100644 --- a/js/streamql/src/index.spec.ts +++ b/js/streamql/src/index.spec.ts @@ -20,9 +20,9 @@ const readFile = (path: string) => { console.log(fileURLToPath(import.meta.url)); return fs.readFileSync( join(fileURLToPath(import.meta.url), "../../../../tests/streamql", path), - "utf-8" + "utf-8", ); -} +}; describe("streamql", () => { describe("ast", () => { @@ -56,9 +56,7 @@ describe("streamql", () => { for (const c of cases) { it(`Case ${c}`, () => { const input = readFile(`regex/${c}/input.streamql`); - const test: Test = JSON.parse( - readFile(`regex/${c}/test.json`).trim(), - ); + const test: Test = JSON.parse(readFile(`regex/${c}/test.json`).trim()); const query = deserialize(input); if (test.expect === "err") { @@ -77,9 +75,7 @@ describe("streamql", () => { for (const c of cases) { it(`Case ${c}`, () => { const input = readFile(`string/${c}/input.streamql`); - const test: Test = JSON.parse( - readFile(`string/${c}/test.json`).trim(), - ); + const test: Test = JSON.parse(readFile(`string/${c}/test.json`).trim()); const query = deserialize(input); if (test.expect === "err") { diff --git a/js/streamql/src/primitives.ts b/js/streamql/src/primitives.ts index b2aa18f..f94f913 100644 --- a/js/streamql/src/primitives.ts +++ b/js/streamql/src/primitives.ts @@ -4,6 +4,7 @@ export type Maybe = T | undefined | null; export type Query = { AND?: Maybe<[Query, Query]>; OR?: Maybe<[Query, Query]>; + preset?: Maybe; websocket?: Maybe; stream?: Maybe; }; @@ -29,6 +30,8 @@ export type ExprInt = { value: number; }; +export type ExprPreset = { alias: string } | { name: string }; + export type ExprString = { operator: OperatorString; value: string; diff --git a/js/streamql/src/serialize.ts b/js/streamql/src/serialize.ts index 5c2f1be..0282fd0 100644 --- a/js/streamql/src/serialize.ts +++ b/js/streamql/src/serialize.ts @@ -7,6 +7,7 @@ import type { ExprBool, ExprDate, ExprInt, + ExprPreset, ExprString, Query, } from "./primitives.js"; @@ -19,6 +20,9 @@ export const serialize = (query: Query): Result => { const serializeClauseRequestResponse = ( query: Query, ): Result => { + if (isPresent(query.preset)) { + return serializeExprPreset(query.preset); + } if (isPresent(query.stream)) { return serializeClauseStream(query.stream).map((str) => `stream.${str}`); } @@ -90,6 +94,16 @@ const serializeClauseStream = ( return err(new InvalidQuery()); }; +const serializeExprPreset = ( + preset: ExprPreset, +): Result => { + if ("alias" in preset) { + return ok(`preset:${preset.alias}`); + } else { + return ok(`preset:"${preset.name}"`); + } +}; + const serializeExprInt = (value: ExprInt): Result => { return ok(`${value.operator.toLowerCase()}:${value.value}`); };