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,377 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TiDB dialect implementation for the TypeScript ORM
|
|
4
|
+
*
|
|
5
|
+
* TiDB is MySQL-wire-protocol compatible: it speaks the MySQL client/server
|
|
6
|
+
* protocol and understands (almost all of) MySQL's SQL grammar, so this
|
|
7
|
+
* dialect extends {@link MySQLDialect} and reuses MySQL's `mysql2` driver
|
|
8
|
+
* verbatim (connection pooling, escaping, query execution, streaming, most
|
|
9
|
+
* DDL/DML builders). Only the genuine TiDB grammar differences are overridden
|
|
10
|
+
* or added here.
|
|
11
|
+
*
|
|
12
|
+
* Differences from plain MySQL implemented in this dialect:
|
|
13
|
+
*
|
|
14
|
+
* - **Dialect identity**: `name` is `'tidb'` (the wire `library` stays
|
|
15
|
+
* `'mysql2'` since that's the actual driver in use).
|
|
16
|
+
* - **Default port 4000**: TiDB's default SQL port is 4000, not MySQL's 3306.
|
|
17
|
+
* The constructor injects it as a default that the caller can still override.
|
|
18
|
+
* - **AUTO_RANDOM primary keys**: TiDB offers `AUTO_RANDOM` as an alternative
|
|
19
|
+
* to `AUTO_INCREMENT` for (BIGINT) primary keys. It scatters generated IDs
|
|
20
|
+
* across the key space to avoid the write hot-spotting that a monotonic
|
|
21
|
+
* `AUTO_INCREMENT` key causes on a range-partitioned distributed store. A
|
|
22
|
+
* column flag (`autoRandom: true` or `autoRandom: <shardBits>`) emits
|
|
23
|
+
* `AUTO_RANDOM` / `AUTO_RANDOM(n)` instead of `AUTO_INCREMENT`.
|
|
24
|
+
* - **SHARD_ROW_ID_BITS / PRE_SPLIT_REGIONS**: TiDB table options (for tables
|
|
25
|
+
* without an integer PK) that shard the implicit `_tidb_rowid` and
|
|
26
|
+
* pre-split the table into multiple regions up front to spread write load.
|
|
27
|
+
* Both are supported as CREATE TABLE options and are not valid MySQL syntax.
|
|
28
|
+
* - **SPLIT TABLE**: TiDB-only statement to pre-split a table/index's key
|
|
29
|
+
* range into N regions (`SPLIT TABLE t BETWEEN (...) AND (...) REGIONS n`).
|
|
30
|
+
* Not standard MySQL, so it's exposed as a dedicated helper.
|
|
31
|
+
* - **Storage engines**: TiDB parses but effectively ignores MySQL
|
|
32
|
+
* storage-engine clauses such as `ENGINE=InnoDB` (all TiDB tables live in
|
|
33
|
+
* its distributed KV store / TiKV; there is no per-table pluggable engine).
|
|
34
|
+
* The `engine` table option is still emitted for MySQL source compatibility,
|
|
35
|
+
* but has no effect on TiDB — documented here so callers don't rely on it.
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.TiDBDialect = void 0;
|
|
39
|
+
exports.createTiDBDialect = createTiDBDialect;
|
|
40
|
+
const index_1 = require("../mysql/index");
|
|
41
|
+
/**
|
|
42
|
+
* TiDB dialect. MySQL-wire-compatible; reuses the `mysql2` driver via
|
|
43
|
+
* {@link MySQLDialect}. See the file header for the full list of differences.
|
|
44
|
+
*/
|
|
45
|
+
class TiDBDialect extends index_1.MySQLDialect {
|
|
46
|
+
constructor(config = {}) {
|
|
47
|
+
// TiDB's default SQL port is 4000 (MySQL's is 3306). Inject it as a
|
|
48
|
+
// default that an explicit `config.port` still overrides.
|
|
49
|
+
super({ port: 4000, ...config });
|
|
50
|
+
this.name = 'tidb';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build the column-definition SQL fragment for a single column, with TiDB's
|
|
54
|
+
* `AUTO_RANDOM` support. MySQL's own column builder is `private`, so this
|
|
55
|
+
* dialect implements its own (covering the same common flags) rather than
|
|
56
|
+
* reusing it.
|
|
57
|
+
*/
|
|
58
|
+
buildColumnSql(columnName, definition) {
|
|
59
|
+
let sql = `${this.escapeId(columnName)} ${this.getDataTypeSql(definition.type)}`;
|
|
60
|
+
if (definition.charset) {
|
|
61
|
+
sql += ` CHARACTER SET ${this.escapeId(definition.charset)}`;
|
|
62
|
+
}
|
|
63
|
+
if (definition.collate) {
|
|
64
|
+
sql += ` COLLATE ${this.escapeId(definition.collate)}`;
|
|
65
|
+
}
|
|
66
|
+
if (definition.allowNull === false) {
|
|
67
|
+
sql += ' NOT NULL';
|
|
68
|
+
}
|
|
69
|
+
if (definition.defaultValue !== undefined) {
|
|
70
|
+
sql += ` DEFAULT ${this.formatDefaultValue(definition.defaultValue)}`;
|
|
71
|
+
}
|
|
72
|
+
if (definition.invisible) {
|
|
73
|
+
sql += ' INVISIBLE';
|
|
74
|
+
}
|
|
75
|
+
if (definition.primaryKey) {
|
|
76
|
+
sql += ' PRIMARY KEY';
|
|
77
|
+
}
|
|
78
|
+
// AUTO_RANDOM is TiDB's alternative to AUTO_INCREMENT and wins when both
|
|
79
|
+
// are specified. `autoRandom: <number>` emits `AUTO_RANDOM(n)`.
|
|
80
|
+
if (definition.autoRandom !== undefined && definition.autoRandom !== false) {
|
|
81
|
+
const shardBits = typeof definition.autoRandom === 'number' ? `(${definition.autoRandom})` : '';
|
|
82
|
+
sql += ` AUTO_RANDOM${shardBits}`;
|
|
83
|
+
}
|
|
84
|
+
else if (definition.autoIncrement) {
|
|
85
|
+
sql += ' AUTO_INCREMENT';
|
|
86
|
+
}
|
|
87
|
+
if (definition.unique) {
|
|
88
|
+
if (typeof definition.unique === 'string') {
|
|
89
|
+
sql += ` UNIQUE KEY ${this.escapeId(definition.unique)}`;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
sql += ' UNIQUE';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (definition.references) {
|
|
96
|
+
const refField = definition.references.field;
|
|
97
|
+
const refFieldSql = Array.isArray(refField)
|
|
98
|
+
? `(${refField.map((f) => this.escapeId(f)).join(', ')})`
|
|
99
|
+
: `(${this.escapeId(refField)})`;
|
|
100
|
+
sql += ` REFERENCES ${this.escapeId(definition.references.table)}${refFieldSql}`;
|
|
101
|
+
if (definition.references.onDelete) {
|
|
102
|
+
sql += ` ON DELETE ${definition.references.onDelete}`;
|
|
103
|
+
}
|
|
104
|
+
if (definition.references.onUpdate) {
|
|
105
|
+
sql += ` ON UPDATE ${definition.references.onUpdate}`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (definition.comment) {
|
|
109
|
+
sql += ` COMMENT '${this.escapeSqlString(definition.comment)}'`;
|
|
110
|
+
}
|
|
111
|
+
return sql;
|
|
112
|
+
}
|
|
113
|
+
/** Escape single quotes/backslashes for embedding a string literal. */
|
|
114
|
+
escapeSqlString(str) {
|
|
115
|
+
return str.replace(/'/g, "''").replace(/\\/g, '\\\\');
|
|
116
|
+
}
|
|
117
|
+
/** Render a column DEFAULT value. */
|
|
118
|
+
formatDefaultValue(value) {
|
|
119
|
+
if (value === null) {
|
|
120
|
+
return 'NULL';
|
|
121
|
+
}
|
|
122
|
+
if (typeof value === 'string') {
|
|
123
|
+
if (value.toUpperCase().includes('CURRENT_') || value.toUpperCase() === 'NULL') {
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
return `'${this.escapeSqlString(value)}'`;
|
|
127
|
+
}
|
|
128
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
129
|
+
return String(value);
|
|
130
|
+
}
|
|
131
|
+
if (typeof value === 'object' &&
|
|
132
|
+
value !== null &&
|
|
133
|
+
typeof value.toDefaultValue === 'function') {
|
|
134
|
+
return value.toDefaultValue();
|
|
135
|
+
}
|
|
136
|
+
return `'${this.escapeSqlString(String(value))}'`;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Build a TiDB `CREATE TABLE` statement, supporting `AUTO_RANDOM` primary
|
|
140
|
+
* keys and the `SHARD_ROW_ID_BITS` / `PRE_SPLIT_REGIONS` table options.
|
|
141
|
+
* Pure/synchronous — returns the SQL string without executing it.
|
|
142
|
+
*/
|
|
143
|
+
buildCreateTableSql(tableName, columns, options) {
|
|
144
|
+
const columnDefs = Object.entries(columns).map(([name, def]) => this.buildColumnSql(name, def));
|
|
145
|
+
let sql = 'CREATE TABLE';
|
|
146
|
+
if (options?.ifNotExists) {
|
|
147
|
+
sql += ' IF NOT EXISTS';
|
|
148
|
+
}
|
|
149
|
+
sql += ` ${this.escapeId(tableName)} (${columnDefs.join(', ')})`;
|
|
150
|
+
// ENGINE is parsed but ignored by TiDB (no per-table pluggable engine —
|
|
151
|
+
// everything lives in TiKV). Emitted only for MySQL source compatibility.
|
|
152
|
+
if (options?.engine) {
|
|
153
|
+
sql += ` ENGINE=${options.engine}`;
|
|
154
|
+
}
|
|
155
|
+
if (options?.charset) {
|
|
156
|
+
sql += ` DEFAULT CHARSET=${options.charset}`;
|
|
157
|
+
}
|
|
158
|
+
if (options?.collate) {
|
|
159
|
+
sql += ` COLLATE ${options.collate}`;
|
|
160
|
+
}
|
|
161
|
+
if (options?.comment) {
|
|
162
|
+
sql += ` COMMENT='${this.escapeSqlString(options.comment)}'`;
|
|
163
|
+
}
|
|
164
|
+
// TiDB-specific table options (not valid MySQL syntax).
|
|
165
|
+
if (options?.shardRowIdBits !== undefined) {
|
|
166
|
+
sql += ` SHARD_ROW_ID_BITS = ${options.shardRowIdBits}`;
|
|
167
|
+
}
|
|
168
|
+
if (options?.preSplitRegions !== undefined) {
|
|
169
|
+
sql += ` PRE_SPLIT_REGIONS = ${options.preSplitRegions}`;
|
|
170
|
+
}
|
|
171
|
+
return sql;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create a table using TiDB grammar (AUTO_RANDOM, SHARD_ROW_ID_BITS,
|
|
175
|
+
* PRE_SPLIT_REGIONS). Overrides the MySQL implementation, whose private
|
|
176
|
+
* column builder cannot emit `AUTO_RANDOM`.
|
|
177
|
+
*/
|
|
178
|
+
async createTable(tableName, columns, options) {
|
|
179
|
+
const sql = this.buildCreateTableSql(tableName, columns, options);
|
|
180
|
+
await this.query(sql);
|
|
181
|
+
}
|
|
182
|
+
// ==========================================================================
|
|
183
|
+
// Upsert (ON DUPLICATE KEY UPDATE) — TiDB compatibility override
|
|
184
|
+
//
|
|
185
|
+
// MySQL 8.0.19 introduced the row-alias INSERT form
|
|
186
|
+
// `INSERT INTO t (...) VALUES (...) AS new_vals
|
|
187
|
+
// ON DUPLICATE KEY UPDATE col = new_vals.col`
|
|
188
|
+
// and the base MySQLDialect emits exactly that (because the older
|
|
189
|
+
// `VALUES(col)` function form is deprecated in MySQL 8.0.20+).
|
|
190
|
+
//
|
|
191
|
+
// TiDB does NOT support that row-alias syntax in the INSERT statement — a
|
|
192
|
+
// real TiDB server rejects `INSERT ... VALUES (...) AS alias ...` with a
|
|
193
|
+
// parse error. TiDB *does* fully support the classic `VALUES(col)` function
|
|
194
|
+
// form inside ON DUPLICATE KEY UPDATE (across all TiDB versions), so we
|
|
195
|
+
// override the two upsert builders to emit that form instead. It is the
|
|
196
|
+
// TiDB-compatible way to express the same "insert or update" semantics.
|
|
197
|
+
// ==========================================================================
|
|
198
|
+
/**
|
|
199
|
+
* Build an INSERT query. Identical to the MySQL builder except that when
|
|
200
|
+
* `options.upsert` is set, the `ON DUPLICATE KEY UPDATE` clause uses the
|
|
201
|
+
* TiDB-compatible `VALUES(col)` function form rather than MySQL 8.0.19's
|
|
202
|
+
* row-alias (`AS new_vals`) form, which TiDB rejects.
|
|
203
|
+
*/
|
|
204
|
+
buildInsertQuery(tableName, values, options) {
|
|
205
|
+
const base = super.buildInsertQuery(tableName, values, { ...options, upsert: false });
|
|
206
|
+
if (!options?.upsert) {
|
|
207
|
+
return base;
|
|
208
|
+
}
|
|
209
|
+
const columns = Object.keys(values);
|
|
210
|
+
const updateFields = options.updateOnDuplicate && options.updateOnDuplicate.length > 0
|
|
211
|
+
? options.updateOnDuplicate
|
|
212
|
+
: columns;
|
|
213
|
+
const updateClause = updateFields
|
|
214
|
+
.map((c) => `${this.escapeId(c)} = VALUES(${this.escapeId(c)})`)
|
|
215
|
+
.join(', ');
|
|
216
|
+
return {
|
|
217
|
+
sql: `${base.sql} ON DUPLICATE KEY UPDATE ${updateClause}`,
|
|
218
|
+
values: base.values,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Build an UPSERT query using TiDB-compatible `ON DUPLICATE KEY UPDATE col =
|
|
223
|
+
* VALUES(col)` syntax (the base MySQL dialect emits the row-alias form that
|
|
224
|
+
* TiDB does not accept). TiDB, like MySQL, has no `RETURNING` clause.
|
|
225
|
+
*/
|
|
226
|
+
buildUpsertQuery(tableName, values, options) {
|
|
227
|
+
if (options?.returning) {
|
|
228
|
+
throw new Error('TiDB does not support the RETURNING clause. Re-fetch the row after the upsert instead.');
|
|
229
|
+
}
|
|
230
|
+
const base = super.buildInsertQuery(tableName, values);
|
|
231
|
+
const columns = Object.keys(values);
|
|
232
|
+
const updateFields = options?.updateOnDuplicate && options.updateOnDuplicate.length > 0
|
|
233
|
+
? options.updateOnDuplicate
|
|
234
|
+
: columns;
|
|
235
|
+
const updateClause = updateFields
|
|
236
|
+
.map((c) => `${this.escapeId(c)} = VALUES(${this.escapeId(c)})`)
|
|
237
|
+
.join(', ');
|
|
238
|
+
return {
|
|
239
|
+
sql: `${base.sql} ON DUPLICATE KEY UPDATE ${updateClause}`,
|
|
240
|
+
values: base.values,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// ==========================================================================
|
|
244
|
+
// Data-type mapping — reject types TiDB does not implement
|
|
245
|
+
// ==========================================================================
|
|
246
|
+
/**
|
|
247
|
+
* Map an ORM {@link DataType} to TiDB column SQL. Delegates to the MySQL
|
|
248
|
+
* mapping for everything TiDB shares, but rejects the spatial/GIS types up
|
|
249
|
+
* front: TiDB implements no spatial data types (GEOMETRY, POINT, POLYGON,
|
|
250
|
+
* …), so emitting them would produce a `CREATE TABLE` that a real TiDB
|
|
251
|
+
* server rejects. Failing here gives a clear, actionable error instead of
|
|
252
|
+
* an opaque server-side parse error.
|
|
253
|
+
*/
|
|
254
|
+
getDataTypeSql(dataType) {
|
|
255
|
+
if (dataType && typeof dataType === 'object') {
|
|
256
|
+
const key = dataType.key;
|
|
257
|
+
const spatial = new Set([
|
|
258
|
+
'GEOMETRY',
|
|
259
|
+
'GEOGRAPHY',
|
|
260
|
+
'POINT',
|
|
261
|
+
'LINESTRING',
|
|
262
|
+
'POLYGON',
|
|
263
|
+
'MULTIPOINT',
|
|
264
|
+
'MULTILINESTRING',
|
|
265
|
+
'MULTIPOLYGON',
|
|
266
|
+
'GEOMETRYCOLLECTION',
|
|
267
|
+
]);
|
|
268
|
+
if (key && spatial.has(key)) {
|
|
269
|
+
throw new Error(`TiDB does not support spatial/GIS data types (got '${key}'). ` +
|
|
270
|
+
'Store the geometry as JSON/TEXT or a pair of numeric columns instead.');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return super.getDataTypeSql(dataType);
|
|
274
|
+
}
|
|
275
|
+
// ==========================================================================
|
|
276
|
+
// Constraints — TiDB supports ALTER TABLE ADD/DROP CONSTRAINT
|
|
277
|
+
//
|
|
278
|
+
// The base MySQLDialect throws "addConstraint is not supported in MySQL",
|
|
279
|
+
// but TiDB fully supports altering a table to add a PRIMARY KEY / UNIQUE /
|
|
280
|
+
// FOREIGN KEY / CHECK constraint and to drop it again, so implement them.
|
|
281
|
+
// ==========================================================================
|
|
282
|
+
/**
|
|
283
|
+
* Build an `ALTER TABLE ... ADD CONSTRAINT` statement (synchronous).
|
|
284
|
+
*/
|
|
285
|
+
buildAddConstraintSql(tableName, options) {
|
|
286
|
+
const namePart = options.name ? `CONSTRAINT ${this.escapeId(options.name)} ` : '';
|
|
287
|
+
const fieldList = (options.fields || []).map((f) => this.escapeId(f)).join(', ');
|
|
288
|
+
const prefix = `ALTER TABLE ${this.escapeId(tableName)} ADD ${namePart}`;
|
|
289
|
+
switch (options.type) {
|
|
290
|
+
case 'PRIMARY KEY':
|
|
291
|
+
return `${prefix}PRIMARY KEY (${fieldList})`;
|
|
292
|
+
case 'UNIQUE':
|
|
293
|
+
return `${prefix}UNIQUE (${fieldList})`;
|
|
294
|
+
case 'CHECK':
|
|
295
|
+
return `${prefix}CHECK (${options.check ?? ''})`;
|
|
296
|
+
case 'FOREIGN KEY': {
|
|
297
|
+
if (!options.references) {
|
|
298
|
+
throw new Error('FOREIGN KEY constraint requires a `references` target.');
|
|
299
|
+
}
|
|
300
|
+
const refFields = options.references.fields.map((f) => this.escapeId(f)).join(', ');
|
|
301
|
+
return `${prefix}FOREIGN KEY (${fieldList}) REFERENCES ${this.escapeId(options.references.table)} (${refFields})`;
|
|
302
|
+
}
|
|
303
|
+
default:
|
|
304
|
+
throw new Error(`Unsupported constraint type: ${String(options.type)}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Build an `ALTER TABLE ... DROP ...` statement for a constraint
|
|
309
|
+
* (synchronous). TiDB (like MySQL) drops each constraint kind with a
|
|
310
|
+
* different clause, so the caller passes the constraint `type`; when omitted
|
|
311
|
+
* a generic `DROP CONSTRAINT` (valid for CHECK constraints) is emitted.
|
|
312
|
+
*/
|
|
313
|
+
buildDropConstraintSql(tableName, constraintName, type) {
|
|
314
|
+
const t = this.escapeId(tableName);
|
|
315
|
+
switch (type) {
|
|
316
|
+
case 'PRIMARY KEY':
|
|
317
|
+
return `ALTER TABLE ${t} DROP PRIMARY KEY`;
|
|
318
|
+
case 'FOREIGN KEY':
|
|
319
|
+
return `ALTER TABLE ${t} DROP FOREIGN KEY ${this.escapeId(constraintName)}`;
|
|
320
|
+
case 'UNIQUE':
|
|
321
|
+
return `ALTER TABLE ${t} DROP INDEX ${this.escapeId(constraintName)}`;
|
|
322
|
+
case 'CHECK':
|
|
323
|
+
return `ALTER TABLE ${t} DROP CHECK ${this.escapeId(constraintName)}`;
|
|
324
|
+
default:
|
|
325
|
+
return `ALTER TABLE ${t} DROP CONSTRAINT ${this.escapeId(constraintName)}`;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Add a constraint to an existing table (TiDB supports this; MySQL base
|
|
330
|
+
* throws). Executes {@link buildAddConstraintSql}.
|
|
331
|
+
*/
|
|
332
|
+
async addConstraint(tableName, options) {
|
|
333
|
+
await this.query(this.buildAddConstraintSql(tableName, options));
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Drop a constraint from a table by name. Emits a generic
|
|
337
|
+
* `ALTER TABLE ... DROP CONSTRAINT name` (valid on TiDB for CHECK
|
|
338
|
+
* constraints); for foreign keys / unique keys / primary keys use
|
|
339
|
+
* {@link buildDropConstraintSql} with an explicit `type`.
|
|
340
|
+
*/
|
|
341
|
+
async removeConstraint(tableName, constraintName) {
|
|
342
|
+
await this.query(this.buildDropConstraintSql(tableName, constraintName));
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Build a TiDB `SPLIT TABLE` statement. This pre-splits a table's (or an
|
|
346
|
+
* index's) key range into `regions` regions, distributing write load before
|
|
347
|
+
* data arrives. Not standard MySQL. Pure/synchronous.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* // SPLIT TABLE `t` BETWEEN (0) AND (1000000) REGIONS 16
|
|
351
|
+
* dialect.buildSplitTableSql('t', { between: [0, 1000000], regions: 16 });
|
|
352
|
+
*/
|
|
353
|
+
buildSplitTableSql(tableName, options) {
|
|
354
|
+
const bound = (value) => {
|
|
355
|
+
const parts = Array.isArray(value) ? value : [value];
|
|
356
|
+
return `(${parts.map((v) => this.escape(v)).join(', ')})`;
|
|
357
|
+
};
|
|
358
|
+
const target = options.index
|
|
359
|
+
? `${this.escapeId(tableName)} INDEX ${this.escapeId(options.index)}`
|
|
360
|
+
: this.escapeId(tableName);
|
|
361
|
+
const [lower, upper] = options.between;
|
|
362
|
+
return `SPLIT TABLE ${target} BETWEEN ${bound(lower)} AND ${bound(upper)} REGIONS ${options.regions}`;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Execute a {@link buildSplitTableSql} statement.
|
|
366
|
+
*/
|
|
367
|
+
async splitTable(tableName, options) {
|
|
368
|
+
await this.query(this.buildSplitTableSql(tableName, options));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
exports.TiDBDialect = TiDBDialect;
|
|
372
|
+
/**
|
|
373
|
+
* Convenience factory mirroring `createMySQLDialect`.
|
|
374
|
+
*/
|
|
375
|
+
function createTiDBDialect(options = {}) {
|
|
376
|
+
return new TiDBDialect(options);
|
|
377
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TimescaleDB dialect implementation for the TypeScript ORM
|
|
4
|
+
*
|
|
5
|
+
* TimescaleDB is not a separate database engine — it is a PostgreSQL extension
|
|
6
|
+
* (`CREATE EXTENSION timescaledb`) that layers time-series capabilities on top
|
|
7
|
+
* of a stock PostgreSQL server. Because of that, this dialect extends
|
|
8
|
+
* `PostgresDialect` and reuses the exact same `pg` driver, wire protocol, and
|
|
9
|
+
* default port (5432). Everything PostgreSQL can do, TimescaleDB can do; this
|
|
10
|
+
* subclass only adds thin SQL builders for TimescaleDB-specific features.
|
|
11
|
+
*
|
|
12
|
+
* TimescaleDB-specific helpers (pure, synchronous SQL builders — they return
|
|
13
|
+
* the SQL string so callers can run it through the inherited `query()`):
|
|
14
|
+
*
|
|
15
|
+
* - `createExtensionSQL()` → `CREATE EXTENSION IF NOT EXISTS timescaledb`
|
|
16
|
+
* - `createHypertable()` → `SELECT create_hypertable(...)`
|
|
17
|
+
* - `addCompressionPolicy()` → `SELECT add_compression_policy(...)`
|
|
18
|
+
* - `addRetentionPolicy()` → `SELECT add_retention_policy(...)`
|
|
19
|
+
* - `createContinuousAggregate()` → `CREATE MATERIALIZED VIEW ... WITH (timescaledb.continuous) AS ...`
|
|
20
|
+
* - `enableCompression()` → `ALTER TABLE ... SET (timescaledb.compress, ...)`
|
|
21
|
+
*
|
|
22
|
+
* @see https://docs.timescale.com/
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.TimescaleDBDialect = void 0;
|
|
26
|
+
exports.createTimescaleDBDialect = createTimescaleDBDialect;
|
|
27
|
+
const index_1 = require("../postgres/index");
|
|
28
|
+
/**
|
|
29
|
+
* TimescaleDB dialect — a PostgreSQL dialect (reusing the `pg` driver on the
|
|
30
|
+
* standard port 5432) extended with time-series helpers backed by the
|
|
31
|
+
* `timescaledb` extension.
|
|
32
|
+
*/
|
|
33
|
+
class TimescaleDBDialect extends index_1.PostgresDialect {
|
|
34
|
+
constructor(config = {}) {
|
|
35
|
+
// TimescaleDB runs inside PostgreSQL, so it uses PostgreSQL's default port
|
|
36
|
+
// (5432). Let callers override it, but default to 5432.
|
|
37
|
+
super({ port: 5432, ...config });
|
|
38
|
+
// Override the inherited `name = 'postgres'` so the ORM identifies this as
|
|
39
|
+
// its own dialect. `library` stays `'pg'` (inherited) since TimescaleDB
|
|
40
|
+
// speaks the PostgreSQL wire protocol through the same driver. The base
|
|
41
|
+
// types `name` as the string literal `'postgres'`, so the override is cast
|
|
42
|
+
// to that literal type (the runtime value is still `'timescaledb'`) to
|
|
43
|
+
// satisfy the property-override compatibility check without editing the base.
|
|
44
|
+
this.name = 'timescaledb';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build the SQL that enables the TimescaleDB extension on the current
|
|
48
|
+
* database. Overrides the base `createExtension()` idea with a dedicated,
|
|
49
|
+
* synchronous SQL builder specifically for `timescaledb`.
|
|
50
|
+
*
|
|
51
|
+
* @param extensionName - Extension to enable. Defaults to `'timescaledb'`.
|
|
52
|
+
* @returns `CREATE EXTENSION IF NOT EXISTS timescaledb`
|
|
53
|
+
*/
|
|
54
|
+
createExtensionSQL(extensionName = 'timescaledb') {
|
|
55
|
+
return `CREATE EXTENSION IF NOT EXISTS ${this.escapeId(extensionName)}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format a TimescaleDB interval argument. Time-based hypertables use a
|
|
59
|
+
* PostgreSQL interval literal (`INTERVAL '7 days'`); integer-based
|
|
60
|
+
* hypertables use a bare integer (e.g. `86400000`). A number is emitted
|
|
61
|
+
* as a raw integer with no `INTERVAL` keyword; a string is wrapped in a
|
|
62
|
+
* safely-escaped `INTERVAL '...'` literal.
|
|
63
|
+
*/
|
|
64
|
+
formatInterval(value) {
|
|
65
|
+
if (typeof value === 'number') {
|
|
66
|
+
return String(value);
|
|
67
|
+
}
|
|
68
|
+
return `INTERVAL ${this.escape(value)}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build a `SELECT create_hypertable(...)` statement that converts a regular
|
|
72
|
+
* table into a TimescaleDB hypertable partitioned on a time column.
|
|
73
|
+
*
|
|
74
|
+
* @param table - Table to convert.
|
|
75
|
+
* @param timeColumn - The time/timestamp column to partition on.
|
|
76
|
+
* @param opts - Chunk interval and other options.
|
|
77
|
+
* @returns e.g. `SELECT create_hypertable('conditions', 'time', chunk_time_interval => INTERVAL '7 days')`
|
|
78
|
+
*/
|
|
79
|
+
createHypertable(table, timeColumn, opts) {
|
|
80
|
+
const interval = opts?.chunkTimeInterval ?? '7 days';
|
|
81
|
+
const args = [
|
|
82
|
+
this.escape(table),
|
|
83
|
+
this.escape(timeColumn),
|
|
84
|
+
`chunk_time_interval => ${this.formatInterval(interval)}`,
|
|
85
|
+
];
|
|
86
|
+
if (opts?.ifNotExists) {
|
|
87
|
+
args.push('if_not_exists => TRUE');
|
|
88
|
+
}
|
|
89
|
+
if (opts?.migrateData) {
|
|
90
|
+
args.push('migrate_data => TRUE');
|
|
91
|
+
}
|
|
92
|
+
return `SELECT create_hypertable(${args.join(', ')})`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build a `SELECT add_compression_policy(...)` statement that schedules
|
|
96
|
+
* automatic compression of chunks older than the given interval. The table
|
|
97
|
+
* must have compression enabled first (see {@link enableCompression}).
|
|
98
|
+
*
|
|
99
|
+
* @param table - Hypertable to add the policy to.
|
|
100
|
+
* @param olderThan - Age threshold. A string is a PostgreSQL interval literal
|
|
101
|
+
* (e.g. `'30 days'`); a number is a raw integer threshold for hypertables
|
|
102
|
+
* partitioned on an integer time column.
|
|
103
|
+
* @returns e.g. `SELECT add_compression_policy('conditions', INTERVAL '30 days')`
|
|
104
|
+
*/
|
|
105
|
+
addCompressionPolicy(table, olderThan) {
|
|
106
|
+
return `SELECT add_compression_policy(${this.escape(table)}, ${this.formatInterval(olderThan)})`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Build a `SELECT add_retention_policy(...)` statement that schedules
|
|
110
|
+
* automatic dropping of chunks older than the given interval.
|
|
111
|
+
*
|
|
112
|
+
* @param table - Hypertable to add the policy to.
|
|
113
|
+
* @param olderThan - Age threshold. A string is a PostgreSQL interval literal
|
|
114
|
+
* (e.g. `'90 days'`); a number is a raw integer threshold for hypertables
|
|
115
|
+
* partitioned on an integer time column.
|
|
116
|
+
* @returns e.g. `SELECT add_retention_policy('conditions', INTERVAL '90 days')`
|
|
117
|
+
*/
|
|
118
|
+
addRetentionPolicy(table, olderThan) {
|
|
119
|
+
return `SELECT add_retention_policy(${this.escape(table)}, ${this.formatInterval(olderThan)})`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build a `CREATE MATERIALIZED VIEW ... WITH (timescaledb.continuous) AS ...`
|
|
123
|
+
* statement for a continuous aggregate — a TimescaleDB materialized view that
|
|
124
|
+
* is incrementally and automatically refreshed as new data arrives.
|
|
125
|
+
*
|
|
126
|
+
* @param viewName - Name of the continuous aggregate view to create.
|
|
127
|
+
* @param query - The `SELECT` query (typically using `time_bucket(...)`) that defines the aggregate.
|
|
128
|
+
* @returns e.g. `CREATE MATERIALIZED VIEW "daily_avg" WITH (timescaledb.continuous) AS SELECT ...`
|
|
129
|
+
*/
|
|
130
|
+
createContinuousAggregate(viewName, query) {
|
|
131
|
+
return `CREATE MATERIALIZED VIEW ${this.escapeId(viewName)} WITH (timescaledb.continuous) AS ${query}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build an `ALTER TABLE ... SET (timescaledb.compress, ...)` statement that
|
|
135
|
+
* enables native compression on a hypertable and optionally configures the
|
|
136
|
+
* segment-by / order-by columns.
|
|
137
|
+
*
|
|
138
|
+
* @param table - Hypertable to enable compression on.
|
|
139
|
+
* @param opts - Segment-by and order-by column configuration.
|
|
140
|
+
* @returns e.g. `ALTER TABLE "conditions" SET (timescaledb.compress, timescaledb.compress_segmentby = 'device_id')`
|
|
141
|
+
*/
|
|
142
|
+
enableCompression(table, opts) {
|
|
143
|
+
const settings = ['timescaledb.compress'];
|
|
144
|
+
if (opts?.segmentBy !== undefined) {
|
|
145
|
+
const segmentBy = Array.isArray(opts.segmentBy)
|
|
146
|
+
? opts.segmentBy.join(', ')
|
|
147
|
+
: opts.segmentBy;
|
|
148
|
+
settings.push(`timescaledb.compress_segmentby = ${this.escape(segmentBy)}`);
|
|
149
|
+
}
|
|
150
|
+
if (opts?.orderBy !== undefined) {
|
|
151
|
+
const orderBy = Array.isArray(opts.orderBy) ? opts.orderBy.join(', ') : opts.orderBy;
|
|
152
|
+
settings.push(`timescaledb.compress_orderby = ${this.escape(orderBy)}`);
|
|
153
|
+
}
|
|
154
|
+
return `ALTER TABLE ${this.quoteTable(table)} SET (${settings.join(', ')})`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.TimescaleDBDialect = TimescaleDBDialect;
|
|
158
|
+
/**
|
|
159
|
+
* Create a new TimescaleDB dialect instance.
|
|
160
|
+
*/
|
|
161
|
+
function createTimescaleDBDialect(options) {
|
|
162
|
+
return new TimescaleDBDialect(options || {});
|
|
163
|
+
}
|
|
164
|
+
exports.default = TimescaleDBDialect;
|