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,152 @@
1
+ "use strict";
2
+ /**
3
+ * Dialect-agnostic fallback implementation of `Dialect.queryStream()`.
4
+ *
5
+ * Dialects whose driver exposes a real server-side cursor (postgres, mysql,
6
+ * cockroachdb) implement `queryStream` natively for true constant-memory
7
+ * streaming. Every other dialect uses `createPaginatedQueryStream()` here:
8
+ * it pages through the query via repeated `LIMIT`/`OFFSET`-equivalent
9
+ * queries (one dialect-appropriate page-clause per round trip, built with
10
+ * the dialect's own `buildLimitOffset()` by default), instead of loading the
11
+ * whole result set into memory at once. It's not as fast as a native cursor
12
+ * for very large result sets — each page is a fresh query — but it's
13
+ * correct on every dialect that can run a `SELECT * FROM (<sql>) AS alias`
14
+ * wrapped subquery with a trailing pagination clause, which is effectively
15
+ * all of them.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.buildPaginatedPageQuery = buildPaginatedPageQuery;
19
+ exports.createPaginatedQueryStream = createPaginatedQueryStream;
20
+ exports.createOracleQueryStream = createOracleQueryStream;
21
+ const stream_1 = require("stream");
22
+ /** Strips a single trailing `;` (and surrounding whitespace) so the query is safe to wrap as a subquery. */
23
+ function stripTrailingSemicolon(sql) {
24
+ return sql.trim().replace(/;\s*$/, '');
25
+ }
26
+ /**
27
+ * Build the SQL for one page of a paginated stream. Exposed separately from
28
+ * `createPaginatedQueryStream()` so dialects with an unusual pagination
29
+ * syntax (see `createOracleQueryStream()`) can supply their own page-builder
30
+ * while still reusing the shared stream/backpressure/model-mapping logic.
31
+ */
32
+ function buildPaginatedPageQuery(dialect, sql, limit, offset) {
33
+ const inner = stripTrailingSemicolon(sql);
34
+ const pageClause = dialect.buildLimitOffset(limit, offset);
35
+ return `SELECT * FROM (${inner}) AS __prorm_stream_page ${pageClause}`;
36
+ }
37
+ /**
38
+ * Core pull-based streaming loop shared by every fallback implementation.
39
+ * `fetchPage(limit, offset)` is called once per page, only after the
40
+ * previous page has been fully drained by the consumer (real backpressure,
41
+ * not read-ahead buffering) — it must return the raw rows for that page.
42
+ */
43
+ function createPageDrivenStream(fetchPage, options) {
44
+ const batchSize = options?.batchSize || 1000;
45
+ const highWaterMark = options?.highWaterMark || 1000;
46
+ let offset = 0;
47
+ let buffer = [];
48
+ let bufferIndex = 0;
49
+ let exhausted = false;
50
+ let fetching = false;
51
+ const stream = new stream_1.Readable({
52
+ objectMode: true,
53
+ highWaterMark,
54
+ read() {
55
+ pump();
56
+ },
57
+ });
58
+ function pushRow(row) {
59
+ if (options?.mapToModel && options?.model) {
60
+ const instance = new options.model();
61
+ Object.assign(instance, row);
62
+ return stream.push(instance);
63
+ }
64
+ return stream.push(row);
65
+ }
66
+ function pump() {
67
+ if (fetching)
68
+ return;
69
+ // Drain whatever is already buffered first.
70
+ while (bufferIndex < buffer.length) {
71
+ const canContinue = pushRow(buffer[bufferIndex]);
72
+ bufferIndex++;
73
+ if (!canContinue)
74
+ return; // consumer applied backpressure; resume on next read()
75
+ }
76
+ if (exhausted) {
77
+ stream.push(null);
78
+ return;
79
+ }
80
+ fetching = true;
81
+ fetchPage(batchSize, offset)
82
+ .then((rows) => {
83
+ fetching = false;
84
+ buffer = rows;
85
+ bufferIndex = 0;
86
+ offset += rows.length;
87
+ if (rows.length < batchSize) {
88
+ exhausted = true;
89
+ }
90
+ if (rows.length === 0) {
91
+ stream.push(null);
92
+ return;
93
+ }
94
+ pump();
95
+ })
96
+ .catch((error) => {
97
+ fetching = false;
98
+ stream.destroy(error instanceof Error ? error : new Error(String(error)));
99
+ });
100
+ }
101
+ return stream;
102
+ }
103
+ /**
104
+ * Generic LIMIT/OFFSET-paginated `queryStream` fallback. Suitable for any
105
+ * dialect whose `buildLimitOffset()` returns a self-sufficient trailing
106
+ * clause (sqlite, mariadb, redshift, snowflake, clickhouse, duckdb, hana,
107
+ * spanner, mssql, db2 all qualify — mssql's own `buildLimitOffset` already
108
+ * injects a no-op `ORDER BY` when none is supplied, so it works unmodified
109
+ * here).
110
+ */
111
+ function createPaginatedQueryStream(dialect, sql, options) {
112
+ if (!sql || !sql.trim()) {
113
+ const stream = new stream_1.Readable({ objectMode: true, read() { } });
114
+ process.nextTick(() => stream.destroy(new Error('queryStream: sql must be a non-empty string')));
115
+ return stream;
116
+ }
117
+ return createPageDrivenStream(async (limit, offset) => {
118
+ const pageSql = buildPaginatedPageQuery(dialect, sql, limit, offset);
119
+ const result = await dialect.query(pageSql, options?.transaction ? { transaction: options.transaction } : undefined);
120
+ return result.rows || [];
121
+ }, options);
122
+ }
123
+ /**
124
+ * Oracle-specific streaming. Oracle's `buildLimitOffset()` returns a bare
125
+ * `WHERE ROWNUM <= n` fragment that only limits the *first* n rows of the
126
+ * result set — it doesn't skip the first `offset` rows, so wrapping it the
127
+ * same way as `createPaginatedQueryStream()` would return the same leading
128
+ * rows on every page instead of paging forward. Rather than depend on that,
129
+ * this builds the standard "windowed ROWNUM" pagination idiom directly,
130
+ * which is correct for offset+limit on any Oracle version (no dependency on
131
+ * 12c's OFFSET/FETCH syntax):
132
+ *
133
+ * SELECT * FROM (
134
+ * SELECT a.*, ROWNUM rnum FROM (<sql>) a WHERE ROWNUM <= :offset + :limit
135
+ * ) WHERE rnum > :offset
136
+ */
137
+ function createOracleQueryStream(dialect, sql, options) {
138
+ if (!sql || !sql.trim()) {
139
+ const stream = new stream_1.Readable({ objectMode: true, read() { } });
140
+ process.nextTick(() => stream.destroy(new Error('queryStream: sql must be a non-empty string')));
141
+ return stream;
142
+ }
143
+ const inner = stripTrailingSemicolon(sql);
144
+ return createPageDrivenStream(async (limit, offset) => {
145
+ const upperBound = offset + limit;
146
+ const pageSql = `SELECT * FROM (SELECT __prorm_inner.*, ROWNUM __prorm_rnum FROM (${inner}) __prorm_inner ` +
147
+ `WHERE ROWNUM <= ${upperBound}) WHERE __prorm_rnum > ${offset}`;
148
+ const result = await dialect.query(pageSql, options?.transaction ? { transaction: options.transaction } : undefined);
149
+ // Strip the synthetic __prorm_rnum column so callers see only real columns.
150
+ return (result.rows || []).map(({ __prorm_rnum, ...row }) => row);
151
+ }, options);
152
+ }
@@ -0,0 +1,433 @@
1
+ "use strict";
2
+ /**
3
+ * QuestDB dialect implementation for the TypeScript ORM
4
+ *
5
+ * QuestDB is a high-performance, column-oriented time-series database that
6
+ * speaks the PostgreSQL wire protocol, so this dialect extends
7
+ * `PostgresDialect` and reuses the exact same `pg` driver. Everything is
8
+ * inherited from Postgres except the handful of areas where QuestDB's SQL
9
+ * dialect genuinely diverges. The notable differences this subclass models:
10
+ *
11
+ * - Default SQL port is 8812 (QuestDB's `pgwire` port), not Postgres's 5432.
12
+ *
13
+ * - Designated timestamp + partitioning. Time-series tables in QuestDB elect
14
+ * one `TIMESTAMP` column as the "designated timestamp" and are physically
15
+ * partitioned by a time unit:
16
+ * `CREATE TABLE t (...) TIMESTAMP(ts) PARTITION BY DAY`
17
+ * Supported partition units are `NONE | YEAR | MONTH | DAY | HOUR` (WEEK is
18
+ * also accepted by QuestDB but rarely used). These are supplied via the
19
+ * table options (`timestamp` + `partitionBy`).
20
+ *
21
+ * - `SYMBOL` type for low-cardinality repeated strings (e.g. ticker symbols,
22
+ * device ids). QuestDB stores SYMBOLs as an interned dictionary of ints,
23
+ * which is far more compact/faster than STRING for repeated values. Columns
24
+ * can opt into `SYMBOL CAPACITY n` (dictionary size hint) and `CACHE`
25
+ * (keep the dictionary in memory).
26
+ *
27
+ * - WAL tables. Partitioned tables can be created with a write-ahead log
28
+ * (`WAL`, the default in modern QuestDB) or without it (`BYPASS WAL`).
29
+ *
30
+ * - No traditional constraints. QuestDB has NO PRIMARY KEY, NO FOREIGN KEY,
31
+ * NO UNIQUE, NO NOT NULL and NO DEFAULT clauses in `CREATE TABLE` — those
32
+ * concepts don't exist in the engine, so they are deliberately omitted from
33
+ * the generated DDL. Row de-duplication is instead expressed with a
34
+ * `DEDUP UPSERT KEYS(...)` clause (WAL tables only), which upserts rows that
35
+ * share the given key columns (the designated timestamp must be one of
36
+ * them).
37
+ *
38
+ * - Type mapping. QuestDB's type names differ from Postgres's:
39
+ * INTEGER -> INT, BIGINT -> LONG, FLOAT -> FLOAT, DOUBLE -> DOUBLE,
40
+ * BOOLEAN -> BOOLEAN, STRING/TEXT/CHAR -> STRING, SYMBOL -> SYMBOL,
41
+ * DATE/DATETIME/TIME -> TIMESTAMP, BLOB -> BINARY, UUID -> UUID.
42
+ *
43
+ * The core DDL builder here (`buildCreateTableSQL`) is a pure, synchronous
44
+ * function that returns the SQL string, so it can be unit-tested without a
45
+ * live connection; `createTable()` simply runs it through the inherited
46
+ * `query()`.
47
+ *
48
+ * @see https://questdb.io/docs/
49
+ */
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.QuestDBDialect = void 0;
52
+ exports.createQuestDBDialect = createQuestDBDialect;
53
+ const index_1 = require("../postgres/index");
54
+ const prorm_1 = require("../../prorm");
55
+ /**
56
+ * QuestDB dialect class. Extends the PostgreSQL dialect (QuestDB is
57
+ * PG-wire-compatible) and overrides only the CREATE TABLE DDL and the type
58
+ * mapping to reflect QuestDB's time-series-specific SQL.
59
+ */
60
+ class QuestDBDialect extends index_1.PostgresDialect {
61
+ constructor(config = {}) {
62
+ // QuestDB's PostgreSQL-wire (pgwire) port defaults to 8812.
63
+ super({ port: 8812, ...config });
64
+ this.name = 'questdb';
65
+ }
66
+ /**
67
+ * Build the column fragment for a single column, honouring QuestDB's
68
+ * `SYMBOL [CAPACITY n] [CACHE]` syntax and deliberately omitting the
69
+ * PRIMARY KEY / UNIQUE / FOREIGN KEY / NOT NULL / DEFAULT clauses that
70
+ * QuestDB does not support in CREATE TABLE.
71
+ */
72
+ buildQuestColumnSql(columnName, definition) {
73
+ const dt = definition.type;
74
+ const isSymbol = definition.symbol === true ||
75
+ (typeof dt === 'object' && dt !== null && dt.key === 'SYMBOL') ||
76
+ (typeof definition.type === 'string' && definition.type.toUpperCase() === 'SYMBOL');
77
+ let typeSql;
78
+ if (isSymbol) {
79
+ typeSql = 'SYMBOL';
80
+ if (definition.symbolCapacity) {
81
+ typeSql += ` CAPACITY ${definition.symbolCapacity}`;
82
+ }
83
+ if (definition.symbolCache) {
84
+ typeSql += ' CACHE';
85
+ }
86
+ }
87
+ else {
88
+ typeSql = this.getDataTypeSql(definition.type);
89
+ }
90
+ // Note: PRIMARY KEY / UNIQUE / FOREIGN KEY / NOT NULL / DEFAULT are
91
+ // intentionally NOT emitted — QuestDB's CREATE TABLE grammar has no such
92
+ // column constraints.
93
+ return `${this.escapeId(columnName)} ${typeSql}`;
94
+ }
95
+ /**
96
+ * Pure, synchronous builder for a QuestDB `CREATE TABLE` statement. Returns
97
+ * the SQL string so it can be unit-tested without a database connection.
98
+ *
99
+ * Emits, in order:
100
+ * CREATE TABLE [IF NOT EXISTS] name (cols...)
101
+ * [TIMESTAMP(designated) PARTITION BY UNIT [WAL|BYPASS WAL]]
102
+ * [DEDUP UPSERT KEYS(...)]
103
+ */
104
+ buildCreateTableSQL(tableName, columns, options) {
105
+ const columnDefs = [];
106
+ for (const [columnName, definition] of Object.entries(columns)) {
107
+ columnDefs.push(this.buildQuestColumnSql(columnName, definition));
108
+ }
109
+ let sql = 'CREATE TABLE';
110
+ if (options?.ifNotExists) {
111
+ sql += ' IF NOT EXISTS';
112
+ }
113
+ sql += ` ${this.escapeId(tableName)} (${columnDefs.join(', ')})`;
114
+ // Designated timestamp + time partitioning. QuestDB only partitions tables
115
+ // that declare a designated timestamp, so PARTITION BY is emitted inside
116
+ // the timestamp branch.
117
+ if (options?.timestamp) {
118
+ sql += ` TIMESTAMP(${this.escapeId(options.timestamp)})`;
119
+ const unit = options.partitionBy ?? 'NONE';
120
+ sql += ` PARTITION BY ${unit}`;
121
+ // WAL / BYPASS WAL applies to partitioned tables.
122
+ if (options.wal === true) {
123
+ sql += ' WAL';
124
+ }
125
+ else if (options.wal === false) {
126
+ sql += ' BYPASS WAL';
127
+ }
128
+ // DEDUP requires a designated timestamp (and a WAL table).
129
+ if (options.dedupUpsertKeys && options.dedupUpsertKeys.length > 0) {
130
+ const keys = options.dedupUpsertKeys.map((k) => this.escapeId(k)).join(', ');
131
+ sql += ` DEDUP UPSERT KEYS(${keys})`;
132
+ }
133
+ }
134
+ return sql;
135
+ }
136
+ /**
137
+ * Create a new table using QuestDB's CREATE TABLE grammar. Delegates SQL
138
+ * construction to the synchronous {@link buildCreateTableSQL} and runs it
139
+ * through the inherited `query()`.
140
+ */
141
+ async createTable(tableName, columns, options) {
142
+ const sql = this.buildCreateTableSQL(tableName, columns, options);
143
+ await this.query(sql);
144
+ }
145
+ /**
146
+ * Map an ORM data type to QuestDB's type name. QuestDB's type vocabulary
147
+ * differs from PostgreSQL's, so this overrides the inherited mapping.
148
+ * @see https://questdb.io/docs/reference/sql/datatypes/
149
+ */
150
+ getDataTypeSql(dataType) {
151
+ // String shorthand types (e.g. 'BIGINT', 'DATETIME') — normalize the
152
+ // common cross-dialect names to QuestDB equivalents.
153
+ if (typeof dataType === 'string') {
154
+ const up = dataType.toUpperCase();
155
+ if (/^DATETIME(\(\d+\))?$/.test(up) || up === 'TIMESTAMP' || up === 'DATE' || up === 'TIME') {
156
+ return 'TIMESTAMP';
157
+ }
158
+ if (up === 'BIGINT')
159
+ return 'LONG';
160
+ if (up === 'INTEGER' || up === 'INT')
161
+ return 'INT';
162
+ if (up === 'DOUBLE' || up === 'DOUBLE PRECISION' || up === 'DECIMAL' || up === 'NUMERIC') {
163
+ return 'DOUBLE';
164
+ }
165
+ if (up === 'REAL')
166
+ return 'FLOAT';
167
+ if (up === 'TEXT' || up === 'VARCHAR' || up === 'CHAR' || up === 'STRING')
168
+ return 'STRING';
169
+ if (up === 'SYMBOL')
170
+ return 'SYMBOL';
171
+ if (up === 'BOOL' || up === 'BOOLEAN')
172
+ return 'BOOLEAN';
173
+ return dataType;
174
+ }
175
+ if (!dataType || typeof dataType !== 'object') {
176
+ return 'STRING';
177
+ }
178
+ const dt = dataType;
179
+ switch (dt.key) {
180
+ case 'INTEGER':
181
+ return 'INT';
182
+ case 'BIGINT':
183
+ return 'LONG';
184
+ case 'FLOAT':
185
+ return 'FLOAT';
186
+ case 'DOUBLE':
187
+ case 'DECIMAL':
188
+ return 'DOUBLE';
189
+ case 'BOOLEAN':
190
+ return 'BOOLEAN';
191
+ case 'STRING':
192
+ case 'TEXT':
193
+ case 'CHAR':
194
+ return 'STRING';
195
+ case 'SYMBOL':
196
+ return 'SYMBOL';
197
+ case 'DATE':
198
+ case 'DATEONLY':
199
+ case 'TIME':
200
+ return 'TIMESTAMP';
201
+ case 'UUID':
202
+ return 'UUID';
203
+ case 'BLOB':
204
+ return 'BINARY';
205
+ case 'JSON':
206
+ case 'JSONB':
207
+ // QuestDB has no native JSON type; store as STRING.
208
+ return 'STRING';
209
+ default:
210
+ // Fall back to the PostgreSQL mapping for anything QuestDB shares.
211
+ return super.getDataTypeSql(dataType);
212
+ }
213
+ }
214
+ // ===========================================================================
215
+ // Pagination
216
+ // ===========================================================================
217
+ /**
218
+ * Build a QuestDB `LIMIT` clause. QuestDB does NOT support the SQL-standard
219
+ * `OFFSET` keyword; instead it uses:
220
+ * - `LIMIT n` — first `n` rows (or last `n` when negative).
221
+ * - `LIMIT lo, hi` — rows in the half-open range `(lo, hi]`, which is how
222
+ * an offset is expressed. To skip `offset` rows and
223
+ * return `limit` of them we emit `LIMIT offset, offset+limit`.
224
+ *
225
+ * @see https://questdb.io/docs/reference/sql/limit/
226
+ */
227
+ buildLimitOffset(limit, offset) {
228
+ const hasLimit = limit !== undefined && limit !== null;
229
+ const hasOffset = offset !== undefined && offset !== null;
230
+ if (hasLimit && hasOffset) {
231
+ const lo = Number(offset);
232
+ const hi = lo + Number(limit);
233
+ return ` LIMIT ${lo}, ${hi}`;
234
+ }
235
+ if (hasLimit) {
236
+ return ` LIMIT ${Number(limit)}`;
237
+ }
238
+ // Offset-only has no direct QuestDB form (an upper bound is required for
239
+ // `LIMIT lo, hi`), so nothing is emitted. Callers needing a lower bound
240
+ // without an explicit page size should pass an explicit `limit`.
241
+ return '';
242
+ }
243
+ // ===========================================================================
244
+ // DML — INSERT / UPSERT / UPDATE / DELETE
245
+ // ===========================================================================
246
+ /**
247
+ * Build a QuestDB `INSERT`. QuestDB has **no** `ON CONFLICT` clause (row
248
+ * de-duplication is configured on the table via `DEDUP UPSERT KEYS(...)` at
249
+ * `CREATE TABLE` time) and **no** `RETURNING` clause, so both are omitted —
250
+ * any `upsert`/`conflictFields`/`returning` options are ignored here.
251
+ */
252
+ buildInsertQuery(tableName, values, _options) {
253
+ const columns = Object.keys(values);
254
+ const processedValues = [];
255
+ const placeholders = [];
256
+ let paramIndex = 1;
257
+ for (const value of Object.values(values)) {
258
+ if (value instanceof prorm_1.Literal) {
259
+ placeholders.push(value.val);
260
+ }
261
+ else {
262
+ placeholders.push(`$${paramIndex}`);
263
+ processedValues.push(value);
264
+ paramIndex++;
265
+ }
266
+ }
267
+ const sql = `INSERT INTO ${this.escapeId(tableName)} ` +
268
+ `(${columns.map((c) => this.escapeId(c)).join(', ')}) ` +
269
+ `VALUES (${placeholders.join(', ')})`;
270
+ return { sql, values: processedValues };
271
+ }
272
+ /**
273
+ * QuestDB has no `INSERT ... ON CONFLICT DO UPDATE`. The closest concept is a
274
+ * table-level `DEDUP UPSERT KEYS(...)` declaration, after which a plain
275
+ * `INSERT` transparently upserts rows sharing the dedup keys. This therefore
276
+ * emits a bare `INSERT` (no `ON CONFLICT`, no `RETURNING`); `conflictFields`
277
+ * and `updateOnDuplicate` are ignored because QuestDB resolves conflicts from
278
+ * the table's DEDUP configuration, not the statement.
279
+ */
280
+ buildUpsertQuery(tableName, values, _options) {
281
+ return this.buildInsertQuery(tableName, values);
282
+ }
283
+ /**
284
+ * Build a QuestDB `UPDATE`. QuestDB supports `UPDATE t SET ... WHERE ...` but
285
+ * does NOT support `LIMIT` on updates nor a `RETURNING` clause, so those
286
+ * options are omitted.
287
+ * @see https://questdb.io/docs/reference/sql/update/
288
+ */
289
+ buildUpdateQuery(tableName, values, where, _options) {
290
+ const setClauses = [];
291
+ const queryValues = [];
292
+ let paramIndex = 1;
293
+ for (const [key, value] of Object.entries(values)) {
294
+ if (value instanceof prorm_1.Literal) {
295
+ setClauses.push(`${this.escapeId(key)} = ${value.val}`);
296
+ }
297
+ else {
298
+ setClauses.push(`${this.escapeId(key)} = $${paramIndex}`);
299
+ queryValues.push(value);
300
+ paramIndex++;
301
+ }
302
+ }
303
+ const whereClause = this.buildWhereClause(where);
304
+ let sql = `UPDATE ${this.escapeId(tableName)} SET ${setClauses.join(', ')}`;
305
+ if (whereClause.sql) {
306
+ sql += ` WHERE ${whereClause.sql}`;
307
+ }
308
+ return { sql, values: [...queryValues, ...whereClause.values] };
309
+ }
310
+ /**
311
+ * Build a QuestDB "delete". IMPORTANT: QuestDB does **not** support
312
+ * row-level `DELETE`. Bulk removal is done by dropping whole time partitions
313
+ * (`ALTER TABLE t DROP PARTITION ...`) or emptying the table
314
+ * (`TRUNCATE TABLE t`). Accordingly:
315
+ * - `options.truncate` produces a valid `TRUNCATE TABLE t` statement.
316
+ * - Any other call throws, because emitting a `DELETE ... WHERE ...` that
317
+ * the server will reject would be misleading. Callers wanting to remove
318
+ * a time range should drop the relevant partition(s) via raw SQL / the
319
+ * partition APIs instead.
320
+ * @see https://questdb.io/docs/reference/sql/alter-table-drop-partition/
321
+ */
322
+ buildDeleteQuery(tableName, _where, options) {
323
+ if (options?.truncate) {
324
+ return { sql: `TRUNCATE TABLE ${this.escapeId(tableName)}`, values: [] };
325
+ }
326
+ throw new Error('QuestDB does not support row-level DELETE. Remove data by dropping ' +
327
+ 'time partitions (ALTER TABLE ... DROP PARTITION ...) or truncating ' +
328
+ 'the table (pass { truncate: true }).');
329
+ }
330
+ // ===========================================================================
331
+ // DDL — columns, indexes, rename, unsupported constraints
332
+ // ===========================================================================
333
+ /**
334
+ * Pure builder for `ALTER TABLE t ADD COLUMN name type` (testable without a
335
+ * connection). QuestDB supports adding a column but NOT the per-column
336
+ * constraints (NOT NULL / DEFAULT / PRIMARY KEY / UNIQUE / REFERENCES) that
337
+ * the Postgres builder would emit, so this reuses the QuestDB column builder.
338
+ */
339
+ buildAddColumnSQL(tableName, columnName, definition) {
340
+ return `ALTER TABLE ${this.escapeId(tableName)} ADD COLUMN ${this.buildQuestColumnSql(columnName, definition)}`;
341
+ }
342
+ /**
343
+ * Add a column. Overridden so QuestDB's constraint-free `ADD COLUMN` grammar
344
+ * (and SYMBOL support) is used rather than the inherited Postgres one.
345
+ */
346
+ async addColumn(tableName, columnName, definition) {
347
+ await this.query(this.buildAddColumnSQL(tableName, columnName, definition));
348
+ }
349
+ /**
350
+ * Pure builder for a QuestDB SYMBOL-column index. QuestDB has no
351
+ * PostgreSQL-style `CREATE INDEX`; indexes exist only on `SYMBOL` columns and
352
+ * are added via `ALTER TABLE t ALTER COLUMN col ADD INDEX [CAPACITY n]`.
353
+ * @see https://questdb.io/docs/reference/sql/alter-table-alter-column-add-index/
354
+ */
355
+ buildAddIndexSQL(tableName, column, capacity) {
356
+ let sql = `ALTER TABLE ${this.escapeId(tableName)} ALTER COLUMN ${this.escapeId(column)} ADD INDEX`;
357
+ if (capacity) {
358
+ sql += ` CAPACITY ${capacity}`;
359
+ }
360
+ return sql;
361
+ }
362
+ /**
363
+ * Pure builder for dropping a QuestDB SYMBOL index:
364
+ * `ALTER TABLE t ALTER COLUMN col DROP INDEX`.
365
+ */
366
+ buildDropIndexSQL(tableName, column) {
367
+ return `ALTER TABLE ${this.escapeId(tableName)} ALTER COLUMN ${this.escapeId(column)} DROP INDEX`;
368
+ }
369
+ /**
370
+ * Add an index. In QuestDB an "index" is a SYMBOL-column index, so each field
371
+ * is indexed with its own `ALTER COLUMN ... ADD INDEX`. The `indexName` and
372
+ * PG-only options (unique/using/expression/where/include) have no meaning and
373
+ * are ignored.
374
+ */
375
+ async addIndex(tableName, _indexName, fields = [], options) {
376
+ for (const field of fields) {
377
+ await this.query(this.buildAddIndexSQL(tableName, field, options?.capacity));
378
+ }
379
+ }
380
+ /**
381
+ * Create an index (SYMBOL-column index) from an {@link IndexDefinition}.
382
+ */
383
+ async createIndex(tableName, indexDef) {
384
+ for (const field of indexDef.fields || []) {
385
+ await this.query(this.buildAddIndexSQL(tableName, field, indexDef.capacity));
386
+ }
387
+ }
388
+ /**
389
+ * Remove an index. QuestDB drops the index off the SYMBOL column, so the
390
+ * `indexName` argument is interpreted as the column name.
391
+ */
392
+ async removeIndex(tableName, columnName) {
393
+ await this.query(this.buildDropIndexSQL(tableName, columnName));
394
+ }
395
+ async dropIndex(tableName, columnName, _options) {
396
+ await this.query(this.buildDropIndexSQL(tableName, columnName));
397
+ }
398
+ /**
399
+ * Pure builder for `RENAME TABLE old TO new`. QuestDB renames tables with a
400
+ * dedicated `RENAME TABLE` statement, NOT `ALTER TABLE ... RENAME TO`.
401
+ * @see https://questdb.io/docs/reference/sql/rename/
402
+ */
403
+ buildRenameTableSQL(oldName, newName) {
404
+ return `RENAME TABLE ${this.escapeId(oldName)} TO ${this.escapeId(newName)}`;
405
+ }
406
+ async renameTable(oldName, newName) {
407
+ await this.query(this.buildRenameTableSQL(oldName, newName));
408
+ }
409
+ // ---------------------------------------------------------------------------
410
+ // Unsupported relational constraints. QuestDB has no PRIMARY KEY / FOREIGN
411
+ // KEY / UNIQUE / CHECK constraints, so these fail loudly rather than emitting
412
+ // SQL the engine cannot parse.
413
+ // ---------------------------------------------------------------------------
414
+ async addForeignKey() {
415
+ throw new Error('QuestDB does not support FOREIGN KEY constraints.');
416
+ }
417
+ async addConstraint() {
418
+ throw new Error('QuestDB does not support table constraints (PRIMARY KEY / FOREIGN KEY / ' +
419
+ 'UNIQUE / CHECK). Use DEDUP UPSERT KEYS on CREATE TABLE for row de-duplication.');
420
+ }
421
+ async createConstraint(_tableName, _constraintDef) {
422
+ throw new Error('QuestDB does not support table constraints (PRIMARY KEY / FOREIGN KEY / ' +
423
+ 'UNIQUE / CHECK). Use DEDUP UPSERT KEYS on CREATE TABLE for row de-duplication.');
424
+ }
425
+ }
426
+ exports.QuestDBDialect = QuestDBDialect;
427
+ /**
428
+ * Create a new QuestDB dialect instance.
429
+ */
430
+ function createQuestDBDialect(options) {
431
+ return new QuestDBDialect(options || {});
432
+ }
433
+ exports.default = QuestDBDialect;