From 13bae50dc5e619433acdf0fe50c5256ce11be099 Mon Sep 17 00:00:00 2001 From: Kevin Hinterlong Date: Thu, 18 Mar 2021 12:14:51 -0500 Subject: [PATCH 1/2] Update: Allow parameters in elide filters --- packages/data/addon/adapters/facts/elide.ts | 8 ++-- .../tests/unit/adapters/facts/elide-test.ts | 46 ++++++++----------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/packages/data/addon/adapters/facts/elide.ts b/packages/data/addon/adapters/facts/elide.ts index dacce1bb3..110e60784 100644 --- a/packages/data/addon/adapters/facts/elide.ts +++ b/packages/data/addon/adapters/facts/elide.ts @@ -110,7 +110,7 @@ export default class ElideFactsAdapter extends EmberObject implements NaviFactAd nbet: (f, v) => `${f}=lt=('${v[0]}'),${f}=gt=('${v[1]}')`, }; - private buildFilterStr(filters: Filter[], canonicalToAlias: Record, dataSourceName: string): string { + private buildFilterStr(filters: Filter[], canonicalToAlias: Record): string { const filterStrings = filters.map((filter) => { const { field, parameters, operator, values, type } = filter; @@ -124,9 +124,7 @@ export default class ElideFactsAdapter extends EmberObject implements NaviFactAd if (canonicalToAlias[canonicalName]) { fieldStr = canonicalToAlias[canonicalName]; } else { - this.assertAllDefaultParams(filter, dataSourceName); - // TODO: Non default Parameters cannot be specified in filters yet - fieldStr = getElideField(field, {}); + fieldStr = getElideField(field, parameters); } let filterVals = values.map((v) => escape(`${v}`)); @@ -177,7 +175,7 @@ export default class ElideFactsAdapter extends EmberObject implements NaviFactAd }) .join(' '); - const filterString = this.buildFilterStr(filters, columnCanonicalToAlias, request.dataSource); + const filterString = this.buildFilterStr(filters, columnCanonicalToAlias); filterString.length && args.push(`filter: "${filterString}"`); const sortStrings = sorts.map((sort) => { diff --git a/packages/data/tests/unit/adapters/facts/elide-test.ts b/packages/data/tests/unit/adapters/facts/elide-test.ts index 2ac2cc412..7aa809ae5 100644 --- a/packages/data/tests/unit/adapters/facts/elide-test.ts +++ b/packages/data/tests/unit/adapters/facts/elide-test.ts @@ -81,7 +81,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { const queryStr = adapter['dataQueryFromRequest'](TestRequest); assert.equal( queryStr, - `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time=ge=('2015-01-03');time=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, + `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time(grain:\\"day\\")=ge=('2015-01-03');time(grain:\\"day\\")=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, 'dataQueryFromRequestV2 returns the correct query string for the given request V2' ); @@ -300,7 +300,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { const expectedColumns = TestRequest.columns .map((c, idx) => getElideField(c.field, c.parameters, `col${idx}`)) .join(' '); - const expectedArgs = `(filter: "d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time=ge=('2015-01-03');time=lt=('2015-01-04');col0=gt=('0')",sort: "col3",first: "10000")`; + const expectedArgs = `(filter: "d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time(grain:"day")=ge=('2015-01-03');time(grain:"day")=lt=('2015-01-04');col0=gt=('0')",sort: "col3",first: "10000")`; assert.equal( requestObj.variables.query.replace(/[ \t\r\n]+/g, ' '), @@ -581,7 +581,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { //test all of the escaped functionalities and verify them in the below assert assert.equal( queryStr, - `{"query":"{ table1(filter: \\"d6=in=('with, comma','no comma');d7=in=('with \\"quote\\"','but why');d8=in=('okay','with \\\\\\\\'single quote\\\\\\\\'')\\",sort: \\"d1\\",first: \\"10000\\") { edges { node { } } } }"}`, + `{"query":"{ table1(filter: \\"d6(field:\\"id\\")=in=('with, comma','no comma');d7(field:\\"id\\")=in=('with \\"quote\\"','but why');d8(field:\\"id\\")=in=('okay','with \\\\\\\\'single quote\\\\\\\\'')\\",sort: \\"d1\\",first: \\"10000\\") { edges { node { } } } }"}`, 'dataQueryFromRequestV2 returns the correct query string with escaped quotes and commas for the given request V2' ); }); @@ -605,7 +605,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { }, ]; assert.equal( - adapter['buildFilterStr'](filters, { 'table1.dim1(p=q)': 'col1' }, 'elideData'), + adapter['buildFilterStr'](filters, { 'table1.dim1(p=q)': 'col1' }), "col1=in=('*v1*');dim1=in=('*v2*')", '`buildFilterStr` builds correct filter string for an aliased column' ); @@ -623,7 +623,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { }, ]; assert.equal( - adapter['buildFilterStr'](filters, {}, 'elideData'), + adapter['buildFilterStr'](filters, {}), "dim1=in=('*v1*')", '`buildFilterStr` builds correct filter string for a `contains` filter' ); @@ -638,7 +638,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { }, ]; assert.equal( - adapter['buildFilterStr'](escapedFilter, {}, 'elideData'), + adapter['buildFilterStr'](escapedFilter, {}), "dim1=in=('*\\\\'*')", '`buildFilterStr` builds correct filter string for a `contains` filter and escaped value' ); @@ -656,7 +656,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { }, ]; assert.equal( - adapter['buildFilterStr'](noValues, {}, 'elideData'), + adapter['buildFilterStr'](noValues, {}), '', '`buildFilterStr` returns an empty string if no filters have values' ); @@ -678,7 +678,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { }, ]; assert.equal( - adapter['buildFilterStr'](someValues, {}, 'elideData'), + adapter['buildFilterStr'](someValues, {}), "dim2==('1')", '`buildFilterStr` filters out filters with empty values' ); @@ -702,31 +702,23 @@ module('Unit | Adapter | facts/elide', function (hooks) { values: ['test'], }, ]; - assert.throws( - () => adapter['buildFilterStr'](noValues, {}, 'elideData'), - /FactAdapterError: Parameters are not supported in elide unles table1.dim1\(param=val\) is added as a column./, - '`buildFilterStr` throws an error when there is no alias if non-default params are used' + assert.deepEqual( + adapter['buildFilterStr'](noValues, {}), + 'dim1(param:"val")=in=(\'*test*\')', + '`buildFilterStr` returns a filter when there is no alias if params are used' ); DefaultParams = { param: 'notval' }; - assert.throws( - () => adapter['buildFilterStr'](noValues, {}, 'elideData'), - /FactAdapterError: Parameters are not supported in elide unles table1.dim1\(param=val\) is added as a column./, - '`buildFilterStr` throws an error when there is no alias if non-default params are used' - ); - assert.deepEqual( - adapter['buildFilterStr'](noValues, { 'table1.dim1(param=val)': 'col1' }, 'elideData'), - `col1=in=('*test*')`, - '`buildFilterStr` returns alias if available when there are non-default params' + adapter['buildFilterStr'](noValues, {}), + 'dim1(param:"val")=in=(\'*test*\')', + '`buildFilterStr` returns a filter when there is no alias if non-default params are used' ); - DefaultParams = { param: 'val' }; - assert.deepEqual( - adapter['buildFilterStr'](noValues, {}, 'elideData'), - `dim1=in=('*test*')`, - '`buildFilterStr` returns a filter with no parameters when all are default' + adapter['buildFilterStr'](noValues, { 'table1.dim1(param=val)': 'col1' }), + `col1=in=('*test*')`, + '`buildFilterStr` returns alias if available' ); }); @@ -735,7 +727,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { const adapter: ElideFactsAdapter = this.owner.lookup('adapter:facts/elide'); assert.equal( decodeURIComponent(adapter.urlForFindQuery(TestRequest, {})), - `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time=ge=('2015-01-03');time=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, + `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time(grain:\\"day\\")=ge=('2015-01-03');time(grain:\\"day\\")=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, 'urlForFindQuery correctly built the query for the provided request' ); }); From 1873bae9b6cdea9cad2091b8f5815222c31af6b4 Mon Sep 17 00:00:00 2001 From: Kevin Hinterlong Date: Fri, 19 Mar 2021 10:46:35 -0500 Subject: [PATCH 2/2] Update: Fix Elide filter param format --- packages/data/addon/adapters/facts/elide.ts | 18 ++++++++++++++++-- .../tests/unit/adapters/facts/elide-test.ts | 12 ++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/data/addon/adapters/facts/elide.ts b/packages/data/addon/adapters/facts/elide.ts index 110e60784..190bb4342 100644 --- a/packages/data/addon/adapters/facts/elide.ts +++ b/packages/data/addon/adapters/facts/elide.ts @@ -34,7 +34,7 @@ import { omitBy } from 'lodash-es'; const escape = (value: string) => value.replace(/'/g, "\\\\'"); /** - * Formats elide request field + * Formats elide request field as `col(param1:"val1", param2:"val2")` */ export function getElideField(fieldName: string, parameters: Parameters = {}, alias?: string) { const aliasStr = alias ? `${alias}:` : ''; @@ -50,6 +50,20 @@ export function getElideField(fieldName: string, parameters: Parameters = {}, al return `${aliasStr}${field}${paramsStr}`; } +/** + * Formats elide filter field as `col[param1:val1][param2:val2]` + */ +export function getElideFilterField(fieldName: string, parameters: Parameters = {}) { + const parts = fieldName.split('.'); + const field = parts[parts.length - 1]; + + const paramsStr = Object.entries(parameters) + .map(([param, val]) => `[${param}:${val}]`) + .join(''); + + return `${field}${paramsStr}`; +} + export default class ElideFactsAdapter extends EmberObject implements NaviFactAdapter { /** * @property {Object} apollo - apollo client query manager using the overridden elide service @@ -124,7 +138,7 @@ export default class ElideFactsAdapter extends EmberObject implements NaviFactAd if (canonicalToAlias[canonicalName]) { fieldStr = canonicalToAlias[canonicalName]; } else { - fieldStr = getElideField(field, parameters); + fieldStr = getElideFilterField(field, parameters); } let filterVals = values.map((v) => escape(`${v}`)); diff --git a/packages/data/tests/unit/adapters/facts/elide-test.ts b/packages/data/tests/unit/adapters/facts/elide-test.ts index 7aa809ae5..34dc31ace 100644 --- a/packages/data/tests/unit/adapters/facts/elide-test.ts +++ b/packages/data/tests/unit/adapters/facts/elide-test.ts @@ -81,7 +81,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { const queryStr = adapter['dataQueryFromRequest'](TestRequest); assert.equal( queryStr, - `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time(grain:\\"day\\")=ge=('2015-01-03');time(grain:\\"day\\")=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, + `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time[grain:day]=ge=('2015-01-03');time[grain:day]=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, 'dataQueryFromRequestV2 returns the correct query string for the given request V2' ); @@ -300,7 +300,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { const expectedColumns = TestRequest.columns .map((c, idx) => getElideField(c.field, c.parameters, `col${idx}`)) .join(' '); - const expectedArgs = `(filter: "d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time(grain:"day")=ge=('2015-01-03');time(grain:"day")=lt=('2015-01-04');col0=gt=('0')",sort: "col3",first: "10000")`; + const expectedArgs = `(filter: "d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time[grain:day]=ge=('2015-01-03');time[grain:day]=lt=('2015-01-04');col0=gt=('0')",sort: "col3",first: "10000")`; assert.equal( requestObj.variables.query.replace(/[ \t\r\n]+/g, ' '), @@ -581,7 +581,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { //test all of the escaped functionalities and verify them in the below assert assert.equal( queryStr, - `{"query":"{ table1(filter: \\"d6(field:\\"id\\")=in=('with, comma','no comma');d7(field:\\"id\\")=in=('with \\"quote\\"','but why');d8(field:\\"id\\")=in=('okay','with \\\\\\\\'single quote\\\\\\\\'')\\",sort: \\"d1\\",first: \\"10000\\") { edges { node { } } } }"}`, + `{"query":"{ table1(filter: \\"d6[field:id]=in=('with, comma','no comma');d7[field:id]=in=('with \\"quote\\"','but why');d8[field:id]=in=('okay','with \\\\\\\\'single quote\\\\\\\\'')\\",sort: \\"d1\\",first: \\"10000\\") { edges { node { } } } }"}`, 'dataQueryFromRequestV2 returns the correct query string with escaped quotes and commas for the given request V2' ); }); @@ -704,14 +704,14 @@ module('Unit | Adapter | facts/elide', function (hooks) { ]; assert.deepEqual( adapter['buildFilterStr'](noValues, {}), - 'dim1(param:"val")=in=(\'*test*\')', + "dim1[param:val]=in=('*test*')", '`buildFilterStr` returns a filter when there is no alias if params are used' ); DefaultParams = { param: 'notval' }; assert.deepEqual( adapter['buildFilterStr'](noValues, {}), - 'dim1(param:"val")=in=(\'*test*\')', + "dim1[param:val]=in=('*test*')", '`buildFilterStr` returns a filter when there is no alias if non-default params are used' ); @@ -727,7 +727,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { const adapter: ElideFactsAdapter = this.owner.lookup('adapter:facts/elide'); assert.equal( decodeURIComponent(adapter.urlForFindQuery(TestRequest, {})), - `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time(grain:\\"day\\")=ge=('2015-01-03');time(grain:\\"day\\")=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, + `{"query":"{ table1(filter: \\"d3=in=('v1','v2');d4=in=('v3','v4');d5=isnull=true;time[grain:day]=ge=('2015-01-03');time[grain:day]=lt=('2015-01-04');col0=gt=('0')\\",sort: \\"col3\\",first: \\"10000\\") { edges { node { col0:m1 col1:m2 col2:r(p:\\"123\\") col3:d1 col4:d2 } } } }"}`, 'urlForFindQuery correctly built the query for the provided request' ); });