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,457 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Greenplum dialect implementation for the TypeScript ORM.
|
|
4
|
+
*
|
|
5
|
+
* Greenplum Database is a massively-parallel-processing (MPP) analytics
|
|
6
|
+
* database built by forking PostgreSQL (historically the 8.2/8.3 line, with
|
|
7
|
+
* later releases rebased onto PostgreSQL 9.x and 12). Because it speaks the
|
|
8
|
+
* PostgreSQL wire protocol and is largely SQL-compatible with it, this dialect
|
|
9
|
+
* extends {@link PostgresDialect} and reuses the same `pg` driver (default port
|
|
10
|
+
* 5432, exactly like Postgres — the coordinator/master segment listens on the
|
|
11
|
+
* standard Postgres port).
|
|
12
|
+
*
|
|
13
|
+
* Notable Greenplum-specific differences vs. plain PostgreSQL that this dialect
|
|
14
|
+
* models on top of the inherited Postgres behavior:
|
|
15
|
+
*
|
|
16
|
+
* - Distribution policy: every Greenplum table is physically distributed across
|
|
17
|
+
* segments. `CREATE TABLE` accepts a trailing `DISTRIBUTED BY (cols)` /
|
|
18
|
+
* `DISTRIBUTED RANDOMLY` / `DISTRIBUTED REPLICATED` clause. This dialect emits
|
|
19
|
+
* that clause when a distribution option is supplied (see
|
|
20
|
+
* {@link GreenplumDialect.buildDistributionClause}). To stay safe against
|
|
21
|
+
* plain-Postgres targets it only emits the clause when explicitly asked; when
|
|
22
|
+
* asked but under-specified it defaults to `DISTRIBUTED RANDOMLY`.
|
|
23
|
+
* - Append-optimized / column-oriented storage: Greenplum supports
|
|
24
|
+
* append-optimized (AO) tables and column orientation with compression via a
|
|
25
|
+
* table `WITH (appendoptimized=true, orientation=column, compresstype=zstd)`
|
|
26
|
+
* storage clause (see {@link GreenplumDialect.buildStorageClause}).
|
|
27
|
+
* - Legacy partitioning: in addition to Postgres 10+ declarative partitioning
|
|
28
|
+
* (inherited from the base dialect), Greenplum has its own older
|
|
29
|
+
* `PARTITION BY RANGE(col) (START (...) END (...) EVERY (...))` syntax
|
|
30
|
+
* (see {@link GreenplumDialect.buildRangePartitionClause}).
|
|
31
|
+
* - External tables: `CREATE EXTERNAL TABLE ... LOCATION ('gpfdist://...')
|
|
32
|
+
* FORMAT '...'` exposes external data (e.g. served by the `gpfdist` file
|
|
33
|
+
* distribution daemon) as a readable/writable table
|
|
34
|
+
* (see {@link GreenplumDialect.buildExternalTableSQL}).
|
|
35
|
+
*
|
|
36
|
+
* Greenplum does NOT support some PostgreSQL features (e.g. `SERIAL` maps to a
|
|
37
|
+
* distributed sequence, no global secondary UNIQUE guarantees unless the
|
|
38
|
+
* distribution key is a subset of the constraint, no savepoints inside some
|
|
39
|
+
* plans). Those caveats are inherited-as-is from the Postgres behavior here and
|
|
40
|
+
* are out of scope for this dialect wrapper.
|
|
41
|
+
*/
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.GreenplumDialect = void 0;
|
|
44
|
+
exports.createGreenplumDialect = createGreenplumDialect;
|
|
45
|
+
const index_1 = require("../postgres/index");
|
|
46
|
+
/**
|
|
47
|
+
* Greenplum dialect class. Extends {@link PostgresDialect}, overriding the
|
|
48
|
+
* `CREATE TABLE` builder to append Greenplum distribution/storage clauses and
|
|
49
|
+
* adding helpers for legacy range partitioning and external tables.
|
|
50
|
+
*/
|
|
51
|
+
class GreenplumDialect extends index_1.PostgresDialect {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
// Greenplum's coordinator listens on the standard Postgres port 5432.
|
|
54
|
+
super({ port: 5432, ...config });
|
|
55
|
+
// Explicit `string` type (rather than the inferred `'greenplum'` literal)
|
|
56
|
+
// keeps this assignable to the base `readonly name: string` property.
|
|
57
|
+
this.name = 'greenplum';
|
|
58
|
+
this.library = 'pg';
|
|
59
|
+
}
|
|
60
|
+
// ==========================================================================
|
|
61
|
+
// Distribution policy
|
|
62
|
+
// ==========================================================================
|
|
63
|
+
/**
|
|
64
|
+
* Build the trailing `DISTRIBUTED ...` clause for a Greenplum `CREATE TABLE`.
|
|
65
|
+
*
|
|
66
|
+
* Returns an empty string when no distribution option is supplied, so callers
|
|
67
|
+
* that never set one produce plain-Postgres-compatible DDL. When a
|
|
68
|
+
* distribution intent is expressed but under-specified (e.g. an empty
|
|
69
|
+
* `distributedBy` array), it falls back to `DISTRIBUTED RANDOMLY`.
|
|
70
|
+
*
|
|
71
|
+
* @returns e.g. `DISTRIBUTED BY ("id")`, `DISTRIBUTED RANDOMLY`,
|
|
72
|
+
* `DISTRIBUTED REPLICATED`, or `''`.
|
|
73
|
+
*/
|
|
74
|
+
buildDistributionClause(options) {
|
|
75
|
+
if (!options) {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
if (options.distributedReplicated) {
|
|
79
|
+
return 'DISTRIBUTED REPLICATED';
|
|
80
|
+
}
|
|
81
|
+
if (options.distributedBy && options.distributedBy.length > 0) {
|
|
82
|
+
const cols = options.distributedBy.map((c) => this.escapeId(c)).join(', ');
|
|
83
|
+
return `DISTRIBUTED BY (${cols})`;
|
|
84
|
+
}
|
|
85
|
+
// Either `distributedRandomly` was set, or a distribution intent was
|
|
86
|
+
// expressed without usable columns — default to random distribution.
|
|
87
|
+
if (options.distributedRandomly ||
|
|
88
|
+
options.distributedBy !== undefined ||
|
|
89
|
+
options.distributedReplicated !== undefined) {
|
|
90
|
+
return 'DISTRIBUTED RANDOMLY';
|
|
91
|
+
}
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
// ==========================================================================
|
|
95
|
+
// Append-optimized / columnar storage
|
|
96
|
+
// ==========================================================================
|
|
97
|
+
/**
|
|
98
|
+
* Build the `WITH (...)` storage clause for append-optimized / column-
|
|
99
|
+
* oriented Greenplum tables. Returns `''` unless append-optimized storage is
|
|
100
|
+
* requested (via `appendOptimized`, a non-`row` `orientation`, or any of the
|
|
101
|
+
* compression parameters).
|
|
102
|
+
*
|
|
103
|
+
* @returns e.g. `WITH (appendoptimized=true, orientation=column, compresstype=zstd)`.
|
|
104
|
+
*/
|
|
105
|
+
buildStorageClause(options) {
|
|
106
|
+
if (!options) {
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
const wantsAO = options.appendOptimized === true ||
|
|
110
|
+
options.orientation !== undefined ||
|
|
111
|
+
options.compressType !== undefined ||
|
|
112
|
+
options.compressLevel !== undefined ||
|
|
113
|
+
options.blocksize !== undefined;
|
|
114
|
+
if (!wantsAO) {
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
const params = ['appendoptimized=true'];
|
|
118
|
+
if (options.orientation) {
|
|
119
|
+
params.push(`orientation=${options.orientation}`);
|
|
120
|
+
}
|
|
121
|
+
if (options.compressType) {
|
|
122
|
+
params.push(`compresstype=${options.compressType}`);
|
|
123
|
+
}
|
|
124
|
+
if (options.compressLevel !== undefined) {
|
|
125
|
+
params.push(`compresslevel=${options.compressLevel}`);
|
|
126
|
+
}
|
|
127
|
+
if (options.blocksize !== undefined) {
|
|
128
|
+
params.push(`blocksize=${options.blocksize}`);
|
|
129
|
+
}
|
|
130
|
+
return `WITH (${params.join(', ')})`;
|
|
131
|
+
}
|
|
132
|
+
// ==========================================================================
|
|
133
|
+
// CREATE TABLE
|
|
134
|
+
// ==========================================================================
|
|
135
|
+
/**
|
|
136
|
+
* Synchronously build the full Greenplum `CREATE TABLE` statement, including
|
|
137
|
+
* the append-optimized storage `WITH (...)` clause and the trailing
|
|
138
|
+
* `DISTRIBUTED ...` clause. Exposed as a sync builder so callers (and tests)
|
|
139
|
+
* can inspect the emitted SQL without a live connection.
|
|
140
|
+
*/
|
|
141
|
+
buildCreateTableSQL(tableName, columns, options) {
|
|
142
|
+
const defs = Object.entries(columns).map(([name, def]) => this.buildGreenplumColumnSql(name, def));
|
|
143
|
+
// Table-level constraints are emitted inside the column list.
|
|
144
|
+
for (const c of options?.constraints ?? []) {
|
|
145
|
+
defs.push(this.buildTableConstraintSql(c));
|
|
146
|
+
}
|
|
147
|
+
let sql = 'CREATE TABLE';
|
|
148
|
+
if (options?.ifNotExists) {
|
|
149
|
+
sql += ' IF NOT EXISTS';
|
|
150
|
+
}
|
|
151
|
+
sql += ` ${this.escapeId(tableName)} (${defs.join(', ')})`;
|
|
152
|
+
// Legacy inheritance / declarative partitioning passthrough.
|
|
153
|
+
if (options?.inherit) {
|
|
154
|
+
sql += ` INHERITS (${this.escapeId(options.inherit)})`;
|
|
155
|
+
}
|
|
156
|
+
if (options?.partitionBy) {
|
|
157
|
+
sql += ` PARTITION BY ${options.partitionBy}`;
|
|
158
|
+
}
|
|
159
|
+
// Append-optimized / columnar storage parameters.
|
|
160
|
+
const storage = this.buildStorageClause(options);
|
|
161
|
+
if (storage) {
|
|
162
|
+
sql += ` ${storage}`;
|
|
163
|
+
}
|
|
164
|
+
// TABLESPACE follows storage/partitioning and precedes the DISTRIBUTED clause.
|
|
165
|
+
if (options?.tablespace) {
|
|
166
|
+
sql += ` TABLESPACE ${options.tablespace}`;
|
|
167
|
+
}
|
|
168
|
+
// Distribution policy — must be the final clause on a Greenplum CREATE TABLE.
|
|
169
|
+
const distribution = this.buildDistributionClause(options);
|
|
170
|
+
if (distribution) {
|
|
171
|
+
sql += ` ${distribution}`;
|
|
172
|
+
}
|
|
173
|
+
return sql;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Build a single table-level constraint clause for the CREATE TABLE column
|
|
177
|
+
* list, e.g. `CONSTRAINT "pk_orders" PRIMARY KEY ("id")` or
|
|
178
|
+
* `FOREIGN KEY ("customer_id") REFERENCES "customers"("id")`.
|
|
179
|
+
*/
|
|
180
|
+
buildTableConstraintSql(c) {
|
|
181
|
+
const prefix = c.name ? `CONSTRAINT ${this.escapeId(c.name)} ` : '';
|
|
182
|
+
const cols = (c.fields ?? []).map((f) => this.escapeId(f)).join(', ');
|
|
183
|
+
switch (c.type) {
|
|
184
|
+
case 'PRIMARY KEY':
|
|
185
|
+
return `${prefix}PRIMARY KEY (${cols})`;
|
|
186
|
+
case 'UNIQUE':
|
|
187
|
+
return `${prefix}UNIQUE (${cols})`;
|
|
188
|
+
case 'FOREIGN KEY': {
|
|
189
|
+
const ref = c.references;
|
|
190
|
+
const refClause = ref
|
|
191
|
+
? ` REFERENCES ${this.escapeId(ref.table)}(${this.escapeId(ref.field)})`
|
|
192
|
+
: '';
|
|
193
|
+
return `${prefix}FOREIGN KEY (${cols})${refClause}`;
|
|
194
|
+
}
|
|
195
|
+
case 'CHECK':
|
|
196
|
+
return `${prefix}CHECK (${c.expression ?? ''})`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ==========================================================================
|
|
200
|
+
// Upsert — Greenplum has no INSERT ... ON CONFLICT
|
|
201
|
+
// ==========================================================================
|
|
202
|
+
/**
|
|
203
|
+
* Greenplum (Postgres 8/9-derived) does not implement `INSERT ... ON
|
|
204
|
+
* CONFLICT`. Refuse an upsert INSERT with a clear error pointing callers at
|
|
205
|
+
* {@link GreenplumDialect.buildUpsertQuery}'s staging-table strategy. Plain
|
|
206
|
+
* (non-upsert) inserts delegate to the inherited PostgreSQL builder.
|
|
207
|
+
*/
|
|
208
|
+
buildInsertQuery(tableName, values, options) {
|
|
209
|
+
if (options?.upsert) {
|
|
210
|
+
throw new Error('GreenplumDialect: INSERT ... ON CONFLICT upsert is not supported by Greenplum ' +
|
|
211
|
+
'(Postgres 8/9-derived). Use buildUpsertQuery(), which emits a staging-table ' +
|
|
212
|
+
'CREATE TEMP + DELETE ... USING + INSERT ... SELECT strategy instead.');
|
|
213
|
+
}
|
|
214
|
+
return super.buildInsertQuery(tableName, values, options);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Build a Greenplum-compatible upsert as a staging-table batch (no
|
|
218
|
+
* `ON CONFLICT`):
|
|
219
|
+
*
|
|
220
|
+
* CREATE TEMP TABLE "<t>_gp_upsert_stg" (LIKE "<t>") ON COMMIT DROP;
|
|
221
|
+
* INSERT INTO "<t>_gp_upsert_stg" (cols) VALUES (...);
|
|
222
|
+
* DELETE FROM "<t>" USING stg WHERE "<t>".k = stg.k [AND ...];
|
|
223
|
+
* INSERT INTO "<t>" (writeCols) SELECT writeCols FROM stg [RETURNING ...];
|
|
224
|
+
* [DROP TABLE stg] -- only when no RETURNING (RETURNING must be the last statement)
|
|
225
|
+
*
|
|
226
|
+
* `writeCols` is the conflict keys plus `updateOnDuplicate` when given,
|
|
227
|
+
* otherwise every provided column.
|
|
228
|
+
*/
|
|
229
|
+
buildUpsertQuery(tableName, values, options) {
|
|
230
|
+
const conflictFields = options?.conflictFields ?? [];
|
|
231
|
+
if (conflictFields.length === 0) {
|
|
232
|
+
throw new Error('GreenplumDialect.buildUpsertQuery: options.conflictFields is required — the ' +
|
|
233
|
+
'staging-table strategy matches existing rows on these key columns.');
|
|
234
|
+
}
|
|
235
|
+
const cols = Object.keys(values);
|
|
236
|
+
const qTable = this.escapeId(tableName);
|
|
237
|
+
const stg = this.escapeId(`${tableName}_gp_upsert_stg`);
|
|
238
|
+
const q = (c) => this.escapeId(c);
|
|
239
|
+
// Columns written back into the target: keys + updated columns, else all.
|
|
240
|
+
const writeCols = options?.updateOnDuplicate && options.updateOnDuplicate.length > 0
|
|
241
|
+
? Array.from(new Set([...conflictFields, ...options.updateOnDuplicate]))
|
|
242
|
+
: cols;
|
|
243
|
+
const placeholders = cols.map((_, i) => `$${i + 1}`).join(', ');
|
|
244
|
+
const joinCond = conflictFields
|
|
245
|
+
.map((k) => `${qTable}.${q(k)} = ${stg}.${q(k)}`)
|
|
246
|
+
.join(' AND ');
|
|
247
|
+
const writeList = writeCols.map(q).join(', ');
|
|
248
|
+
const statements = [
|
|
249
|
+
`CREATE TEMP TABLE ${stg} (LIKE ${qTable}) ON COMMIT DROP`,
|
|
250
|
+
`INSERT INTO ${stg} (${cols.map(q).join(', ')}) VALUES (${placeholders})`,
|
|
251
|
+
`DELETE FROM ${qTable} USING ${stg} WHERE ${joinCond}`,
|
|
252
|
+
];
|
|
253
|
+
let finalInsert = `INSERT INTO ${qTable} (${writeList}) SELECT ${writeList} FROM ${stg}`;
|
|
254
|
+
if (options?.returning === true) {
|
|
255
|
+
finalInsert += ' RETURNING *';
|
|
256
|
+
}
|
|
257
|
+
else if (Array.isArray(options?.returning) && options.returning.length > 0) {
|
|
258
|
+
finalInsert += ` RETURNING ${options.returning.map(q).join(', ')}`;
|
|
259
|
+
}
|
|
260
|
+
statements.push(finalInsert);
|
|
261
|
+
// RETURNING must be the last statement; otherwise eagerly drop the staging
|
|
262
|
+
// table (it is also ON COMMIT DROP as a safety net).
|
|
263
|
+
if (!options?.returning) {
|
|
264
|
+
statements.push(`DROP TABLE ${stg}`);
|
|
265
|
+
}
|
|
266
|
+
return { sql: statements.join(';\n'), values: Object.values(values) };
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Create a new table, emitting Greenplum distribution and append-optimized
|
|
270
|
+
* storage clauses. Overrides {@link PostgresDialect.createTable}.
|
|
271
|
+
*/
|
|
272
|
+
async createTable(tableName, columns, options) {
|
|
273
|
+
const sql = this.buildCreateTableSQL(tableName, columns, options);
|
|
274
|
+
await this.query(sql);
|
|
275
|
+
// Table comment (inherited COMMENT ON semantics).
|
|
276
|
+
if (options?.comment) {
|
|
277
|
+
await this.query(`COMMENT ON TABLE ${this.escapeId(tableName)} IS ${this.escape(options.comment)}`);
|
|
278
|
+
}
|
|
279
|
+
// Post-creation indexes, delegated to the inherited addIndex().
|
|
280
|
+
if (options?.indexes) {
|
|
281
|
+
for (const index of options.indexes) {
|
|
282
|
+
await this.addIndex(tableName, index.name || `idx_${tableName}_${index.fields.join('_')}`, index.fields, {
|
|
283
|
+
unique: index.unique,
|
|
284
|
+
type: index.type,
|
|
285
|
+
using: index.using,
|
|
286
|
+
where: index.where,
|
|
287
|
+
expression: index.expression,
|
|
288
|
+
include: index.include,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Build a single column definition for a Greenplum `CREATE TABLE`. Mirrors
|
|
295
|
+
* the common subset of the Postgres column builder (which is private on the
|
|
296
|
+
* base class): type, NOT NULL, DEFAULT, PRIMARY KEY, UNIQUE, and references.
|
|
297
|
+
*/
|
|
298
|
+
buildGreenplumColumnSql(columnName, definition) {
|
|
299
|
+
const dt = definition.type;
|
|
300
|
+
// Auto-increment integer columns -> SERIAL (Postgres-compatibility
|
|
301
|
+
// shorthand; Greenplum backs it with a distributed sequence).
|
|
302
|
+
if (definition.autoIncrement && (dt.key === 'INTEGER' || !dt.key)) {
|
|
303
|
+
let sql = `${this.escapeId(columnName)} SERIAL`;
|
|
304
|
+
if (definition.primaryKey)
|
|
305
|
+
sql += ' PRIMARY KEY';
|
|
306
|
+
if (definition.allowNull === false)
|
|
307
|
+
sql += ' NOT NULL';
|
|
308
|
+
if (definition.unique)
|
|
309
|
+
sql += ' UNIQUE';
|
|
310
|
+
return sql;
|
|
311
|
+
}
|
|
312
|
+
let sql = `${this.escapeId(columnName)} ${this.getDataTypeSql(definition.type)}`;
|
|
313
|
+
if (definition.allowNull === false) {
|
|
314
|
+
sql += ' NOT NULL';
|
|
315
|
+
}
|
|
316
|
+
if (definition.defaultValue !== undefined) {
|
|
317
|
+
sql += ` DEFAULT ${this.escape(definition.defaultValue)}`;
|
|
318
|
+
}
|
|
319
|
+
if (definition.primaryKey) {
|
|
320
|
+
sql += ' PRIMARY KEY';
|
|
321
|
+
}
|
|
322
|
+
if (definition.unique) {
|
|
323
|
+
sql += ' UNIQUE';
|
|
324
|
+
}
|
|
325
|
+
if (definition.references) {
|
|
326
|
+
const refField = definition.references.field;
|
|
327
|
+
const refFieldSql = Array.isArray(refField)
|
|
328
|
+
? `(${refField.map((f) => this.escapeId(f)).join(', ')})`
|
|
329
|
+
: `(${this.escapeId(refField)})`;
|
|
330
|
+
sql += ` REFERENCES ${this.escapeId(definition.references.table)}${refFieldSql}`;
|
|
331
|
+
if (definition.references.onDelete) {
|
|
332
|
+
sql += ` ON DELETE ${definition.references.onDelete}`;
|
|
333
|
+
}
|
|
334
|
+
if (definition.references.onUpdate) {
|
|
335
|
+
sql += ` ON UPDATE ${definition.references.onUpdate}`;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return sql;
|
|
339
|
+
}
|
|
340
|
+
// ==========================================================================
|
|
341
|
+
// Legacy Greenplum range partitioning
|
|
342
|
+
// ==========================================================================
|
|
343
|
+
/**
|
|
344
|
+
* Build Greenplum's legacy `PARTITION BY RANGE(col) (START (...) END (...)
|
|
345
|
+
* EVERY (...))` clause (distinct from Postgres 10+ declarative partitioning,
|
|
346
|
+
* which the base dialect handles via `PARTITION BY RANGE (col)`).
|
|
347
|
+
*
|
|
348
|
+
* @param column - The range-partition key column.
|
|
349
|
+
* @param spec - Start/end bounds and optional `EVERY` step.
|
|
350
|
+
* @returns e.g.
|
|
351
|
+
* `PARTITION BY RANGE(sale_date) (START ('2020-01-01') END ('2021-01-01') EVERY (INTERVAL '1 month'))`.
|
|
352
|
+
*/
|
|
353
|
+
buildRangePartitionClause(column, spec) {
|
|
354
|
+
const parts = [
|
|
355
|
+
`START (${this.formatPartitionBound(spec.start)})`,
|
|
356
|
+
`END (${this.formatPartitionBound(spec.end)})`,
|
|
357
|
+
];
|
|
358
|
+
if (spec.every !== undefined) {
|
|
359
|
+
parts.push(`EVERY (${this.formatPartitionBound(spec.every)})`);
|
|
360
|
+
}
|
|
361
|
+
return `PARTITION BY RANGE(${this.escapeId(column)}) (${parts.join(' ')})`;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Format a range-partition bound value as a SQL literal: numbers verbatim,
|
|
365
|
+
* already-expression strings (INTERVAL / DATE / TIMESTAMP keyword or a
|
|
366
|
+
* `func(...)` call) raw, and any other string single-quoted.
|
|
367
|
+
*/
|
|
368
|
+
formatPartitionBound(value) {
|
|
369
|
+
if (typeof value === 'number') {
|
|
370
|
+
return String(value);
|
|
371
|
+
}
|
|
372
|
+
const trimmed = value.trim();
|
|
373
|
+
if (/^(INTERVAL|DATE|TIMESTAMP|TIME|NUMERIC|MAXVALUE|MINVALUE)\b/i.test(trimmed) ||
|
|
374
|
+
/^[a-zA-Z_][a-zA-Z0-9_.]*\([^)]*\)$/.test(trimmed) ||
|
|
375
|
+
/^'.*'$/.test(trimmed)) {
|
|
376
|
+
return trimmed;
|
|
377
|
+
}
|
|
378
|
+
return `'${trimmed.replace(/'/g, "''")}'`;
|
|
379
|
+
}
|
|
380
|
+
// ==========================================================================
|
|
381
|
+
// External tables (gpfdist / EXTERNAL WEB)
|
|
382
|
+
// ==========================================================================
|
|
383
|
+
/**
|
|
384
|
+
* Build a Greenplum `CREATE EXTERNAL TABLE` statement. External tables expose
|
|
385
|
+
* data served over `gpfdist://`, `http://`, `s3://`, etc. as a queryable
|
|
386
|
+
* (and optionally writable) table with no local segment storage.
|
|
387
|
+
*
|
|
388
|
+
* @param tableName - Name of the external table to create.
|
|
389
|
+
* @param columns - Column definitions (types only; no distribution/constraints).
|
|
390
|
+
* @param options - External-table options (locations, format, writable, ...).
|
|
391
|
+
* @returns e.g.
|
|
392
|
+
* `CREATE EXTERNAL TABLE "ext_sales" (...) LOCATION ('gpfdist://host:8081/sales/*.csv') FORMAT 'CSV' (DELIMITER ',' HEADER)`.
|
|
393
|
+
*/
|
|
394
|
+
buildExternalTableSQL(tableName, columns, options) {
|
|
395
|
+
if (!options.locations || options.locations.length === 0) {
|
|
396
|
+
throw new Error('Greenplum external table requires at least one LOCATION.');
|
|
397
|
+
}
|
|
398
|
+
const columnDefs = Object.entries(columns)
|
|
399
|
+
.map(([name, def]) => `${this.escapeId(name)} ${this.getDataTypeSql(def.type)}`)
|
|
400
|
+
.join(', ');
|
|
401
|
+
let sql = 'CREATE';
|
|
402
|
+
if (options.writable) {
|
|
403
|
+
sql += ' WRITABLE';
|
|
404
|
+
}
|
|
405
|
+
sql += ' EXTERNAL';
|
|
406
|
+
if (options.web) {
|
|
407
|
+
sql += ' WEB';
|
|
408
|
+
}
|
|
409
|
+
sql += ' TABLE';
|
|
410
|
+
if (options.ifNotExists) {
|
|
411
|
+
sql += ' IF NOT EXISTS';
|
|
412
|
+
}
|
|
413
|
+
sql += ` ${this.escapeId(tableName)} (${columnDefs})`;
|
|
414
|
+
const locations = options.locations
|
|
415
|
+
.map((loc) => `'${loc.replace(/'/g, "''")}'`)
|
|
416
|
+
.join(', ');
|
|
417
|
+
sql += ` LOCATION (${locations})`;
|
|
418
|
+
const format = options.format || 'TEXT';
|
|
419
|
+
sql += ` FORMAT '${format}'`;
|
|
420
|
+
const formatOpts = [];
|
|
421
|
+
if (options.delimiter !== undefined) {
|
|
422
|
+
formatOpts.push(`DELIMITER '${options.delimiter.replace(/'/g, "''")}'`);
|
|
423
|
+
}
|
|
424
|
+
if (options.header) {
|
|
425
|
+
formatOpts.push('HEADER');
|
|
426
|
+
}
|
|
427
|
+
if (formatOpts.length > 0) {
|
|
428
|
+
sql += ` (${formatOpts.join(' ')})`;
|
|
429
|
+
}
|
|
430
|
+
if (options.encoding) {
|
|
431
|
+
sql += ` ENCODING '${options.encoding.replace(/'/g, "''")}'`;
|
|
432
|
+
}
|
|
433
|
+
if (options.logErrors) {
|
|
434
|
+
sql += ' LOG ERRORS';
|
|
435
|
+
}
|
|
436
|
+
if (options.rejectLimit !== undefined) {
|
|
437
|
+
const unit = options.rejectLimitType || 'ROWS';
|
|
438
|
+
sql += ` SEGMENT REJECT LIMIT ${options.rejectLimit} ${unit}`;
|
|
439
|
+
}
|
|
440
|
+
return sql;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Create an external table by executing the statement built by
|
|
444
|
+
* {@link GreenplumDialect.buildExternalTableSQL}.
|
|
445
|
+
*/
|
|
446
|
+
async createExternalTable(tableName, columns, options) {
|
|
447
|
+
await this.query(this.buildExternalTableSQL(tableName, columns, options));
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
exports.GreenplumDialect = GreenplumDialect;
|
|
451
|
+
/**
|
|
452
|
+
* Create a new Greenplum dialect instance.
|
|
453
|
+
*/
|
|
454
|
+
function createGreenplumDialect(options) {
|
|
455
|
+
return new GreenplumDialect(options || {});
|
|
456
|
+
}
|
|
457
|
+
exports.default = GreenplumDialect;
|