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,720 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base dialect interface for the ORM
|
|
4
|
+
* Each database dialect implements this interface
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.DialectRegistry = exports.BaseDialect = void 0;
|
|
8
|
+
const index_1 = require("../errors/index");
|
|
9
|
+
/**
|
|
10
|
+
* Abstract base class for database dialects
|
|
11
|
+
* Provides common functionality for all dialect implementations
|
|
12
|
+
*/
|
|
13
|
+
class BaseDialect {
|
|
14
|
+
constructor() {
|
|
15
|
+
this._connection = null;
|
|
16
|
+
this._connected = false;
|
|
17
|
+
this.dialectName = 'unknown';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a stored procedure (alias for createStoredProcedure)
|
|
21
|
+
* @param options - Stored procedure options
|
|
22
|
+
*/
|
|
23
|
+
async createProcedure(options) {
|
|
24
|
+
return this.createStoredProcedure(options);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Drop a stored procedure (alias for dropStoredProcedure)
|
|
28
|
+
* @param procedureName - Name of the stored procedure
|
|
29
|
+
* @param options - Drop options
|
|
30
|
+
*/
|
|
31
|
+
async dropProcedure(procedureName, options) {
|
|
32
|
+
return this.dropStoredProcedure(procedureName, options);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rename a column (default throws error)
|
|
36
|
+
*/
|
|
37
|
+
async renameColumn(_tableName, _oldColumnName, _newColumnName) {
|
|
38
|
+
throw new Error(`renameColumn not supported for ${this.dialectName} dialect`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Add a foreign key (default throws error)
|
|
42
|
+
*/
|
|
43
|
+
async addForeignKey(_tableName, _columnName, _referencedTableName, _referencedColumnName, _options) {
|
|
44
|
+
throw new Error(`addForeignKey not supported for ${this.dialectName} dialect`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Bulk insert records (default implementation)
|
|
48
|
+
*/
|
|
49
|
+
async bulkInsert(tableName, records, _options) {
|
|
50
|
+
if (records.length === 0) {
|
|
51
|
+
return { rows: [], rowCount: 0, fields: [] };
|
|
52
|
+
}
|
|
53
|
+
const values = [];
|
|
54
|
+
const placeholders = [];
|
|
55
|
+
const columns = Object.keys(records[0]);
|
|
56
|
+
for (const record of records) {
|
|
57
|
+
const rowPlaceholders = [];
|
|
58
|
+
for (let i = 0; i < columns.length; i++) {
|
|
59
|
+
rowPlaceholders.push(`$${values.length + i + 1}`);
|
|
60
|
+
values.push(record[columns[i]]);
|
|
61
|
+
}
|
|
62
|
+
placeholders.push(`(${rowPlaceholders.join(', ')})`);
|
|
63
|
+
}
|
|
64
|
+
const sql = `INSERT INTO ${this.quoteTable(tableName)} (${columns.map((c) => this.escapeId(c)).join(', ')}) VALUES ${placeholders.join(', ')}`;
|
|
65
|
+
return this.query(sql);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a fulltext index (default throws error)
|
|
69
|
+
*/
|
|
70
|
+
async createFulltextIndex(_tableName, _indexName, _fields, _options) {
|
|
71
|
+
throw new Error(`createFulltextIndex not supported for ${this.dialectName} dialect`);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create a spatial index (default throws error)
|
|
75
|
+
*/
|
|
76
|
+
async createSpatialIndex(_tableName, _indexName, _fields, _options) {
|
|
77
|
+
throw new Error(`createSpatialIndex not supported for ${this.dialectName} dialect`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* List all schemas in the database
|
|
81
|
+
*/
|
|
82
|
+
async listSchemas() {
|
|
83
|
+
return this.showAllSchemas();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generate SQL for creating a database (default implementation)
|
|
87
|
+
* @param options - Database creation options
|
|
88
|
+
*/
|
|
89
|
+
createDatabaseSQL(options) {
|
|
90
|
+
const parts = [];
|
|
91
|
+
parts.push(`CREATE DATABASE ${this.quoteIdentifier(options.name)}`);
|
|
92
|
+
if (options.encoding) {
|
|
93
|
+
parts.push(`ENCODING = '${options.encoding}'`);
|
|
94
|
+
}
|
|
95
|
+
if (options.lcCollate) {
|
|
96
|
+
parts.push(`LC_COLLATE = '${options.lcCollate}'`);
|
|
97
|
+
}
|
|
98
|
+
if (options.lcCtype) {
|
|
99
|
+
parts.push(`LC_CTYPE = '${options.lcCtype}'`);
|
|
100
|
+
}
|
|
101
|
+
if (options.template) {
|
|
102
|
+
parts.push(`TEMPLATE = ${options.template}`);
|
|
103
|
+
}
|
|
104
|
+
if (options.tablespace) {
|
|
105
|
+
parts.push(`TABLESPACE = ${options.tablespace}`);
|
|
106
|
+
}
|
|
107
|
+
if (options.isTemplate !== undefined) {
|
|
108
|
+
parts.push(options.isTemplate ? 'IS_TEMPLATE = true' : 'IS_TEMPLATE = false');
|
|
109
|
+
}
|
|
110
|
+
if (options.collate) {
|
|
111
|
+
parts.push(`COLLATE = '${options.collate}'`);
|
|
112
|
+
}
|
|
113
|
+
return parts.join(' ');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Generate SQL for dropping a database
|
|
117
|
+
* @param name - Database name to drop
|
|
118
|
+
*/
|
|
119
|
+
dropDatabaseSQL(name) {
|
|
120
|
+
return `DROP DATABASE IF EXISTS ${this.quoteIdentifier(name)}`;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate SQL for creating a savepoint
|
|
124
|
+
* @param name - Savepoint name (optional, will be generated if not provided)
|
|
125
|
+
*/
|
|
126
|
+
createSavepointSQL(name) {
|
|
127
|
+
const savepointName = name || `sp_${Date.now()}`;
|
|
128
|
+
return `SAVEPOINT ${savepointName}`;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Generate SQL for releasing a savepoint
|
|
132
|
+
* @param name - Savepoint name to release
|
|
133
|
+
*/
|
|
134
|
+
releaseSavepointSQL(name) {
|
|
135
|
+
return `RELEASE SAVEPOINT ${name}`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Generate SQL for rolling back to a savepoint
|
|
139
|
+
* @param name - Savepoint name to rollback to
|
|
140
|
+
*/
|
|
141
|
+
rollbackToSavepointSQL(name) {
|
|
142
|
+
return `ROLLBACK TO SAVEPOINT ${name}`;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Create a PostgreSQL extension (only supported in PostgreSQL)
|
|
146
|
+
* @param extensionName - Name of the extension to create
|
|
147
|
+
* @param options - Extension options
|
|
148
|
+
*/
|
|
149
|
+
createExtension(_extensionName, _options) {
|
|
150
|
+
throw new Error('Extensions are only supported in PostgreSQL');
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Drop a PostgreSQL extension (only supported in PostgreSQL)
|
|
154
|
+
* @param extensionName - Name of the extension to drop
|
|
155
|
+
* @param options - Drop options
|
|
156
|
+
*/
|
|
157
|
+
dropExtension(_extensionName, _options) {
|
|
158
|
+
throw new Error('Extensions are only supported in PostgreSQL');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get all installed PostgreSQL extensions (only supported in PostgreSQL)
|
|
162
|
+
* @returns Array of extension information
|
|
163
|
+
*/
|
|
164
|
+
getExtensions() {
|
|
165
|
+
throw new Error('Extensions are only supported in PostgreSQL');
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if a PostgreSQL extension is installed (only supported in PostgreSQL)
|
|
169
|
+
* @param extensionName - Name of the extension
|
|
170
|
+
* @returns True if the extension is installed
|
|
171
|
+
*/
|
|
172
|
+
hasExtension(_extensionName) {
|
|
173
|
+
throw new Error('Extensions are only supported in PostgreSQL');
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a PostgreSQL enum type (only supported in PostgreSQL)
|
|
177
|
+
*/
|
|
178
|
+
createEnumType(_name, _values, _options) {
|
|
179
|
+
throw new Error('CREATE TYPE ... AS ENUM is only supported in PostgreSQL');
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Drop a PostgreSQL type (only supported in PostgreSQL)
|
|
183
|
+
*/
|
|
184
|
+
dropType(_name, _options) {
|
|
185
|
+
throw new Error('DROP TYPE is only supported in PostgreSQL');
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Create a PostgreSQL domain (only supported in PostgreSQL)
|
|
189
|
+
*/
|
|
190
|
+
createDomain(_name, _baseType, _options) {
|
|
191
|
+
throw new Error('CREATE DOMAIN is only supported in PostgreSQL');
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Drop a PostgreSQL domain (only supported in PostgreSQL)
|
|
195
|
+
*/
|
|
196
|
+
dropDomain(_name, _options) {
|
|
197
|
+
throw new Error('DROP DOMAIN is only supported in PostgreSQL');
|
|
198
|
+
}
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Foreign Data Wrapper stubs – overridden by PostgresDialect
|
|
201
|
+
// All other dialects throw a DatabaseError.
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
buildCreateServerQuery(_name, _opts) {
|
|
204
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
205
|
+
}
|
|
206
|
+
buildAlterServerQuery(_name, _opts) {
|
|
207
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
208
|
+
}
|
|
209
|
+
buildDropServerQuery(_name, _opts) {
|
|
210
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
211
|
+
}
|
|
212
|
+
buildCreateUserMappingQuery(_opts) {
|
|
213
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
214
|
+
}
|
|
215
|
+
buildAlterUserMappingQuery(_opts) {
|
|
216
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
217
|
+
}
|
|
218
|
+
buildDropUserMappingQuery(_serverName, _user, _opts) {
|
|
219
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create a user mapping (default throws error)
|
|
223
|
+
*/
|
|
224
|
+
async createUserMapping(_userName, _serverName, _options) {
|
|
225
|
+
throw new Error(`createUserMapping not supported for ${this.dialectName} dialect`);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Drop a user mapping (default throws error)
|
|
229
|
+
*/
|
|
230
|
+
async dropUserMapping(_userName, _serverName, _options) {
|
|
231
|
+
throw new Error(`dropUserMapping not supported for ${this.dialectName} dialect`);
|
|
232
|
+
}
|
|
233
|
+
buildCreateForeignTableQuery(_tableName, _opts) {
|
|
234
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
235
|
+
}
|
|
236
|
+
buildDropForeignTableQuery(_tableName, _opts) {
|
|
237
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
238
|
+
}
|
|
239
|
+
buildImportForeignSchemaQuery(_remoteSchema, _serverName, _opts) {
|
|
240
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
241
|
+
}
|
|
242
|
+
getServersQuery() {
|
|
243
|
+
throw new Error('Foreign Data Wrappers are not supported by this dialect');
|
|
244
|
+
}
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
// User / privilege management stubs – overridden by MySQL and MariaDB dialects.
|
|
247
|
+
// All other dialects (SQLite, etc.) throw a DatabaseError.
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
buildCreateUserQuery(_username, _options) {
|
|
250
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
251
|
+
}
|
|
252
|
+
buildAlterUserQuery(_username, _options) {
|
|
253
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
254
|
+
}
|
|
255
|
+
buildDropUserQuery(_username, _options) {
|
|
256
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
257
|
+
}
|
|
258
|
+
getUsersQuery() {
|
|
259
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
260
|
+
}
|
|
261
|
+
buildGrantQuery(_options) {
|
|
262
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
263
|
+
}
|
|
264
|
+
buildRevokeQuery(_options) {
|
|
265
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
266
|
+
}
|
|
267
|
+
buildShowGrantsQuery(_username, _host) {
|
|
268
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
269
|
+
}
|
|
270
|
+
buildFlushPrivilegesQuery() {
|
|
271
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
272
|
+
}
|
|
273
|
+
buildCreateRoleQuery(_roleName, _options) {
|
|
274
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
275
|
+
}
|
|
276
|
+
buildDropRoleQuery(_roleName, _options) {
|
|
277
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
278
|
+
}
|
|
279
|
+
buildGrantRoleQuery(_role, _to, _options) {
|
|
280
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
281
|
+
}
|
|
282
|
+
buildRevokeRoleQuery(_role, _from, _options) {
|
|
283
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
284
|
+
}
|
|
285
|
+
getRolesQuery() {
|
|
286
|
+
throw new index_1.DatabaseError('User management is not supported by this dialect');
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Build a JSON/JSONB path query
|
|
290
|
+
* Default implementation using common JSON extraction syntax
|
|
291
|
+
*
|
|
292
|
+
* @param column - The JSON/JSONB column name
|
|
293
|
+
* @param path - The JSON path to access (e.g., 'key' or 'key.subkey')
|
|
294
|
+
* @param value - The value to compare against (optional)
|
|
295
|
+
* @param operator - The comparison operator to use (defaults to =)
|
|
296
|
+
* @returns SQL fragment and values for the JSON query
|
|
297
|
+
*/
|
|
298
|
+
buildJsonQuery(column, path, value, operator = '=') {
|
|
299
|
+
const values = [];
|
|
300
|
+
const columnRef = this.quoteIdentifier(column);
|
|
301
|
+
// Convert dot notation path to JSON path
|
|
302
|
+
const jsonPath = path
|
|
303
|
+
.split('.')
|
|
304
|
+
.map((p) => `$.${p}`)
|
|
305
|
+
.join('');
|
|
306
|
+
// Build JSON extraction SQL
|
|
307
|
+
// Using JSON_EXTRACT for compatibility (works with MySQL, SQLite)
|
|
308
|
+
// For PostgreSQL, dialects should override this method
|
|
309
|
+
const jsonExtract = `JSON_EXTRACT(${columnRef}, '${jsonPath}')`;
|
|
310
|
+
if (value !== undefined) {
|
|
311
|
+
values.push(value);
|
|
312
|
+
// Use = comparison with the extracted value
|
|
313
|
+
return { sql: `${jsonExtract} ${operator} ?`, values };
|
|
314
|
+
}
|
|
315
|
+
// Just return the JSON extraction without value comparison
|
|
316
|
+
return { sql: jsonExtract, values };
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Format a value for SQL based on its type
|
|
320
|
+
*/
|
|
321
|
+
formatValue(value) {
|
|
322
|
+
if (value === null || value === undefined) {
|
|
323
|
+
return 'NULL';
|
|
324
|
+
}
|
|
325
|
+
if (typeof value === 'boolean') {
|
|
326
|
+
return value ? '1' : '0';
|
|
327
|
+
}
|
|
328
|
+
if (typeof value === 'number') {
|
|
329
|
+
return String(value);
|
|
330
|
+
}
|
|
331
|
+
// Handle Date objects or date-like objects
|
|
332
|
+
if (value instanceof Date || (value && typeof value === 'object' && typeof value.getFullYear === 'function')) {
|
|
333
|
+
return this.formatDate(new Date(value.getFullYear(), value.getMonth(), value.getDate(), value.getHours(), value.getMinutes(), value.getSeconds(), value.getMilliseconds()));
|
|
334
|
+
}
|
|
335
|
+
// Handle date strings
|
|
336
|
+
if (typeof value === 'string') {
|
|
337
|
+
const dateStr = value.trim();
|
|
338
|
+
// Check if it looks like an ISO date string
|
|
339
|
+
if (/^\d{4}-\d{2}-\d{2}/.test(dateStr) || /^\d{4}-\d{2}-\d{2}T/.test(dateStr)) {
|
|
340
|
+
const parsedDate = new Date(dateStr);
|
|
341
|
+
if (!isNaN(parsedDate.getTime())) {
|
|
342
|
+
return this.formatDate(parsedDate);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (Buffer.isBuffer(value)) {
|
|
347
|
+
return `X'${value.toString('hex')}'`;
|
|
348
|
+
}
|
|
349
|
+
if (Array.isArray(value) || typeof value === 'object') {
|
|
350
|
+
return this.escape(JSON.stringify(value));
|
|
351
|
+
}
|
|
352
|
+
return this.escape(String(value));
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Format a date for SQL
|
|
356
|
+
*/
|
|
357
|
+
formatDate(date) {
|
|
358
|
+
const year = date.getFullYear();
|
|
359
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
360
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
361
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
362
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
363
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
364
|
+
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
|
365
|
+
return `'${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}'`;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Replace placeholders in SQL with actual values
|
|
369
|
+
* Supports both named (:param) and positional (?) placeholders
|
|
370
|
+
* Properly escapes values to prevent SQL injection
|
|
371
|
+
*/
|
|
372
|
+
replaceReplacements(sql, replacements) {
|
|
373
|
+
if (!replacements) {
|
|
374
|
+
return sql;
|
|
375
|
+
}
|
|
376
|
+
// Handle array replacements (positional ?)
|
|
377
|
+
if (Array.isArray(replacements)) {
|
|
378
|
+
return this.replacePositionalReplacements(sql, replacements);
|
|
379
|
+
}
|
|
380
|
+
// Handle object replacements (named :param)
|
|
381
|
+
return this.replaceNamedReplacements(sql, replacements);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Replace positional (?) placeholders with escaped values
|
|
385
|
+
*/
|
|
386
|
+
replacePositionalReplacements(sql, replacements) {
|
|
387
|
+
let result = sql;
|
|
388
|
+
let paramIndex = 0;
|
|
389
|
+
// Use a placeholder to avoid infinite loops with ?
|
|
390
|
+
const placeholder = '__POS_PLACEHOLDER__';
|
|
391
|
+
// First, escape the ? to avoid issues with the replacement loop
|
|
392
|
+
// We'll track positions of ?
|
|
393
|
+
const matches = [];
|
|
394
|
+
// Find all ? that are not inside quotes
|
|
395
|
+
let inSingleQuote = false;
|
|
396
|
+
let inDoubleQuote = false;
|
|
397
|
+
let escaped = false;
|
|
398
|
+
let i = 0;
|
|
399
|
+
while (i < result.length) {
|
|
400
|
+
const char = result[i];
|
|
401
|
+
if (escaped) {
|
|
402
|
+
escaped = false;
|
|
403
|
+
i++;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (char === '\\') {
|
|
407
|
+
escaped = true;
|
|
408
|
+
i++;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (char === "'" && !inDoubleQuote) {
|
|
412
|
+
inSingleQuote = !inSingleQuote;
|
|
413
|
+
}
|
|
414
|
+
else if (char === '"' && !inSingleQuote) {
|
|
415
|
+
inDoubleQuote = !inDoubleQuote;
|
|
416
|
+
}
|
|
417
|
+
if (!inSingleQuote && !inDoubleQuote && char === '?') {
|
|
418
|
+
const value = replacements[paramIndex];
|
|
419
|
+
const escapedValue = this.escapeReplacement(value);
|
|
420
|
+
matches.push({ index: i, value: escapedValue });
|
|
421
|
+
paramIndex++;
|
|
422
|
+
}
|
|
423
|
+
i++;
|
|
424
|
+
}
|
|
425
|
+
// Replace from end to beginning to maintain correct indices
|
|
426
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
427
|
+
const match = matches[i];
|
|
428
|
+
result = result.slice(0, match.index) + match.value + result.slice(match.index + 1);
|
|
429
|
+
}
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Replace named (:param) placeholders with escaped values
|
|
434
|
+
*/
|
|
435
|
+
replaceNamedReplacements(sql, replacements) {
|
|
436
|
+
let result = sql;
|
|
437
|
+
// Find all :param placeholders
|
|
438
|
+
// Match :param where param is alphanumeric (and possibly with underscores)
|
|
439
|
+
const namedParamRegex = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
440
|
+
// We need to handle this carefully to avoid replacing inside strings
|
|
441
|
+
// For simplicity, we'll use a two-pass approach
|
|
442
|
+
// First pass: identify placeholders not in quotes
|
|
443
|
+
const matches = [];
|
|
444
|
+
let inSingleQuote = false;
|
|
445
|
+
let inDoubleQuote = false;
|
|
446
|
+
const escaped = false;
|
|
447
|
+
const i = 0;
|
|
448
|
+
// Make a fresh regex for each call
|
|
449
|
+
const regex = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
450
|
+
let match;
|
|
451
|
+
// Reset regex state
|
|
452
|
+
regex.lastIndex = 0;
|
|
453
|
+
while ((match = regex.exec(result)) !== null) {
|
|
454
|
+
// Check if we're inside quotes
|
|
455
|
+
const beforeMatch = result.slice(0, match.index);
|
|
456
|
+
const inQuote = false;
|
|
457
|
+
for (const char of beforeMatch) {
|
|
458
|
+
if (char === "'" && !inDoubleQuote) {
|
|
459
|
+
inSingleQuote = !inSingleQuote;
|
|
460
|
+
}
|
|
461
|
+
else if (char === '"' && !inSingleQuote) {
|
|
462
|
+
inDoubleQuote = !inDoubleQuote;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (!inSingleQuote && !inDoubleQuote) {
|
|
466
|
+
matches.push({
|
|
467
|
+
match: match[0],
|
|
468
|
+
param: match[1],
|
|
469
|
+
index: match.index,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
// Reset quote state tracking for next iteration
|
|
473
|
+
inSingleQuote = false;
|
|
474
|
+
inDoubleQuote = false;
|
|
475
|
+
}
|
|
476
|
+
// Replace from end to beginning to maintain correct indices
|
|
477
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
478
|
+
const m = matches[i];
|
|
479
|
+
const value = replacements[m.param];
|
|
480
|
+
if (value === undefined) {
|
|
481
|
+
throw new Error(`Replacement parameter :${m.param} is not defined`);
|
|
482
|
+
}
|
|
483
|
+
const escapedValue = this.escapeReplacement(value);
|
|
484
|
+
result = result.slice(0, m.index) + escapedValue + result.slice(m.index + m.match.length);
|
|
485
|
+
}
|
|
486
|
+
return result;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Escape a replacement value for safe inclusion in SQL
|
|
490
|
+
*/
|
|
491
|
+
escapeReplacement(value) {
|
|
492
|
+
if (value === null || value === undefined) {
|
|
493
|
+
return 'NULL';
|
|
494
|
+
}
|
|
495
|
+
// Handle arrays - convert to (val1, val2, ...) for IN clauses
|
|
496
|
+
if (Array.isArray(value)) {
|
|
497
|
+
const escapedValues = value.map((v) => this.escapeReplacement(v));
|
|
498
|
+
return `(${escapedValues.join(', ')})`;
|
|
499
|
+
}
|
|
500
|
+
// Handle boolean
|
|
501
|
+
if (typeof value === 'boolean') {
|
|
502
|
+
return value ? '1' : '0';
|
|
503
|
+
}
|
|
504
|
+
// Handle numbers
|
|
505
|
+
if (typeof value === 'number') {
|
|
506
|
+
return String(value);
|
|
507
|
+
}
|
|
508
|
+
// Handle Date
|
|
509
|
+
if (value instanceof Date) {
|
|
510
|
+
return this.formatDate(value);
|
|
511
|
+
}
|
|
512
|
+
// Handle Buffer
|
|
513
|
+
if (Buffer.isBuffer(value)) {
|
|
514
|
+
return `X'${value.toString('hex')}'`;
|
|
515
|
+
}
|
|
516
|
+
// Handle objects/arrays as JSON strings
|
|
517
|
+
if (typeof value === 'object') {
|
|
518
|
+
return this.escape(JSON.stringify(value));
|
|
519
|
+
}
|
|
520
|
+
// Handle strings and other types
|
|
521
|
+
return this.escape(String(value));
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Parse a value from the database
|
|
525
|
+
*/
|
|
526
|
+
parseValue(value, type) {
|
|
527
|
+
if (value === null || value === undefined) {
|
|
528
|
+
return value;
|
|
529
|
+
}
|
|
530
|
+
// Handle based on data type
|
|
531
|
+
const typeObj = type;
|
|
532
|
+
const typeKey = typeObj?.key || '';
|
|
533
|
+
switch (typeKey) {
|
|
534
|
+
case 'BOOLEAN':
|
|
535
|
+
if (typeof value === 'number') {
|
|
536
|
+
return value === 1;
|
|
537
|
+
}
|
|
538
|
+
if (typeof value === 'string') {
|
|
539
|
+
return value.toLowerCase() === 'true' || value === '1';
|
|
540
|
+
}
|
|
541
|
+
return Boolean(value);
|
|
542
|
+
case 'INTEGER':
|
|
543
|
+
case 'BIGINT':
|
|
544
|
+
case 'FLOAT':
|
|
545
|
+
case 'DOUBLE':
|
|
546
|
+
case 'DECIMAL':
|
|
547
|
+
return Number(value);
|
|
548
|
+
case 'DATE':
|
|
549
|
+
case 'DATEONLY':
|
|
550
|
+
case 'TIME':
|
|
551
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
552
|
+
return new Date(value);
|
|
553
|
+
}
|
|
554
|
+
return value;
|
|
555
|
+
case 'JSON':
|
|
556
|
+
case 'JSONB':
|
|
557
|
+
if (typeof value === 'string') {
|
|
558
|
+
try {
|
|
559
|
+
return JSON.parse(value);
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
return value;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return value;
|
|
566
|
+
case 'BLOB':
|
|
567
|
+
if (typeof value === 'string') {
|
|
568
|
+
return Buffer.from(value, 'hex');
|
|
569
|
+
}
|
|
570
|
+
return value;
|
|
571
|
+
default:
|
|
572
|
+
return value;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Get the isolation level SQL
|
|
577
|
+
*/
|
|
578
|
+
getIsolationLevelSql(isolationLevel) {
|
|
579
|
+
if (!isolationLevel) {
|
|
580
|
+
return '';
|
|
581
|
+
}
|
|
582
|
+
const levels = {
|
|
583
|
+
'READ UNCOMMITTED': 'READ UNCOMMITTED',
|
|
584
|
+
'READ COMMITTED': 'READ COMMITTED',
|
|
585
|
+
'REPEATABLE READ': 'REPEATABLE READ',
|
|
586
|
+
SERIALIZABLE: 'SERIALIZABLE',
|
|
587
|
+
};
|
|
588
|
+
const level = levels[isolationLevel];
|
|
589
|
+
return level ? `ISOLATION LEVEL ${level}` : '';
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Resolve the 'all' include option to actual include configurations
|
|
593
|
+
*/
|
|
594
|
+
resolveAllInclude(include, parentAlias, depth) {
|
|
595
|
+
const result = [];
|
|
596
|
+
const model = include.model;
|
|
597
|
+
const associations = model?.associations || {};
|
|
598
|
+
for (const [assocName, association] of Object.entries(associations)) {
|
|
599
|
+
// If 'all' is a string, only include that specific association
|
|
600
|
+
if (typeof include.all === 'string' && include.all !== assocName) {
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
const assocModel = association.target;
|
|
604
|
+
// Build the include config for this association
|
|
605
|
+
const assocInclude = {
|
|
606
|
+
model: assocModel,
|
|
607
|
+
as: assocName,
|
|
608
|
+
where: include.where,
|
|
609
|
+
required: include.required,
|
|
610
|
+
attributes: include.attributes,
|
|
611
|
+
order: include.order,
|
|
612
|
+
limit: include.limit,
|
|
613
|
+
offset: include.offset,
|
|
614
|
+
duplicating: include.duplicating,
|
|
615
|
+
};
|
|
616
|
+
// Handle nested includes within 'all' - recursively process them
|
|
617
|
+
if (include.include && include.include.length > 0) {
|
|
618
|
+
assocInclude.include = this.resolveAllInclude({ all: true, include: include.include }, assocName, depth + 1);
|
|
619
|
+
}
|
|
620
|
+
result.push(assocInclude);
|
|
621
|
+
}
|
|
622
|
+
return result;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Generate column list with proper aliasing to avoid duplicates
|
|
626
|
+
*/
|
|
627
|
+
generateSelectColumns(mainTableName, mainTableAlias, attributes, includes) {
|
|
628
|
+
// If explicit attributes are provided, use those
|
|
629
|
+
if (attributes) {
|
|
630
|
+
if (Array.isArray(attributes)) {
|
|
631
|
+
// Add table alias prefix to avoid duplicates
|
|
632
|
+
return attributes
|
|
633
|
+
.map((a) => `${this.escapeId(mainTableAlias)}.${this.escapeId(a)}`)
|
|
634
|
+
.join(', ');
|
|
635
|
+
}
|
|
636
|
+
else if (attributes.include) {
|
|
637
|
+
return attributes.include
|
|
638
|
+
.map((a) => `${this.escapeId(mainTableAlias)}.${this.escapeId(a)}`)
|
|
639
|
+
.join(', ');
|
|
640
|
+
}
|
|
641
|
+
else if (attributes.exclude) {
|
|
642
|
+
// For exclude, we need to get all columns and exclude specific ones
|
|
643
|
+
// This is database-specific; for now, return * with EXCEPT
|
|
644
|
+
return `* EXCEPT (${attributes.exclude.map((a) => this.escapeId(a)).join(', ')})`;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
// Default: select all columns from main table with alias prefix
|
|
648
|
+
// and all columns from included tables with their aliases
|
|
649
|
+
const mainColumns = [`${this.escapeId(mainTableAlias)}.*`];
|
|
650
|
+
// Add columns from included tables to avoid duplicates
|
|
651
|
+
if (includes && includes.length > 0) {
|
|
652
|
+
for (const inc of includes) {
|
|
653
|
+
mainColumns.push(`${this.escapeId(inc.alias)}.*`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return mainColumns.join(', ');
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Flatten nested includes to handle 'all' option
|
|
660
|
+
*/
|
|
661
|
+
flattenIncludesWithAll(includes, parentAlias = 'main', depth = 0) {
|
|
662
|
+
const flattened = [];
|
|
663
|
+
for (const include of includes) {
|
|
664
|
+
// Handle 'all' option
|
|
665
|
+
if (include.all) {
|
|
666
|
+
const resolved = this.resolveAllInclude(include, parentAlias, depth);
|
|
667
|
+
for (const res of resolved) {
|
|
668
|
+
const nested = this.flattenIncludesWithAll([res], res.as || '', depth + 1);
|
|
669
|
+
flattened.push(...nested);
|
|
670
|
+
}
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
flattened.push(include);
|
|
674
|
+
// Recursively process nested includes
|
|
675
|
+
if (include.include && include.include.length > 0) {
|
|
676
|
+
const nested = this.flattenIncludesWithAll(include.include, include.as || include.model?.tableName || '', depth + 1);
|
|
677
|
+
// Replace nested includes with flattened versions
|
|
678
|
+
include.include = nested;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return flattened;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
exports.BaseDialect = BaseDialect;
|
|
685
|
+
/**
|
|
686
|
+
* Dialect registry for managing available dialects
|
|
687
|
+
*/
|
|
688
|
+
class DialectRegistry {
|
|
689
|
+
/**
|
|
690
|
+
* Register a new dialect
|
|
691
|
+
*/
|
|
692
|
+
static register(name, factory) {
|
|
693
|
+
this.dialects.set(name.toLowerCase(), factory);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Get a dialect by name
|
|
697
|
+
*/
|
|
698
|
+
static get(name) {
|
|
699
|
+
const factory = this.dialects.get(name.toLowerCase());
|
|
700
|
+
if (!factory) {
|
|
701
|
+
const available = Array.from(this.dialects.keys()).join(', ');
|
|
702
|
+
throw new Error(`Dialect "${name}" is not registered. Available dialects: ${available}`);
|
|
703
|
+
}
|
|
704
|
+
return factory;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Check if a dialect is registered
|
|
708
|
+
*/
|
|
709
|
+
static has(name) {
|
|
710
|
+
return this.dialects.has(name.toLowerCase());
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Get all registered dialect names
|
|
714
|
+
*/
|
|
715
|
+
static getAvailable() {
|
|
716
|
+
return Array.from(this.dialects.keys());
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
exports.DialectRegistry = DialectRegistry;
|
|
720
|
+
DialectRegistry.dialects = new Map();
|