@ductape/sdk 0.0.4-v5 → 0.0.4-v51
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 +1 -1
- package/dist/api/services/appApi.service.d.ts +48 -2
- package/dist/api/services/appApi.service.js +101 -2
- package/dist/api/services/appApi.service.js.map +1 -1
- package/dist/api/services/pricingApi.service.d.ts +10 -0
- package/dist/api/services/pricingApi.service.js +34 -0
- package/dist/api/services/pricingApi.service.js.map +1 -0
- package/dist/api/services/processorApi.service.d.ts +12 -2
- package/dist/api/services/processorApi.service.js +12 -2
- package/dist/api/services/processorApi.service.js.map +1 -1
- package/dist/api/services/productsApi.service.d.ts +40 -1
- package/dist/api/services/productsApi.service.js +105 -1
- package/dist/api/services/productsApi.service.js.map +1 -1
- package/dist/api/services/userApi.service.js +1 -0
- package/dist/api/services/userApi.service.js.map +1 -1
- package/dist/api/services/workspaceApi.service.js +1 -0
- package/dist/api/services/workspaceApi.service.js.map +1 -1
- package/dist/api/services/workspaceSecretsApi.service.d.ts +75 -0
- package/dist/api/services/workspaceSecretsApi.service.js +62 -0
- package/dist/api/services/workspaceSecretsApi.service.js.map +1 -0
- package/dist/api/urls.d.ts +6 -1
- package/dist/api/urls.js +12 -2
- package/dist/api/urls.js.map +1 -1
- package/dist/api/utils/cache.utils.d.ts +1 -1
- package/dist/api/utils/cache.utils.js +10 -4
- package/dist/api/utils/cache.utils.js.map +1 -1
- package/dist/api/utils/strings.utils.d.ts +2 -0
- package/dist/api/utils/strings.utils.js +14 -0
- package/dist/api/utils/strings.utils.js.map +1 -1
- package/dist/apps/services/app.service.d.ts +51 -33
- package/dist/apps/services/app.service.js +488 -244
- package/dist/apps/services/app.service.js.map +1 -1
- package/dist/apps/validators/joi-validators/create.appAction.validator.d.ts +1 -2
- package/dist/apps/validators/joi-validators/create.appAction.validator.js +21 -2
- package/dist/apps/validators/joi-validators/create.appAction.validator.js.map +1 -1
- package/dist/apps/validators/joi-validators/create.appWebhook.validator.d.ts +1 -2
- package/dist/apps/validators/joi-validators/create.appWebhook.validator.js +2 -15
- package/dist/apps/validators/joi-validators/create.appWebhook.validator.js.map +1 -1
- package/dist/apps/validators/joi-validators/update.appAction.validator.js +11 -1
- package/dist/apps/validators/joi-validators/update.appAction.validator.js.map +1 -1
- package/dist/apps/validators/joi-validators/update.appActionResponse.validator.d.ts +1 -1
- package/dist/apps/validators/joi-validators/update.appActionResponse.validator.js +34 -1
- package/dist/apps/validators/joi-validators/update.appActionResponse.validator.js.map +1 -1
- package/dist/apps/validators/joi-validators/update.appWebhook.validator.d.ts +1 -2
- package/dist/apps/validators/joi-validators/update.appWebhook.validator.js +2 -14
- package/dist/apps/validators/joi-validators/update.appWebhook.validator.js.map +1 -1
- package/dist/clients/pricing.client.d.ts +3 -0
- package/dist/clients/pricing.client.js +33 -0
- package/dist/clients/pricing.client.js.map +1 -0
- package/dist/database/adapters/base.adapter.d.ts +176 -0
- package/dist/database/adapters/base.adapter.js +31 -0
- package/dist/database/adapters/base.adapter.js.map +1 -0
- package/dist/database/adapters/dynamodb.adapter.d.ts +91 -0
- package/dist/database/adapters/dynamodb.adapter.js +1608 -0
- package/dist/database/adapters/dynamodb.adapter.js.map +1 -0
- package/dist/database/adapters/mongodb.adapter.d.ts +71 -0
- package/dist/database/adapters/mongodb.adapter.js +1072 -0
- package/dist/database/adapters/mongodb.adapter.js.map +1 -0
- package/dist/database/adapters/mysql.adapter.d.ts +146 -0
- package/dist/database/adapters/mysql.adapter.js +1492 -0
- package/dist/database/adapters/mysql.adapter.js.map +1 -0
- package/dist/database/adapters/postgresql.adapter.d.ts +147 -0
- package/dist/database/adapters/postgresql.adapter.js +1603 -0
- package/dist/database/adapters/postgresql.adapter.js.map +1 -0
- package/dist/database/database.service.d.ts +232 -0
- package/dist/database/database.service.js +802 -0
- package/dist/database/database.service.js.map +1 -0
- package/dist/database/index.d.ts +18 -0
- package/dist/database/index.js +98 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/types/aggregation.types.d.ts +261 -0
- package/dist/database/types/aggregation.types.js +21 -0
- package/dist/database/types/aggregation.types.js.map +1 -0
- package/dist/database/types/connection.types.d.ts +132 -0
- package/dist/database/types/connection.types.js +6 -0
- package/dist/database/types/connection.types.js.map +1 -0
- package/dist/database/types/database.types.d.ts +175 -0
- package/dist/database/types/database.types.js +75 -0
- package/dist/database/types/database.types.js.map +1 -0
- package/dist/database/types/index.d.ts +12 -0
- package/dist/database/types/index.js +37 -0
- package/dist/database/types/index.js.map +1 -0
- package/dist/database/types/index.types.d.ts +220 -0
- package/dist/database/types/index.types.js +27 -0
- package/dist/database/types/index.types.js.map +1 -0
- package/dist/database/types/migration.types.d.ts +205 -0
- package/dist/database/types/migration.types.js +44 -0
- package/dist/database/types/migration.types.js.map +1 -0
- package/dist/database/types/query.types.d.ts +305 -0
- package/dist/database/types/query.types.js +57 -0
- package/dist/database/types/query.types.js.map +1 -0
- package/dist/database/types/result.types.d.ts +220 -0
- package/dist/database/types/result.types.js +6 -0
- package/dist/database/types/result.types.js.map +1 -0
- package/dist/database/types/schema.types.d.ts +190 -0
- package/dist/database/types/schema.types.js +69 -0
- package/dist/database/types/schema.types.js.map +1 -0
- package/dist/database/utils/helpers.d.ts +66 -0
- package/dist/database/utils/helpers.js +501 -0
- package/dist/database/utils/helpers.js.map +1 -0
- package/dist/database/utils/migration.utils.d.ts +151 -0
- package/dist/database/utils/migration.utils.js +476 -0
- package/dist/database/utils/migration.utils.js.map +1 -0
- package/dist/database/utils/transaction.d.ts +64 -0
- package/dist/database/utils/transaction.js +130 -0
- package/dist/database/utils/transaction.js.map +1 -0
- package/dist/database/validators/connection.validator.d.ts +20 -0
- package/dist/database/validators/connection.validator.js +267 -0
- package/dist/database/validators/connection.validator.js.map +1 -0
- package/dist/database/validators/query.validator.d.ts +31 -0
- package/dist/database/validators/query.validator.js +305 -0
- package/dist/database/validators/query.validator.js.map +1 -0
- package/dist/database/validators/schema.validator.d.ts +31 -0
- package/dist/database/validators/schema.validator.js +334 -0
- package/dist/database/validators/schema.validator.js.map +1 -0
- package/dist/graph/adapters/arangodb.adapter.d.ts +80 -0
- package/dist/graph/adapters/arangodb.adapter.js +1393 -0
- package/dist/graph/adapters/arangodb.adapter.js.map +1 -0
- package/dist/graph/adapters/base.adapter.d.ts +228 -0
- package/dist/graph/adapters/base.adapter.js +38 -0
- package/dist/graph/adapters/base.adapter.js.map +1 -0
- package/dist/graph/adapters/index.d.ts +10 -0
- package/dist/graph/adapters/index.js +23 -0
- package/dist/graph/adapters/index.js.map +1 -0
- package/dist/graph/adapters/memgraph.adapter.d.ts +85 -0
- package/dist/graph/adapters/memgraph.adapter.js +1491 -0
- package/dist/graph/adapters/memgraph.adapter.js.map +1 -0
- package/dist/graph/adapters/neo4j.adapter.d.ts +88 -0
- package/dist/graph/adapters/neo4j.adapter.js +1861 -0
- package/dist/graph/adapters/neo4j.adapter.js.map +1 -0
- package/dist/graph/adapters/neptune.adapter.d.ts +87 -0
- package/dist/graph/adapters/neptune.adapter.js +1430 -0
- package/dist/graph/adapters/neptune.adapter.js.map +1 -0
- package/dist/graph/graph.service.d.ts +278 -0
- package/dist/graph/graph.service.js +687 -0
- package/dist/graph/graph.service.js.map +1 -0
- package/dist/graph/index.d.ts +11 -0
- package/dist/graph/index.js +42 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/types/connection.types.d.ts +158 -0
- package/dist/graph/types/connection.types.js +43 -0
- package/dist/graph/types/connection.types.js.map +1 -0
- package/dist/graph/types/graph.types.d.ts +144 -0
- package/dist/graph/types/graph.types.js +84 -0
- package/dist/graph/types/graph.types.js.map +1 -0
- package/dist/graph/types/index.d.ts +11 -0
- package/dist/graph/types/index.js +35 -0
- package/dist/graph/types/index.js.map +1 -0
- package/dist/graph/types/node.types.d.ts +193 -0
- package/dist/graph/types/node.types.js +49 -0
- package/dist/graph/types/node.types.js.map +1 -0
- package/dist/graph/types/path.types.d.ts +224 -0
- package/dist/graph/types/path.types.js +38 -0
- package/dist/graph/types/path.types.js.map +1 -0
- package/dist/graph/types/query.types.d.ts +247 -0
- package/dist/graph/types/query.types.js +23 -0
- package/dist/graph/types/query.types.js.map +1 -0
- package/dist/graph/types/relationship.types.d.ts +224 -0
- package/dist/graph/types/relationship.types.js +35 -0
- package/dist/graph/types/relationship.types.js.map +1 -0
- package/dist/graph/types/result.types.d.ts +237 -0
- package/dist/graph/types/result.types.js +7 -0
- package/dist/graph/types/result.types.js.map +1 -0
- package/dist/graph/validators/index.d.ts +81 -0
- package/dist/graph/validators/index.js +243 -0
- package/dist/graph/validators/index.js.map +1 -0
- package/dist/imports/imports.service.d.ts +3 -3
- package/dist/imports/imports.service.js +7 -7
- package/dist/imports/imports.service.js.map +1 -1
- package/dist/imports/imports.types.d.ts +8 -0
- package/dist/imports/repos/postmanV21.repo.d.ts +1 -1
- package/dist/imports/repos/postmanV21.repo.js +29 -2
- package/dist/imports/repos/postmanV21.repo.js.map +1 -1
- package/dist/index.d.ts +1244 -150
- package/dist/index.js +1309 -209
- package/dist/index.js.map +1 -1
- package/dist/inputs/inputs.service.js +2 -2
- package/dist/inputs/inputs.service.js.map +1 -1
- package/dist/inputs/utils/inputs.utils.create.js +1 -1
- package/dist/inputs/utils/inputs.utils.create.js.map +1 -1
- package/dist/logs/logs.types.d.ts +5 -0
- package/dist/logs/logs.types.js +1 -0
- package/dist/logs/logs.types.js.map +1 -1
- package/dist/parsers/index.d.ts +3 -0
- package/dist/parsers/index.js +27 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/pipelines/postman.pipelines.d.ts +15 -0
- package/dist/parsers/pipelines/postman.pipelines.js +103 -0
- package/dist/parsers/pipelines/postman.pipelines.js.map +1 -0
- package/dist/parsers/types/postman.types.d.ts +200 -0
- package/dist/parsers/types/postman.types.js +3 -0
- package/dist/parsers/types/postman.types.js.map +1 -0
- package/dist/parsers/utils/postman.utils.d.ts +12 -0
- package/dist/parsers/utils/postman.utils.js +116 -0
- package/dist/parsers/utils/postman.utils.js.map +1 -0
- package/dist/parsers/validators/postman-auth.validators.d.ts +10 -0
- package/dist/parsers/validators/postman-auth.validators.js +127 -0
- package/dist/parsers/validators/postman-auth.validators.js.map +1 -0
- package/dist/parsers/validators/postman-request.validators.d.ts +13 -0
- package/dist/parsers/validators/postman-request.validators.js +139 -0
- package/dist/parsers/validators/postman-request.validators.js.map +1 -0
- package/dist/parsers/validators/postman-response.validators.d.ts +13 -0
- package/dist/parsers/validators/postman-response.validators.js +150 -0
- package/dist/parsers/validators/postman-response.validators.js.map +1 -0
- package/dist/parsers/validators/postman-variable.validators.d.ts +14 -0
- package/dist/parsers/validators/postman-variable.validators.js +163 -0
- package/dist/parsers/validators/postman-variable.validators.js.map +1 -0
- package/dist/pricing/pricing.repo.d.ts +0 -0
- package/dist/pricing/pricing.repo.js +1 -0
- package/dist/pricing/pricing.repo.js.map +1 -0
- package/dist/pricing/pricing.service.d.ts +24 -0
- package/dist/pricing/pricing.service.js +51 -0
- package/dist/pricing/pricing.service.js.map +1 -0
- package/dist/pricing/pricing.types.d.ts +76 -0
- package/dist/pricing/pricing.types.js +21 -0
- package/dist/pricing/pricing.types.js.map +1 -0
- package/dist/pricing/utils/string.utils.d.ts +1 -0
- package/dist/pricing/utils/string.utils.js +9 -0
- package/dist/pricing/utils/string.utils.js.map +1 -0
- package/dist/processor/repos/sms.repo.d.ts +4 -4
- package/dist/processor/repos/sms.repo.js +23 -10
- package/dist/processor/repos/sms.repo.js.map +1 -1
- package/dist/processor/services/messagebrokers/kafka.service.js +0 -2
- package/dist/processor/services/messagebrokers/kafka.service.js.map +1 -1
- package/dist/processor/services/messagebrokers/rabbitmq.service.d.ts +9 -1
- package/dist/processor/services/messagebrokers/rabbitmq.service.js +40 -11
- package/dist/processor/services/messagebrokers/rabbitmq.service.js.map +1 -1
- package/dist/processor/services/processor.service.d.ts +38 -10
- package/dist/processor/services/processor.service.js +533 -248
- package/dist/processor/services/processor.service.js.map +1 -1
- package/dist/processor/services/request.service.d.ts +36 -0
- package/dist/processor/services/request.service.js +304 -0
- package/dist/processor/services/request.service.js.map +1 -0
- package/dist/processor/types/request.types.d.ts +14 -0
- package/dist/processor/types/request.types.js +3 -0
- package/dist/processor/types/request.types.js.map +1 -0
- package/dist/processor/utils/processor.utils.d.ts +3 -0
- package/dist/processor/utils/processor.utils.js +84 -22
- package/dist/processor/utils/processor.utils.js.map +1 -1
- package/dist/processor/utils/request.utils.d.ts +20 -0
- package/dist/processor/utils/request.utils.js +113 -0
- package/dist/processor/utils/request.utils.js.map +1 -0
- package/dist/products/services/products.service.d.ts +114 -77
- package/dist/products/services/products.service.js +805 -362
- package/dist/products/services/products.service.js.map +1 -1
- package/dist/products/services/utils/crypt.utils.d.ts +1 -0
- package/dist/products/services/utils/crypt.utils.js +17 -0
- package/dist/products/services/utils/crypt.utils.js.map +1 -0
- package/dist/products/services/utils/functions.utils.d.ts +13 -0
- package/dist/products/services/utils/functions.utils.js +289 -0
- package/dist/products/services/utils/functions.utils.js.map +1 -0
- package/dist/products/services/utils/objects.utils.d.ts +13 -0
- package/dist/products/services/utils/objects.utils.js +89 -0
- package/dist/products/services/utils/objects.utils.js.map +1 -0
- package/dist/products/services/utils/string.utils.d.ts +12 -0
- package/dist/products/services/utils/string.utils.js +168 -0
- package/dist/products/services/utils/string.utils.js.map +1 -0
- package/dist/products/utils/string.utils.d.ts +1 -1
- package/dist/products/utils/string.utils.js +14 -2
- package/dist/products/utils/string.utils.js.map +1 -1
- package/dist/products/validators/index.d.ts +4 -1
- package/dist/products/validators/index.js +7 -1
- package/dist/products/validators/index.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productDatabaseAction.validator.d.ts +15 -4
- package/dist/products/validators/joi-validators/create.productDatabaseAction.validator.js +501 -109
- package/dist/products/validators/joi-validators/create.productDatabaseAction.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productEnv.validator.js +1 -0
- package/dist/products/validators/joi-validators/create.productEnv.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productGraph.validator.d.ts +3 -0
- package/dist/products/validators/joi-validators/create.productGraph.validator.js +82 -0
- package/dist/products/validators/joi-validators/create.productGraph.validator.js.map +1 -0
- package/dist/products/validators/joi-validators/create.productGraphAction.validator.d.ts +14 -0
- package/dist/products/validators/joi-validators/create.productGraphAction.validator.js +696 -0
- package/dist/products/validators/joi-validators/create.productGraphAction.validator.js.map +1 -0
- package/dist/products/validators/joi-validators/create.productHealthcheck.validator.d.ts +4 -0
- package/dist/products/validators/joi-validators/create.productHealthcheck.validator.js +58 -0
- package/dist/products/validators/joi-validators/create.productHealthcheck.validator.js.map +1 -0
- package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js +1 -0
- package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productMessageBrokers.validator.js +9 -4
- package/dist/products/validators/joi-validators/create.productMessageBrokers.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productNotification.validator.js +5 -2
- package/dist/products/validators/joi-validators/create.productNotification.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.userAuth.validator.js +1 -0
- package/dist/products/validators/joi-validators/create.userAuth.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/update.dataValue.validator.js +1 -0
- package/dist/products/validators/joi-validators/update.dataValue.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/update.productDatabaseAction.validator.d.ts +6 -0
- package/dist/products/validators/joi-validators/update.productDatabaseAction.validator.js +28 -26
- package/dist/products/validators/joi-validators/update.productDatabaseAction.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/update.productEnv.validator.js +3 -0
- package/dist/products/validators/joi-validators/update.productEnv.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/update.productGraph.validator.d.ts +3 -0
- package/dist/products/validators/joi-validators/update.productGraph.validator.js +87 -0
- package/dist/products/validators/joi-validators/update.productGraph.validator.js.map +1 -0
- package/dist/products/validators/joi-validators/update.productGraphAction.validator.d.ts +7 -0
- package/dist/products/validators/joi-validators/update.productGraphAction.validator.js +72 -0
- package/dist/products/validators/joi-validators/update.productGraphAction.validator.js.map +1 -0
- package/dist/products/validators/joi-validators/update.productMessageBrokerTopic.validator.js +1 -0
- package/dist/products/validators/joi-validators/update.productMessageBrokerTopic.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/update.userAuth.validator.js +1 -0
- package/dist/products/validators/joi-validators/update.userAuth.validator.js.map +1 -1
- package/dist/test/test.health.d.ts +1 -0
- package/dist/test/test.health.js +49 -0
- package/dist/test/test.health.js.map +1 -0
- package/dist/test/test.import.js +51 -4
- package/dist/test/test.import.js.map +1 -1
- package/dist/test/test.imports.js +22 -7
- package/dist/test/test.imports.js.map +1 -1
- package/dist/test/test.notifiers.d.ts +1 -0
- package/dist/test/test.notifiers.js +85 -0
- package/dist/test/test.notifiers.js.map +1 -0
- package/dist/test/test.processor.js +30 -115
- package/dist/test/test.processor.js.map +1 -1
- package/dist/test/test.products.d.ts +1 -0
- package/dist/test/test.products.js +49 -0
- package/dist/test/test.products.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/appBuilder.types.d.ts +5 -12
- package/dist/types/enums.d.ts +4 -1
- package/dist/types/enums.js +3 -0
- package/dist/types/enums.js.map +1 -1
- package/dist/types/index.types.d.ts +4 -0
- package/dist/types/pricing.types.d.ts +4 -0
- package/dist/types/pricing.types.js +3 -0
- package/dist/types/pricing.types.js.map +1 -0
- package/dist/types/processor.types.d.ts +67 -11
- package/dist/types/processor.types.js.map +1 -1
- package/dist/types/productsBuilder.types.d.ts +132 -14
- package/dist/types/productsBuilder.types.js +69 -4
- package/dist/types/productsBuilder.types.js.map +1 -1
- package/dist/types/request-tracker.interface.d.ts +0 -0
- package/dist/types/request-tracker.interface.js +1 -0
- package/dist/types/request-tracker.interface.js.map +1 -0
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/constants.js.map +1 -0
- package/package.json +17 -3
|
@@ -0,0 +1,1491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Memgraph Graph Database Adapter
|
|
4
|
+
* Implements the BaseGraphAdapter for Memgraph using Cypher query language
|
|
5
|
+
* Memgraph is Cypher-compatible and uses the Bolt protocol similar to Neo4j
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.MemgraphAdapter = void 0;
|
|
42
|
+
const base_adapter_1 = require("./base.adapter");
|
|
43
|
+
const graph_types_1 = require("../types/graph.types");
|
|
44
|
+
const node_types_1 = require("../types/node.types");
|
|
45
|
+
const relationship_types_1 = require("../types/relationship.types");
|
|
46
|
+
/**
|
|
47
|
+
* Memgraph connection implementation
|
|
48
|
+
* Uses Bolt protocol which is compatible with neo4j-driver
|
|
49
|
+
*/
|
|
50
|
+
class MemgraphConnection {
|
|
51
|
+
constructor(config, id) {
|
|
52
|
+
this.config = config;
|
|
53
|
+
this.type = graph_types_1.GraphDatabaseType.MEMGRAPH;
|
|
54
|
+
this.status = graph_types_1.GraphConnectionStatus.DISCONNECTED;
|
|
55
|
+
this.queryLanguage = graph_types_1.GraphQueryLanguage.CYPHER;
|
|
56
|
+
this.driver = null;
|
|
57
|
+
this.currentSession = null;
|
|
58
|
+
this.id = id || `memgraph-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
59
|
+
this.createdAt = new Date();
|
|
60
|
+
}
|
|
61
|
+
async connect() {
|
|
62
|
+
var _a;
|
|
63
|
+
if (this.status === graph_types_1.GraphConnectionStatus.CONNECTED) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.status = graph_types_1.GraphConnectionStatus.CONNECTING;
|
|
67
|
+
try {
|
|
68
|
+
// Use neo4j-driver which is compatible with Memgraph's Bolt protocol
|
|
69
|
+
const neo4j = await Promise.resolve().then(() => __importStar(require('neo4j-driver')));
|
|
70
|
+
const port = this.config.port || 7687;
|
|
71
|
+
const uri = `bolt://${this.config.host}:${port}`;
|
|
72
|
+
const authToken = this.config.username && this.config.password
|
|
73
|
+
? neo4j.default.auth.basic(this.config.username, this.config.password)
|
|
74
|
+
: undefined;
|
|
75
|
+
const driverConfig = {
|
|
76
|
+
maxConnectionPoolSize: this.config.poolSize || 50,
|
|
77
|
+
connectionTimeout: this.config.connectionTimeout || 30000,
|
|
78
|
+
};
|
|
79
|
+
if (this.config.encrypted !== undefined) {
|
|
80
|
+
driverConfig.encrypted = this.config.encrypted;
|
|
81
|
+
}
|
|
82
|
+
if ((_a = this.config.options) === null || _a === void 0 ? void 0 : _a.trustAll) {
|
|
83
|
+
driverConfig.trust = 'TRUST_ALL_CERTIFICATES';
|
|
84
|
+
}
|
|
85
|
+
this.driver = neo4j.default.driver(uri, authToken, driverConfig);
|
|
86
|
+
// Verify connectivity
|
|
87
|
+
await this.driver.verifyConnectivity();
|
|
88
|
+
this.status = graph_types_1.GraphConnectionStatus.CONNECTED;
|
|
89
|
+
this.lastUsedAt = new Date();
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
this.status = graph_types_1.GraphConnectionStatus.ERROR;
|
|
93
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.CONNECTION_ERROR, `Failed to connect to Memgraph: ${error.message}`, error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async disconnect() {
|
|
97
|
+
if (this.currentSession) {
|
|
98
|
+
await this.currentSession.close();
|
|
99
|
+
this.currentSession = null;
|
|
100
|
+
}
|
|
101
|
+
if (this.driver) {
|
|
102
|
+
await this.driver.close();
|
|
103
|
+
this.driver = null;
|
|
104
|
+
}
|
|
105
|
+
this.status = graph_types_1.GraphConnectionStatus.DISCONNECTED;
|
|
106
|
+
}
|
|
107
|
+
isConnected() {
|
|
108
|
+
return this.status === graph_types_1.GraphConnectionStatus.CONNECTED && this.driver !== null;
|
|
109
|
+
}
|
|
110
|
+
getClient() {
|
|
111
|
+
if (!this.driver) {
|
|
112
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.CONNECTION_ERROR, 'Memgraph driver not initialized. Call connect() first.');
|
|
113
|
+
}
|
|
114
|
+
return this.driver;
|
|
115
|
+
}
|
|
116
|
+
getSession() {
|
|
117
|
+
if (!this.driver) {
|
|
118
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.CONNECTION_ERROR, 'Memgraph driver not initialized. Call connect() first.');
|
|
119
|
+
}
|
|
120
|
+
const sessionConfig = {};
|
|
121
|
+
if (this.config.database) {
|
|
122
|
+
sessionConfig.database = this.config.database;
|
|
123
|
+
}
|
|
124
|
+
this.currentSession = this.driver.session(sessionConfig);
|
|
125
|
+
this.lastUsedAt = new Date();
|
|
126
|
+
return this.currentSession;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Memgraph transaction implementation
|
|
131
|
+
*/
|
|
132
|
+
class MemgraphTransaction {
|
|
133
|
+
constructor(connection, session, transaction) {
|
|
134
|
+
this.connection = connection;
|
|
135
|
+
this.session = session;
|
|
136
|
+
this.status = graph_types_1.GraphTransactionStatus.PENDING;
|
|
137
|
+
this.id = `tx-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
138
|
+
this.createdAt = new Date();
|
|
139
|
+
this.native = transaction;
|
|
140
|
+
this.status = graph_types_1.GraphTransactionStatus.ACTIVE;
|
|
141
|
+
}
|
|
142
|
+
async commit() {
|
|
143
|
+
if (this.status !== graph_types_1.GraphTransactionStatus.ACTIVE) {
|
|
144
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.TRANSACTION_ERROR, `Cannot commit transaction in ${this.status} state`);
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await this.native.commit();
|
|
148
|
+
this.status = graph_types_1.GraphTransactionStatus.COMMITTED;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
this.status = graph_types_1.GraphTransactionStatus.FAILED;
|
|
152
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.TRANSACTION_ERROR, `Failed to commit transaction: ${error.message}`, error);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async rollback() {
|
|
156
|
+
if (this.status !== graph_types_1.GraphTransactionStatus.ACTIVE) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
await this.native.rollback();
|
|
161
|
+
this.status = graph_types_1.GraphTransactionStatus.ROLLED_BACK;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
this.status = graph_types_1.GraphTransactionStatus.FAILED;
|
|
165
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.TRANSACTION_ERROR, `Failed to rollback transaction: ${error.message}`, error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
isActive() {
|
|
169
|
+
return this.status === graph_types_1.GraphTransactionStatus.ACTIVE;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Memgraph Graph Database Adapter
|
|
174
|
+
*/
|
|
175
|
+
class MemgraphAdapter extends base_adapter_1.BaseGraphAdapter {
|
|
176
|
+
constructor() {
|
|
177
|
+
super(...arguments);
|
|
178
|
+
this.type = graph_types_1.GraphDatabaseType.MEMGRAPH;
|
|
179
|
+
this.supportedLanguages = [graph_types_1.GraphQueryLanguage.CYPHER];
|
|
180
|
+
this.defaultLanguage = graph_types_1.GraphQueryLanguage.CYPHER;
|
|
181
|
+
}
|
|
182
|
+
// ==================== CONNECTION METHODS ====================
|
|
183
|
+
async connect(config) {
|
|
184
|
+
if (config.type !== graph_types_1.GraphDatabaseType.MEMGRAPH) {
|
|
185
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, `Invalid config type ${config.type}. Expected ${graph_types_1.GraphDatabaseType.MEMGRAPH}`);
|
|
186
|
+
}
|
|
187
|
+
const connection = new MemgraphConnection(config);
|
|
188
|
+
await connection.connect();
|
|
189
|
+
return connection;
|
|
190
|
+
}
|
|
191
|
+
async disconnect(connection) {
|
|
192
|
+
await connection.disconnect();
|
|
193
|
+
}
|
|
194
|
+
async testConnection(connection) {
|
|
195
|
+
const startTime = Date.now();
|
|
196
|
+
try {
|
|
197
|
+
const session = connection.getSession();
|
|
198
|
+
const result = await session.run('RETURN 1 AS test');
|
|
199
|
+
await session.close();
|
|
200
|
+
return {
|
|
201
|
+
connected: true,
|
|
202
|
+
message: 'Connection successful',
|
|
203
|
+
databaseType: graph_types_1.GraphDatabaseType.MEMGRAPH,
|
|
204
|
+
queryLanguage: graph_types_1.GraphQueryLanguage.CYPHER,
|
|
205
|
+
responseTime: Date.now() - startTime,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
connected: false,
|
|
211
|
+
message: 'Connection failed',
|
|
212
|
+
databaseType: graph_types_1.GraphDatabaseType.MEMGRAPH,
|
|
213
|
+
queryLanguage: graph_types_1.GraphQueryLanguage.CYPHER,
|
|
214
|
+
responseTime: Date.now() - startTime,
|
|
215
|
+
error: error.message,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async getDatabaseInfo(connection) {
|
|
220
|
+
const session = connection.getSession();
|
|
221
|
+
try {
|
|
222
|
+
// Memgraph version query
|
|
223
|
+
const result = await session.run('CALL mg.info() YIELD * RETURN *');
|
|
224
|
+
const record = result.records[0];
|
|
225
|
+
return {
|
|
226
|
+
version: (record === null || record === void 0 ? void 0 : record.get('version')) || 'Unknown',
|
|
227
|
+
edition: 'Memgraph',
|
|
228
|
+
features: ['cypher', 'streaming', 'in-memory'],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
catch (_a) {
|
|
232
|
+
// Fallback for older Memgraph versions
|
|
233
|
+
return {
|
|
234
|
+
version: 'Unknown',
|
|
235
|
+
edition: 'Memgraph',
|
|
236
|
+
features: ['cypher', 'streaming', 'in-memory'],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
await session.close();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// ==================== TRANSACTION METHODS ====================
|
|
244
|
+
async beginTransaction(connection, options) {
|
|
245
|
+
const session = connection.getSession();
|
|
246
|
+
const txConfig = {};
|
|
247
|
+
if (options === null || options === void 0 ? void 0 : options.timeout) {
|
|
248
|
+
txConfig.timeout = options.timeout;
|
|
249
|
+
}
|
|
250
|
+
if (options === null || options === void 0 ? void 0 : options.metadata) {
|
|
251
|
+
txConfig.metadata = options.metadata;
|
|
252
|
+
}
|
|
253
|
+
const transaction = session.beginTransaction(txConfig);
|
|
254
|
+
return new MemgraphTransaction(connection, session, transaction);
|
|
255
|
+
}
|
|
256
|
+
async commitTransaction(connection, transaction) {
|
|
257
|
+
await transaction.commit();
|
|
258
|
+
}
|
|
259
|
+
async rollbackTransaction(connection, transaction) {
|
|
260
|
+
await transaction.rollback();
|
|
261
|
+
}
|
|
262
|
+
// ==================== RAW QUERY METHODS ====================
|
|
263
|
+
async executeRaw(connection, options, transaction) {
|
|
264
|
+
var _a;
|
|
265
|
+
const startTime = Date.now();
|
|
266
|
+
try {
|
|
267
|
+
let result;
|
|
268
|
+
if (transaction && transaction.isActive()) {
|
|
269
|
+
result = await transaction.native.run(options.query, options.params || {});
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
const session = connection.getSession();
|
|
273
|
+
try {
|
|
274
|
+
result = await session.run(options.query, options.params || {});
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
await session.close();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const records = result.records.map((record) => {
|
|
281
|
+
const obj = {};
|
|
282
|
+
record.keys.forEach((key) => {
|
|
283
|
+
obj[key] = this.convertValue(record.get(key));
|
|
284
|
+
});
|
|
285
|
+
return obj;
|
|
286
|
+
});
|
|
287
|
+
return {
|
|
288
|
+
success: true,
|
|
289
|
+
executionTime: Date.now() - startTime,
|
|
290
|
+
data: records,
|
|
291
|
+
columns: result.records.length > 0 ? [...result.records[0].keys] : [],
|
|
292
|
+
count: records.length,
|
|
293
|
+
statistics: this.parseStatistics((_a = result.summary) === null || _a === void 0 ? void 0 : _a.counters),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
throw this.wrapError(error, graph_types_1.GraphErrorType.QUERY_ERROR, `Query execution failed: ${error.message}`, options.query, options.params);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// ==================== NODE OPERATIONS ====================
|
|
301
|
+
async createNode(connection, options, transaction) {
|
|
302
|
+
const startTime = Date.now();
|
|
303
|
+
const labels = this.normalizeLabels(options.labels);
|
|
304
|
+
const labelStr = labels.map(l => this.escapeIdentifier(l)).join(':');
|
|
305
|
+
const { clause: propsClause, params } = this.buildPropertiesClause(options.properties);
|
|
306
|
+
const query = `CREATE (n:${labelStr} ${propsClause}) RETURN n`;
|
|
307
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
308
|
+
return {
|
|
309
|
+
success: true,
|
|
310
|
+
executionTime: Date.now() - startTime,
|
|
311
|
+
node: result.data.length > 0 ? this.parseNode(result.data[0].n) : undefined,
|
|
312
|
+
created: true,
|
|
313
|
+
statistics: result.statistics,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
async findNodes(connection, options, transaction) {
|
|
317
|
+
const startTime = Date.now();
|
|
318
|
+
const labels = options.labels ? this.normalizeLabels(options.labels) : [];
|
|
319
|
+
const labelStr = labels.length > 0 ? ':' + labels.map(l => this.escapeIdentifier(l)).join(':') : '';
|
|
320
|
+
let query = `MATCH (n${labelStr})`;
|
|
321
|
+
const params = {};
|
|
322
|
+
// Build WHERE clause
|
|
323
|
+
const whereParts = [];
|
|
324
|
+
if (options.where) {
|
|
325
|
+
const { clause, params: whereParams } = this.buildWhereFromClause(options.where, 'n');
|
|
326
|
+
whereParts.push(clause);
|
|
327
|
+
Object.assign(params, whereParams);
|
|
328
|
+
}
|
|
329
|
+
if (options.properties) {
|
|
330
|
+
Object.entries(options.properties).forEach(([key, value], index) => {
|
|
331
|
+
const paramName = `prop_${index}`;
|
|
332
|
+
whereParts.push(`n.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
333
|
+
params[paramName] = value;
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (whereParts.length > 0) {
|
|
337
|
+
query += ` WHERE ${whereParts.join(' AND ')}`;
|
|
338
|
+
}
|
|
339
|
+
query += ` RETURN n`;
|
|
340
|
+
// ORDER BY
|
|
341
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
342
|
+
const orderParts = options.orderBy.map(o => `n.${this.escapeIdentifier(o.property)} ${o.direction}`);
|
|
343
|
+
query += ` ORDER BY ${orderParts.join(', ')}`;
|
|
344
|
+
}
|
|
345
|
+
// SKIP and LIMIT
|
|
346
|
+
if (options.skip !== undefined) {
|
|
347
|
+
query += ` SKIP ${options.skip}`;
|
|
348
|
+
}
|
|
349
|
+
if (options.limit !== undefined) {
|
|
350
|
+
query += ` LIMIT ${options.limit}`;
|
|
351
|
+
}
|
|
352
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
353
|
+
const nodes = result.data.map(row => this.parseNode(row.n));
|
|
354
|
+
return {
|
|
355
|
+
success: true,
|
|
356
|
+
executionTime: Date.now() - startTime,
|
|
357
|
+
nodes,
|
|
358
|
+
count: nodes.length,
|
|
359
|
+
hasMore: options.limit !== undefined && nodes.length === options.limit,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
async findNodeById(connection, id, transaction) {
|
|
363
|
+
// Memgraph uses internal IDs
|
|
364
|
+
const query = `MATCH (n) WHERE id(n) = $id RETURN n`;
|
|
365
|
+
const result = await this.executeRaw(connection, { query, params: { id: typeof id === 'string' ? parseInt(id, 10) : id } }, transaction);
|
|
366
|
+
if (result.data.length === 0) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
return this.parseNode(result.data[0].n);
|
|
370
|
+
}
|
|
371
|
+
async updateNode(connection, options, transaction) {
|
|
372
|
+
var _a;
|
|
373
|
+
const startTime = Date.now();
|
|
374
|
+
const params = {};
|
|
375
|
+
let matchClause = 'MATCH (n)';
|
|
376
|
+
if (options.id !== undefined) {
|
|
377
|
+
matchClause = 'MATCH (n) WHERE id(n) = $nodeId';
|
|
378
|
+
params.nodeId = typeof options.id === 'string' ? parseInt(options.id, 10) : options.id;
|
|
379
|
+
}
|
|
380
|
+
else if (options.labels) {
|
|
381
|
+
const labels = this.normalizeLabels(options.labels);
|
|
382
|
+
matchClause = `MATCH (n:${labels.map(l => this.escapeIdentifier(l)).join(':')})`;
|
|
383
|
+
}
|
|
384
|
+
if (options.where) {
|
|
385
|
+
const { clause, params: whereParams } = this.buildWhereFromClause(options.where, 'n');
|
|
386
|
+
matchClause += options.id === undefined && !options.labels ? ` WHERE ${clause}` : ` AND ${clause}`;
|
|
387
|
+
Object.assign(params, whereParams);
|
|
388
|
+
}
|
|
389
|
+
const setParts = [];
|
|
390
|
+
const removeParts = [];
|
|
391
|
+
if (options.set) {
|
|
392
|
+
Object.entries(options.set).forEach(([key, value], index) => {
|
|
393
|
+
const paramName = `set_${index}`;
|
|
394
|
+
setParts.push(`n.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
395
|
+
params[paramName] = value;
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (options.addLabels && options.addLabels.length > 0) {
|
|
399
|
+
setParts.push(`n:${options.addLabels.map(l => this.escapeIdentifier(l)).join(':')}`);
|
|
400
|
+
}
|
|
401
|
+
if (options.remove && options.remove.length > 0) {
|
|
402
|
+
options.remove.forEach(prop => {
|
|
403
|
+
removeParts.push(`n.${this.escapeIdentifier(prop)}`);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
if (options.removeLabels && options.removeLabels.length > 0) {
|
|
407
|
+
removeParts.push(`n:${options.removeLabels.map(l => this.escapeIdentifier(l)).join(':')}`);
|
|
408
|
+
}
|
|
409
|
+
let query = matchClause;
|
|
410
|
+
if (setParts.length > 0) {
|
|
411
|
+
query += ` SET ${setParts.join(', ')}`;
|
|
412
|
+
}
|
|
413
|
+
if (removeParts.length > 0) {
|
|
414
|
+
query += ` REMOVE ${removeParts.join(', ')}`;
|
|
415
|
+
}
|
|
416
|
+
query += ' RETURN n';
|
|
417
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
418
|
+
return {
|
|
419
|
+
success: true,
|
|
420
|
+
executionTime: Date.now() - startTime,
|
|
421
|
+
node: result.data.length > 0 ? this.parseNode(result.data[0].n) : undefined,
|
|
422
|
+
updated: result.data.length > 0,
|
|
423
|
+
matchedCount: result.data.length,
|
|
424
|
+
modifiedCount: ((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.propertiesSet) || 0,
|
|
425
|
+
statistics: result.statistics,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
async deleteNode(connection, options, transaction) {
|
|
429
|
+
var _a, _b;
|
|
430
|
+
const startTime = Date.now();
|
|
431
|
+
const params = {};
|
|
432
|
+
let matchClause = 'MATCH (n)';
|
|
433
|
+
if (options.id !== undefined) {
|
|
434
|
+
matchClause = 'MATCH (n) WHERE id(n) = $nodeId';
|
|
435
|
+
params.nodeId = typeof options.id === 'string' ? parseInt(options.id, 10) : options.id;
|
|
436
|
+
}
|
|
437
|
+
else if (options.labels) {
|
|
438
|
+
const labels = this.normalizeLabels(options.labels);
|
|
439
|
+
matchClause = `MATCH (n:${labels.map(l => this.escapeIdentifier(l)).join(':')})`;
|
|
440
|
+
}
|
|
441
|
+
if (options.where) {
|
|
442
|
+
const { clause, params: whereParams } = this.buildWhereFromClause(options.where, 'n');
|
|
443
|
+
matchClause += options.id === undefined && !options.labels ? ` WHERE ${clause}` : ` AND ${clause}`;
|
|
444
|
+
Object.assign(params, whereParams);
|
|
445
|
+
}
|
|
446
|
+
const deleteCmd = options.detach ? 'DETACH DELETE' : 'DELETE';
|
|
447
|
+
const query = `${matchClause} ${deleteCmd} n`;
|
|
448
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
449
|
+
return {
|
|
450
|
+
success: true,
|
|
451
|
+
executionTime: Date.now() - startTime,
|
|
452
|
+
deletedCount: ((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.nodesDeleted) || 0,
|
|
453
|
+
deletedRelationshipsCount: ((_b = result.statistics) === null || _b === void 0 ? void 0 : _b.relationshipsDeleted) || 0,
|
|
454
|
+
statistics: result.statistics,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
async mergeNode(connection, options, transaction) {
|
|
458
|
+
var _a;
|
|
459
|
+
const startTime = Date.now();
|
|
460
|
+
const labels = this.normalizeLabels(options.labels);
|
|
461
|
+
const labelStr = labels.map(l => this.escapeIdentifier(l)).join(':');
|
|
462
|
+
const params = {};
|
|
463
|
+
const matchProps = [];
|
|
464
|
+
Object.entries(options.matchProperties).forEach(([key, value], index) => {
|
|
465
|
+
const paramName = `match_${index}`;
|
|
466
|
+
matchProps.push(`${this.escapeIdentifier(key)}: $${paramName}`);
|
|
467
|
+
params[paramName] = value;
|
|
468
|
+
});
|
|
469
|
+
let query = `MERGE (n:${labelStr} {${matchProps.join(', ')}})`;
|
|
470
|
+
if (options.onCreate && Object.keys(options.onCreate).length > 0) {
|
|
471
|
+
const createProps = [];
|
|
472
|
+
Object.entries(options.onCreate).forEach(([key, value], index) => {
|
|
473
|
+
const paramName = `create_${index}`;
|
|
474
|
+
createProps.push(`n.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
475
|
+
params[paramName] = value;
|
|
476
|
+
});
|
|
477
|
+
query += ` ON CREATE SET ${createProps.join(', ')}`;
|
|
478
|
+
}
|
|
479
|
+
if (options.onMatch && Object.keys(options.onMatch).length > 0) {
|
|
480
|
+
const matchSetProps = [];
|
|
481
|
+
Object.entries(options.onMatch).forEach(([key, value], index) => {
|
|
482
|
+
const paramName = `match_set_${index}`;
|
|
483
|
+
matchSetProps.push(`n.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
484
|
+
params[paramName] = value;
|
|
485
|
+
});
|
|
486
|
+
query += ` ON MATCH SET ${matchSetProps.join(', ')}`;
|
|
487
|
+
}
|
|
488
|
+
query += ' RETURN n';
|
|
489
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
490
|
+
const created = (((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.nodesCreated) || 0) > 0;
|
|
491
|
+
return {
|
|
492
|
+
success: true,
|
|
493
|
+
executionTime: Date.now() - startTime,
|
|
494
|
+
node: result.data.length > 0 ? this.parseNode(result.data[0].n) : undefined,
|
|
495
|
+
created,
|
|
496
|
+
matched: !created,
|
|
497
|
+
statistics: result.statistics,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
// ==================== RELATIONSHIP OPERATIONS ====================
|
|
501
|
+
async createRelationship(connection, options, transaction) {
|
|
502
|
+
var _a;
|
|
503
|
+
const startTime = Date.now();
|
|
504
|
+
const params = {};
|
|
505
|
+
const fromMatch = this.buildNodeReference(options.fromNode, 'from', params);
|
|
506
|
+
const toMatch = this.buildNodeReference(options.toNode, 'to', params);
|
|
507
|
+
let propsClause = '';
|
|
508
|
+
if (options.properties && Object.keys(options.properties).length > 0) {
|
|
509
|
+
const { clause, params: propParams } = this.buildPropertiesClause(options.properties, 'rel_');
|
|
510
|
+
propsClause = ` ${clause}`;
|
|
511
|
+
Object.assign(params, propParams);
|
|
512
|
+
}
|
|
513
|
+
const query = `
|
|
514
|
+
MATCH ${fromMatch}, ${toMatch}
|
|
515
|
+
CREATE (from)-[r:${this.escapeIdentifier(options.type)}${propsClause}]->(to)
|
|
516
|
+
RETURN r
|
|
517
|
+
`;
|
|
518
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
519
|
+
return {
|
|
520
|
+
success: true,
|
|
521
|
+
executionTime: Date.now() - startTime,
|
|
522
|
+
relationship: result.data.length > 0 ? this.parseRelationship(result.data[0].r) : undefined,
|
|
523
|
+
created: (((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.relationshipsCreated) || 0) > 0,
|
|
524
|
+
statistics: result.statistics,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
async findRelationships(connection, options, transaction) {
|
|
528
|
+
const startTime = Date.now();
|
|
529
|
+
const params = {};
|
|
530
|
+
let typePattern = '';
|
|
531
|
+
if (options.type) {
|
|
532
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
533
|
+
typePattern = ':' + types.map(t => this.escapeIdentifier(t)).join('|');
|
|
534
|
+
}
|
|
535
|
+
const directionStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
536
|
+
const directionEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
537
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
538
|
+
let query = `MATCH (from)${directionStart}[r${typePattern}]${directionEnd}(to)`;
|
|
539
|
+
const whereParts = [];
|
|
540
|
+
if (options.fromNode && options.fromNode.id) {
|
|
541
|
+
params.fromId = typeof options.fromNode.id === 'string'
|
|
542
|
+
? parseInt(options.fromNode.id, 10)
|
|
543
|
+
: options.fromNode.id;
|
|
544
|
+
whereParts.push('id(from) = $fromId');
|
|
545
|
+
}
|
|
546
|
+
if (options.toNode && options.toNode.id) {
|
|
547
|
+
params.toId = typeof options.toNode.id === 'string'
|
|
548
|
+
? parseInt(options.toNode.id, 10)
|
|
549
|
+
: options.toNode.id;
|
|
550
|
+
whereParts.push('id(to) = $toId');
|
|
551
|
+
}
|
|
552
|
+
if (options.properties) {
|
|
553
|
+
Object.entries(options.properties).forEach(([key, value], index) => {
|
|
554
|
+
const paramName = `rel_prop_${index}`;
|
|
555
|
+
whereParts.push(`r.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
556
|
+
params[paramName] = value;
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
if (whereParts.length > 0) {
|
|
560
|
+
query += ` WHERE ${whereParts.join(' AND ')}`;
|
|
561
|
+
}
|
|
562
|
+
query += options.includeNodes ? ' RETURN r, from, to' : ' RETURN r';
|
|
563
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
564
|
+
const orderParts = options.orderBy.map(o => `r.${this.escapeIdentifier(o.property)} ${o.direction}`);
|
|
565
|
+
query += ` ORDER BY ${orderParts.join(', ')}`;
|
|
566
|
+
}
|
|
567
|
+
if (options.skip !== undefined) {
|
|
568
|
+
query += ` SKIP ${options.skip}`;
|
|
569
|
+
}
|
|
570
|
+
if (options.limit !== undefined) {
|
|
571
|
+
query += ` LIMIT ${options.limit}`;
|
|
572
|
+
}
|
|
573
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
574
|
+
const relationships = result.data.map(row => this.parseRelationship(row.r));
|
|
575
|
+
return {
|
|
576
|
+
success: true,
|
|
577
|
+
executionTime: Date.now() - startTime,
|
|
578
|
+
relationships,
|
|
579
|
+
count: relationships.length,
|
|
580
|
+
hasMore: options.limit !== undefined && relationships.length === options.limit,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
async findRelationshipById(connection, id, transaction) {
|
|
584
|
+
const query = `MATCH ()-[r]->() WHERE id(r) = $id RETURN r`;
|
|
585
|
+
const result = await this.executeRaw(connection, { query, params: { id: typeof id === 'string' ? parseInt(id, 10) : id } }, transaction);
|
|
586
|
+
if (result.data.length === 0) {
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
return this.parseRelationship(result.data[0].r);
|
|
590
|
+
}
|
|
591
|
+
async updateRelationship(connection, options, transaction) {
|
|
592
|
+
var _a;
|
|
593
|
+
const startTime = Date.now();
|
|
594
|
+
const params = {};
|
|
595
|
+
let matchClause = 'MATCH ()-[r]->()';
|
|
596
|
+
if (options.id !== undefined) {
|
|
597
|
+
matchClause = 'MATCH ()-[r]->() WHERE id(r) = $relId';
|
|
598
|
+
params.relId = typeof options.id === 'string' ? parseInt(options.id, 10) : options.id;
|
|
599
|
+
}
|
|
600
|
+
else if (options.type) {
|
|
601
|
+
matchClause = `MATCH ()-[r:${this.escapeIdentifier(options.type)}]->()`;
|
|
602
|
+
}
|
|
603
|
+
const setParts = [];
|
|
604
|
+
if (options.set) {
|
|
605
|
+
Object.entries(options.set).forEach(([key, value], index) => {
|
|
606
|
+
const paramName = `set_${index}`;
|
|
607
|
+
setParts.push(`r.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
608
|
+
params[paramName] = value;
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
let query = matchClause;
|
|
612
|
+
if (setParts.length > 0) {
|
|
613
|
+
query += ` SET ${setParts.join(', ')}`;
|
|
614
|
+
}
|
|
615
|
+
if (options.remove && options.remove.length > 0) {
|
|
616
|
+
query += ` REMOVE ${options.remove.map(p => `r.${this.escapeIdentifier(p)}`).join(', ')}`;
|
|
617
|
+
}
|
|
618
|
+
query += ' RETURN r';
|
|
619
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
620
|
+
return {
|
|
621
|
+
success: true,
|
|
622
|
+
executionTime: Date.now() - startTime,
|
|
623
|
+
relationship: result.data.length > 0 ? this.parseRelationship(result.data[0].r) : undefined,
|
|
624
|
+
updated: result.data.length > 0,
|
|
625
|
+
matchedCount: result.data.length,
|
|
626
|
+
modifiedCount: ((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.propertiesSet) || 0,
|
|
627
|
+
statistics: result.statistics,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
async deleteRelationship(connection, options, transaction) {
|
|
631
|
+
var _a;
|
|
632
|
+
const startTime = Date.now();
|
|
633
|
+
const params = {};
|
|
634
|
+
let matchClause = 'MATCH ()-[r]->()';
|
|
635
|
+
if (options.id !== undefined) {
|
|
636
|
+
matchClause = 'MATCH ()-[r]->() WHERE id(r) = $relId';
|
|
637
|
+
params.relId = typeof options.id === 'string' ? parseInt(options.id, 10) : options.id;
|
|
638
|
+
}
|
|
639
|
+
else if (options.type) {
|
|
640
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
641
|
+
matchClause = `MATCH ()-[r:${types.map(t => this.escapeIdentifier(t)).join('|')}]->()`;
|
|
642
|
+
}
|
|
643
|
+
const query = `${matchClause} DELETE r`;
|
|
644
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
645
|
+
return {
|
|
646
|
+
success: true,
|
|
647
|
+
executionTime: Date.now() - startTime,
|
|
648
|
+
deletedCount: ((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.relationshipsDeleted) || 0,
|
|
649
|
+
statistics: result.statistics,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
async mergeRelationship(connection, options, transaction) {
|
|
653
|
+
var _a;
|
|
654
|
+
const startTime = Date.now();
|
|
655
|
+
const params = {};
|
|
656
|
+
const fromMatch = this.buildNodeReference(options.fromNode, 'from', params);
|
|
657
|
+
const toMatch = this.buildNodeReference(options.toNode, 'to', params);
|
|
658
|
+
let matchPropsClause = '';
|
|
659
|
+
if (options.matchProperties && Object.keys(options.matchProperties).length > 0) {
|
|
660
|
+
const { clause, params: matchParams } = this.buildPropertiesClause(options.matchProperties, 'match_');
|
|
661
|
+
matchPropsClause = ` ${clause}`;
|
|
662
|
+
Object.assign(params, matchParams);
|
|
663
|
+
}
|
|
664
|
+
let query = `
|
|
665
|
+
MATCH ${fromMatch}, ${toMatch}
|
|
666
|
+
MERGE (from)-[r:${this.escapeIdentifier(options.type)}${matchPropsClause}]->(to)
|
|
667
|
+
`;
|
|
668
|
+
if (options.onCreate && Object.keys(options.onCreate).length > 0) {
|
|
669
|
+
const createProps = [];
|
|
670
|
+
Object.entries(options.onCreate).forEach(([key, value], index) => {
|
|
671
|
+
const paramName = `create_${index}`;
|
|
672
|
+
createProps.push(`r.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
673
|
+
params[paramName] = value;
|
|
674
|
+
});
|
|
675
|
+
query += ` ON CREATE SET ${createProps.join(', ')}`;
|
|
676
|
+
}
|
|
677
|
+
if (options.onMatch && Object.keys(options.onMatch).length > 0) {
|
|
678
|
+
const matchSetProps = [];
|
|
679
|
+
Object.entries(options.onMatch).forEach(([key, value], index) => {
|
|
680
|
+
const paramName = `match_set_${index}`;
|
|
681
|
+
matchSetProps.push(`r.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
682
|
+
params[paramName] = value;
|
|
683
|
+
});
|
|
684
|
+
query += ` ON MATCH SET ${matchSetProps.join(', ')}`;
|
|
685
|
+
}
|
|
686
|
+
query += ' RETURN r';
|
|
687
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
688
|
+
const created = (((_a = result.statistics) === null || _a === void 0 ? void 0 : _a.relationshipsCreated) || 0) > 0;
|
|
689
|
+
return {
|
|
690
|
+
success: true,
|
|
691
|
+
executionTime: Date.now() - startTime,
|
|
692
|
+
relationship: result.data.length > 0 ? this.parseRelationship(result.data[0].r) : undefined,
|
|
693
|
+
created,
|
|
694
|
+
matched: !created,
|
|
695
|
+
statistics: result.statistics,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
// ==================== PATH & TRAVERSAL OPERATIONS ====================
|
|
699
|
+
async traverse(connection, options, transaction) {
|
|
700
|
+
const startTime = Date.now();
|
|
701
|
+
const params = {};
|
|
702
|
+
const startNodeMatch = this.buildNodeSelectorMatch(options.startNode, 'start', params);
|
|
703
|
+
const minDepth = options.minDepth || 1;
|
|
704
|
+
const maxDepth = options.maxDepth || 10;
|
|
705
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
706
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
707
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
708
|
+
const query = `
|
|
709
|
+
MATCH ${startNodeMatch}
|
|
710
|
+
MATCH path = (start)${dirStart}[*${minDepth}..${maxDepth}]${dirEnd}(end)
|
|
711
|
+
${options.limit ? `WITH path LIMIT ${options.limit}` : ''}
|
|
712
|
+
RETURN path
|
|
713
|
+
`;
|
|
714
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
715
|
+
const paths = [];
|
|
716
|
+
const nodesMap = new Map();
|
|
717
|
+
const relsMap = new Map();
|
|
718
|
+
result.data.forEach(row => {
|
|
719
|
+
if (row.path) {
|
|
720
|
+
const parsedPath = this.parsePath(row.path);
|
|
721
|
+
paths.push(parsedPath);
|
|
722
|
+
parsedPath.nodes.forEach(n => nodesMap.set(String(n.id), n));
|
|
723
|
+
parsedPath.relationships.forEach(r => relsMap.set(String(r.id), r));
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
return {
|
|
727
|
+
success: true,
|
|
728
|
+
executionTime: Date.now() - startTime,
|
|
729
|
+
paths: options.returnPaths ? paths : undefined,
|
|
730
|
+
nodes: options.returnNodes ? Array.from(nodesMap.values()) : undefined,
|
|
731
|
+
relationships: Array.from(relsMap.values()),
|
|
732
|
+
count: paths.length,
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
async shortestPath(connection, options, transaction) {
|
|
736
|
+
const startTime = Date.now();
|
|
737
|
+
const params = {};
|
|
738
|
+
const startNodeMatch = this.buildNodeSelectorMatch(options.startNode, 'start', params);
|
|
739
|
+
const endNodeMatch = this.buildNodeSelectorMatch(options.endNode, 'end', params, 'end_');
|
|
740
|
+
const maxDepth = options.maxDepth ? `*..${options.maxDepth}` : '*';
|
|
741
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
742
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
743
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
744
|
+
let query;
|
|
745
|
+
if (options.weightProperty) {
|
|
746
|
+
// Memgraph weighted shortest path using WSP
|
|
747
|
+
query = `
|
|
748
|
+
MATCH ${startNodeMatch}, ${endNodeMatch}
|
|
749
|
+
CALL algo.shortestPath(start, end, {
|
|
750
|
+
relationship: null,
|
|
751
|
+
weight: '${options.weightProperty}',
|
|
752
|
+
default: ${options.defaultWeight || 1}
|
|
753
|
+
}) YIELD path, weight
|
|
754
|
+
RETURN path, weight
|
|
755
|
+
`;
|
|
756
|
+
}
|
|
757
|
+
else if (options.returnAllShortest) {
|
|
758
|
+
query = `
|
|
759
|
+
MATCH ${startNodeMatch}, ${endNodeMatch}
|
|
760
|
+
MATCH path = allShortestPaths((start)${dirStart}[${maxDepth}]${dirEnd}(end))
|
|
761
|
+
RETURN path
|
|
762
|
+
`;
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
query = `
|
|
766
|
+
MATCH ${startNodeMatch}, ${endNodeMatch}
|
|
767
|
+
MATCH path = shortestPath((start)${dirStart}[${maxDepth}]${dirEnd}(end))
|
|
768
|
+
RETURN path
|
|
769
|
+
`;
|
|
770
|
+
}
|
|
771
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
772
|
+
if (result.data.length === 0) {
|
|
773
|
+
return {
|
|
774
|
+
success: true,
|
|
775
|
+
executionTime: Date.now() - startTime,
|
|
776
|
+
found: false,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
const paths = result.data.map(row => {
|
|
780
|
+
const parsedPath = this.parsePath(row.path);
|
|
781
|
+
if (row.weight !== undefined) {
|
|
782
|
+
return Object.assign(Object.assign({}, parsedPath), { totalWeight: row.weight, weights: [] });
|
|
783
|
+
}
|
|
784
|
+
return parsedPath;
|
|
785
|
+
});
|
|
786
|
+
return {
|
|
787
|
+
success: true,
|
|
788
|
+
executionTime: Date.now() - startTime,
|
|
789
|
+
path: options.returnAllShortest ? undefined : paths[0],
|
|
790
|
+
paths: options.returnAllShortest ? paths : undefined,
|
|
791
|
+
found: true,
|
|
792
|
+
length: paths[0].length,
|
|
793
|
+
totalWeight: paths[0].totalWeight,
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
async allPaths(connection, options, transaction) {
|
|
797
|
+
const startTime = Date.now();
|
|
798
|
+
const params = {};
|
|
799
|
+
const startNodeMatch = this.buildNodeSelectorMatch(options.startNode, 'start', params);
|
|
800
|
+
const endNodeMatch = this.buildNodeSelectorMatch(options.endNode, 'end', params, 'end_');
|
|
801
|
+
const minDepth = options.minDepth || 1;
|
|
802
|
+
const maxDepth = options.maxDepth || 10;
|
|
803
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
804
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
805
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
806
|
+
let query = `
|
|
807
|
+
MATCH ${startNodeMatch}, ${endNodeMatch}
|
|
808
|
+
MATCH path = (start)${dirStart}[*${minDepth}..${maxDepth}]${dirEnd}(end)
|
|
809
|
+
RETURN path
|
|
810
|
+
`;
|
|
811
|
+
if (options.limit) {
|
|
812
|
+
query += ` LIMIT ${options.limit}`;
|
|
813
|
+
}
|
|
814
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
815
|
+
const paths = result.data.map(row => this.parsePath(row.path));
|
|
816
|
+
return {
|
|
817
|
+
success: true,
|
|
818
|
+
executionTime: Date.now() - startTime,
|
|
819
|
+
paths,
|
|
820
|
+
count: paths.length,
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
async matchPattern(connection, options, transaction) {
|
|
824
|
+
const startTime = Date.now();
|
|
825
|
+
const params = {};
|
|
826
|
+
const { pattern } = options;
|
|
827
|
+
const nodePatterns = [];
|
|
828
|
+
pattern.nodes.forEach(node => {
|
|
829
|
+
const labels = node.labels
|
|
830
|
+
? ':' + (Array.isArray(node.labels) ? node.labels : [node.labels])
|
|
831
|
+
.map(l => this.escapeIdentifier(l)).join(':')
|
|
832
|
+
: '';
|
|
833
|
+
let props = '';
|
|
834
|
+
if (node.properties && Object.keys(node.properties).length > 0) {
|
|
835
|
+
const { clause, params: nodeParams } = this.buildPropertiesClause(node.properties, `${node.variable}_`);
|
|
836
|
+
props = ` ${clause}`;
|
|
837
|
+
Object.assign(params, nodeParams);
|
|
838
|
+
}
|
|
839
|
+
nodePatterns.push(`(${node.variable}${labels}${props})`);
|
|
840
|
+
});
|
|
841
|
+
const matchClauses = [];
|
|
842
|
+
if (pattern.relationships.length === 0) {
|
|
843
|
+
matchClauses.push(`MATCH ${nodePatterns.join(', ')}`);
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
pattern.relationships.forEach(rel => {
|
|
847
|
+
const relVar = rel.variable || '';
|
|
848
|
+
const types = rel.type
|
|
849
|
+
? ':' + (Array.isArray(rel.type) ? rel.type : [rel.type])
|
|
850
|
+
.map(t => this.escapeIdentifier(t)).join('|')
|
|
851
|
+
: '';
|
|
852
|
+
const dirStart = rel.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
853
|
+
const dirEnd = rel.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
854
|
+
rel.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
855
|
+
let hops = '';
|
|
856
|
+
if (rel.minHops !== undefined || rel.maxHops !== undefined) {
|
|
857
|
+
const min = rel.minHops || '';
|
|
858
|
+
const max = rel.maxHops || '';
|
|
859
|
+
hops = `*${min}..${max}`;
|
|
860
|
+
}
|
|
861
|
+
matchClauses.push(`MATCH (${rel.startNode})${dirStart}[${relVar}${types}${hops}]${dirEnd}(${rel.endNode})`);
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
let query = matchClauses.join(' ');
|
|
865
|
+
if (pattern.where) {
|
|
866
|
+
const conditions = pattern.where.conditions
|
|
867
|
+
.map(c => c.expression)
|
|
868
|
+
.join(pattern.where.operator === 'OR' ? ' OR ' : ' AND ');
|
|
869
|
+
query += ` WHERE ${conditions}`;
|
|
870
|
+
}
|
|
871
|
+
const returnVars = options.return || pattern.nodes.map(n => n.variable);
|
|
872
|
+
query += ` RETURN ${returnVars.join(', ')}`;
|
|
873
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
874
|
+
const orderParts = options.orderBy.map(o => `${o.expression} ${o.direction}`);
|
|
875
|
+
query += ` ORDER BY ${orderParts.join(', ')}`;
|
|
876
|
+
}
|
|
877
|
+
if (options.skip !== undefined) {
|
|
878
|
+
query += ` SKIP ${options.skip}`;
|
|
879
|
+
}
|
|
880
|
+
if (options.limit !== undefined) {
|
|
881
|
+
query += ` LIMIT ${options.limit}`;
|
|
882
|
+
}
|
|
883
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
884
|
+
return {
|
|
885
|
+
success: true,
|
|
886
|
+
executionTime: Date.now() - startTime,
|
|
887
|
+
matches: result.data,
|
|
888
|
+
count: result.data.length,
|
|
889
|
+
hasMore: options.limit !== undefined && result.data.length === options.limit,
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
async extractSubgraph(connection, options, transaction) {
|
|
893
|
+
const startTime = Date.now();
|
|
894
|
+
const params = {};
|
|
895
|
+
const startNodes = Array.isArray(options.startNodes) ? options.startNodes : [options.startNodes];
|
|
896
|
+
const startMatches = startNodes.map((node, idx) => this.buildNodeSelectorMatch(node, `start${idx}`, params, `start${idx}_`));
|
|
897
|
+
const maxDepth = options.maxDepth || 3;
|
|
898
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
899
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
900
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
901
|
+
const query = `
|
|
902
|
+
MATCH ${startMatches.join(', ')}
|
|
903
|
+
WITH [${startNodes.map((_, i) => `start${i}`).join(', ')}] AS starts
|
|
904
|
+
UNWIND starts AS start
|
|
905
|
+
MATCH path = (start)${dirStart}[*0..${maxDepth}]${dirEnd}(n)
|
|
906
|
+
WITH COLLECT(DISTINCT n) AS nodes, COLLECT(relationships(path)) AS rels
|
|
907
|
+
UNWIND rels AS relList
|
|
908
|
+
UNWIND relList AS r
|
|
909
|
+
RETURN nodes, COLLECT(DISTINCT r) AS relationships
|
|
910
|
+
`;
|
|
911
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
912
|
+
const nodes = [];
|
|
913
|
+
const relationships = [];
|
|
914
|
+
if (result.data.length > 0) {
|
|
915
|
+
const row = result.data[0];
|
|
916
|
+
if (row.nodes) {
|
|
917
|
+
row.nodes.forEach((n) => nodes.push(this.parseNode(n)));
|
|
918
|
+
}
|
|
919
|
+
if (row.relationships) {
|
|
920
|
+
row.relationships.forEach((r) => relationships.push(this.parseRelationship(r)));
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return {
|
|
924
|
+
success: true,
|
|
925
|
+
executionTime: Date.now() - startTime,
|
|
926
|
+
subgraph: {
|
|
927
|
+
nodes,
|
|
928
|
+
relationships,
|
|
929
|
+
nodeCount: nodes.length,
|
|
930
|
+
relationshipCount: relationships.length,
|
|
931
|
+
},
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
async getNeighborhood(connection, options, transaction) {
|
|
935
|
+
const startTime = Date.now();
|
|
936
|
+
const params = {};
|
|
937
|
+
const centerMatch = this.buildNodeSelectorMatch(options.node, 'center', params);
|
|
938
|
+
const depth = options.depth || 1;
|
|
939
|
+
let relTypes = '';
|
|
940
|
+
if (options.relationshipTypes && options.relationshipTypes.length > 0) {
|
|
941
|
+
relTypes = ':' + options.relationshipTypes.map(t => this.escapeIdentifier(t)).join('|');
|
|
942
|
+
}
|
|
943
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
944
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
945
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
946
|
+
const query = `
|
|
947
|
+
MATCH ${centerMatch}
|
|
948
|
+
MATCH path = (center)${dirStart}[${relTypes}*0..${depth}]${dirEnd}(n)
|
|
949
|
+
WITH COLLECT(DISTINCT n) AS nodes, COLLECT(relationships(path)) AS rels
|
|
950
|
+
UNWIND rels AS relList
|
|
951
|
+
UNWIND relList AS r
|
|
952
|
+
RETURN nodes, COLLECT(DISTINCT r) AS relationships
|
|
953
|
+
`;
|
|
954
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
955
|
+
const nodes = [];
|
|
956
|
+
const relationships = [];
|
|
957
|
+
if (result.data.length > 0) {
|
|
958
|
+
const row = result.data[0];
|
|
959
|
+
if (row.nodes) {
|
|
960
|
+
row.nodes.forEach((n) => nodes.push(this.parseNode(n)));
|
|
961
|
+
}
|
|
962
|
+
if (row.relationships) {
|
|
963
|
+
row.relationships.forEach((r) => relationships.push(this.parseRelationship(r)));
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return {
|
|
967
|
+
success: true,
|
|
968
|
+
executionTime: Date.now() - startTime,
|
|
969
|
+
nodes,
|
|
970
|
+
relationships,
|
|
971
|
+
levels: new Map(),
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
async findConnectedComponents(connection, options, transaction) {
|
|
975
|
+
const startTime = Date.now();
|
|
976
|
+
// Memgraph has built-in algorithm support through MAGE library
|
|
977
|
+
const query = `
|
|
978
|
+
CALL algo.weaklyConnectedComponents() YIELD node, componentId
|
|
979
|
+
RETURN componentId, COLLECT(node) AS nodes
|
|
980
|
+
ORDER BY size(nodes) DESC
|
|
981
|
+
`;
|
|
982
|
+
try {
|
|
983
|
+
const result = await this.executeRaw(connection, { query }, transaction);
|
|
984
|
+
const components = result.data.map((row, idx) => ({
|
|
985
|
+
id: row.componentId || idx,
|
|
986
|
+
nodes: (row.nodes || []).map((n) => this.parseNode(n)),
|
|
987
|
+
size: (row.nodes || []).length,
|
|
988
|
+
}));
|
|
989
|
+
if (options.minSize) {
|
|
990
|
+
return {
|
|
991
|
+
success: true,
|
|
992
|
+
executionTime: Date.now() - startTime,
|
|
993
|
+
components: components.filter(c => c.size >= options.minSize),
|
|
994
|
+
count: components.filter(c => c.size >= options.minSize).length,
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
success: true,
|
|
999
|
+
executionTime: Date.now() - startTime,
|
|
1000
|
+
components,
|
|
1001
|
+
count: components.length,
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
catch (_a) {
|
|
1005
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Connected components requires MAGE library in Memgraph');
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
// ==================== AGGREGATION OPERATIONS ====================
|
|
1009
|
+
async countNodes(connection, labels, where, transaction) {
|
|
1010
|
+
var _a;
|
|
1011
|
+
const startTime = Date.now();
|
|
1012
|
+
const params = {};
|
|
1013
|
+
let labelStr = '';
|
|
1014
|
+
if (labels) {
|
|
1015
|
+
const labelArr = Array.isArray(labels) ? labels : [labels];
|
|
1016
|
+
labelStr = ':' + labelArr.map(l => this.escapeIdentifier(l)).join(':');
|
|
1017
|
+
}
|
|
1018
|
+
let query = `MATCH (n${labelStr})`;
|
|
1019
|
+
if (where && Object.keys(where).length > 0) {
|
|
1020
|
+
const whereParts = [];
|
|
1021
|
+
Object.entries(where).forEach(([key, value], index) => {
|
|
1022
|
+
const paramName = `where_${index}`;
|
|
1023
|
+
whereParts.push(`n.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
1024
|
+
params[paramName] = value;
|
|
1025
|
+
});
|
|
1026
|
+
query += ` WHERE ${whereParts.join(' AND ')}`;
|
|
1027
|
+
}
|
|
1028
|
+
query += ' RETURN count(n) AS count';
|
|
1029
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1030
|
+
return {
|
|
1031
|
+
success: true,
|
|
1032
|
+
executionTime: Date.now() - startTime,
|
|
1033
|
+
count: this.toNumber(((_a = result.data[0]) === null || _a === void 0 ? void 0 : _a.count) || 0),
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
async countRelationships(connection, type, where, transaction) {
|
|
1037
|
+
var _a;
|
|
1038
|
+
const startTime = Date.now();
|
|
1039
|
+
const params = {};
|
|
1040
|
+
let typeStr = '';
|
|
1041
|
+
if (type) {
|
|
1042
|
+
const typeArr = Array.isArray(type) ? type : [type];
|
|
1043
|
+
typeStr = ':' + typeArr.map(t => this.escapeIdentifier(t)).join('|');
|
|
1044
|
+
}
|
|
1045
|
+
let query = `MATCH ()-[r${typeStr}]->()`;
|
|
1046
|
+
if (where && Object.keys(where).length > 0) {
|
|
1047
|
+
const whereParts = [];
|
|
1048
|
+
Object.entries(where).forEach(([key, value], index) => {
|
|
1049
|
+
const paramName = `where_${index}`;
|
|
1050
|
+
whereParts.push(`r.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
1051
|
+
params[paramName] = value;
|
|
1052
|
+
});
|
|
1053
|
+
query += ` WHERE ${whereParts.join(' AND ')}`;
|
|
1054
|
+
}
|
|
1055
|
+
query += ' RETURN count(r) AS count';
|
|
1056
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1057
|
+
return {
|
|
1058
|
+
success: true,
|
|
1059
|
+
executionTime: Date.now() - startTime,
|
|
1060
|
+
count: this.toNumber(((_a = result.data[0]) === null || _a === void 0 ? void 0 : _a.count) || 0),
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
async getStatistics(connection, transaction) {
|
|
1064
|
+
const startTime = Date.now();
|
|
1065
|
+
const query = `
|
|
1066
|
+
MATCH (n)
|
|
1067
|
+
WITH count(n) AS nodeCount
|
|
1068
|
+
MATCH ()-[r]->()
|
|
1069
|
+
RETURN nodeCount, count(r) AS relCount
|
|
1070
|
+
`;
|
|
1071
|
+
const result = await this.executeRaw(connection, { query }, transaction);
|
|
1072
|
+
const row = result.data[0] || {};
|
|
1073
|
+
return {
|
|
1074
|
+
success: true,
|
|
1075
|
+
executionTime: Date.now() - startTime,
|
|
1076
|
+
nodeCount: this.toNumber(row.nodeCount || 0),
|
|
1077
|
+
relationshipCount: this.toNumber(row.relCount || 0),
|
|
1078
|
+
labelCounts: {},
|
|
1079
|
+
relationshipTypeCounts: {},
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
// ==================== SEARCH OPERATIONS ====================
|
|
1083
|
+
async fullTextSearch(connection, options, transaction) {
|
|
1084
|
+
const startTime = Date.now();
|
|
1085
|
+
// Memgraph uses text search index
|
|
1086
|
+
const query = `
|
|
1087
|
+
CALL mg.text_search('${options.index}', '${options.query}')
|
|
1088
|
+
YIELD node, score
|
|
1089
|
+
${options.labels ? `WHERE ${options.labels.map(l => `'${l}' IN labels(node)`).join(' OR ')}` : ''}
|
|
1090
|
+
RETURN node${options.score ? ', score' : ''}
|
|
1091
|
+
${options.limit ? `LIMIT ${options.limit}` : ''}
|
|
1092
|
+
`;
|
|
1093
|
+
const result = await this.executeRaw(connection, { query }, transaction);
|
|
1094
|
+
const nodes = result.data.map(row => {
|
|
1095
|
+
const node = this.parseNode(row.node);
|
|
1096
|
+
if (options.score && row.score !== undefined) {
|
|
1097
|
+
return Object.assign(Object.assign({}, node), { score: row.score });
|
|
1098
|
+
}
|
|
1099
|
+
return node;
|
|
1100
|
+
});
|
|
1101
|
+
return {
|
|
1102
|
+
success: true,
|
|
1103
|
+
executionTime: Date.now() - startTime,
|
|
1104
|
+
nodes,
|
|
1105
|
+
count: nodes.length,
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
async vectorSearch(connection, options, transaction) {
|
|
1109
|
+
// Memgraph doesn't have built-in vector search (as of early 2024)
|
|
1110
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Vector search is not natively supported in Memgraph');
|
|
1111
|
+
}
|
|
1112
|
+
// ==================== SCHEMA OPERATIONS ====================
|
|
1113
|
+
async createNodeConstraint(connection, constraint, transaction) {
|
|
1114
|
+
const startTime = Date.now();
|
|
1115
|
+
let query;
|
|
1116
|
+
const props = constraint.properties.join(', ');
|
|
1117
|
+
switch (constraint.type) {
|
|
1118
|
+
case node_types_1.NodeConstraintType.UNIQUE:
|
|
1119
|
+
query = `CREATE CONSTRAINT ON (n:${this.escapeIdentifier(constraint.label)}) ASSERT n.${constraint.properties[0]} IS UNIQUE`;
|
|
1120
|
+
break;
|
|
1121
|
+
case node_types_1.NodeConstraintType.EXISTS:
|
|
1122
|
+
query = `CREATE CONSTRAINT ON (n:${this.escapeIdentifier(constraint.label)}) ASSERT EXISTS (n.${constraint.properties[0]})`;
|
|
1123
|
+
break;
|
|
1124
|
+
default:
|
|
1125
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, `Constraint type ${constraint.type} not supported in Memgraph`);
|
|
1126
|
+
}
|
|
1127
|
+
await this.executeRaw(connection, { query }, transaction);
|
|
1128
|
+
return {
|
|
1129
|
+
success: true,
|
|
1130
|
+
executionTime: Date.now() - startTime,
|
|
1131
|
+
name: constraint.name,
|
|
1132
|
+
created: true,
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
async createRelationshipConstraint(connection, constraint, transaction) {
|
|
1136
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Relationship constraints are not supported in Memgraph');
|
|
1137
|
+
}
|
|
1138
|
+
async dropConstraint(connection, name, transaction) {
|
|
1139
|
+
const startTime = Date.now();
|
|
1140
|
+
// Memgraph constraint drop syntax
|
|
1141
|
+
const query = `DROP CONSTRAINT ON (n) ASSERT n.${name} IS UNIQUE`;
|
|
1142
|
+
try {
|
|
1143
|
+
await this.executeRaw(connection, { query }, transaction);
|
|
1144
|
+
}
|
|
1145
|
+
catch (_a) {
|
|
1146
|
+
// Try existence constraint
|
|
1147
|
+
const existsQuery = `DROP CONSTRAINT ON (n) ASSERT EXISTS (n.${name})`;
|
|
1148
|
+
await this.executeRaw(connection, { query: existsQuery }, transaction);
|
|
1149
|
+
}
|
|
1150
|
+
return {
|
|
1151
|
+
success: true,
|
|
1152
|
+
executionTime: Date.now() - startTime,
|
|
1153
|
+
name,
|
|
1154
|
+
dropped: true,
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
async listConstraints(connection, transaction) {
|
|
1158
|
+
const startTime = Date.now();
|
|
1159
|
+
const query = 'SHOW CONSTRAINT INFO';
|
|
1160
|
+
const result = await this.executeRaw(connection, { query }, transaction);
|
|
1161
|
+
const constraints = result.data.map((row) => ({
|
|
1162
|
+
name: row.constraint_name || row.name || '',
|
|
1163
|
+
type: row.type || 'UNIQUE',
|
|
1164
|
+
entityType: 'NODE',
|
|
1165
|
+
labelsOrTypes: [row.label || ''],
|
|
1166
|
+
properties: [row.property || ''],
|
|
1167
|
+
}));
|
|
1168
|
+
return {
|
|
1169
|
+
success: true,
|
|
1170
|
+
executionTime: Date.now() - startTime,
|
|
1171
|
+
constraints,
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
async createNodeIndex(connection, index, transaction) {
|
|
1175
|
+
const startTime = Date.now();
|
|
1176
|
+
const props = index.properties.map(p => `n.${this.escapeIdentifier(p)}`).join(', ');
|
|
1177
|
+
const query = `CREATE INDEX ON :${this.escapeIdentifier(index.label)}(${index.properties.join(', ')})`;
|
|
1178
|
+
await this.executeRaw(connection, { query }, transaction);
|
|
1179
|
+
return {
|
|
1180
|
+
success: true,
|
|
1181
|
+
executionTime: Date.now() - startTime,
|
|
1182
|
+
name: index.name,
|
|
1183
|
+
created: true,
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
async createRelationshipIndex(connection, index, transaction) {
|
|
1187
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Relationship indexes are not directly supported in Memgraph');
|
|
1188
|
+
}
|
|
1189
|
+
async dropIndex(connection, name, transaction) {
|
|
1190
|
+
const startTime = Date.now();
|
|
1191
|
+
// Memgraph requires label and property for index drop
|
|
1192
|
+
const query = `DROP INDEX ON :${name}`;
|
|
1193
|
+
await this.executeRaw(connection, { query }, transaction);
|
|
1194
|
+
return {
|
|
1195
|
+
success: true,
|
|
1196
|
+
executionTime: Date.now() - startTime,
|
|
1197
|
+
name,
|
|
1198
|
+
dropped: true,
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
async listIndexes(connection, transaction) {
|
|
1202
|
+
const startTime = Date.now();
|
|
1203
|
+
const query = 'SHOW INDEX INFO';
|
|
1204
|
+
const result = await this.executeRaw(connection, { query }, transaction);
|
|
1205
|
+
const indexes = result.data.map((row) => ({
|
|
1206
|
+
name: `${row.label}_${row.property}`,
|
|
1207
|
+
type: row.type || 'BTREE',
|
|
1208
|
+
entityType: 'NODE',
|
|
1209
|
+
labelsOrTypes: [row.label || ''],
|
|
1210
|
+
properties: [row.property || ''],
|
|
1211
|
+
state: 'ONLINE',
|
|
1212
|
+
}));
|
|
1213
|
+
return {
|
|
1214
|
+
success: true,
|
|
1215
|
+
executionTime: Date.now() - startTime,
|
|
1216
|
+
indexes,
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
// ==================== UTILITY METHODS ====================
|
|
1220
|
+
escapeIdentifier(identifier) {
|
|
1221
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier)) {
|
|
1222
|
+
return identifier;
|
|
1223
|
+
}
|
|
1224
|
+
return `\`${identifier.replace(/`/g, '``')}\``;
|
|
1225
|
+
}
|
|
1226
|
+
escapeValue(value) {
|
|
1227
|
+
if (value === null)
|
|
1228
|
+
return 'null';
|
|
1229
|
+
if (typeof value === 'string')
|
|
1230
|
+
return `'${value.replace(/'/g, "\\'")}'`;
|
|
1231
|
+
if (typeof value === 'number')
|
|
1232
|
+
return String(value);
|
|
1233
|
+
if (typeof value === 'boolean')
|
|
1234
|
+
return value ? 'true' : 'false';
|
|
1235
|
+
if (value instanceof Date)
|
|
1236
|
+
return `datetime('${value.toISOString()}')`;
|
|
1237
|
+
if (Array.isArray(value))
|
|
1238
|
+
return `[${value.map(v => this.escapeValue(v)).join(', ')}]`;
|
|
1239
|
+
return String(value);
|
|
1240
|
+
}
|
|
1241
|
+
buildWhereClause(where, variableName = 'n') {
|
|
1242
|
+
const params = {};
|
|
1243
|
+
const parts = [];
|
|
1244
|
+
Object.entries(where).forEach(([key, value], index) => {
|
|
1245
|
+
const paramName = `where_${index}`;
|
|
1246
|
+
parts.push(`${variableName}.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
1247
|
+
params[paramName] = value;
|
|
1248
|
+
});
|
|
1249
|
+
return {
|
|
1250
|
+
clause: parts.join(' AND '),
|
|
1251
|
+
params,
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
// ==================== PROTECTED PARSER METHODS ====================
|
|
1255
|
+
parseNode(nativeNode) {
|
|
1256
|
+
if (!nativeNode) {
|
|
1257
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.NODE_ERROR, 'Cannot parse null node');
|
|
1258
|
+
}
|
|
1259
|
+
if (nativeNode.identity !== undefined) {
|
|
1260
|
+
return {
|
|
1261
|
+
id: this.toNumber(nativeNode.identity),
|
|
1262
|
+
labels: nativeNode.labels || [],
|
|
1263
|
+
properties: this.convertProperties(nativeNode.properties),
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
return {
|
|
1267
|
+
id: nativeNode.id || nativeNode.identity || '',
|
|
1268
|
+
labels: nativeNode.labels || [],
|
|
1269
|
+
properties: (nativeNode.properties || nativeNode),
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
parseRelationship(nativeRelationship) {
|
|
1273
|
+
if (!nativeRelationship) {
|
|
1274
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.RELATIONSHIP_ERROR, 'Cannot parse null relationship');
|
|
1275
|
+
}
|
|
1276
|
+
if (nativeRelationship.identity !== undefined) {
|
|
1277
|
+
return {
|
|
1278
|
+
id: this.toNumber(nativeRelationship.identity),
|
|
1279
|
+
type: nativeRelationship.type,
|
|
1280
|
+
startNodeId: this.toNumber(nativeRelationship.start),
|
|
1281
|
+
endNodeId: this.toNumber(nativeRelationship.end),
|
|
1282
|
+
properties: this.convertProperties(nativeRelationship.properties),
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
return {
|
|
1286
|
+
id: nativeRelationship.id || nativeRelationship.identity || '',
|
|
1287
|
+
type: nativeRelationship.type || '',
|
|
1288
|
+
startNodeId: nativeRelationship.startNodeId || nativeRelationship.start || '',
|
|
1289
|
+
endNodeId: nativeRelationship.endNodeId || nativeRelationship.end || '',
|
|
1290
|
+
properties: (nativeRelationship.properties || nativeRelationship),
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
parsePath(nativePath) {
|
|
1294
|
+
if (!nativePath) {
|
|
1295
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.PATH_ERROR, 'Cannot parse null path');
|
|
1296
|
+
}
|
|
1297
|
+
const nodes = [];
|
|
1298
|
+
const relationships = [];
|
|
1299
|
+
if (nativePath.segments) {
|
|
1300
|
+
nativePath.segments.forEach((segment) => {
|
|
1301
|
+
if (nodes.length === 0) {
|
|
1302
|
+
nodes.push(this.parseNode(segment.start));
|
|
1303
|
+
}
|
|
1304
|
+
relationships.push(this.parseRelationship(segment.relationship));
|
|
1305
|
+
nodes.push(this.parseNode(segment.end));
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
return {
|
|
1309
|
+
nodes,
|
|
1310
|
+
relationships,
|
|
1311
|
+
length: relationships.length,
|
|
1312
|
+
start: nodes[0],
|
|
1313
|
+
end: nodes[nodes.length - 1],
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
// ==================== PRIVATE HELPER METHODS ====================
|
|
1317
|
+
convertValue(value) {
|
|
1318
|
+
if (value === null || value === undefined)
|
|
1319
|
+
return value;
|
|
1320
|
+
// Handle Neo4j Integer type (used by Bolt protocol)
|
|
1321
|
+
if (value && typeof value.toNumber === 'function') {
|
|
1322
|
+
return value.toNumber();
|
|
1323
|
+
}
|
|
1324
|
+
if (value.labels !== undefined && value.properties !== undefined) {
|
|
1325
|
+
return this.parseNode(value);
|
|
1326
|
+
}
|
|
1327
|
+
if (value.type !== undefined && value.start !== undefined && value.end !== undefined) {
|
|
1328
|
+
return this.parseRelationship(value);
|
|
1329
|
+
}
|
|
1330
|
+
if (value.segments !== undefined) {
|
|
1331
|
+
return this.parsePath(value);
|
|
1332
|
+
}
|
|
1333
|
+
if (Array.isArray(value)) {
|
|
1334
|
+
return value.map(v => this.convertValue(v));
|
|
1335
|
+
}
|
|
1336
|
+
if (typeof value === 'object') {
|
|
1337
|
+
const converted = {};
|
|
1338
|
+
Object.entries(value).forEach(([key, val]) => {
|
|
1339
|
+
converted[key] = this.convertValue(val);
|
|
1340
|
+
});
|
|
1341
|
+
return converted;
|
|
1342
|
+
}
|
|
1343
|
+
return value;
|
|
1344
|
+
}
|
|
1345
|
+
convertProperties(properties) {
|
|
1346
|
+
if (!properties)
|
|
1347
|
+
return {};
|
|
1348
|
+
const converted = {};
|
|
1349
|
+
Object.entries(properties).forEach(([key, value]) => {
|
|
1350
|
+
converted[key] = this.convertValue(value);
|
|
1351
|
+
});
|
|
1352
|
+
return converted;
|
|
1353
|
+
}
|
|
1354
|
+
toNumber(value) {
|
|
1355
|
+
if (value && typeof value.toNumber === 'function') {
|
|
1356
|
+
return value.toNumber();
|
|
1357
|
+
}
|
|
1358
|
+
if (typeof value === 'number') {
|
|
1359
|
+
return value;
|
|
1360
|
+
}
|
|
1361
|
+
return parseInt(value, 10) || 0;
|
|
1362
|
+
}
|
|
1363
|
+
normalizeLabels(labels) {
|
|
1364
|
+
return Array.isArray(labels) ? labels : [labels];
|
|
1365
|
+
}
|
|
1366
|
+
buildPropertiesClause(properties, prefix = '') {
|
|
1367
|
+
const params = {};
|
|
1368
|
+
const propParts = [];
|
|
1369
|
+
Object.entries(properties).forEach(([key, value], index) => {
|
|
1370
|
+
const paramName = `${prefix}prop_${index}`;
|
|
1371
|
+
propParts.push(`${this.escapeIdentifier(key)}: $${paramName}`);
|
|
1372
|
+
params[paramName] = value;
|
|
1373
|
+
});
|
|
1374
|
+
return {
|
|
1375
|
+
clause: `{${propParts.join(', ')}}`,
|
|
1376
|
+
params,
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
buildNodeReference(ref, alias, params, prefix = '') {
|
|
1380
|
+
let pattern = `(${alias}`;
|
|
1381
|
+
if (ref.labels) {
|
|
1382
|
+
const labels = this.normalizeLabels(ref.labels);
|
|
1383
|
+
pattern += ':' + labels.map(l => this.escapeIdentifier(l)).join(':');
|
|
1384
|
+
}
|
|
1385
|
+
pattern += ')';
|
|
1386
|
+
if (ref.id !== undefined) {
|
|
1387
|
+
const paramName = `${prefix}id`;
|
|
1388
|
+
params[paramName] = typeof ref.id === 'string' ? parseInt(ref.id, 10) : ref.id;
|
|
1389
|
+
pattern += ` WHERE id(${alias}) = $${paramName}`;
|
|
1390
|
+
}
|
|
1391
|
+
return pattern;
|
|
1392
|
+
}
|
|
1393
|
+
buildWhereFromClause(where, alias, prefix = '') {
|
|
1394
|
+
const params = {};
|
|
1395
|
+
const clause = this.buildWhereCondition(where, alias, params, prefix);
|
|
1396
|
+
return { clause, params };
|
|
1397
|
+
}
|
|
1398
|
+
buildWhereCondition(where, alias, params, prefix, index = 0) {
|
|
1399
|
+
const paramName = `${prefix}where_${index}`;
|
|
1400
|
+
let condition;
|
|
1401
|
+
switch (where.operator) {
|
|
1402
|
+
case node_types_1.NodeComparisonOperator.IS_NULL:
|
|
1403
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} IS NULL`;
|
|
1404
|
+
break;
|
|
1405
|
+
case node_types_1.NodeComparisonOperator.IS_NOT_NULL:
|
|
1406
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} IS NOT NULL`;
|
|
1407
|
+
break;
|
|
1408
|
+
case node_types_1.NodeComparisonOperator.IN:
|
|
1409
|
+
case node_types_1.NodeComparisonOperator.NOT_IN:
|
|
1410
|
+
params[paramName] = where.value;
|
|
1411
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} ${where.operator} $${paramName}`;
|
|
1412
|
+
break;
|
|
1413
|
+
case node_types_1.NodeComparisonOperator.CONTAINS:
|
|
1414
|
+
params[paramName] = where.value;
|
|
1415
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} CONTAINS $${paramName}`;
|
|
1416
|
+
break;
|
|
1417
|
+
case node_types_1.NodeComparisonOperator.STARTS_WITH:
|
|
1418
|
+
params[paramName] = where.value;
|
|
1419
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} STARTS WITH $${paramName}`;
|
|
1420
|
+
break;
|
|
1421
|
+
case node_types_1.NodeComparisonOperator.ENDS_WITH:
|
|
1422
|
+
params[paramName] = where.value;
|
|
1423
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} ENDS WITH $${paramName}`;
|
|
1424
|
+
break;
|
|
1425
|
+
case node_types_1.NodeComparisonOperator.REGEX:
|
|
1426
|
+
params[paramName] = where.value;
|
|
1427
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} =~ $${paramName}`;
|
|
1428
|
+
break;
|
|
1429
|
+
default:
|
|
1430
|
+
params[paramName] = where.value;
|
|
1431
|
+
condition = `${alias}.${this.escapeIdentifier(where.property)} ${where.operator} $${paramName}`;
|
|
1432
|
+
}
|
|
1433
|
+
if (where.and && where.and.length > 0) {
|
|
1434
|
+
const andClauses = where.and.map((w, i) => this.buildWhereCondition(w, alias, params, prefix, index + i + 1));
|
|
1435
|
+
condition = `(${condition} AND ${andClauses.join(' AND ')})`;
|
|
1436
|
+
}
|
|
1437
|
+
if (where.or && where.or.length > 0) {
|
|
1438
|
+
const orClauses = where.or.map((w, i) => this.buildWhereCondition(w, alias, params, prefix, index + i + 100));
|
|
1439
|
+
condition = `(${condition} OR ${orClauses.join(' OR ')})`;
|
|
1440
|
+
}
|
|
1441
|
+
return condition;
|
|
1442
|
+
}
|
|
1443
|
+
buildNodeSelectorMatch(selector, alias, params, prefix = '') {
|
|
1444
|
+
let pattern = `(${alias}`;
|
|
1445
|
+
if (selector.labels) {
|
|
1446
|
+
const labels = this.normalizeLabels(selector.labels);
|
|
1447
|
+
pattern += ':' + labels.map((l) => this.escapeIdentifier(l)).join(':');
|
|
1448
|
+
}
|
|
1449
|
+
pattern += ')';
|
|
1450
|
+
const whereParts = [];
|
|
1451
|
+
if (selector.id !== undefined) {
|
|
1452
|
+
const paramName = `${prefix}id`;
|
|
1453
|
+
params[paramName] = typeof selector.id === 'string' ? parseInt(selector.id, 10) : selector.id;
|
|
1454
|
+
whereParts.push(`id(${alias}) = $${paramName}`);
|
|
1455
|
+
}
|
|
1456
|
+
if (selector.properties && Object.keys(selector.properties).length > 0) {
|
|
1457
|
+
Object.entries(selector.properties).forEach(([key, value], index) => {
|
|
1458
|
+
const paramName = `${prefix}prop_${index}`;
|
|
1459
|
+
whereParts.push(`${alias}.${this.escapeIdentifier(key)} = $${paramName}`);
|
|
1460
|
+
params[paramName] = value;
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
if (selector.where) {
|
|
1464
|
+
const { clause, params: whereParams } = this.buildWhereFromClause(selector.where, alias, prefix);
|
|
1465
|
+
whereParts.push(clause);
|
|
1466
|
+
Object.assign(params, whereParams);
|
|
1467
|
+
}
|
|
1468
|
+
if (whereParts.length > 0) {
|
|
1469
|
+
return `${pattern} WHERE ${whereParts.join(' AND ')}`;
|
|
1470
|
+
}
|
|
1471
|
+
return pattern;
|
|
1472
|
+
}
|
|
1473
|
+
parseStatistics(counters) {
|
|
1474
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1475
|
+
if (!counters)
|
|
1476
|
+
return undefined;
|
|
1477
|
+
return {
|
|
1478
|
+
nodesCreated: ((_a = counters.nodesCreated) === null || _a === void 0 ? void 0 : _a.call(counters)) || 0,
|
|
1479
|
+
nodesDeleted: ((_b = counters.nodesDeleted) === null || _b === void 0 ? void 0 : _b.call(counters)) || 0,
|
|
1480
|
+
relationshipsCreated: ((_c = counters.relationshipsCreated) === null || _c === void 0 ? void 0 : _c.call(counters)) || 0,
|
|
1481
|
+
relationshipsDeleted: ((_d = counters.relationshipsDeleted) === null || _d === void 0 ? void 0 : _d.call(counters)) || 0,
|
|
1482
|
+
propertiesSet: ((_e = counters.propertiesSet) === null || _e === void 0 ? void 0 : _e.call(counters)) || 0,
|
|
1483
|
+
labelsAdded: ((_f = counters.labelsAdded) === null || _f === void 0 ? void 0 : _f.call(counters)) || 0,
|
|
1484
|
+
labelsRemoved: ((_g = counters.labelsRemoved) === null || _g === void 0 ? void 0 : _g.call(counters)) || 0,
|
|
1485
|
+
containsUpdates: ((_h = counters.containsUpdates) === null || _h === void 0 ? void 0 : _h.call(counters)) || false,
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
exports.MemgraphAdapter = MemgraphAdapter;
|
|
1490
|
+
exports.default = MemgraphAdapter;
|
|
1491
|
+
//# sourceMappingURL=memgraph.adapter.js.map
|