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,518 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.concat = concat;
|
|
4
|
+
exports.substring = substring;
|
|
5
|
+
exports.trim = trim;
|
|
6
|
+
exports.ltrim = ltrim;
|
|
7
|
+
exports.rtrim = rtrim;
|
|
8
|
+
exports.upper = upper;
|
|
9
|
+
exports.lower = lower;
|
|
10
|
+
exports.length = length;
|
|
11
|
+
exports.replace = replace;
|
|
12
|
+
exports.lpad = lpad;
|
|
13
|
+
exports.rpad = rpad;
|
|
14
|
+
exports.split = split;
|
|
15
|
+
exports.repeat = repeat;
|
|
16
|
+
exports.reverse = reverse;
|
|
17
|
+
/**
|
|
18
|
+
* Typed string-function builders.
|
|
19
|
+
*
|
|
20
|
+
* These helpers produce dialect-correct SQL fragments for common string
|
|
21
|
+
* operations (CONCAT, SUBSTRING, TRIM, padding, etc.) so callers never need
|
|
22
|
+
* to hand-write raw SQL for the handful of functions that genuinely differ
|
|
23
|
+
* between dialects (Postgres `||` vs `CONCAT()`, Oracle `SUBSTR` vs the
|
|
24
|
+
* standard `SUBSTRING`, MSSQL `LEN` vs `LENGTH`/`CHAR_LENGTH`, etc.)
|
|
25
|
+
*
|
|
26
|
+
* This module is intentionally self-contained: it does not modify
|
|
27
|
+
* `src/operators.ts` or `src/query-builders/sql-compiler.ts`. It only reads
|
|
28
|
+
* the `literal`, `ColExpression`, `FnExpression`, and `LiteralExpression`
|
|
29
|
+
* primitives from `../../operators` and returns plain `{ $literal: string }`
|
|
30
|
+
* values (via `literal()`) that can be dropped into `attributes`, `where`,
|
|
31
|
+
* etc. exactly like any other literal expression.
|
|
32
|
+
*/
|
|
33
|
+
const operators_1 = require("../../operators");
|
|
34
|
+
// ==================== Internal rendering helpers ====================
|
|
35
|
+
/**
|
|
36
|
+
* Quote/escape a raw string as a SQL string literal.
|
|
37
|
+
* Doubling the single quote is valid escaping syntax across all 11
|
|
38
|
+
* supported dialects (standard SQL escaping).
|
|
39
|
+
*/
|
|
40
|
+
function quoteStringLiteral(value) {
|
|
41
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Quote an identifier (column name), honoring dialect-specific quoting
|
|
45
|
+
* characters and supporting dotted `table.column` references.
|
|
46
|
+
*/
|
|
47
|
+
function quoteIdentifier(dialect, name) {
|
|
48
|
+
const parts = name.split('.');
|
|
49
|
+
return parts.map((part) => quoteIdentifierPart(dialect, part)).join('.');
|
|
50
|
+
}
|
|
51
|
+
function quoteIdentifierPart(dialect, part) {
|
|
52
|
+
switch (dialect) {
|
|
53
|
+
case 'mysql':
|
|
54
|
+
case 'mariadb':
|
|
55
|
+
case 'clickhouse':
|
|
56
|
+
return `\`${part.replace(/`/g, '``')}\``;
|
|
57
|
+
case 'mssql':
|
|
58
|
+
return `[${part.replace(/\]/g, ']]')}]`;
|
|
59
|
+
case 'oracle':
|
|
60
|
+
case 'sqlite':
|
|
61
|
+
case 'postgres':
|
|
62
|
+
case 'cockroachdb':
|
|
63
|
+
case 'redshift':
|
|
64
|
+
case 'db2':
|
|
65
|
+
case 'snowflake':
|
|
66
|
+
return `"${part.replace(/"/g, '""')}"`;
|
|
67
|
+
default:
|
|
68
|
+
return `"${part.replace(/"/g, '""')}"`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Render a `SqlExpr` (column-like argument) into a raw SQL fragment.
|
|
73
|
+
*
|
|
74
|
+
* Plain strings are treated as literal string VALUES and are quoted.
|
|
75
|
+
* `ColExpression`/`FnExpression`/`LiteralExpression` objects are unwrapped
|
|
76
|
+
* and rendered as expressions/identifiers.
|
|
77
|
+
*/
|
|
78
|
+
function toSqlFragment(dialect, arg) {
|
|
79
|
+
if (typeof arg === 'number') {
|
|
80
|
+
return String(arg);
|
|
81
|
+
}
|
|
82
|
+
if (typeof arg === 'string') {
|
|
83
|
+
return quoteStringLiteral(arg);
|
|
84
|
+
}
|
|
85
|
+
if (arg && typeof arg === 'object') {
|
|
86
|
+
if (arg.__type === 'col') {
|
|
87
|
+
return quoteIdentifier(dialect, arg.col);
|
|
88
|
+
}
|
|
89
|
+
if (arg.__type === 'fn') {
|
|
90
|
+
const fnExpr = arg;
|
|
91
|
+
const args = fnExpr.args.map((a) => toSqlFragment(dialect, a));
|
|
92
|
+
return `${fnExpr.fn}(${args.join(', ')})`;
|
|
93
|
+
}
|
|
94
|
+
if (arg.__type === 'literal') {
|
|
95
|
+
return arg.sql;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Fallback - should not normally be reached given the SqlExpr type.
|
|
99
|
+
return String(arg);
|
|
100
|
+
}
|
|
101
|
+
function unsupported(fnName, dialect, reason) {
|
|
102
|
+
throw new Error(`[query-builders/functions/string] ${fnName}() is not supported for dialect "${dialect}": ${reason}`);
|
|
103
|
+
}
|
|
104
|
+
// ==================== concat ====================
|
|
105
|
+
/**
|
|
106
|
+
* String concatenation.
|
|
107
|
+
*
|
|
108
|
+
* - MySQL, MariaDB, MSSQL, Snowflake, ClickHouse: use the variadic
|
|
109
|
+
* `CONCAT(a, b, c, ...)` function (all support 2+ arguments).
|
|
110
|
+
* - Postgres, CockroachDB, Redshift, SQLite, Oracle, DB2: use the `||`
|
|
111
|
+
* operator. These dialects' `CONCAT()` function (where it exists at all)
|
|
112
|
+
* is limited to exactly 2 arguments (Oracle, DB2), so `||` is used
|
|
113
|
+
* uniformly for correctness with any number of parts. Postgres/CockroachDB/
|
|
114
|
+
* SQLite treat `||` as the idiomatic concatenation operator.
|
|
115
|
+
*
|
|
116
|
+
* @param parts - Column-like arguments (columns via `col()`, nested
|
|
117
|
+
* expressions via `fn()`, or literal string values as plain strings).
|
|
118
|
+
*/
|
|
119
|
+
function concat(dialect, ...parts) {
|
|
120
|
+
if (parts.length === 0) {
|
|
121
|
+
throw new Error('[query-builders/functions/string] concat() requires at least one argument');
|
|
122
|
+
}
|
|
123
|
+
const rendered = parts.map((p) => toSqlFragment(dialect, p));
|
|
124
|
+
switch (dialect) {
|
|
125
|
+
case 'mysql':
|
|
126
|
+
case 'mariadb':
|
|
127
|
+
case 'mssql':
|
|
128
|
+
case 'snowflake':
|
|
129
|
+
case 'clickhouse':
|
|
130
|
+
return wrap(`CONCAT(${rendered.join(', ')})`);
|
|
131
|
+
case 'postgres':
|
|
132
|
+
case 'cockroachdb':
|
|
133
|
+
case 'redshift':
|
|
134
|
+
case 'sqlite':
|
|
135
|
+
case 'oracle':
|
|
136
|
+
case 'db2':
|
|
137
|
+
return wrap(rendered.join(' || '));
|
|
138
|
+
default:
|
|
139
|
+
return wrap(`CONCAT(${rendered.join(', ')})`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function wrap(sql) {
|
|
143
|
+
// `literal()` returns { $literal: string }. We also attach __type/sql so
|
|
144
|
+
// callers who want the LiteralExpression shape can use it interchangeably;
|
|
145
|
+
// both shapes are recognized by isLiteralExpression()/isRawLiteral().
|
|
146
|
+
const lit = (0, operators_1.literal)(sql);
|
|
147
|
+
return Object.assign(lit, { __type: 'literal', sql });
|
|
148
|
+
}
|
|
149
|
+
// ==================== substring ====================
|
|
150
|
+
/**
|
|
151
|
+
* Extract a substring.
|
|
152
|
+
*
|
|
153
|
+
* - Oracle, DB2, SQLite: use `SUBSTR(expr, start, length)`. SQLite has no
|
|
154
|
+
* built-in `SUBSTRING` function (only `substr`); Oracle/DB2 use `SUBSTR`
|
|
155
|
+
* as their canonical name (both also happen to accept the same argument
|
|
156
|
+
* order as the standard `SUBSTRING(expr, start, length)` form).
|
|
157
|
+
* - MSSQL: `SUBSTRING(expr, start, length)`, but MSSQL requires the length
|
|
158
|
+
* argument. When `length` is omitted, `LEN(expr)` is used as a safe upper
|
|
159
|
+
* bound so the result runs to the end of the string.
|
|
160
|
+
* - MySQL, MariaDB, Postgres, CockroachDB, Redshift, Snowflake, ClickHouse:
|
|
161
|
+
* `SUBSTRING(expr, start, length)` comma-argument form, length optional.
|
|
162
|
+
*
|
|
163
|
+
* @param expr - The column/expression to extract from.
|
|
164
|
+
* @param start - 1-based start position (SQL substring indices are 1-based).
|
|
165
|
+
* @param length - Optional number of characters to extract.
|
|
166
|
+
*/
|
|
167
|
+
function substring(dialect, expr, start, length) {
|
|
168
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
169
|
+
switch (dialect) {
|
|
170
|
+
case 'oracle':
|
|
171
|
+
case 'db2':
|
|
172
|
+
case 'sqlite':
|
|
173
|
+
return wrap(length !== undefined ? `SUBSTR(${rendered}, ${start}, ${length})` : `SUBSTR(${rendered}, ${start})`);
|
|
174
|
+
case 'mssql': {
|
|
175
|
+
const len = length !== undefined ? String(length) : `LEN(${rendered})`;
|
|
176
|
+
return wrap(`SUBSTRING(${rendered}, ${start}, ${len})`);
|
|
177
|
+
}
|
|
178
|
+
case 'mysql':
|
|
179
|
+
case 'mariadb':
|
|
180
|
+
case 'postgres':
|
|
181
|
+
case 'cockroachdb':
|
|
182
|
+
case 'redshift':
|
|
183
|
+
case 'snowflake':
|
|
184
|
+
case 'clickhouse':
|
|
185
|
+
default:
|
|
186
|
+
return wrap(length !== undefined
|
|
187
|
+
? `SUBSTRING(${rendered}, ${start}, ${length})`
|
|
188
|
+
: `SUBSTRING(${rendered}, ${start})`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Trim whitespace (or specific characters) from a string.
|
|
193
|
+
*
|
|
194
|
+
* - Postgres, CockroachDB, Redshift, Oracle, DB2, Snowflake, MySQL, MariaDB,
|
|
195
|
+
* ClickHouse: support the standard
|
|
196
|
+
* `TRIM([BOTH|LEADING|TRAILING] [chars FROM] expr)` syntax.
|
|
197
|
+
* - SQLite: has no `[BOTH|LEADING|TRAILING] FROM` syntax; instead uses
|
|
198
|
+
* `trim(expr[, chars])` / `ltrim(expr[, chars])` / `rtrim(expr[, chars])`.
|
|
199
|
+
* - MSSQL: `TRIM` (2017+) only trims both sides; for one-sided trimming we
|
|
200
|
+
* fall back to `LTRIM`/`RTRIM`. Native `LTRIM`/`RTRIM` in MSSQL only
|
|
201
|
+
* support a `chars` argument starting with SQL Server 2022, so when
|
|
202
|
+
* `chars` is supplied on an older-compatible codepath it is still passed
|
|
203
|
+
* through (SQL Server will error at runtime on versions that don't
|
|
204
|
+
* support it — this is a documented MSSQL version limitation, not a
|
|
205
|
+
* limitation of this helper).
|
|
206
|
+
*/
|
|
207
|
+
function trim(dialect, expr, options) {
|
|
208
|
+
const side = options?.side ?? 'both';
|
|
209
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
210
|
+
const chars = options?.chars;
|
|
211
|
+
switch (dialect) {
|
|
212
|
+
case 'sqlite': {
|
|
213
|
+
const fnName = side === 'leading' ? 'ltrim' : side === 'trailing' ? 'rtrim' : 'trim';
|
|
214
|
+
return wrap(chars !== undefined ? `${fnName}(${rendered}, ${quoteStringLiteral(chars)})` : `${fnName}(${rendered})`);
|
|
215
|
+
}
|
|
216
|
+
case 'mssql': {
|
|
217
|
+
if (side === 'leading') {
|
|
218
|
+
return wrap(chars !== undefined ? `LTRIM(${rendered}, ${quoteStringLiteral(chars)})` : `LTRIM(${rendered})`);
|
|
219
|
+
}
|
|
220
|
+
if (side === 'trailing') {
|
|
221
|
+
return wrap(chars !== undefined ? `RTRIM(${rendered}, ${quoteStringLiteral(chars)})` : `RTRIM(${rendered})`);
|
|
222
|
+
}
|
|
223
|
+
return wrap(chars !== undefined ? `TRIM(${quoteStringLiteral(chars)} FROM ${rendered})` : `TRIM(${rendered})`);
|
|
224
|
+
}
|
|
225
|
+
case 'postgres':
|
|
226
|
+
case 'cockroachdb':
|
|
227
|
+
case 'redshift':
|
|
228
|
+
case 'oracle':
|
|
229
|
+
case 'db2':
|
|
230
|
+
case 'snowflake':
|
|
231
|
+
case 'mysql':
|
|
232
|
+
case 'mariadb':
|
|
233
|
+
case 'clickhouse':
|
|
234
|
+
default: {
|
|
235
|
+
const sideKeyword = side === 'leading' ? 'LEADING' : side === 'trailing' ? 'TRAILING' : 'BOTH';
|
|
236
|
+
if (chars !== undefined) {
|
|
237
|
+
return wrap(`TRIM(${sideKeyword} ${quoteStringLiteral(chars)} FROM ${rendered})`);
|
|
238
|
+
}
|
|
239
|
+
return wrap(`TRIM(${sideKeyword} FROM ${rendered})`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/** Trim from the left only. Equivalent to `trim(dialect, expr, { side: 'leading' })`. */
|
|
244
|
+
function ltrim(dialect, expr, chars) {
|
|
245
|
+
return trim(dialect, expr, { side: 'leading', chars });
|
|
246
|
+
}
|
|
247
|
+
/** Trim from the right only. Equivalent to `trim(dialect, expr, { side: 'trailing' })`. */
|
|
248
|
+
function rtrim(dialect, expr, chars) {
|
|
249
|
+
return trim(dialect, expr, { side: 'trailing', chars });
|
|
250
|
+
}
|
|
251
|
+
// ==================== upper / lower ====================
|
|
252
|
+
/**
|
|
253
|
+
* Uppercase a string. Identical (`UPPER(expr)`) across all 11 dialects.
|
|
254
|
+
*/
|
|
255
|
+
function upper(dialect, expr) {
|
|
256
|
+
return wrap(`UPPER(${toSqlFragment(dialect, expr)})`);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Lowercase a string. Identical (`LOWER(expr)`) across all 11 dialects.
|
|
260
|
+
*/
|
|
261
|
+
function lower(dialect, expr) {
|
|
262
|
+
return wrap(`LOWER(${toSqlFragment(dialect, expr)})`);
|
|
263
|
+
}
|
|
264
|
+
// ==================== length ====================
|
|
265
|
+
/**
|
|
266
|
+
* Get the character length of a string.
|
|
267
|
+
*
|
|
268
|
+
* - MySQL, MariaDB, Postgres, CockroachDB, DB2, Snowflake: use
|
|
269
|
+
* `CHAR_LENGTH(expr)`. This is deliberately chosen over `LENGTH()` on
|
|
270
|
+
* MySQL/MariaDB because `LENGTH()` there counts BYTES, which is wrong for
|
|
271
|
+
* multi-byte (e.g. UTF-8) text; `CHAR_LENGTH()` always counts characters.
|
|
272
|
+
* - MSSQL: has no `CHAR_LENGTH`/`LENGTH` function at all; uses `LEN(expr)`
|
|
273
|
+
* (already character-counting).
|
|
274
|
+
* - Redshift: uses `LEN(expr)`, its documented/idiomatic string-length
|
|
275
|
+
* function (Redshift's SQL dialect favors `LEN` even though it is
|
|
276
|
+
* Postgres-derived).
|
|
277
|
+
* - Oracle: uses `LENGTH(expr)` (Oracle has no `CHAR_LENGTH` keyword;
|
|
278
|
+
* `LENGTH` already counts characters for CHAR/VARCHAR2 data).
|
|
279
|
+
* - SQLite: uses `length(expr)`, which for TEXT values already counts
|
|
280
|
+
* characters, not bytes (SQLite has no separate `CHAR_LENGTH`).
|
|
281
|
+
* - ClickHouse: `length()` counts BYTES. For character-correct behavior
|
|
282
|
+
* with multi-byte text, `lengthUTF8(expr)` is used instead.
|
|
283
|
+
*/
|
|
284
|
+
function length(dialect, expr) {
|
|
285
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
286
|
+
switch (dialect) {
|
|
287
|
+
case 'mssql':
|
|
288
|
+
case 'redshift':
|
|
289
|
+
return wrap(`LEN(${rendered})`);
|
|
290
|
+
case 'oracle':
|
|
291
|
+
case 'sqlite':
|
|
292
|
+
return wrap(`LENGTH(${rendered})`);
|
|
293
|
+
case 'clickhouse':
|
|
294
|
+
return wrap(`lengthUTF8(${rendered})`);
|
|
295
|
+
case 'mysql':
|
|
296
|
+
case 'mariadb':
|
|
297
|
+
case 'postgres':
|
|
298
|
+
case 'cockroachdb':
|
|
299
|
+
case 'db2':
|
|
300
|
+
case 'snowflake':
|
|
301
|
+
default:
|
|
302
|
+
return wrap(`CHAR_LENGTH(${rendered})`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// ==================== replace ====================
|
|
306
|
+
/**
|
|
307
|
+
* Replace all occurrences of a substring.
|
|
308
|
+
* `REPLACE(expr, search, replacement)` is identical across all 11 dialects.
|
|
309
|
+
*/
|
|
310
|
+
function replace(dialect, expr, search, replacement) {
|
|
311
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
312
|
+
return wrap(`REPLACE(${rendered}, ${quoteStringLiteral(search)}, ${quoteStringLiteral(replacement)})`);
|
|
313
|
+
}
|
|
314
|
+
// ==================== lpad / rpad ====================
|
|
315
|
+
/**
|
|
316
|
+
* Left-pad a string to a target length.
|
|
317
|
+
*
|
|
318
|
+
* - MySQL, MariaDB, Postgres, CockroachDB, Redshift, Oracle, Snowflake:
|
|
319
|
+
* native `LPAD(expr, length, pad)`.
|
|
320
|
+
* - ClickHouse: native `leftPad(expr, length, pad)`.
|
|
321
|
+
* - MSSQL: has no `LPAD`. Workaround using `RIGHT(REPLICATE(pad, length) +
|
|
322
|
+
* expr, length)` — replicate the pad string enough times to guarantee at
|
|
323
|
+
* least `length` characters, prepend it to `expr`, then take the
|
|
324
|
+
* rightmost `length` characters (matches LPAD's truncate-on-overflow
|
|
325
|
+
* semantics).
|
|
326
|
+
* - DB2: has no `LPAD` in Db2 for LUW. Workaround using a `CASE` expression:
|
|
327
|
+
* if the string is already >= target length, return it unchanged;
|
|
328
|
+
* otherwise prepend enough of the repeated pad string (via `REPEAT` +
|
|
329
|
+
* `SUBSTR`) to reach the target length.
|
|
330
|
+
* - SQLite: throws. SQLite has neither `LPAD` nor a `REPEAT` function, and
|
|
331
|
+
* there is no safe single-expression workaround without a recursive CTE,
|
|
332
|
+
* so this is not something a scalar SQL fragment can express correctly.
|
|
333
|
+
*/
|
|
334
|
+
function lpad(dialect, expr, targetLength, padString = ' ') {
|
|
335
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
336
|
+
const pad = quoteStringLiteral(padString);
|
|
337
|
+
switch (dialect) {
|
|
338
|
+
case 'mysql':
|
|
339
|
+
case 'mariadb':
|
|
340
|
+
case 'postgres':
|
|
341
|
+
case 'cockroachdb':
|
|
342
|
+
case 'redshift':
|
|
343
|
+
case 'oracle':
|
|
344
|
+
case 'snowflake':
|
|
345
|
+
return wrap(`LPAD(${rendered}, ${targetLength}, ${pad})`);
|
|
346
|
+
case 'clickhouse':
|
|
347
|
+
return wrap(`leftPad(${rendered}, ${targetLength}, ${pad})`);
|
|
348
|
+
case 'mssql':
|
|
349
|
+
return wrap(`RIGHT(REPLICATE(${pad}, ${targetLength}) + ${rendered}, ${targetLength})`);
|
|
350
|
+
case 'db2':
|
|
351
|
+
return wrap(`CASE WHEN CHAR_LENGTH(${rendered}) >= ${targetLength} THEN ${rendered} ` +
|
|
352
|
+
`ELSE SUBSTR(REPEAT(${pad}, ${targetLength}), 1, ${targetLength} - CHAR_LENGTH(${rendered})) || ${rendered} END`);
|
|
353
|
+
case 'sqlite':
|
|
354
|
+
return unsupported('lpad', dialect, 'SQLite has no LPAD/REPEAT function and no safe single-expression workaround');
|
|
355
|
+
default:
|
|
356
|
+
return wrap(`LPAD(${rendered}, ${targetLength}, ${pad})`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Right-pad a string to a target length. See {@link lpad} for per-dialect
|
|
361
|
+
* notes; the same dialects that lack `LPAD` also lack `RPAD`.
|
|
362
|
+
*/
|
|
363
|
+
function rpad(dialect, expr, targetLength, padString = ' ') {
|
|
364
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
365
|
+
const pad = quoteStringLiteral(padString);
|
|
366
|
+
switch (dialect) {
|
|
367
|
+
case 'mysql':
|
|
368
|
+
case 'mariadb':
|
|
369
|
+
case 'postgres':
|
|
370
|
+
case 'cockroachdb':
|
|
371
|
+
case 'redshift':
|
|
372
|
+
case 'oracle':
|
|
373
|
+
case 'snowflake':
|
|
374
|
+
return wrap(`RPAD(${rendered}, ${targetLength}, ${pad})`);
|
|
375
|
+
case 'clickhouse':
|
|
376
|
+
return wrap(`rightPad(${rendered}, ${targetLength}, ${pad})`);
|
|
377
|
+
case 'mssql':
|
|
378
|
+
return wrap(`LEFT(${rendered} + REPLICATE(${pad}, ${targetLength}), ${targetLength})`);
|
|
379
|
+
case 'db2':
|
|
380
|
+
return wrap(`CASE WHEN CHAR_LENGTH(${rendered}) >= ${targetLength} THEN ${rendered} ` +
|
|
381
|
+
`ELSE ${rendered} || SUBSTR(REPEAT(${pad}, ${targetLength}), 1, ${targetLength} - CHAR_LENGTH(${rendered})) END`);
|
|
382
|
+
case 'sqlite':
|
|
383
|
+
return unsupported('rpad', dialect, 'SQLite has no RPAD/REPEAT function and no safe single-expression workaround');
|
|
384
|
+
default:
|
|
385
|
+
return wrap(`RPAD(${rendered}, ${targetLength}, ${pad})`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// ==================== split ====================
|
|
389
|
+
/**
|
|
390
|
+
* Split a string on a delimiter, returning an array/collection expression
|
|
391
|
+
* where the dialect has a real mechanism for it.
|
|
392
|
+
*
|
|
393
|
+
* - Postgres, CockroachDB: `STRING_TO_ARRAY(expr, delimiter)` -> `text[]`.
|
|
394
|
+
* - Redshift: `SPLIT_TO_ARRAY(expr, delimiter)` -> `SUPER` array (Redshift's
|
|
395
|
+
* SUPER-type based array support).
|
|
396
|
+
* - Snowflake: `SPLIT(expr, delimiter)` -> `ARRAY` (variant).
|
|
397
|
+
* - ClickHouse: `splitByString(delimiter, expr)` -> `Array(String)`. Note
|
|
398
|
+
* the argument order is reversed compared to the others (separator comes
|
|
399
|
+
* first in ClickHouse).
|
|
400
|
+
* - MySQL, MariaDB, MSSQL, Oracle, DB2, SQLite: throw. None of these have a
|
|
401
|
+
* clean way to produce an array/collection from a scalar expression:
|
|
402
|
+
* - MySQL/MariaDB have no array type at all (only `SUBSTRING_INDEX` for
|
|
403
|
+
* extracting a single part by position, which is a different contract).
|
|
404
|
+
* - MSSQL's `STRING_SPLIT` is a table-valued function usable only in a
|
|
405
|
+
* `FROM` clause, not as a scalar expression.
|
|
406
|
+
* - Oracle/DB2/SQLite have no built-in split-to-array function; producing
|
|
407
|
+
* one requires `CONNECT BY`/recursive CTE tricks that cannot be
|
|
408
|
+
* expressed as a single SQL fragment.
|
|
409
|
+
*/
|
|
410
|
+
function split(dialect, expr, delimiter) {
|
|
411
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
412
|
+
const delim = quoteStringLiteral(delimiter);
|
|
413
|
+
switch (dialect) {
|
|
414
|
+
case 'postgres':
|
|
415
|
+
case 'cockroachdb':
|
|
416
|
+
return wrap(`STRING_TO_ARRAY(${rendered}, ${delim})`);
|
|
417
|
+
case 'redshift':
|
|
418
|
+
return wrap(`SPLIT_TO_ARRAY(${rendered}, ${delim})`);
|
|
419
|
+
case 'snowflake':
|
|
420
|
+
return wrap(`SPLIT(${rendered}, ${delim})`);
|
|
421
|
+
case 'clickhouse':
|
|
422
|
+
return wrap(`splitByString(${delim}, ${rendered})`);
|
|
423
|
+
case 'mysql':
|
|
424
|
+
case 'mariadb':
|
|
425
|
+
return unsupported('split', dialect, 'no array type / split-to-array function exists; use SUBSTRING_INDEX for extracting a single part instead');
|
|
426
|
+
case 'mssql':
|
|
427
|
+
return unsupported('split', dialect, 'STRING_SPLIT is table-valued (usable only in a FROM clause), not a scalar expression');
|
|
428
|
+
case 'oracle':
|
|
429
|
+
case 'db2':
|
|
430
|
+
case 'sqlite':
|
|
431
|
+
return unsupported('split', dialect, 'no built-in split-to-array function; would require CONNECT BY/recursive-CTE tricks that cannot be expressed as a single SQL fragment');
|
|
432
|
+
default:
|
|
433
|
+
return unsupported('split', dialect, 'no known split mechanism for this dialect');
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// ==================== repeat ====================
|
|
437
|
+
/**
|
|
438
|
+
* Repeat a string N times.
|
|
439
|
+
*
|
|
440
|
+
* - MySQL, MariaDB, Postgres, CockroachDB, Redshift, DB2, Snowflake,
|
|
441
|
+
* ClickHouse: native `REPEAT(expr, n)` (ClickHouse: `repeat(expr, n)`).
|
|
442
|
+
* - MSSQL: has no `REPEAT`; uses `REPLICATE(expr, n)`, which is exactly
|
|
443
|
+
* equivalent.
|
|
444
|
+
* - Oracle: has no `REPEAT`. Workaround: `RPAD(expr, LENGTH(expr) * n,
|
|
445
|
+
* expr)` — `RPAD`'s first argument already contributes one copy of
|
|
446
|
+
* `expr`, and padding with `expr` itself out to `length(expr) * n`
|
|
447
|
+
* characters fills in the remaining `n - 1` copies, producing `expr`
|
|
448
|
+
* repeated exactly `n` times (requires `expr` to be non-empty, since
|
|
449
|
+
* Oracle treats `''` as `NULL`).
|
|
450
|
+
* - SQLite: throws. SQLite has no `REPEAT` function and no safe
|
|
451
|
+
* single-expression workaround (the zeroblob/hex tricks that exist are
|
|
452
|
+
* fragile and only work for single-character pad values).
|
|
453
|
+
*/
|
|
454
|
+
function repeat(dialect, expr, n) {
|
|
455
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
456
|
+
switch (dialect) {
|
|
457
|
+
case 'mysql':
|
|
458
|
+
case 'mariadb':
|
|
459
|
+
case 'postgres':
|
|
460
|
+
case 'cockroachdb':
|
|
461
|
+
case 'redshift':
|
|
462
|
+
case 'db2':
|
|
463
|
+
case 'snowflake':
|
|
464
|
+
return wrap(`REPEAT(${rendered}, ${n})`);
|
|
465
|
+
case 'clickhouse':
|
|
466
|
+
return wrap(`repeat(${rendered}, ${n})`);
|
|
467
|
+
case 'mssql':
|
|
468
|
+
return wrap(`REPLICATE(${rendered}, ${n})`);
|
|
469
|
+
case 'oracle':
|
|
470
|
+
return wrap(`RPAD(${rendered}, LENGTH(${rendered}) * ${n}, ${rendered})`);
|
|
471
|
+
case 'sqlite':
|
|
472
|
+
return unsupported('repeat', dialect, 'SQLite has no REPEAT function and no safe single-expression workaround');
|
|
473
|
+
default:
|
|
474
|
+
return wrap(`REPEAT(${rendered}, ${n})`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// ==================== reverse ====================
|
|
478
|
+
/**
|
|
479
|
+
* Reverse a string.
|
|
480
|
+
*
|
|
481
|
+
* - MySQL, MariaDB, MSSQL, Postgres (9.1+), CockroachDB, Snowflake: native
|
|
482
|
+
* `REVERSE(expr)`.
|
|
483
|
+
* - ClickHouse: `reverse()` reverses BYTES, not characters, which breaks
|
|
484
|
+
* multi-byte text; `reverseUTF8(expr)` is used instead for correctness.
|
|
485
|
+
* - Oracle: no built-in `REVERSE` function for strings; there is no safe
|
|
486
|
+
* single-expression workaround (would require a hierarchical
|
|
487
|
+
* `CONNECT BY LEVEL` query), so this throws.
|
|
488
|
+
* - DB2: no built-in `REVERSE` scalar function in Db2 for LUW; throws for
|
|
489
|
+
* the same reason as Oracle.
|
|
490
|
+
* - Redshift: not present in Redshift's documented string-function list
|
|
491
|
+
* (Redshift's SQL dialect is derived from an old Postgres release that
|
|
492
|
+
* predates Postgres's `REVERSE`); throws rather than risk incorrect SQL.
|
|
493
|
+
* - SQLite: no built-in `REVERSE` function; throws.
|
|
494
|
+
*/
|
|
495
|
+
function reverse(dialect, expr) {
|
|
496
|
+
const rendered = toSqlFragment(dialect, expr);
|
|
497
|
+
switch (dialect) {
|
|
498
|
+
case 'mysql':
|
|
499
|
+
case 'mariadb':
|
|
500
|
+
case 'mssql':
|
|
501
|
+
case 'postgres':
|
|
502
|
+
case 'cockroachdb':
|
|
503
|
+
case 'snowflake':
|
|
504
|
+
return wrap(`REVERSE(${rendered})`);
|
|
505
|
+
case 'clickhouse':
|
|
506
|
+
return wrap(`reverseUTF8(${rendered})`);
|
|
507
|
+
case 'oracle':
|
|
508
|
+
return unsupported('reverse', dialect, 'Oracle has no built-in REVERSE function for strings');
|
|
509
|
+
case 'db2':
|
|
510
|
+
return unsupported('reverse', dialect, 'Db2 for LUW has no built-in REVERSE scalar function');
|
|
511
|
+
case 'redshift':
|
|
512
|
+
return unsupported('reverse', dialect, 'REVERSE is not part of Redshift\'s documented string function set');
|
|
513
|
+
case 'sqlite':
|
|
514
|
+
return unsupported('reverse', dialect, 'SQLite has no built-in REVERSE function');
|
|
515
|
+
default:
|
|
516
|
+
return wrap(`REVERSE(${rendered})`);
|
|
517
|
+
}
|
|
518
|
+
}
|