Skip to content

Commit

Permalink
feat: convert field to object {name:}
Browse files Browse the repository at this point in the history
BREAKING CHANGE: changes field format
  • Loading branch information
gajus committed Sep 29, 2022
1 parent 38f0a0a commit 1becc83
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 99 deletions.
14 changes: 8 additions & 6 deletions src/grammar.ne
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ const range = ( minInclusive, maxInclusive) => {

const field = d => {
return {
field: d[0],
fieldPath: d[0].split('.').filter(Boolean),
field: {
name: d[0].name,
path: d[0].name.split('.').filter(Boolean),
},
...d[3]
}
};
Expand Down Expand Up @@ -91,12 +93,12 @@ post_boolean_primary ->

side ->
field ":" _ query {% field %}
| query {% d => ({field: '<implicit>', ...d[0]}) %}
| query {% d => ({field: {name: '<implicit>'}, ...d[0]}) %}

field ->
[_a-zA-Z$] [a-zA-Z\d_$.]:* {% d => d[0] + d[1].join('') %}
| sqstring {% id %}
| dqstring {% id %}
[_a-zA-Z$] [a-zA-Z\d_$.]:* {% d => ({name: d[0] + d[1].join('')}) %}
| sqstring {% d => ({name: d[0]}) %}
| dqstring {% d => ({name: d[0]}) %}

query ->
relational_operator _ decimal {% d => ({quoted: false, query: d[2], relationalOperator: d[0][0]}) %}
Expand Down
14 changes: 8 additions & 6 deletions src/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ const range = ( minInclusive, maxInclusive) => {

const field = d => {
return {
field: d[0],
fieldPath: d[0].split('.').filter(Boolean),
field: {
name: d[0].name,
path: d[0].name.split('.').filter(Boolean),
},
...d[3]
}
};
Expand Down Expand Up @@ -224,12 +226,12 @@ const grammar: Grammar = {
{"name": "post_boolean_primary", "symbols": [{"literal":"("}, "_", "boolean_primary", "_", {"literal":")"}], "postprocess": d => d[2]},
{"name": "post_boolean_primary", "symbols": ["__", "boolean_primary"], "postprocess": d => d[1]},
{"name": "side", "symbols": ["field", {"literal":":"}, "_", "query"], "postprocess": field},
{"name": "side", "symbols": ["query"], "postprocess": d => ({field: '<implicit>', ...d[0]})},
{"name": "side", "symbols": ["query"], "postprocess": d => ({field: {name: '<implicit>'}, ...d[0]})},
{"name": "field$ebnf$1", "symbols": []},
{"name": "field$ebnf$1", "symbols": ["field$ebnf$1", /[a-zA-Z\d_$.]/], "postprocess": (d) => d[0].concat([d[1]])},
{"name": "field", "symbols": [/[_a-zA-Z$]/, "field$ebnf$1"], "postprocess": d => d[0] + d[1].join('')},
{"name": "field", "symbols": ["sqstring"], "postprocess": id},
{"name": "field", "symbols": ["dqstring"], "postprocess": id},
{"name": "field", "symbols": [/[_a-zA-Z$]/, "field$ebnf$1"], "postprocess": d => ({name: d[0] + d[1].join('')})},
{"name": "field", "symbols": ["sqstring"], "postprocess": d => ({name: d[0]})},
{"name": "field", "symbols": ["dqstring"], "postprocess": d => ({name: d[0]})},
{"name": "query", "symbols": ["relational_operator", "_", "decimal"], "postprocess": d => ({quoted: false, query: d[2], relationalOperator: d[0][0]})},
{"name": "query", "symbols": ["decimal"], "postprocess": d => ({quoted: false, query: d.join('')})},
{"name": "query", "symbols": ["regex"], "postprocess": d => ({quoted: false, regex: true, query: d.join('')})},
Expand Down
6 changes: 3 additions & 3 deletions src/hydrateAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export const hydrateAst = (subject: ParserAst): HydratedAst => {

if (
optionalChainingIsSupported &&
typeof subject.field === 'string' &&
isSafePath(subject.field)
typeof subject.field?.name === 'string' &&
isSafePath(subject.field.name)
) {
newSubject.getValue = new Function('subject', createGetValueFunctionBody(subject.field)) as (subject: unknown) => unknown;
newSubject.getValue = new Function('subject', createGetValueFunctionBody(subject.field.name)) as (subject: unknown) => unknown;
}

if (subject.left) {
Expand Down
29 changes: 16 additions & 13 deletions src/internalFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,26 +128,26 @@ const testField = <T extends Object>(
ast.test = createValueTest(ast);
}

if (ast.field in row) {
if (ast.field.name in row) {
return testValue(
ast,
row[ast.field],
row[ast.field.name],
resultFast,
path,
highlights,
);
} else if (optionalChainingIsSupported && ast.getValue && ast.fieldPath) {
} else if (optionalChainingIsSupported && ast.getValue && ast.field.path) {
return testValue(
ast,
ast.getValue(row),
resultFast,
ast.fieldPath,
ast.field.path,
highlights,
);
} else if (ast.fieldPath) {
} else if (ast.field.path) {
let value = row;

for (const key of ast.fieldPath) {
for (const key of ast.field.path) {
if (typeof value !== 'object' || value === null) {
return false;
} else if (key in value) {
Expand All @@ -161,23 +161,26 @@ const testField = <T extends Object>(
ast,
value,
resultFast,
ast.fieldPath,
ast.field.path,
highlights,
);
} else if (ast.field === '<implicit>') {
} else if (ast.field.name === '<implicit>') {
let foundMatch = false;

for (const field in row) {
for (const fieldName in row) {
if (testValue(
{
...ast,
field,
field: {
...ast.field,
name: fieldName,
},
},
row[field],
row[fieldName],
resultFast,
[
...path,
field,
fieldName,
],
highlights,
)) {
Expand Down Expand Up @@ -208,7 +211,7 @@ export const internalFilter = <T extends Object>(
row,
ast,
resultFast,
ast.field === '<implicit>' ? path : [...path, ast.field],
ast.field.name === '<implicit>' ? path : [...path, ast.field.name],
highlights,
);
});
Expand Down
6 changes: 4 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ export type Range = {
export type RelationalOperator = '<' | '<=' | '=' | '>' | '>=';

export type ParserAst = {
field: string,
fieldPath?: readonly string[],
field: {
name: string,
path?: readonly string[],
},
left?: ParserAst,
operand?: ParserAst,
operator?: 'AND' | 'NOT' | 'OR',
Expand Down
38 changes: 28 additions & 10 deletions test/liqe/hydrateAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
if (isOptionalChainingSupported()) {
test('adds getValue when field is a safe path', (t) => {
const parserAst = {
field: '.foo',
field: {
name: '.foo',
},
};

const hydratedAst = hydrateAst(parserAst);
Expand All @@ -19,26 +21,36 @@ if (isOptionalChainingSupported()) {

test('adds getValue when field is a safe path (recursive)', (t) => {
const parserAst = {
field: '<implicit>',
field: {
name: '<implicit>',
},
left: {
field: '<implicit>',
field: {
name: '<implicit>',
},
right: {
field: '<implicit>',
field: {
name: '<implicit>',
},
operand: {
field: '.foo',
field: {
name: '.foo',
},
},
},
},
};

const hydratedAst = hydrateAst(parserAst);

t.true('getValue' in hydratedAst!.left!.right!.operand!);
t.true('getValue' in (hydratedAst?.left?.right?.operand ?? {}));
});

test('does not add getValue if path is unsafe', (t) => {
const parserAst = {
field: 'foo',
field: {
name: 'foo',
},
};

const hydratedAst = hydrateAst(parserAst);
Expand All @@ -48,7 +60,9 @@ if (isOptionalChainingSupported()) {

test('getValue accesses existing value', (t) => {
const parserAst = {
field: '.foo',
field: {
name: '.foo',
},
};

const hydratedAst = hydrateAst(parserAst);
Expand All @@ -58,7 +72,9 @@ if (isOptionalChainingSupported()) {

test('getValue accesses existing value (deep)', (t) => {
const parserAst = {
field: '.foo.bar.baz',
field: {
name: '.foo.bar.baz',
},
};

const hydratedAst = hydrateAst(parserAst);
Expand All @@ -68,7 +84,9 @@ if (isOptionalChainingSupported()) {

test('returns undefined if path does not resolve', (t) => {
const parserAst = {
field: '.foo.bar.baz',
field: {
name: '.foo.bar.baz',
},
};

const hydratedAst = hydrateAst(parserAst);
Expand Down
Loading

0 comments on commit 1becc83

Please sign in to comment.