ts-prorm-orm 1.1.0

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.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,470 @@
1
+ "use strict";
2
+ /**
3
+ * Amazon Neptune store.
4
+ *
5
+ * Neptune is a managed graph database: data is modeled as vertices and
6
+ * edges (plus their properties), queried by graph traversal, not by
7
+ * arbitrary `WHERE`-clause SQL. It has no joins, no relational schema, and
8
+ * no `query(sql)` shape, so — like the other stores in `src/nosql/` — this
9
+ * class does not implement the SQL-shaped `Dialect` interface
10
+ * (`src/dialects/dialect.ts`). Instead it implements the minimal
11
+ * `NoSqlStore` marker interface (`src/nosql/store.ts`) and exposes
12
+ * Neptune's own query model directly: Gremlin traversals.
13
+ *
14
+ * Neptune supports two graph query languages: Gremlin and openCypher.
15
+ * This store uses **Gremlin**, via the official `gremlin` npm package
16
+ * (Apache TinkerPop's JavaScript Gremlin Language Variant), because it is
17
+ * the more universally-supported path for Neptune from Node.js — the
18
+ * `gremlin` package speaks Neptune's Gremlin websocket protocol directly
19
+ * (`DriverRemoteConnection` for the fluent, bytecode-based traversal API;
20
+ * `Client` for raw Gremlin script submission).
21
+ *
22
+ * ## IAM authentication — read this before using in production
23
+ *
24
+ * Neptune clusters can require AWS IAM (SigV4) request signing on every
25
+ * Gremlin connection. **This store does NOT implement SigV4 signing.**
26
+ * Correctly signing a websocket handshake (canonical request, credential
27
+ * scope, signing key derivation, clock-skew-sensitive timestamps, and
28
+ * keeping all of that valid for the life of a persistent connection) is
29
+ * substantial, security-sensitive logic that is easy to get subtly wrong,
30
+ * and shipping a partial/approximate implementation would be worse than
31
+ * not shipping one — silent auth failures or, worse, requests that
32
+ * "happen to work" against a lenient test setup but fail against real
33
+ * Neptune are not an acceptable trade-off here.
34
+ *
35
+ * Instead, `NeptuneStoreOptions` supports two supported ways to connect:
36
+ *
37
+ * 1. **No auth** — Neptune clusters are frequently run inside a VPC with
38
+ * IAM database authentication *disabled*, relying on VPC/security-group
39
+ * isolation instead. Just supply `endpoint`/`url` and nothing else.
40
+ * 2. **Caller-supplied signed headers** — if the target cluster has IAM
41
+ * auth enabled, sign the request yourself (e.g. with
42
+ * `@aws-sdk/signature-v4` / `aws4`, or your own SigV4 helper) and pass
43
+ * the resulting headers via `options.headers` (static) or
44
+ * `options.authHeaderProvider` (called on every `connect()`, so it can
45
+ * mint a fresh signature — SigV4 signatures are timestamp-bound and a
46
+ * static one will eventually be rejected). This store passes those
47
+ * headers straight through to `DriverRemoteConnection`/`Client` via
48
+ * their `options.headers` field; it performs no signing of its own.
49
+ *
50
+ * See the README in this directory for a worked example of option 2.
51
+ */
52
+ var __importDefault = (this && this.__importDefault) || function (mod) {
53
+ return (mod && mod.__esModule) ? mod : { "default": mod };
54
+ };
55
+ Object.defineProperty(exports, "__esModule", { value: true });
56
+ exports.NeptuneStore = exports.NeptuneError = void 0;
57
+ // The `gremlin` package ships no TypeScript declarations, so this import
58
+ // is implicitly `any` (the repo's tsconfig has `noImplicitAny: false`,
59
+ // which is exactly the escape hatch intended for cases like this). All
60
+ // gremlin types used below (`GraphTraversalSource`, `Traversal`, ...) are
61
+ // therefore documented in comments rather than enforced by the compiler.
62
+ const gremlin_1 = __importDefault(require("gremlin"));
63
+ const errors_1 = require("../../errors");
64
+ /** `DatabaseError` subclass used for all Neptune/Gremlin failures wrapped by this store. */
65
+ class NeptuneError extends errors_1.DatabaseError {
66
+ constructor(message, options = {}) {
67
+ super(message, options);
68
+ this.name = 'NeptuneError';
69
+ }
70
+ }
71
+ exports.NeptuneError = NeptuneError;
72
+ /** Recursively converts Gremlin's `Map`/`Array` result shapes (from `valueMap()`/`elementMap()`) into plain JS objects/arrays. */
73
+ function normalizeValue(value) {
74
+ if (value instanceof Map) {
75
+ const obj = {};
76
+ for (const [key, val] of value.entries()) {
77
+ obj[String(key)] = normalizeValue(val);
78
+ }
79
+ return obj;
80
+ }
81
+ if (Array.isArray(value)) {
82
+ return value.map(normalizeValue);
83
+ }
84
+ return value;
85
+ }
86
+ /** Splits a normalized `elementMap()` result into a `NeptuneVertex`. */
87
+ function toVertex(normalized) {
88
+ const { id, label, ...properties } = normalized;
89
+ return { id: id, label: String(label), properties };
90
+ }
91
+ /** Splits a normalized `elementMap()` result into a `NeptuneEdge`. `IN`/`OUT` are the endpoint vertex IDs Gremlin's edge `elementMap()` reports them under. */
92
+ function toEdge(normalized) {
93
+ const { id, label, IN, OUT, ...properties } = normalized;
94
+ return {
95
+ id: id,
96
+ label: String(label),
97
+ outV: OUT,
98
+ inV: IN,
99
+ properties,
100
+ };
101
+ }
102
+ function wrapConnectionError(err, endpoint) {
103
+ const parent = err instanceof Error ? err : new Error(String(err));
104
+ return new errors_1.ConnectionError(`Unable to connect to Neptune: ${parent.message}`, {
105
+ parent,
106
+ database: 'neptune',
107
+ host: endpoint,
108
+ });
109
+ }
110
+ function wrapNeptuneError(err, action) {
111
+ const parent = err instanceof Error ? err : new Error(String(err));
112
+ return new NeptuneError(`Neptune ${action} failed: ${parent.message}`, {
113
+ parent,
114
+ original: parent.message,
115
+ });
116
+ }
117
+ /**
118
+ * `NeptuneStore` wraps the `gremlin` package's `DriverRemoteConnection`
119
+ * (fluent, bytecode-based traversals via a `GraphTraversalSource`, i.e.
120
+ * `g`) and `Client` (raw Gremlin script submission) to talk to Amazon
121
+ * Neptune, implementing the minimal `NoSqlStore` marker interface. Vertex/
122
+ * edge CRUD helpers below are convenience wrappers built on top of real
123
+ * Gremlin steps (`addV`/`addE`/`has`/`hasLabel`/`drop`/...) — for anything
124
+ * they don't cover, use `getClient()` (the raw `GraphTraversalSource`),
125
+ * `traversal()` (build an arbitrary traversal against `g`), or `submit()`
126
+ * (raw parameterized Gremlin script text).
127
+ */
128
+ class NeptuneStore {
129
+ constructor(options = {}) {
130
+ this.name = 'neptune';
131
+ this.library = 'gremlin';
132
+ this.connection = null;
133
+ this.g = null;
134
+ this.client = null;
135
+ this.connected = false;
136
+ this.options = options;
137
+ }
138
+ // ---------------------------------------------------------------------
139
+ // Connection lifecycle
140
+ // ---------------------------------------------------------------------
141
+ resolveUrl() {
142
+ if (this.options.url) {
143
+ return this.options.url;
144
+ }
145
+ if (!this.options.endpoint) {
146
+ throw new errors_1.ConnectionError('NeptuneStore requires either `url` or `endpoint` to connect', {
147
+ database: 'neptune',
148
+ });
149
+ }
150
+ const scheme = this.options.useSsl === false ? 'ws' : 'wss';
151
+ const port = this.options.port ?? 8182;
152
+ return `${scheme}://${this.options.endpoint}:${port}/gremlin`;
153
+ }
154
+ async resolveHeaders() {
155
+ const provided = this.options.authHeaderProvider ? await this.options.authHeaderProvider() : undefined;
156
+ const merged = { ...this.options.headers, ...provided };
157
+ return Object.keys(merged).length > 0 ? merged : undefined;
158
+ }
159
+ async connect() {
160
+ const url = this.resolveUrl();
161
+ try {
162
+ const headers = await this.resolveHeaders();
163
+ const connectionOptions = {
164
+ traversalSource: this.options.traversalSource ?? 'g',
165
+ rejectUnauthorized: this.options.rejectUnauthorized,
166
+ headers,
167
+ ...this.options.connectionOptions,
168
+ };
169
+ this.connection = new gremlin_1.default.driver.DriverRemoteConnection(url, connectionOptions);
170
+ await this.connection.open();
171
+ this.g = gremlin_1.default.process.AnonymousTraversalSource.traversal().with_(this.connection);
172
+ this.client = new gremlin_1.default.driver.Client(url, connectionOptions);
173
+ await this.client.open();
174
+ this.connected = true;
175
+ }
176
+ catch (err) {
177
+ await this.safeCloseAll();
178
+ this.connected = false;
179
+ throw wrapConnectionError(err, this.options.endpoint ?? url);
180
+ }
181
+ }
182
+ async safeCloseAll() {
183
+ try {
184
+ await this.client?.close();
185
+ }
186
+ catch {
187
+ // ignore - we're already tearing down after a failure
188
+ }
189
+ try {
190
+ await this.connection?.close();
191
+ }
192
+ catch {
193
+ // ignore - we're already tearing down after a failure
194
+ }
195
+ this.client = null;
196
+ this.connection = null;
197
+ this.g = null;
198
+ }
199
+ async disconnect() {
200
+ await this.safeCloseAll();
201
+ this.connected = false;
202
+ }
203
+ isConnected() {
204
+ return this.connected && this.connection !== null && this.connection.isOpen === true;
205
+ }
206
+ /** Returns the underlying `GraphTraversalSource` (`g`) for building traversals not wrapped below. */
207
+ getClient() {
208
+ return this.requireG();
209
+ }
210
+ /** Access to the raw `DriverRemoteConnection`, e.g. to inspect `isOpen` directly. */
211
+ getConnection() {
212
+ if (!this.connection) {
213
+ throw new errors_1.ConnectionError('Neptune client is not connected. Call connect() first.', {
214
+ database: 'neptune',
215
+ });
216
+ }
217
+ return this.connection;
218
+ }
219
+ requireG() {
220
+ if (!this.g || !this.connected) {
221
+ throw new errors_1.ConnectionError('Neptune client is not connected. Call connect() first.', {
222
+ database: 'neptune',
223
+ });
224
+ }
225
+ return this.g;
226
+ }
227
+ requireClient() {
228
+ if (!this.client || !this.connected) {
229
+ throw new errors_1.ConnectionError('Neptune client is not connected. Call connect() first.', {
230
+ database: 'neptune',
231
+ });
232
+ }
233
+ return this.client;
234
+ }
235
+ // ---------------------------------------------------------------------
236
+ // Raw Gremlin
237
+ // ---------------------------------------------------------------------
238
+ /**
239
+ * Runs an arbitrary traversal built against `g` and Gremlin's anonymous
240
+ * traversal statics (`gremlin.process.statics`, e.g. `statics.V(id)` for
241
+ * nested traversals like `.to(statics.V(id))`), returning the fully
242
+ * materialized, normalized result list. This is the escape hatch for any
243
+ * Gremlin step this store doesn't wrap in a dedicated helper.
244
+ *
245
+ * @example
246
+ * const names = await store.traversal((g) => g.V().hasLabel('person').values('name'));
247
+ */
248
+ async traversal(build) {
249
+ const g = this.requireG();
250
+ try {
251
+ const t = build(g, gremlin_1.default.process.statics);
252
+ const list = await t.toList();
253
+ return list.map(normalizeValue);
254
+ }
255
+ catch (err) {
256
+ throw wrapNeptuneError(err, 'traversal');
257
+ }
258
+ }
259
+ /**
260
+ * Submits a raw Gremlin script string via the driver's script-eval
261
+ * `Client` (as opposed to the fluent bytecode traversal `g` used
262
+ * elsewhere in this class), with `bindings` substituted server-side for
263
+ * named parameters in the script (e.g. `'g.V(id)'` with
264
+ * `{ id: '1' }`) — the standard way to parameterize Gremlin script text
265
+ * without string-concatenating untrusted values into it.
266
+ */
267
+ async submit(script, bindings = {}) {
268
+ const client = this.requireClient();
269
+ try {
270
+ const resultSet = await client.submit(script, bindings);
271
+ const list = typeof resultSet.toArray === 'function' ? resultSet.toArray() : resultSet;
272
+ return list.map(normalizeValue);
273
+ }
274
+ catch (err) {
275
+ throw wrapNeptuneError(err, `script submit ('${script}')`);
276
+ }
277
+ }
278
+ // ---------------------------------------------------------------------
279
+ // Vertex CRUD
280
+ // ---------------------------------------------------------------------
281
+ /** `addV(label)` + a `property(key, value)` step per entry in `properties`, returning the created vertex via `elementMap()`. */
282
+ async addVertex(label, properties = {}) {
283
+ const g = this.requireG();
284
+ try {
285
+ let t = g.addV(label);
286
+ for (const [key, value] of Object.entries(properties)) {
287
+ t = t.property(key, value);
288
+ }
289
+ const { value } = await t.elementMap().next();
290
+ return toVertex(normalizeValue(value));
291
+ }
292
+ catch (err) {
293
+ throw wrapNeptuneError(err, `addVertex('${label}')`);
294
+ }
295
+ }
296
+ /** `g.V(id).elementMap().next()` — returns `undefined` if no vertex with that ID exists. */
297
+ async getVertex(id) {
298
+ const g = this.requireG();
299
+ try {
300
+ const { value, done } = await g.V(id).elementMap().next();
301
+ if (done || value === undefined || value === null) {
302
+ return undefined;
303
+ }
304
+ return toVertex(normalizeValue(value));
305
+ }
306
+ catch (err) {
307
+ throw wrapNeptuneError(err, `getVertex('${String(id)}')`);
308
+ }
309
+ }
310
+ /** `g.V()` filtered by `options.label`/`options.has`/`options.limit`, projected with `elementMap()`. */
311
+ async findVertices(options = {}) {
312
+ const g = this.requireG();
313
+ try {
314
+ let t = g.V();
315
+ t = this.applyElementFilters(t, options);
316
+ const list = await t.elementMap().toList();
317
+ return list.map((v) => toVertex(normalizeValue(v)));
318
+ }
319
+ catch (err) {
320
+ throw wrapNeptuneError(err, 'findVertices');
321
+ }
322
+ }
323
+ /** Same filters as `findVertices()`, terminated with `count()` instead of materializing elements. */
324
+ async countVertices(options = {}) {
325
+ const g = this.requireG();
326
+ try {
327
+ let t = g.V();
328
+ t = this.applyElementFilters(t, options);
329
+ const { value } = await t.count().next();
330
+ return Number(value);
331
+ }
332
+ catch (err) {
333
+ throw wrapNeptuneError(err, 'countVertices');
334
+ }
335
+ }
336
+ /** `g.V(id)` + a `property(key, value)` step per entry in `properties` (existing properties keep their value unless overwritten here), returning the updated vertex. */
337
+ async updateVertex(id, properties) {
338
+ const g = this.requireG();
339
+ try {
340
+ let t = g.V(id);
341
+ for (const [key, value] of Object.entries(properties)) {
342
+ t = t.property(key, value);
343
+ }
344
+ const { value, done } = await t.elementMap().next();
345
+ if (done || value === undefined || value === null) {
346
+ return undefined;
347
+ }
348
+ return toVertex(normalizeValue(value));
349
+ }
350
+ catch (err) {
351
+ throw wrapNeptuneError(err, `updateVertex('${String(id)}')`);
352
+ }
353
+ }
354
+ /** `g.V(id).drop().iterate()` — also drops any incident edges (Neptune cascades edge drops when their vertex is dropped). No-op (does not throw) if the vertex doesn't exist. */
355
+ async dropVertex(id) {
356
+ const g = this.requireG();
357
+ try {
358
+ await g.V(id).drop().iterate();
359
+ }
360
+ catch (err) {
361
+ throw wrapNeptuneError(err, `dropVertex('${String(id)}')`);
362
+ }
363
+ }
364
+ // ---------------------------------------------------------------------
365
+ // Edge CRUD
366
+ // ---------------------------------------------------------------------
367
+ /**
368
+ * `g.V(fromId).addE(label).to(statics.V(toId))` + a `property(key, value)`
369
+ * step per entry in `properties`, returning the created edge via
370
+ * `elementMap()`. Throws a `NeptuneError` if `fromId`/`toId` don't
371
+ * resolve to existing vertices (same as real Gremlin `addE`/`to`).
372
+ */
373
+ async addEdge(fromId, label, toId, properties = {}) {
374
+ const g = this.requireG();
375
+ try {
376
+ let t = g.V(fromId).addE(label).to(gremlin_1.default.process.statics.V(toId));
377
+ for (const [key, value] of Object.entries(properties)) {
378
+ t = t.property(key, value);
379
+ }
380
+ const { value } = await t.elementMap().next();
381
+ return toEdge(normalizeValue(value));
382
+ }
383
+ catch (err) {
384
+ throw wrapNeptuneError(err, `addEdge('${label}')`);
385
+ }
386
+ }
387
+ /** `g.E(id).elementMap().next()` — returns `undefined` if no edge with that ID exists. */
388
+ async getEdge(id) {
389
+ const g = this.requireG();
390
+ try {
391
+ const { value, done } = await g.E(id).elementMap().next();
392
+ if (done || value === undefined || value === null) {
393
+ return undefined;
394
+ }
395
+ return toEdge(normalizeValue(value));
396
+ }
397
+ catch (err) {
398
+ throw wrapNeptuneError(err, `getEdge('${String(id)}')`);
399
+ }
400
+ }
401
+ /** `g.E()` filtered by `options.label`/`options.has`/`options.limit`, projected with `elementMap()`. */
402
+ async findEdges(options = {}) {
403
+ const g = this.requireG();
404
+ try {
405
+ let t = g.E();
406
+ t = this.applyElementFilters(t, options);
407
+ const list = await t.elementMap().toList();
408
+ return list.map((v) => toEdge(normalizeValue(v)));
409
+ }
410
+ catch (err) {
411
+ throw wrapNeptuneError(err, 'findEdges');
412
+ }
413
+ }
414
+ /** `g.E(id).drop().iterate()`. No-op (does not throw) if the edge doesn't exist. */
415
+ async dropEdge(id) {
416
+ const g = this.requireG();
417
+ try {
418
+ await g.E(id).drop().iterate();
419
+ }
420
+ catch (err) {
421
+ throw wrapNeptuneError(err, `dropEdge('${String(id)}')`);
422
+ }
423
+ }
424
+ // ---------------------------------------------------------------------
425
+ // Traversal convenience
426
+ // ---------------------------------------------------------------------
427
+ /**
428
+ * `g.V(id).out(edgeLabel)` (or `.in_()`/`.both()` per `options.direction`,
429
+ * default `'out'`), projected with `elementMap()`. The common
430
+ * "one-hop neighbors" query — for multi-hop traversals, path-finding, or
431
+ * anything else Gremlin's step library covers beyond one hop, use
432
+ * `traversal()` directly.
433
+ */
434
+ async neighbors(id, options = {}) {
435
+ const g = this.requireG();
436
+ const direction = options.direction ?? 'out';
437
+ try {
438
+ let t = g.V(id);
439
+ const step = direction === 'in' ? 'in_' : direction === 'both' ? 'both' : 'out';
440
+ t = options.edgeLabel ? t[step](options.edgeLabel) : t[step]();
441
+ if (options.limit !== undefined) {
442
+ t = t.limit(options.limit);
443
+ }
444
+ const list = await t.elementMap().toList();
445
+ return list.map((v) => toVertex(normalizeValue(v)));
446
+ }
447
+ catch (err) {
448
+ throw wrapNeptuneError(err, `neighbors('${String(id)}')`);
449
+ }
450
+ }
451
+ // ---------------------------------------------------------------------
452
+ // Internal helpers
453
+ // ---------------------------------------------------------------------
454
+ applyElementFilters(t, options) {
455
+ if (options.label) {
456
+ t = t.hasLabel(options.label);
457
+ }
458
+ if (options.has) {
459
+ for (const [key, value] of Object.entries(options.has)) {
460
+ t = t.has(key, value);
461
+ }
462
+ }
463
+ if (options.limit !== undefined) {
464
+ t = t.limit(options.limit);
465
+ }
466
+ return t;
467
+ }
468
+ }
469
+ exports.NeptuneStore = NeptuneStore;
470
+ exports.default = NeptuneStore;
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ /**
3
+ * NSQ topic/channel queue store.
4
+ *
5
+ * NSQ is a realtime distributed messaging platform. Producers `publish`
6
+ * messages to a *topic* via a `Writer`; consumers create a `Reader` bound to
7
+ * a topic + *channel* and handle each delivered message (calling
8
+ * `msg.finish()`/`msg.requeue()`). NSQ distributes a topic's messages across
9
+ * all channels, and load-balances within a channel. It is not a database and
10
+ * does not fit the SQL-shaped `Dialect` interface, so this class implements
11
+ * the minimal `NoSqlStore` marker interface and exposes NSQ's real
12
+ * publish/subscribe operations instead.
13
+ *
14
+ * Uses the `nsqjs` driver. It is an optional peer loaded lazily (via
15
+ * `require`) inside `connect()`, so importing this module does not require it
16
+ * to be installed unless you actually connect. A pre-built driver module
17
+ * (providing `Writer` and `Reader` constructors) can be injected via
18
+ * `NsqStoreOptions.client`, in which case `connect()` adopts it and skips the
19
+ * `require` entirely (used by the unit tests to inject mocks).
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.NsqStore = void 0;
23
+ const errors_1 = require("../../errors");
24
+ function wrapConnectionError(err) {
25
+ const parent = err instanceof Error ? err : new Error(String(err));
26
+ const message = /econnrefused/i.test(parent.message)
27
+ ? 'Connection refused'
28
+ : `Unable to connect to NSQ: ${parent.message}`;
29
+ return new errors_1.ConnectionError(message, { parent, database: 'nsq' });
30
+ }
31
+ function wrapDatabaseError(err, action) {
32
+ const parent = err instanceof Error ? err : new Error(String(err));
33
+ return errors_1.DatabaseError.from(parent, { message: `NSQ ${action} failed: ${parent.message}` });
34
+ }
35
+ /**
36
+ * `NsqStore` wraps a single producer `Writer` plus a pool of consumer
37
+ * `Reader`s (keyed by `topic/channel`) and exposes the common queue surface.
38
+ * NSQ has no server-side job registry, so `getJob()`/`remove()` (which imply
39
+ * addressing a job by id) are not supported and throw.
40
+ */
41
+ class NsqStore {
42
+ constructor(options = {}) {
43
+ this.name = 'nsq';
44
+ this.library = 'nsqjs';
45
+ this.driver = null;
46
+ this.writer = null;
47
+ this.connected = false;
48
+ this.readers = new Map();
49
+ this.options = options;
50
+ }
51
+ // ---------------------------------------------------------------------
52
+ // Connection lifecycle
53
+ // ---------------------------------------------------------------------
54
+ async connect() {
55
+ if (this.connected && this.writer) {
56
+ return;
57
+ }
58
+ try {
59
+ this.driver = this.options.client != null ? this.options.client : require('nsqjs');
60
+ const host = this.options.nsqdHost || '127.0.0.1';
61
+ const port = this.options.nsqdPort || 4150;
62
+ this.writer = new this.driver.Writer(host, port);
63
+ // A real nsqjs Writer connects asynchronously and emits 'ready'; a mock
64
+ // Writer may expose neither, so only wait when both are present.
65
+ if (typeof this.writer.connect === 'function' &&
66
+ typeof this.writer.on === 'function') {
67
+ await new Promise((resolve, reject) => {
68
+ this.writer.on('ready', () => resolve());
69
+ this.writer.on('error', (err) => reject(err));
70
+ this.writer.connect();
71
+ });
72
+ }
73
+ this.connected = true;
74
+ }
75
+ catch (err) {
76
+ this.writer = null;
77
+ this.driver = null;
78
+ this.connected = false;
79
+ throw wrapConnectionError(err);
80
+ }
81
+ }
82
+ async disconnect() {
83
+ for (const reader of this.readers.values()) {
84
+ try {
85
+ if (reader && typeof reader.close === 'function')
86
+ reader.close();
87
+ }
88
+ catch {
89
+ // Ignore teardown errors.
90
+ }
91
+ }
92
+ this.readers.clear();
93
+ try {
94
+ if (this.writer && typeof this.writer.close === 'function')
95
+ this.writer.close();
96
+ }
97
+ catch {
98
+ // Ignore teardown errors.
99
+ }
100
+ this.writer = null;
101
+ this.driver = null;
102
+ this.connected = false;
103
+ }
104
+ isConnected() {
105
+ return this.connected && this.writer !== null;
106
+ }
107
+ /** Returns the underlying producer `Writer` for operations not wrapped here. */
108
+ getClient() {
109
+ return this.requireWriter();
110
+ }
111
+ requireWriter() {
112
+ if (!this.writer) {
113
+ throw new errors_1.ConnectionError('Not connected to NSQ', { database: 'nsq' });
114
+ }
115
+ return this.writer;
116
+ }
117
+ // ---------------------------------------------------------------------
118
+ // Queue operations
119
+ // ---------------------------------------------------------------------
120
+ /**
121
+ * Publish a message to a topic via the producer `Writer`. The payload is
122
+ * JSON-serialized (strings/Buffers pass through). NSQ does not return a
123
+ * client-visible job id, so this resolves to `null`.
124
+ */
125
+ async enqueue(queue, jobData) {
126
+ const writer = this.requireWriter();
127
+ const message = typeof jobData === 'string' || Buffer.isBuffer(jobData) ? jobData : JSON.stringify(jobData);
128
+ return new Promise((resolve, reject) => {
129
+ try {
130
+ writer.publish(queue, message, (err) => {
131
+ if (err)
132
+ reject(wrapDatabaseError(err, 'enqueue'));
133
+ else
134
+ resolve(null);
135
+ });
136
+ }
137
+ catch (err) {
138
+ reject(wrapDatabaseError(err, 'enqueue'));
139
+ }
140
+ });
141
+ }
142
+ /**
143
+ * Subscribe a `Reader` to `queue` (topic) on a channel and invoke
144
+ * `handler(msg)` for each delivered message. One reader is cached per
145
+ * `topic/channel`; a repeat `process()` on the same pair returns it.
146
+ */
147
+ async process(queue, handler, opts = {}) {
148
+ try {
149
+ const { channel = 'default', ...readerOpts } = opts;
150
+ const key = `${queue}/${channel}`;
151
+ const existing = this.readers.get(key);
152
+ if (existing)
153
+ return existing;
154
+ const driver = this.driver;
155
+ if (!driver) {
156
+ throw new errors_1.ConnectionError('Not connected to NSQ', { database: 'nsq' });
157
+ }
158
+ const reader = new driver.Reader(queue, channel, {
159
+ ...(this.options.readerOptions || {}),
160
+ ...readerOpts,
161
+ });
162
+ reader.on('message', (msg) => handler(msg));
163
+ reader.connect();
164
+ this.readers.set(key, reader);
165
+ return reader;
166
+ }
167
+ catch (err) {
168
+ if (err instanceof errors_1.ConnectionError)
169
+ throw err;
170
+ throw wrapDatabaseError(err, 'process');
171
+ }
172
+ }
173
+ /** Not supported: NSQ exposes no server-side lookup of a message by id. */
174
+ async getJob(_queue, _id) {
175
+ throw new errors_1.DatabaseError('NSQ does not support getJob (no addressable job ids)', {
176
+ code: undefined,
177
+ });
178
+ }
179
+ /** Not supported: NSQ messages are acknowledged via `finish()`, not removed by id. */
180
+ async remove(_queue, _id) {
181
+ throw new errors_1.DatabaseError('NSQ does not support remove (use msg.finish() in the handler)', {
182
+ code: undefined,
183
+ });
184
+ }
185
+ /**
186
+ * Return a lightweight local view of consumers for a topic: the number of
187
+ * active `Reader`s this store has bound to it. (NSQ's authoritative stats
188
+ * live in nsqd's HTTP `/stats` endpoint, not the client library.)
189
+ */
190
+ async stats(queue) {
191
+ let count = 0;
192
+ for (const key of this.readers.keys()) {
193
+ if (key.startsWith(`${queue}/`))
194
+ count++;
195
+ }
196
+ return { topic: queue, readers: count };
197
+ }
198
+ }
199
+ exports.NsqStore = NsqStore;
200
+ exports.default = NsqStore;