@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,1430 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AWS Neptune Graph Database Adapter
|
|
4
|
+
* Implements the BaseGraphAdapter for Amazon Neptune using Gremlin or openCypher
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.NeptuneAdapter = void 0;
|
|
8
|
+
const base_adapter_1 = require("./base.adapter");
|
|
9
|
+
const graph_types_1 = require("../types/graph.types");
|
|
10
|
+
const relationship_types_1 = require("../types/relationship.types");
|
|
11
|
+
/**
|
|
12
|
+
* Neptune connection implementation
|
|
13
|
+
*/
|
|
14
|
+
class NeptuneConnection {
|
|
15
|
+
constructor(config, id) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.type = graph_types_1.GraphDatabaseType.NEPTUNE;
|
|
18
|
+
this.status = graph_types_1.GraphConnectionStatus.DISCONNECTED;
|
|
19
|
+
this.httpClient = null;
|
|
20
|
+
this.awsCredentials = null;
|
|
21
|
+
this.id = id || `neptune-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
22
|
+
this.createdAt = new Date();
|
|
23
|
+
this.queryLanguage = config.queryLanguage;
|
|
24
|
+
}
|
|
25
|
+
async connect() {
|
|
26
|
+
var _a;
|
|
27
|
+
if (this.status === graph_types_1.GraphConnectionStatus.CONNECTED) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.status = graph_types_1.GraphConnectionStatus.CONNECTING;
|
|
31
|
+
try {
|
|
32
|
+
// Build endpoint URL
|
|
33
|
+
const port = this.config.port || 8182;
|
|
34
|
+
const protocol = this.config.ssl !== false ? 'https' : 'http';
|
|
35
|
+
const baseUrl = `${protocol}://${this.config.endpoint}:${port}`;
|
|
36
|
+
// If using IAM auth, set up AWS signing
|
|
37
|
+
if (this.config.useIAM) {
|
|
38
|
+
this.awsCredentials = {
|
|
39
|
+
accessKeyId: this.config.accessKeyId,
|
|
40
|
+
secretAccessKey: this.config.secretAccessKey,
|
|
41
|
+
sessionToken: this.config.sessionToken,
|
|
42
|
+
region: this.config.region,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
this.httpClient = {
|
|
46
|
+
baseUrl,
|
|
47
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, (_a = this.config.options) === null || _a === void 0 ? void 0 : _a.headers),
|
|
48
|
+
};
|
|
49
|
+
// Verify connectivity with a simple query
|
|
50
|
+
await this.executeQuery(this.queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN
|
|
51
|
+
? 'g.V().limit(1).count()'
|
|
52
|
+
: 'MATCH (n) RETURN count(n) LIMIT 1');
|
|
53
|
+
this.status = graph_types_1.GraphConnectionStatus.CONNECTED;
|
|
54
|
+
this.lastUsedAt = new Date();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
this.status = graph_types_1.GraphConnectionStatus.ERROR;
|
|
58
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.CONNECTION_ERROR, `Failed to connect to Neptune: ${error.message}`, error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async disconnect() {
|
|
62
|
+
this.httpClient = null;
|
|
63
|
+
this.awsCredentials = null;
|
|
64
|
+
this.status = graph_types_1.GraphConnectionStatus.DISCONNECTED;
|
|
65
|
+
}
|
|
66
|
+
isConnected() {
|
|
67
|
+
return this.status === graph_types_1.GraphConnectionStatus.CONNECTED && this.httpClient !== null;
|
|
68
|
+
}
|
|
69
|
+
getClient() {
|
|
70
|
+
if (!this.httpClient) {
|
|
71
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.CONNECTION_ERROR, 'Neptune client not initialized. Call connect() first.');
|
|
72
|
+
}
|
|
73
|
+
return this.httpClient;
|
|
74
|
+
}
|
|
75
|
+
getSession() {
|
|
76
|
+
return this.getClient();
|
|
77
|
+
}
|
|
78
|
+
getConfig() {
|
|
79
|
+
return this.config;
|
|
80
|
+
}
|
|
81
|
+
async executeQuery(query, params) {
|
|
82
|
+
if (!this.httpClient) {
|
|
83
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.CONNECTION_ERROR, 'Neptune client not initialized');
|
|
84
|
+
}
|
|
85
|
+
this.lastUsedAt = new Date();
|
|
86
|
+
const endpoint = this.queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN
|
|
87
|
+
? '/gremlin'
|
|
88
|
+
: '/openCypher';
|
|
89
|
+
const body = this.queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN
|
|
90
|
+
? { gremlin: query, bindings: params || {} }
|
|
91
|
+
: { query, parameters: params || {} };
|
|
92
|
+
try {
|
|
93
|
+
// Make HTTP request to Neptune
|
|
94
|
+
const response = await this.makeRequest(endpoint, body);
|
|
95
|
+
return response;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.QUERY_ERROR, `Neptune query failed: ${error.message}`, error, query, params);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async makeRequest(endpoint, body) {
|
|
102
|
+
const url = `${this.httpClient.baseUrl}${endpoint}`;
|
|
103
|
+
const headers = Object.assign({}, this.httpClient.headers);
|
|
104
|
+
// Sign request if using IAM auth
|
|
105
|
+
if (this.awsCredentials) {
|
|
106
|
+
const signedHeaders = await this.signRequest('POST', url, JSON.stringify(body));
|
|
107
|
+
Object.assign(headers, signedHeaders);
|
|
108
|
+
}
|
|
109
|
+
// Using fetch for HTTP requests
|
|
110
|
+
const response = await fetch(url, {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers,
|
|
113
|
+
body: JSON.stringify(body),
|
|
114
|
+
});
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
const errorBody = await response.text();
|
|
117
|
+
throw new Error(`HTTP ${response.status}: ${errorBody}`);
|
|
118
|
+
}
|
|
119
|
+
return response.json();
|
|
120
|
+
}
|
|
121
|
+
async signRequest(method, url, body) {
|
|
122
|
+
// AWS Signature V4 signing
|
|
123
|
+
// In production, use aws-sdk or @aws-sdk/signature-v4
|
|
124
|
+
// This is a placeholder for the signing logic
|
|
125
|
+
const timestamp = new Date().toISOString().replace(/[:-]|\.\d{3}/g, '');
|
|
126
|
+
const date = timestamp.slice(0, 8);
|
|
127
|
+
return {
|
|
128
|
+
'X-Amz-Date': timestamp,
|
|
129
|
+
'X-Amz-Security-Token': this.awsCredentials.sessionToken || '',
|
|
130
|
+
// In production, add proper Authorization header with signature
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Neptune transaction implementation
|
|
136
|
+
* Note: Neptune has limited transaction support, primarily for Gremlin
|
|
137
|
+
*/
|
|
138
|
+
class NeptuneTransaction {
|
|
139
|
+
constructor(connection, transactionId) {
|
|
140
|
+
this.connection = connection;
|
|
141
|
+
this.status = graph_types_1.GraphTransactionStatus.PENDING;
|
|
142
|
+
this.id = transactionId || `tx-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
143
|
+
this.createdAt = new Date();
|
|
144
|
+
this.status = graph_types_1.GraphTransactionStatus.ACTIVE;
|
|
145
|
+
this.native = { transactionId: this.id };
|
|
146
|
+
}
|
|
147
|
+
async commit() {
|
|
148
|
+
if (this.status !== graph_types_1.GraphTransactionStatus.ACTIVE) {
|
|
149
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.TRANSACTION_ERROR, `Cannot commit transaction in ${this.status} state`);
|
|
150
|
+
}
|
|
151
|
+
// Neptune auto-commits each query, so this is a no-op
|
|
152
|
+
this.status = graph_types_1.GraphTransactionStatus.COMMITTED;
|
|
153
|
+
}
|
|
154
|
+
async rollback() {
|
|
155
|
+
if (this.status !== graph_types_1.GraphTransactionStatus.ACTIVE) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Neptune doesn't support rollback in the traditional sense
|
|
159
|
+
this.status = graph_types_1.GraphTransactionStatus.ROLLED_BACK;
|
|
160
|
+
}
|
|
161
|
+
isActive() {
|
|
162
|
+
return this.status === graph_types_1.GraphTransactionStatus.ACTIVE;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* AWS Neptune Graph Database Adapter
|
|
167
|
+
*/
|
|
168
|
+
class NeptuneAdapter extends base_adapter_1.BaseGraphAdapter {
|
|
169
|
+
constructor() {
|
|
170
|
+
super(...arguments);
|
|
171
|
+
this.type = graph_types_1.GraphDatabaseType.NEPTUNE;
|
|
172
|
+
this.supportedLanguages = [graph_types_1.GraphQueryLanguage.GREMLIN, graph_types_1.GraphQueryLanguage.OPENCYPHER];
|
|
173
|
+
this.defaultLanguage = graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
174
|
+
}
|
|
175
|
+
// ==================== CONNECTION METHODS ====================
|
|
176
|
+
async connect(config) {
|
|
177
|
+
if (config.type !== graph_types_1.GraphDatabaseType.NEPTUNE) {
|
|
178
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, `Invalid config type ${config.type}. Expected ${graph_types_1.GraphDatabaseType.NEPTUNE}`);
|
|
179
|
+
}
|
|
180
|
+
const connection = new NeptuneConnection(config);
|
|
181
|
+
await connection.connect();
|
|
182
|
+
return connection;
|
|
183
|
+
}
|
|
184
|
+
async disconnect(connection) {
|
|
185
|
+
await connection.disconnect();
|
|
186
|
+
}
|
|
187
|
+
async testConnection(connection) {
|
|
188
|
+
const startTime = Date.now();
|
|
189
|
+
const neptuneConn = connection;
|
|
190
|
+
const queryLanguage = neptuneConn.getConfig().queryLanguage;
|
|
191
|
+
try {
|
|
192
|
+
const testQuery = queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN
|
|
193
|
+
? 'g.V().limit(1).count()'
|
|
194
|
+
: 'MATCH (n) RETURN count(n) AS count LIMIT 1';
|
|
195
|
+
await neptuneConn.executeQuery(testQuery);
|
|
196
|
+
return {
|
|
197
|
+
connected: true,
|
|
198
|
+
message: 'Connection successful',
|
|
199
|
+
databaseType: graph_types_1.GraphDatabaseType.NEPTUNE,
|
|
200
|
+
queryLanguage,
|
|
201
|
+
responseTime: Date.now() - startTime,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
return {
|
|
206
|
+
connected: false,
|
|
207
|
+
message: 'Connection failed',
|
|
208
|
+
databaseType: graph_types_1.GraphDatabaseType.NEPTUNE,
|
|
209
|
+
queryLanguage,
|
|
210
|
+
responseTime: Date.now() - startTime,
|
|
211
|
+
error: error.message,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async getDatabaseInfo(connection) {
|
|
216
|
+
const neptuneConn = connection;
|
|
217
|
+
try {
|
|
218
|
+
// Neptune doesn't have a direct version query, use status endpoint
|
|
219
|
+
const response = await neptuneConn.executeQuery('g.V().limit(0)');
|
|
220
|
+
return {
|
|
221
|
+
version: 'Neptune',
|
|
222
|
+
edition: 'AWS Neptune',
|
|
223
|
+
features: ['gremlin', 'openCypher', 'sparql'],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (_a) {
|
|
227
|
+
return {
|
|
228
|
+
version: 'Unknown',
|
|
229
|
+
edition: 'AWS Neptune',
|
|
230
|
+
features: [],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// ==================== TRANSACTION METHODS ====================
|
|
235
|
+
async beginTransaction(connection, options) {
|
|
236
|
+
// Neptune has limited transaction support
|
|
237
|
+
return new NeptuneTransaction(connection);
|
|
238
|
+
}
|
|
239
|
+
async commitTransaction(connection, transaction) {
|
|
240
|
+
await transaction.commit();
|
|
241
|
+
}
|
|
242
|
+
async rollbackTransaction(connection, transaction) {
|
|
243
|
+
await transaction.rollback();
|
|
244
|
+
}
|
|
245
|
+
// ==================== RAW QUERY METHODS ====================
|
|
246
|
+
async executeRaw(connection, options, transaction) {
|
|
247
|
+
const startTime = Date.now();
|
|
248
|
+
const neptuneConn = connection;
|
|
249
|
+
try {
|
|
250
|
+
const response = await neptuneConn.executeQuery(options.query, options.params);
|
|
251
|
+
const data = this.parseQueryResponse(response, neptuneConn.getConfig().queryLanguage);
|
|
252
|
+
return {
|
|
253
|
+
success: true,
|
|
254
|
+
executionTime: Date.now() - startTime,
|
|
255
|
+
data: data,
|
|
256
|
+
count: data.length,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
throw this.wrapError(error, graph_types_1.GraphErrorType.QUERY_ERROR, `Query execution failed: ${error.message}`, options.query, options.params);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
parseQueryResponse(response, language) {
|
|
264
|
+
if (language === graph_types_1.GraphQueryLanguage.GREMLIN) {
|
|
265
|
+
return this.parseGremlinResponse(response);
|
|
266
|
+
}
|
|
267
|
+
return this.parseOpenCypherResponse(response);
|
|
268
|
+
}
|
|
269
|
+
parseGremlinResponse(response) {
|
|
270
|
+
if (!response || !response.result)
|
|
271
|
+
return [];
|
|
272
|
+
const data = response.result.data;
|
|
273
|
+
if (!data || !data['@value'])
|
|
274
|
+
return [];
|
|
275
|
+
return data['@value'].map((item) => this.parseGremlinValue(item));
|
|
276
|
+
}
|
|
277
|
+
parseGremlinValue(value) {
|
|
278
|
+
if (!value)
|
|
279
|
+
return value;
|
|
280
|
+
if (value['@type']) {
|
|
281
|
+
const type = value['@type'];
|
|
282
|
+
const val = value['@value'];
|
|
283
|
+
switch (type) {
|
|
284
|
+
case 'g:Vertex':
|
|
285
|
+
return this.parseGremlinVertex(val);
|
|
286
|
+
case 'g:Edge':
|
|
287
|
+
return this.parseGremlinEdge(val);
|
|
288
|
+
case 'g:Path':
|
|
289
|
+
return this.parseGremlinPath(val);
|
|
290
|
+
case 'g:Int64':
|
|
291
|
+
case 'g:Int32':
|
|
292
|
+
case 'g:Double':
|
|
293
|
+
case 'g:Float':
|
|
294
|
+
return Number(val);
|
|
295
|
+
case 'g:List':
|
|
296
|
+
return val.map((v) => this.parseGremlinValue(v));
|
|
297
|
+
case 'g:Map':
|
|
298
|
+
return this.parseGremlinMap(val);
|
|
299
|
+
case 'g:Set':
|
|
300
|
+
return val.map((v) => this.parseGremlinValue(v));
|
|
301
|
+
case 'g:UUID':
|
|
302
|
+
return val;
|
|
303
|
+
case 'g:Date':
|
|
304
|
+
return new Date(val);
|
|
305
|
+
default:
|
|
306
|
+
return val;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (Array.isArray(value)) {
|
|
310
|
+
return value.map(v => this.parseGremlinValue(v));
|
|
311
|
+
}
|
|
312
|
+
if (typeof value === 'object') {
|
|
313
|
+
const result = {};
|
|
314
|
+
Object.entries(value).forEach(([k, v]) => {
|
|
315
|
+
result[k] = this.parseGremlinValue(v);
|
|
316
|
+
});
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
return value;
|
|
320
|
+
}
|
|
321
|
+
parseGremlinVertex(val) {
|
|
322
|
+
const properties = {};
|
|
323
|
+
if (val.properties) {
|
|
324
|
+
Object.entries(val.properties).forEach(([key, propArray]) => {
|
|
325
|
+
var _a, _b, _c;
|
|
326
|
+
if (Array.isArray(propArray) && propArray.length > 0) {
|
|
327
|
+
properties[key] = ((_b = (_a = propArray[0]) === null || _a === void 0 ? void 0 : _a['@value']) === null || _b === void 0 ? void 0 : _b.value) || ((_c = propArray[0]) === null || _c === void 0 ? void 0 : _c.value);
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
id: val.id,
|
|
333
|
+
labels: [val.label],
|
|
334
|
+
properties,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
parseGremlinEdge(val) {
|
|
338
|
+
const properties = {};
|
|
339
|
+
if (val.properties) {
|
|
340
|
+
Object.entries(val.properties).forEach(([key, propVal]) => {
|
|
341
|
+
properties[key] = this.parseGremlinValue(propVal);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
id: val.id,
|
|
346
|
+
type: val.label,
|
|
347
|
+
startNodeId: val.outV,
|
|
348
|
+
endNodeId: val.inV,
|
|
349
|
+
properties,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
parseGremlinPath(val) {
|
|
353
|
+
var _a;
|
|
354
|
+
const objects = ((_a = val.objects) === null || _a === void 0 ? void 0 : _a.map((obj) => this.parseGremlinValue(obj))) || [];
|
|
355
|
+
const nodes = [];
|
|
356
|
+
const relationships = [];
|
|
357
|
+
objects.forEach((obj) => {
|
|
358
|
+
if (obj.labels) {
|
|
359
|
+
nodes.push(obj);
|
|
360
|
+
}
|
|
361
|
+
else if (obj.type) {
|
|
362
|
+
relationships.push(obj);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return {
|
|
366
|
+
nodes,
|
|
367
|
+
relationships,
|
|
368
|
+
length: relationships.length,
|
|
369
|
+
start: nodes[0],
|
|
370
|
+
end: nodes[nodes.length - 1],
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
parseGremlinMap(val) {
|
|
374
|
+
const result = {};
|
|
375
|
+
for (let i = 0; i < val.length; i += 2) {
|
|
376
|
+
const key = this.parseGremlinValue(val[i]);
|
|
377
|
+
const value = this.parseGremlinValue(val[i + 1]);
|
|
378
|
+
result[key] = value;
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
parseOpenCypherResponse(response) {
|
|
383
|
+
if (!response || !response.results)
|
|
384
|
+
return [];
|
|
385
|
+
return response.results;
|
|
386
|
+
}
|
|
387
|
+
// ==================== NODE OPERATIONS ====================
|
|
388
|
+
async createNode(connection, options, transaction) {
|
|
389
|
+
const startTime = Date.now();
|
|
390
|
+
const neptuneConn = connection;
|
|
391
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
392
|
+
const labels = this.normalizeLabels(options.labels);
|
|
393
|
+
let query;
|
|
394
|
+
let params = {};
|
|
395
|
+
if (isGremlin) {
|
|
396
|
+
// Gremlin addV query
|
|
397
|
+
const propsSteps = Object.entries(options.properties)
|
|
398
|
+
.map(([key, value]) => `.property('${key}', ${this.gremlinValue(value)})`)
|
|
399
|
+
.join('');
|
|
400
|
+
query = `g.addV('${labels[0]}')${propsSteps}`;
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
// openCypher CREATE query
|
|
404
|
+
const labelStr = labels.map(l => this.escapeIdentifier(l)).join(':');
|
|
405
|
+
const propEntries = Object.entries(options.properties);
|
|
406
|
+
const propStr = propEntries.map(([k], i) => `${k}: $prop${i}`).join(', ');
|
|
407
|
+
propEntries.forEach(([, v], i) => { params[`prop${i}`] = v; });
|
|
408
|
+
query = `CREATE (n:${labelStr} {${propStr}}) RETURN n`;
|
|
409
|
+
}
|
|
410
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
411
|
+
return {
|
|
412
|
+
success: true,
|
|
413
|
+
executionTime: Date.now() - startTime,
|
|
414
|
+
node: result.data.length > 0 ? this.parseNode(result.data[0]) : undefined,
|
|
415
|
+
created: true,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
async findNodes(connection, options, transaction) {
|
|
419
|
+
const startTime = Date.now();
|
|
420
|
+
const neptuneConn = connection;
|
|
421
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
422
|
+
let query;
|
|
423
|
+
const params = {};
|
|
424
|
+
if (isGremlin) {
|
|
425
|
+
query = this.buildGremlinFindNodesQuery(options);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
query = this.buildCypherFindNodesQuery(options, params);
|
|
429
|
+
}
|
|
430
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
431
|
+
const nodes = result.data.map(row => this.parseNode(isGremlin ? row : row.n || row));
|
|
432
|
+
return {
|
|
433
|
+
success: true,
|
|
434
|
+
executionTime: Date.now() - startTime,
|
|
435
|
+
nodes,
|
|
436
|
+
count: nodes.length,
|
|
437
|
+
hasMore: options.limit !== undefined && nodes.length === options.limit,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
buildGremlinFindNodesQuery(options) {
|
|
441
|
+
let query = 'g.V()';
|
|
442
|
+
if (options.labels) {
|
|
443
|
+
const labels = this.normalizeLabels(options.labels);
|
|
444
|
+
query += `.hasLabel('${labels.join("', '")}')`;
|
|
445
|
+
}
|
|
446
|
+
if (options.properties) {
|
|
447
|
+
Object.entries(options.properties).forEach(([key, value]) => {
|
|
448
|
+
query += `.has('${key}', ${this.gremlinValue(value)})`;
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
452
|
+
const orderSteps = options.orderBy.map(o => `by('${o.property}', ${o.direction === 'DESC' ? 'desc' : 'asc'})`).join('.');
|
|
453
|
+
query += `.order().${orderSteps}`;
|
|
454
|
+
}
|
|
455
|
+
if (options.skip) {
|
|
456
|
+
query += `.skip(${options.skip})`;
|
|
457
|
+
}
|
|
458
|
+
if (options.limit) {
|
|
459
|
+
query += `.limit(${options.limit})`;
|
|
460
|
+
}
|
|
461
|
+
return query;
|
|
462
|
+
}
|
|
463
|
+
buildCypherFindNodesQuery(options, params) {
|
|
464
|
+
const labels = options.labels ? this.normalizeLabels(options.labels) : [];
|
|
465
|
+
const labelStr = labels.length > 0 ? ':' + labels.map(l => this.escapeIdentifier(l)).join(':') : '';
|
|
466
|
+
let query = `MATCH (n${labelStr})`;
|
|
467
|
+
if (options.properties && Object.keys(options.properties).length > 0) {
|
|
468
|
+
const whereParts = [];
|
|
469
|
+
Object.entries(options.properties).forEach(([key, value], index) => {
|
|
470
|
+
const paramName = `prop_${index}`;
|
|
471
|
+
whereParts.push(`n.${key} = $${paramName}`);
|
|
472
|
+
params[paramName] = value;
|
|
473
|
+
});
|
|
474
|
+
query += ` WHERE ${whereParts.join(' AND ')}`;
|
|
475
|
+
}
|
|
476
|
+
query += ' RETURN n';
|
|
477
|
+
if (options.orderBy && options.orderBy.length > 0) {
|
|
478
|
+
const orderParts = options.orderBy.map(o => `n.${o.property} ${o.direction}`);
|
|
479
|
+
query += ` ORDER BY ${orderParts.join(', ')}`;
|
|
480
|
+
}
|
|
481
|
+
if (options.skip !== undefined) {
|
|
482
|
+
query += ` SKIP ${options.skip}`;
|
|
483
|
+
}
|
|
484
|
+
if (options.limit !== undefined) {
|
|
485
|
+
query += ` LIMIT ${options.limit}`;
|
|
486
|
+
}
|
|
487
|
+
return query;
|
|
488
|
+
}
|
|
489
|
+
async findNodeById(connection, id, transaction) {
|
|
490
|
+
const neptuneConn = connection;
|
|
491
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
492
|
+
const query = isGremlin
|
|
493
|
+
? `g.V('${id}')`
|
|
494
|
+
: `MATCH (n) WHERE id(n) = $id RETURN n`;
|
|
495
|
+
const result = await this.executeRaw(connection, { query, params: { id } }, transaction);
|
|
496
|
+
if (result.data.length === 0) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
return this.parseNode(isGremlin ? result.data[0] : result.data[0].n);
|
|
500
|
+
}
|
|
501
|
+
async updateNode(connection, options, transaction) {
|
|
502
|
+
const startTime = Date.now();
|
|
503
|
+
const neptuneConn = connection;
|
|
504
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
505
|
+
let query;
|
|
506
|
+
const params = {};
|
|
507
|
+
if (isGremlin) {
|
|
508
|
+
query = `g.V('${options.id}')`;
|
|
509
|
+
if (options.set) {
|
|
510
|
+
Object.entries(options.set).forEach(([key, value]) => {
|
|
511
|
+
query += `.property('${key}', ${this.gremlinValue(value)})`;
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
if (options.remove && options.remove.length > 0) {
|
|
515
|
+
options.remove.forEach(prop => {
|
|
516
|
+
query += `.properties('${prop}').drop()`;
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
query = `MATCH (n) WHERE id(n) = $nodeId`;
|
|
522
|
+
params.nodeId = options.id;
|
|
523
|
+
const setParts = [];
|
|
524
|
+
if (options.set) {
|
|
525
|
+
Object.entries(options.set).forEach(([key, value], index) => {
|
|
526
|
+
const paramName = `set_${index}`;
|
|
527
|
+
setParts.push(`n.${key} = $${paramName}`);
|
|
528
|
+
params[paramName] = value;
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
if (setParts.length > 0) {
|
|
532
|
+
query += ` SET ${setParts.join(', ')}`;
|
|
533
|
+
}
|
|
534
|
+
if (options.remove && options.remove.length > 0) {
|
|
535
|
+
query += ` REMOVE ${options.remove.map(p => `n.${p}`).join(', ')}`;
|
|
536
|
+
}
|
|
537
|
+
query += ' RETURN n';
|
|
538
|
+
}
|
|
539
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
540
|
+
return {
|
|
541
|
+
success: true,
|
|
542
|
+
executionTime: Date.now() - startTime,
|
|
543
|
+
node: result.data.length > 0 ? this.parseNode(isGremlin ? result.data[0] : result.data[0].n) : undefined,
|
|
544
|
+
updated: result.data.length > 0,
|
|
545
|
+
matchedCount: result.data.length,
|
|
546
|
+
modifiedCount: Object.keys(options.set || {}).length,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
async deleteNode(connection, options, transaction) {
|
|
550
|
+
const startTime = Date.now();
|
|
551
|
+
const neptuneConn = connection;
|
|
552
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
553
|
+
let query;
|
|
554
|
+
const params = {};
|
|
555
|
+
if (isGremlin) {
|
|
556
|
+
if (options.id) {
|
|
557
|
+
query = `g.V('${options.id}').drop()`;
|
|
558
|
+
}
|
|
559
|
+
else if (options.labels) {
|
|
560
|
+
const labels = this.normalizeLabels(options.labels);
|
|
561
|
+
query = `g.V().hasLabel('${labels.join("', '")}').drop()`;
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Must specify id or labels for delete');
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
if (options.id) {
|
|
569
|
+
query = `MATCH (n) WHERE id(n) = $nodeId ${options.detach ? 'DETACH DELETE' : 'DELETE'} n`;
|
|
570
|
+
params.nodeId = options.id;
|
|
571
|
+
}
|
|
572
|
+
else if (options.labels) {
|
|
573
|
+
const labels = this.normalizeLabels(options.labels);
|
|
574
|
+
query = `MATCH (n:${labels.join(':')}) ${options.detach ? 'DETACH DELETE' : 'DELETE'} n`;
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Must specify id or labels for delete');
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
await this.executeRaw(connection, { query, params }, transaction);
|
|
581
|
+
return {
|
|
582
|
+
success: true,
|
|
583
|
+
executionTime: Date.now() - startTime,
|
|
584
|
+
deletedCount: 1, // Neptune doesn't return count
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
async mergeNode(connection, options, transaction) {
|
|
588
|
+
const startTime = Date.now();
|
|
589
|
+
const neptuneConn = connection;
|
|
590
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
591
|
+
const labels = this.normalizeLabels(options.labels);
|
|
592
|
+
let query;
|
|
593
|
+
const params = {};
|
|
594
|
+
if (isGremlin) {
|
|
595
|
+
// Gremlin coalesce pattern for merge
|
|
596
|
+
const matchProps = Object.entries(options.matchProperties)
|
|
597
|
+
.map(([k, v]) => `.has('${k}', ${this.gremlinValue(v)})`)
|
|
598
|
+
.join('');
|
|
599
|
+
const createProps = Object.entries(Object.assign(Object.assign({}, options.matchProperties), options.onCreate))
|
|
600
|
+
.map(([k, v]) => `.property('${k}', ${this.gremlinValue(v)})`)
|
|
601
|
+
.join('');
|
|
602
|
+
const updateProps = Object.entries(options.onMatch || {})
|
|
603
|
+
.map(([k, v]) => `.property('${k}', ${this.gremlinValue(v)})`)
|
|
604
|
+
.join('');
|
|
605
|
+
query = `g.V().hasLabel('${labels[0]}')${matchProps}.fold().coalesce(unfold()${updateProps}, addV('${labels[0]}')${createProps})`;
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
// openCypher MERGE
|
|
609
|
+
const matchPropsStr = Object.entries(options.matchProperties)
|
|
610
|
+
.map(([k], i) => `${k}: $match${i}`)
|
|
611
|
+
.join(', ');
|
|
612
|
+
Object.entries(options.matchProperties).forEach(([, v], i) => { params[`match${i}`] = v; });
|
|
613
|
+
query = `MERGE (n:${labels.join(':')} {${matchPropsStr}})`;
|
|
614
|
+
if (options.onCreate && Object.keys(options.onCreate).length > 0) {
|
|
615
|
+
const createProps = Object.entries(options.onCreate)
|
|
616
|
+
.map(([k], i) => `n.${k} = $create${i}`)
|
|
617
|
+
.join(', ');
|
|
618
|
+
Object.entries(options.onCreate).forEach(([, v], i) => { params[`create${i}`] = v; });
|
|
619
|
+
query += ` ON CREATE SET ${createProps}`;
|
|
620
|
+
}
|
|
621
|
+
if (options.onMatch && Object.keys(options.onMatch).length > 0) {
|
|
622
|
+
const matchSetProps = Object.entries(options.onMatch)
|
|
623
|
+
.map(([k], i) => `n.${k} = $update${i}`)
|
|
624
|
+
.join(', ');
|
|
625
|
+
Object.entries(options.onMatch).forEach(([, v], i) => { params[`update${i}`] = v; });
|
|
626
|
+
query += ` ON MATCH SET ${matchSetProps}`;
|
|
627
|
+
}
|
|
628
|
+
query += ' RETURN n';
|
|
629
|
+
}
|
|
630
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
631
|
+
return {
|
|
632
|
+
success: true,
|
|
633
|
+
executionTime: Date.now() - startTime,
|
|
634
|
+
node: result.data.length > 0 ? this.parseNode(isGremlin ? result.data[0] : result.data[0].n) : undefined,
|
|
635
|
+
created: true, // Neptune doesn't distinguish
|
|
636
|
+
matched: false,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
// ==================== RELATIONSHIP OPERATIONS ====================
|
|
640
|
+
async createRelationship(connection, options, transaction) {
|
|
641
|
+
const startTime = Date.now();
|
|
642
|
+
const neptuneConn = connection;
|
|
643
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
644
|
+
let query;
|
|
645
|
+
const params = {};
|
|
646
|
+
if (isGremlin) {
|
|
647
|
+
const fromId = options.fromNode.id;
|
|
648
|
+
const toId = options.toNode.id;
|
|
649
|
+
const propsSteps = options.properties
|
|
650
|
+
? Object.entries(options.properties)
|
|
651
|
+
.map(([k, v]) => `.property('${k}', ${this.gremlinValue(v)})`)
|
|
652
|
+
.join('')
|
|
653
|
+
: '';
|
|
654
|
+
query = `g.V('${fromId}').addE('${options.type}').to(g.V('${toId}'))${propsSteps}`;
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
const fromMatch = this.buildCypherNodeMatch(options.fromNode, 'from', params, 'from_');
|
|
658
|
+
const toMatch = this.buildCypherNodeMatch(options.toNode, 'to', params, 'to_');
|
|
659
|
+
let propsStr = '';
|
|
660
|
+
if (options.properties && Object.keys(options.properties).length > 0) {
|
|
661
|
+
propsStr = ' {' + Object.entries(options.properties)
|
|
662
|
+
.map(([k], i) => { params[`rel${i}`] = options.properties[k]; return `${k}: $rel${i}`; })
|
|
663
|
+
.join(', ') + '}';
|
|
664
|
+
}
|
|
665
|
+
query = `
|
|
666
|
+
MATCH ${fromMatch}, ${toMatch}
|
|
667
|
+
CREATE (from)-[r:${options.type}${propsStr}]->(to)
|
|
668
|
+
RETURN r
|
|
669
|
+
`;
|
|
670
|
+
}
|
|
671
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
672
|
+
return {
|
|
673
|
+
success: true,
|
|
674
|
+
executionTime: Date.now() - startTime,
|
|
675
|
+
relationship: result.data.length > 0 ? this.parseRelationship(isGremlin ? result.data[0] : result.data[0].r) : undefined,
|
|
676
|
+
created: true,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
async findRelationships(connection, options, transaction) {
|
|
680
|
+
const startTime = Date.now();
|
|
681
|
+
const neptuneConn = connection;
|
|
682
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
683
|
+
let query;
|
|
684
|
+
const params = {};
|
|
685
|
+
if (isGremlin) {
|
|
686
|
+
query = 'g.E()';
|
|
687
|
+
if (options.type) {
|
|
688
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
689
|
+
query += `.hasLabel('${types.join("', '")}')`;
|
|
690
|
+
}
|
|
691
|
+
if (options.properties) {
|
|
692
|
+
Object.entries(options.properties).forEach(([k, v]) => {
|
|
693
|
+
query += `.has('${k}', ${this.gremlinValue(v)})`;
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
if (options.limit) {
|
|
697
|
+
query += `.limit(${options.limit})`;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
let typeStr = '';
|
|
702
|
+
if (options.type) {
|
|
703
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
704
|
+
typeStr = ':' + types.join('|');
|
|
705
|
+
}
|
|
706
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
707
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
708
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
709
|
+
query = `MATCH ()-[r${typeStr}]->() RETURN r`;
|
|
710
|
+
if (options.limit) {
|
|
711
|
+
query += ` LIMIT ${options.limit}`;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
715
|
+
const relationships = result.data.map(row => this.parseRelationship(isGremlin ? row : row.r || row));
|
|
716
|
+
return {
|
|
717
|
+
success: true,
|
|
718
|
+
executionTime: Date.now() - startTime,
|
|
719
|
+
relationships,
|
|
720
|
+
count: relationships.length,
|
|
721
|
+
hasMore: options.limit !== undefined && relationships.length === options.limit,
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
async findRelationshipById(connection, id, transaction) {
|
|
725
|
+
const neptuneConn = connection;
|
|
726
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
727
|
+
const query = isGremlin
|
|
728
|
+
? `g.E('${id}')`
|
|
729
|
+
: `MATCH ()-[r]->() WHERE id(r) = $id RETURN r`;
|
|
730
|
+
const result = await this.executeRaw(connection, { query, params: { id } }, transaction);
|
|
731
|
+
if (result.data.length === 0) {
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
return this.parseRelationship(isGremlin ? result.data[0] : result.data[0].r);
|
|
735
|
+
}
|
|
736
|
+
async updateRelationship(connection, options, transaction) {
|
|
737
|
+
const startTime = Date.now();
|
|
738
|
+
const neptuneConn = connection;
|
|
739
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
740
|
+
let query;
|
|
741
|
+
const params = {};
|
|
742
|
+
if (isGremlin) {
|
|
743
|
+
query = `g.E('${options.id}')`;
|
|
744
|
+
if (options.set) {
|
|
745
|
+
Object.entries(options.set).forEach(([k, v]) => {
|
|
746
|
+
query += `.property('${k}', ${this.gremlinValue(v)})`;
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
query = `MATCH ()-[r]->() WHERE id(r) = $relId`;
|
|
752
|
+
params.relId = options.id;
|
|
753
|
+
if (options.set && Object.keys(options.set).length > 0) {
|
|
754
|
+
const setParts = Object.entries(options.set).map(([k], i) => {
|
|
755
|
+
params[`set${i}`] = options.set[k];
|
|
756
|
+
return `r.${k} = $set${i}`;
|
|
757
|
+
});
|
|
758
|
+
query += ` SET ${setParts.join(', ')}`;
|
|
759
|
+
}
|
|
760
|
+
query += ' RETURN r';
|
|
761
|
+
}
|
|
762
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
763
|
+
return {
|
|
764
|
+
success: true,
|
|
765
|
+
executionTime: Date.now() - startTime,
|
|
766
|
+
relationship: result.data.length > 0 ? this.parseRelationship(isGremlin ? result.data[0] : result.data[0].r) : undefined,
|
|
767
|
+
updated: result.data.length > 0,
|
|
768
|
+
matchedCount: result.data.length,
|
|
769
|
+
modifiedCount: Object.keys(options.set || {}).length,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
async deleteRelationship(connection, options, transaction) {
|
|
773
|
+
const startTime = Date.now();
|
|
774
|
+
const neptuneConn = connection;
|
|
775
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
776
|
+
let query;
|
|
777
|
+
const params = {};
|
|
778
|
+
if (isGremlin) {
|
|
779
|
+
if (options.id) {
|
|
780
|
+
query = `g.E('${options.id}').drop()`;
|
|
781
|
+
}
|
|
782
|
+
else if (options.type) {
|
|
783
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
784
|
+
query = `g.E().hasLabel('${types.join("', '")}').drop()`;
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Must specify id or type for delete');
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
if (options.id) {
|
|
792
|
+
query = `MATCH ()-[r]->() WHERE id(r) = $relId DELETE r`;
|
|
793
|
+
params.relId = options.id;
|
|
794
|
+
}
|
|
795
|
+
else if (options.type) {
|
|
796
|
+
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
797
|
+
query = `MATCH ()-[r:${types.join('|')}]->() DELETE r`;
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
800
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Must specify id or type for delete');
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
await this.executeRaw(connection, { query, params }, transaction);
|
|
804
|
+
return {
|
|
805
|
+
success: true,
|
|
806
|
+
executionTime: Date.now() - startTime,
|
|
807
|
+
deletedCount: 1,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
async mergeRelationship(connection, options, transaction) {
|
|
811
|
+
const startTime = Date.now();
|
|
812
|
+
const neptuneConn = connection;
|
|
813
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
814
|
+
let query;
|
|
815
|
+
const params = {};
|
|
816
|
+
if (isGremlin) {
|
|
817
|
+
// Gremlin coalesce pattern for edge merge
|
|
818
|
+
const fromId = options.fromNode.id;
|
|
819
|
+
const toId = options.toNode.id;
|
|
820
|
+
const matchProps = options.matchProperties
|
|
821
|
+
? Object.entries(options.matchProperties)
|
|
822
|
+
.map(([k, v]) => `.has('${k}', ${this.gremlinValue(v)})`)
|
|
823
|
+
.join('')
|
|
824
|
+
: '';
|
|
825
|
+
const createProps = Object.entries(Object.assign(Object.assign({}, options.matchProperties), options.onCreate))
|
|
826
|
+
.map(([k, v]) => `.property('${k}', ${this.gremlinValue(v)})`)
|
|
827
|
+
.join('');
|
|
828
|
+
query = `g.V('${fromId}').outE('${options.type}')${matchProps}.where(inV().hasId('${toId}')).fold().coalesce(unfold(), g.V('${fromId}').addE('${options.type}').to(g.V('${toId}'))${createProps})`;
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
const fromMatch = this.buildCypherNodeMatch(options.fromNode, 'from', params, 'from_');
|
|
832
|
+
const toMatch = this.buildCypherNodeMatch(options.toNode, 'to', params, 'to_');
|
|
833
|
+
query = `
|
|
834
|
+
MATCH ${fromMatch}, ${toMatch}
|
|
835
|
+
MERGE (from)-[r:${options.type}]->(to)
|
|
836
|
+
`;
|
|
837
|
+
if (options.onCreate && Object.keys(options.onCreate).length > 0) {
|
|
838
|
+
const createProps = Object.entries(options.onCreate)
|
|
839
|
+
.map(([k], i) => { params[`create${i}`] = options.onCreate[k]; return `r.${k} = $create${i}`; })
|
|
840
|
+
.join(', ');
|
|
841
|
+
query += ` ON CREATE SET ${createProps}`;
|
|
842
|
+
}
|
|
843
|
+
if (options.onMatch && Object.keys(options.onMatch).length > 0) {
|
|
844
|
+
const matchSetProps = Object.entries(options.onMatch)
|
|
845
|
+
.map(([k], i) => { params[`update${i}`] = options.onMatch[k]; return `r.${k} = $update${i}`; })
|
|
846
|
+
.join(', ');
|
|
847
|
+
query += ` ON MATCH SET ${matchSetProps}`;
|
|
848
|
+
}
|
|
849
|
+
query += ' RETURN r';
|
|
850
|
+
}
|
|
851
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
852
|
+
return {
|
|
853
|
+
success: true,
|
|
854
|
+
executionTime: Date.now() - startTime,
|
|
855
|
+
relationship: result.data.length > 0 ? this.parseRelationship(isGremlin ? result.data[0] : result.data[0].r) : undefined,
|
|
856
|
+
created: true,
|
|
857
|
+
matched: false,
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
// ==================== PATH & TRAVERSAL OPERATIONS ====================
|
|
861
|
+
async traverse(connection, options, transaction) {
|
|
862
|
+
const startTime = Date.now();
|
|
863
|
+
const neptuneConn = connection;
|
|
864
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
865
|
+
let query;
|
|
866
|
+
const params = {};
|
|
867
|
+
const minDepth = options.minDepth || 1;
|
|
868
|
+
const maxDepth = options.maxDepth || 10;
|
|
869
|
+
if (isGremlin) {
|
|
870
|
+
const startId = options.startNode.id;
|
|
871
|
+
const direction = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? 'in' :
|
|
872
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? 'out' : 'both';
|
|
873
|
+
query = `g.V('${startId}').repeat(${direction}()).times(${maxDepth}).emit().path()`;
|
|
874
|
+
if (options.limit) {
|
|
875
|
+
query += `.limit(${options.limit})`;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
const startMatch = this.buildCypherNodeMatch(options.startNode, 'start', params);
|
|
880
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
881
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
882
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
883
|
+
query = `
|
|
884
|
+
MATCH ${startMatch}
|
|
885
|
+
MATCH path = (start)${dirStart}[*${minDepth}..${maxDepth}]${dirEnd}(end)
|
|
886
|
+
RETURN path
|
|
887
|
+
`;
|
|
888
|
+
if (options.limit) {
|
|
889
|
+
query += ` LIMIT ${options.limit}`;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
893
|
+
const paths = result.data.map(row => this.parsePath(isGremlin ? row : row.path || row));
|
|
894
|
+
const nodesMap = new Map();
|
|
895
|
+
const relsMap = new Map();
|
|
896
|
+
paths.forEach(p => {
|
|
897
|
+
p.nodes.forEach(n => nodesMap.set(String(n.id), n));
|
|
898
|
+
p.relationships.forEach(r => relsMap.set(String(r.id), r));
|
|
899
|
+
});
|
|
900
|
+
return {
|
|
901
|
+
success: true,
|
|
902
|
+
executionTime: Date.now() - startTime,
|
|
903
|
+
paths: options.returnPaths ? paths : undefined,
|
|
904
|
+
nodes: options.returnNodes ? Array.from(nodesMap.values()) : undefined,
|
|
905
|
+
relationships: Array.from(relsMap.values()),
|
|
906
|
+
count: paths.length,
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
async shortestPath(connection, options, transaction) {
|
|
910
|
+
const startTime = Date.now();
|
|
911
|
+
const neptuneConn = connection;
|
|
912
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
913
|
+
let query;
|
|
914
|
+
const params = {};
|
|
915
|
+
if (isGremlin) {
|
|
916
|
+
const startId = options.startNode.id;
|
|
917
|
+
const endId = options.endNode.id;
|
|
918
|
+
const maxDepth = options.maxDepth || 10;
|
|
919
|
+
query = `g.V('${startId}').repeat(out().simplePath()).until(hasId('${endId}').or().loops().is(${maxDepth})).hasId('${endId}').path().limit(1)`;
|
|
920
|
+
}
|
|
921
|
+
else {
|
|
922
|
+
const startMatch = this.buildCypherNodeMatch(options.startNode, 'start', params);
|
|
923
|
+
const endMatch = this.buildCypherNodeMatch(options.endNode, 'end', params, 'end_');
|
|
924
|
+
const maxDepth = options.maxDepth ? `*..${options.maxDepth}` : '*';
|
|
925
|
+
query = `
|
|
926
|
+
MATCH ${startMatch}, ${endMatch}
|
|
927
|
+
MATCH path = shortestPath((start)-[${maxDepth}]-(end))
|
|
928
|
+
RETURN path
|
|
929
|
+
`;
|
|
930
|
+
}
|
|
931
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
932
|
+
if (result.data.length === 0) {
|
|
933
|
+
return {
|
|
934
|
+
success: true,
|
|
935
|
+
executionTime: Date.now() - startTime,
|
|
936
|
+
found: false,
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
const path = this.parsePath(isGremlin ? result.data[0] : result.data[0].path);
|
|
940
|
+
return {
|
|
941
|
+
success: true,
|
|
942
|
+
executionTime: Date.now() - startTime,
|
|
943
|
+
path,
|
|
944
|
+
found: true,
|
|
945
|
+
length: path.length,
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
async allPaths(connection, options, transaction) {
|
|
949
|
+
const startTime = Date.now();
|
|
950
|
+
const neptuneConn = connection;
|
|
951
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
952
|
+
const minDepth = options.minDepth || 1;
|
|
953
|
+
const maxDepth = options.maxDepth || 10;
|
|
954
|
+
let query;
|
|
955
|
+
const params = {};
|
|
956
|
+
if (isGremlin) {
|
|
957
|
+
const startId = options.startNode.id;
|
|
958
|
+
const endId = options.endNode.id;
|
|
959
|
+
query = `g.V('${startId}').repeat(out().simplePath()).until(hasId('${endId}').or().loops().is(${maxDepth})).hasId('${endId}').path()`;
|
|
960
|
+
if (options.limit) {
|
|
961
|
+
query += `.limit(${options.limit})`;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
const startMatch = this.buildCypherNodeMatch(options.startNode, 'start', params);
|
|
966
|
+
const endMatch = this.buildCypherNodeMatch(options.endNode, 'end', params, 'end_');
|
|
967
|
+
query = `
|
|
968
|
+
MATCH ${startMatch}, ${endMatch}
|
|
969
|
+
MATCH path = (start)-[*${minDepth}..${maxDepth}]-(end)
|
|
970
|
+
RETURN path
|
|
971
|
+
`;
|
|
972
|
+
if (options.limit) {
|
|
973
|
+
query += ` LIMIT ${options.limit}`;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
977
|
+
const paths = result.data.map(row => this.parsePath(isGremlin ? row : row.path || row));
|
|
978
|
+
return {
|
|
979
|
+
success: true,
|
|
980
|
+
executionTime: Date.now() - startTime,
|
|
981
|
+
paths,
|
|
982
|
+
count: paths.length,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
async matchPattern(connection, options, transaction) {
|
|
986
|
+
const startTime = Date.now();
|
|
987
|
+
const neptuneConn = connection;
|
|
988
|
+
if (neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN) {
|
|
989
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Pattern matching is better supported with openCypher. Consider using traverse() for Gremlin.');
|
|
990
|
+
}
|
|
991
|
+
// Build openCypher pattern query
|
|
992
|
+
const params = {};
|
|
993
|
+
const { pattern } = options;
|
|
994
|
+
const matchClauses = [];
|
|
995
|
+
pattern.nodes.forEach(node => {
|
|
996
|
+
const labels = node.labels
|
|
997
|
+
? ':' + (Array.isArray(node.labels) ? node.labels : [node.labels]).join(':')
|
|
998
|
+
: '';
|
|
999
|
+
matchClauses.push(`(${node.variable}${labels})`);
|
|
1000
|
+
});
|
|
1001
|
+
let query = `MATCH ${matchClauses.join(', ')}`;
|
|
1002
|
+
if (pattern.relationships.length > 0) {
|
|
1003
|
+
pattern.relationships.forEach(rel => {
|
|
1004
|
+
const typeStr = rel.type
|
|
1005
|
+
? ':' + (Array.isArray(rel.type) ? rel.type : [rel.type]).join('|')
|
|
1006
|
+
: '';
|
|
1007
|
+
query += `, (${rel.startNode})-[${rel.variable || ''}${typeStr}]->(${rel.endNode})`;
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
const returnVars = options.return || pattern.nodes.map(n => n.variable);
|
|
1011
|
+
query += ` RETURN ${returnVars.join(', ')}`;
|
|
1012
|
+
if (options.limit) {
|
|
1013
|
+
query += ` LIMIT ${options.limit}`;
|
|
1014
|
+
}
|
|
1015
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1016
|
+
return {
|
|
1017
|
+
success: true,
|
|
1018
|
+
executionTime: Date.now() - startTime,
|
|
1019
|
+
matches: result.data,
|
|
1020
|
+
count: result.data.length,
|
|
1021
|
+
hasMore: options.limit !== undefined && result.data.length === options.limit,
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
async extractSubgraph(connection, options, transaction) {
|
|
1025
|
+
const startTime = Date.now();
|
|
1026
|
+
const neptuneConn = connection;
|
|
1027
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
1028
|
+
const startNodes = Array.isArray(options.startNodes) ? options.startNodes : [options.startNodes];
|
|
1029
|
+
const maxDepth = options.maxDepth || 3;
|
|
1030
|
+
let query;
|
|
1031
|
+
const params = {};
|
|
1032
|
+
if (isGremlin) {
|
|
1033
|
+
const startIds = startNodes.map(n => `'${n.id}'`).join(', ');
|
|
1034
|
+
query = `g.V(${startIds}).repeat(both().simplePath()).times(${maxDepth}).emit().dedup().fold().as('nodes').V(${startIds}).repeat(bothE().dedup().by(id).otherV().simplePath()).times(${maxDepth}).emit().dedup().fold().as('edges').select('nodes', 'edges')`;
|
|
1035
|
+
}
|
|
1036
|
+
else {
|
|
1037
|
+
const startMatches = startNodes.map((node, idx) => this.buildCypherNodeMatch(node, `start${idx}`, params, `start${idx}_`));
|
|
1038
|
+
query = `
|
|
1039
|
+
MATCH ${startMatches.join(', ')}
|
|
1040
|
+
WITH [${startNodes.map((_, i) => `start${i}`).join(', ')}] AS starts
|
|
1041
|
+
UNWIND starts AS start
|
|
1042
|
+
MATCH path = (start)-[*0..${maxDepth}]-(n)
|
|
1043
|
+
WITH COLLECT(DISTINCT n) AS nodes, COLLECT(DISTINCT relationships(path)) AS rels
|
|
1044
|
+
UNWIND rels AS relList
|
|
1045
|
+
UNWIND relList AS r
|
|
1046
|
+
RETURN nodes, COLLECT(DISTINCT r) AS relationships
|
|
1047
|
+
`;
|
|
1048
|
+
}
|
|
1049
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1050
|
+
const nodes = [];
|
|
1051
|
+
const relationships = [];
|
|
1052
|
+
if (result.data.length > 0) {
|
|
1053
|
+
const row = result.data[0];
|
|
1054
|
+
if (row.nodes) {
|
|
1055
|
+
row.nodes.forEach((n) => nodes.push(this.parseNode(n)));
|
|
1056
|
+
}
|
|
1057
|
+
if (row.relationships || row.edges) {
|
|
1058
|
+
(row.relationships || row.edges).forEach((r) => relationships.push(this.parseRelationship(r)));
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
success: true,
|
|
1063
|
+
executionTime: Date.now() - startTime,
|
|
1064
|
+
subgraph: {
|
|
1065
|
+
nodes,
|
|
1066
|
+
relationships,
|
|
1067
|
+
nodeCount: nodes.length,
|
|
1068
|
+
relationshipCount: relationships.length,
|
|
1069
|
+
},
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
async getNeighborhood(connection, options, transaction) {
|
|
1073
|
+
const startTime = Date.now();
|
|
1074
|
+
const neptuneConn = connection;
|
|
1075
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
1076
|
+
const depth = options.depth || 1;
|
|
1077
|
+
let query;
|
|
1078
|
+
const params = {};
|
|
1079
|
+
if (isGremlin) {
|
|
1080
|
+
const nodeId = options.node.id;
|
|
1081
|
+
const direction = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? 'in' :
|
|
1082
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? 'out' : 'both';
|
|
1083
|
+
query = `g.V('${nodeId}').repeat(${direction}().simplePath()).times(${depth}).emit()${options.includeCenter ? '' : '.where(neq(V(\'' + nodeId + '\')))'}`;
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
const centerMatch = this.buildCypherNodeMatch(options.node, 'center', params);
|
|
1087
|
+
const dirStart = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '<-' : '-';
|
|
1088
|
+
const dirEnd = options.direction === relationship_types_1.RelationshipDirection.INCOMING ? '-' :
|
|
1089
|
+
options.direction === relationship_types_1.RelationshipDirection.OUTGOING ? '->' : '-';
|
|
1090
|
+
query = `
|
|
1091
|
+
MATCH ${centerMatch}
|
|
1092
|
+
MATCH path = (center)${dirStart}[*0..${depth}]${dirEnd}(n)
|
|
1093
|
+
WITH COLLECT(DISTINCT n) AS nodes, COLLECT(DISTINCT relationships(path)) AS rels
|
|
1094
|
+
UNWIND rels AS relList
|
|
1095
|
+
UNWIND relList AS r
|
|
1096
|
+
RETURN nodes, COLLECT(DISTINCT r) AS relationships
|
|
1097
|
+
`;
|
|
1098
|
+
}
|
|
1099
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1100
|
+
const nodes = [];
|
|
1101
|
+
const relationships = [];
|
|
1102
|
+
if (isGremlin) {
|
|
1103
|
+
result.data.forEach((n) => nodes.push(this.parseNode(n)));
|
|
1104
|
+
}
|
|
1105
|
+
else if (result.data.length > 0) {
|
|
1106
|
+
const row = result.data[0];
|
|
1107
|
+
if (row.nodes) {
|
|
1108
|
+
row.nodes.forEach((n) => nodes.push(this.parseNode(n)));
|
|
1109
|
+
}
|
|
1110
|
+
if (row.relationships) {
|
|
1111
|
+
row.relationships.forEach((r) => relationships.push(this.parseRelationship(r)));
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return {
|
|
1115
|
+
success: true,
|
|
1116
|
+
executionTime: Date.now() - startTime,
|
|
1117
|
+
nodes,
|
|
1118
|
+
relationships,
|
|
1119
|
+
levels: new Map(), // Would need additional queries to populate
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
async findConnectedComponents(connection, options, transaction) {
|
|
1123
|
+
const startTime = Date.now();
|
|
1124
|
+
const neptuneConn = connection;
|
|
1125
|
+
// Neptune doesn't have built-in connected components
|
|
1126
|
+
// This is a simplified implementation
|
|
1127
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Connected components analysis requires Neptune Analytics or manual implementation');
|
|
1128
|
+
}
|
|
1129
|
+
// ==================== AGGREGATION OPERATIONS ====================
|
|
1130
|
+
async countNodes(connection, labels, where, transaction) {
|
|
1131
|
+
var _a;
|
|
1132
|
+
const startTime = Date.now();
|
|
1133
|
+
const neptuneConn = connection;
|
|
1134
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
1135
|
+
let query;
|
|
1136
|
+
const params = {};
|
|
1137
|
+
if (isGremlin) {
|
|
1138
|
+
query = 'g.V()';
|
|
1139
|
+
if (labels) {
|
|
1140
|
+
const labelArr = Array.isArray(labels) ? labels : [labels];
|
|
1141
|
+
query += `.hasLabel('${labelArr.join("', '")}')`;
|
|
1142
|
+
}
|
|
1143
|
+
if (where) {
|
|
1144
|
+
Object.entries(where).forEach(([k, v]) => {
|
|
1145
|
+
query += `.has('${k}', ${this.gremlinValue(v)})`;
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
query += '.count()';
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
const labelStr = labels
|
|
1152
|
+
? ':' + (Array.isArray(labels) ? labels : [labels]).join(':')
|
|
1153
|
+
: '';
|
|
1154
|
+
query = `MATCH (n${labelStr})`;
|
|
1155
|
+
if (where && Object.keys(where).length > 0) {
|
|
1156
|
+
const whereParts = Object.entries(where).map(([k], i) => {
|
|
1157
|
+
params[`w${i}`] = where[k];
|
|
1158
|
+
return `n.${k} = $w${i}`;
|
|
1159
|
+
});
|
|
1160
|
+
query += ` WHERE ${whereParts.join(' AND ')}`;
|
|
1161
|
+
}
|
|
1162
|
+
query += ' RETURN count(n) AS count';
|
|
1163
|
+
}
|
|
1164
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1165
|
+
const count = isGremlin
|
|
1166
|
+
? result.data[0] || 0
|
|
1167
|
+
: ((_a = result.data[0]) === null || _a === void 0 ? void 0 : _a.count) || 0;
|
|
1168
|
+
return {
|
|
1169
|
+
success: true,
|
|
1170
|
+
executionTime: Date.now() - startTime,
|
|
1171
|
+
count: Number(count),
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
async countRelationships(connection, type, where, transaction) {
|
|
1175
|
+
var _a;
|
|
1176
|
+
const startTime = Date.now();
|
|
1177
|
+
const neptuneConn = connection;
|
|
1178
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
1179
|
+
let query;
|
|
1180
|
+
const params = {};
|
|
1181
|
+
if (isGremlin) {
|
|
1182
|
+
query = 'g.E()';
|
|
1183
|
+
if (type) {
|
|
1184
|
+
const typeArr = Array.isArray(type) ? type : [type];
|
|
1185
|
+
query += `.hasLabel('${typeArr.join("', '")}')`;
|
|
1186
|
+
}
|
|
1187
|
+
if (where) {
|
|
1188
|
+
Object.entries(where).forEach(([k, v]) => {
|
|
1189
|
+
query += `.has('${k}', ${this.gremlinValue(v)})`;
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
query += '.count()';
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
const typeStr = type
|
|
1196
|
+
? ':' + (Array.isArray(type) ? type : [type]).join('|')
|
|
1197
|
+
: '';
|
|
1198
|
+
query = `MATCH ()-[r${typeStr}]->() RETURN count(r) AS count`;
|
|
1199
|
+
}
|
|
1200
|
+
const result = await this.executeRaw(connection, { query, params }, transaction);
|
|
1201
|
+
const count = isGremlin
|
|
1202
|
+
? result.data[0] || 0
|
|
1203
|
+
: ((_a = result.data[0]) === null || _a === void 0 ? void 0 : _a.count) || 0;
|
|
1204
|
+
return {
|
|
1205
|
+
success: true,
|
|
1206
|
+
executionTime: Date.now() - startTime,
|
|
1207
|
+
count: Number(count),
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
async getStatistics(connection, transaction) {
|
|
1211
|
+
const startTime = Date.now();
|
|
1212
|
+
const neptuneConn = connection;
|
|
1213
|
+
const isGremlin = neptuneConn.getConfig().queryLanguage === graph_types_1.GraphQueryLanguage.GREMLIN;
|
|
1214
|
+
let nodeCount = 0;
|
|
1215
|
+
let relationshipCount = 0;
|
|
1216
|
+
if (isGremlin) {
|
|
1217
|
+
const nodeResult = await this.executeRaw(connection, { query: 'g.V().count()' }, transaction);
|
|
1218
|
+
nodeCount = nodeResult.data[0] || 0;
|
|
1219
|
+
const relResult = await this.executeRaw(connection, { query: 'g.E().count()' }, transaction);
|
|
1220
|
+
relationshipCount = relResult.data[0] || 0;
|
|
1221
|
+
}
|
|
1222
|
+
else {
|
|
1223
|
+
const result = await this.executeRaw(connection, {
|
|
1224
|
+
query: `
|
|
1225
|
+
MATCH (n)
|
|
1226
|
+
WITH count(n) AS nodeCount
|
|
1227
|
+
MATCH ()-[r]->()
|
|
1228
|
+
RETURN nodeCount, count(r) AS relCount
|
|
1229
|
+
`,
|
|
1230
|
+
}, transaction);
|
|
1231
|
+
if (result.data.length > 0) {
|
|
1232
|
+
nodeCount = result.data[0].nodeCount || 0;
|
|
1233
|
+
relationshipCount = result.data[0].relCount || 0;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return {
|
|
1237
|
+
success: true,
|
|
1238
|
+
executionTime: Date.now() - startTime,
|
|
1239
|
+
nodeCount: Number(nodeCount),
|
|
1240
|
+
relationshipCount: Number(relationshipCount),
|
|
1241
|
+
labelCounts: {},
|
|
1242
|
+
relationshipTypeCounts: {},
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
// ==================== SEARCH OPERATIONS ====================
|
|
1246
|
+
async fullTextSearch(connection, options, transaction) {
|
|
1247
|
+
// Neptune doesn't have built-in full-text search
|
|
1248
|
+
// Would need to use OpenSearch integration
|
|
1249
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Full-text search requires Neptune integration with OpenSearch');
|
|
1250
|
+
}
|
|
1251
|
+
async vectorSearch(connection, options, transaction) {
|
|
1252
|
+
// Neptune Analytics supports vector search
|
|
1253
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Vector search requires Neptune Analytics');
|
|
1254
|
+
}
|
|
1255
|
+
// ==================== SCHEMA OPERATIONS ====================
|
|
1256
|
+
// Note: Neptune has limited schema support compared to Neo4j
|
|
1257
|
+
async createNodeConstraint(connection, constraint, transaction) {
|
|
1258
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Neptune does not support explicit constraints');
|
|
1259
|
+
}
|
|
1260
|
+
async createRelationshipConstraint(connection, constraint, transaction) {
|
|
1261
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Neptune does not support explicit constraints');
|
|
1262
|
+
}
|
|
1263
|
+
async dropConstraint(connection, name, transaction) {
|
|
1264
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Neptune does not support explicit constraints');
|
|
1265
|
+
}
|
|
1266
|
+
async listConstraints(connection, transaction) {
|
|
1267
|
+
return {
|
|
1268
|
+
success: true,
|
|
1269
|
+
executionTime: 0,
|
|
1270
|
+
constraints: [],
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
async createNodeIndex(connection, index, transaction) {
|
|
1274
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Neptune automatically indexes all properties');
|
|
1275
|
+
}
|
|
1276
|
+
async createRelationshipIndex(connection, index, transaction) {
|
|
1277
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Neptune automatically indexes all properties');
|
|
1278
|
+
}
|
|
1279
|
+
async dropIndex(connection, name, transaction) {
|
|
1280
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.VALIDATION_ERROR, 'Neptune does not support dropping indexes');
|
|
1281
|
+
}
|
|
1282
|
+
async listIndexes(connection, transaction) {
|
|
1283
|
+
return {
|
|
1284
|
+
success: true,
|
|
1285
|
+
executionTime: 0,
|
|
1286
|
+
indexes: [],
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
// ==================== UTILITY METHODS ====================
|
|
1290
|
+
escapeIdentifier(identifier) {
|
|
1291
|
+
return identifier.replace(/[^a-zA-Z0-9_]/g, '_');
|
|
1292
|
+
}
|
|
1293
|
+
escapeValue(value) {
|
|
1294
|
+
if (value === null)
|
|
1295
|
+
return 'null';
|
|
1296
|
+
if (typeof value === 'string')
|
|
1297
|
+
return `'${value.replace(/'/g, "\\'")}'`;
|
|
1298
|
+
if (typeof value === 'number')
|
|
1299
|
+
return String(value);
|
|
1300
|
+
if (typeof value === 'boolean')
|
|
1301
|
+
return value ? 'true' : 'false';
|
|
1302
|
+
if (value instanceof Date)
|
|
1303
|
+
return `datetime('${value.toISOString()}')`;
|
|
1304
|
+
if (Array.isArray(value))
|
|
1305
|
+
return `[${value.map(v => this.escapeValue(v)).join(', ')}]`;
|
|
1306
|
+
return String(value);
|
|
1307
|
+
}
|
|
1308
|
+
buildWhereClause(where, variableName = 'n') {
|
|
1309
|
+
const params = {};
|
|
1310
|
+
const parts = [];
|
|
1311
|
+
Object.entries(where).forEach(([key, value], index) => {
|
|
1312
|
+
const paramName = `where_${index}`;
|
|
1313
|
+
parts.push(`${variableName}.${key} = $${paramName}`);
|
|
1314
|
+
params[paramName] = value;
|
|
1315
|
+
});
|
|
1316
|
+
return {
|
|
1317
|
+
clause: parts.join(' AND '),
|
|
1318
|
+
params,
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
// ==================== PROTECTED PARSER METHODS ====================
|
|
1322
|
+
parseNode(nativeNode) {
|
|
1323
|
+
if (!nativeNode) {
|
|
1324
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.NODE_ERROR, 'Cannot parse null node');
|
|
1325
|
+
}
|
|
1326
|
+
// Already parsed
|
|
1327
|
+
if (nativeNode.labels && nativeNode.properties !== undefined) {
|
|
1328
|
+
return nativeNode;
|
|
1329
|
+
}
|
|
1330
|
+
return {
|
|
1331
|
+
id: nativeNode.id || '',
|
|
1332
|
+
labels: nativeNode.labels || [nativeNode.label] || [],
|
|
1333
|
+
properties: (nativeNode.properties || nativeNode),
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
parseRelationship(nativeRelationship) {
|
|
1337
|
+
if (!nativeRelationship) {
|
|
1338
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.RELATIONSHIP_ERROR, 'Cannot parse null relationship');
|
|
1339
|
+
}
|
|
1340
|
+
// Already parsed
|
|
1341
|
+
if (nativeRelationship.type && nativeRelationship.startNodeId !== undefined) {
|
|
1342
|
+
return nativeRelationship;
|
|
1343
|
+
}
|
|
1344
|
+
return {
|
|
1345
|
+
id: nativeRelationship.id || '',
|
|
1346
|
+
type: nativeRelationship.type || nativeRelationship.label || '',
|
|
1347
|
+
startNodeId: nativeRelationship.startNodeId || nativeRelationship.outV || '',
|
|
1348
|
+
endNodeId: nativeRelationship.endNodeId || nativeRelationship.inV || '',
|
|
1349
|
+
properties: (nativeRelationship.properties || nativeRelationship),
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
parsePath(nativePath) {
|
|
1353
|
+
if (!nativePath) {
|
|
1354
|
+
throw new graph_types_1.GraphError(graph_types_1.GraphErrorType.PATH_ERROR, 'Cannot parse null path');
|
|
1355
|
+
}
|
|
1356
|
+
// Already parsed
|
|
1357
|
+
if (nativePath.nodes && nativePath.relationships !== undefined) {
|
|
1358
|
+
return nativePath;
|
|
1359
|
+
}
|
|
1360
|
+
const nodes = [];
|
|
1361
|
+
const relationships = [];
|
|
1362
|
+
if (nativePath.objects) {
|
|
1363
|
+
// Gremlin path
|
|
1364
|
+
nativePath.objects.forEach((obj) => {
|
|
1365
|
+
if (obj.labels || obj.label) {
|
|
1366
|
+
nodes.push(this.parseNode(obj));
|
|
1367
|
+
}
|
|
1368
|
+
else if (obj.type || obj.outV) {
|
|
1369
|
+
relationships.push(this.parseRelationship(obj));
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
else if (nativePath.nodes && nativePath.relationships) {
|
|
1374
|
+
// Already structured
|
|
1375
|
+
nativePath.nodes.forEach((n) => nodes.push(this.parseNode(n)));
|
|
1376
|
+
nativePath.relationships.forEach((r) => relationships.push(this.parseRelationship(r)));
|
|
1377
|
+
}
|
|
1378
|
+
return {
|
|
1379
|
+
nodes,
|
|
1380
|
+
relationships,
|
|
1381
|
+
length: relationships.length,
|
|
1382
|
+
start: nodes[0],
|
|
1383
|
+
end: nodes[nodes.length - 1],
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
// ==================== PRIVATE HELPER METHODS ====================
|
|
1387
|
+
normalizeLabels(labels) {
|
|
1388
|
+
return Array.isArray(labels) ? labels : [labels];
|
|
1389
|
+
}
|
|
1390
|
+
gremlinValue(value) {
|
|
1391
|
+
if (value === null)
|
|
1392
|
+
return 'null';
|
|
1393
|
+
if (typeof value === 'string')
|
|
1394
|
+
return `'${value.replace(/'/g, "\\'")}'`;
|
|
1395
|
+
if (typeof value === 'number')
|
|
1396
|
+
return String(value);
|
|
1397
|
+
if (typeof value === 'boolean')
|
|
1398
|
+
return value.toString();
|
|
1399
|
+
if (value instanceof Date)
|
|
1400
|
+
return `datetime('${value.toISOString()}')`;
|
|
1401
|
+
if (Array.isArray(value))
|
|
1402
|
+
return `[${value.map(v => this.gremlinValue(v)).join(', ')}]`;
|
|
1403
|
+
return String(value);
|
|
1404
|
+
}
|
|
1405
|
+
buildCypherNodeMatch(ref, alias, params, prefix = '') {
|
|
1406
|
+
let pattern = `(${alias}`;
|
|
1407
|
+
if (ref.labels) {
|
|
1408
|
+
const labels = this.normalizeLabels(ref.labels);
|
|
1409
|
+
pattern += ':' + labels.join(':');
|
|
1410
|
+
}
|
|
1411
|
+
if (ref.id !== undefined) {
|
|
1412
|
+
const paramName = `${prefix}id`;
|
|
1413
|
+
params[paramName] = ref.id;
|
|
1414
|
+
pattern += ` {id: $${paramName}}`;
|
|
1415
|
+
}
|
|
1416
|
+
else if (ref.properties && Object.keys(ref.properties).length > 0) {
|
|
1417
|
+
const propParts = Object.entries(ref.properties).map(([k], i) => {
|
|
1418
|
+
const paramName = `${prefix}prop${i}`;
|
|
1419
|
+
params[paramName] = ref.properties[k];
|
|
1420
|
+
return `${k}: $${paramName}`;
|
|
1421
|
+
});
|
|
1422
|
+
pattern += ` {${propParts.join(', ')}}`;
|
|
1423
|
+
}
|
|
1424
|
+
pattern += ')';
|
|
1425
|
+
return pattern;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
exports.NeptuneAdapter = NeptuneAdapter;
|
|
1429
|
+
exports.default = NeptuneAdapter;
|
|
1430
|
+
//# sourceMappingURL=neptune.adapter.js.map
|