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,364 @@
1
+ "use strict";
2
+ /**
3
+ * ArangoDB store implementation.
4
+ *
5
+ * ArangoDB is a multi-model database: it stores JSON documents (like a
6
+ * document store), lets those documents form named graphs (vertices/edges),
7
+ * and queries both shapes through a single query language, AQL. None of
8
+ * that fits the SQL-shaped `Dialect` interface (no `JOIN`, no relational
9
+ * schema, no `query(sql)` returning rows in the SQL sense), so this class
10
+ * implements the minimal `NoSqlStore` marker interface and exposes
11
+ * ArangoDB's real surface directly: collection management, document CRUD,
12
+ * parameterized AQL queries with cursor-based iteration, graph/edge
13
+ * operations (including AQL graph traversal), and index management.
14
+ *
15
+ * Uses the official `arangojs` driver (v10).
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.ArangoStore = void 0;
19
+ const arangojs_1 = require("arangojs");
20
+ const errors_1 = require("../../errors");
21
+ function wrapConnectionError(err, url) {
22
+ const parent = err instanceof Error ? err : new Error(String(err));
23
+ const host = Array.isArray(url) ? url[0] : url;
24
+ const message = /econnrefused/i.test(parent.message)
25
+ ? 'Connection refused'
26
+ : `Unable to connect to ArangoDB: ${parent.message}`;
27
+ return new errors_1.ConnectionError(message, { parent, database: 'arangodb', host });
28
+ }
29
+ function wrapDatabaseError(err, message) {
30
+ const parent = err instanceof Error ? err : new Error(String(err));
31
+ // Keep the `action` context (e.g. "ArangoDB ensureIndex failed") but don't
32
+ // discard the real underlying error text (e.g. ArangoDB's own
33
+ // "unique constraint violated" message) - append it so callers inspecting
34
+ // `err.message` still see what actually went wrong.
35
+ const combined = message ? `${message}: ${parent.message}` : parent.message;
36
+ return errors_1.DatabaseError.from(parent, { message: combined });
37
+ }
38
+ /** Normalize `"hash"`/`"skiplist"` (legacy names) to `"persistent"`, the type ArangoDB 3.12+ actually stores them as. */
39
+ function normalizeIndexType(type) {
40
+ return type === 'hash' || type === 'skiplist' ? 'persistent' : type;
41
+ }
42
+ /**
43
+ * Whether an `IndexSelector` needs to be resolved to an id-based handle
44
+ * before being handed to `arangojs`. `IndexSelector`'s TypeScript type
45
+ * (`ObjectWithIndexId | ObjectWithName | string`) advertises `{ name }` as
46
+ * a first-class way to identify an index, but `arangojs`'s actual runtime
47
+ * `_indexHandle()` helper (used by `Collection#index()`/`#dropIndex()`)
48
+ * only ever looks at `selector.id` - a plain `{ name }` object with no
49
+ * `id` throws `"Index handle must be a string or an object with an id
50
+ * attribute"` even when an index with that name exists. See
51
+ * `resolveIndexSelector()` below, which works around this by looking the
52
+ * index up by name via `listIndexes()` first.
53
+ */
54
+ function isNameOnlySelector(selector) {
55
+ return typeof selector !== 'string' && !('id' in selector) && 'name' in selector && selector.name !== undefined;
56
+ }
57
+ /**
58
+ * `ArangoStore` wraps the official `arangojs` driver's `Database`/
59
+ * `Collection`/`Graph`/`Cursor` API in a typed, promise-based convenience
60
+ * layer covering document CRUD, AQL queries, graphs, and indexes.
61
+ */
62
+ class ArangoStore {
63
+ constructor(options = {}) {
64
+ this.name = 'arangodb';
65
+ this.library = 'arangojs';
66
+ this.db = null;
67
+ this.connected = false;
68
+ this.options = options;
69
+ }
70
+ // ---------------------------------------------------------------------
71
+ // Connection lifecycle
72
+ // ---------------------------------------------------------------------
73
+ /**
74
+ * `arangojs`'s `Database` is a thin HTTP client wrapper with no persistent
75
+ * socket to open, so "connecting" here means constructing it and making
76
+ * one real request (`version()`) to fail fast on a bad URL/host/auth
77
+ * instead of only discovering the problem on the first real operation.
78
+ */
79
+ async connect() {
80
+ if (this.connected && this.db) {
81
+ return;
82
+ }
83
+ try {
84
+ const db = new arangojs_1.Database(this.options);
85
+ await db.version();
86
+ this.db = db;
87
+ this.connected = true;
88
+ }
89
+ catch (err) {
90
+ this.db = null;
91
+ this.connected = false;
92
+ throw wrapConnectionError(err, this.options.url);
93
+ }
94
+ }
95
+ async disconnect() {
96
+ if (this.db) {
97
+ this.db.close();
98
+ this.db = null;
99
+ }
100
+ this.connected = false;
101
+ }
102
+ isConnected() {
103
+ return this.connected && this.db !== null;
104
+ }
105
+ /** Returns the underlying `arangojs` `Database` instance for anything not wrapped here. */
106
+ getClient() {
107
+ return this.requireDb();
108
+ }
109
+ requireDb() {
110
+ if (!this.db) {
111
+ throw new errors_1.ConnectionError('Not connected to ArangoDB', { database: 'arangodb' });
112
+ }
113
+ return this.db;
114
+ }
115
+ async exec(fn, action) {
116
+ const db = this.requireDb();
117
+ try {
118
+ return await fn(db);
119
+ }
120
+ catch (err) {
121
+ throw wrapDatabaseError(err, `ArangoDB ${action} failed`);
122
+ }
123
+ }
124
+ // ---------------------------------------------------------------------
125
+ // Collection management
126
+ // ---------------------------------------------------------------------
127
+ /** Create a document collection. */
128
+ async createCollection(collectionName, options) {
129
+ return this.exec(async (db) => {
130
+ const collection = await db.createCollection(collectionName, options);
131
+ const result = await collection.properties();
132
+ return result;
133
+ }, 'createCollection');
134
+ }
135
+ /** Create an edge collection (documents store `_from`/`_to` and can be traversed as graph edges). */
136
+ async createEdgeCollection(collectionName, options) {
137
+ return this.exec(async (db) => {
138
+ const collection = await db.createEdgeCollection(collectionName, options);
139
+ const result = await collection.properties();
140
+ return result;
141
+ }, 'createEdgeCollection');
142
+ }
143
+ /** Drop a collection (document or edge). */
144
+ async dropCollection(collectionName, options) {
145
+ return this.exec(async (db) => {
146
+ await db.collection(collectionName).drop(options);
147
+ return true;
148
+ }, 'dropCollection');
149
+ }
150
+ /** Whether a collection with this name exists. */
151
+ async collectionExists(collectionName) {
152
+ return this.exec((db) => db.collection(collectionName).exists(), 'collection.exists');
153
+ }
154
+ /** List collections in the database (excludes system collections like `_users` by default). */
155
+ async listCollections(excludeSystem = true) {
156
+ return this.exec((db) => db.listCollections(excludeSystem), 'listCollections');
157
+ }
158
+ /** Remove all documents from a collection without dropping the collection itself. */
159
+ async truncateCollection(collectionName) {
160
+ await this.exec(async (db) => {
161
+ await db.collection(collectionName).truncate();
162
+ }, 'truncateCollection');
163
+ }
164
+ /** Number of documents currently in a collection. */
165
+ async collectionCount(collectionName) {
166
+ return this.exec(async (db) => {
167
+ const result = await db.collection(collectionName).count();
168
+ return result.count;
169
+ }, 'collection.count');
170
+ }
171
+ // ---------------------------------------------------------------------
172
+ // Document CRUD
173
+ // ---------------------------------------------------------------------
174
+ /** Insert a single document. Pass `_key` in `data` to choose the key explicitly; otherwise ArangoDB generates one. */
175
+ async insert(collectionName, data, options) {
176
+ return this.exec((db) => db.collection(collectionName).save(data, options), 'save');
177
+ }
178
+ /** Insert multiple documents in one request. Per-document failures (e.g. duplicate `_key`) come back as entries with `error: true` rather than throwing. */
179
+ async insertMany(collectionName, data, options) {
180
+ return this.exec((db) => db.collection(collectionName).saveAll(data, options), 'saveAll');
181
+ }
182
+ /** Fetch a single document by key/id. Returns `null` if it does not exist (rather than throwing). */
183
+ async getDocument(collectionName, selector, options) {
184
+ return this.exec(async (db) => {
185
+ const doc = await db
186
+ .collection(collectionName)
187
+ .document(selector, { ...options, graceful: true });
188
+ return (doc ?? null);
189
+ }, 'document');
190
+ }
191
+ /** Fetch multiple documents by key/id. Entries for documents that don't exist come back as `null`. */
192
+ async getDocuments(collectionName, selectors) {
193
+ return this.exec(async (db) => {
194
+ const raw = await db.collection(collectionName).documents(selectors);
195
+ return raw.map((doc) => doc && doc.error ? null : doc);
196
+ }, 'documents');
197
+ }
198
+ /** Whether a document with this key/id exists in the collection. */
199
+ async documentExists(collectionName, selector) {
200
+ return this.exec((db) => db.collection(collectionName).documentExists(selector), 'documentExists');
201
+ }
202
+ /** Partially update a document (shallow/deep merge of `patch` into the existing document, per ArangoDB's `PATCH` semantics). */
203
+ async updateDocument(collectionName, selector, patch, options) {
204
+ return this.exec((db) => db.collection(collectionName).update(selector, patch, options), 'update');
205
+ }
206
+ /** Fully replace a document's content (unlike `updateDocument`, unspecified fields are dropped). */
207
+ async replaceDocument(collectionName, selector, data, options) {
208
+ return this.exec((db) => db.collection(collectionName).replace(selector, data, options), 'replace');
209
+ }
210
+ /** Delete a single document by key/id. */
211
+ async removeDocument(collectionName, selector, options) {
212
+ return this.exec((db) => db.collection(collectionName).remove(selector, options), 'remove');
213
+ }
214
+ /** Delete multiple documents by key/id in one request. */
215
+ async removeDocuments(collectionName, selectors) {
216
+ return this.exec((db) => db.collection(collectionName).removeAll(selectors), 'removeAll');
217
+ }
218
+ // ---------------------------------------------------------------------
219
+ // AQL queries
220
+ // ---------------------------------------------------------------------
221
+ /**
222
+ * Run a parameterized AQL query and return the (cursor-based) result
223
+ * set as a native `arangojs` `Cursor` - iterate it with `for await`,
224
+ * `cursor.next()`, or `cursor.all()` to page through large result sets
225
+ * without loading everything into memory at once. Use `@name` in `query`
226
+ * for bind parameters and supply their values via `bindVars` (never
227
+ * string-interpolate untrusted values into `query` itself).
228
+ */
229
+ async query(query, bindVars = {}, options) {
230
+ return this.exec((db) => db.query(query, bindVars, options), 'query');
231
+ }
232
+ /** Convenience wrapper around `query()` that depletes the cursor and returns all results as an array. */
233
+ async queryAll(query, bindVars = {}, options) {
234
+ const cursor = await this.query(query, bindVars, options);
235
+ return cursor.all();
236
+ }
237
+ // ---------------------------------------------------------------------
238
+ // Graphs
239
+ // ---------------------------------------------------------------------
240
+ /**
241
+ * Create a named graph over one or more edge definitions (each mapping
242
+ * an edge collection to the vertex collection(s) it connects `from` and
243
+ * `to`). Collections referenced by the edge definitions that don't exist
244
+ * yet are created automatically by ArangoDB.
245
+ */
246
+ async createGraph(graphName, edgeDefinitions, options) {
247
+ return this.exec((db) => db.graph(graphName).create(edgeDefinitions, options), 'createGraph');
248
+ }
249
+ /** Drop a graph. If `dropCollections` is `true`, also drops the graph's vertex/edge collections (as long as they aren't used by another graph). */
250
+ async dropGraph(graphName, dropCollections = false) {
251
+ return this.exec((db) => db.graph(graphName).drop(dropCollections), 'graph.drop');
252
+ }
253
+ /** Whether a graph with this name exists. */
254
+ async graphExists(graphName) {
255
+ return this.exec((db) => db.graph(graphName).exists(), 'graph.exists');
256
+ }
257
+ /** List all graphs in the database. */
258
+ async listGraphs() {
259
+ return this.exec((db) => db.listGraphs(), 'listGraphs');
260
+ }
261
+ /** Add an existing (or new) vertex collection to a graph as an orphan collection (not tied to a specific edge definition). */
262
+ async addVertexCollection(graphName, collectionName) {
263
+ return this.exec((db) => db.graph(graphName).addVertexCollection(collectionName), 'graph.addVertexCollection');
264
+ }
265
+ /** Add a new edge definition to an existing graph. */
266
+ async addEdgeDefinition(graphName, edgeDefinition) {
267
+ return this.exec((db) => db.graph(graphName).addEdgeDefinition(edgeDefinition), 'graph.addEdgeDefinition');
268
+ }
269
+ // ---------------------------------------------------------------------
270
+ // Edges
271
+ // ---------------------------------------------------------------------
272
+ /** Insert an edge document into an edge collection, connecting `from` and `to` (each a document `_id`, e.g. `'people/alice'`). */
273
+ async insertEdge(edgeCollectionName, from, to, data = {}, options) {
274
+ return this.insert(edgeCollectionName, { ...data, _from: from, _to: to }, options);
275
+ }
276
+ /**
277
+ * Traverse a named graph from a start vertex using AQL's
278
+ * `FOR v, e, p IN min..max DIRECTION start GRAPH graphName` syntax,
279
+ * returning each visited vertex (`v`), the edge that reached it (`e`,
280
+ * `null` at depth 0), and the full path (`p`) as vertex/edge arrays.
281
+ *
282
+ * @param startVertexId - Start vertex `_id`, e.g. `'people/alice'`.
283
+ * @param graphName - Name of a graph created with `createGraph()`.
284
+ */
285
+ async traverse(startVertexId, graphName, options = {}) {
286
+ const direction = options.direction ?? 'OUTBOUND';
287
+ const minDepth = options.minDepth ?? 1;
288
+ const maxDepth = options.maxDepth ?? 1;
289
+ let aqlQuery = `FOR v, e, p IN ${minDepth}..${maxDepth} ${direction} @start GRAPH @graphName`;
290
+ if (options.filter) {
291
+ aqlQuery += ` FILTER ${options.filter}`;
292
+ }
293
+ if (options.limit !== undefined) {
294
+ aqlQuery += ` LIMIT ${options.limit}`;
295
+ }
296
+ aqlQuery += ' RETURN { vertex: v, edge: e, path: p }';
297
+ const rows = await this.queryAll(aqlQuery, { start: startVertexId, graphName });
298
+ return rows;
299
+ }
300
+ // ---------------------------------------------------------------------
301
+ // Indexes
302
+ // ---------------------------------------------------------------------
303
+ /** Create an index on a collection. `type: 'hash'`/`'skiplist'` are normalized to `'persistent'` (see `ArangoIndexType`). */
304
+ async createIndex(collectionName, options) {
305
+ return this.exec(async (db) => {
306
+ const type = normalizeIndexType(options.type);
307
+ const payload = {
308
+ type,
309
+ fields: options.fields,
310
+ name: options.name,
311
+ unique: options.unique,
312
+ sparse: options.sparse,
313
+ geoJson: options.geoJson,
314
+ minLength: options.minLength,
315
+ expireAfter: options.expireAfter,
316
+ inBackground: options.inBackground,
317
+ // `ensureIndex`'s overloads are keyed on a `type` literal per index
318
+ // kind; we accept a broader, unified option shape above and pass
319
+ // only the fields relevant to `type` through, so a runtime cast is
320
+ // needed here rather than a narrower compile-time overload match.
321
+ };
322
+ const result = await db.collection(collectionName).ensureIndex(payload);
323
+ return result;
324
+ }, 'ensureIndex');
325
+ }
326
+ /** Drop an index by id or name. */
327
+ async dropIndex(collectionName, selector) {
328
+ return this.exec(async (db) => {
329
+ const resolved = await this.resolveIndexSelector(db, collectionName, selector);
330
+ await db.collection(collectionName).dropIndex(resolved);
331
+ return true;
332
+ }, 'dropIndex');
333
+ }
334
+ /** List all indexes on a collection (including the automatic primary/edge indexes). */
335
+ async listIndexes(collectionName) {
336
+ return this.exec((db) => db.collection(collectionName).indexes(), 'indexes');
337
+ }
338
+ /** Fetch a single index's description by id or name. */
339
+ async getIndex(collectionName, selector) {
340
+ return this.exec(async (db) => {
341
+ const resolved = await this.resolveIndexSelector(db, collectionName, selector);
342
+ return db.collection(collectionName).index(resolved);
343
+ }, 'index');
344
+ }
345
+ /**
346
+ * Resolve a `{ name }`-only `IndexSelector` to an `{ id }` one by looking
347
+ * it up via `listIndexes()` first. String selectors and selectors that
348
+ * already carry an `id` are passed through unchanged - see
349
+ * `isNameOnlySelector()` for why this is necessary.
350
+ */
351
+ async resolveIndexSelector(db, collectionName, selector) {
352
+ if (!isNameOnlySelector(selector)) {
353
+ return selector;
354
+ }
355
+ const indexes = await db.collection(collectionName).indexes();
356
+ const found = indexes.find((index) => index.name === selector.name);
357
+ if (!found) {
358
+ throw new Error(`Index not found: ${selector.name}`);
359
+ }
360
+ return { id: found.id };
361
+ }
362
+ }
363
+ exports.ArangoStore = ArangoStore;
364
+ exports.default = ArangoStore;
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AzureBlobStore = void 0;
4
+ /**
5
+ * Azure Blob Storage store.
6
+ *
7
+ * Azure Blob Storage is an object store: opaque byte blobs addressed by a
8
+ * `container` + `blob name` pair, with no query language, no joins, and no
9
+ * ad hoc filtering. It does not fit the SQL-shaped `Dialect` interface
10
+ * (`src/dialects/dialect.ts`), so this store implements the minimal
11
+ * `NoSqlStore` marker interface (`src/nosql/store.ts`) and exposes Azure
12
+ * Blob Storage's own object-level operations (upload/download/delete/exists/
13
+ * list/create-container) directly.
14
+ *
15
+ * Built on the official `@azure/storage-blob` SDK. That package is an
16
+ * optional peer dependency here: it is lazy-`require()`d inside `connect()`
17
+ * only when a client isn't injected, so importing this module never forces
18
+ * the SDK to be installed. Tests inject a pre-built `BlobServiceClient` mock
19
+ * via the `client` option and never touch the real SDK or the network.
20
+ */
21
+ const errors_1 = require("../../errors");
22
+ function toBuffer(data) {
23
+ if (Buffer.isBuffer(data))
24
+ return data;
25
+ if (typeof data === 'string')
26
+ return Buffer.from(data);
27
+ if (data instanceof ArrayBuffer)
28
+ return Buffer.from(new Uint8Array(data));
29
+ return Buffer.from(data);
30
+ }
31
+ /** Collect a Node.js readable stream into a single Buffer. */
32
+ function streamToBuffer(stream) {
33
+ return new Promise((resolve, reject) => {
34
+ const chunks = [];
35
+ stream.on('data', (chunk) => chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk));
36
+ stream.on('end', () => resolve(Buffer.concat(chunks)));
37
+ stream.on('error', reject);
38
+ });
39
+ }
40
+ /**
41
+ * `AzureBlobStore` wraps a `@azure/storage-blob` `BlobServiceClient` and
42
+ * exposes Azure Blob Storage's object-level operations. It implements the
43
+ * minimal `NoSqlStore` marker interface — there is no `query(sql)` because
44
+ * Blob Storage has no query language; access is by container + blob name.
45
+ */
46
+ class AzureBlobStore {
47
+ constructor(options = {}) {
48
+ this.name = 'azure-blob';
49
+ this.library = '@azure/storage-blob';
50
+ this.client = null;
51
+ this.connected = false;
52
+ this.options = options;
53
+ }
54
+ // ---------------------------------------------------------------------
55
+ // NoSqlStore lifecycle
56
+ // ---------------------------------------------------------------------
57
+ async connect() {
58
+ if (this.connected && this.client) {
59
+ return;
60
+ }
61
+ try {
62
+ if (this.options.client) {
63
+ // An injected client is used as-is; the SDK is never require()d.
64
+ this.client = this.options.client;
65
+ }
66
+ else {
67
+ // Lazy-load the SDK only when we actually have to build a client, so
68
+ // this module can be imported without `@azure/storage-blob` installed.
69
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
70
+ const az = require('@azure/storage-blob');
71
+ const connectionString = this.resolveConnectionString();
72
+ this.client = az.BlobServiceClient.fromConnectionString(connectionString);
73
+ }
74
+ this.connected = true;
75
+ }
76
+ catch (err) {
77
+ this.client = null;
78
+ this.connected = false;
79
+ throw new errors_1.ConnectionError(`Failed to connect to Azure Blob Storage: ${err instanceof Error ? err.message : String(err)}`, { parent: err instanceof Error ? err : undefined, database: 'azure-blob' });
80
+ }
81
+ }
82
+ resolveConnectionString() {
83
+ if (this.options.connectionString) {
84
+ return this.options.connectionString;
85
+ }
86
+ if (this.options.account && this.options.accountKey) {
87
+ const suffix = this.options.endpointSuffix ?? 'core.windows.net';
88
+ return (`DefaultEndpointsProtocol=https;AccountName=${this.options.account};` +
89
+ `AccountKey=${this.options.accountKey};EndpointSuffix=${suffix}`);
90
+ }
91
+ throw new Error('AzureBlobStore requires one of: `client`, `connectionString`, or `account` + `accountKey`.');
92
+ }
93
+ async disconnect() {
94
+ // The `BlobServiceClient` holds no persistent socket to close (each
95
+ // request is an independent HTTPS call), so there's nothing to tear down
96
+ // beyond dropping our reference and flipping the connected flag.
97
+ this.client = null;
98
+ this.connected = false;
99
+ }
100
+ isConnected() {
101
+ return this.connected && this.client !== null;
102
+ }
103
+ /** Returns the underlying `BlobServiceClient` for anything not wrapped here. */
104
+ getClient() {
105
+ return this.requireClient();
106
+ }
107
+ requireClient() {
108
+ if (!this.client || !this.connected) {
109
+ throw new errors_1.ConnectionError('Not connected to Azure Blob Storage. Call connect() first.', {
110
+ database: 'azure-blob',
111
+ });
112
+ }
113
+ return this.client;
114
+ }
115
+ blockBlob(container, key) {
116
+ return this.requireClient().getContainerClient(container).getBlockBlobClient(key);
117
+ }
118
+ wrapError(action, err) {
119
+ const parent = err instanceof Error ? err : new Error(String(err));
120
+ return errors_1.DatabaseError.from(parent, { message: `Azure Blob ${action} failed: ${parent.message}` });
121
+ }
122
+ // ---------------------------------------------------------------------
123
+ // Blob operations
124
+ // ---------------------------------------------------------------------
125
+ /** Uploads `data` to `container`/`key`, creating or overwriting the block blob. */
126
+ async uploadBlob(container, key, data) {
127
+ const blockBlob = this.blockBlob(container, key);
128
+ const buffer = toBuffer(data);
129
+ try {
130
+ await blockBlob.upload(buffer, buffer.length);
131
+ }
132
+ catch (err) {
133
+ throw this.wrapError(`upload to '${container}/${key}'`, err);
134
+ }
135
+ }
136
+ /** Downloads `container`/`key` and returns its full contents as a Buffer. */
137
+ async downloadBlob(container, key) {
138
+ const blockBlob = this.blockBlob(container, key);
139
+ try {
140
+ const response = await blockBlob.download();
141
+ if (response.readableStreamBody) {
142
+ return await streamToBuffer(response.readableStreamBody);
143
+ }
144
+ // Browser build fallback: the body arrives as a Blob instead of a stream.
145
+ const blobBody = response.blobBody ?? response.contentAsBlob;
146
+ if (blobBody) {
147
+ const blob = await blobBody;
148
+ return Buffer.from(await blob.arrayBuffer());
149
+ }
150
+ return Buffer.alloc(0);
151
+ }
152
+ catch (err) {
153
+ throw this.wrapError(`download of '${container}/${key}'`, err);
154
+ }
155
+ }
156
+ /** Deletes `container`/`key`. */
157
+ async deleteBlob(container, key) {
158
+ const blockBlob = this.blockBlob(container, key);
159
+ try {
160
+ await blockBlob.delete();
161
+ }
162
+ catch (err) {
163
+ throw this.wrapError(`delete of '${container}/${key}'`, err);
164
+ }
165
+ }
166
+ /** Returns whether `container`/`key` exists. */
167
+ async blobExists(container, key) {
168
+ const blockBlob = this.blockBlob(container, key);
169
+ try {
170
+ return await blockBlob.exists();
171
+ }
172
+ catch (err) {
173
+ throw this.wrapError(`exists check of '${container}/${key}'`, err);
174
+ }
175
+ }
176
+ /**
177
+ * Lists the names of all blobs in `container`, optionally filtered to those
178
+ * whose name starts with `prefix`. Iterates the SDK's async paging iterator
179
+ * (`listBlobsFlat`) fully and returns a flat array of blob names.
180
+ */
181
+ async listBlobs(container, prefix) {
182
+ const containerClient = this.requireClient().getContainerClient(container);
183
+ const names = [];
184
+ try {
185
+ for await (const blob of containerClient.listBlobsFlat({ prefix })) {
186
+ names.push(blob.name);
187
+ }
188
+ }
189
+ catch (err) {
190
+ throw this.wrapError(`list of '${container}'`, err);
191
+ }
192
+ return names;
193
+ }
194
+ /** Creates `container`. */
195
+ async createContainer(container) {
196
+ const containerClient = this.requireClient().getContainerClient(container);
197
+ try {
198
+ await containerClient.create();
199
+ }
200
+ catch (err) {
201
+ throw this.wrapError(`create container '${container}'`, err);
202
+ }
203
+ }
204
+ }
205
+ exports.AzureBlobStore = AzureBlobStore;
206
+ exports.default = AzureBlobStore;