Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion js/httpql/httpql.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
RightParen { ")" }
Dot { "." }
Colon { ":" }
LeftBracket { "[" }
RightBracket { "]" }
Hex { $[0-9a-fA-F] }
RegexDelim { "/" }

Expand All @@ -40,6 +42,8 @@
RequestIntFieldName { "len" | "port" }
RequestDateFieldName { "created_at" }
RequestBoolFieldName { "tls" }
RequestHeaderFieldName { "header" }
RequestHeaderSubfieldName { "name" | "value" }

// Response field names
ResponseStringFieldName { "raw" }
Expand Down Expand Up @@ -107,7 +111,9 @@ RequestClause {
RequestNamespace Dot RequestIntFieldName Dot IntExpression |
RequestNamespace Dot RequestStringFieldName Dot StringExpression |
RequestNamespace Dot RequestDateFieldName Dot DateExpression |
RequestNamespace Dot RequestBoolFieldName Dot BoolExpression
RequestNamespace Dot RequestBoolFieldName Dot BoolExpression |
RequestNamespace Dot RequestHeaderFieldName Dot RequestHeaderSubfieldName Dot StringExpression |
RequestNamespace Dot RequestHeaderFieldName LeftBracket StringValue RightBracket Dot StringExpression
}

ResponseClause {
Expand Down
89 changes: 82 additions & 7 deletions js/httpql/src/deserialize/clause.request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,62 @@ import type { Result } from "neverthrow";

import { type HTTPQLError, InvalidQuery } from "../errors.js";
import { terms } from "../parser/index.js";
import type { ClauseRequest } from "../primitives.js";
import { getChildString, isPresent } from "../utils.js";
import { OperatorString, type Query } from "../primitives.js";
import { getChildString, isAbsent, isPresent } from "../utils.js";

import { deserializeBoolExpr } from "./expr.bool.js";
import { deserializeDateExpr } from "./expr.date.js";
import { deserializeIntExpr } from "./expr.int.js";
import { deserializeStringExpr } from "./expr.string.js";
import { deserializeString } from "./string.js";

export const deserializeRequestClause = (
node: SyntaxNode,
doc: string,
): Result<ClauseRequest, HTTPQLError> => {
): Result<Query, HTTPQLError> => {
const headerShortExpr = (() => {
const headerNameResult = deserializeString(node, doc);
if (headerNameResult.isErr()) {
return;
}

const { value: headerName, isRaw } = headerNameResult.value;
if (isRaw) {
return;
}

const valueExprNode = node.getChild(terms.StringExpression);
if (isAbsent(valueExprNode)) return;

return deserializeStringExpr(valueExprNode, doc).map((valueExpr) => {
return {
AND: [
{
request: {
header: {
name: {
operator: OperatorString.Eq,
value: headerName,
isRaw: false,
},
},
},
},
{
request: {
header: {
value: valueExpr,
},
},
},
],
} satisfies Query;
});
})();
if (isPresent(headerShortExpr)) {
return headerShortExpr;
}

const stringField = (() => {
const child = getChildString(node, terms.RequestStringFieldName, doc);

Expand All @@ -36,6 +80,17 @@ export const deserializeRequestClause = (
}
}
})();
const headerSubfield = (() => {
const child = getChildString(node, terms.RequestHeaderSubfieldName, doc);
if (isPresent(child)) {
switch (child) {
case "name":
return "name";
case "value":
return "value";
}
}
})();

const intField = (() => {
const child = getChildString(node, terms.RequestIntFieldName, doc);
Expand Down Expand Up @@ -95,31 +150,51 @@ export const deserializeRequestClause = (
if (isPresent(stringField) && isPresent(stringFilter)) {
return stringFilter.map((filter) => {
return {
[stringField]: filter,
request: {
[stringField]: filter,
},
};
});
}

if (isPresent(intField) && isPresent(intFilter)) {
return intFilter.map((filter) => {
return {
[intField]: filter,
request: {
[intField]: filter,
},
};
});
}

if (isPresent(dateField) && isPresent(dateFilter)) {
return dateFilter.map((filter) => {
return {
[dateField]: filter,
request: {
[dateField]: filter,
},
};
});
}

if (isPresent(boolField) && isPresent(boolFilter)) {
return boolFilter.map((filter) => {
return {
[boolField]: filter,
request: {
[boolField]: filter,
},
};
});
}

if (isPresent(headerSubfield) && isPresent(stringFilter)) {
return stringFilter.map((filter) => {
return {
request: {
header: {
[headerSubfield]: filter,
},
},
};
});
}
Expand Down
4 changes: 1 addition & 3 deletions js/httpql/src/deserialize/clause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ export const deserializeClause = (

const requestClause = node.getChild(terms.RequestClause);
if (isPresent(requestClause)) {
return deserializeRequestClause(requestClause, doc).map((request) => ({
request,
}));
return deserializeRequestClause(requestClause, doc);
}

const responseClause = node.getChild(terms.ResponseClause);
Expand Down
3 changes: 2 additions & 1 deletion js/httpql/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const readFile = (path: string) => {
describe("httpql", () => {
describe("ast", () => {
const cases = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21,
];
for (const c of cases) {
it(`Case ${c}`, () => {
Expand Down
43 changes: 24 additions & 19 deletions js/httpql/src/parser/parser.terms.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This file was generated by lezer-generator. You probably shouldn't edit it.
export const BlockComment = 1,
export const
BlockComment = 1,
LineComment = 2,
HTTPQL = 3,
Query = 4,
Expand Down Expand Up @@ -33,21 +34,25 @@ export const BlockComment = 1,
BoolExpression = 32,
BoolOperator = 33,
BoolValue = 34,
ResponseClause = 35,
ResponseNamespace = 36,
ResponseIntFieldName = 37,
ResponseStringFieldName = 38,
PresetClause = 39,
PresetNamespace = 40,
PresetNameExpression = 41,
PresetAliasExpression = 42,
SymbolValue = 43,
SourceClause = 44,
SourceNamespace = 45,
SourceNameExpression = 46,
RightParen = 47,
LeftParen = 48,
GroupQuery = 49,
LogicalQuery = 50,
And = 51,
Or = 52;
RequestHeaderFieldName = 35,
RequestHeaderSubfieldName = 36,
LeftBracket = 37,
RightBracket = 38,
ResponseClause = 39,
ResponseNamespace = 40,
ResponseIntFieldName = 41,
ResponseStringFieldName = 42,
PresetClause = 43,
PresetNamespace = 44,
PresetNameExpression = 45,
PresetAliasExpression = 46,
SymbolValue = 47,
SourceClause = 48,
SourceNamespace = 49,
SourceNameExpression = 50,
RightParen = 51,
LeftParen = 52,
GroupQuery = 53,
LogicalQuery = 54,
And = 55,
Or = 56
Loading