ts-prorm-orm 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,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;