Skip to content
Snippets Groups Projects
Commit 2950efcc authored by Marcos Pieras's avatar Marcos Pieras
Browse files

fix: handle objects as it was in go

parent b8bcfc36
No related branches found
Tags v1.18.0
No related merge requests found
Pipeline #141509 passed
import { Record, Node, Relationship, Path, PathSegment, isRelationship, isNode, isPath, isPathSegment, Integer } from 'neo4j-driver'; import { Record, Node, Relationship, Path, PathSegment, isRelationship, isNode, isPath, isPathSegment, Integer } from "neo4j-driver";
import { log } from '../../logger'; import { log } from "../../logger";
import type { EdgeQueryResult, NodeQueryResult } from 'ts-common'; import type { EdgeQueryResult, NodeQueryResult } from "ts-common";
import type { GraphQueryResultFromBackend } from 'ts-common'; import type { GraphQueryResultFromBackend } from "ts-common";
export function parseCypherQuery(result: Record[], returnType: "nodelink" | "table" = "nodelink"): GraphQueryResultFromBackend { export function parseCypherQuery(result: Record[], returnType: "nodelink" | "table" = "nodelink"): GraphQueryResultFromBackend {
try {
try { try {
try { switch (returnType) {
switch (returnType) { case "nodelink":
case "nodelink": return parseNodeLinkQuery(result);
return parseNodeLinkQuery(result); case "table":
case "table": // TODO: add table support later
// TODO: add table support later // return parseGroupByQuery(result.records as any);
// return parseGroupByQuery(result.records as any); log.error(`Table format not supported yet`);
log.error(`Table format not supported yet`); throw new Error("Table format not supported yet");
throw new Error("Table format not supported yet"); default:
default: log.error(`Error Unknown query Format`);
log.error(`Error Unknown query Format`); throw new Error("Unknown query Format");
throw new Error("Unknown query Format"); }
}
} catch (err) {
log.error(`Parsing failed ${err}`);
throw err;
}
} catch (err) { } catch (err) {
log.error(`Error executing query`, err); log.error(`Parsing failed ${err}`);
throw err; throw err;
} }
} catch (err) {
log.error(`Error executing query`, err);
throw err;
}
} }
function parseNodeLinkQuery(results: Record[]): GraphQueryResultFromBackend { function parseNodeLinkQuery(results: Record[]): GraphQueryResultFromBackend {
let nodes: NodeQueryResult[] = []; let nodes: NodeQueryResult[] = [];
let edges: EdgeQueryResult[] = []; let edges: EdgeQueryResult[] = [];
let nodeIds: Set<string> = new Set(); let nodeIds: Set<string> = new Set();
let edgeIds: Set<string> = new Set(); let edgeIds: Set<string> = new Set();
const result: GraphQueryResultFromBackend = { nodes, edges }; const result: GraphQueryResultFromBackend = { nodes, edges };
for (let i = 0; i < results.length; i++) { for (let i = 0; i < results.length; i++) {
const resList = results[i]; const resList = results[i];
for (let j = 0; j < resList.length; j++) { for (let j = 0; j < resList.length; j++) {
const res = resList.get(j); const res = resList.get(j);
parseNodeLinkEntity(res, nodes, edges, nodeIds, edgeIds); parseNodeLinkEntity(res, nodes, edges, nodeIds, edgeIds);
}
} }
}
return result; return result;
} }
function parseNodeLinkEntity(res: Node | Relationship | Path | PathSegment, nodes: NodeQueryResult[], edges: EdgeQueryResult[], nodeIds: Set<string>, edgeIds: Set<string>): void { function parseNodeLinkEntity(
if (isRelationship(res)) { res: Node | Relationship | Path | PathSegment,
const neoEdge = parseEdge(res); nodes: NodeQueryResult[],
if (!edgeIds.has(neoEdge._id)) { edges: EdgeQueryResult[],
edgeIds.add(neoEdge._id); nodeIds: Set<string>,
edges.push(neoEdge); edgeIds: Set<string>
} ): void {
} else if (isNode(res)) { if (isRelationship(res)) {
const neoNode = parseNode(res); const neoEdge = parseEdge(res);
if (!nodeIds.has(neoNode._id)) { if (!edgeIds.has(neoEdge._id)) {
nodeIds.add(neoNode._id); edgeIds.add(neoEdge._id);
nodes.push(neoNode); edges.push(neoEdge);
} }
} else if (isPath(res)) { } else if (isNode(res)) {
parseNodeLinkEntity(res.start, nodes, edges, nodeIds, edgeIds); const neoNode = parseNode(res);
for (const segment of res.segments) { if (!nodeIds.has(neoNode._id)) {
parseNodeLinkEntity(segment.relationship, nodes, edges, nodeIds, edgeIds); nodeIds.add(neoNode._id);
parseNodeLinkEntity(segment.end, nodes, edges, nodeIds, edgeIds); nodes.push(neoNode);
} }
parseNodeLinkEntity(res.end, nodes, edges, nodeIds, edgeIds); } else if (isPath(res)) {
} else if (isPathSegment(res)) { parseNodeLinkEntity(res.start, nodes, edges, nodeIds, edgeIds);
parseNodeLinkEntity(res.start, nodes, edges, nodeIds, edgeIds); for (const segment of res.segments) {
parseNodeLinkEntity(res.relationship, nodes, edges, nodeIds, edgeIds); parseNodeLinkEntity(segment.relationship, nodes, edges, nodeIds, edgeIds);
parseNodeLinkEntity(res.end, nodes, edges, nodeIds, edgeIds); parseNodeLinkEntity(segment.end, nodes, edges, nodeIds, edgeIds);
} else {
log.warn(`Ignoring Unknown type ${res}`);
} }
parseNodeLinkEntity(res.end, nodes, edges, nodeIds, edgeIds);
} else if (isPathSegment(res)) {
parseNodeLinkEntity(res.start, nodes, edges, nodeIds, edgeIds);
parseNodeLinkEntity(res.relationship, nodes, edges, nodeIds, edgeIds);
parseNodeLinkEntity(res.end, nodes, edges, nodeIds, edgeIds);
} else {
log.warn(`Ignoring Unknown type ${res}`);
}
} }
function parseNode(node: Node): NodeQueryResult { function parseNode(node: Node): NodeQueryResult {
return { return {
_id: node.identity.toString(), _id: node.identity.toString(),
label: node.labels[0], // TODO: only using first label label: node.labels[0], // TODO: only using first label
attributes: Object.fromEntries(Object.entries(node.properties)?.map(([k, v]) => { attributes: Object.fromEntries(
if (Integer.isInteger(v)) { Object.entries(node.properties)?.map(([k, v]) => {
return [k, v.toNumber()]; if (Integer.isInteger(v)) {
} return [k, v.toNumber()];
}
if (v instanceof Object) { return [k, v];
// TODO: for now, we don't support nested objects })
return [k, JSON.stringify(v)]; ),
} };
return [k, v];
})),
};
} }
function parseEdge(edge: Relationship): EdgeQueryResult { function parseEdge(edge: Relationship): EdgeQueryResult {
return { return {
_id: edge.identity.toString(), _id: edge.identity.toString(),
label: edge.type, label: edge.type,
from: edge.start.toString(), from: edge.start.toString(),
to: edge.end.toString(), to: edge.end.toString(),
attributes: { ...edge.properties, type: edge.type }, attributes: { ...edge.properties, type: edge.type },
}; };
} }
function parseGroupByQuery(results: Record<any, string>[]): any { function parseGroupByQuery(results: Record<any, string>[]): any {
// TODO: not tested, since we don't use this yet // TODO: not tested, since we don't use this yet
let groupKey: string; let groupKey: string;
let byKey: string; let byKey: string;
const group: string[] = []; const group: string[] = [];
const by: string[] = []; const by: string[] = [];
const result: { [key: string]: any } = {}; const result: { [key: string]: any } = {};
if (results[0].keys.length !== 2) { if (results[0].keys.length !== 2) {
throw new Error("invalid result format"); throw new Error("invalid result format");
} }
// Checks if the first letter of the first key is either an e or an r, since that would make it the By-key // Checks if the first letter of the first key is either an e or an r, since that would make it the By-key
// By-keys start with e0_attr or r0_attr and group keys with an aggregation funcion such as AVG_attr or MIN_attr // By-keys start with e0_attr or r0_attr and group keys with an aggregation funcion such as AVG_attr or MIN_attr
// This will work when an aggregation function starts with an E or R, since e != E // This will work when an aggregation function starts with an E or R, since e != E
if (results[0].keys[0][0] === 'e' || results[0].keys[0][0] === 'r') { if (results[0].keys[0][0] === "e" || results[0].keys[0][0] === "r") {
byKey = results[0].keys[0]; byKey = results[0].keys[0];
groupKey = results[0].keys[1]; groupKey = results[0].keys[1];
} else { } else {
byKey = results[0].keys[1]; byKey = results[0].keys[1];
groupKey = results[0].keys[0]; groupKey = results[0].keys[0];
}
// Form proper result structure
for (const res of results) {
const g = res.get(groupKey);
const b = res.get(byKey);
if (g !== null && b !== null) {
group.push(g.toString());
by.push(b.toString());
} }
}
// Form proper result structure result["group"] = { name: groupKey, values: group };
for (const res of results) { result["by"] = { name: byKey, values: by };
const g = res.get(groupKey);
const b = res.get(byKey);
if (g !== null && b !== null) { return result;
group.push(g.toString()); }
by.push(b.toString());
}
}
result["group"] = { name: groupKey, values: group };
result["by"] = { name: byKey, values: by };
return result;
}
\ No newline at end of file
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