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 tags found
No related merge requests found
Pipeline #141509 passed
import { Record, Node, Relationship, Path, PathSegment, isRelationship, isNode, isPath, isPathSegment, Integer } from 'neo4j-driver';
import { log } from '../../logger';
import type { EdgeQueryResult, NodeQueryResult } from 'ts-common';
import type { GraphQueryResultFromBackend } from 'ts-common';
import { Record, Node, Relationship, Path, PathSegment, isRelationship, isNode, isPath, isPathSegment, Integer } from "neo4j-driver";
import { log } from "../../logger";
import type { EdgeQueryResult, NodeQueryResult } from "ts-common";
import type { GraphQueryResultFromBackend } from "ts-common";
export function parseCypherQuery(result: Record[], returnType: "nodelink" | "table" = "nodelink"): GraphQueryResultFromBackend {
try {
try {
try {
switch (returnType) {
case "nodelink":
return parseNodeLinkQuery(result);
case "table":
// TODO: add table support later
// return parseGroupByQuery(result.records as any);
log.error(`Table format not supported yet`);
throw new Error("Table format not supported yet");
default:
log.error(`Error Unknown query Format`);
throw new Error("Unknown query Format");
}
} catch (err) {
log.error(`Parsing failed ${err}`);
throw err;
}
switch (returnType) {
case "nodelink":
return parseNodeLinkQuery(result);
case "table":
// TODO: add table support later
// return parseGroupByQuery(result.records as any);
log.error(`Table format not supported yet`);
throw new Error("Table format not supported yet");
default:
log.error(`Error Unknown query Format`);
throw new Error("Unknown query Format");
}
} catch (err) {
log.error(`Error executing query`, err);
throw err;
log.error(`Parsing failed ${err}`);
throw err;
}
} catch (err) {
log.error(`Error executing query`, err);
throw err;
}
}
function parseNodeLinkQuery(results: Record[]): GraphQueryResultFromBackend {
let nodes: NodeQueryResult[] = [];
let edges: EdgeQueryResult[] = [];
let nodeIds: Set<string> = new Set();
let edgeIds: Set<string> = new Set();
const result: GraphQueryResultFromBackend = { nodes, edges };
for (let i = 0; i < results.length; i++) {
const resList = results[i];
for (let j = 0; j < resList.length; j++) {
const res = resList.get(j);
parseNodeLinkEntity(res, nodes, edges, nodeIds, edgeIds);
}
let nodes: NodeQueryResult[] = [];
let edges: EdgeQueryResult[] = [];
let nodeIds: Set<string> = new Set();
let edgeIds: Set<string> = new Set();
const result: GraphQueryResultFromBackend = { nodes, edges };
for (let i = 0; i < results.length; i++) {
const resList = results[i];
for (let j = 0; j < resList.length; j++) {
const res = resList.get(j);
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 {
if (isRelationship(res)) {
const neoEdge = parseEdge(res);
if (!edgeIds.has(neoEdge._id)) {
edgeIds.add(neoEdge._id);
edges.push(neoEdge);
}
} else if (isNode(res)) {
const neoNode = parseNode(res);
if (!nodeIds.has(neoNode._id)) {
nodeIds.add(neoNode._id);
nodes.push(neoNode);
}
} else if (isPath(res)) {
parseNodeLinkEntity(res.start, nodes, edges, nodeIds, edgeIds);
for (const segment of res.segments) {
parseNodeLinkEntity(segment.relationship, nodes, edges, nodeIds, edgeIds);
parseNodeLinkEntity(segment.end, nodes, edges, nodeIds, edgeIds);
}
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 parseNodeLinkEntity(
res: Node | Relationship | Path | PathSegment,
nodes: NodeQueryResult[],
edges: EdgeQueryResult[],
nodeIds: Set<string>,
edgeIds: Set<string>
): void {
if (isRelationship(res)) {
const neoEdge = parseEdge(res);
if (!edgeIds.has(neoEdge._id)) {
edgeIds.add(neoEdge._id);
edges.push(neoEdge);
}
} else if (isNode(res)) {
const neoNode = parseNode(res);
if (!nodeIds.has(neoNode._id)) {
nodeIds.add(neoNode._id);
nodes.push(neoNode);
}
} else if (isPath(res)) {
parseNodeLinkEntity(res.start, nodes, edges, nodeIds, edgeIds);
for (const segment of res.segments) {
parseNodeLinkEntity(segment.relationship, nodes, edges, nodeIds, edgeIds);
parseNodeLinkEntity(segment.end, nodes, edges, nodeIds, edgeIds);
}
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 {
return {
_id: node.identity.toString(),
label: node.labels[0], // TODO: only using first label
attributes: Object.fromEntries(Object.entries(node.properties)?.map(([k, v]) => {
if (Integer.isInteger(v)) {
return [k, v.toNumber()];
}
return {
_id: node.identity.toString(),
label: node.labels[0], // TODO: only using first label
attributes: Object.fromEntries(
Object.entries(node.properties)?.map(([k, v]) => {
if (Integer.isInteger(v)) {
return [k, v.toNumber()];
}
if (v instanceof Object) {
// TODO: for now, we don't support nested objects
return [k, JSON.stringify(v)];
}
return [k, v];
})),
};
return [k, v];
})
),
};
}
function parseEdge(edge: Relationship): EdgeQueryResult {
return {
_id: edge.identity.toString(),
label: edge.type,
from: edge.start.toString(),
to: edge.end.toString(),
attributes: { ...edge.properties, type: edge.type },
};
return {
_id: edge.identity.toString(),
label: edge.type,
from: edge.start.toString(),
to: edge.end.toString(),
attributes: { ...edge.properties, type: edge.type },
};
}
function parseGroupByQuery(results: Record<any, string>[]): any {
// TODO: not tested, since we don't use this yet
let groupKey: string;
let byKey: string;
const group: string[] = [];
const by: string[] = [];
const result: { [key: string]: any } = {};
if (results[0].keys.length !== 2) {
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
// 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
if (results[0].keys[0][0] === 'e' || results[0].keys[0][0] === 'r') {
byKey = results[0].keys[0];
groupKey = results[0].keys[1];
} else {
byKey = results[0].keys[1];
groupKey = results[0].keys[0];
// TODO: not tested, since we don't use this yet
let groupKey: string;
let byKey: string;
const group: string[] = [];
const by: string[] = [];
const result: { [key: string]: any } = {};
if (results[0].keys.length !== 2) {
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
// 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
if (results[0].keys[0][0] === "e" || results[0].keys[0][0] === "r") {
byKey = results[0].keys[0];
groupKey = results[0].keys[1];
} else {
byKey = results[0].keys[1];
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
for (const res of results) {
const g = res.get(groupKey);
const b = res.get(byKey);
result["group"] = { name: groupKey, values: group };
result["by"] = { name: byKey, values: by };
if (g !== null && b !== null) {
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
return result;
}
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