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,399 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Typed math-function builder API.
|
|
4
|
+
*
|
|
5
|
+
* Provides typed, autocomplete-friendly builders for common SQL math
|
|
6
|
+
* functions (`ROUND`, `CEIL`/`CEILING`, `FLOOR`, `POWER`, `MOD`, random
|
|
7
|
+
* number generation, `GREATEST`/`LEAST`, `TRUNC`/`TRUNCATE`, ...) across all
|
|
8
|
+
* 11 supported dialects, so callers never need to hand-write raw,
|
|
9
|
+
* dialect-specific SQL for these.
|
|
10
|
+
*
|
|
11
|
+
* This module is intentionally self-contained: it does not add any new
|
|
12
|
+
* dispatch branches to the shared SQL compiler. Every builder resolves
|
|
13
|
+
* directly to a final, dialect-correct SQL fragment string, which is then
|
|
14
|
+
* wrapped with the existing `literal()` helper from `src/operators.ts` so it
|
|
15
|
+
* slots into `attributes: [...]`, `where`, etc. exactly the way `fn()`/
|
|
16
|
+
* `col()`/`cast()` do today.
|
|
17
|
+
*
|
|
18
|
+
* Dialect quirks verified while building this (do not assume symmetry with
|
|
19
|
+
* Postgres/MySQL):
|
|
20
|
+
*
|
|
21
|
+
* - `RANDOM()`/`RAND()` do NOT uniformly return a float in `[0, 1)`:
|
|
22
|
+
* - mysql / mariadb / mssql / db2: `RAND()` -> float in [0, 1).
|
|
23
|
+
* - postgres / cockroachdb / redshift: `RANDOM()` -> float in [0, 1).
|
|
24
|
+
* - sqlite: `RANDOM()` returns a *signed 64-bit integer*
|
|
25
|
+
* (-2^63 .. 2^63-1), NOT a [0,1) float. It must be normalized.
|
|
26
|
+
* - snowflake: `RANDOM()` returns a random *64-bit integer* as well
|
|
27
|
+
* (not [0,1)); the documented way to get a uniform float is
|
|
28
|
+
* `UNIFORM(0::FLOAT, 1::FLOAT, RANDOM())`.
|
|
29
|
+
* - oracle: no `RANDOM()`/`RAND()` at all -- must use
|
|
30
|
+
* `DBMS_RANDOM.VALUE`.
|
|
31
|
+
* - clickhouse: `rand()` returns a `UInt32` (0 .. 2^32-1), NOT [0,1).
|
|
32
|
+
* The [0,1) equivalent is `randCanonical()`.
|
|
33
|
+
*
|
|
34
|
+
* - `CEIL` vs `CEILING`: T-SQL (mssql) has no `CEIL` function at all --
|
|
35
|
+
* only `CEILING`. All other dialects here accept `CEIL`.
|
|
36
|
+
*
|
|
37
|
+
* - `GREATEST`/`LEAST`: not supported natively before SQL Server 2022, so
|
|
38
|
+
* mssql gets a portable nested-`CASE` fallback here (works on every
|
|
39
|
+
* supported SQL Server version, not just 2022+). sqlite has no
|
|
40
|
+
* `GREATEST`/`LEAST` keywords either, but its scalar `MAX`/`MIN` (called
|
|
41
|
+
* with 2+ arguments) behave exactly like `GREATEST`/`LEAST`, so that is
|
|
42
|
+
* used instead.
|
|
43
|
+
*
|
|
44
|
+
* - `MOD`: mssql has no `MOD()` function -- only the `%` operator.
|
|
45
|
+
* clickhouse's function is named `modulo`, not `mod`.
|
|
46
|
+
*
|
|
47
|
+
* - `TRUNCATE`/`TRUNC`: MySQL/MariaDB use `TRUNCATE(value, decimals)`;
|
|
48
|
+
* Oracle/Postgres/CockroachDB/Redshift/DB2/Snowflake use
|
|
49
|
+
* `TRUNC(value, decimals)`; mssql has neither -- truncation is done via
|
|
50
|
+
* `ROUND(value, decimals, 1)` (the undocumented-looking-but-real third
|
|
51
|
+
* "truncate instead of round" argument of T-SQL's `ROUND`); sqlite's
|
|
52
|
+
* `trunc()` math-extension function only takes a single argument (no
|
|
53
|
+
* decimals), so a `TRUNC(value * 10^n) / 10^n` fallback is used when
|
|
54
|
+
* `decimals` is supplied.
|
|
55
|
+
*
|
|
56
|
+
* - ClickHouse function names are matched to ClickHouse's own lower-case
|
|
57
|
+
* documented spelling (`round`, `floor`, `ceil`, `abs`, `sign`, `pow`,
|
|
58
|
+
* `modulo`, `trunc`, `greatest`, `least`, `rand`, `randCanonical`) rather
|
|
59
|
+
* than upper-cased ANSI style, since not all of them have registered
|
|
60
|
+
* case-insensitive aliases.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { round, power, random, greatest } from './query-builders/functions/math';
|
|
65
|
+
* import { col } from '../../operators';
|
|
66
|
+
*
|
|
67
|
+
* User.findAll({
|
|
68
|
+
* attributes: [
|
|
69
|
+
* [round('postgres', col('price'), 2), 'roundedPrice'],
|
|
70
|
+
* [power('postgres', col('base'), 2), 'squared'],
|
|
71
|
+
* [random('postgres'), 'rnd'],
|
|
72
|
+
* [greatest('mssql', col('a'), col('b'), 10), 'best'],
|
|
73
|
+
* ],
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
78
|
+
exports.round = round;
|
|
79
|
+
exports.ceil = ceil;
|
|
80
|
+
exports.floor = floor;
|
|
81
|
+
exports.power = power;
|
|
82
|
+
exports.sqrt = sqrt;
|
|
83
|
+
exports.abs = abs;
|
|
84
|
+
exports.sign = sign;
|
|
85
|
+
exports.mod = mod;
|
|
86
|
+
exports.random = random;
|
|
87
|
+
exports.greatest = greatest;
|
|
88
|
+
exports.least = least;
|
|
89
|
+
exports.truncate = truncate;
|
|
90
|
+
const operators_1 = require("../../operators");
|
|
91
|
+
/** Identifier quote style used per dialect when rendering `col()` refs. */
|
|
92
|
+
function quoteIdentifier(dialect, name) {
|
|
93
|
+
const parts = name.split('.');
|
|
94
|
+
const quoteOne = (part) => {
|
|
95
|
+
if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
96
|
+
return `\`${part.replace(/`/g, '``')}\``;
|
|
97
|
+
}
|
|
98
|
+
if (dialect === 'mssql') {
|
|
99
|
+
return `[${part.replace(/]/g, ']]')}]`;
|
|
100
|
+
}
|
|
101
|
+
// postgres, sqlite, cockroachdb, redshift, db2, oracle, snowflake, clickhouse
|
|
102
|
+
return `"${part.replace(/"/g, '""')}"`;
|
|
103
|
+
};
|
|
104
|
+
return parts.map(quoteOne).join('.');
|
|
105
|
+
}
|
|
106
|
+
/** Escape a plain string as a single-quoted SQL string literal. */
|
|
107
|
+
function quoteStringLiteral(value) {
|
|
108
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Flatten a math-function argument (string, number, ColExpression,
|
|
112
|
+
* FnExpression, LiteralExpression) into a raw SQL fragment string.
|
|
113
|
+
*
|
|
114
|
+
* Per this module's contract: plain strings/numbers are rendered as literal
|
|
115
|
+
* SQL *values* (not identifiers) -- use `col()` to reference a column.
|
|
116
|
+
*/
|
|
117
|
+
function toSqlFragment(dialect, arg) {
|
|
118
|
+
if (typeof arg === 'number') {
|
|
119
|
+
return String(arg);
|
|
120
|
+
}
|
|
121
|
+
if (typeof arg === 'string') {
|
|
122
|
+
return quoteStringLiteral(arg);
|
|
123
|
+
}
|
|
124
|
+
if ((0, operators_1.isFnExpression)(arg)) {
|
|
125
|
+
const args = arg.args.map((a) => toSqlFragment(dialect, a)).join(', ');
|
|
126
|
+
return `${arg.fn}(${args})`;
|
|
127
|
+
}
|
|
128
|
+
if ((0, operators_1.isColExpression)(arg)) {
|
|
129
|
+
return quoteIdentifier(dialect, arg.col);
|
|
130
|
+
}
|
|
131
|
+
if ((0, operators_1.isLiteralExpression)(arg)) {
|
|
132
|
+
// Handles both { __type: 'literal', sql } and { $literal: sql } shapes.
|
|
133
|
+
return arg.sql ?? arg.$literal;
|
|
134
|
+
}
|
|
135
|
+
// Fallback: stringify.
|
|
136
|
+
return String(arg);
|
|
137
|
+
}
|
|
138
|
+
function isClickhouse(dialect) {
|
|
139
|
+
return dialect === 'clickhouse';
|
|
140
|
+
}
|
|
141
|
+
function isMssql(dialect) {
|
|
142
|
+
return dialect === 'mssql';
|
|
143
|
+
}
|
|
144
|
+
function isSqlite(dialect) {
|
|
145
|
+
return dialect === 'sqlite';
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Build a nested CASE expression that computes GREATEST/LEAST-equivalent
|
|
149
|
+
* semantics for dialects lacking a native function (used for mssql, which
|
|
150
|
+
* has no GREATEST/LEAST before SQL Server 2022).
|
|
151
|
+
*
|
|
152
|
+
* @param comparator '>=' for GREATEST, '<=' for LEAST
|
|
153
|
+
*/
|
|
154
|
+
function caseBasedExtreme(dialect, values, comparator) {
|
|
155
|
+
// Build, for each candidate index i, the condition that value[i] is the
|
|
156
|
+
// extreme among all values (i.e. value[i] <comparator> value[j] for all j).
|
|
157
|
+
function build(remaining) {
|
|
158
|
+
if (remaining.length === 1) {
|
|
159
|
+
return remaining[0];
|
|
160
|
+
}
|
|
161
|
+
const [first, ...rest] = remaining;
|
|
162
|
+
const conditions = values.map((v) => `${first} ${comparator} ${v}`).join(' AND ');
|
|
163
|
+
return `CASE WHEN ${conditions} THEN ${first} ELSE ${build(rest)} END`;
|
|
164
|
+
}
|
|
165
|
+
return build(values);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* `ROUND(value[, decimals])`
|
|
169
|
+
*
|
|
170
|
+
* ANSI-consistent across all 11 dialects: MySQL, MariaDB, Postgres, MSSQL,
|
|
171
|
+
* Oracle, SQLite (math-functions extension, 3.35+), CockroachDB, Redshift,
|
|
172
|
+
* DB2, Snowflake, and ClickHouse all accept an optional second `decimals`
|
|
173
|
+
* argument with the same semantics.
|
|
174
|
+
*/
|
|
175
|
+
function round(dialect, expr, decimals) {
|
|
176
|
+
const value = toSqlFragment(dialect, expr);
|
|
177
|
+
const fnName = isClickhouse(dialect) ? 'round' : 'ROUND';
|
|
178
|
+
const args = decimals !== undefined ? `${value}, ${decimals}` : value;
|
|
179
|
+
return (0, operators_1.literal)(`${fnName}(${args})`);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* `CEIL(value)` / `CEILING(value)`.
|
|
183
|
+
*
|
|
184
|
+
* mssql has no `CEIL` -- only `CEILING`. Every other dialect here accepts
|
|
185
|
+
* `CEIL` (ClickHouse spells it lower-case).
|
|
186
|
+
*/
|
|
187
|
+
function ceil(dialect, expr) {
|
|
188
|
+
const value = toSqlFragment(dialect, expr);
|
|
189
|
+
let fnName;
|
|
190
|
+
if (isMssql(dialect)) {
|
|
191
|
+
fnName = 'CEILING';
|
|
192
|
+
}
|
|
193
|
+
else if (isClickhouse(dialect)) {
|
|
194
|
+
fnName = 'ceil';
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
fnName = 'CEIL';
|
|
198
|
+
}
|
|
199
|
+
return (0, operators_1.literal)(`${fnName}(${value})`);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* `FLOOR(value)`. Consistent naming across all 11 dialects.
|
|
203
|
+
*/
|
|
204
|
+
function floor(dialect, expr) {
|
|
205
|
+
const value = toSqlFragment(dialect, expr);
|
|
206
|
+
const fnName = isClickhouse(dialect) ? 'floor' : 'FLOOR';
|
|
207
|
+
return (0, operators_1.literal)(`${fnName}(${value})`);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* `POWER(base, exponent)`.
|
|
211
|
+
*
|
|
212
|
+
* Consistent across all 11 dialects (SQLite's math-functions extension
|
|
213
|
+
* registers both `pow` and `power` as synonyms; ClickHouse registers `pow`
|
|
214
|
+
* and `power` as synonyms too -- lower-cased here for ClickHouse).
|
|
215
|
+
*/
|
|
216
|
+
function power(dialect, base, exponent) {
|
|
217
|
+
const b = toSqlFragment(dialect, base);
|
|
218
|
+
const e = toSqlFragment(dialect, exponent);
|
|
219
|
+
const fnName = isClickhouse(dialect) ? 'pow' : 'POWER';
|
|
220
|
+
return (0, operators_1.literal)(`${fnName}(${b}, ${e})`);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* `SQRT(value)`. Consistent naming across all 11 dialects.
|
|
224
|
+
*/
|
|
225
|
+
function sqrt(dialect, expr) {
|
|
226
|
+
const value = toSqlFragment(dialect, expr);
|
|
227
|
+
const fnName = isClickhouse(dialect) ? 'sqrt' : 'SQRT';
|
|
228
|
+
return (0, operators_1.literal)(`${fnName}(${value})`);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* `ABS(value)`. Consistent naming across all 11 dialects.
|
|
232
|
+
*/
|
|
233
|
+
function abs(dialect, expr) {
|
|
234
|
+
const value = toSqlFragment(dialect, expr);
|
|
235
|
+
const fnName = isClickhouse(dialect) ? 'abs' : 'ABS';
|
|
236
|
+
return (0, operators_1.literal)(`${fnName}(${value})`);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* `SIGN(value)` -- returns -1/0/1.
|
|
240
|
+
*
|
|
241
|
+
* Every dialect here has a native `SIGN()` function EXCEPT sqlite, whose
|
|
242
|
+
* built-in math-functions extension does not include `sign` at all -- so a
|
|
243
|
+
* portable `CASE` expression is used for sqlite instead.
|
|
244
|
+
*/
|
|
245
|
+
function sign(dialect, expr) {
|
|
246
|
+
const value = toSqlFragment(dialect, expr);
|
|
247
|
+
if (isSqlite(dialect)) {
|
|
248
|
+
return (0, operators_1.literal)(`(CASE WHEN ${value} > 0 THEN 1 WHEN ${value} < 0 THEN -1 ELSE 0 END)`);
|
|
249
|
+
}
|
|
250
|
+
const fnName = isClickhouse(dialect) ? 'sign' : 'SIGN';
|
|
251
|
+
return (0, operators_1.literal)(`${fnName}(${value})`);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* `MOD(dividend, divisor)`.
|
|
255
|
+
*
|
|
256
|
+
* mssql has no `MOD()` function at all -- only the `%` operator, so mssql
|
|
257
|
+
* renders `(dividend % divisor)`. ClickHouse's function is named `modulo`
|
|
258
|
+
* (not `mod`). Every other dialect here has a native `MOD(a, b)` function.
|
|
259
|
+
*/
|
|
260
|
+
function mod(dialect, dividend, divisor) {
|
|
261
|
+
const a = toSqlFragment(dialect, dividend);
|
|
262
|
+
const b = toSqlFragment(dialect, divisor);
|
|
263
|
+
if (isMssql(dialect)) {
|
|
264
|
+
return (0, operators_1.literal)(`(${a} % ${b})`);
|
|
265
|
+
}
|
|
266
|
+
if (isClickhouse(dialect)) {
|
|
267
|
+
return (0, operators_1.literal)(`modulo(${a}, ${b})`);
|
|
268
|
+
}
|
|
269
|
+
return (0, operators_1.literal)(`MOD(${a}, ${b})`);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Random value in `[0, 1)`, using the REAL per-dialect function/expression
|
|
273
|
+
* (deliberately not assumed symmetric):
|
|
274
|
+
*
|
|
275
|
+
* - mysql / mariadb: `RAND()`
|
|
276
|
+
* - postgres / cockroachdb / redshift: `RANDOM()`
|
|
277
|
+
* - mssql: `RAND()`
|
|
278
|
+
* - oracle: `DBMS_RANDOM.VALUE` (no `RAND()`/`RANDOM()` exists in Oracle)
|
|
279
|
+
* - db2: `RAND()`
|
|
280
|
+
* - sqlite: `RANDOM()` returns a signed 64-bit *integer*, not a [0,1)
|
|
281
|
+
* float -- normalized here via `(0.5 + RANDOM() / 18446744073709551616.0)`.
|
|
282
|
+
* - snowflake: `RANDOM()` also returns a 64-bit integer, not [0,1) --
|
|
283
|
+
* normalized here via `UNIFORM(0::FLOAT, 1::FLOAT, RANDOM())`, which is
|
|
284
|
+
* Snowflake's documented way to get a uniform float.
|
|
285
|
+
* - clickhouse: `rand()` returns a `UInt32`, not [0,1) -- `randCanonical()`
|
|
286
|
+
* is ClickHouse's documented [0,1) float generator.
|
|
287
|
+
*/
|
|
288
|
+
function random(dialect) {
|
|
289
|
+
switch (dialect) {
|
|
290
|
+
case 'mysql':
|
|
291
|
+
case 'mariadb':
|
|
292
|
+
case 'mssql':
|
|
293
|
+
case 'db2':
|
|
294
|
+
return (0, operators_1.literal)('RAND()');
|
|
295
|
+
case 'postgres':
|
|
296
|
+
case 'cockroachdb':
|
|
297
|
+
case 'redshift':
|
|
298
|
+
return (0, operators_1.literal)('RANDOM()');
|
|
299
|
+
case 'oracle':
|
|
300
|
+
return (0, operators_1.literal)('DBMS_RANDOM.VALUE');
|
|
301
|
+
case 'sqlite':
|
|
302
|
+
return (0, operators_1.literal)('(0.5 + CAST(RANDOM() AS REAL) / 18446744073709551616.0)');
|
|
303
|
+
case 'snowflake':
|
|
304
|
+
return (0, operators_1.literal)('UNIFORM(0::FLOAT, 1::FLOAT, RANDOM())');
|
|
305
|
+
case 'clickhouse':
|
|
306
|
+
return (0, operators_1.literal)('randCanonical()');
|
|
307
|
+
default:
|
|
308
|
+
return (0, operators_1.literal)('RANDOM()');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* `GREATEST(v1, v2, ...)`.
|
|
313
|
+
*
|
|
314
|
+
* - mssql: no native `GREATEST` before SQL Server 2022 -- a portable nested
|
|
315
|
+
* `CASE` expression is used so it works on every supported SQL Server
|
|
316
|
+
* version (not just 2022+).
|
|
317
|
+
* - sqlite: no `GREATEST` keyword -- but scalar `MAX(v1, v2, ...)` (called
|
|
318
|
+
* with 2+ args) behaves exactly like `GREATEST`, so that is used instead.
|
|
319
|
+
* - every other dialect here has native `GREATEST(...)`.
|
|
320
|
+
*/
|
|
321
|
+
function greatest(dialect, ...values) {
|
|
322
|
+
if (values.length === 0) {
|
|
323
|
+
throw new Error('greatest() requires at least one value');
|
|
324
|
+
}
|
|
325
|
+
const rendered = values.map((v) => toSqlFragment(dialect, v));
|
|
326
|
+
if (rendered.length === 1) {
|
|
327
|
+
return (0, operators_1.literal)(rendered[0]);
|
|
328
|
+
}
|
|
329
|
+
if (isMssql(dialect)) {
|
|
330
|
+
return (0, operators_1.literal)(caseBasedExtreme(dialect, rendered, '>='));
|
|
331
|
+
}
|
|
332
|
+
if (isSqlite(dialect)) {
|
|
333
|
+
return (0, operators_1.literal)(`MAX(${rendered.join(', ')})`);
|
|
334
|
+
}
|
|
335
|
+
const fnName = isClickhouse(dialect) ? 'greatest' : 'GREATEST';
|
|
336
|
+
return (0, operators_1.literal)(`${fnName}(${rendered.join(', ')})`);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* `LEAST(v1, v2, ...)`.
|
|
340
|
+
*
|
|
341
|
+
* Same quirks as {@link greatest}: mssql falls back to a nested `CASE`
|
|
342
|
+
* expression, sqlite uses scalar `MIN(v1, v2, ...)`.
|
|
343
|
+
*/
|
|
344
|
+
function least(dialect, ...values) {
|
|
345
|
+
if (values.length === 0) {
|
|
346
|
+
throw new Error('least() requires at least one value');
|
|
347
|
+
}
|
|
348
|
+
const rendered = values.map((v) => toSqlFragment(dialect, v));
|
|
349
|
+
if (rendered.length === 1) {
|
|
350
|
+
return (0, operators_1.literal)(rendered[0]);
|
|
351
|
+
}
|
|
352
|
+
if (isMssql(dialect)) {
|
|
353
|
+
return (0, operators_1.literal)(caseBasedExtreme(dialect, rendered, '<='));
|
|
354
|
+
}
|
|
355
|
+
if (isSqlite(dialect)) {
|
|
356
|
+
return (0, operators_1.literal)(`MIN(${rendered.join(', ')})`);
|
|
357
|
+
}
|
|
358
|
+
const fnName = isClickhouse(dialect) ? 'least' : 'LEAST';
|
|
359
|
+
return (0, operators_1.literal)(`${fnName}(${rendered.join(', ')})`);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Truncate a value toward zero (no rounding), optionally to `decimals`
|
|
363
|
+
* decimal places.
|
|
364
|
+
*
|
|
365
|
+
* - mysql / mariadb: `TRUNCATE(value, decimals)` (function name is
|
|
366
|
+
* `TRUNCATE`, not `TRUNC`; decimals defaults to 0 when omitted).
|
|
367
|
+
* - oracle / postgres / cockroachdb / redshift / db2 / snowflake:
|
|
368
|
+
* `TRUNC(value, decimals)`.
|
|
369
|
+
* - mssql: no `TRUNC`/`TRUNCATE` function at all -- uses the (real, if
|
|
370
|
+
* obscure) third argument of T-SQL's `ROUND(value, decimals, function)`,
|
|
371
|
+
* where a non-zero third argument truncates instead of rounding:
|
|
372
|
+
* `ROUND(value, decimals, 1)`.
|
|
373
|
+
* - sqlite: the math-functions extension's `trunc(X)` only accepts a single
|
|
374
|
+
* argument (no decimals support) -- when `decimals` is supplied, a
|
|
375
|
+
* `TRUNC(value * 10^n) / 10^n` fallback is used.
|
|
376
|
+
* - clickhouse: `trunc(value, decimals)` (lower-case, 2-arg form supported).
|
|
377
|
+
*/
|
|
378
|
+
function truncate(dialect, expr, decimals) {
|
|
379
|
+
const value = toSqlFragment(dialect, expr);
|
|
380
|
+
const d = decimals ?? 0;
|
|
381
|
+
if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
382
|
+
return (0, operators_1.literal)(`TRUNCATE(${value}, ${d})`);
|
|
383
|
+
}
|
|
384
|
+
if (isMssql(dialect)) {
|
|
385
|
+
return (0, operators_1.literal)(`ROUND(${value}, ${d}, 1)`);
|
|
386
|
+
}
|
|
387
|
+
if (isSqlite(dialect)) {
|
|
388
|
+
if (decimals === undefined || decimals === 0) {
|
|
389
|
+
return (0, operators_1.literal)(`trunc(${value})`);
|
|
390
|
+
}
|
|
391
|
+
const factor = Math.pow(10, decimals);
|
|
392
|
+
return (0, operators_1.literal)(`(trunc((${value}) * ${factor}) / ${factor}.0)`);
|
|
393
|
+
}
|
|
394
|
+
if (isClickhouse(dialect)) {
|
|
395
|
+
return (0, operators_1.literal)(decimals !== undefined ? `trunc(${value}, ${decimals})` : `trunc(${value})`);
|
|
396
|
+
}
|
|
397
|
+
// oracle, postgres, cockroachdb, redshift, db2, snowflake
|
|
398
|
+
return (0, operators_1.literal)(`TRUNC(${value}, ${d})`);
|
|
399
|
+
}
|