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,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PubSubStore = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Google Cloud Pub/Sub store.
|
|
6
|
+
*
|
|
7
|
+
* Pub/Sub is a managed, topic-and-subscription messaging service. It has no
|
|
8
|
+
* query language and no SQL-shaped access pattern, so this store implements the
|
|
9
|
+
* minimal `NoSqlStore` marker interface (`src/nosql/store.ts`) and exposes
|
|
10
|
+
* Pub/Sub's real operations: publishing messages to a topic (`publish`),
|
|
11
|
+
* receiving messages on a subscription via an event listener (`subscribe`), and
|
|
12
|
+
* topic/subscription administration (`createTopic`, `createSubscription`).
|
|
13
|
+
*
|
|
14
|
+
* Built on `@google-cloud/pubsub`: `new PubSub()` yields a client whose
|
|
15
|
+
* `topic(name).publishMessage(...)` publishes and whose
|
|
16
|
+
* `subscription(name).on('message', ...)` streams messages. The driver is
|
|
17
|
+
* loaded lazily inside `connect()` via `require`, and tests inject a mock
|
|
18
|
+
* client through the `client` option so no real driver or network is used.
|
|
19
|
+
*
|
|
20
|
+
* Message encoding: `publish()` accepts a `string` (UTF-8 encoded), a `Buffer`
|
|
21
|
+
* (sent as-is), or any other JSON-serializable value (`JSON.stringify`d then
|
|
22
|
+
* UTF-8 encoded). The bytes become the message `data`.
|
|
23
|
+
*/
|
|
24
|
+
const errors_1 = require("../../errors");
|
|
25
|
+
/** Encode a message into the `Buffer` Pub/Sub carries as message `data`. */
|
|
26
|
+
function toData(message) {
|
|
27
|
+
if (Buffer.isBuffer(message))
|
|
28
|
+
return message;
|
|
29
|
+
if (typeof message === 'string')
|
|
30
|
+
return Buffer.from(message, 'utf8');
|
|
31
|
+
return Buffer.from(JSON.stringify(message), 'utf8');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `PubSubStore` wraps a `@google-cloud/pubsub` client and exposes topic
|
|
35
|
+
* publishing, subscription listening, and topic/subscription administration.
|
|
36
|
+
*/
|
|
37
|
+
class PubSubStore {
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
this.name = 'pubsub';
|
|
40
|
+
this.library = '@google-cloud/pubsub';
|
|
41
|
+
this.client = null;
|
|
42
|
+
this.connected = false;
|
|
43
|
+
/** Subscription objects that have live listeners, tracked for `disconnect()`. */
|
|
44
|
+
this.subscriptions = new Set();
|
|
45
|
+
this.options = options;
|
|
46
|
+
}
|
|
47
|
+
// ---------------------------------------------------------------------
|
|
48
|
+
// Lifecycle
|
|
49
|
+
// ---------------------------------------------------------------------
|
|
50
|
+
async connect() {
|
|
51
|
+
if (this.connected && this.client)
|
|
52
|
+
return;
|
|
53
|
+
try {
|
|
54
|
+
if (this.options.client) {
|
|
55
|
+
this.client = this.options.client;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const { PubSub } = require('@google-cloud/pubsub');
|
|
59
|
+
this.client = new PubSub({
|
|
60
|
+
projectId: this.options.projectId,
|
|
61
|
+
keyFilename: this.options.keyFilename,
|
|
62
|
+
apiEndpoint: this.options.apiEndpoint,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
this.connected = true;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
this.client = null;
|
|
69
|
+
this.connected = false;
|
|
70
|
+
throw new errors_1.ConnectionError(`Failed to connect to Pub/Sub: ${err instanceof Error ? err.message : String(err)}`, { parent: err instanceof Error ? err : undefined, database: 'pubsub' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async disconnect() {
|
|
74
|
+
for (const subscription of this.subscriptions) {
|
|
75
|
+
try {
|
|
76
|
+
subscription.removeAllListeners?.();
|
|
77
|
+
await subscription.close?.();
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Best-effort teardown.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.subscriptions.clear();
|
|
84
|
+
try {
|
|
85
|
+
await this.client?.close?.();
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
this.client = null;
|
|
89
|
+
this.connected = false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
isConnected() {
|
|
93
|
+
return this.connected && this.client !== null;
|
|
94
|
+
}
|
|
95
|
+
/** Returns the underlying `PubSub` client for anything not wrapped here. */
|
|
96
|
+
getClient() {
|
|
97
|
+
return this.requireClient();
|
|
98
|
+
}
|
|
99
|
+
requireClient() {
|
|
100
|
+
if (!this.client || !this.connected) {
|
|
101
|
+
throw new errors_1.ConnectionError('Pub/Sub client is not connected. Call connect() first.', {
|
|
102
|
+
database: 'pubsub',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return this.client;
|
|
106
|
+
}
|
|
107
|
+
wrapError(action, err) {
|
|
108
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
109
|
+
return new errors_1.DatabaseError(`Pub/Sub ${action} failed: ${parent.message}`, {
|
|
110
|
+
parent,
|
|
111
|
+
original: parent.message,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// ---------------------------------------------------------------------
|
|
115
|
+
// Producing
|
|
116
|
+
// ---------------------------------------------------------------------
|
|
117
|
+
/**
|
|
118
|
+
* Publish one `message` to `topic` via `topic(name).publishMessage`. The
|
|
119
|
+
* message is encoded per the module's rules (string → UTF-8, Buffer → as-is,
|
|
120
|
+
* else JSON). Returns the server-assigned message id.
|
|
121
|
+
*/
|
|
122
|
+
async publish(topic, message, attributes) {
|
|
123
|
+
const client = this.requireClient();
|
|
124
|
+
try {
|
|
125
|
+
return await client.topic(topic).publishMessage({ data: toData(message), attributes });
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
throw this.wrapError(`publish to topic '${topic}'`, err);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------
|
|
132
|
+
// Administration
|
|
133
|
+
// ---------------------------------------------------------------------
|
|
134
|
+
/** `createTopic` — create a new topic. */
|
|
135
|
+
async createTopic(name) {
|
|
136
|
+
const client = this.requireClient();
|
|
137
|
+
try {
|
|
138
|
+
await client.createTopic(name);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
throw this.wrapError(`createTopic '${name}'`, err);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** `createSubscription` — attach a new subscription `name` to `topic`. */
|
|
145
|
+
async createSubscription(topic, name, options) {
|
|
146
|
+
const client = this.requireClient();
|
|
147
|
+
try {
|
|
148
|
+
await client.createSubscription(topic, name, options);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
throw this.wrapError(`createSubscription '${name}' on topic '${topic}'`, err);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ---------------------------------------------------------------------
|
|
155
|
+
// Consuming
|
|
156
|
+
// ---------------------------------------------------------------------
|
|
157
|
+
/**
|
|
158
|
+
* Subscribe to `subscription`, invoking `handler` for each streamed message
|
|
159
|
+
* (the driver's `Message` object; call `.ack()` / `.nack()` on it). Attaches
|
|
160
|
+
* a `'message'` listener via `subscription(name).on('message', ...)` and
|
|
161
|
+
* returns a subscription handle whose `stop()` detaches the listener; it is
|
|
162
|
+
* also tracked so `disconnect()` detaches it.
|
|
163
|
+
*/
|
|
164
|
+
async subscribe(subscription, handler) {
|
|
165
|
+
const client = this.requireClient();
|
|
166
|
+
let sub;
|
|
167
|
+
try {
|
|
168
|
+
sub = client.subscription(subscription);
|
|
169
|
+
sub.on('message', (message) => {
|
|
170
|
+
void handler(message);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
throw this.wrapError(`subscribe to '${subscription}'`, err);
|
|
175
|
+
}
|
|
176
|
+
this.subscriptions.add(sub);
|
|
177
|
+
return {
|
|
178
|
+
stop: async () => {
|
|
179
|
+
this.subscriptions.delete(sub);
|
|
180
|
+
sub.removeAllListeners?.();
|
|
181
|
+
await sub.close?.();
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.PubSubStore = PubSubStore;
|
|
187
|
+
exports.default = PubSubStore;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Apache Pulsar store implementation.
|
|
4
|
+
*
|
|
5
|
+
* Pulsar is a distributed pub/sub messaging and streaming platform. It has no
|
|
6
|
+
* query language and does not fit the SQL-shaped `Dialect` interface, so this
|
|
7
|
+
* class implements the minimal `NoSqlStore` marker interface and exposes
|
|
8
|
+
* Pulsar's real operations - producing to topics, subscribing consumers, and
|
|
9
|
+
* creating readers - instead of forcing everything into a `query(sql)` shape.
|
|
10
|
+
*
|
|
11
|
+
* Uses the `pulsar-client` driver. `pulsar-client` is loaded lazily inside
|
|
12
|
+
* `connect()` (or supplied pre-built via `options.client`) so importing this
|
|
13
|
+
* module does not require the driver to be installed.
|
|
14
|
+
*
|
|
15
|
+
* ## Message serialization
|
|
16
|
+
*
|
|
17
|
+
* Pulsar sends and receives raw bytes. `produce()` accepts a `string` or a
|
|
18
|
+
* `Buffer`: strings are UTF-8 encoded to a `Buffer` and Buffers are passed
|
|
19
|
+
* through untouched, then handed to the producer as `{ data: Buffer }`.
|
|
20
|
+
* Consumers receive Pulsar `Message` objects; use `msg.getData()` to read the
|
|
21
|
+
* raw bytes back.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.PulsarStore = void 0;
|
|
25
|
+
const errors_1 = require("../../errors");
|
|
26
|
+
function wrapConnectionError(err, serviceUrl) {
|
|
27
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
28
|
+
const message = /econnrefused/i.test(parent.message)
|
|
29
|
+
? 'Connection refused'
|
|
30
|
+
: `Unable to connect to Pulsar: ${parent.message}`;
|
|
31
|
+
return new errors_1.ConnectionError(message, {
|
|
32
|
+
parent,
|
|
33
|
+
database: 'pulsar',
|
|
34
|
+
host: serviceUrl,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function wrapDatabaseError(err, message) {
|
|
38
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
39
|
+
const combined = message ? `${message}: ${parent.message}` : parent.message;
|
|
40
|
+
return errors_1.DatabaseError.from(parent, { message: combined });
|
|
41
|
+
}
|
|
42
|
+
/** Serialize a `string`/`Buffer` message into the raw bytes Pulsar expects. */
|
|
43
|
+
function toBuffer(message) {
|
|
44
|
+
return Buffer.isBuffer(message) ? message : Buffer.from(message, 'utf8');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* `PulsarStore` wraps a `pulsar-client` `Client` and exposes Pulsar's core
|
|
48
|
+
* operations: producing messages, consumer subscriptions, and readers.
|
|
49
|
+
*/
|
|
50
|
+
class PulsarStore {
|
|
51
|
+
constructor(options = {}) {
|
|
52
|
+
this.name = 'pulsar';
|
|
53
|
+
this.library = 'pulsar-client';
|
|
54
|
+
this.client = null;
|
|
55
|
+
/** One cached producer per topic, so repeated `produce()` calls reuse it. */
|
|
56
|
+
this.producers = new Map();
|
|
57
|
+
/** Consumers created via `subscribe()`, tracked so `disconnect()` can close them. */
|
|
58
|
+
this.consumers = [];
|
|
59
|
+
/** Readers created via `createReader()`, tracked so `disconnect()` can close them. */
|
|
60
|
+
this.readers = [];
|
|
61
|
+
/** Set false on `disconnect()` to stop live `subscribe()` receive loops. */
|
|
62
|
+
this.receiving = false;
|
|
63
|
+
this.connected = false;
|
|
64
|
+
this.options = options;
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------
|
|
67
|
+
// Connection lifecycle
|
|
68
|
+
// ---------------------------------------------------------------------
|
|
69
|
+
async connect() {
|
|
70
|
+
if (this.connected && this.client) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
if (this.options.client) {
|
|
75
|
+
this.client = this.options.client;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Lazy-load the driver so importing this module doesn't require
|
|
79
|
+
// `pulsar-client` to be installed unless a real connection is made.
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
81
|
+
const Pulsar = require('pulsar-client');
|
|
82
|
+
this.client = new Pulsar.Client({
|
|
83
|
+
serviceUrl: this.options.serviceUrl,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
this.receiving = true;
|
|
87
|
+
this.connected = true;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
this.client = null;
|
|
91
|
+
this.connected = false;
|
|
92
|
+
throw wrapConnectionError(err, this.options.serviceUrl);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async disconnect() {
|
|
96
|
+
// Stop receive loops before closing anything.
|
|
97
|
+
this.receiving = false;
|
|
98
|
+
for (const consumer of this.consumers.splice(0)) {
|
|
99
|
+
try {
|
|
100
|
+
await consumer.close();
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Best-effort teardown - keep closing the rest.
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const reader of this.readers.splice(0)) {
|
|
107
|
+
try {
|
|
108
|
+
await reader.close();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Best-effort teardown.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const producer of this.producers.values()) {
|
|
115
|
+
try {
|
|
116
|
+
await producer.close();
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Best-effort teardown.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
this.producers.clear();
|
|
123
|
+
if (this.client) {
|
|
124
|
+
try {
|
|
125
|
+
await this.client.close();
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Best-effort teardown.
|
|
129
|
+
}
|
|
130
|
+
this.client = null;
|
|
131
|
+
}
|
|
132
|
+
this.connected = false;
|
|
133
|
+
}
|
|
134
|
+
isConnected() {
|
|
135
|
+
return this.connected && this.client !== null;
|
|
136
|
+
}
|
|
137
|
+
/** Returns the underlying `pulsar-client` `Client` for anything not wrapped here. */
|
|
138
|
+
getClient() {
|
|
139
|
+
return this.requireClient();
|
|
140
|
+
}
|
|
141
|
+
requireClient() {
|
|
142
|
+
if (!this.client) {
|
|
143
|
+
throw new errors_1.ConnectionError('Not connected to Pulsar', { database: 'pulsar' });
|
|
144
|
+
}
|
|
145
|
+
return this.client;
|
|
146
|
+
}
|
|
147
|
+
// ---------------------------------------------------------------------
|
|
148
|
+
// Producing
|
|
149
|
+
// ---------------------------------------------------------------------
|
|
150
|
+
/**
|
|
151
|
+
* Produce `message` to `topic`. The producer for a topic is created on first
|
|
152
|
+
* use and cached, so repeated `produce()` calls to the same topic reuse it.
|
|
153
|
+
* `message` may be a UTF-8 `string` or a `Buffer`; it is serialized to raw
|
|
154
|
+
* bytes and sent as `{ data: Buffer }`. Returns the producer's send result.
|
|
155
|
+
*/
|
|
156
|
+
async produce(topic, message) {
|
|
157
|
+
const client = this.requireClient();
|
|
158
|
+
try {
|
|
159
|
+
let producer = this.producers.get(topic);
|
|
160
|
+
if (!producer) {
|
|
161
|
+
producer = await client.createProducer({ topic });
|
|
162
|
+
this.producers.set(topic, producer);
|
|
163
|
+
}
|
|
164
|
+
return await producer.send({ data: toBuffer(message) });
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
throw wrapDatabaseError(err, `Pulsar produce to "${topic}" failed`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// ---------------------------------------------------------------------
|
|
171
|
+
// Consuming
|
|
172
|
+
// ---------------------------------------------------------------------
|
|
173
|
+
/**
|
|
174
|
+
* Subscribe a consumer to `topic` under `subscription` and invoke `handler`
|
|
175
|
+
* for every received message. Runs a background receive loop that calls
|
|
176
|
+
* `consumer.receive()`, passes each message to `handler`, then
|
|
177
|
+
* acknowledges it with `consumer.acknowledge(msg)`. The loop stops on
|
|
178
|
+
* `disconnect()`. The consumer is tracked so `disconnect()` closes it.
|
|
179
|
+
* Returns the created consumer.
|
|
180
|
+
*/
|
|
181
|
+
async subscribe(topic, subscription, handler, options = {}) {
|
|
182
|
+
const client = this.requireClient();
|
|
183
|
+
let consumer;
|
|
184
|
+
try {
|
|
185
|
+
consumer = await client.subscribe({ topic, subscription, ...options });
|
|
186
|
+
this.consumers.push(consumer);
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
throw wrapDatabaseError(err, `Pulsar subscribe to "${topic}" failed`);
|
|
190
|
+
}
|
|
191
|
+
// Background receive loop: pull, dispatch to handler, acknowledge. Stops
|
|
192
|
+
// when `disconnect()` flips `this.receiving` to false.
|
|
193
|
+
void (async () => {
|
|
194
|
+
while (this.receiving) {
|
|
195
|
+
let msg;
|
|
196
|
+
try {
|
|
197
|
+
msg = await consumer.receive();
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// Consumer closed (typically during disconnect) - end the loop.
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
await handler(msg);
|
|
205
|
+
await consumer.acknowledge(msg);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// Handler/ack failure: don't kill the loop, move to the next message.
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
})();
|
|
212
|
+
return consumer;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Create a Pulsar reader over `topic`. Readers give non-destructive,
|
|
216
|
+
* position-controlled reads (no subscription/acks). The reader is tracked so
|
|
217
|
+
* `disconnect()` closes it. Returns the created reader.
|
|
218
|
+
*/
|
|
219
|
+
async createReader(topic, options = {}) {
|
|
220
|
+
const client = this.requireClient();
|
|
221
|
+
try {
|
|
222
|
+
const reader = await client.createReader({ topic, ...options });
|
|
223
|
+
this.readers.push(reader);
|
|
224
|
+
return reader;
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
throw wrapDatabaseError(err, `Pulsar createReader for "${topic}" failed`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
exports.PulsarStore = PulsarStore;
|
|
232
|
+
exports.default = PulsarStore;
|