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,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Apache Doris store.
|
|
4
|
+
*
|
|
5
|
+
* Apache Doris is a real-time MPP analytical (OLAP) database. Like StarRocks
|
|
6
|
+
* (with which it shares ancestry), it speaks the **MySQL wire protocol**, so
|
|
7
|
+
* it is queried with the `mysql2` driver over a normal MySQL connection/pool.
|
|
8
|
+
* Doris is a columnar analytics engine rather than an OLTP store, which does
|
|
9
|
+
* not fit this ORM's SQL `Dialect` abstraction cleanly, so it is modelled as
|
|
10
|
+
* a `NoSqlStore` (`src/nosql/store.ts`) exposing a direct `query`/`ingest`
|
|
11
|
+
* surface.
|
|
12
|
+
*
|
|
13
|
+
* ## Driver: `mysql2` (MySQL-wire)
|
|
14
|
+
*
|
|
15
|
+
* The `mysql2` package is an optional peer dependency, lazily `require`d
|
|
16
|
+
* inside `connect()` so importing this module never forces it to be
|
|
17
|
+
* installed. Tests inject a pre-built mock connection via
|
|
18
|
+
* `DorisStoreOptions.client`, which skips the `require` entirely.
|
|
19
|
+
*
|
|
20
|
+
* ## Ingestion
|
|
21
|
+
*
|
|
22
|
+
* `ingest()` performs a batched `INSERT` over the MySQL wire. For
|
|
23
|
+
* high-throughput loading Doris also offers **Stream Load** (an HTTP
|
|
24
|
+
* `PUT /api/{db}/{table}/_stream_load` endpoint). Stream Load is a separate
|
|
25
|
+
* (optional) HTTP transport and is intentionally not wired here; use the
|
|
26
|
+
* `mysql2`-based `ingest()` for wire-level inserts, or POST to the Stream Load
|
|
27
|
+
* endpoint yourself for bulk pipelines.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.DorisStore = void 0;
|
|
31
|
+
const errors_1 = require("../../errors");
|
|
32
|
+
/**
|
|
33
|
+
* `DorisStore` wraps a `mysql2` connection to a Doris frontend and exposes
|
|
34
|
+
* `query(sql, params)` for reads/DDL and `ingest(table, rows)` for batched
|
|
35
|
+
* wire-level inserts.
|
|
36
|
+
*/
|
|
37
|
+
class DorisStore {
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
this.name = 'doris';
|
|
40
|
+
this.library = 'mysql2';
|
|
41
|
+
this.client = null;
|
|
42
|
+
this.connected = false;
|
|
43
|
+
this.options = options;
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------
|
|
46
|
+
// NoSqlStore lifecycle
|
|
47
|
+
// ---------------------------------------------------------------------
|
|
48
|
+
async connect() {
|
|
49
|
+
if (this.connected && this.client) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
let client = this.options.client;
|
|
54
|
+
if (!client) {
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
56
|
+
const mysql = require('mysql2/promise');
|
|
57
|
+
client = (await mysql.createConnection({
|
|
58
|
+
host: this.options.host,
|
|
59
|
+
port: this.options.port,
|
|
60
|
+
user: this.options.user,
|
|
61
|
+
password: this.options.password,
|
|
62
|
+
database: this.options.database,
|
|
63
|
+
...this.options.connectionOptions,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
this.client = client;
|
|
67
|
+
this.connected = true;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
this.client = null;
|
|
71
|
+
this.connected = false;
|
|
72
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
73
|
+
throw new errors_1.ConnectionError(`Unable to connect to Doris: ${parent.message}`, {
|
|
74
|
+
parent,
|
|
75
|
+
database: 'doris',
|
|
76
|
+
host: this.options.host,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async disconnect() {
|
|
81
|
+
if (this.client) {
|
|
82
|
+
try {
|
|
83
|
+
await this.client.end?.();
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
this.client = null;
|
|
87
|
+
this.connected = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
this.connected = false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
isConnected() {
|
|
95
|
+
return this.connected && this.client !== null;
|
|
96
|
+
}
|
|
97
|
+
/** Returns the underlying `mysql2` connection for anything not wrapped here. */
|
|
98
|
+
getClient() {
|
|
99
|
+
return this.requireClient();
|
|
100
|
+
}
|
|
101
|
+
requireClient() {
|
|
102
|
+
if (!this.client || !this.connected) {
|
|
103
|
+
throw new errors_1.ConnectionError('Doris client is not connected. Call connect() first.', {
|
|
104
|
+
database: 'doris',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return this.client;
|
|
108
|
+
}
|
|
109
|
+
// ---------------------------------------------------------------------
|
|
110
|
+
// Query + ingest
|
|
111
|
+
// ---------------------------------------------------------------------
|
|
112
|
+
/**
|
|
113
|
+
* Execute a SQL statement over the MySQL wire with optional positional
|
|
114
|
+
* `params` and return the result rows (the first element of `mysql2`'s
|
|
115
|
+
* `[rows, fields]` tuple).
|
|
116
|
+
*/
|
|
117
|
+
async query(sql, params) {
|
|
118
|
+
const client = this.requireClient();
|
|
119
|
+
try {
|
|
120
|
+
const [rows] = await client.query(sql, params);
|
|
121
|
+
return (rows ?? []);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
125
|
+
throw errors_1.DatabaseError.from(parent, {
|
|
126
|
+
message: `Doris query failed: ${parent.message}`,
|
|
127
|
+
sql,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Batch-insert `rows` into `table` via a single parameterized
|
|
133
|
+
* `INSERT INTO table (cols) VALUES (...)` over the MySQL wire. Columns are
|
|
134
|
+
* taken from the first row. Returns the driver result (`OkPacket`).
|
|
135
|
+
*
|
|
136
|
+
* For high-throughput bulk loading, use Doris Stream Load (HTTP) instead —
|
|
137
|
+
* see the module header.
|
|
138
|
+
*/
|
|
139
|
+
async ingest(table, rows) {
|
|
140
|
+
if (rows.length === 0) {
|
|
141
|
+
throw new errors_1.DatabaseError('ingest() requires at least one row', {
|
|
142
|
+
original: 'empty rows array',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const columns = Object.keys(rows[0]);
|
|
146
|
+
if (columns.length === 0) {
|
|
147
|
+
throw new errors_1.DatabaseError('ingest() requires at least one column', {
|
|
148
|
+
original: 'empty row object',
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const values = rows.map((r) => columns.map((c) => r[c]));
|
|
152
|
+
const client = this.requireClient();
|
|
153
|
+
// mysql2 expands a single `?` bound to a nested array into a bulk VALUES list.
|
|
154
|
+
const sql = `INSERT INTO ${table} (${columns.join(', ')}) VALUES ?`;
|
|
155
|
+
try {
|
|
156
|
+
const [result] = await client.query(sql, [values]);
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
161
|
+
throw errors_1.DatabaseError.from(parent, {
|
|
162
|
+
message: `Doris ingest failed: ${parent.message}`,
|
|
163
|
+
sql,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.DorisStore = DorisStore;
|
|
169
|
+
exports.default = DorisStore;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Apache Druid store.
|
|
4
|
+
*
|
|
5
|
+
* Druid is a real-time OLAP / analytics datastore designed for sub-second
|
|
6
|
+
* queries over large event streams. It is not a relational database: it has
|
|
7
|
+
* no cross-datasource joins in the classic sense, no row-level UPDATE/DELETE,
|
|
8
|
+
* and ingestion happens by submitting *tasks* to an indexing service rather
|
|
9
|
+
* than by running `INSERT`. That model does not fit the SQL-shaped `Dialect`
|
|
10
|
+
* interface (`src/dialects/dialect.ts`), so this class implements the minimal
|
|
11
|
+
* `NoSqlStore` marker interface (`src/nosql/store.ts`) and talks to Druid's
|
|
12
|
+
* HTTP JSON API directly.
|
|
13
|
+
*
|
|
14
|
+
* ## No canonical driver - HTTP over `fetch`
|
|
15
|
+
*
|
|
16
|
+
* Druid has no single canonical npm client; it is just an HTTP/JSON API.
|
|
17
|
+
* Rather than depend on any package this store uses the global `fetch`. Tests
|
|
18
|
+
* (and callers wanting their own transport) can inject an alternative client
|
|
19
|
+
* via `DruidStoreOptions.client`; when omitted a tiny `fetch`-based client is
|
|
20
|
+
* built against `endpoint` at `connect()` time.
|
|
21
|
+
*
|
|
22
|
+
* ## Endpoints wrapped
|
|
23
|
+
*
|
|
24
|
+
* - `query(sql, params?)` -> `POST /druid/v2/sql` (Druid SQL, returns rows)
|
|
25
|
+
* - `nativeQuery(spec)` -> `POST /druid/v2` (native JSON query)
|
|
26
|
+
* - `ingest(target, rows)` -> `POST /druid/indexer/v1/task` (inline index task)
|
|
27
|
+
* - `submitTask(spec)` -> `POST /druid/indexer/v1/task` (arbitrary task spec)
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.DruidStore = exports.DEFAULT_DRUID_ENDPOINT = void 0;
|
|
31
|
+
exports.createFetchClient = createFetchClient;
|
|
32
|
+
const errors_1 = require("../../errors");
|
|
33
|
+
/** Default Druid router/broker HTTP endpoint. */
|
|
34
|
+
exports.DEFAULT_DRUID_ENDPOINT = 'http://localhost:8888';
|
|
35
|
+
/** Build a `fetch`-backed client for the given endpoint. */
|
|
36
|
+
function createFetchClient(endpoint, headers) {
|
|
37
|
+
const base = endpoint.endsWith('/') ? endpoint.slice(0, -1) : endpoint;
|
|
38
|
+
return {
|
|
39
|
+
async post(path, body) {
|
|
40
|
+
const res = await fetch(`${base}${path}`, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers: { 'Content-Type': 'application/json', ...(headers ?? {}) },
|
|
43
|
+
body: JSON.stringify(body),
|
|
44
|
+
});
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
47
|
+
}
|
|
48
|
+
const text = await res.text();
|
|
49
|
+
return text ? JSON.parse(text) : undefined;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* `DruidStore` wraps Druid's HTTP query + indexing API behind the
|
|
55
|
+
* `NoSqlStore` lifecycle: SQL and native queries for reads, task submission
|
|
56
|
+
* for ingestion.
|
|
57
|
+
*/
|
|
58
|
+
class DruidStore {
|
|
59
|
+
constructor(options = {}) {
|
|
60
|
+
this.name = 'druid';
|
|
61
|
+
this.library = 'fetch';
|
|
62
|
+
this.client = null;
|
|
63
|
+
this.connected = false;
|
|
64
|
+
this.endpoint = options.endpoint ?? exports.DEFAULT_DRUID_ENDPOINT;
|
|
65
|
+
this.injectedClient = options.client;
|
|
66
|
+
this.headers = options.headers;
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------
|
|
69
|
+
// Connection lifecycle
|
|
70
|
+
// ---------------------------------------------------------------------
|
|
71
|
+
async connect() {
|
|
72
|
+
if (this.connected && this.client) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.client = this.injectedClient ?? createFetchClient(this.endpoint, this.headers);
|
|
76
|
+
this.connected = true;
|
|
77
|
+
}
|
|
78
|
+
async disconnect() {
|
|
79
|
+
this.client = null;
|
|
80
|
+
this.connected = false;
|
|
81
|
+
}
|
|
82
|
+
isConnected() {
|
|
83
|
+
return this.connected && this.client !== null;
|
|
84
|
+
}
|
|
85
|
+
/** Returns the underlying (internal or injected) HTTP client. */
|
|
86
|
+
getClient() {
|
|
87
|
+
return this.requireClient();
|
|
88
|
+
}
|
|
89
|
+
requireClient() {
|
|
90
|
+
if (!this.client || !this.connected) {
|
|
91
|
+
throw new errors_1.ConnectionError('Not connected to Druid. Call connect() first.', {
|
|
92
|
+
database: 'druid',
|
|
93
|
+
host: this.endpoint,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return this.client;
|
|
97
|
+
}
|
|
98
|
+
async post(path, body, action) {
|
|
99
|
+
const client = this.requireClient();
|
|
100
|
+
try {
|
|
101
|
+
return await client.post(path, body);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
105
|
+
throw errors_1.DatabaseError.from(parent, { message: `Druid ${action} failed: ${parent.message}` });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ---------------------------------------------------------------------
|
|
109
|
+
// Query API
|
|
110
|
+
// ---------------------------------------------------------------------
|
|
111
|
+
/**
|
|
112
|
+
* Run a Druid SQL query via `POST /druid/v2/sql`. Optional positional
|
|
113
|
+
* `params` are sent as Druid SQL parameters (`{ value }` objects). Druid
|
|
114
|
+
* returns an array of row objects, which is returned as-is.
|
|
115
|
+
*/
|
|
116
|
+
async query(sql, params) {
|
|
117
|
+
const body = { query: sql };
|
|
118
|
+
if (params && params.length > 0) {
|
|
119
|
+
body.parameters = params.map((value) => ({ value }));
|
|
120
|
+
}
|
|
121
|
+
const rows = await this.post('/druid/v2/sql', body, 'query');
|
|
122
|
+
return (rows ?? []);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Run a native (JSON) Druid query via `POST /druid/v2`. Returns the parsed
|
|
126
|
+
* response body (shape depends on the native query type).
|
|
127
|
+
*/
|
|
128
|
+
async nativeQuery(spec) {
|
|
129
|
+
return (await this.post('/druid/v2', spec, 'nativeQuery'));
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------
|
|
132
|
+
// Ingestion (indexing tasks)
|
|
133
|
+
// ---------------------------------------------------------------------
|
|
134
|
+
/**
|
|
135
|
+
* Ingest `rows` into datasource `target` by submitting an inline
|
|
136
|
+
* `index_parallel` task to `POST /druid/indexer/v1/task`. Returns the task
|
|
137
|
+
* submission response (typically `{ task: '<id>' }`).
|
|
138
|
+
*/
|
|
139
|
+
async ingest(target, rows) {
|
|
140
|
+
const spec = {
|
|
141
|
+
type: 'index_parallel',
|
|
142
|
+
spec: {
|
|
143
|
+
dataSchema: { dataSource: target },
|
|
144
|
+
ioConfig: {
|
|
145
|
+
type: 'index_parallel',
|
|
146
|
+
inputSource: {
|
|
147
|
+
type: 'inline',
|
|
148
|
+
data: rows.map((r) => JSON.stringify(r)).join('\n'),
|
|
149
|
+
},
|
|
150
|
+
inputFormat: { type: 'json' },
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
return this.submitTask(spec);
|
|
155
|
+
}
|
|
156
|
+
/** Submit an arbitrary task spec to `POST /druid/indexer/v1/task`. */
|
|
157
|
+
async submitTask(spec) {
|
|
158
|
+
return this.post('/druid/indexer/v1/task', spec, 'submitTask');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.DruidStore = DruidStore;
|
|
162
|
+
exports.default = DruidStore;
|