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.
- package/CHANGELOG.md +1111 -0
- package/LICENSE +21 -0
- package/README.md +573 -0
- package/dist/audit/history-query.js +180 -0
- package/dist/audit/index.js +23 -0
- package/dist/audit/logger.js +236 -0
- package/dist/cache/cache-manager.js +84 -0
- package/dist/cache/index.js +16 -0
- package/dist/cache/redis-cluster-cache.js +557 -0
- package/dist/cli.js +2200 -0
- package/dist/compliance/audit-trail.js +68 -0
- package/dist/compliance/backup-verification.js +685 -0
- package/dist/compliance/breach-detector.js +505 -0
- package/dist/compliance/consent-record.js +227 -0
- package/dist/compliance/consent-versioning.js +331 -0
- package/dist/compliance/cross-border-log.js +530 -0
- package/dist/compliance/data-classifier.js +258 -0
- package/dist/compliance/data-lineage.js +565 -0
- package/dist/compliance/data-masker.js +303 -0
- package/dist/compliance/data-portability.js +265 -0
- package/dist/compliance/data-retention.js +195 -0
- package/dist/compliance/dsar-workflow.js +342 -0
- package/dist/compliance/field-encryption.js +223 -0
- package/dist/compliance/immutable-record.js +148 -0
- package/dist/compliance/index.js +260 -0
- package/dist/compliance/privacy-impact-assessment.js +364 -0
- package/dist/compliance/pseudonymization.js +269 -0
- package/dist/compliance/query-firewall.js +1182 -0
- package/dist/compliance/rate-limiter.js +580 -0
- package/dist/compliance/right-to-erasure.js +117 -0
- package/dist/compliance/row-level-security.js +246 -0
- package/dist/compliance/security-decorator.js +574 -0
- package/dist/compliance/security-monitor.js +525 -0
- package/dist/compliance/sensitive-data-discovery.js +476 -0
- package/dist/compliance/session-isolation.js +472 -0
- package/dist/compliance/tls-enforcer.js +108 -0
- package/dist/compliance/worm-storage.js +712 -0
- package/dist/connection-manager.js +198 -0
- package/dist/connection-pool.js +519 -0
- package/dist/decorators/audit.js +136 -0
- package/dist/decorators/belongs-to-many.js +115 -0
- package/dist/decorators/belongs-to.js +115 -0
- package/dist/decorators/check.js +435 -0
- package/dist/decorators/collate.js +329 -0
- package/dist/decorators/comment.js +205 -0
- package/dist/decorators/database-settings.js +236 -0
- package/dist/decorators/default.js +244 -0
- package/dist/decorators/encryption.js +235 -0
- package/dist/decorators/engine.js +97 -0
- package/dist/decorators/fk-constraints.js +594 -0
- package/dist/decorators/foreign-table.js +136 -0
- package/dist/decorators/generated.js +274 -0
- package/dist/decorators/has-many.js +127 -0
- package/dist/decorators/has-one.js +116 -0
- package/dist/decorators/hstore.js +129 -0
- package/dist/decorators/index.js +355 -0
- package/dist/decorators/json-column.js +83 -0
- package/dist/decorators/jsonb.js +101 -0
- package/dist/decorators/orm-decorators.js +425 -0
- package/dist/decorators/permissions.js +294 -0
- package/dist/decorators/procedure.js +210 -0
- package/dist/decorators/query-options.js +556 -0
- package/dist/decorators/range.js +167 -0
- package/dist/decorators/set-column.js +83 -0
- package/dist/decorators/spatial.js +114 -0
- package/dist/decorators/storage.js +580 -0
- package/dist/decorators/timezone.js +512 -0
- package/dist/decorators/trigger.js +90 -0
- package/dist/decorators/uuid.js +135 -0
- package/dist/decorators/view.js +258 -0
- package/dist/diagrams/chen-diagram.js +354 -0
- package/dist/diagrams/class-diagram.js +384 -0
- package/dist/diagrams/dependency-diagram.js +432 -0
- package/dist/diagrams/er-diagram.js +605 -0
- package/dist/diagrams/flow-diagram.js +394 -0
- package/dist/diagrams/gantt-diagram.js +411 -0
- package/dist/diagrams/index-diagram.js +353 -0
- package/dist/diagrams/index.js +184 -0
- package/dist/diagrams/migration-diagram.js +316 -0
- package/dist/diagrams/model-diagram.js +616 -0
- package/dist/diagrams/package-diagram.js +376 -0
- package/dist/diagrams/palette.js +85 -0
- package/dist/diagrams/relational-diagram.js +455 -0
- package/dist/diagrams/schemadoc-diagram.js +309 -0
- package/dist/diagrams/sequence-diagram.js +307 -0
- package/dist/diagrams/state-diagram.js +344 -0
- package/dist/diagrams/svg-dom.js +111 -0
- package/dist/diagrams/tree-diagram.js +250 -0
- package/dist/dialects/clickhouse/index.js +1742 -0
- package/dist/dialects/cockroachdb/index.js +4677 -0
- package/dist/dialects/cratedb/index.js +441 -0
- package/dist/dialects/databricks/index.js +517 -0
- package/dist/dialects/db2/index.js +2225 -0
- package/dist/dialects/dialect.js +720 -0
- package/dist/dialects/duckdb/index.js +2014 -0
- package/dist/dialects/exasol/index.js +357 -0
- package/dist/dialects/firebird/index.js +495 -0
- package/dist/dialects/greenplum/index.js +457 -0
- package/dist/dialects/hana/index.js +1741 -0
- package/dist/dialects/mariadb/index.js +3590 -0
- package/dist/dialects/mssql/index.js +2296 -0
- package/dist/dialects/mysql/index.js +4058 -0
- package/dist/dialects/oracle/index.js +2999 -0
- package/dist/dialects/postgres/index.js +5319 -0
- package/dist/dialects/query-stream-helper.js +152 -0
- package/dist/dialects/questdb/index.js +433 -0
- package/dist/dialects/redshift/index.js +2277 -0
- package/dist/dialects/singlestore/index.js +354 -0
- package/dist/dialects/snowflake/index.js +2082 -0
- package/dist/dialects/spanner/index.js +1768 -0
- package/dist/dialects/sqlite/index.js +3382 -0
- package/dist/dialects/tidb/index.js +377 -0
- package/dist/dialects/timescaledb/index.js +164 -0
- package/dist/dialects/trino/index.js +420 -0
- package/dist/dialects/turso/index.js +227 -0
- package/dist/dialects/vertica/index.js +317 -0
- package/dist/dialects/yugabytedb/index.js +424 -0
- package/dist/errors/index.js +472 -0
- package/dist/errors/utils.js +340 -0
- package/dist/errors.js +21 -0
- package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
- package/dist/extensions/catalog/mssql-features.js +147 -0
- package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
- package/dist/extensions/catalog/oracle-db2-features.js +196 -0
- package/dist/extensions/catalog/postgres-extensions.js +516 -0
- package/dist/extensions/index.js +71 -0
- package/dist/extensions/types.js +13 -0
- package/dist/foreign-data.js +173 -0
- package/dist/hooks/hooks-manager.js +350 -0
- package/dist/hooks/index.js +37 -0
- package/dist/index.js +463 -0
- package/dist/logging.js +335 -0
- package/dist/migrations/index.js +40 -0
- package/dist/migrations/migration.js +196 -0
- package/dist/migrations/migrator.js +411 -0
- package/dist/migrations/prormmigration.js +275 -0
- package/dist/migrations/query-interface.js +435 -0
- package/dist/migrations/seeder.js +353 -0
- package/dist/models/associations.js +852 -0
- package/dist/models/constraints.js +288 -0
- package/dist/models/data-types.js +2518 -0
- package/dist/models/decorators.js +445 -0
- package/dist/models/index.js +33 -0
- package/dist/models/indexes.js +531 -0
- package/dist/models/methods.js +382 -0
- package/dist/models/model-manager.js +103 -0
- package/dist/models/model.js +5349 -0
- package/dist/models/operators.js +67 -0
- package/dist/models/scopes.js +189 -0
- package/dist/models/typescript-types.js +26 -0
- package/dist/nosql/aerospike/index.js +205 -0
- package/dist/nosql/allegrograph/index.js +169 -0
- package/dist/nosql/arangodb/index.js +364 -0
- package/dist/nosql/azure-blob/index.js +206 -0
- package/dist/nosql/beanstalkd/index.js +231 -0
- package/dist/nosql/beequeue/index.js +210 -0
- package/dist/nosql/bigchaindb/index.js +195 -0
- package/dist/nosql/bigtable/index.js +224 -0
- package/dist/nosql/blazegraph/index.js +173 -0
- package/dist/nosql/bullmq/index.js +191 -0
- package/dist/nosql/cassandra/index.js +174 -0
- package/dist/nosql/chroma/index.js +190 -0
- package/dist/nosql/cloudflare-kv/index.js +220 -0
- package/dist/nosql/coherence/index.js +200 -0
- package/dist/nosql/cosmosdb/index.js +157 -0
- package/dist/nosql/couchbase/index.js +213 -0
- package/dist/nosql/dax/index.js +212 -0
- package/dist/nosql/deno-kv/index.js +206 -0
- package/dist/nosql/dgraph/index.js +171 -0
- package/dist/nosql/doris/index.js +169 -0
- package/dist/nosql/druid/index.js +162 -0
- package/dist/nosql/dynamodb/index.js +937 -0
- package/dist/nosql/elasticsearch/index.js +377 -0
- package/dist/nosql/etcd/index.js +502 -0
- package/dist/nosql/eventhubs/index.js +213 -0
- package/dist/nosql/eventstore/index.js +254 -0
- package/dist/nosql/faunadb/index.js +188 -0
- package/dist/nosql/firestore/index.js +177 -0
- package/dist/nosql/fluree/index.js +148 -0
- package/dist/nosql/fuseki/index.js +170 -0
- package/dist/nosql/gcs/index.js +172 -0
- package/dist/nosql/gearman/index.js +160 -0
- package/dist/nosql/geode/index.js +196 -0
- package/dist/nosql/graphdb/index.js +169 -0
- package/dist/nosql/graylog/index.js +188 -0
- package/dist/nosql/gridgain/index.js +171 -0
- package/dist/nosql/hazelcast/index.js +162 -0
- package/dist/nosql/hbase/index.js +230 -0
- package/dist/nosql/ignite/index.js +173 -0
- package/dist/nosql/immudb/index.js +184 -0
- package/dist/nosql/index.js +232 -0
- package/dist/nosql/infinispan/index.js +200 -0
- package/dist/nosql/influxdb/index.js +0 -0
- package/dist/nosql/kafka/index.js +234 -0
- package/dist/nosql/keyspaces/index.js +189 -0
- package/dist/nosql/kinesis/index.js +253 -0
- package/dist/nosql/leveldb/index.js +153 -0
- package/dist/nosql/lmdb/index.js +160 -0
- package/dist/nosql/loki/index.js +201 -0
- package/dist/nosql/marklogic/index.js +204 -0
- package/dist/nosql/materialize/index.js +145 -0
- package/dist/nosql/meilisearch/index.js +154 -0
- package/dist/nosql/memcached/index.js +223 -0
- package/dist/nosql/milvus/index.js +410 -0
- package/dist/nosql/minio/index.js +265 -0
- package/dist/nosql/momento/index.js +179 -0
- package/dist/nosql/mongodb/index.js +461 -0
- package/dist/nosql/nats/index.js +247 -0
- package/dist/nosql/nedb/index.js +164 -0
- package/dist/nosql/neo4j/index.js +450 -0
- package/dist/nosql/neptune/index.js +470 -0
- package/dist/nosql/nsq/index.js +200 -0
- package/dist/nosql/opensearch/index.js +186 -0
- package/dist/nosql/orientdb/index.js +175 -0
- package/dist/nosql/papertrail/index.js +200 -0
- package/dist/nosql/pinecone/index.js +0 -0
- package/dist/nosql/pinot/index.js +133 -0
- package/dist/nosql/pouchdb/index.js +172 -0
- package/dist/nosql/prometheus/index.js +174 -0
- package/dist/nosql/provendb/index.js +147 -0
- package/dist/nosql/pubsub/index.js +187 -0
- package/dist/nosql/pulsar/index.js +232 -0
- package/dist/nosql/qdrant/index.js +295 -0
- package/dist/nosql/qldb/index.js +192 -0
- package/dist/nosql/r2/index.js +281 -0
- package/dist/nosql/rabbitmq/index.js +237 -0
- package/dist/nosql/ravendb/index.js +175 -0
- package/dist/nosql/redis/index.js +607 -0
- package/dist/nosql/redpanda/index.js +237 -0
- package/dist/nosql/resque/index.js +203 -0
- package/dist/nosql/rethinkdb/index.js +232 -0
- package/dist/nosql/rocksdb/index.js +152 -0
- package/dist/nosql/rockset/index.js +126 -0
- package/dist/nosql/s3/index.js +298 -0
- package/dist/nosql/scylladb/index.js +178 -0
- package/dist/nosql/signoz/index.js +227 -0
- package/dist/nosql/sns/index.js +201 -0
- package/dist/nosql/solr/index.js +231 -0
- package/dist/nosql/splunk/index.js +227 -0
- package/dist/nosql/sqs/index.js +246 -0
- package/dist/nosql/stardog/index.js +169 -0
- package/dist/nosql/starrocks/index.js +170 -0
- package/dist/nosql/store.js +2 -0
- package/dist/nosql/sumologic/index.js +213 -0
- package/dist/nosql/surrealdb/index.js +179 -0
- package/dist/nosql/terminusdb/index.js +151 -0
- package/dist/nosql/tigergraph/index.js +469 -0
- package/dist/nosql/typesense/index.js +148 -0
- package/dist/nosql/unqlite/index.js +157 -0
- package/dist/nosql/upstash/index.js +167 -0
- package/dist/nosql/vercel-kv/index.js +166 -0
- package/dist/nosql/victoriametrics/index.js +213 -0
- package/dist/nosql/virtuoso/index.js +169 -0
- package/dist/nosql/weaviate/index.js +276 -0
- package/dist/operators/index.js +108 -0
- package/dist/operators.js +2690 -0
- package/dist/prisma-migrate/index.js +38 -0
- package/dist/prisma-migrate/migration-generator.js +125 -0
- package/dist/prisma-migrate/model-generator.js +172 -0
- package/dist/prisma-migrate/relations.js +100 -0
- package/dist/prisma-migrate/schema-parser.js +167 -0
- package/dist/prisma-migrate/type-mapper.js +40 -0
- package/dist/prorm.js +6832 -0
- package/dist/query-builders/cte-builder.js +80 -0
- package/dist/query-builders/functions/aggregate.js +390 -0
- package/dist/query-builders/functions/conditional.js +503 -0
- package/dist/query-builders/functions/datetime.js +695 -0
- package/dist/query-builders/functions/fulltext.js +439 -0
- package/dist/query-builders/functions/index.js +93 -0
- package/dist/query-builders/functions/json.js +427 -0
- package/dist/query-builders/functions/math.js +399 -0
- package/dist/query-builders/functions/string.js +518 -0
- package/dist/query-builders/functions/window.js +328 -0
- package/dist/query-builders/include-builder.js +323 -0
- package/dist/query-builders/index-expression-builder.js +242 -0
- package/dist/query-builders/index.js +161 -0
- package/dist/query-builders/insert-builder.js +164 -0
- package/dist/query-builders/model-helpers.js +38 -0
- package/dist/query-builders/order-limit-builder.js +239 -0
- package/dist/query-builders/sql-compiler.js +2040 -0
- package/dist/query-builders/subquery-builder.js +152 -0
- package/dist/query-builders/update-builder.js +182 -0
- package/dist/query-builders/view-builder.js +218 -0
- package/dist/query-builders/where-builder.js +1532 -0
- package/dist/query-interface.js +622 -0
- package/dist/query-optimizers/batch-optimizer.js +426 -0
- package/dist/query-optimizers/explain-plans.js +415 -0
- package/dist/query-optimizers/index.js +51 -0
- package/dist/query-optimizers/prepared-statement-cache.js +423 -0
- package/dist/query-optimizers/query-hints.js +438 -0
- package/dist/query-optimizers/query-optimizer.js +278 -0
- package/dist/query-optimizers/slow-query-logger.js +271 -0
- package/dist/replica-manager.js +507 -0
- package/dist/schema/index.js +15 -0
- package/dist/schema/migration-generator.js +374 -0
- package/dist/schema/schema-differ.js +549 -0
- package/dist/schema/types.js +6 -0
- package/dist/sql-constants.js +300 -0
- package/dist/sqlite-advanced.js +1047 -0
- package/dist/streams/index.js +12 -0
- package/dist/streams/transforms.js +178 -0
- package/dist/transaction.js +456 -0
- package/dist/types/index.js +180 -0
- package/dist/user-management.js +127 -0
- package/dist/utils/date.js +300 -0
- package/dist/utils/index.js +1079 -0
- package/dist/utils/string.js +161 -0
- package/dist/validators/index.js +19 -0
- package/dist/validators/validator.js +911 -0
- package/package.json +190 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventHubsStore = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Azure Event Hubs store.
|
|
6
|
+
*
|
|
7
|
+
* Event Hubs is a managed, partitioned event-ingestion / event-streaming
|
|
8
|
+
* service (Azure's Kafka-like offering). It has no query language and no
|
|
9
|
+
* SQL-shaped access pattern, so this store implements the minimal `NoSqlStore`
|
|
10
|
+
* marker interface (`src/nosql/store.ts`) and exposes Event Hubs's real
|
|
11
|
+
* operations: sending event batches to a hub (`publish`) and subscribing a
|
|
12
|
+
* consumer to receive events (`subscribe`).
|
|
13
|
+
*
|
|
14
|
+
* Built on `@azure/event-hubs`: an `EventHubProducerClient` sends events
|
|
15
|
+
* (`sendBatch`) and an `EventHubConsumerClient` receives them (`subscribe`).
|
|
16
|
+
* The driver is loaded lazily inside `connect()` via `require` so importing
|
|
17
|
+
* this module never hard-requires it, and tests inject a mock module through
|
|
18
|
+
* the `client` option (an object exposing `EventHubProducerClient` and
|
|
19
|
+
* `EventHubConsumerClient` constructors) so no real driver or network is used.
|
|
20
|
+
*
|
|
21
|
+
* Message encoding: `publish()` accepts a `string` or `Buffer` (used as the
|
|
22
|
+
* event `body` unchanged) or any other JSON-serializable value (`JSON.stringify`d
|
|
23
|
+
* to a string body). Event Hubs itself AMQP-encodes the body on the wire.
|
|
24
|
+
*
|
|
25
|
+
* Note: Event Hubs (namespaces / hubs) are provisioned via the Azure
|
|
26
|
+
* management plane (ARM / portal / CLI), not the data-plane SDK, so this store
|
|
27
|
+
* intentionally does not expose a `createTopic`.
|
|
28
|
+
*/
|
|
29
|
+
const errors_1 = require("../../errors");
|
|
30
|
+
/** Encode a message into the `body` Event Hubs sends (string/Buffer as-is, else JSON string). */
|
|
31
|
+
function toBody(message) {
|
|
32
|
+
if (Buffer.isBuffer(message))
|
|
33
|
+
return message;
|
|
34
|
+
if (typeof message === 'string')
|
|
35
|
+
return message;
|
|
36
|
+
return JSON.stringify(message);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `EventHubsStore` wraps `@azure/event-hubs` producer/consumer clients and
|
|
40
|
+
* exposes event publishing and consumer subscriptions.
|
|
41
|
+
*/
|
|
42
|
+
class EventHubsStore {
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
this.name = 'eventhubs';
|
|
45
|
+
this.library = '@azure/event-hubs';
|
|
46
|
+
this.azure = null;
|
|
47
|
+
this.producer = null;
|
|
48
|
+
/** Producers cached by event hub name (the default hub plus any others used). */
|
|
49
|
+
this.producers = new Map();
|
|
50
|
+
/** Active consumer subscriptions, tracked so `disconnect()` can close them. */
|
|
51
|
+
this.consumers = new Set();
|
|
52
|
+
this.connected = false;
|
|
53
|
+
this.options = options;
|
|
54
|
+
}
|
|
55
|
+
// ---------------------------------------------------------------------
|
|
56
|
+
// Lifecycle
|
|
57
|
+
// ---------------------------------------------------------------------
|
|
58
|
+
async connect() {
|
|
59
|
+
if (this.connected && this.azure)
|
|
60
|
+
return;
|
|
61
|
+
try {
|
|
62
|
+
this.azure = this.options.client ?? require('@azure/event-hubs');
|
|
63
|
+
this.connected = true;
|
|
64
|
+
if (this.options.eventHubName) {
|
|
65
|
+
this.producer = this.producerFor(this.options.eventHubName);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
this.azure = null;
|
|
70
|
+
this.producer = null;
|
|
71
|
+
this.connected = false;
|
|
72
|
+
throw new errors_1.ConnectionError(`Failed to connect to Event Hubs: ${err instanceof Error ? err.message : String(err)}`, { parent: err instanceof Error ? err : undefined, database: 'eventhubs' });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async disconnect() {
|
|
76
|
+
for (const consumer of this.consumers) {
|
|
77
|
+
try {
|
|
78
|
+
await consumer.close();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Best-effort teardown.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
this.consumers.clear();
|
|
85
|
+
for (const producer of this.producers.values()) {
|
|
86
|
+
try {
|
|
87
|
+
await producer.close?.();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Best-effort teardown.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.producers.clear();
|
|
94
|
+
this.producer = null;
|
|
95
|
+
this.azure = null;
|
|
96
|
+
this.connected = false;
|
|
97
|
+
}
|
|
98
|
+
isConnected() {
|
|
99
|
+
return this.connected && this.azure !== null;
|
|
100
|
+
}
|
|
101
|
+
/** Returns the underlying default `EventHubProducerClient` for anything not wrapped here. */
|
|
102
|
+
getClient() {
|
|
103
|
+
if (!this.connected || !this.azure) {
|
|
104
|
+
throw new errors_1.ConnectionError('Event Hubs is not connected. Call connect() first.', {
|
|
105
|
+
database: 'eventhubs',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return this.producerFor(this.options.eventHubName);
|
|
109
|
+
}
|
|
110
|
+
requireModule() {
|
|
111
|
+
if (!this.connected || !this.azure) {
|
|
112
|
+
throw new errors_1.ConnectionError('Event Hubs is not connected. Call connect() first.', {
|
|
113
|
+
database: 'eventhubs',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return this.azure;
|
|
117
|
+
}
|
|
118
|
+
/** Resolve (and cache) a producer for a given event hub name. */
|
|
119
|
+
producerFor(eventHubName) {
|
|
120
|
+
const azure = this.requireModule();
|
|
121
|
+
const hub = eventHubName ?? this.options.eventHubName ?? '';
|
|
122
|
+
const cached = this.producers.get(hub);
|
|
123
|
+
if (cached)
|
|
124
|
+
return cached;
|
|
125
|
+
const producer = new azure.EventHubProducerClient(this.options.connectionString, hub || undefined);
|
|
126
|
+
this.producers.set(hub, producer);
|
|
127
|
+
return producer;
|
|
128
|
+
}
|
|
129
|
+
wrapError(action, err) {
|
|
130
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
131
|
+
return new errors_1.DatabaseError(`Event Hubs ${action} failed: ${parent.message}`, {
|
|
132
|
+
parent,
|
|
133
|
+
original: parent.message,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// ---------------------------------------------------------------------
|
|
137
|
+
// Producing
|
|
138
|
+
// ---------------------------------------------------------------------
|
|
139
|
+
/**
|
|
140
|
+
* Send one `message` to `eventHubName` (or the store's default hub) as a
|
|
141
|
+
* single-event batch via `EventHubProducerClient.sendBatch`. The message is
|
|
142
|
+
* encoded per the module's rules (string/Buffer as-is, else JSON string).
|
|
143
|
+
*/
|
|
144
|
+
async publish(eventHubName, message) {
|
|
145
|
+
const producer = this.producerFor(eventHubName);
|
|
146
|
+
try {
|
|
147
|
+
await producer.sendBatch([{ body: toBody(message) }]);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
throw this.wrapError(`publish to '${eventHubName}'`, err);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------------
|
|
154
|
+
// Consuming
|
|
155
|
+
// ---------------------------------------------------------------------
|
|
156
|
+
/**
|
|
157
|
+
* Subscribe a new `EventHubConsumerClient` to `eventHubName`, invoking
|
|
158
|
+
* `handler` once per received event. Returns a subscription whose `stop()`
|
|
159
|
+
* closes both the underlying subscription and consumer client; the
|
|
160
|
+
* subscription is tracked so `disconnect()` closes it too.
|
|
161
|
+
*/
|
|
162
|
+
async subscribe(eventHubName, handler, options = {}) {
|
|
163
|
+
const azure = this.requireModule();
|
|
164
|
+
const consumerGroup = options.consumerGroup ?? this.options.consumerGroup ?? '$Default';
|
|
165
|
+
let consumer;
|
|
166
|
+
try {
|
|
167
|
+
consumer = new azure.EventHubConsumerClient(consumerGroup, this.options.connectionString, eventHubName);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
throw this.wrapError(`subscribe to '${eventHubName}'`, err);
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const handle = consumer.subscribe({
|
|
174
|
+
processEvents: async (events) => {
|
|
175
|
+
for (const event of events ?? []) {
|
|
176
|
+
await handler(event);
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
processError: async () => {
|
|
180
|
+
/* swallow — surface via the raw client if needed */
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
const tracked = {
|
|
184
|
+
async close() {
|
|
185
|
+
try {
|
|
186
|
+
await handle.close();
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
await consumer.close?.();
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
this.consumers.add(tracked);
|
|
194
|
+
return {
|
|
195
|
+
stop: async () => {
|
|
196
|
+
this.consumers.delete(tracked);
|
|
197
|
+
await tracked.close();
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
try {
|
|
203
|
+
await consumer.close?.();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Don't leak the half-set-up consumer.
|
|
207
|
+
}
|
|
208
|
+
throw this.wrapError(`subscribe to '${eventHubName}'`, err);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.EventHubsStore = EventHubsStore;
|
|
213
|
+
exports.default = EventHubsStore;
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventStoreStore = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* EventStoreDB (Kurrent) store.
|
|
6
|
+
*
|
|
7
|
+
* EventStoreDB is a purpose-built database for event sourcing: an append-only
|
|
8
|
+
* log of immutable events organized into streams, with catch-up and persistent
|
|
9
|
+
* subscriptions for reading them back. It has no SQL-shaped access pattern, so
|
|
10
|
+
* this store implements the minimal `NoSqlStore` marker interface
|
|
11
|
+
* (`src/nosql/store.ts`) and exposes EventStoreDB's real operations: appending
|
|
12
|
+
* an event to a stream (`publish`), a catch-up subscription that delivers
|
|
13
|
+
* events to a handler (`subscribe`), and reading a stream back (`readStream`).
|
|
14
|
+
*
|
|
15
|
+
* Built on `@eventstore/db-client`: an `EventStoreDBClient` appends
|
|
16
|
+
* (`appendToStream`), subscribes (`subscribeToStream`), and reads
|
|
17
|
+
* (`readStream`); the module's `jsonEvent(...)` helper builds event payloads.
|
|
18
|
+
* The driver is loaded lazily inside `connect()` via `require` so importing
|
|
19
|
+
* this module never hard-requires it, and tests inject a mock client through
|
|
20
|
+
* the `client` option so no real driver or network is used.
|
|
21
|
+
*
|
|
22
|
+
* Streams are created implicitly by the first append, so `createStream()` is a
|
|
23
|
+
* documented no-op that resolves without contacting the server.
|
|
24
|
+
*
|
|
25
|
+
* Message encoding: `publish()` accepts a `string` or `Buffer` (parsed as JSON
|
|
26
|
+
* when possible, otherwise wrapped as `{ value }`) or any other value (used as
|
|
27
|
+
* the event `data` directly). Each event is written as a JSON event with a
|
|
28
|
+
* caller-supplied `type` (default `'message'`).
|
|
29
|
+
*/
|
|
30
|
+
const errors_1 = require("../../errors");
|
|
31
|
+
/** Build the JSON-event payload for an append, using the driver's `jsonEvent` when available. */
|
|
32
|
+
function buildEvent(esdb, message, options) {
|
|
33
|
+
const type = options.type ?? 'message';
|
|
34
|
+
let data;
|
|
35
|
+
if (typeof message === 'string' || Buffer.isBuffer(message)) {
|
|
36
|
+
const text = message.toString();
|
|
37
|
+
try {
|
|
38
|
+
data = JSON.parse(text);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
data = { value: text };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
data = message;
|
|
46
|
+
}
|
|
47
|
+
const spec = { type, data, metadata: options.metadata, id: options.id };
|
|
48
|
+
if (esdb && typeof esdb.jsonEvent === 'function') {
|
|
49
|
+
return esdb.jsonEvent(spec);
|
|
50
|
+
}
|
|
51
|
+
// Fallback when the real driver isn't loaded (e.g. tests inject a client but
|
|
52
|
+
// not the module): a plain JSON-event-shaped object.
|
|
53
|
+
return { ...spec, contentType: 'application/json' };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* `EventStoreStore` wraps an `@eventstore/db-client` `EventStoreDBClient` and
|
|
57
|
+
* exposes appending events, catch-up subscriptions, and stream reads.
|
|
58
|
+
*/
|
|
59
|
+
class EventStoreStore {
|
|
60
|
+
constructor(options = {}) {
|
|
61
|
+
this.name = 'eventstore';
|
|
62
|
+
this.library = '@eventstore/db-client';
|
|
63
|
+
this.client = null;
|
|
64
|
+
this.esdb = null;
|
|
65
|
+
this.connected = false;
|
|
66
|
+
/** Active subscriptions, tracked so `disconnect()` can end them. */
|
|
67
|
+
this.subscriptions = new Set();
|
|
68
|
+
this.options = options;
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------
|
|
71
|
+
// Lifecycle
|
|
72
|
+
// ---------------------------------------------------------------------
|
|
73
|
+
async connect() {
|
|
74
|
+
if (this.connected && this.client)
|
|
75
|
+
return;
|
|
76
|
+
try {
|
|
77
|
+
if (this.options.client) {
|
|
78
|
+
this.client = this.options.client;
|
|
79
|
+
this.tryLoadSdk();
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const esdb = require('@eventstore/db-client');
|
|
83
|
+
this.esdb = esdb;
|
|
84
|
+
this.client = esdb.EventStoreDBClient.connectionString(this.options.connectionString ?? 'esdb://localhost:2113?tls=false');
|
|
85
|
+
}
|
|
86
|
+
this.connected = true;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
this.client = null;
|
|
90
|
+
this.esdb = null;
|
|
91
|
+
this.connected = false;
|
|
92
|
+
throw new errors_1.ConnectionError(`Failed to connect to EventStoreDB: ${err instanceof Error ? err.message : String(err)}`, { parent: err instanceof Error ? err : undefined, database: 'eventstore' });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
tryLoadSdk() {
|
|
96
|
+
if (this.esdb)
|
|
97
|
+
return;
|
|
98
|
+
try {
|
|
99
|
+
this.esdb = require('@eventstore/db-client');
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
this.esdb = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async disconnect() {
|
|
106
|
+
for (const sub of this.subscriptions) {
|
|
107
|
+
try {
|
|
108
|
+
sub.stop();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Best-effort teardown.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this.subscriptions.clear();
|
|
115
|
+
try {
|
|
116
|
+
await this.client?.dispose?.();
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
this.client = null;
|
|
120
|
+
this.esdb = null;
|
|
121
|
+
this.connected = false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
isConnected() {
|
|
125
|
+
return this.connected && this.client !== null;
|
|
126
|
+
}
|
|
127
|
+
/** Returns the underlying `EventStoreDBClient` for anything not wrapped here. */
|
|
128
|
+
getClient() {
|
|
129
|
+
return this.requireClient();
|
|
130
|
+
}
|
|
131
|
+
requireClient() {
|
|
132
|
+
if (!this.client || !this.connected) {
|
|
133
|
+
throw new errors_1.ConnectionError('EventStoreDB client is not connected. Call connect() first.', {
|
|
134
|
+
database: 'eventstore',
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return this.client;
|
|
138
|
+
}
|
|
139
|
+
wrapError(action, err) {
|
|
140
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
141
|
+
return new errors_1.DatabaseError(`EventStoreDB ${action} failed: ${parent.message}`, {
|
|
142
|
+
parent,
|
|
143
|
+
original: parent.message,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// ---------------------------------------------------------------------
|
|
147
|
+
// Producing
|
|
148
|
+
// ---------------------------------------------------------------------
|
|
149
|
+
/**
|
|
150
|
+
* Append one event carrying `message` to `stream` via `appendToStream`. The
|
|
151
|
+
* message is turned into a JSON event (`jsonEvent`) with `options.type`
|
|
152
|
+
* (default 'message'). Returns the driver's append result (next expected
|
|
153
|
+
* revision, etc.).
|
|
154
|
+
*/
|
|
155
|
+
async publish(stream, message, options = {}) {
|
|
156
|
+
const client = this.requireClient();
|
|
157
|
+
const event = buildEvent(this.esdb, message, options);
|
|
158
|
+
try {
|
|
159
|
+
return await client.appendToStream(stream, event, options.expectedRevision !== undefined
|
|
160
|
+
? { expectedRevision: options.expectedRevision }
|
|
161
|
+
: undefined);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
throw this.wrapError(`append to stream '${stream}'`, err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// ---------------------------------------------------------------------
|
|
168
|
+
// Stream administration
|
|
169
|
+
// ---------------------------------------------------------------------
|
|
170
|
+
/**
|
|
171
|
+
* Streams are created implicitly by the first append in EventStoreDB, so this
|
|
172
|
+
* is a documented no-op that resolves without contacting the server. Provided
|
|
173
|
+
* to satisfy the common store surface (alias `createTopic`).
|
|
174
|
+
*/
|
|
175
|
+
async createStream(_name) {
|
|
176
|
+
this.requireClient();
|
|
177
|
+
// Intentional no-op: EventStoreDB has no explicit stream-creation API.
|
|
178
|
+
}
|
|
179
|
+
/** Alias for `createStream()`, matching the common store surface. */
|
|
180
|
+
createTopic(name) {
|
|
181
|
+
return this.createStream(name);
|
|
182
|
+
}
|
|
183
|
+
// ---------------------------------------------------------------------
|
|
184
|
+
// Reading
|
|
185
|
+
// ---------------------------------------------------------------------
|
|
186
|
+
/**
|
|
187
|
+
* Read events from `stream` into an array by draining the driver's async
|
|
188
|
+
* iterable. Options (`fromRevision`, `maxCount`, `direction`, ...) are passed
|
|
189
|
+
* straight through.
|
|
190
|
+
*/
|
|
191
|
+
async readStream(stream, options) {
|
|
192
|
+
const client = this.requireClient();
|
|
193
|
+
try {
|
|
194
|
+
const events = [];
|
|
195
|
+
for await (const resolved of client.readStream(stream, options)) {
|
|
196
|
+
events.push(resolved);
|
|
197
|
+
}
|
|
198
|
+
return events;
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
throw this.wrapError(`read stream '${stream}'`, err);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ---------------------------------------------------------------------
|
|
205
|
+
// Consuming
|
|
206
|
+
// ---------------------------------------------------------------------
|
|
207
|
+
/**
|
|
208
|
+
* Subscribe to `stream` with a catch-up subscription (`subscribeToStream`),
|
|
209
|
+
* invoking `handler` once per resolved event. Returns a subscription whose
|
|
210
|
+
* `stop()` ends it; it is tracked so `disconnect()` ends it too. The
|
|
211
|
+
* consuming loop runs detached (not awaited); this method resolves once the
|
|
212
|
+
* subscription is opened.
|
|
213
|
+
*/
|
|
214
|
+
async subscribe(stream, handler, options = {}) {
|
|
215
|
+
const client = this.requireClient();
|
|
216
|
+
let iterable;
|
|
217
|
+
try {
|
|
218
|
+
iterable = client.subscribeToStream(stream, {
|
|
219
|
+
fromRevision: options.fromRevision ?? 'end',
|
|
220
|
+
resolveLinkTos: options.resolveLinkTos,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
throw this.wrapError(`subscribe to stream '${stream}'`, err);
|
|
225
|
+
}
|
|
226
|
+
let stopped = false;
|
|
227
|
+
const subscription = {
|
|
228
|
+
stop: () => {
|
|
229
|
+
stopped = true;
|
|
230
|
+
this.subscriptions.delete(subscription);
|
|
231
|
+
try {
|
|
232
|
+
iterable.unsubscribe?.();
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Best-effort.
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
this.subscriptions.add(subscription);
|
|
240
|
+
const loop = async () => {
|
|
241
|
+
for await (const resolved of iterable) {
|
|
242
|
+
if (stopped)
|
|
243
|
+
break;
|
|
244
|
+
await handler(resolved);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
loop().catch(() => {
|
|
248
|
+
/* swallow — best-effort background consuming */
|
|
249
|
+
});
|
|
250
|
+
return subscription;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.EventStoreStore = EventStoreStore;
|
|
254
|
+
exports.default = EventStoreStore;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FaunaDB store implementation for the Prorm NoSQL layer.
|
|
4
|
+
*
|
|
5
|
+
* Fauna is a multi-model, distributed database (document, relational, graph)
|
|
6
|
+
* driven by FQL - a functional query language expressed as composed function
|
|
7
|
+
* calls rather than SQL strings. It does not fit the SQL-shaped `Dialect`
|
|
8
|
+
* interface, so this class implements the minimal `NoSqlStore` marker
|
|
9
|
+
* interface for connection lifecycle and otherwise exposes Fauna's real
|
|
10
|
+
* document CRUD (built from FQL expressions) plus a raw FQL `query` escape
|
|
11
|
+
* hatch.
|
|
12
|
+
*
|
|
13
|
+
* Uses the official `faunadb` 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 `client`
|
|
16
|
+
* (and FQL builder `q`) via options, 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.FaunaDbStore = void 0;
|
|
21
|
+
const errors_1 = require("../../errors");
|
|
22
|
+
class FaunaDbStore {
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.name = 'faunadb';
|
|
25
|
+
this.library = 'faunadb';
|
|
26
|
+
this.client = null;
|
|
27
|
+
this.q = null;
|
|
28
|
+
this.connected = false;
|
|
29
|
+
this.options = options;
|
|
30
|
+
}
|
|
31
|
+
// ---------------------------------------------------------------------
|
|
32
|
+
// Connection lifecycle
|
|
33
|
+
// ---------------------------------------------------------------------
|
|
34
|
+
async connect() {
|
|
35
|
+
if (this.connected && this.client) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
if (this.options.client) {
|
|
40
|
+
this.client = this.options.client;
|
|
41
|
+
this.q = this.options.q ?? this.tryRequireQuery();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
45
|
+
const fauna = require('faunadb');
|
|
46
|
+
this.client = new fauna.Client({
|
|
47
|
+
secret: this.options.secret,
|
|
48
|
+
domain: this.options.domain,
|
|
49
|
+
});
|
|
50
|
+
this.q = this.options.q ?? fauna.query;
|
|
51
|
+
}
|
|
52
|
+
this.connected = true;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
this.client = null;
|
|
56
|
+
this.q = null;
|
|
57
|
+
this.connected = false;
|
|
58
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
59
|
+
throw new errors_1.ConnectionError(`Unable to connect to FaunaDB: ${parent.message}`, {
|
|
60
|
+
parent,
|
|
61
|
+
database: 'faunadb',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
tryRequireQuery() {
|
|
66
|
+
try {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
68
|
+
return require('faunadb').query;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async disconnect() {
|
|
75
|
+
if (this.client && typeof this.client.close === 'function') {
|
|
76
|
+
try {
|
|
77
|
+
this.client.close();
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// ignore close errors; the reference is dropped below regardless.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.client = null;
|
|
84
|
+
this.q = null;
|
|
85
|
+
this.connected = false;
|
|
86
|
+
}
|
|
87
|
+
isConnected() {
|
|
88
|
+
return this.connected && this.client !== null;
|
|
89
|
+
}
|
|
90
|
+
getClient() {
|
|
91
|
+
return this.requireClient();
|
|
92
|
+
}
|
|
93
|
+
requireClient() {
|
|
94
|
+
if (!this.client || !this.connected) {
|
|
95
|
+
throw new errors_1.ConnectionError('Not connected to FaunaDB. Call connect() first.', {
|
|
96
|
+
database: 'faunadb',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return this.client;
|
|
100
|
+
}
|
|
101
|
+
requireQuery() {
|
|
102
|
+
const q = this.q;
|
|
103
|
+
if (!q) {
|
|
104
|
+
throw new errors_1.ConnectionError('FaunaDB FQL builder unavailable. Call connect() first.', {
|
|
105
|
+
database: 'faunadb',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return q;
|
|
109
|
+
}
|
|
110
|
+
// ---------------------------------------------------------------------
|
|
111
|
+
// Document CRUD (FQL)
|
|
112
|
+
// ---------------------------------------------------------------------
|
|
113
|
+
/** Create a document in `collection`; returns the new document's id. */
|
|
114
|
+
async insert(collection, doc) {
|
|
115
|
+
const client = this.requireClient();
|
|
116
|
+
const q = this.requireQuery();
|
|
117
|
+
try {
|
|
118
|
+
const result = await client.query(q.Create(q.Collection(collection), { data: doc }));
|
|
119
|
+
return result?.ref?.id ?? result?.data?.id;
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
throw wrapDatabaseError(err, 'FaunaDB insert failed');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** Fetch a document by id, returning its `data`. */
|
|
126
|
+
async get(collection, id) {
|
|
127
|
+
const client = this.requireClient();
|
|
128
|
+
const q = this.requireQuery();
|
|
129
|
+
try {
|
|
130
|
+
const result = await client.query(q.Get(q.Ref(q.Collection(collection), id)));
|
|
131
|
+
return result?.data;
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
throw wrapDatabaseError(err, 'FaunaDB get failed');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Merge `patch` into a document's `data`, returning the updated data. */
|
|
138
|
+
async update(collection, id, patch) {
|
|
139
|
+
const client = this.requireClient();
|
|
140
|
+
const q = this.requireQuery();
|
|
141
|
+
try {
|
|
142
|
+
const result = await client.query(q.Update(q.Ref(q.Collection(collection), id), { data: patch }));
|
|
143
|
+
return result?.data;
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
throw wrapDatabaseError(err, 'FaunaDB update failed');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Delete a document by id. */
|
|
150
|
+
async delete(collection, id) {
|
|
151
|
+
const client = this.requireClient();
|
|
152
|
+
const q = this.requireQuery();
|
|
153
|
+
try {
|
|
154
|
+
return await client.query(q.Delete(q.Ref(q.Collection(collection), id)));
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
throw wrapDatabaseError(err, 'FaunaDB delete failed');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Run an FQL query. When `expr` is provided it is executed directly;
|
|
162
|
+
* otherwise all documents in `collection` are paginated and dereferenced.
|
|
163
|
+
* Returns the query's `data` array.
|
|
164
|
+
*/
|
|
165
|
+
async query(collection, expr) {
|
|
166
|
+
const client = this.requireClient();
|
|
167
|
+
const q = this.requireQuery();
|
|
168
|
+
try {
|
|
169
|
+
const query = expr !== undefined
|
|
170
|
+
? expr
|
|
171
|
+
: q.Map(q.Paginate(q.Documents(q.Collection(collection))), q.Lambda('ref', q.Get(q.Var('ref'))));
|
|
172
|
+
const result = await client.query(query);
|
|
173
|
+
return result?.data ?? [];
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
throw wrapDatabaseError(err, 'FaunaDB query failed');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.FaunaDbStore = FaunaDbStore;
|
|
181
|
+
function wrapDatabaseError(err, message) {
|
|
182
|
+
if (err instanceof errors_1.ConnectionError) {
|
|
183
|
+
return err;
|
|
184
|
+
}
|
|
185
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
186
|
+
return errors_1.DatabaseError.from(parent, { message: `${message}: ${parent.message}` });
|
|
187
|
+
}
|
|
188
|
+
exports.default = FaunaDbStore;
|