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,281 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.R2Store = void 0;
4
+ /**
5
+ * Cloudflare R2 object-storage store.
6
+ *
7
+ * R2 is Cloudflare's S3-compatible object store: like Amazon S3 it has no
8
+ * query language, no rows, and no SQL-shaped access pattern — data is opaque
9
+ * objects (byte bodies plus metadata) addressed by a `(bucket, key)` pair,
10
+ * where the "key" is a flat string that only *looks* like a path
11
+ * (`foo/bar/baz.json`); R2 has no real directories, just an optional key
12
+ * `prefix` you can filter listings by. None of that fits the SQL-shaped
13
+ * `Dialect` interface, so this store implements the minimal `NoSqlStore`
14
+ * marker interface (`src/nosql/store.ts`) and exposes object-level operations
15
+ * directly.
16
+ *
17
+ * Because R2 speaks the S3 wire protocol, this store is built on AWS SDK v3
18
+ * (`@aws-sdk/client-s3`) exactly like `S3Store`: an `S3Client` uses the
19
+ * command pattern — you construct a command object (`new PutObjectCommand(
20
+ * input)`) and hand it to `client.send(command)`. The only differences from a
21
+ * plain S3 connection are R2-specific client settings: R2 has no regions, so
22
+ * `region` is the sentinel `'auto'`; requests go to an account-specific
23
+ * `endpoint` (e.g. `https://<account_id>.r2.cloudflarestorage.com`); and
24
+ * path-style addressing is required (`forcePathStyle: true`).
25
+ *
26
+ * The SDK is loaded lazily inside `connect()` (via `require`) rather than a
27
+ * top-level import so that importing this module doesn't hard-require the
28
+ * `@aws-sdk/client-s3` package unless an R2 store is actually connected — and
29
+ * so tests can inject a pre-built mock `client` and never load the SDK at all.
30
+ */
31
+ const errors_1 = require("../../errors");
32
+ /**
33
+ * Cloudflare R2 store, implementing the minimal `NoSqlStore` marker interface.
34
+ * Unlike the SQL dialects there is no `query(sql)` — R2's operations are
35
+ * object-shaped (Put/Get/Delete/List/Head) and that shape is preserved here
36
+ * rather than forced into a SQL string.
37
+ */
38
+ class R2Store {
39
+ constructor(options = {}) {
40
+ this.name = 'r2';
41
+ this.library = '@aws-sdk/client-s3';
42
+ this.client = null;
43
+ this.aws = null;
44
+ this.connected = false;
45
+ this.options = options;
46
+ }
47
+ // ---------------------------------------------------------------------
48
+ // NoSqlStore lifecycle
49
+ // ---------------------------------------------------------------------
50
+ async connect() {
51
+ try {
52
+ if (this.options.client) {
53
+ // A pre-built client was injected (mock or custom). Use it directly
54
+ // and don't require the SDK at all. We still best-effort lazy-load the
55
+ // SDK for the command constructors if it happens to be installed; if
56
+ // not, the command classes are loaded on demand in each method.
57
+ this.client = this.options.client;
58
+ this.tryLoadSdk();
59
+ }
60
+ else {
61
+ const aws = require('@aws-sdk/client-s3');
62
+ this.aws = aws;
63
+ this.client = new aws.S3Client({
64
+ // R2 has no regions; the SDK still requires a region, and R2
65
+ // expects the sentinel 'auto'.
66
+ region: this.options.region ?? 'auto',
67
+ // R2 uses an account-specific endpoint rather than the AWS default.
68
+ endpoint: this.options.endpoint,
69
+ credentials: this.options.credentials,
70
+ // R2 requires path-style addressing (endpoint/bucket/key).
71
+ forcePathStyle: true,
72
+ });
73
+ }
74
+ this.connected = true;
75
+ }
76
+ catch (err) {
77
+ this.connected = false;
78
+ this.client = null;
79
+ this.aws = null;
80
+ throw new errors_1.ConnectionError(`Failed to connect to R2: ${err instanceof Error ? err.message : String(err)}`, { parent: err instanceof Error ? err : undefined });
81
+ }
82
+ }
83
+ /**
84
+ * Attempt to lazy-load `@aws-sdk/client-s3` for its command constructors.
85
+ * Best-effort: when a client was injected (e.g. a test mock) the SDK may
86
+ * not be installed, so a failure here is swallowed and the command classes
87
+ * are loaded on demand instead (see `command()`).
88
+ */
89
+ tryLoadSdk() {
90
+ if (this.aws)
91
+ return;
92
+ try {
93
+ this.aws = require('@aws-sdk/client-s3');
94
+ }
95
+ catch {
96
+ this.aws = null;
97
+ }
98
+ }
99
+ async disconnect() {
100
+ try {
101
+ this.client?.destroy?.();
102
+ }
103
+ finally {
104
+ this.client = null;
105
+ this.aws = null;
106
+ this.connected = false;
107
+ }
108
+ }
109
+ isConnected() {
110
+ return this.connected && this.client !== null;
111
+ }
112
+ /** Returns the underlying `S3Client` (loosely typed) for anything not wrapped here. */
113
+ getClient() {
114
+ return this.requireClient();
115
+ }
116
+ requireClient() {
117
+ if (!this.client || !this.connected) {
118
+ throw new errors_1.ConnectionError('R2 client is not connected. Call connect() first.');
119
+ }
120
+ return this.client;
121
+ }
122
+ /**
123
+ * Resolve an S3 command constructor by name from the (lazily loaded) SDK,
124
+ * so that with an injected mock client we only load `@aws-sdk/client-s3`
125
+ * the first time a command is actually built. Throws a `ConnectionError`
126
+ * if the SDK genuinely can't be resolved.
127
+ */
128
+ command(name, input) {
129
+ if (!this.aws) {
130
+ this.tryLoadSdk();
131
+ }
132
+ const Ctor = this.aws?.[name];
133
+ if (typeof Ctor !== 'function') {
134
+ throw new errors_1.ConnectionError(`R2 command '${name}' is unavailable: '@aws-sdk/client-s3' could not be loaded.`);
135
+ }
136
+ return new Ctor(input);
137
+ }
138
+ /** Wraps an AWS SDK failure in a `DatabaseError`, preserving the original error. */
139
+ wrapError(action, err) {
140
+ const parent = err instanceof Error ? err : new Error(String(err));
141
+ const name = parent.name ? ` (${parent.name})` : '';
142
+ return new errors_1.DatabaseError(`R2 ${action} failed${name}: ${parent.message}`, {
143
+ parent,
144
+ original: parent.message,
145
+ });
146
+ }
147
+ // ---------------------------------------------------------------------
148
+ // Object operations (AWS v3 command pattern via client.send)
149
+ // ---------------------------------------------------------------------
150
+ /** `PutObject` — store an object's body (and optional metadata) under `bucket`/`key`. */
151
+ async putObject(bucket, key, body, options = {}) {
152
+ const client = this.requireClient();
153
+ try {
154
+ const result = await client.send(this.command('PutObjectCommand', {
155
+ Bucket: bucket,
156
+ Key: key,
157
+ Body: body,
158
+ ContentType: options.contentType,
159
+ Metadata: options.metadata,
160
+ CacheControl: options.cacheControl,
161
+ ContentEncoding: options.contentEncoding,
162
+ }));
163
+ return { etag: result?.ETag, versionId: result?.VersionId };
164
+ }
165
+ catch (err) {
166
+ throw this.wrapError(`PutObject on '${bucket}/${key}'`, err);
167
+ }
168
+ }
169
+ /** `GetObject` — fetch an object's body and metadata. */
170
+ async getObject(bucket, key) {
171
+ const client = this.requireClient();
172
+ try {
173
+ const result = await client.send(this.command('GetObjectCommand', { Bucket: bucket, Key: key }));
174
+ return {
175
+ body: result?.Body,
176
+ contentType: result?.ContentType,
177
+ contentLength: result?.ContentLength,
178
+ etag: result?.ETag,
179
+ lastModified: result?.LastModified,
180
+ metadata: result?.Metadata,
181
+ };
182
+ }
183
+ catch (err) {
184
+ throw this.wrapError(`GetObject on '${bucket}/${key}'`, err);
185
+ }
186
+ }
187
+ /** `DeleteObject` — remove an object. Succeeds even if the key doesn't exist. */
188
+ async deleteObject(bucket, key) {
189
+ const client = this.requireClient();
190
+ try {
191
+ await client.send(this.command('DeleteObjectCommand', { Bucket: bucket, Key: key }));
192
+ }
193
+ catch (err) {
194
+ throw this.wrapError(`DeleteObject on '${bucket}/${key}'`, err);
195
+ }
196
+ }
197
+ /**
198
+ * `ListObjectsV2` — list objects in `bucket`, optionally restricted to
199
+ * those whose key starts with `prefix`. A single call returns at most
200
+ * 1000 objects; use `result.nextContinuationToken` (via the raw client)
201
+ * to page beyond that.
202
+ */
203
+ async listObjects(bucket, prefix) {
204
+ const client = this.requireClient();
205
+ try {
206
+ const result = await client.send(this.command('ListObjectsV2Command', { Bucket: bucket, Prefix: prefix }));
207
+ const contents = result?.Contents ?? [];
208
+ return {
209
+ objects: contents.map((o) => ({
210
+ key: o?.Key,
211
+ size: o?.Size,
212
+ etag: o?.ETag,
213
+ lastModified: o?.LastModified,
214
+ })),
215
+ isTruncated: Boolean(result?.IsTruncated),
216
+ nextContinuationToken: result?.NextContinuationToken,
217
+ };
218
+ }
219
+ catch (err) {
220
+ throw this.wrapError(`ListObjects on '${bucket}'`, err);
221
+ }
222
+ }
223
+ /** `HeadObject` — fetch an object's metadata without its body. Throws (NotFound) if the object doesn't exist. */
224
+ async headObject(bucket, key) {
225
+ const client = this.requireClient();
226
+ try {
227
+ const result = await client.send(this.command('HeadObjectCommand', { Bucket: bucket, Key: key }));
228
+ return {
229
+ contentType: result?.ContentType,
230
+ contentLength: result?.ContentLength,
231
+ etag: result?.ETag,
232
+ lastModified: result?.LastModified,
233
+ metadata: result?.Metadata,
234
+ };
235
+ }
236
+ catch (err) {
237
+ throw this.wrapError(`HeadObject on '${bucket}/${key}'`, err);
238
+ }
239
+ }
240
+ /**
241
+ * Whether an object exists, implemented via `HeadObject`. Returns `false`
242
+ * when R2 reports the object is missing (a `NotFound` / 404 error) rather
243
+ * than throwing; any other error (e.g. access denied) is re-thrown.
244
+ */
245
+ async objectExists(bucket, key) {
246
+ try {
247
+ await this.headObject(bucket, key);
248
+ return true;
249
+ }
250
+ catch (err) {
251
+ if (this.isNotFound(err)) {
252
+ return false;
253
+ }
254
+ throw err;
255
+ }
256
+ }
257
+ /**
258
+ * Recognize "object does not exist" errors across the shapes the SDK (and
259
+ * its wrapped form here) can surface them: the raw error's `.name`
260
+ * (`NotFound`, `NoSuchKey`), its HTTP status (404), or the wrapped
261
+ * `DatabaseError`'s `.parent`.
262
+ */
263
+ isNotFound(err) {
264
+ const candidates = [err];
265
+ const parent = err?.parent;
266
+ if (parent)
267
+ candidates.push(parent);
268
+ for (const c of candidates) {
269
+ const name = c?.name;
270
+ if (name === 'NotFound' || name === 'NoSuchKey')
271
+ return true;
272
+ const status = c?.$metadata?.httpStatusCode ??
273
+ c?.statusCode;
274
+ if (status === 404)
275
+ return true;
276
+ }
277
+ return false;
278
+ }
279
+ }
280
+ exports.R2Store = R2Store;
281
+ exports.default = R2Store;
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ /**
3
+ * RabbitMQ (AMQP 0-9-1) store.
4
+ *
5
+ * RabbitMQ is a message broker, not a database: there is no query language,
6
+ * no relational schema, and no `query(sql)` shape. Producers publish
7
+ * messages to *exchanges*, which route them (by binding key/pattern) into
8
+ * *queues*, from which *consumers* read. Like the other stores in
9
+ * `src/nosql/`, this class therefore does not implement the SQL-shaped
10
+ * `Dialect` interface (`src/dialects/dialect.ts`). Instead it implements the
11
+ * minimal `NoSqlStore` marker interface (`src/nosql/store.ts`) and exposes
12
+ * RabbitMQ's real operations — assert/bind topology, publish, and consume —
13
+ * directly, mapped onto a single AMQP channel.
14
+ *
15
+ * Uses the official `amqplib` driver. `amqplib` is an optional peer of this
16
+ * ORM and is loaded lazily (via `require`) inside `connect()`, so importing
17
+ * this module does not require `amqplib` to be installed unless you actually
18
+ * connect. For tests (and for advanced setups that manage the AMQP
19
+ * connection themselves), a pre-built connection can be injected via
20
+ * `RabbitMQStoreOptions.connection`, in which case `connect()` uses it and
21
+ * skips the `require` entirely.
22
+ *
23
+ * ## Message serialization
24
+ *
25
+ * AMQP message bodies are raw bytes (`Buffer`). For convenience, both
26
+ * `sendToQueue()` and `publish()` accept any value: a `Buffer` (or
27
+ * `Uint8Array`) is sent as-is, a `string` is UTF-8 encoded, and anything
28
+ * else is serialized with `JSON.stringify` before being wrapped in a
29
+ * `Buffer`. Consumers receive the raw `amqplib` message object; decode
30
+ * `msg.content` (a `Buffer`) yourself (e.g. `JSON.parse(msg.content.toString())`).
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.RabbitMQStore = void 0;
34
+ const errors_1 = require("../../errors");
35
+ /**
36
+ * Normalize an arbitrary message value into a `Buffer` suitable for the
37
+ * AMQP wire: `Buffer`/`Uint8Array` pass through, strings are UTF-8 encoded,
38
+ * everything else is `JSON.stringify`'d.
39
+ */
40
+ function toBuffer(message) {
41
+ if (Buffer.isBuffer(message)) {
42
+ return message;
43
+ }
44
+ if (message instanceof Uint8Array) {
45
+ return Buffer.from(message);
46
+ }
47
+ if (typeof message === 'string') {
48
+ return Buffer.from(message);
49
+ }
50
+ return Buffer.from(JSON.stringify(message));
51
+ }
52
+ function wrapConnectionError(err) {
53
+ const parent = err instanceof Error ? err : new Error(String(err));
54
+ const message = /econnrefused/i.test(parent.message)
55
+ ? 'Connection refused'
56
+ : `Unable to connect to RabbitMQ: ${parent.message}`;
57
+ return new errors_1.ConnectionError(message, { parent, database: 'rabbitmq' });
58
+ }
59
+ function wrapDatabaseError(err, action) {
60
+ const parent = err instanceof Error ? err : new Error(String(err));
61
+ return errors_1.DatabaseError.from(parent, { message: `RabbitMQ ${action} failed: ${parent.message}` });
62
+ }
63
+ /**
64
+ * `RabbitMQStore` wraps a single `amqplib` channel and exposes RabbitMQ's
65
+ * core AMQP operations: asserting queues/exchanges, binding them, publishing
66
+ * (to a queue directly or via an exchange), consuming with ack/nack, and
67
+ * consumer prefetch (QoS).
68
+ */
69
+ class RabbitMQStore {
70
+ constructor(options = {}) {
71
+ this.name = 'rabbitmq';
72
+ this.library = 'amqplib';
73
+ this.connection = null;
74
+ this.channel = null;
75
+ this.connected = false;
76
+ this.options = options;
77
+ }
78
+ // ---------------------------------------------------------------------
79
+ // Connection lifecycle
80
+ // ---------------------------------------------------------------------
81
+ async connect() {
82
+ if (this.connected && this.channel) {
83
+ return;
84
+ }
85
+ try {
86
+ if (this.options.connection != null) {
87
+ // Caller-supplied connection: adopt it, don't require the driver.
88
+ this.connection = this.options.connection;
89
+ }
90
+ else {
91
+ // Lazy-load amqplib only when actually connecting, so importing this
92
+ // module doesn't hard-require the optional driver to be installed.
93
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
94
+ const amqp = require('amqplib');
95
+ this.connection = await amqp.connect(this.options.url || 'amqp://localhost');
96
+ }
97
+ this.channel = await this.connection.createChannel();
98
+ this.connected = true;
99
+ }
100
+ catch (err) {
101
+ this.channel = null;
102
+ this.connection = null;
103
+ this.connected = false;
104
+ throw wrapConnectionError(err);
105
+ }
106
+ }
107
+ async disconnect() {
108
+ try {
109
+ if (this.channel) {
110
+ await this.channel.close();
111
+ }
112
+ }
113
+ catch {
114
+ // Ignore channel-close errors; we're tearing down regardless.
115
+ }
116
+ try {
117
+ if (this.connection) {
118
+ await this.connection.close();
119
+ }
120
+ }
121
+ catch {
122
+ // Ignore connection-close errors; we're tearing down regardless.
123
+ }
124
+ this.channel = null;
125
+ this.connection = null;
126
+ this.connected = false;
127
+ }
128
+ isConnected() {
129
+ return this.connected && this.channel !== null;
130
+ }
131
+ /** Returns the underlying `amqplib` channel for operations not wrapped here. */
132
+ getClient() {
133
+ return this.requireChannel();
134
+ }
135
+ /** Returns the underlying `amqplib` connection. */
136
+ getConnection() {
137
+ if (!this.connection) {
138
+ throw new errors_1.ConnectionError('Not connected to RabbitMQ', { database: 'rabbitmq' });
139
+ }
140
+ return this.connection;
141
+ }
142
+ requireChannel() {
143
+ if (!this.channel) {
144
+ throw new errors_1.ConnectionError('Not connected to RabbitMQ', { database: 'rabbitmq' });
145
+ }
146
+ return this.channel;
147
+ }
148
+ async exec(fn, action) {
149
+ const channel = this.requireChannel();
150
+ try {
151
+ return await fn(channel);
152
+ }
153
+ catch (err) {
154
+ throw wrapDatabaseError(err, action);
155
+ }
156
+ }
157
+ // ---------------------------------------------------------------------
158
+ // Topology (queues, exchanges, bindings)
159
+ // ---------------------------------------------------------------------
160
+ /**
161
+ * Declare a queue, creating it if it doesn't exist (idempotent). Returns
162
+ * amqplib's assertion reply (`{ queue, messageCount, consumerCount }`).
163
+ * Pass `''` as `queue` to have the broker generate a unique name.
164
+ */
165
+ async assertQueue(queue, options) {
166
+ return this.exec((c) => c.assertQueue(queue, options), 'assertQueue');
167
+ }
168
+ /**
169
+ * Declare an exchange of the given `type` (`'direct'`, `'fanout'`,
170
+ * `'topic'`, `'headers'`), creating it if it doesn't exist (idempotent).
171
+ */
172
+ async assertExchange(exchange, type, options) {
173
+ return this.exec((c) => c.assertExchange(exchange, type, options), 'assertExchange');
174
+ }
175
+ /**
176
+ * Bind `queue` to `exchange` so messages published to `exchange` matching
177
+ * `pattern` (the routing/binding key) are routed into `queue`.
178
+ */
179
+ async bindQueue(queue, exchange, pattern) {
180
+ return this.exec((c) => c.bindQueue(queue, exchange, pattern), 'bindQueue');
181
+ }
182
+ // ---------------------------------------------------------------------
183
+ // Producing
184
+ // ---------------------------------------------------------------------
185
+ /**
186
+ * Send a message straight to a named `queue` (via the default exchange).
187
+ * Non-`Buffer` messages are serialized — strings UTF-8 encoded, other
188
+ * values `JSON.stringify`'d (see the module docs). Returns amqplib's
189
+ * boolean write result (`false` when the channel's write buffer is full
190
+ * and you should wait for a `'drain'` event before writing more).
191
+ */
192
+ async sendToQueue(queue, message, options) {
193
+ return this.exec((c) => c.sendToQueue(queue, toBuffer(message), options), 'sendToQueue');
194
+ }
195
+ /**
196
+ * Publish a message to an `exchange` with a `routingKey`; the exchange
197
+ * routes it to bound queues. Non-`Buffer` messages are serialized like
198
+ * `sendToQueue()`. Returns amqplib's boolean write result.
199
+ */
200
+ async publish(exchange, routingKey, message, options) {
201
+ return this.exec((c) => c.publish(exchange, routingKey, toBuffer(message), options), 'publish');
202
+ }
203
+ // ---------------------------------------------------------------------
204
+ // Consuming
205
+ // ---------------------------------------------------------------------
206
+ /**
207
+ * Register `handler` to receive each message delivered from `queue`. The
208
+ * handler is called with the raw amqplib message object (or `null` if the
209
+ * consumer is cancelled by the broker); decode `msg.content` yourself.
210
+ * Unless `options.noAck` is set, call `ack(msg)`/`nack(msg)` when done.
211
+ * Returns amqplib's `{ consumerTag }` reply.
212
+ */
213
+ async consume(queue, handler, options) {
214
+ return this.exec((c) => c.consume(queue, (msg) => handler(msg), options), 'consume');
215
+ }
216
+ /** Acknowledge a delivered message so the broker can drop it. */
217
+ ack(message, allUpTo) {
218
+ this.requireChannel().ack(message, allUpTo);
219
+ }
220
+ /**
221
+ * Reject a delivered message. By default RabbitMQ requeues it (`requeue`
222
+ * defaults to `true` in amqplib); pass `requeue = false` to drop or
223
+ * dead-letter it.
224
+ */
225
+ nack(message, allUpTo, requeue) {
226
+ this.requireChannel().nack(message, allUpTo, requeue);
227
+ }
228
+ /**
229
+ * Set the consumer prefetch (QoS) — the max number of unacknowledged
230
+ * messages the broker will deliver to consumers on this channel at once.
231
+ */
232
+ async prefetch(count, global) {
233
+ return this.exec((c) => c.prefetch(count, global), 'prefetch');
234
+ }
235
+ }
236
+ exports.RabbitMQStore = RabbitMQStore;
237
+ exports.default = RabbitMQStore;
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ /**
3
+ * RavenDB store implementation for the Prorm NoSQL layer.
4
+ *
5
+ * RavenDB is a transactional, multi-model document database with a
6
+ * unit-of-work session API (store/load/delete + saveChanges) and a fluent,
7
+ * indexed query builder. It does not fit the SQL-shaped `Dialect` interface,
8
+ * so this class implements the minimal `NoSqlStore` marker interface for
9
+ * connection lifecycle and exposes RavenDB's real session CRUD plus `query`
10
+ * API through a small document-CRUD convenience layer. Each operation opens
11
+ * its own short-lived session and commits with `saveChanges()`.
12
+ *
13
+ * Uses the official `ravendb` driver. That driver is an optional peer
14
+ * dependency and is loaded lazily inside `connect()` so importing this module
15
+ * never requires it to be installed. Tests inject a pre-built mock
16
+ * `DocumentStore` via `options.client`, which bypasses the lazy `require`
17
+ * entirely - no real driver and no network are needed.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.RavenDbStore = void 0;
21
+ const errors_1 = require("../../errors");
22
+ class RavenDbStore {
23
+ constructor(options = {}) {
24
+ this.name = 'ravendb';
25
+ this.library = 'ravendb';
26
+ this.store = null;
27
+ this.connected = false;
28
+ this.options = options;
29
+ }
30
+ // ---------------------------------------------------------------------
31
+ // Connection lifecycle
32
+ // ---------------------------------------------------------------------
33
+ async connect() {
34
+ if (this.connected && this.store) {
35
+ return;
36
+ }
37
+ try {
38
+ if (this.options.client) {
39
+ this.store = this.options.client;
40
+ }
41
+ else {
42
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
43
+ const mod = require('ravendb');
44
+ const DocumentStoreCtor = mod.DocumentStore;
45
+ this.store = new DocumentStoreCtor(this.options.urls, this.options.database);
46
+ }
47
+ if (typeof this.store.initialize === 'function') {
48
+ this.store.initialize();
49
+ }
50
+ this.connected = true;
51
+ }
52
+ catch (err) {
53
+ this.store = null;
54
+ this.connected = false;
55
+ const parent = err instanceof Error ? err : new Error(String(err));
56
+ throw new errors_1.ConnectionError(`Unable to connect to RavenDB: ${parent.message}`, {
57
+ parent,
58
+ database: 'ravendb',
59
+ });
60
+ }
61
+ }
62
+ async disconnect() {
63
+ if (this.store && typeof this.store.dispose === 'function') {
64
+ try {
65
+ await this.store.dispose();
66
+ }
67
+ catch (err) {
68
+ throw wrapDatabaseError(err, 'RavenDB disconnect failed');
69
+ }
70
+ }
71
+ this.store = null;
72
+ this.connected = false;
73
+ }
74
+ isConnected() {
75
+ return this.connected && this.store !== null;
76
+ }
77
+ getClient() {
78
+ return this.requireStore();
79
+ }
80
+ requireStore() {
81
+ if (!this.store || !this.connected) {
82
+ throw new errors_1.ConnectionError('Not connected to RavenDB. Call connect() first.', {
83
+ database: 'ravendb',
84
+ });
85
+ }
86
+ return this.store;
87
+ }
88
+ // ---------------------------------------------------------------------
89
+ // Document CRUD (unit-of-work sessions)
90
+ // ---------------------------------------------------------------------
91
+ /** Store a document in `collection`; returns the id used. */
92
+ async insert(collection, doc) {
93
+ const store = this.requireStore();
94
+ try {
95
+ const id = (doc.id ?? `${collection}/${genId()}`);
96
+ const session = store.openSession();
97
+ await session.store(doc, id);
98
+ await session.saveChanges();
99
+ return id;
100
+ }
101
+ catch (err) {
102
+ throw wrapDatabaseError(err, 'RavenDB insert failed');
103
+ }
104
+ }
105
+ /** Load a document by id. */
106
+ async get(_collection, id) {
107
+ const store = this.requireStore();
108
+ try {
109
+ const session = store.openSession();
110
+ return await session.load(id);
111
+ }
112
+ catch (err) {
113
+ throw wrapDatabaseError(err, 'RavenDB get failed');
114
+ }
115
+ }
116
+ /** Load, merge `patch`, and save; returns the updated entity. */
117
+ async update(_collection, id, patch) {
118
+ const store = this.requireStore();
119
+ try {
120
+ const session = store.openSession();
121
+ const entity = await session.load(id);
122
+ const merged = Object.assign(entity ?? {}, patch);
123
+ await session.saveChanges();
124
+ return merged;
125
+ }
126
+ catch (err) {
127
+ throw wrapDatabaseError(err, 'RavenDB update failed');
128
+ }
129
+ }
130
+ /** Delete a document by id. */
131
+ async delete(_collection, id) {
132
+ const store = this.requireStore();
133
+ try {
134
+ const session = store.openSession();
135
+ await session.delete(id);
136
+ await session.saveChanges();
137
+ return { id };
138
+ }
139
+ catch (err) {
140
+ throw wrapDatabaseError(err, 'RavenDB delete failed');
141
+ }
142
+ }
143
+ /**
144
+ * Query `collection`. `filter` is a plain object whose entries become
145
+ * `whereEquals(field, value)` conditions on the session query. Returns all
146
+ * matched documents.
147
+ */
148
+ async query(collection, filter = {}) {
149
+ const store = this.requireStore();
150
+ try {
151
+ const session = store.openSession();
152
+ let q = session.query({ collection });
153
+ for (const [field, value] of Object.entries(filter)) {
154
+ q = q.whereEquals(field, value);
155
+ }
156
+ const results = await q.all();
157
+ return results ?? [];
158
+ }
159
+ catch (err) {
160
+ throw wrapDatabaseError(err, 'RavenDB query failed');
161
+ }
162
+ }
163
+ }
164
+ exports.RavenDbStore = RavenDbStore;
165
+ function genId() {
166
+ return `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
167
+ }
168
+ function wrapDatabaseError(err, message) {
169
+ if (err instanceof errors_1.ConnectionError) {
170
+ return err;
171
+ }
172
+ const parent = err instanceof Error ? err : new Error(String(err));
173
+ return errors_1.DatabaseError.from(parent, { message: `${message}: ${parent.message}` });
174
+ }
175
+ exports.default = RavenDbStore;