@langchain/neo4j 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -3
- package/dist/chains/graph_qa/index.d.cts +2 -0
- package/dist/graphs/document.cjs.map +1 -1
- package/dist/graphs/document.js.map +1 -1
- package/dist/graphs/index.d.cts +3 -0
- package/dist/graphs/memgraph_graph.cjs +1 -2
- package/dist/graphs/memgraph_graph.cjs.map +1 -1
- package/dist/graphs/memgraph_graph.js +1 -2
- package/dist/graphs/memgraph_graph.js.map +1 -1
- package/dist/graphs/neo4j_graph.cjs.map +1 -1
- package/dist/graphs/neo4j_graph.js.map +1 -1
- package/dist/stores/message/index.d.cts +1 -0
- package/dist/stores/message/neo4j.cjs +5 -10
- package/dist/stores/message/neo4j.cjs.map +1 -1
- package/dist/stores/message/neo4j.js +5 -10
- package/dist/stores/message/neo4j.js.map +1 -1
- package/dist/vectorstores/index.d.cts +1 -0
- package/dist/vectorstores/neo4j_vector.cjs.map +1 -1
- package/dist/vectorstores/neo4j_vector.js.map +1 -1
- package/package.json +20 -29
package/README.md
CHANGED
|
@@ -54,7 +54,12 @@ const graph = await Neo4jGraph.initialize({
|
|
|
54
54
|
You can add structured graph documents (nodes and relationships extracted from text) to the database:
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
Neo4jGraph,
|
|
59
|
+
Node,
|
|
60
|
+
Relationship,
|
|
61
|
+
GraphDocument,
|
|
62
|
+
} from "@langchain/neo4j";
|
|
58
63
|
import { Document } from "@langchain/core/documents";
|
|
59
64
|
|
|
60
65
|
const source = new Document({
|
|
@@ -62,8 +67,16 @@ const source = new Document({
|
|
|
62
67
|
metadata: { id: "doc1" },
|
|
63
68
|
});
|
|
64
69
|
|
|
65
|
-
const alice = new Node({
|
|
66
|
-
|
|
70
|
+
const alice = new Node({
|
|
71
|
+
id: "alice",
|
|
72
|
+
type: "Person",
|
|
73
|
+
properties: { name: "Alice" },
|
|
74
|
+
});
|
|
75
|
+
const acme = new Node({
|
|
76
|
+
id: "acme",
|
|
77
|
+
type: "Company",
|
|
78
|
+
properties: { name: "Acme Corp" },
|
|
79
|
+
});
|
|
67
80
|
const worksAt = new Relationship({
|
|
68
81
|
source: alice,
|
|
69
82
|
target: acme,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.cjs","names":["Serializable"],"sources":["../../src/graphs/document.ts"],"sourcesContent":["import { Serializable } from \"@langchain/core/load/serializable\";\nimport { Document } from \"@langchain/core/documents\";\n\n//
|
|
1
|
+
{"version":3,"file":"document.cjs","names":["Serializable"],"sources":["../../src/graphs/document.ts"],"sourcesContent":["import { Serializable } from \"@langchain/core/load/serializable\";\nimport { Document } from \"@langchain/core/documents\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport class Node extends Serializable {\n id: string | number;\n\n type: string;\n\n properties: Record<string, Any>;\n\n lc_namespace = [\"langchain\", \"graph\", \"document_node\"];\n\n constructor({\n id,\n type = \"Node\",\n properties = {},\n }: {\n id: string | number;\n type: string;\n properties?: Record<string, Any>;\n }) {\n super();\n this.id = id;\n this.type = type;\n this.properties = properties;\n }\n}\n\nexport class Relationship extends Serializable {\n source: Node;\n\n target: Node;\n\n type: string;\n\n properties: Record<string, Any>;\n\n lc_namespace = [\"langchain\", \"graph\", \"document_relationship\"];\n\n constructor({\n source,\n target,\n type,\n properties = {},\n }: {\n source: Node;\n target: Node;\n type: string;\n properties?: Record<string, Any>;\n }) {\n super();\n this.source = source;\n this.target = target;\n this.type = type;\n this.properties = properties;\n }\n}\n\nexport class GraphDocument extends Serializable {\n nodes: Node[];\n\n relationships: Relationship[];\n\n source: Document;\n\n lc_namespace = [\"langchain\", \"graph\", \"graph_document\"];\n\n constructor({\n nodes,\n relationships,\n source,\n }: {\n nodes: Node[];\n relationships: Relationship[];\n source: Document;\n }) {\n super({\n nodes,\n relationships,\n source,\n });\n this.nodes = nodes;\n this.relationships = relationships;\n this.source = source;\n }\n}\n"],"mappings":";;;AAMA,IAAa,OAAb,cAA0BA,kCAAAA,aAAa;CACrC;CAEA;CAEA;CAEA,eAAe;EAAC;EAAa;EAAS;EAAgB;CAEtD,YAAY,EACV,IACA,OAAO,QACP,aAAa,EAAE,IAKd;AACD,SAAO;AACP,OAAK,KAAK;AACV,OAAK,OAAO;AACZ,OAAK,aAAa;;;AAItB,IAAa,eAAb,cAAkCA,kCAAAA,aAAa;CAC7C;CAEA;CAEA;CAEA;CAEA,eAAe;EAAC;EAAa;EAAS;EAAwB;CAE9D,YAAY,EACV,QACA,QACA,MACA,aAAa,EAAE,IAMd;AACD,SAAO;AACP,OAAK,SAAS;AACd,OAAK,SAAS;AACd,OAAK,OAAO;AACZ,OAAK,aAAa;;;AAItB,IAAa,gBAAb,cAAmCA,kCAAAA,aAAa;CAC9C;CAEA;CAEA;CAEA,eAAe;EAAC;EAAa;EAAS;EAAiB;CAEvD,YAAY,EACV,OACA,eACA,UAKC;AACD,QAAM;GACJ;GACA;GACA;GACD,CAAC;AACF,OAAK,QAAQ;AACb,OAAK,gBAAgB;AACrB,OAAK,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.js","names":[],"sources":["../../src/graphs/document.ts"],"sourcesContent":["import { Serializable } from \"@langchain/core/load/serializable\";\nimport { Document } from \"@langchain/core/documents\";\n\n//
|
|
1
|
+
{"version":3,"file":"document.js","names":[],"sources":["../../src/graphs/document.ts"],"sourcesContent":["import { Serializable } from \"@langchain/core/load/serializable\";\nimport { Document } from \"@langchain/core/documents\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport class Node extends Serializable {\n id: string | number;\n\n type: string;\n\n properties: Record<string, Any>;\n\n lc_namespace = [\"langchain\", \"graph\", \"document_node\"];\n\n constructor({\n id,\n type = \"Node\",\n properties = {},\n }: {\n id: string | number;\n type: string;\n properties?: Record<string, Any>;\n }) {\n super();\n this.id = id;\n this.type = type;\n this.properties = properties;\n }\n}\n\nexport class Relationship extends Serializable {\n source: Node;\n\n target: Node;\n\n type: string;\n\n properties: Record<string, Any>;\n\n lc_namespace = [\"langchain\", \"graph\", \"document_relationship\"];\n\n constructor({\n source,\n target,\n type,\n properties = {},\n }: {\n source: Node;\n target: Node;\n type: string;\n properties?: Record<string, Any>;\n }) {\n super();\n this.source = source;\n this.target = target;\n this.type = type;\n this.properties = properties;\n }\n}\n\nexport class GraphDocument extends Serializable {\n nodes: Node[];\n\n relationships: Relationship[];\n\n source: Document;\n\n lc_namespace = [\"langchain\", \"graph\", \"graph_document\"];\n\n constructor({\n nodes,\n relationships,\n source,\n }: {\n nodes: Node[];\n relationships: Relationship[];\n source: Document;\n }) {\n super({\n nodes,\n relationships,\n source,\n });\n this.nodes = nodes;\n this.relationships = relationships;\n this.source = source;\n }\n}\n"],"mappings":";;AAMA,IAAa,OAAb,cAA0B,aAAa;CACrC;CAEA;CAEA;CAEA,eAAe;EAAC;EAAa;EAAS;EAAgB;CAEtD,YAAY,EACV,IACA,OAAO,QACP,aAAa,EAAE,IAKd;AACD,SAAO;AACP,OAAK,KAAK;AACV,OAAK,OAAO;AACZ,OAAK,aAAa;;;AAItB,IAAa,eAAb,cAAkC,aAAa;CAC7C;CAEA;CAEA;CAEA;CAEA,eAAe;EAAC;EAAa;EAAS;EAAwB;CAE9D,YAAY,EACV,QACA,QACA,MACA,aAAa,EAAE,IAMd;AACD,SAAO;AACP,OAAK,SAAS;AACd,OAAK,SAAS;AACd,OAAK,OAAO;AACZ,OAAK,aAAa;;;AAItB,IAAa,gBAAb,cAAmC,aAAa;CAC9C;CAEA;CAEA;CAEA,eAAe;EAAC;EAAa;EAAS;EAAiB;CAEvD,YAAY,EACV,OACA,eACA,UAKC;AACD,QAAM;GACJ;GACA;GACA;GACD,CAAC;AACF,OAAK,QAAQ;AACb,OAAK,gBAAgB;AACrB,OAAK,SAAS"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { GraphDocument, Node, Relationship } from "./document.cjs";
|
|
2
|
+
import { AddGraphDocumentsConfig, BASE_ENTITY_LABEL, Neo4jGraph, Neo4jGraphConfig, NodeType, PathType, RelType, StructuredSchema, formatSchema } from "./neo4j_graph.cjs";
|
|
3
|
+
import { MemgraphGraph, MemgraphGraphConfig } from "./memgraph_graph.cjs";
|
|
@@ -39,8 +39,7 @@ var MemgraphGraph = class MemgraphGraph extends require_neo4j_graph.Neo4jGraph {
|
|
|
39
39
|
await graph.refreshSchema();
|
|
40
40
|
console.debug("Schema refreshed successfully.");
|
|
41
41
|
} catch (e) {
|
|
42
|
-
|
|
43
|
-
throw new Error(error.message);
|
|
42
|
+
throw new Error(e.message);
|
|
44
43
|
}
|
|
45
44
|
return graph;
|
|
46
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memgraph_graph.cjs","names":["Neo4jGraph"],"sources":["../../src/graphs/memgraph_graph.ts"],"sourcesContent":["import { Neo4jGraph } from \"./neo4j_graph.js\";\n\nexport interface MemgraphGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n}\n\nconst rawSchemaQuery = `\nCALL llm_util.schema(\"raw\")\nYIELD *\nRETURN *\n`;\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class MemgraphGraph extends Neo4jGraph {\n constructor({\n url,\n username,\n password,\n database = \"memgraph\",\n }: MemgraphGraphConfig) {\n super({ url, username, password, database });\n }\n\n static async initialize(config: MemgraphGraphConfig): Promise<MemgraphGraph> {\n const graph = new MemgraphGraph(config);\n\n try {\n await graph.verifyConnectivity();\n } catch {\n console.error(\"Failed to verify connection.\");\n }\n\n try {\n await graph.refreshSchema();\n console.debug(\"Schema refreshed successfully.\");\n } catch (e) {\n const error = e as Error;\n throw new Error(error.message);\n }\n\n return graph;\n }\n\n async refreshSchema() {\n const rawSchemaQueryResult = await this.query(rawSchemaQuery);\n if (rawSchemaQueryResult?.[0]?.schema) {\n const rawSchema = rawSchemaQueryResult?.[0]?.schema;\n\n this.structuredSchema = {\n nodeProps: rawSchema.node_props,\n relProps: rawSchema.rel_props,\n relationships: rawSchema.relationships,\n };\n\n const formattedNodeProps = Object.entries(rawSchema.node_props)\n .map(([nodeName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Node name: '${nodeName}', Node properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRelProps = Object.entries(rawSchema.rel_props)\n .map(([relationshipName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Relationship name: '${relationshipName}', Relationship properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRels = rawSchema.relationships\n ?.map(\n (el: { end: string; start: string; type: string }) =>\n `(:${el.start})-[:${el.type}]->(:${el.end})`\n )\n .join(\"\\n\");\n\n this.schema = [\n \"Node properties are the following:\",\n formattedNodeProps,\n \"Relationship properties are the following:\",\n formattedRelProps,\n \"The relationships are the following:\",\n formattedRels,\n ].join(\"\\n\");\n }\n }\n}\n"],"mappings":";;AASA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;AAoBvB,IAAa,gBAAb,MAAa,sBAAsBA,oBAAAA,WAAW;CAC5C,YAAY,EACV,KACA,UACA,UACA,WAAW,cACW;AACtB,QAAM;GAAE;GAAK;GAAU;GAAU;GAAU,CAAC;;CAG9C,aAAa,WAAW,QAAqD;EAC3E,MAAM,QAAQ,IAAI,cAAc,OAAO;AAEvC,MAAI;AACF,SAAM,MAAM,oBAAoB;UAC1B;AACN,WAAQ,MAAM,+BAA+B;;AAG/C,MAAI;AACF,SAAM,MAAM,eAAe;AAC3B,WAAQ,MAAM,iCAAiC;WACxC,GAAG;
|
|
1
|
+
{"version":3,"file":"memgraph_graph.cjs","names":["Neo4jGraph"],"sources":["../../src/graphs/memgraph_graph.ts"],"sourcesContent":["import { Neo4jGraph } from \"./neo4j_graph.js\";\n\nexport interface MemgraphGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n}\n\nconst rawSchemaQuery = `\nCALL llm_util.schema(\"raw\")\nYIELD *\nRETURN *\n`;\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class MemgraphGraph extends Neo4jGraph {\n constructor({\n url,\n username,\n password,\n database = \"memgraph\",\n }: MemgraphGraphConfig) {\n super({ url, username, password, database });\n }\n\n static async initialize(config: MemgraphGraphConfig): Promise<MemgraphGraph> {\n const graph = new MemgraphGraph(config);\n\n try {\n await graph.verifyConnectivity();\n } catch {\n console.error(\"Failed to verify connection.\");\n }\n\n try {\n await graph.refreshSchema();\n console.debug(\"Schema refreshed successfully.\");\n } catch (e) {\n const error = e as Error;\n throw new Error(error.message);\n }\n\n return graph;\n }\n\n async refreshSchema() {\n const rawSchemaQueryResult = await this.query(rawSchemaQuery);\n if (rawSchemaQueryResult?.[0]?.schema) {\n const rawSchema = rawSchemaQueryResult?.[0]?.schema;\n\n this.structuredSchema = {\n nodeProps: rawSchema.node_props,\n relProps: rawSchema.rel_props,\n relationships: rawSchema.relationships,\n };\n\n const formattedNodeProps = Object.entries(rawSchema.node_props)\n .map(([nodeName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Node name: '${nodeName}', Node properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRelProps = Object.entries(rawSchema.rel_props)\n .map(([relationshipName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Relationship name: '${relationshipName}', Relationship properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRels = rawSchema.relationships\n ?.map(\n (el: { end: string; start: string; type: string }) =>\n `(:${el.start})-[:${el.type}]->(:${el.end})`\n )\n .join(\"\\n\");\n\n this.schema = [\n \"Node properties are the following:\",\n formattedNodeProps,\n \"Relationship properties are the following:\",\n formattedRelProps,\n \"The relationships are the following:\",\n formattedRels,\n ].join(\"\\n\");\n }\n }\n}\n"],"mappings":";;AASA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;AAoBvB,IAAa,gBAAb,MAAa,sBAAsBA,oBAAAA,WAAW;CAC5C,YAAY,EACV,KACA,UACA,UACA,WAAW,cACW;AACtB,QAAM;GAAE;GAAK;GAAU;GAAU;GAAU,CAAC;;CAG9C,aAAa,WAAW,QAAqD;EAC3E,MAAM,QAAQ,IAAI,cAAc,OAAO;AAEvC,MAAI;AACF,SAAM,MAAM,oBAAoB;UAC1B;AACN,WAAQ,MAAM,+BAA+B;;AAG/C,MAAI;AACF,SAAM,MAAM,eAAe;AAC3B,WAAQ,MAAM,iCAAiC;WACxC,GAAG;AAEV,SAAM,IAAI,MADI,EACQ,QAAQ;;AAGhC,SAAO;;CAGT,MAAM,gBAAgB;EACpB,MAAM,uBAAuB,MAAM,KAAK,MAAM,eAAe;AAC7D,MAAI,uBAAuB,IAAI,QAAQ;GACrC,MAAM,YAAY,uBAAuB,IAAI;AAE7C,QAAK,mBAAmB;IACtB,WAAW,UAAU;IACrB,UAAU,UAAU;IACpB,eAAe,UAAU;IAC1B;AAuBD,QAAK,SAAS;IACZ;IAtByB,OAAO,QAAQ,UAAU,WAAW,CAC5D,KAAK,CAAC,UAAU,gBAAgB;AAE/B,YAAO,eAAe,SAAS,sBADT,KAAK,UAAU,WAAW;MAEhD,CACD,KAAK,KAAK;IAmBX;IAjBwB,OAAO,QAAQ,UAAU,UAAU,CAC1D,KAAK,CAAC,kBAAkB,gBAAgB;AAEvC,YAAO,uBAAuB,iBAAiB,8BADzB,KAAK,UAAU,WAAW;MAEhD,CACD,KAAK,KAAK;IAcX;IAZoB,UAAU,eAC5B,KACC,OACC,KAAK,GAAG,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI,GAC7C,CACA,KAAK,KAAK;IASZ,CAAC,KAAK,KAAK"}
|
|
@@ -39,8 +39,7 @@ var MemgraphGraph = class MemgraphGraph extends Neo4jGraph {
|
|
|
39
39
|
await graph.refreshSchema();
|
|
40
40
|
console.debug("Schema refreshed successfully.");
|
|
41
41
|
} catch (e) {
|
|
42
|
-
|
|
43
|
-
throw new Error(error.message);
|
|
42
|
+
throw new Error(e.message);
|
|
44
43
|
}
|
|
45
44
|
return graph;
|
|
46
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memgraph_graph.js","names":[],"sources":["../../src/graphs/memgraph_graph.ts"],"sourcesContent":["import { Neo4jGraph } from \"./neo4j_graph.js\";\n\nexport interface MemgraphGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n}\n\nconst rawSchemaQuery = `\nCALL llm_util.schema(\"raw\")\nYIELD *\nRETURN *\n`;\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class MemgraphGraph extends Neo4jGraph {\n constructor({\n url,\n username,\n password,\n database = \"memgraph\",\n }: MemgraphGraphConfig) {\n super({ url, username, password, database });\n }\n\n static async initialize(config: MemgraphGraphConfig): Promise<MemgraphGraph> {\n const graph = new MemgraphGraph(config);\n\n try {\n await graph.verifyConnectivity();\n } catch {\n console.error(\"Failed to verify connection.\");\n }\n\n try {\n await graph.refreshSchema();\n console.debug(\"Schema refreshed successfully.\");\n } catch (e) {\n const error = e as Error;\n throw new Error(error.message);\n }\n\n return graph;\n }\n\n async refreshSchema() {\n const rawSchemaQueryResult = await this.query(rawSchemaQuery);\n if (rawSchemaQueryResult?.[0]?.schema) {\n const rawSchema = rawSchemaQueryResult?.[0]?.schema;\n\n this.structuredSchema = {\n nodeProps: rawSchema.node_props,\n relProps: rawSchema.rel_props,\n relationships: rawSchema.relationships,\n };\n\n const formattedNodeProps = Object.entries(rawSchema.node_props)\n .map(([nodeName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Node name: '${nodeName}', Node properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRelProps = Object.entries(rawSchema.rel_props)\n .map(([relationshipName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Relationship name: '${relationshipName}', Relationship properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRels = rawSchema.relationships\n ?.map(\n (el: { end: string; start: string; type: string }) =>\n `(:${el.start})-[:${el.type}]->(:${el.end})`\n )\n .join(\"\\n\");\n\n this.schema = [\n \"Node properties are the following:\",\n formattedNodeProps,\n \"Relationship properties are the following:\",\n formattedRelProps,\n \"The relationships are the following:\",\n formattedRels,\n ].join(\"\\n\");\n }\n }\n}\n"],"mappings":";;AASA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;AAoBvB,IAAa,gBAAb,MAAa,sBAAsB,WAAW;CAC5C,YAAY,EACV,KACA,UACA,UACA,WAAW,cACW;AACtB,QAAM;GAAE;GAAK;GAAU;GAAU;GAAU,CAAC;;CAG9C,aAAa,WAAW,QAAqD;EAC3E,MAAM,QAAQ,IAAI,cAAc,OAAO;AAEvC,MAAI;AACF,SAAM,MAAM,oBAAoB;UAC1B;AACN,WAAQ,MAAM,+BAA+B;;AAG/C,MAAI;AACF,SAAM,MAAM,eAAe;AAC3B,WAAQ,MAAM,iCAAiC;WACxC,GAAG;
|
|
1
|
+
{"version":3,"file":"memgraph_graph.js","names":[],"sources":["../../src/graphs/memgraph_graph.ts"],"sourcesContent":["import { Neo4jGraph } from \"./neo4j_graph.js\";\n\nexport interface MemgraphGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n}\n\nconst rawSchemaQuery = `\nCALL llm_util.schema(\"raw\")\nYIELD *\nRETURN *\n`;\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class MemgraphGraph extends Neo4jGraph {\n constructor({\n url,\n username,\n password,\n database = \"memgraph\",\n }: MemgraphGraphConfig) {\n super({ url, username, password, database });\n }\n\n static async initialize(config: MemgraphGraphConfig): Promise<MemgraphGraph> {\n const graph = new MemgraphGraph(config);\n\n try {\n await graph.verifyConnectivity();\n } catch {\n console.error(\"Failed to verify connection.\");\n }\n\n try {\n await graph.refreshSchema();\n console.debug(\"Schema refreshed successfully.\");\n } catch (e) {\n const error = e as Error;\n throw new Error(error.message);\n }\n\n return graph;\n }\n\n async refreshSchema() {\n const rawSchemaQueryResult = await this.query(rawSchemaQuery);\n if (rawSchemaQueryResult?.[0]?.schema) {\n const rawSchema = rawSchemaQueryResult?.[0]?.schema;\n\n this.structuredSchema = {\n nodeProps: rawSchema.node_props,\n relProps: rawSchema.rel_props,\n relationships: rawSchema.relationships,\n };\n\n const formattedNodeProps = Object.entries(rawSchema.node_props)\n .map(([nodeName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Node name: '${nodeName}', Node properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRelProps = Object.entries(rawSchema.rel_props)\n .map(([relationshipName, properties]) => {\n const propertiesStr = JSON.stringify(properties);\n return `Relationship name: '${relationshipName}', Relationship properties: ${propertiesStr}`;\n })\n .join(\"\\n\");\n\n const formattedRels = rawSchema.relationships\n ?.map(\n (el: { end: string; start: string; type: string }) =>\n `(:${el.start})-[:${el.type}]->(:${el.end})`\n )\n .join(\"\\n\");\n\n this.schema = [\n \"Node properties are the following:\",\n formattedNodeProps,\n \"Relationship properties are the following:\",\n formattedRelProps,\n \"The relationships are the following:\",\n formattedRels,\n ].join(\"\\n\");\n }\n }\n}\n"],"mappings":";;AASA,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;AAoBvB,IAAa,gBAAb,MAAa,sBAAsB,WAAW;CAC5C,YAAY,EACV,KACA,UACA,UACA,WAAW,cACW;AACtB,QAAM;GAAE;GAAK;GAAU;GAAU;GAAU,CAAC;;CAG9C,aAAa,WAAW,QAAqD;EAC3E,MAAM,QAAQ,IAAI,cAAc,OAAO;AAEvC,MAAI;AACF,SAAM,MAAM,oBAAoB;UAC1B;AACN,WAAQ,MAAM,+BAA+B;;AAG/C,MAAI;AACF,SAAM,MAAM,eAAe;AAC3B,WAAQ,MAAM,iCAAiC;WACxC,GAAG;AAEV,SAAM,IAAI,MADI,EACQ,QAAQ;;AAGhC,SAAO;;CAGT,MAAM,gBAAgB;EACpB,MAAM,uBAAuB,MAAM,KAAK,MAAM,eAAe;AAC7D,MAAI,uBAAuB,IAAI,QAAQ;GACrC,MAAM,YAAY,uBAAuB,IAAI;AAE7C,QAAK,mBAAmB;IACtB,WAAW,UAAU;IACrB,UAAU,UAAU;IACpB,eAAe,UAAU;IAC1B;AAuBD,QAAK,SAAS;IACZ;IAtByB,OAAO,QAAQ,UAAU,WAAW,CAC5D,KAAK,CAAC,UAAU,gBAAgB;AAE/B,YAAO,eAAe,SAAS,sBADT,KAAK,UAAU,WAAW;MAEhD,CACD,KAAK,KAAK;IAmBX;IAjBwB,OAAO,QAAQ,UAAU,UAAU,CAC1D,KAAK,CAAC,kBAAkB,gBAAgB;AAEvC,YAAO,uBAAuB,iBAAiB,8BADzB,KAAK,UAAU,WAAW;MAEhD,CACD,KAAK,KAAK;IAcX;IAZoB,UAAU,eAC5B,KACC,OACC,KAAK,GAAG,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI,GAC7C,CACA,KAAK,KAAK;IASZ,CAAC,KAAK,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neo4j_graph.cjs","names":["neo4j"],"sources":["../../src/graphs/neo4j_graph.ts"],"sourcesContent":["import neo4j, {\n RoutingControl,\n type Driver as Neo4jDriver,\n type Record as Neo4jRecord,\n type Path as Neo4jPath,\n} from \"neo4j-driver\";\nimport { sha256 } from \"@langchain/core/utils/hash\";\nimport { GraphDocument } from \"./document.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport interface Neo4jGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n timeoutMs?: number;\n enhancedSchema?: boolean;\n}\n\nexport interface StructuredSchema {\n nodeProps: { [key: NodeType[\"labels\"]]: NodeType[\"properties\"] };\n relProps: { [key: RelType[\"type\"]]: RelType[\"properties\"] };\n relationships: PathType[];\n metadata?: {\n constraint: Record<string, Any>;\n index: Record<string, Any>;\n };\n}\n\nexport interface AddGraphDocumentsConfig {\n baseEntityLabel?: boolean;\n includeSource?: boolean;\n}\n\nexport type NodeType = {\n labels: string;\n properties: { property: string; type: string }[];\n};\n\nexport type RelType = {\n type: string;\n properties: { property: string; type: string }[];\n};\n\nexport type PathType = { start: string; type: string; end: string };\n\nexport const BASE_ENTITY_LABEL = \"__Entity__\";\n\nconst DISTINCT_VALUE_LIMIT = 10;\nconst LIST_LIMIT = 128;\nconst EXHAUSTIVE_SEARCH_LIMIT = 10000;\nconst EXCLUDED_LABELS = [\"Bloom_Perspective\", \"Bloom_Scene\"];\nconst EXCLUDED_RELS = [\"Bloom_HAS_SCENE\"];\n\nconst INCLUDE_DOCS_QUERY = `\nMERGE (d:Document {id:$document.metadata.id})\nSET d.text = $document.pageContent\nSET d += $document.metadata\nWITH d\n`;\n\nconst NODE_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"node\"\n AND NOT label IN $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {labels: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"relationship\"\n AND NOT label in $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {type: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE type = \"RELATIONSHIP\" AND elementType = \"node\"\nUNWIND other AS other_node\nWITH * WHERE NOT label IN $EXCLUDED_LABELS\n AND NOT other_node IN $EXCLUDED_LABELS\nRETURN {start: label, type: property, end: toString(other_node)} AS output\n`;\n\nfunction isDistinctMoreThanLimit(\n distinct_count = 11,\n limit = DISTINCT_VALUE_LIMIT\n): boolean {\n return distinct_count !== undefined && distinct_count > limit;\n}\n\nfunction cleanStringValues(text: string) {\n return text.replace(/\\n/g, \" \").replace(/\\r/g, \" \");\n}\n\nexport function formatSchema(\n schema: Record<string, Any>,\n isEnhanced: boolean\n): string {\n let formattedNodeProps: string[] = [];\n let formattedRelProps: string[] = [];\n\n if (isEnhanced) {\n for (const [nodeType, properties] of Object.entries(schema.nodeProps)) {\n formattedNodeProps.push(`- **${nodeType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min !== undefined) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values.length > 0) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (!prop.min_size || prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedNodeProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n\n for (const [relType, properties] of Object.entries(schema.relProps)) {\n formattedRelProps.push(`- **${relType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedRelProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n } else {\n formattedNodeProps = Object.entries(schema.nodeProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type}`)\n .join(\", \");\n return `${key} {${propsStr}}`;\n }\n );\n\n formattedRelProps = Object.entries(schema.relProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type} `)\n .join(\", \");\n return `${key} {${propsStr} } `;\n }\n );\n }\n\n const formattedRels = schema.relationships.map(\n (el: Record<string, string>) =>\n `(: ${el.start}) - [: ${el.type}] -> (:${el.end})`\n );\n\n return [\n \"Node properties are the following:\",\n formattedNodeProps?.join(\", \"),\n \"Relationship properties are the following:\",\n formattedRelProps?.join(\", \"),\n \"The relationships are the following:\",\n formattedRels?.join(\", \"),\n ].join(\"\\n\");\n}\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class Neo4jGraph {\n private driver: Neo4jDriver;\n\n private database: string;\n\n private timeoutMs: number | undefined;\n\n private enhancedSchema: boolean;\n\n protected schema = \"\";\n\n protected structuredSchema: StructuredSchema = {\n nodeProps: {},\n relProps: {},\n relationships: [],\n metadata: {\n constraint: {},\n index: {},\n },\n };\n\n constructor({\n url,\n username,\n password,\n database = \"neo4j\",\n timeoutMs,\n enhancedSchema = false,\n }: Neo4jGraphConfig) {\n try {\n this.driver = neo4j.driver(url, neo4j.auth.basic(username, password));\n this.database = database;\n this.timeoutMs = timeoutMs;\n this.enhancedSchema = enhancedSchema;\n } catch {\n throw new Error(\n \"Could not create a Neo4j driver instance. Please check the connection details.\"\n );\n }\n }\n\n static async initialize(config: Neo4jGraphConfig): Promise<Neo4jGraph> {\n const graph = new Neo4jGraph(config);\n\n await graph.verifyConnectivity();\n\n try {\n await graph.refreshSchema();\n } catch (error: Any) {\n if (error.code === \"Neo.ClientError.Procedure.ProcedureNotFound\") {\n throw new Error(\n \"Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that 'apoc.meta.data()' is allowed in Neo4j configuration.\"\n );\n }\n\n throw error;\n } finally {\n console.log(\"Schema refreshed successfully.\");\n }\n\n return graph;\n }\n\n getSchema(): string {\n return this.schema;\n }\n\n getStructuredSchema() {\n return this.structuredSchema;\n }\n\n async query<RecordShape extends Record<string, Any> = Record<string, Any>>(\n query: string,\n params: Record<string, Any> = {},\n routing: RoutingControl = neo4j.routing.WRITE\n ): Promise<RecordShape[]> {\n const result = await this.driver.executeQuery<RecordShape>(query, params, {\n database: this.database,\n routing,\n transactionConfig: { timeout: this.timeoutMs },\n });\n return toObjects<RecordShape>(result.records);\n }\n\n async verifyConnectivity() {\n await this.driver.getServerInfo();\n }\n\n async refreshSchema() {\n const nodeProperties = (\n await this.query<{ output: NodeType }>(NODE_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const relationshipsProperties = (\n await this.query<{ output: RelType }>(REL_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_RELS,\n })\n )?.map((el) => el.output);\n\n const relationships: PathType[] = (\n await this.query<{ output: PathType }>(REL_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const constraint = await this.query(\"SHOW CONSTRAINTS\");\n\n const index = await this.query(\"SHOW INDEXES YIELD *\");\n\n this.structuredSchema = {\n nodeProps: Object.fromEntries(\n nodeProperties?.map((el) => [el.labels, el.properties]) || []\n ),\n relProps: Object.fromEntries(\n relationshipsProperties?.map((el) => [el.type, el.properties]) || []\n ),\n relationships: relationships || [],\n metadata: {\n constraint,\n index,\n },\n };\n\n if (this.enhancedSchema) {\n const schemaCounts = await this.query(\n `CALL apoc.meta.graphSample() YIELD nodes, relationships ` +\n `RETURN nodes, [rel in relationships | {name: apoc.any.property(rel, 'type'), count: apoc.any.property(rel, 'count')}] AS relationships`\n );\n for (const node of schemaCounts[0].nodes) {\n if (EXCLUDED_LABELS.includes(node.name)) {\n continue;\n }\n\n const nodeProps = this.structuredSchema.nodeProps[node.name];\n\n if (!nodeProps) {\n continue;\n }\n\n const enhancedCypher = await this.enhancedSchemaCypher(\n node.name,\n nodeProps,\n node.count < EXHAUSTIVE_SEARCH_LIMIT\n );\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of nodeProps) {\n if (enhancedInfo[prop.property]) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n\n for (const rel of schemaCounts[0].relationships) {\n if (EXCLUDED_RELS.includes(rel.name)) {\n continue;\n }\n const relProps = this.structuredSchema.relProps[rel.name];\n\n if (!relProps) {\n continue;\n }\n const enhancedCypher = await this.enhancedSchemaCypher(\n rel.name,\n relProps,\n rel.count < EXHAUSTIVE_SEARCH_LIMIT,\n true\n );\n\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of relProps) {\n if (prop.property in enhancedInfo) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n }\n\n this.schema = formatSchema(this.structuredSchema, this.enhancedSchema);\n }\n\n async enhancedSchemaCypher(\n labelOrType: string,\n properties: { property: string; type: string }[],\n exhaustive: boolean,\n isRelationship = false\n ) {\n let matchClause = isRelationship\n ? `MATCH ()-[n:\\`${labelOrType}\\`]->()`\n : `MATCH (n:\\`${labelOrType}\\`)`;\n\n const withClauses: string[] = [];\n const returnClauses: string[] = [];\n const outputDict: { [key: string]: string } = {};\n\n if (exhaustive) {\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n if (propType === \"STRING\") {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(\n `values: \\`${propName}_values\\`[..${DISTINCT_VALUE_LIMIT}], distinct_count: size(\\`${propName}_values\\`)`\n );\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n } else {\n matchClause += ` WITH n LIMIT 5`;\n\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n const propIndex = this.structuredSchema?.metadata?.index.filter(\n (el: Any) =>\n el.label === labelOrType &&\n el.properties[0] === propName &&\n el.type === \"RANGE\"\n );\n\n if (propType === \"STRING\") {\n if (\n propIndex.length > 0 &&\n propIndex[0].size > 0 &&\n propIndex[0].distinctValues <= DISTINCT_VALUE_LIMIT\n ) {\n const distinctValuesPromise = await this.query(\n `CALL apoc.schema.properties.distinct('${labelOrType}', '${propName}') YIELD value`\n );\n const distinctValues = distinctValuesPromise[0].value;\n returnClauses.push(\n `values: ${distinctValues}, distinct_count: ${distinctValues.length}`\n );\n } else {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n if (!propIndex) {\n withClauses.push(\n `collect(distinct toString(n.\\`${propName}\\`)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n } else {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n }\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n }\n\n const withClause = `WITH ${withClauses.join(\", \")}`;\n const returnClause = `RETURN {${Object.entries(outputDict)\n .map(([k, v]) => `\\`${k}\\`: ${v}`)\n .join(\", \")}} AS output`;\n\n const cypherQuery = [matchClause, withClause, returnClause].join(\"\\n\");\n\n return cypherQuery;\n }\n\n async addGraphDocuments(\n graphDocuments: GraphDocument[],\n config: AddGraphDocumentsConfig = {}\n ): Promise<void> {\n const { baseEntityLabel } = config;\n\n if (baseEntityLabel) {\n const constraintExists =\n this.structuredSchema?.metadata?.constraint?.some(\n (el: Any) =>\n JSON.stringify(el.labelsOrTypes) ===\n JSON.stringify([BASE_ENTITY_LABEL]) &&\n JSON.stringify(el.properties) === JSON.stringify([\"id\"])\n ) ?? false;\n\n if (!constraintExists) {\n await this.query(`\n CREATE CONSTRAINT IF NOT EXISTS FOR (b:${BASE_ENTITY_LABEL})\n REQUIRE b.id IS UNIQUE;\n `);\n await this.refreshSchema();\n }\n }\n\n const nodeImportQuery = getNodeImportQuery(config);\n const relImportQuery = getRelImportQuery(config);\n\n for (const document of graphDocuments) {\n if (!document.source.metadata.id) {\n document.source.metadata.id = sha256(document.source.pageContent);\n }\n\n await this.query(nodeImportQuery, {\n data: document.nodes.map((el: Any) => ({ ...el })),\n document: { ...document.source },\n });\n\n await this.query(relImportQuery, {\n data: document.relationships.map((el: Any) => ({\n source: el.source.id,\n source_label: el.source.type,\n target: el.target.id,\n target_label: el.target.type,\n type: el.type.replace(/ /g, \"_\").toUpperCase(),\n properties: el.properties,\n })),\n });\n }\n }\n\n async close() {\n await this.driver.close();\n }\n}\n\nfunction getNodeImportQuery({\n baseEntityLabel,\n includeSource,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n MERGE(source: \\`${BASE_ENTITY_LABEL}\\` {id: row.id})\n SET source += row.properties\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(source)\" : \"\"}\n WITH source, row\n CALL apoc.create.addLabels(source, [row.type]) YIELD node\n RETURN distinct 'done' AS result\n `;\n } else {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n CALL apoc.merge.node([row.type], {id: row.id},\n row.properties, {}) YIELD node\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(node)\" : \"\"}\n RETURN distinct 'done' AS result\n `;\n }\n}\n\nfunction getRelImportQuery({\n baseEntityLabel,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n UNWIND $data AS row\n MERGE (source:\\`${BASE_ENTITY_LABEL}\\` {id: row.source})\n MERGE (target:\\`${BASE_ENTITY_LABEL}\\` {id: row.target})\n WITH source, target, row\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n } else {\n return `\n UNWIND $data AS row\n CALL apoc.merge.node([row.source_label], {id: row.source},\n {}, {}) YIELD node as source\n CALL apoc.merge.node([row.target_label], {id: row.target},\n {}, {}) YIELD node as target\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n }\n}\n\nfunction toObjects<\n RecordShape extends Record<string, Any> = Record<string, Any>,\n>(records: Neo4jRecord<RecordShape>): RecordShape[] {\n return records.map((record: Any) => {\n const rObj = record.toObject();\n const out: Partial<RecordShape> = {};\n Object.keys(rObj).forEach((key: keyof RecordShape) => {\n out[key] = itemIntToString(rObj[key]);\n });\n return out as RecordShape;\n });\n}\n\nfunction itemIntToString(item: Any): Any {\n if (neo4j.isInt(item)) return item.toString();\n if (Array.isArray(item)) return item.map((ii) => itemIntToString(ii));\n if ([\"number\", \"string\", \"boolean\"].indexOf(typeof item) !== -1) return item;\n if (item === null) return item;\n if (typeof item === \"object\") return objIntToString(item);\n}\n\nfunction objIntToString(obj: Any) {\n const entry = extractFromNeoObjects(obj);\n let newObj: Any = null;\n if (Array.isArray(entry)) {\n newObj = entry.map((item) => itemIntToString(item));\n } else if (entry !== null && typeof entry === \"object\") {\n newObj = {};\n Object.keys(entry).forEach((key) => {\n newObj[key] = itemIntToString(entry[key]);\n });\n }\n return newObj;\n}\n\nfunction extractFromNeoObjects(obj: Any) {\n if (\n // eslint-disable-next-line\n obj instanceof (neo4j.types.Node as any) ||\n // eslint-disable-next-line\n obj instanceof (neo4j.types.Relationship as any)\n ) {\n return obj.properties;\n // eslint-disable-next-line\n } else if (obj instanceof (neo4j.types.Path as any)) {\n // eslint-disable-next-line\n return [].concat.apply<any[], any[], any[]>([], extractPathForRows(obj));\n }\n return obj;\n}\n\nconst extractPathForRows = (path: Neo4jPath) => {\n let { segments } = path;\n if (!Array.isArray(path.segments) || path.segments.length < 1) {\n segments = [{ ...path, end: null } as Any];\n }\n\n return segments.map((segment: Any) =>\n [\n objIntToString(segment.start),\n objIntToString(segment.relationship),\n objIntToString(segment.end),\n ].filter((part) => part !== null)\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"neo4j_graph.cjs","names":["neo4j"],"sources":["../../src/graphs/neo4j_graph.ts"],"sourcesContent":["import neo4j, {\n RoutingControl,\n type Driver as Neo4jDriver,\n type Record as Neo4jRecord,\n type Path as Neo4jPath,\n} from \"neo4j-driver\";\nimport { sha256 } from \"@langchain/core/utils/hash\";\nimport { GraphDocument } from \"./document.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport interface Neo4jGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n timeoutMs?: number;\n enhancedSchema?: boolean;\n}\n\nexport interface StructuredSchema {\n nodeProps: { [key: NodeType[\"labels\"]]: NodeType[\"properties\"] };\n relProps: { [key: RelType[\"type\"]]: RelType[\"properties\"] };\n relationships: PathType[];\n metadata?: {\n constraint: Record<string, Any>;\n index: Record<string, Any>;\n };\n}\n\nexport interface AddGraphDocumentsConfig {\n baseEntityLabel?: boolean;\n includeSource?: boolean;\n}\n\nexport type NodeType = {\n labels: string;\n properties: { property: string; type: string }[];\n};\n\nexport type RelType = {\n type: string;\n properties: { property: string; type: string }[];\n};\n\nexport type PathType = { start: string; type: string; end: string };\n\nexport const BASE_ENTITY_LABEL = \"__Entity__\";\n\nconst DISTINCT_VALUE_LIMIT = 10;\nconst LIST_LIMIT = 128;\nconst EXHAUSTIVE_SEARCH_LIMIT = 10000;\nconst EXCLUDED_LABELS = [\"Bloom_Perspective\", \"Bloom_Scene\"];\nconst EXCLUDED_RELS = [\"Bloom_HAS_SCENE\"];\n\nconst INCLUDE_DOCS_QUERY = `\nMERGE (d:Document {id:$document.metadata.id})\nSET d.text = $document.pageContent\nSET d += $document.metadata\nWITH d\n`;\n\nconst NODE_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"node\"\n AND NOT label IN $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {labels: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"relationship\"\n AND NOT label in $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {type: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE type = \"RELATIONSHIP\" AND elementType = \"node\"\nUNWIND other AS other_node\nWITH * WHERE NOT label IN $EXCLUDED_LABELS\n AND NOT other_node IN $EXCLUDED_LABELS\nRETURN {start: label, type: property, end: toString(other_node)} AS output\n`;\n\nfunction isDistinctMoreThanLimit(\n distinct_count = 11,\n limit = DISTINCT_VALUE_LIMIT\n): boolean {\n return distinct_count !== undefined && distinct_count > limit;\n}\n\nfunction cleanStringValues(text: string) {\n return text.replace(/\\n/g, \" \").replace(/\\r/g, \" \");\n}\n\nexport function formatSchema(\n schema: Record<string, Any>,\n isEnhanced: boolean\n): string {\n let formattedNodeProps: string[] = [];\n let formattedRelProps: string[] = [];\n\n if (isEnhanced) {\n for (const [nodeType, properties] of Object.entries(schema.nodeProps)) {\n formattedNodeProps.push(`- **${nodeType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min !== undefined) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values.length > 0) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (!prop.min_size || prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedNodeProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n\n for (const [relType, properties] of Object.entries(schema.relProps)) {\n formattedRelProps.push(`- **${relType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedRelProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n } else {\n formattedNodeProps = Object.entries(schema.nodeProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type}`)\n .join(\", \");\n return `${key} {${propsStr}}`;\n }\n );\n\n formattedRelProps = Object.entries(schema.relProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type} `)\n .join(\", \");\n return `${key} {${propsStr} } `;\n }\n );\n }\n\n const formattedRels = schema.relationships.map(\n (el: Record<string, string>) =>\n `(: ${el.start}) - [: ${el.type}] -> (:${el.end})`\n );\n\n return [\n \"Node properties are the following:\",\n formattedNodeProps?.join(\", \"),\n \"Relationship properties are the following:\",\n formattedRelProps?.join(\", \"),\n \"The relationships are the following:\",\n formattedRels?.join(\", \"),\n ].join(\"\\n\");\n}\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class Neo4jGraph {\n private driver: Neo4jDriver;\n\n private database: string;\n\n private timeoutMs: number | undefined;\n\n private enhancedSchema: boolean;\n\n protected schema = \"\";\n\n protected structuredSchema: StructuredSchema = {\n nodeProps: {},\n relProps: {},\n relationships: [],\n metadata: {\n constraint: {},\n index: {},\n },\n };\n\n constructor({\n url,\n username,\n password,\n database = \"neo4j\",\n timeoutMs,\n enhancedSchema = false,\n }: Neo4jGraphConfig) {\n try {\n this.driver = neo4j.driver(url, neo4j.auth.basic(username, password));\n this.database = database;\n this.timeoutMs = timeoutMs;\n this.enhancedSchema = enhancedSchema;\n } catch {\n throw new Error(\n \"Could not create a Neo4j driver instance. Please check the connection details.\"\n );\n }\n }\n\n static async initialize(config: Neo4jGraphConfig): Promise<Neo4jGraph> {\n const graph = new Neo4jGraph(config);\n\n await graph.verifyConnectivity();\n\n try {\n await graph.refreshSchema();\n } catch (error: Any) {\n if (error.code === \"Neo.ClientError.Procedure.ProcedureNotFound\") {\n throw new Error(\n \"Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that 'apoc.meta.data()' is allowed in Neo4j configuration.\"\n );\n }\n\n throw error;\n } finally {\n console.log(\"Schema refreshed successfully.\");\n }\n\n return graph;\n }\n\n getSchema(): string {\n return this.schema;\n }\n\n getStructuredSchema() {\n return this.structuredSchema;\n }\n\n async query<RecordShape extends Record<string, Any> = Record<string, Any>>(\n query: string,\n params: Record<string, Any> = {},\n routing: RoutingControl = neo4j.routing.WRITE\n ): Promise<RecordShape[]> {\n const result = await this.driver.executeQuery<RecordShape>(query, params, {\n database: this.database,\n routing,\n transactionConfig: { timeout: this.timeoutMs },\n });\n return toObjects<RecordShape>(result.records);\n }\n\n async verifyConnectivity() {\n await this.driver.getServerInfo();\n }\n\n async refreshSchema() {\n const nodeProperties = (\n await this.query<{ output: NodeType }>(NODE_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const relationshipsProperties = (\n await this.query<{ output: RelType }>(REL_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_RELS,\n })\n )?.map((el) => el.output);\n\n const relationships: PathType[] = (\n await this.query<{ output: PathType }>(REL_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const constraint = await this.query(\"SHOW CONSTRAINTS\");\n\n const index = await this.query(\"SHOW INDEXES YIELD *\");\n\n this.structuredSchema = {\n nodeProps: Object.fromEntries(\n nodeProperties?.map((el) => [el.labels, el.properties]) || []\n ),\n relProps: Object.fromEntries(\n relationshipsProperties?.map((el) => [el.type, el.properties]) || []\n ),\n relationships: relationships || [],\n metadata: {\n constraint,\n index,\n },\n };\n\n if (this.enhancedSchema) {\n const schemaCounts = await this.query(\n `CALL apoc.meta.graphSample() YIELD nodes, relationships ` +\n `RETURN nodes, [rel in relationships | {name: apoc.any.property(rel, 'type'), count: apoc.any.property(rel, 'count')}] AS relationships`\n );\n for (const node of schemaCounts[0].nodes) {\n if (EXCLUDED_LABELS.includes(node.name)) {\n continue;\n }\n\n const nodeProps = this.structuredSchema.nodeProps[node.name];\n\n if (!nodeProps) {\n continue;\n }\n\n const enhancedCypher = await this.enhancedSchemaCypher(\n node.name,\n nodeProps,\n node.count < EXHAUSTIVE_SEARCH_LIMIT\n );\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of nodeProps) {\n if (enhancedInfo[prop.property]) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n\n for (const rel of schemaCounts[0].relationships) {\n if (EXCLUDED_RELS.includes(rel.name)) {\n continue;\n }\n const relProps = this.structuredSchema.relProps[rel.name];\n\n if (!relProps) {\n continue;\n }\n const enhancedCypher = await this.enhancedSchemaCypher(\n rel.name,\n relProps,\n rel.count < EXHAUSTIVE_SEARCH_LIMIT,\n true\n );\n\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of relProps) {\n if (prop.property in enhancedInfo) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n }\n\n this.schema = formatSchema(this.structuredSchema, this.enhancedSchema);\n }\n\n async enhancedSchemaCypher(\n labelOrType: string,\n properties: { property: string; type: string }[],\n exhaustive: boolean,\n isRelationship = false\n ) {\n let matchClause = isRelationship\n ? `MATCH ()-[n:\\`${labelOrType}\\`]->()`\n : `MATCH (n:\\`${labelOrType}\\`)`;\n\n const withClauses: string[] = [];\n const returnClauses: string[] = [];\n const outputDict: { [key: string]: string } = {};\n\n if (exhaustive) {\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n if (propType === \"STRING\") {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(\n `values: \\`${propName}_values\\`[..${DISTINCT_VALUE_LIMIT}], distinct_count: size(\\`${propName}_values\\`)`\n );\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n } else {\n matchClause += ` WITH n LIMIT 5`;\n\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n const propIndex = this.structuredSchema?.metadata?.index.filter(\n (el: Any) =>\n el.label === labelOrType &&\n el.properties[0] === propName &&\n el.type === \"RANGE\"\n );\n\n if (propType === \"STRING\") {\n if (\n propIndex.length > 0 &&\n propIndex[0].size > 0 &&\n propIndex[0].distinctValues <= DISTINCT_VALUE_LIMIT\n ) {\n const distinctValuesPromise = await this.query(\n `CALL apoc.schema.properties.distinct('${labelOrType}', '${propName}') YIELD value`\n );\n const distinctValues = distinctValuesPromise[0].value;\n returnClauses.push(\n `values: ${distinctValues}, distinct_count: ${distinctValues.length}`\n );\n } else {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n if (!propIndex) {\n withClauses.push(\n `collect(distinct toString(n.\\`${propName}\\`)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n } else {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n }\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n }\n\n const withClause = `WITH ${withClauses.join(\", \")}`;\n const returnClause = `RETURN {${Object.entries(outputDict)\n .map(([k, v]) => `\\`${k}\\`: ${v}`)\n .join(\", \")}} AS output`;\n\n const cypherQuery = [matchClause, withClause, returnClause].join(\"\\n\");\n\n return cypherQuery;\n }\n\n async addGraphDocuments(\n graphDocuments: GraphDocument[],\n config: AddGraphDocumentsConfig = {}\n ): Promise<void> {\n const { baseEntityLabel } = config;\n\n if (baseEntityLabel) {\n const constraintExists =\n this.structuredSchema?.metadata?.constraint?.some(\n (el: Any) =>\n JSON.stringify(el.labelsOrTypes) ===\n JSON.stringify([BASE_ENTITY_LABEL]) &&\n JSON.stringify(el.properties) === JSON.stringify([\"id\"])\n ) ?? false;\n\n if (!constraintExists) {\n await this.query(`\n CREATE CONSTRAINT IF NOT EXISTS FOR (b:${BASE_ENTITY_LABEL})\n REQUIRE b.id IS UNIQUE;\n `);\n await this.refreshSchema();\n }\n }\n\n const nodeImportQuery = getNodeImportQuery(config);\n const relImportQuery = getRelImportQuery(config);\n\n for (const document of graphDocuments) {\n if (!document.source.metadata.id) {\n document.source.metadata.id = sha256(document.source.pageContent);\n }\n\n await this.query(nodeImportQuery, {\n data: document.nodes.map((el: Any) => ({ ...el })),\n document: { ...document.source },\n });\n\n await this.query(relImportQuery, {\n data: document.relationships.map((el: Any) => ({\n source: el.source.id,\n source_label: el.source.type,\n target: el.target.id,\n target_label: el.target.type,\n type: el.type.replace(/ /g, \"_\").toUpperCase(),\n properties: el.properties,\n })),\n });\n }\n }\n\n async close() {\n await this.driver.close();\n }\n}\n\nfunction getNodeImportQuery({\n baseEntityLabel,\n includeSource,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n MERGE(source: \\`${BASE_ENTITY_LABEL}\\` {id: row.id})\n SET source += row.properties\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(source)\" : \"\"}\n WITH source, row\n CALL apoc.create.addLabels(source, [row.type]) YIELD node\n RETURN distinct 'done' AS result\n `;\n } else {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n CALL apoc.merge.node([row.type], {id: row.id},\n row.properties, {}) YIELD node\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(node)\" : \"\"}\n RETURN distinct 'done' AS result\n `;\n }\n}\n\nfunction getRelImportQuery({\n baseEntityLabel,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n UNWIND $data AS row\n MERGE (source:\\`${BASE_ENTITY_LABEL}\\` {id: row.source})\n MERGE (target:\\`${BASE_ENTITY_LABEL}\\` {id: row.target})\n WITH source, target, row\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n } else {\n return `\n UNWIND $data AS row\n CALL apoc.merge.node([row.source_label], {id: row.source},\n {}, {}) YIELD node as source\n CALL apoc.merge.node([row.target_label], {id: row.target},\n {}, {}) YIELD node as target\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n }\n}\n\nfunction toObjects<\n RecordShape extends Record<string, Any> = Record<string, Any>,\n>(records: Neo4jRecord<RecordShape>): RecordShape[] {\n return records.map((record: Any) => {\n const rObj = record.toObject();\n const out: Partial<RecordShape> = {};\n Object.keys(rObj).forEach((key: keyof RecordShape) => {\n out[key] = itemIntToString(rObj[key]);\n });\n return out as RecordShape;\n });\n}\n\nfunction itemIntToString(item: Any): Any {\n if (neo4j.isInt(item)) return item.toString();\n if (Array.isArray(item)) return item.map((ii) => itemIntToString(ii));\n if ([\"number\", \"string\", \"boolean\"].indexOf(typeof item) !== -1) return item;\n if (item === null) return item;\n if (typeof item === \"object\") return objIntToString(item);\n}\n\nfunction objIntToString(obj: Any) {\n const entry = extractFromNeoObjects(obj);\n let newObj: Any = null;\n if (Array.isArray(entry)) {\n newObj = entry.map((item) => itemIntToString(item));\n } else if (entry !== null && typeof entry === \"object\") {\n newObj = {};\n Object.keys(entry).forEach((key) => {\n newObj[key] = itemIntToString(entry[key]);\n });\n }\n return newObj;\n}\n\nfunction extractFromNeoObjects(obj: Any) {\n if (\n // oxlint-disable-next-line\n obj instanceof (neo4j.types.Node as any) ||\n // oxlint-disable-next-line\n obj instanceof (neo4j.types.Relationship as any)\n ) {\n return obj.properties;\n // oxlint-disable-next-line\n } else if (obj instanceof (neo4j.types.Path as any)) {\n // oxlint-disable-next-line\n return [].concat.apply<any[], any[], any[]>([], extractPathForRows(obj));\n }\n return obj;\n}\n\nconst extractPathForRows = (path: Neo4jPath) => {\n let { segments } = path;\n if (!Array.isArray(path.segments) || path.segments.length < 1) {\n segments = [{ ...path, end: null } as Any];\n }\n\n return segments.map((segment: Any) =>\n [\n objIntToString(segment.start),\n objIntToString(segment.relationship),\n objIntToString(segment.end),\n ].filter((part) => part !== null)\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neo4j_graph.js","names":[],"sources":["../../src/graphs/neo4j_graph.ts"],"sourcesContent":["import neo4j, {\n RoutingControl,\n type Driver as Neo4jDriver,\n type Record as Neo4jRecord,\n type Path as Neo4jPath,\n} from \"neo4j-driver\";\nimport { sha256 } from \"@langchain/core/utils/hash\";\nimport { GraphDocument } from \"./document.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport interface Neo4jGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n timeoutMs?: number;\n enhancedSchema?: boolean;\n}\n\nexport interface StructuredSchema {\n nodeProps: { [key: NodeType[\"labels\"]]: NodeType[\"properties\"] };\n relProps: { [key: RelType[\"type\"]]: RelType[\"properties\"] };\n relationships: PathType[];\n metadata?: {\n constraint: Record<string, Any>;\n index: Record<string, Any>;\n };\n}\n\nexport interface AddGraphDocumentsConfig {\n baseEntityLabel?: boolean;\n includeSource?: boolean;\n}\n\nexport type NodeType = {\n labels: string;\n properties: { property: string; type: string }[];\n};\n\nexport type RelType = {\n type: string;\n properties: { property: string; type: string }[];\n};\n\nexport type PathType = { start: string; type: string; end: string };\n\nexport const BASE_ENTITY_LABEL = \"__Entity__\";\n\nconst DISTINCT_VALUE_LIMIT = 10;\nconst LIST_LIMIT = 128;\nconst EXHAUSTIVE_SEARCH_LIMIT = 10000;\nconst EXCLUDED_LABELS = [\"Bloom_Perspective\", \"Bloom_Scene\"];\nconst EXCLUDED_RELS = [\"Bloom_HAS_SCENE\"];\n\nconst INCLUDE_DOCS_QUERY = `\nMERGE (d:Document {id:$document.metadata.id})\nSET d.text = $document.pageContent\nSET d += $document.metadata\nWITH d\n`;\n\nconst NODE_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"node\"\n AND NOT label IN $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {labels: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"relationship\"\n AND NOT label in $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {type: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE type = \"RELATIONSHIP\" AND elementType = \"node\"\nUNWIND other AS other_node\nWITH * WHERE NOT label IN $EXCLUDED_LABELS\n AND NOT other_node IN $EXCLUDED_LABELS\nRETURN {start: label, type: property, end: toString(other_node)} AS output\n`;\n\nfunction isDistinctMoreThanLimit(\n distinct_count = 11,\n limit = DISTINCT_VALUE_LIMIT\n): boolean {\n return distinct_count !== undefined && distinct_count > limit;\n}\n\nfunction cleanStringValues(text: string) {\n return text.replace(/\\n/g, \" \").replace(/\\r/g, \" \");\n}\n\nexport function formatSchema(\n schema: Record<string, Any>,\n isEnhanced: boolean\n): string {\n let formattedNodeProps: string[] = [];\n let formattedRelProps: string[] = [];\n\n if (isEnhanced) {\n for (const [nodeType, properties] of Object.entries(schema.nodeProps)) {\n formattedNodeProps.push(`- **${nodeType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min !== undefined) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values.length > 0) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (!prop.min_size || prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedNodeProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n\n for (const [relType, properties] of Object.entries(schema.relProps)) {\n formattedRelProps.push(`- **${relType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedRelProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n } else {\n formattedNodeProps = Object.entries(schema.nodeProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type}`)\n .join(\", \");\n return `${key} {${propsStr}}`;\n }\n );\n\n formattedRelProps = Object.entries(schema.relProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type} `)\n .join(\", \");\n return `${key} {${propsStr} } `;\n }\n );\n }\n\n const formattedRels = schema.relationships.map(\n (el: Record<string, string>) =>\n `(: ${el.start}) - [: ${el.type}] -> (:${el.end})`\n );\n\n return [\n \"Node properties are the following:\",\n formattedNodeProps?.join(\", \"),\n \"Relationship properties are the following:\",\n formattedRelProps?.join(\", \"),\n \"The relationships are the following:\",\n formattedRels?.join(\", \"),\n ].join(\"\\n\");\n}\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class Neo4jGraph {\n private driver: Neo4jDriver;\n\n private database: string;\n\n private timeoutMs: number | undefined;\n\n private enhancedSchema: boolean;\n\n protected schema = \"\";\n\n protected structuredSchema: StructuredSchema = {\n nodeProps: {},\n relProps: {},\n relationships: [],\n metadata: {\n constraint: {},\n index: {},\n },\n };\n\n constructor({\n url,\n username,\n password,\n database = \"neo4j\",\n timeoutMs,\n enhancedSchema = false,\n }: Neo4jGraphConfig) {\n try {\n this.driver = neo4j.driver(url, neo4j.auth.basic(username, password));\n this.database = database;\n this.timeoutMs = timeoutMs;\n this.enhancedSchema = enhancedSchema;\n } catch {\n throw new Error(\n \"Could not create a Neo4j driver instance. Please check the connection details.\"\n );\n }\n }\n\n static async initialize(config: Neo4jGraphConfig): Promise<Neo4jGraph> {\n const graph = new Neo4jGraph(config);\n\n await graph.verifyConnectivity();\n\n try {\n await graph.refreshSchema();\n } catch (error: Any) {\n if (error.code === \"Neo.ClientError.Procedure.ProcedureNotFound\") {\n throw new Error(\n \"Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that 'apoc.meta.data()' is allowed in Neo4j configuration.\"\n );\n }\n\n throw error;\n } finally {\n console.log(\"Schema refreshed successfully.\");\n }\n\n return graph;\n }\n\n getSchema(): string {\n return this.schema;\n }\n\n getStructuredSchema() {\n return this.structuredSchema;\n }\n\n async query<RecordShape extends Record<string, Any> = Record<string, Any>>(\n query: string,\n params: Record<string, Any> = {},\n routing: RoutingControl = neo4j.routing.WRITE\n ): Promise<RecordShape[]> {\n const result = await this.driver.executeQuery<RecordShape>(query, params, {\n database: this.database,\n routing,\n transactionConfig: { timeout: this.timeoutMs },\n });\n return toObjects<RecordShape>(result.records);\n }\n\n async verifyConnectivity() {\n await this.driver.getServerInfo();\n }\n\n async refreshSchema() {\n const nodeProperties = (\n await this.query<{ output: NodeType }>(NODE_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const relationshipsProperties = (\n await this.query<{ output: RelType }>(REL_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_RELS,\n })\n )?.map((el) => el.output);\n\n const relationships: PathType[] = (\n await this.query<{ output: PathType }>(REL_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const constraint = await this.query(\"SHOW CONSTRAINTS\");\n\n const index = await this.query(\"SHOW INDEXES YIELD *\");\n\n this.structuredSchema = {\n nodeProps: Object.fromEntries(\n nodeProperties?.map((el) => [el.labels, el.properties]) || []\n ),\n relProps: Object.fromEntries(\n relationshipsProperties?.map((el) => [el.type, el.properties]) || []\n ),\n relationships: relationships || [],\n metadata: {\n constraint,\n index,\n },\n };\n\n if (this.enhancedSchema) {\n const schemaCounts = await this.query(\n `CALL apoc.meta.graphSample() YIELD nodes, relationships ` +\n `RETURN nodes, [rel in relationships | {name: apoc.any.property(rel, 'type'), count: apoc.any.property(rel, 'count')}] AS relationships`\n );\n for (const node of schemaCounts[0].nodes) {\n if (EXCLUDED_LABELS.includes(node.name)) {\n continue;\n }\n\n const nodeProps = this.structuredSchema.nodeProps[node.name];\n\n if (!nodeProps) {\n continue;\n }\n\n const enhancedCypher = await this.enhancedSchemaCypher(\n node.name,\n nodeProps,\n node.count < EXHAUSTIVE_SEARCH_LIMIT\n );\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of nodeProps) {\n if (enhancedInfo[prop.property]) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n\n for (const rel of schemaCounts[0].relationships) {\n if (EXCLUDED_RELS.includes(rel.name)) {\n continue;\n }\n const relProps = this.structuredSchema.relProps[rel.name];\n\n if (!relProps) {\n continue;\n }\n const enhancedCypher = await this.enhancedSchemaCypher(\n rel.name,\n relProps,\n rel.count < EXHAUSTIVE_SEARCH_LIMIT,\n true\n );\n\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of relProps) {\n if (prop.property in enhancedInfo) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n }\n\n this.schema = formatSchema(this.structuredSchema, this.enhancedSchema);\n }\n\n async enhancedSchemaCypher(\n labelOrType: string,\n properties: { property: string; type: string }[],\n exhaustive: boolean,\n isRelationship = false\n ) {\n let matchClause = isRelationship\n ? `MATCH ()-[n:\\`${labelOrType}\\`]->()`\n : `MATCH (n:\\`${labelOrType}\\`)`;\n\n const withClauses: string[] = [];\n const returnClauses: string[] = [];\n const outputDict: { [key: string]: string } = {};\n\n if (exhaustive) {\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n if (propType === \"STRING\") {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(\n `values: \\`${propName}_values\\`[..${DISTINCT_VALUE_LIMIT}], distinct_count: size(\\`${propName}_values\\`)`\n );\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n } else {\n matchClause += ` WITH n LIMIT 5`;\n\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n const propIndex = this.structuredSchema?.metadata?.index.filter(\n (el: Any) =>\n el.label === labelOrType &&\n el.properties[0] === propName &&\n el.type === \"RANGE\"\n );\n\n if (propType === \"STRING\") {\n if (\n propIndex.length > 0 &&\n propIndex[0].size > 0 &&\n propIndex[0].distinctValues <= DISTINCT_VALUE_LIMIT\n ) {\n const distinctValuesPromise = await this.query(\n `CALL apoc.schema.properties.distinct('${labelOrType}', '${propName}') YIELD value`\n );\n const distinctValues = distinctValuesPromise[0].value;\n returnClauses.push(\n `values: ${distinctValues}, distinct_count: ${distinctValues.length}`\n );\n } else {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n if (!propIndex) {\n withClauses.push(\n `collect(distinct toString(n.\\`${propName}\\`)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n } else {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n }\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n }\n\n const withClause = `WITH ${withClauses.join(\", \")}`;\n const returnClause = `RETURN {${Object.entries(outputDict)\n .map(([k, v]) => `\\`${k}\\`: ${v}`)\n .join(\", \")}} AS output`;\n\n const cypherQuery = [matchClause, withClause, returnClause].join(\"\\n\");\n\n return cypherQuery;\n }\n\n async addGraphDocuments(\n graphDocuments: GraphDocument[],\n config: AddGraphDocumentsConfig = {}\n ): Promise<void> {\n const { baseEntityLabel } = config;\n\n if (baseEntityLabel) {\n const constraintExists =\n this.structuredSchema?.metadata?.constraint?.some(\n (el: Any) =>\n JSON.stringify(el.labelsOrTypes) ===\n JSON.stringify([BASE_ENTITY_LABEL]) &&\n JSON.stringify(el.properties) === JSON.stringify([\"id\"])\n ) ?? false;\n\n if (!constraintExists) {\n await this.query(`\n CREATE CONSTRAINT IF NOT EXISTS FOR (b:${BASE_ENTITY_LABEL})\n REQUIRE b.id IS UNIQUE;\n `);\n await this.refreshSchema();\n }\n }\n\n const nodeImportQuery = getNodeImportQuery(config);\n const relImportQuery = getRelImportQuery(config);\n\n for (const document of graphDocuments) {\n if (!document.source.metadata.id) {\n document.source.metadata.id = sha256(document.source.pageContent);\n }\n\n await this.query(nodeImportQuery, {\n data: document.nodes.map((el: Any) => ({ ...el })),\n document: { ...document.source },\n });\n\n await this.query(relImportQuery, {\n data: document.relationships.map((el: Any) => ({\n source: el.source.id,\n source_label: el.source.type,\n target: el.target.id,\n target_label: el.target.type,\n type: el.type.replace(/ /g, \"_\").toUpperCase(),\n properties: el.properties,\n })),\n });\n }\n }\n\n async close() {\n await this.driver.close();\n }\n}\n\nfunction getNodeImportQuery({\n baseEntityLabel,\n includeSource,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n MERGE(source: \\`${BASE_ENTITY_LABEL}\\` {id: row.id})\n SET source += row.properties\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(source)\" : \"\"}\n WITH source, row\n CALL apoc.create.addLabels(source, [row.type]) YIELD node\n RETURN distinct 'done' AS result\n `;\n } else {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n CALL apoc.merge.node([row.type], {id: row.id},\n row.properties, {}) YIELD node\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(node)\" : \"\"}\n RETURN distinct 'done' AS result\n `;\n }\n}\n\nfunction getRelImportQuery({\n baseEntityLabel,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n UNWIND $data AS row\n MERGE (source:\\`${BASE_ENTITY_LABEL}\\` {id: row.source})\n MERGE (target:\\`${BASE_ENTITY_LABEL}\\` {id: row.target})\n WITH source, target, row\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n } else {\n return `\n UNWIND $data AS row\n CALL apoc.merge.node([row.source_label], {id: row.source},\n {}, {}) YIELD node as source\n CALL apoc.merge.node([row.target_label], {id: row.target},\n {}, {}) YIELD node as target\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n }\n}\n\nfunction toObjects<\n RecordShape extends Record<string, Any> = Record<string, Any>,\n>(records: Neo4jRecord<RecordShape>): RecordShape[] {\n return records.map((record: Any) => {\n const rObj = record.toObject();\n const out: Partial<RecordShape> = {};\n Object.keys(rObj).forEach((key: keyof RecordShape) => {\n out[key] = itemIntToString(rObj[key]);\n });\n return out as RecordShape;\n });\n}\n\nfunction itemIntToString(item: Any): Any {\n if (neo4j.isInt(item)) return item.toString();\n if (Array.isArray(item)) return item.map((ii) => itemIntToString(ii));\n if ([\"number\", \"string\", \"boolean\"].indexOf(typeof item) !== -1) return item;\n if (item === null) return item;\n if (typeof item === \"object\") return objIntToString(item);\n}\n\nfunction objIntToString(obj: Any) {\n const entry = extractFromNeoObjects(obj);\n let newObj: Any = null;\n if (Array.isArray(entry)) {\n newObj = entry.map((item) => itemIntToString(item));\n } else if (entry !== null && typeof entry === \"object\") {\n newObj = {};\n Object.keys(entry).forEach((key) => {\n newObj[key] = itemIntToString(entry[key]);\n });\n }\n return newObj;\n}\n\nfunction extractFromNeoObjects(obj: Any) {\n if (\n // eslint-disable-next-line\n obj instanceof (neo4j.types.Node as any) ||\n // eslint-disable-next-line\n obj instanceof (neo4j.types.Relationship as any)\n ) {\n return obj.properties;\n // eslint-disable-next-line\n } else if (obj instanceof (neo4j.types.Path as any)) {\n // eslint-disable-next-line\n return [].concat.apply<any[], any[], any[]>([], extractPathForRows(obj));\n }\n return obj;\n}\n\nconst extractPathForRows = (path: Neo4jPath) => {\n let { segments } = path;\n if (!Array.isArray(path.segments) || path.segments.length < 1) {\n segments = [{ ...path, end: null } as Any];\n }\n\n return segments.map((segment: Any) =>\n [\n objIntToString(segment.start),\n objIntToString(segment.relationship),\n objIntToString(segment.end),\n ].filter((part) => part !== null)\n );\n};\n"],"mappings":";;;AAgDA,MAAa,oBAAoB;AAEjC,MAAM,uBAAuB;AAC7B,MAAM,aAAa;AACnB,MAAM,0BAA0B;AAChC,MAAM,kBAAkB,CAAC,qBAAqB,cAAc;AAC5D,MAAM,gBAAgB,CAAC,kBAAkB;AAEzC,MAAM,qBAAqB;;;;;;AAO3B,MAAM,wBAAwB;;;;;;;;AAS9B,MAAM,uBAAuB;;;;;;;;AAS7B,MAAM,YAAY;;;;;;;;;AAUlB,SAAS,wBACP,iBAAiB,IACjB,QAAQ,sBACC;AACT,QAAO,mBAAmB,KAAA,KAAa,iBAAiB;;AAG1D,SAAS,kBAAkB,MAAc;AACvC,QAAO,KAAK,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI;;AAGrD,SAAgB,aACd,QACA,YACQ;CACR,IAAI,qBAA+B,EAAE;CACrC,IAAI,oBAA8B,EAAE;AAEpC,KAAI,YAAY;AACd,OAAK,MAAM,CAAC,UAAU,eAAe,OAAO,QAAQ,OAAO,UAAU,EAAE;AACrE,sBAAmB,KAAK,OAAO,SAAS,IAAI;AAE5C,QAAK,MAAM,QAAQ,YAA0C;IAC3D,IAAI,UAAU;AAEd,QAAI,KAAK,SAAS;SACZ,KAAK,OAAO,SAAS,EACvB,KAAI,wBAAwB,KAAK,eAAe,CAC9C,WAAU,YAAY,kBAAkB,KAAK,OAAO,GAAG;SAEvD,WAAU,sBAAsB,KAAK,OAClC,IAAI,kBAAkB,CACtB,KAAK,KAAK;eAIjB;KAAC;KAAW;KAAS;KAAQ;KAAa;KAAkB,CAAC,SAC3D,KAAK,KACN;SAEG,KAAK,QAAQ,KAAA,EACf,WAAU,QAAQ,KAAK,IAAI,SAAS,KAAK;cAErC,KAAK,OAAO,SAAS,EACvB,WAAU,YAAY,KAAK,OAAO;eAG7B,KAAK,SAAS,QAAQ;AAC/B,SAAI,CAAC,KAAK,YAAY,KAAK,WAAW,WACpC;AAEF,eAAU,aAAa,KAAK,SAAS,cAAc,KAAK;;AAG1D,uBAAmB,KACjB,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK,GAAG,UAC3C;;;AAIL,OAAK,MAAM,CAAC,SAAS,eAAe,OAAO,QAAQ,OAAO,SAAS,EAAE;AACnE,qBAAkB,KAAK,OAAO,QAAQ,IAAI;AAE1C,QAAK,MAAM,QAAQ,YAA0C;IAC3D,IAAI,UAAU;AAEd,QAAI,KAAK,SAAS;SACZ,KAAK,OAAO,SAAS,EACvB,KAAI,wBAAwB,KAAK,eAAe,CAC9C,WAAU,YAAY,kBAAkB,KAAK,OAAO,GAAG;SAEvD,WAAU,sBAAsB,KAAK,OAClC,IAAI,kBAAkB,CACtB,KAAK,KAAK;eAIjB;KAAC;KAAW;KAAS;KAAQ;KAAa;KAAkB,CAAC,SAC3D,KAAK,KACN;SAEG,KAAK,IACP,WAAU,QAAQ,KAAK,IAAI,SAAS,KAAK;cAErC,KAAK,OACP,WAAU,YAAY,KAAK,OAAO;eAG7B,KAAK,SAAS,QAAQ;AAC/B,SAAI,KAAK,WAAW,WAClB;AAEF,eAAU,aAAa,KAAK,SAAS,cAAc,KAAK;;AAG1D,sBAAkB,KAChB,SAAS,KAAK,SAAS,MAAM,KAAK,KAAK,GAAG,UAC3C;;;QAGA;AACL,uBAAqB,OAAO,QAAQ,OAAO,UAAU,CAAC,KACnD,CAAC,KAAK,WAA0B;AAI/B,UAAO,GAAG,IAAI,IAHG,MACd,KAAK,SAA8B,GAAG,KAAK,SAAS,IAAI,KAAK,OAAO,CACpE,KAAK,KAAK,CACc;IAE9B;AAED,sBAAoB,OAAO,QAAQ,OAAO,SAAS,CAAC,KACjD,CAAC,KAAK,WAA0B;AAI/B,UAAO,GAAG,IAAI,IAHG,MACd,KAAK,SAA8B,GAAG,KAAK,SAAS,IAAI,KAAK,KAAK,GAAG,CACrE,KAAK,KAAK,CACc;IAE9B;;CAGH,MAAM,gBAAgB,OAAO,cAAc,KACxC,OACC,MAAM,GAAG,MAAM,SAAS,GAAG,KAAK,SAAS,GAAG,IAAI,GACnD;AAED,QAAO;EACL;EACA,oBAAoB,KAAK,KAAK;EAC9B;EACA,mBAAmB,KAAK,KAAK;EAC7B;EACA,eAAe,KAAK,KAAK;EAC1B,CAAC,KAAK,KAAK;;;;;;;;;;;;;;;;AAiBd,IAAa,aAAb,MAAa,WAAW;CACtB;CAEA;CAEA;CAEA;CAEA,SAAmB;CAEnB,mBAA+C;EAC7C,WAAW,EAAE;EACb,UAAU,EAAE;EACZ,eAAe,EAAE;EACjB,UAAU;GACR,YAAY,EAAE;GACd,OAAO,EAAE;GACV;EACF;CAED,YAAY,EACV,KACA,UACA,UACA,WAAW,SACX,WACA,iBAAiB,SACE;AACnB,MAAI;AACF,QAAK,SAAS,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,UAAU,SAAS,CAAC;AACrE,QAAK,WAAW;AAChB,QAAK,YAAY;AACjB,QAAK,iBAAiB;UAChB;AACN,SAAM,IAAI,MACR,iFACD;;;CAIL,aAAa,WAAW,QAA+C;EACrE,MAAM,QAAQ,IAAI,WAAW,OAAO;AAEpC,QAAM,MAAM,oBAAoB;AAEhC,MAAI;AACF,SAAM,MAAM,eAAe;WACpB,OAAY;AACnB,OAAI,MAAM,SAAS,8CACjB,OAAM,IAAI,MACR,oJACD;AAGH,SAAM;YACE;AACR,WAAQ,IAAI,iCAAiC;;AAG/C,SAAO;;CAGT,YAAoB;AAClB,SAAO,KAAK;;CAGd,sBAAsB;AACpB,SAAO,KAAK;;CAGd,MAAM,MACJ,OACA,SAA8B,EAAE,EAChC,UAA0B,MAAM,QAAQ,OAChB;AAMxB,SAAO,WALQ,MAAM,KAAK,OAAO,aAA0B,OAAO,QAAQ;GACxE,UAAU,KAAK;GACf;GACA,mBAAmB,EAAE,SAAS,KAAK,WAAW;GAC/C,CAAC,EACmC,QAAQ;;CAG/C,MAAM,qBAAqB;AACzB,QAAM,KAAK,OAAO,eAAe;;CAGnC,MAAM,gBAAgB;EACpB,MAAM,kBACJ,MAAM,KAAK,MAA4B,uBAAuB,EAC5D,iBAAiB,gBAAgB,OAAO,CAAC,kBAAkB,CAAC,EAC7D,CAAC,GACD,KAAK,OAAO,GAAG,OAAO;EAEzB,MAAM,2BACJ,MAAM,KAAK,MAA2B,sBAAsB,EAC1D,iBAAiB,eAClB,CAAC,GACD,KAAK,OAAO,GAAG,OAAO;EAEzB,MAAM,iBACJ,MAAM,KAAK,MAA4B,WAAW,EAChD,iBAAiB,gBAAgB,OAAO,CAAC,kBAAkB,CAAC,EAC7D,CAAC,GACD,KAAK,OAAO,GAAG,OAAO;EAEzB,MAAM,aAAa,MAAM,KAAK,MAAM,mBAAmB;EAEvD,MAAM,QAAQ,MAAM,KAAK,MAAM,uBAAuB;AAEtD,OAAK,mBAAmB;GACtB,WAAW,OAAO,YAChB,gBAAgB,KAAK,OAAO,CAAC,GAAG,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,CAC9D;GACD,UAAU,OAAO,YACf,yBAAyB,KAAK,OAAO,CAAC,GAAG,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,CACrE;GACD,eAAe,iBAAiB,EAAE;GAClC,UAAU;IACR;IACA;IACD;GACF;AAED,MAAI,KAAK,gBAAgB;GACvB,MAAM,eAAe,MAAM,KAAK,MAC9B,iMAED;AACD,QAAK,MAAM,QAAQ,aAAa,GAAG,OAAO;AACxC,QAAI,gBAAgB,SAAS,KAAK,KAAK,CACrC;IAGF,MAAM,YAAY,KAAK,iBAAiB,UAAU,KAAK;AAEvD,QAAI,CAAC,UACH;IAGF,MAAM,iBAAiB,MAAM,KAAK,qBAChC,KAAK,MACL,WACA,KAAK,QAAQ,wBACd;IAED,MAAM,gBADsB,MAAM,KAAK,MAAM,eAAe,EACnB,GAAG;AAE5C,SAAK,MAAM,QAAQ,UACjB,KAAI,aAAa,KAAK,UACpB,QAAO,OAAO,MAAM,aAAa,KAAK,UAAU;;AAKtD,QAAK,MAAM,OAAO,aAAa,GAAG,eAAe;AAC/C,QAAI,cAAc,SAAS,IAAI,KAAK,CAClC;IAEF,MAAM,WAAW,KAAK,iBAAiB,SAAS,IAAI;AAEpD,QAAI,CAAC,SACH;IAEF,MAAM,iBAAiB,MAAM,KAAK,qBAChC,IAAI,MACJ,UACA,IAAI,QAAQ,yBACZ,KACD;IAGD,MAAM,gBADsB,MAAM,KAAK,MAAM,eAAe,EACnB,GAAG;AAE5C,SAAK,MAAM,QAAQ,SACjB,KAAI,KAAK,YAAY,aACnB,QAAO,OAAO,MAAM,aAAa,KAAK,UAAU;;;AAMxD,OAAK,SAAS,aAAa,KAAK,kBAAkB,KAAK,eAAe;;CAGxE,MAAM,qBACJ,aACA,YACA,YACA,iBAAiB,OACjB;EACA,IAAI,cAAc,iBACd,iBAAiB,YAAY,WAC7B,cAAc,YAAY;EAE9B,MAAM,cAAwB,EAAE;EAChC,MAAM,gBAA0B,EAAE;EAClC,MAAM,aAAwC,EAAE;AAEhD,MAAI,WACF,MAAK,MAAM,QAAQ,YAAY;GAC7B,MAAM,WAAW,KAAK;GACtB,MAAM,WAAW,KAAK;AAEtB,OAAI,aAAa,UAAU;AACzB,gBAAY,KACV,kCAAkC,SAAS,mBAAmB,SAAS,WACxE;AACD,kBAAc,KACZ,aAAa,SAAS,cAAc,qBAAqB,4BAA4B,SAAS,YAC/F;cAED;IAAC;IAAW;IAAS;IAAQ;IAAa;IAAkB,CAAC,SAC3D,SACD,EACD;AACA,gBAAY,KAAK,WAAW,SAAS,WAAW,SAAS,QAAQ;AACjE,gBAAY,KAAK,WAAW,SAAS,WAAW,SAAS,QAAQ;AACjE,gBAAY,KACV,sBAAsB,SAAS,WAAW,SAAS,aACpD;AACD,kBAAc,KACZ,mBAAmB,SAAS,2BAA2B,SAAS,6BAA6B,SAAS,aACvG;cACQ,aAAa,QAAQ;AAC9B,gBAAY,KACV,gBAAgB,SAAS,YAAY,SAAS,4BAA4B,SAAS,YAAY,SAAS,aACzG;AACD,kBAAc,KACZ,eAAe,SAAS,2BAA2B,SAAS,aAC7D;cACQ;IAAC;IAAW;IAAS;IAAW,CAAC,SAAS,SAAS,CAC5D;AAEF,cAAW,YAAY,IAAI,cAAc,KAAK,CAAC;;OAE5C;AACL,kBAAe;AAEf,QAAK,MAAM,QAAQ,YAAY;IAC7B,MAAM,WAAW,KAAK;IACtB,MAAM,WAAW,KAAK;IAEtB,MAAM,YAAY,KAAK,kBAAkB,UAAU,MAAM,QACtD,OACC,GAAG,UAAU,eACb,GAAG,WAAW,OAAO,YACrB,GAAG,SAAS,QACf;AAED,QAAI,aAAa,SACf,KACE,UAAU,SAAS,KACnB,UAAU,GAAG,OAAO,KACpB,UAAU,GAAG,kBAAkB,sBAC/B;KAIA,MAAM,kBAHwB,MAAM,KAAK,MACvC,yCAAyC,YAAY,MAAM,SAAS,gBACrE,EAC4C,GAAG;AAChD,mBAAc,KACZ,WAAW,eAAe,oBAAoB,eAAe,SAC9D;WACI;AACL,iBAAY,KACV,kCAAkC,SAAS,mBAAmB,SAAS,WACxE;AACD,mBAAc,KAAK,WAAW,SAAS,SAAS;;aAGlD;KAAC;KAAW;KAAS;KAAQ;KAAa;KAAkB,CAAC,SAC3D,SACD,CAED,KAAI,CAAC,WAAW;AACd,iBAAY,KACV,iCAAiC,SAAS,YAAY,SAAS,WAChE;AACD,mBAAc,KAAK,WAAW,SAAS,SAAS;WAC3C;AACL,iBAAY,KAAK,WAAW,SAAS,WAAW,SAAS,QAAQ;AACjE,iBAAY,KAAK,WAAW,SAAS,WAAW,SAAS,QAAQ;AACjE,iBAAY,KACV,sBAAsB,SAAS,WAAW,SAAS,aACpD;AACD,mBAAc,KACZ,mBAAmB,SAAS,2BAA2B,SAAS,6BAA6B,SAAS,aACvG;;aAEM,aAAa,QAAQ;AAC9B,iBAAY,KACV,gBAAgB,SAAS,YAAY,SAAS,4BAA4B,SAAS,YAAY,SAAS,aACzG;AACD,mBAAc,KACZ,eAAe,SAAS,2BAA2B,SAAS,aAC7D;eACQ;KAAC;KAAW;KAAS;KAAW,CAAC,SAAS,SAAS,CAC5D;AAGF,eAAW,YAAY,IAAI,cAAc,KAAK,CAAC;;;EAInD,MAAM,aAAa,QAAQ,YAAY,KAAK,KAAK;EACjD,MAAM,eAAe,WAAW,OAAO,QAAQ,WAAW,CACvD,KAAK,CAAC,GAAG,OAAO,KAAK,EAAE,MAAM,IAAI,CACjC,KAAK,KAAK,CAAC;AAId,SAFoB;GAAC;GAAa;GAAY;GAAa,CAAC,KAAK,KAAK;;CAKxE,MAAM,kBACJ,gBACA,SAAkC,EAAE,EACrB;EACf,MAAM,EAAE,oBAAoB;AAE5B,MAAI;OASE,EAPF,KAAK,kBAAkB,UAAU,YAAY,MAC1C,OACC,KAAK,UAAU,GAAG,cAAc,KAC9B,KAAK,UAAU,CAAA,aAAmB,CAAC,IACrC,KAAK,UAAU,GAAG,WAAW,KAAK,KAAK,UAAU,CAAC,KAAK,CAAC,CAC3D,IAAI,QAEgB;AACrB,UAAM,KAAK,MAAM;mDAC0B,kBAAkB;;UAE3D;AACF,UAAM,KAAK,eAAe;;;EAI9B,MAAM,kBAAkB,mBAAmB,OAAO;EAClD,MAAM,iBAAiB,kBAAkB,OAAO;AAEhD,OAAK,MAAM,YAAY,gBAAgB;AACrC,OAAI,CAAC,SAAS,OAAO,SAAS,GAC5B,UAAS,OAAO,SAAS,KAAK,OAAO,SAAS,OAAO,YAAY;AAGnE,SAAM,KAAK,MAAM,iBAAiB;IAChC,MAAM,SAAS,MAAM,KAAK,QAAa,EAAE,GAAG,IAAI,EAAE;IAClD,UAAU,EAAE,GAAG,SAAS,QAAQ;IACjC,CAAC;AAEF,SAAM,KAAK,MAAM,gBAAgB,EAC/B,MAAM,SAAS,cAAc,KAAK,QAAa;IAC7C,QAAQ,GAAG,OAAO;IAClB,cAAc,GAAG,OAAO;IACxB,QAAQ,GAAG,OAAO;IAClB,cAAc,GAAG,OAAO;IACxB,MAAM,GAAG,KAAK,QAAQ,MAAM,IAAI,CAAC,aAAa;IAC9C,YAAY,GAAG;IAChB,EAAE,EACJ,CAAC;;;CAIN,MAAM,QAAQ;AACZ,QAAM,KAAK,OAAO,OAAO;;;AAI7B,SAAS,mBAAmB,EAC1B,iBACA,iBACkC;AAClC,KAAI,gBACF,QAAO;YACC,gBAAgB,qBAAqB,GAAG;;gCAEpB,kBAAkB;;YAEtC,gBAAgB,oCAAoC,GAAG;;;;;KAM/D,QAAO;YACC,gBAAgB,qBAAqB,GAAG;;;;YAIxC,gBAAgB,kCAAkC,GAAG;;;;AAMjE,SAAS,kBAAkB,EACzB,mBACkC;AAClC,KAAI,gBACF,QAAO;;4BAEiB,kBAAkB;4BAClB,kBAAkB;;;;;;KAO1C,QAAO;;;;;;;;;;;AAaX,SAAS,UAEP,SAAkD;AAClD,QAAO,QAAQ,KAAK,WAAgB;EAClC,MAAM,OAAO,OAAO,UAAU;EAC9B,MAAM,MAA4B,EAAE;AACpC,SAAO,KAAK,KAAK,CAAC,SAAS,QAA2B;AACpD,OAAI,OAAO,gBAAgB,KAAK,KAAK;IACrC;AACF,SAAO;GACP;;AAGJ,SAAS,gBAAgB,MAAgB;AACvC,KAAI,MAAM,MAAM,KAAK,CAAE,QAAO,KAAK,UAAU;AAC7C,KAAI,MAAM,QAAQ,KAAK,CAAE,QAAO,KAAK,KAAK,OAAO,gBAAgB,GAAG,CAAC;AACrE,KAAI;EAAC;EAAU;EAAU;EAAU,CAAC,QAAQ,OAAO,KAAK,KAAK,GAAI,QAAO;AACxE,KAAI,SAAS,KAAM,QAAO;AAC1B,KAAI,OAAO,SAAS,SAAU,QAAO,eAAe,KAAK;;AAG3D,SAAS,eAAe,KAAU;CAChC,MAAM,QAAQ,sBAAsB,IAAI;CACxC,IAAI,SAAc;AAClB,KAAI,MAAM,QAAQ,MAAM,CACtB,UAAS,MAAM,KAAK,SAAS,gBAAgB,KAAK,CAAC;UAC1C,UAAU,QAAQ,OAAO,UAAU,UAAU;AACtD,WAAS,EAAE;AACX,SAAO,KAAK,MAAM,CAAC,SAAS,QAAQ;AAClC,UAAO,OAAO,gBAAgB,MAAM,KAAK;IACzC;;AAEJ,QAAO;;AAGT,SAAS,sBAAsB,KAAU;AACvC,KAEE,eAAgB,MAAM,MAAM,QAE5B,eAAgB,MAAM,MAAM,aAE5B,QAAO,IAAI;UAEF,eAAgB,MAAM,MAAM,KAErC,QAAO,EAAE,CAAC,OAAO,MAA2B,EAAE,EAAE,mBAAmB,IAAI,CAAC;AAE1E,QAAO;;AAGT,MAAM,sBAAsB,SAAoB;CAC9C,IAAI,EAAE,aAAa;AACnB,KAAI,CAAC,MAAM,QAAQ,KAAK,SAAS,IAAI,KAAK,SAAS,SAAS,EAC1D,YAAW,CAAC;EAAE,GAAG;EAAM,KAAK;EAAM,CAAQ;AAG5C,QAAO,SAAS,KAAK,YACnB;EACE,eAAe,QAAQ,MAAM;EAC7B,eAAe,QAAQ,aAAa;EACpC,eAAe,QAAQ,IAAI;EAC5B,CAAC,QAAQ,SAAS,SAAS,KAAK,CAClC"}
|
|
1
|
+
{"version":3,"file":"neo4j_graph.js","names":[],"sources":["../../src/graphs/neo4j_graph.ts"],"sourcesContent":["import neo4j, {\n RoutingControl,\n type Driver as Neo4jDriver,\n type Record as Neo4jRecord,\n type Path as Neo4jPath,\n} from \"neo4j-driver\";\nimport { sha256 } from \"@langchain/core/utils/hash\";\nimport { GraphDocument } from \"./document.js\";\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype Any = any;\n\nexport interface Neo4jGraphConfig {\n url: string;\n username: string;\n password: string;\n database?: string;\n timeoutMs?: number;\n enhancedSchema?: boolean;\n}\n\nexport interface StructuredSchema {\n nodeProps: { [key: NodeType[\"labels\"]]: NodeType[\"properties\"] };\n relProps: { [key: RelType[\"type\"]]: RelType[\"properties\"] };\n relationships: PathType[];\n metadata?: {\n constraint: Record<string, Any>;\n index: Record<string, Any>;\n };\n}\n\nexport interface AddGraphDocumentsConfig {\n baseEntityLabel?: boolean;\n includeSource?: boolean;\n}\n\nexport type NodeType = {\n labels: string;\n properties: { property: string; type: string }[];\n};\n\nexport type RelType = {\n type: string;\n properties: { property: string; type: string }[];\n};\n\nexport type PathType = { start: string; type: string; end: string };\n\nexport const BASE_ENTITY_LABEL = \"__Entity__\";\n\nconst DISTINCT_VALUE_LIMIT = 10;\nconst LIST_LIMIT = 128;\nconst EXHAUSTIVE_SEARCH_LIMIT = 10000;\nconst EXCLUDED_LABELS = [\"Bloom_Perspective\", \"Bloom_Scene\"];\nconst EXCLUDED_RELS = [\"Bloom_HAS_SCENE\"];\n\nconst INCLUDE_DOCS_QUERY = `\nMERGE (d:Document {id:$document.metadata.id})\nSET d.text = $document.pageContent\nSET d += $document.metadata\nWITH d\n`;\n\nconst NODE_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"node\"\n AND NOT label IN $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {labels: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_PROPERTIES_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE NOT type = \"RELATIONSHIP\" AND elementType = \"relationship\"\n AND NOT label in $EXCLUDED_LABELS\nWITH label AS nodeLabels, collect({property:property, type:type}) AS properties\nRETURN {type: nodeLabels, properties: properties} AS output\n`;\n\nconst REL_QUERY = `\nCALL apoc.meta.data()\nYIELD label, other, elementType, type, property\nWHERE type = \"RELATIONSHIP\" AND elementType = \"node\"\nUNWIND other AS other_node\nWITH * WHERE NOT label IN $EXCLUDED_LABELS\n AND NOT other_node IN $EXCLUDED_LABELS\nRETURN {start: label, type: property, end: toString(other_node)} AS output\n`;\n\nfunction isDistinctMoreThanLimit(\n distinct_count = 11,\n limit = DISTINCT_VALUE_LIMIT\n): boolean {\n return distinct_count !== undefined && distinct_count > limit;\n}\n\nfunction cleanStringValues(text: string) {\n return text.replace(/\\n/g, \" \").replace(/\\r/g, \" \");\n}\n\nexport function formatSchema(\n schema: Record<string, Any>,\n isEnhanced: boolean\n): string {\n let formattedNodeProps: string[] = [];\n let formattedRelProps: string[] = [];\n\n if (isEnhanced) {\n for (const [nodeType, properties] of Object.entries(schema.nodeProps)) {\n formattedNodeProps.push(`- **${nodeType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min !== undefined) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values.length > 0) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (!prop.min_size || prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedNodeProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n\n for (const [relType, properties] of Object.entries(schema.relProps)) {\n formattedRelProps.push(`- **${relType}**`);\n\n for (const prop of properties as Array<Record<string, Any>>) {\n let example = \"\";\n\n if (prop.type === \"STRING\") {\n if (prop.values.length > 0) {\n if (isDistinctMoreThanLimit(prop.distinct_count)) {\n example = `Example: ${cleanStringValues(prop.values[0])}`;\n } else {\n example = `Available options: ${prop.values\n .map(cleanStringValues)\n .join(\", \")}`;\n }\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n prop.type\n )\n ) {\n if (prop.min) {\n example = `Min: ${prop.min}, Max: ${prop.max}`;\n } else {\n if (prop.values) {\n example = `Example: ${prop.values[0]}`;\n }\n }\n } else if (prop.type === \"LIST\") {\n if (prop.min_size > LIST_LIMIT) {\n continue;\n }\n example = `Min Size: ${prop.min_size}, Max Size: ${prop.max_size}`;\n }\n\n formattedRelProps.push(\n ` - \\`${prop.property}\\`: ${prop.type} ${example}`\n );\n }\n }\n } else {\n formattedNodeProps = Object.entries(schema.nodeProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type}`)\n .join(\", \");\n return `${key} {${propsStr}}`;\n }\n );\n\n formattedRelProps = Object.entries(schema.relProps).map(\n ([key, value]: [string, Any]) => {\n const propsStr = value\n .map((prop: Record<string, Any>) => `${prop.property}: ${prop.type} `)\n .join(\", \");\n return `${key} {${propsStr} } `;\n }\n );\n }\n\n const formattedRels = schema.relationships.map(\n (el: Record<string, string>) =>\n `(: ${el.start}) - [: ${el.type}] -> (:${el.end})`\n );\n\n return [\n \"Node properties are the following:\",\n formattedNodeProps?.join(\", \"),\n \"Relationship properties are the following:\",\n formattedRelProps?.join(\", \"),\n \"The relationships are the following:\",\n formattedRels?.join(\", \"),\n ].join(\"\\n\");\n}\n\n/**\n * @security *Security note*: Make sure that the database connection uses credentials\n * that are narrowly-scoped to only include necessary permissions.\n * Failure to do so may result in data corruption or loss, since the calling\n * code may attempt commands that would result in deletion, mutation\n * of data if appropriately prompted or reading sensitive data if such\n * data is present in the database.\n * The best way to guard against such negative outcomes is to (as appropriate)\n * limit the permissions granted to the credentials used with this tool.\n * For example, creating read only users for the database is a good way to\n * ensure that the calling code cannot mutate or delete data.\n *\n * @link See https://js.langchain.com/docs/security for more information.\n */\nexport class Neo4jGraph {\n private driver: Neo4jDriver;\n\n private database: string;\n\n private timeoutMs: number | undefined;\n\n private enhancedSchema: boolean;\n\n protected schema = \"\";\n\n protected structuredSchema: StructuredSchema = {\n nodeProps: {},\n relProps: {},\n relationships: [],\n metadata: {\n constraint: {},\n index: {},\n },\n };\n\n constructor({\n url,\n username,\n password,\n database = \"neo4j\",\n timeoutMs,\n enhancedSchema = false,\n }: Neo4jGraphConfig) {\n try {\n this.driver = neo4j.driver(url, neo4j.auth.basic(username, password));\n this.database = database;\n this.timeoutMs = timeoutMs;\n this.enhancedSchema = enhancedSchema;\n } catch {\n throw new Error(\n \"Could not create a Neo4j driver instance. Please check the connection details.\"\n );\n }\n }\n\n static async initialize(config: Neo4jGraphConfig): Promise<Neo4jGraph> {\n const graph = new Neo4jGraph(config);\n\n await graph.verifyConnectivity();\n\n try {\n await graph.refreshSchema();\n } catch (error: Any) {\n if (error.code === \"Neo.ClientError.Procedure.ProcedureNotFound\") {\n throw new Error(\n \"Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that 'apoc.meta.data()' is allowed in Neo4j configuration.\"\n );\n }\n\n throw error;\n } finally {\n console.log(\"Schema refreshed successfully.\");\n }\n\n return graph;\n }\n\n getSchema(): string {\n return this.schema;\n }\n\n getStructuredSchema() {\n return this.structuredSchema;\n }\n\n async query<RecordShape extends Record<string, Any> = Record<string, Any>>(\n query: string,\n params: Record<string, Any> = {},\n routing: RoutingControl = neo4j.routing.WRITE\n ): Promise<RecordShape[]> {\n const result = await this.driver.executeQuery<RecordShape>(query, params, {\n database: this.database,\n routing,\n transactionConfig: { timeout: this.timeoutMs },\n });\n return toObjects<RecordShape>(result.records);\n }\n\n async verifyConnectivity() {\n await this.driver.getServerInfo();\n }\n\n async refreshSchema() {\n const nodeProperties = (\n await this.query<{ output: NodeType }>(NODE_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const relationshipsProperties = (\n await this.query<{ output: RelType }>(REL_PROPERTIES_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_RELS,\n })\n )?.map((el) => el.output);\n\n const relationships: PathType[] = (\n await this.query<{ output: PathType }>(REL_QUERY, {\n EXCLUDED_LABELS: EXCLUDED_LABELS.concat([BASE_ENTITY_LABEL]),\n })\n )?.map((el) => el.output);\n\n const constraint = await this.query(\"SHOW CONSTRAINTS\");\n\n const index = await this.query(\"SHOW INDEXES YIELD *\");\n\n this.structuredSchema = {\n nodeProps: Object.fromEntries(\n nodeProperties?.map((el) => [el.labels, el.properties]) || []\n ),\n relProps: Object.fromEntries(\n relationshipsProperties?.map((el) => [el.type, el.properties]) || []\n ),\n relationships: relationships || [],\n metadata: {\n constraint,\n index,\n },\n };\n\n if (this.enhancedSchema) {\n const schemaCounts = await this.query(\n `CALL apoc.meta.graphSample() YIELD nodes, relationships ` +\n `RETURN nodes, [rel in relationships | {name: apoc.any.property(rel, 'type'), count: apoc.any.property(rel, 'count')}] AS relationships`\n );\n for (const node of schemaCounts[0].nodes) {\n if (EXCLUDED_LABELS.includes(node.name)) {\n continue;\n }\n\n const nodeProps = this.structuredSchema.nodeProps[node.name];\n\n if (!nodeProps) {\n continue;\n }\n\n const enhancedCypher = await this.enhancedSchemaCypher(\n node.name,\n nodeProps,\n node.count < EXHAUSTIVE_SEARCH_LIMIT\n );\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of nodeProps) {\n if (enhancedInfo[prop.property]) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n\n for (const rel of schemaCounts[0].relationships) {\n if (EXCLUDED_RELS.includes(rel.name)) {\n continue;\n }\n const relProps = this.structuredSchema.relProps[rel.name];\n\n if (!relProps) {\n continue;\n }\n const enhancedCypher = await this.enhancedSchemaCypher(\n rel.name,\n relProps,\n rel.count < EXHAUSTIVE_SEARCH_LIMIT,\n true\n );\n\n const enhancedInfoPromise = await this.query(enhancedCypher);\n const enhancedInfo = enhancedInfoPromise[0].output;\n\n for (const prop of relProps) {\n if (prop.property in enhancedInfo) {\n Object.assign(prop, enhancedInfo[prop.property]);\n }\n }\n }\n }\n\n this.schema = formatSchema(this.structuredSchema, this.enhancedSchema);\n }\n\n async enhancedSchemaCypher(\n labelOrType: string,\n properties: { property: string; type: string }[],\n exhaustive: boolean,\n isRelationship = false\n ) {\n let matchClause = isRelationship\n ? `MATCH ()-[n:\\`${labelOrType}\\`]->()`\n : `MATCH (n:\\`${labelOrType}\\`)`;\n\n const withClauses: string[] = [];\n const returnClauses: string[] = [];\n const outputDict: { [key: string]: string } = {};\n\n if (exhaustive) {\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n if (propType === \"STRING\") {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(\n `values: \\`${propName}_values\\`[..${DISTINCT_VALUE_LIMIT}], distinct_count: size(\\`${propName}_values\\`)`\n );\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n } else {\n matchClause += ` WITH n LIMIT 5`;\n\n for (const prop of properties) {\n const propName = prop.property;\n const propType = prop.type;\n\n const propIndex = this.structuredSchema?.metadata?.index.filter(\n (el: Any) =>\n el.label === labelOrType &&\n el.properties[0] === propName &&\n el.type === \"RANGE\"\n );\n\n if (propType === \"STRING\") {\n if (\n propIndex.length > 0 &&\n propIndex[0].size > 0 &&\n propIndex[0].distinctValues <= DISTINCT_VALUE_LIMIT\n ) {\n const distinctValuesPromise = await this.query(\n `CALL apoc.schema.properties.distinct('${labelOrType}', '${propName}') YIELD value`\n );\n const distinctValues = distinctValuesPromise[0].value;\n returnClauses.push(\n `values: ${distinctValues}, distinct_count: ${distinctValues.length}`\n );\n } else {\n withClauses.push(\n `collect(distinct substring(n.\\`${propName}\\`, 0, 50)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n }\n } else if (\n [\"INTEGER\", \"FLOAT\", \"DATE\", \"DATE_TIME\", \"LOCAL_DATE_TIME\"].includes(\n propType\n )\n ) {\n if (!propIndex) {\n withClauses.push(\n `collect(distinct toString(n.\\`${propName}\\`)) AS \\`${propName}_values\\``\n );\n returnClauses.push(`values: ${propName}_values`);\n } else {\n withClauses.push(`min(n.\\`${propName}\\`) AS \\`${propName}_min\\``);\n withClauses.push(`max(n.\\`${propName}\\`) AS \\`${propName}_max\\``);\n withClauses.push(\n `count(distinct n.\\`${propName}\\`) AS \\`${propName}_distinct\\``\n );\n returnClauses.push(\n `min: toString(\\`${propName}_min\\`), max: toString(\\`${propName}_max\\`), distinct_count: \\`${propName}_distinct\\``\n );\n }\n } else if (propType === \"LIST\") {\n withClauses.push(\n `min(size(n.\\`${propName}\\`)) AS \\`${propName}_size_min\\`, max(size(n.\\`${propName}\\`)) AS \\`${propName}_size_max\\``\n );\n returnClauses.push(\n `min_size: \\`${propName}_size_min\\`, max_size: \\`${propName}_size_max\\``\n );\n } else if ([\"BOOLEAN\", \"POINT\", \"DURATION\"].includes(propType)) {\n continue;\n }\n\n outputDict[propName] = `{${returnClauses.pop()}}`;\n }\n }\n\n const withClause = `WITH ${withClauses.join(\", \")}`;\n const returnClause = `RETURN {${Object.entries(outputDict)\n .map(([k, v]) => `\\`${k}\\`: ${v}`)\n .join(\", \")}} AS output`;\n\n const cypherQuery = [matchClause, withClause, returnClause].join(\"\\n\");\n\n return cypherQuery;\n }\n\n async addGraphDocuments(\n graphDocuments: GraphDocument[],\n config: AddGraphDocumentsConfig = {}\n ): Promise<void> {\n const { baseEntityLabel } = config;\n\n if (baseEntityLabel) {\n const constraintExists =\n this.structuredSchema?.metadata?.constraint?.some(\n (el: Any) =>\n JSON.stringify(el.labelsOrTypes) ===\n JSON.stringify([BASE_ENTITY_LABEL]) &&\n JSON.stringify(el.properties) === JSON.stringify([\"id\"])\n ) ?? false;\n\n if (!constraintExists) {\n await this.query(`\n CREATE CONSTRAINT IF NOT EXISTS FOR (b:${BASE_ENTITY_LABEL})\n REQUIRE b.id IS UNIQUE;\n `);\n await this.refreshSchema();\n }\n }\n\n const nodeImportQuery = getNodeImportQuery(config);\n const relImportQuery = getRelImportQuery(config);\n\n for (const document of graphDocuments) {\n if (!document.source.metadata.id) {\n document.source.metadata.id = sha256(document.source.pageContent);\n }\n\n await this.query(nodeImportQuery, {\n data: document.nodes.map((el: Any) => ({ ...el })),\n document: { ...document.source },\n });\n\n await this.query(relImportQuery, {\n data: document.relationships.map((el: Any) => ({\n source: el.source.id,\n source_label: el.source.type,\n target: el.target.id,\n target_label: el.target.type,\n type: el.type.replace(/ /g, \"_\").toUpperCase(),\n properties: el.properties,\n })),\n });\n }\n }\n\n async close() {\n await this.driver.close();\n }\n}\n\nfunction getNodeImportQuery({\n baseEntityLabel,\n includeSource,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n MERGE(source: \\`${BASE_ENTITY_LABEL}\\` {id: row.id})\n SET source += row.properties\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(source)\" : \"\"}\n WITH source, row\n CALL apoc.create.addLabels(source, [row.type]) YIELD node\n RETURN distinct 'done' AS result\n `;\n } else {\n return `\n ${includeSource ? INCLUDE_DOCS_QUERY : \"\"}\n UNWIND $data AS row\n CALL apoc.merge.node([row.type], {id: row.id},\n row.properties, {}) YIELD node\n ${includeSource ? \"MERGE (d)-[:MENTIONS]->(node)\" : \"\"}\n RETURN distinct 'done' AS result\n `;\n }\n}\n\nfunction getRelImportQuery({\n baseEntityLabel,\n}: AddGraphDocumentsConfig): string {\n if (baseEntityLabel) {\n return `\n UNWIND $data AS row\n MERGE (source:\\`${BASE_ENTITY_LABEL}\\` {id: row.source})\n MERGE (target:\\`${BASE_ENTITY_LABEL}\\` {id: row.target})\n WITH source, target, row\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n } else {\n return `\n UNWIND $data AS row\n CALL apoc.merge.node([row.source_label], {id: row.source},\n {}, {}) YIELD node as source\n CALL apoc.merge.node([row.target_label], {id: row.target},\n {}, {}) YIELD node as target\n CALL apoc.merge.relationship(source, row.type,\n {}, row.properties, target) YIELD rel\n RETURN distinct 'done'\n `;\n }\n}\n\nfunction toObjects<\n RecordShape extends Record<string, Any> = Record<string, Any>,\n>(records: Neo4jRecord<RecordShape>): RecordShape[] {\n return records.map((record: Any) => {\n const rObj = record.toObject();\n const out: Partial<RecordShape> = {};\n Object.keys(rObj).forEach((key: keyof RecordShape) => {\n out[key] = itemIntToString(rObj[key]);\n });\n return out as RecordShape;\n });\n}\n\nfunction itemIntToString(item: Any): Any {\n if (neo4j.isInt(item)) return item.toString();\n if (Array.isArray(item)) return item.map((ii) => itemIntToString(ii));\n if ([\"number\", \"string\", \"boolean\"].indexOf(typeof item) !== -1) return item;\n if (item === null) return item;\n if (typeof item === \"object\") return objIntToString(item);\n}\n\nfunction objIntToString(obj: Any) {\n const entry = extractFromNeoObjects(obj);\n let newObj: Any = null;\n if (Array.isArray(entry)) {\n newObj = entry.map((item) => itemIntToString(item));\n } else if (entry !== null && typeof entry === \"object\") {\n newObj = {};\n Object.keys(entry).forEach((key) => {\n newObj[key] = itemIntToString(entry[key]);\n });\n }\n return newObj;\n}\n\nfunction extractFromNeoObjects(obj: Any) {\n if (\n // oxlint-disable-next-line\n obj instanceof (neo4j.types.Node as any) ||\n // oxlint-disable-next-line\n obj instanceof (neo4j.types.Relationship as any)\n ) {\n return obj.properties;\n // oxlint-disable-next-line\n } else if (obj instanceof (neo4j.types.Path as any)) {\n // oxlint-disable-next-line\n return [].concat.apply<any[], any[], any[]>([], extractPathForRows(obj));\n }\n return obj;\n}\n\nconst extractPathForRows = (path: Neo4jPath) => {\n let { segments } = path;\n if (!Array.isArray(path.segments) || path.segments.length < 1) {\n segments = [{ ...path, end: null } as Any];\n }\n\n return segments.map((segment: Any) =>\n [\n objIntToString(segment.start),\n objIntToString(segment.relationship),\n objIntToString(segment.end),\n ].filter((part) => part !== null)\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Neo4jChatMessageHistory, Neo4jChatMessageHistoryConfigInput } from "./neo4j.cjs";
|
|
@@ -31,8 +31,7 @@ var Neo4jChatMessageHistory = class Neo4jChatMessageHistory extends _langchain_c
|
|
|
31
31
|
if (url && username && password) try {
|
|
32
32
|
this.driver = neo4j_driver.default.driver(url, neo4j_driver.auth.basic(username, password));
|
|
33
33
|
} catch (e) {
|
|
34
|
-
|
|
35
|
-
throw new Error(`Could not create a Neo4j driver instance. Please check the connection details.\nCause: ${error.message}`);
|
|
34
|
+
throw new Error(`Could not create a Neo4j driver instance. Please check the connection details.\nCause: ${e.message}`);
|
|
36
35
|
}
|
|
37
36
|
else throw new Error("Neo4j connection details not provided.");
|
|
38
37
|
}
|
|
@@ -41,8 +40,7 @@ var Neo4jChatMessageHistory = class Neo4jChatMessageHistory extends _langchain_c
|
|
|
41
40
|
try {
|
|
42
41
|
await instance.verifyConnectivity();
|
|
43
42
|
} catch (e) {
|
|
44
|
-
|
|
45
|
-
throw new Error(`Could not verify connection to the Neo4j database.\nCause: ${error.message}`);
|
|
43
|
+
throw new Error(`Could not verify connection to the Neo4j database.\nCause: ${e.message}`);
|
|
46
44
|
}
|
|
47
45
|
return instance;
|
|
48
46
|
}
|
|
@@ -64,8 +62,7 @@ var Neo4jChatMessageHistory = class Neo4jChatMessageHistory extends _langchain_c
|
|
|
64
62
|
const { records } = await this.driver.executeQuery(getMessagesCypherQuery, { sessionId: this.sessionId });
|
|
65
63
|
return (0, _langchain_core_messages.mapStoredMessagesToChatMessages)(records.map((record) => record.get("result")));
|
|
66
64
|
} catch (e) {
|
|
67
|
-
|
|
68
|
-
throw new Error(`Ohno! Couldn't get messages.\nCause: ${error.message}`);
|
|
65
|
+
throw new Error(`Ohno! Couldn't get messages.\nCause: ${e.message}`);
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
68
|
async addMessage(message) {
|
|
@@ -87,8 +84,7 @@ var Neo4jChatMessageHistory = class Neo4jChatMessageHistory extends _langchain_c
|
|
|
87
84
|
content: message.content
|
|
88
85
|
});
|
|
89
86
|
} catch (e) {
|
|
90
|
-
|
|
91
|
-
throw new Error(`Ohno! Couldn't add message.\nCause: ${error.message}`);
|
|
87
|
+
throw new Error(`Ohno! Couldn't add message.\nCause: ${e.message}`);
|
|
92
88
|
}
|
|
93
89
|
}
|
|
94
90
|
async clear() {
|
|
@@ -100,8 +96,7 @@ var Neo4jChatMessageHistory = class Neo4jChatMessageHistory extends _langchain_c
|
|
|
100
96
|
try {
|
|
101
97
|
await this.driver.executeQuery(clearMessagesCypherQuery, { sessionId: this.sessionId });
|
|
102
98
|
} catch (e) {
|
|
103
|
-
|
|
104
|
-
throw new Error(`Ohno! Couldn't clear chat history.\nCause: ${error.message}`);
|
|
99
|
+
throw new Error(`Ohno! Couldn't clear chat history.\nCause: ${e.message}`);
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
102
|
async close() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neo4j.cjs","names":["BaseListChatMessageHistory","neo4j","auth"],"sources":["../../../src/stores/message/neo4j.ts"],"sourcesContent":["import neo4j, { Driver, Record, auth, type ServerInfo } from \"neo4j-driver\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { BaseListChatMessageHistory } from \"@langchain/core/chat_history\";\nimport {\n BaseMessage,\n mapStoredMessagesToChatMessages,\n} from \"@langchain/core/messages\";\n\nexport type Neo4jChatMessageHistoryConfigInput = {\n sessionId?: string | number;\n sessionNodeLabel?: string;\n messageNodeLabel?: string;\n url: string;\n username: string;\n password: string;\n windowSize?: number;\n};\n\nconst defaultConfig = {\n sessionNodeLabel: \"ChatSession\",\n messageNodeLabel: \"ChatMessage\",\n windowSize: 3,\n};\n\nexport class Neo4jChatMessageHistory extends BaseListChatMessageHistory {\n lc_namespace: string[] = [\"langchain\", \"stores\", \"message\", \"neo4j\"];\n\n sessionId: string | number;\n\n sessionNodeLabel: string;\n\n messageNodeLabel: string;\n\n windowSize: number;\n\n private driver: Driver;\n\n constructor({\n sessionId = uuidv4(),\n sessionNodeLabel = defaultConfig.sessionNodeLabel,\n messageNodeLabel = defaultConfig.messageNodeLabel,\n url,\n username,\n password,\n windowSize = defaultConfig.windowSize,\n }: Neo4jChatMessageHistoryConfigInput) {\n super();\n\n this.sessionId = sessionId;\n this.sessionNodeLabel = sessionNodeLabel;\n this.messageNodeLabel = messageNodeLabel;\n this.windowSize = windowSize;\n\n if (url && username && password) {\n try {\n this.driver = neo4j.driver(url, auth.basic(username, password));\n } catch (e) {\n const error = e as Error;\n throw new Error(\n `Could not create a Neo4j driver instance. Please check the connection details.\\nCause: ${error.message}`\n );\n }\n } else {\n throw new Error(\"Neo4j connection details not provided.\");\n }\n }\n\n static async initialize(\n props: Neo4jChatMessageHistoryConfigInput\n ): Promise<Neo4jChatMessageHistory> {\n const instance = new Neo4jChatMessageHistory(props);\n\n try {\n await instance.verifyConnectivity();\n } catch (e) {\n const error = e as Error;\n throw new Error(\n `Could not verify connection to the Neo4j database.\\nCause: ${error.message}`\n );\n }\n\n return instance;\n }\n\n async verifyConnectivity(): Promise<ServerInfo> {\n const connectivity = await this.driver.getServerInfo();\n return connectivity;\n }\n\n async getMessages(): Promise<BaseMessage[]> {\n const getMessagesCypherQuery = `\n MERGE (chatSession:${this.sessionNodeLabel} {id: $sessionId})\n WITH chatSession\n MATCH (chatSession)-[:LAST_MESSAGE]->(lastMessage)\n MATCH p=(lastMessage)<-[:NEXT*0..${this.windowSize * 2 - 1}]-()\n WITH p, length(p) AS length\n ORDER BY length DESC LIMIT 1\n UNWIND reverse(nodes(p)) AS node\n RETURN {data:{content: node.content}, type:node.type} AS result\n `;\n\n try {\n const { records } = await this.driver.executeQuery(\n getMessagesCypherQuery,\n {\n sessionId: this.sessionId,\n }\n );\n const results = records.map((record: Record) => record.get(\"result\"));\n\n return mapStoredMessagesToChatMessages(results);\n } catch (e) {\n const error = e as Error;\n throw new Error(`Ohno! Couldn't get messages.\\nCause: ${error.message}`);\n }\n }\n\n async addMessage(message: BaseMessage): Promise<void> {\n const addMessageCypherQuery = `\n MERGE (chatSession:${this.sessionNodeLabel} {id: $sessionId})\n WITH chatSession\n OPTIONAL MATCH (chatSession)-[lastMessageRel:LAST_MESSAGE]->(lastMessage)\n CREATE (chatSession)-[:LAST_MESSAGE]->(newLastMessage:${this.messageNodeLabel})\n SET newLastMessage += {type:$type, content:$content}\n WITH newLastMessage, lastMessageRel, lastMessage\n WHERE lastMessage IS NOT NULL\n CREATE (lastMessage)-[:NEXT]->(newLastMessage)\n DELETE lastMessageRel\n `;\n\n try {\n await this.driver.executeQuery(addMessageCypherQuery, {\n sessionId: this.sessionId,\n type: message.getType(),\n content: message.content,\n });\n } catch (e) {\n const error = e as Error;\n throw new Error(`Ohno! Couldn't add message.\\nCause: ${error.message}`);\n }\n }\n\n async clear() {\n const clearMessagesCypherQuery = `\n MATCH p=(chatSession:${this.sessionNodeLabel} {id: $sessionId})-[:LAST_MESSAGE]->(lastMessage)<-[:NEXT*0..]-()\n UNWIND nodes(p) as node\n DETACH DELETE node\n `;\n\n try {\n await this.driver.executeQuery(clearMessagesCypherQuery, {\n sessionId: this.sessionId,\n });\n } catch (e) {\n const error = e as Error;\n throw new Error(\n `Ohno! Couldn't clear chat history.\\nCause: ${error.message}`\n );\n }\n }\n\n async close() {\n await this.driver.close();\n }\n}\n"],"mappings":";;;;;;;AAkBA,MAAM,gBAAgB;CACpB,kBAAkB;CAClB,kBAAkB;CAClB,YAAY;CACb;AAED,IAAa,0BAAb,MAAa,gCAAgCA,6BAAAA,2BAA2B;CACtE,eAAyB;EAAC;EAAa;EAAU;EAAW;EAAQ;CAEpE;CAEA;CAEA;CAEA;CAEA;CAEA,YAAY,EACV,aAAA,GAAA,KAAA,KAAoB,EACpB,mBAAmB,cAAc,kBACjC,mBAAmB,cAAc,kBACjC,KACA,UACA,UACA,aAAa,cAAc,cACU;AACrC,SAAO;AAEP,OAAK,YAAY;AACjB,OAAK,mBAAmB;AACxB,OAAK,mBAAmB;AACxB,OAAK,aAAa;AAElB,MAAI,OAAO,YAAY,SACrB,KAAI;AACF,QAAK,SAASC,aAAAA,QAAM,OAAO,KAAKC,aAAAA,KAAK,MAAM,UAAU,SAAS,CAAC;WACxD,GAAG;
|
|
1
|
+
{"version":3,"file":"neo4j.cjs","names":["BaseListChatMessageHistory","neo4j","auth"],"sources":["../../../src/stores/message/neo4j.ts"],"sourcesContent":["import neo4j, { Driver, Record, auth, type ServerInfo } from \"neo4j-driver\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { BaseListChatMessageHistory } from \"@langchain/core/chat_history\";\nimport {\n BaseMessage,\n mapStoredMessagesToChatMessages,\n} from \"@langchain/core/messages\";\n\nexport type Neo4jChatMessageHistoryConfigInput = {\n sessionId?: string | number;\n sessionNodeLabel?: string;\n messageNodeLabel?: string;\n url: string;\n username: string;\n password: string;\n windowSize?: number;\n};\n\nconst defaultConfig = {\n sessionNodeLabel: \"ChatSession\",\n messageNodeLabel: \"ChatMessage\",\n windowSize: 3,\n};\n\nexport class Neo4jChatMessageHistory extends BaseListChatMessageHistory {\n lc_namespace: string[] = [\"langchain\", \"stores\", \"message\", \"neo4j\"];\n\n sessionId: string | number;\n\n sessionNodeLabel: string;\n\n messageNodeLabel: string;\n\n windowSize: number;\n\n private driver: Driver;\n\n constructor({\n sessionId = uuidv4(),\n sessionNodeLabel = defaultConfig.sessionNodeLabel,\n messageNodeLabel = defaultConfig.messageNodeLabel,\n url,\n username,\n password,\n windowSize = defaultConfig.windowSize,\n }: Neo4jChatMessageHistoryConfigInput) {\n super();\n\n this.sessionId = sessionId;\n this.sessionNodeLabel = sessionNodeLabel;\n this.messageNodeLabel = messageNodeLabel;\n this.windowSize = windowSize;\n\n if (url && username && password) {\n try {\n this.driver = neo4j.driver(url, auth.basic(username, password));\n } catch (e) {\n const error = e as Error;\n throw new Error(\n `Could not create a Neo4j driver instance. Please check the connection details.\\nCause: ${error.message}`\n );\n }\n } else {\n throw new Error(\"Neo4j connection details not provided.\");\n }\n }\n\n static async initialize(\n props: Neo4jChatMessageHistoryConfigInput\n ): Promise<Neo4jChatMessageHistory> {\n const instance = new Neo4jChatMessageHistory(props);\n\n try {\n await instance.verifyConnectivity();\n } catch (e) {\n const error = e as Error;\n throw new Error(\n `Could not verify connection to the Neo4j database.\\nCause: ${error.message}`\n );\n }\n\n return instance;\n }\n\n async verifyConnectivity(): Promise<ServerInfo> {\n const connectivity = await this.driver.getServerInfo();\n return connectivity;\n }\n\n async getMessages(): Promise<BaseMessage[]> {\n const getMessagesCypherQuery = `\n MERGE (chatSession:${this.sessionNodeLabel} {id: $sessionId})\n WITH chatSession\n MATCH (chatSession)-[:LAST_MESSAGE]->(lastMessage)\n MATCH p=(lastMessage)<-[:NEXT*0..${this.windowSize * 2 - 1}]-()\n WITH p, length(p) AS length\n ORDER BY length DESC LIMIT 1\n UNWIND reverse(nodes(p)) AS node\n RETURN {data:{content: node.content}, type:node.type} AS result\n `;\n\n try {\n const { records } = await this.driver.executeQuery(\n getMessagesCypherQuery,\n {\n sessionId: this.sessionId,\n }\n );\n const results = records.map((record: Record) => record.get(\"result\"));\n\n return mapStoredMessagesToChatMessages(results);\n } catch (e) {\n const error = e as Error;\n throw new Error(`Ohno! Couldn't get messages.\\nCause: ${error.message}`);\n }\n }\n\n async addMessage(message: BaseMessage): Promise<void> {\n const addMessageCypherQuery = `\n MERGE (chatSession:${this.sessionNodeLabel} {id: $sessionId})\n WITH chatSession\n OPTIONAL MATCH (chatSession)-[lastMessageRel:LAST_MESSAGE]->(lastMessage)\n CREATE (chatSession)-[:LAST_MESSAGE]->(newLastMessage:${this.messageNodeLabel})\n SET newLastMessage += {type:$type, content:$content}\n WITH newLastMessage, lastMessageRel, lastMessage\n WHERE lastMessage IS NOT NULL\n CREATE (lastMessage)-[:NEXT]->(newLastMessage)\n DELETE lastMessageRel\n `;\n\n try {\n await this.driver.executeQuery(addMessageCypherQuery, {\n sessionId: this.sessionId,\n type: message.getType(),\n content: message.content,\n });\n } catch (e) {\n const error = e as Error;\n throw new Error(`Ohno! Couldn't add message.\\nCause: ${error.message}`);\n }\n }\n\n async clear() {\n const clearMessagesCypherQuery = `\n MATCH p=(chatSession:${this.sessionNodeLabel} {id: $sessionId})-[:LAST_MESSAGE]->(lastMessage)<-[:NEXT*0..]-()\n UNWIND nodes(p) as node\n DETACH DELETE node\n `;\n\n try {\n await this.driver.executeQuery(clearMessagesCypherQuery, {\n sessionId: this.sessionId,\n });\n } catch (e) {\n const error = e as Error;\n throw new Error(\n `Ohno! Couldn't clear chat history.\\nCause: ${error.message}`\n );\n }\n }\n\n async close() {\n await this.driver.close();\n }\n}\n"],"mappings":";;;;;;;AAkBA,MAAM,gBAAgB;CACpB,kBAAkB;CAClB,kBAAkB;CAClB,YAAY;CACb;AAED,IAAa,0BAAb,MAAa,gCAAgCA,6BAAAA,2BAA2B;CACtE,eAAyB;EAAC;EAAa;EAAU;EAAW;EAAQ;CAEpE;CAEA;CAEA;CAEA;CAEA;CAEA,YAAY,EACV,aAAA,GAAA,KAAA,KAAoB,EACpB,mBAAmB,cAAc,kBACjC,mBAAmB,cAAc,kBACjC,KACA,UACA,UACA,aAAa,cAAc,cACU;AACrC,SAAO;AAEP,OAAK,YAAY;AACjB,OAAK,mBAAmB;AACxB,OAAK,mBAAmB;AACxB,OAAK,aAAa;AAElB,MAAI,OAAO,YAAY,SACrB,KAAI;AACF,QAAK,SAASC,aAAAA,QAAM,OAAO,KAAKC,aAAAA,KAAK,MAAM,UAAU,SAAS,CAAC;WACxD,GAAG;AAEV,SAAM,IAAI,MACR,0FAFY,EAEoF,UACjG;;MAGH,OAAM,IAAI,MAAM,yCAAyC;;CAI7D,aAAa,WACX,OACkC;EAClC,MAAM,WAAW,IAAI,wBAAwB,MAAM;AAEnD,MAAI;AACF,SAAM,SAAS,oBAAoB;WAC5B,GAAG;AAEV,SAAM,IAAI,MACR,8DAFY,EAEwD,UACrE;;AAGH,SAAO;;CAGT,MAAM,qBAA0C;AAE9C,SADqB,MAAM,KAAK,OAAO,eAAe;;CAIxD,MAAM,cAAsC;EAC1C,MAAM,yBAAyB;2BACR,KAAK,iBAAiB;;;yCAGR,KAAK,aAAa,IAAI,EAAE;;;;;;AAO7D,MAAI;GACF,MAAM,EAAE,YAAY,MAAM,KAAK,OAAO,aACpC,wBACA,EACE,WAAW,KAAK,WACjB,CACF;AAGD,WAAA,GAAA,yBAAA,iCAFgB,QAAQ,KAAK,WAAmB,OAAO,IAAI,SAAS,CAAC,CAEtB;WACxC,GAAG;AAEV,SAAM,IAAI,MAAM,wCADF,EACgD,UAAU;;;CAI5E,MAAM,WAAW,SAAqC;EACpD,MAAM,wBAAwB;2BACP,KAAK,iBAAiB;;;8DAGa,KAAK,iBAAiB;;;;;;;AAQhF,MAAI;AACF,SAAM,KAAK,OAAO,aAAa,uBAAuB;IACpD,WAAW,KAAK;IAChB,MAAM,QAAQ,SAAS;IACvB,SAAS,QAAQ;IAClB,CAAC;WACK,GAAG;AAEV,SAAM,IAAI,MAAM,uCADF,EAC+C,UAAU;;;CAI3E,MAAM,QAAQ;EACZ,MAAM,2BAA2B;6BACR,KAAK,iBAAiB;;;;AAK/C,MAAI;AACF,SAAM,KAAK,OAAO,aAAa,0BAA0B,EACvD,WAAW,KAAK,WACjB,CAAC;WACK,GAAG;AAEV,SAAM,IAAI,MACR,8CAFY,EAEwC,UACrD;;;CAIL,MAAM,QAAQ;AACZ,QAAM,KAAK,OAAO,OAAO"}
|