Skip to content
Snippets Groups Projects
Commit b1c4f1f4 authored by Leonardo's avatar Leonardo
Browse files

fix: relation based logic query when query is more complex

parent 162864ef
No related branches found
Tags v1.15.2
No related merge requests found
Pipeline #144565 failed
...@@ -11,4 +11,5 @@ export interface EntityCacheData { ...@@ -11,4 +11,5 @@ export interface EntityCacheData {
export interface QueryCacheData { export interface QueryCacheData {
entities: EntityCacheData[]; entities: EntityCacheData[];
relations: RelationCacheData[]; relations: RelationCacheData[];
unwinds: string[];
} }
...@@ -2,7 +2,7 @@ import type { NodeStruct } from 'ts-common'; ...@@ -2,7 +2,7 @@ import type { NodeStruct } from 'ts-common';
import type { QueryCacheData } from './model'; import type { QueryCacheData } from './model';
import { getRelationCypher } from './relation'; import { getRelationCypher } from './relation';
export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] { export function getNodeCypher(JSONQuery: NodeStruct, cacheData: QueryCacheData): [string, QueryCacheData] {
let label = ''; let label = '';
if (JSONQuery.label) { if (JSONQuery.label) {
label = `:${JSONQuery.label}`; label = `:${JSONQuery.label}`;
...@@ -12,8 +12,6 @@ export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] { ...@@ -12,8 +12,6 @@ export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] {
id = JSONQuery.id; id = JSONQuery.id;
} }
const cacheData: QueryCacheData = { entities: [], relations: [] };
if (id) { if (id) {
cacheData.entities.push({ id, queryId: '' }); cacheData.entities.push({ id, queryId: '' });
} }
...@@ -21,11 +19,9 @@ export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] { ...@@ -21,11 +19,9 @@ export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] {
let cypher = `(${id}${label})`; let cypher = `(${id}${label})`;
if (JSONQuery.relation) { if (JSONQuery.relation) {
const [relationCypher, subCache] = getRelationCypher(JSONQuery.relation); const [relationCypher, _cacheData] = getRelationCypher(JSONQuery.relation, cacheData);
if (relationCypher) { if (relationCypher) {
cacheData.entities.push(...subCache.entities);
cacheData.relations.push(...subCache.relations);
if (JSONQuery.relation.direction === 'FROM') { if (JSONQuery.relation.direction === 'FROM') {
cypher += `<-${relationCypher}`; cypher += `<-${relationCypher}`;
} else if (JSONQuery.relation.direction === 'TO') { } else if (JSONQuery.relation.direction === 'TO') {
...@@ -34,6 +30,7 @@ export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] { ...@@ -34,6 +30,7 @@ export function getNodeCypher(JSONQuery: NodeStruct): [string, QueryCacheData] {
cypher += `-${relationCypher}`; cypher += `-${relationCypher}`;
} }
} }
return [cypher, _cacheData];
} }
return [cypher, cacheData]; return [cypher, cacheData];
} }
...@@ -532,4 +532,99 @@ describe('query2Cypher', () => { ...@@ -532,4 +532,99 @@ describe('query2Cypher', () => {
expect(fixCypherSpaces(cypher)).toBe(fixCypherSpaces(expectedCypher)); expect(fixCypherSpaces(cypher)).toBe(fixCypherSpaces(expectedCypher));
}); });
it('should return correctly on a query with boolean logic in relation', () => {
const query: BackendQueryFormat = {
saveStateID: '31966faf-0741-4a70-b92b-62c4b5e25d91',
query: [
{
id: 'path_0',
node: {
id: 'id_1737115397734',
label: 'Product',
relation: {
id: 'id_1737115397848',
label: 'PRODUCT_MATERIAL',
depth: {
max: 1,
min: 1,
},
direction: 'TO',
node: {
id: 'id_1737115397423',
label: 'Material',
},
},
},
},
{
id: 'path_1',
node: {
id: 'id_1737115397734',
label: 'Product',
relation: {
id: 'id_1737115611667',
label: 'DEPARTS_FROM',
depth: {
max: 1,
min: 1,
},
direction: 'TO',
node: {
id: 'id_1737115612952',
label: 'Country',
relation: {
id: 'id_1737115886717',
label: 'CountryFlow',
depth: {
max: 1,
min: 1,
},
direction: 'TO',
node: {
id: 'id_1737115684010',
label: 'Country',
},
},
},
},
},
},
{
id: 'path_2',
node: {
id: 'id_1737115397734',
label: 'Product',
relation: {
id: 'id_1737115682374',
label: 'ARRIVES_AT',
depth: {
max: 1,
min: 1,
},
direction: 'TO',
node: {
id: 'id_1737115684010',
label: 'Country',
},
},
},
},
],
machineLearning: [],
limit: 100,
return: ['*'],
cached: false,
logic: ['And', ['==', '@id_1737115397423.GO', '"852349"'], ['==', '@id_1737115886717.goodFlow', 'false']],
};
const cypher = query2Cypher(query);
const expectedCypher = `MATCH path_0 = ((id_1737115397734:Product)-[id_1737115397848:PRODUCT_MATERIAL*1..1]->(id_1737115397423:Material))
MATCH path_1 = ((id_1737115397734:Product)-[id_1737115611667:DEPARTS_FROM*1..1]->(id_1737115612952:Country)-[id_1737115886717:CountryFlow*1..1]->(id_1737115684010:Country))
MATCH path_2 = ((id_1737115397734:Product)-[id_1737115682374:ARRIVES_AT*1..1]->(id_1737115684010:Country))
WHERE ALL(path_2_rel_id_1737115886717 in id_1737115886717 WHERE ((id_1737115397423.GO = "852349") and
(path_2_rel_id_1737115886717.goodFlow = false))) RETURN * LIMIT 100`;
expect(fixCypherSpaces(cypher)).toEqual(fixCypherSpaces(expectedCypher));
});
}); });
...@@ -13,12 +13,12 @@ import { getNodeCypher } from './node'; ...@@ -13,12 +13,12 @@ import { getNodeCypher } from './node';
export function query2Cypher(JSONQuery: BackendQueryFormat): string | null { export function query2Cypher(JSONQuery: BackendQueryFormat): string | null {
let totalQuery = ''; let totalQuery = '';
let matchQuery = ''; let matchQuery = '';
let cacheData: QueryCacheData = { entities: [], relations: [] }; let cacheData: QueryCacheData = { entities: [], relations: [], unwinds: [] };
// MATCH block // MATCH block
for (const query of JSONQuery.query) { for (const query of JSONQuery.query) {
let match = 'MATCH '; let match = 'MATCH ';
const [nodeCypher, _cacheData] = getNodeCypher(query.node); const [nodeCypher, _cacheData] = getNodeCypher(query.node, cacheData);
cacheData = _cacheData; cacheData = _cacheData;
for (let i = 0; i < cacheData.entities.length; i++) { for (let i = 0; i < cacheData.entities.length; i++) {
......
...@@ -4,8 +4,9 @@ import type { QueryCacheData } from './model'; ...@@ -4,8 +4,9 @@ import type { QueryCacheData } from './model';
export const NoNodeError = new Error('relation must have a node'); export const NoNodeError = new Error('relation must have a node');
export function getRelationCypher(JSONQuery: RelationStruct): [string | undefined, QueryCacheData] { export function getRelationCypher(JSONQuery: RelationStruct, cacheData: QueryCacheData): [string | undefined, QueryCacheData] {
let label = ''; let label = '';
if (JSONQuery.label) { if (JSONQuery.label) {
label = `:${JSONQuery.label}`; label = `:${JSONQuery.label}`;
} }
...@@ -14,12 +15,13 @@ export function getRelationCypher(JSONQuery: RelationStruct): [string | undefine ...@@ -14,12 +15,13 @@ export function getRelationCypher(JSONQuery: RelationStruct): [string | undefine
id = JSONQuery.id; id = JSONQuery.id;
} }
let depth = ''; let depth = '';
if (JSONQuery.depth) { if (JSONQuery.depth) {
// && JSONQuery.depth.min !== 1 && JSONQuery.depth.max !== 1
depth = `*${JSONQuery.depth.min}..${JSONQuery.depth.max}`; depth = `*${JSONQuery.depth.min}..${JSONQuery.depth.max}`;
cacheData.unwinds.push(id + '_unwind');
} }
const cacheData: QueryCacheData = { entities: [], relations: [] };
if (id) { if (id) {
cacheData.relations.push({ id, queryId: '' }); cacheData.relations.push({ id, queryId: '' });
} }
...@@ -29,11 +31,8 @@ export function getRelationCypher(JSONQuery: RelationStruct): [string | undefine ...@@ -29,11 +31,8 @@ export function getRelationCypher(JSONQuery: RelationStruct): [string | undefine
if (!JSONQuery.node) { if (!JSONQuery.node) {
return [undefined, cacheData]; return [undefined, cacheData];
} }
const [nodeCypher, _cacheData] = getNodeCypher(JSONQuery.node, cacheData);
const [nodeCypher, subCache] = getNodeCypher(JSONQuery.node);
cacheData.entities.push(...subCache.entities);
cacheData.relations.push(...subCache.relations);
if (JSONQuery.direction === 'TO') { if (JSONQuery.direction === 'TO') {
cypher += `->${nodeCypher}`; cypher += `->${nodeCypher}`;
} else if (JSONQuery.direction === 'FROM') { } else if (JSONQuery.direction === 'FROM') {
...@@ -41,5 +40,5 @@ export function getRelationCypher(JSONQuery: RelationStruct): [string | undefine ...@@ -41,5 +40,5 @@ export function getRelationCypher(JSONQuery: RelationStruct): [string | undefine
} else { } else {
cypher += `-${nodeCypher}`; cypher += `-${nodeCypher}`;
} }
return [cypher, cacheData]; return [cypher, _cacheData];
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment