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,415 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Explain Query Plans
|
|
4
|
+
* Provides functionality to analyze and explain SQL query execution plans
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ExplainPlanGenerator = exports.ExplainFormat = void 0;
|
|
8
|
+
exports.createExplainPlanGenerator = createExplainPlanGenerator;
|
|
9
|
+
/**
|
|
10
|
+
* Explain output format options
|
|
11
|
+
*/
|
|
12
|
+
var ExplainFormat;
|
|
13
|
+
(function (ExplainFormat) {
|
|
14
|
+
ExplainFormat["TEXT"] = "text";
|
|
15
|
+
ExplainFormat["JSON"] = "json";
|
|
16
|
+
ExplainFormat["XML"] = "xml";
|
|
17
|
+
ExplainFormat["YAML"] = "yaml";
|
|
18
|
+
ExplainFormat["TREE"] = "tree";
|
|
19
|
+
})(ExplainFormat || (exports.ExplainFormat = ExplainFormat = {}));
|
|
20
|
+
/**
|
|
21
|
+
* Explain plan generator for different database dialects
|
|
22
|
+
*/
|
|
23
|
+
class ExplainPlanGenerator {
|
|
24
|
+
constructor(dialect, defaultOptions) {
|
|
25
|
+
this.dialect = dialect;
|
|
26
|
+
this.defaultOptions = {
|
|
27
|
+
format: ExplainFormat.TEXT,
|
|
28
|
+
analyze: false,
|
|
29
|
+
verbose: false,
|
|
30
|
+
...defaultOptions,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set default options for EXPLAIN queries
|
|
35
|
+
*/
|
|
36
|
+
setDefaultOptions(options) {
|
|
37
|
+
this.defaultOptions = { ...this.defaultOptions, ...options };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate an explain plan for a SQL query
|
|
41
|
+
*/
|
|
42
|
+
async explain(sql, options) {
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
const mergedOptions = { ...this.defaultOptions, ...options };
|
|
45
|
+
// Build EXPLAIN statement based on dialect
|
|
46
|
+
const explainSql = this.buildExplainSql(sql, mergedOptions);
|
|
47
|
+
// Execute the explain query
|
|
48
|
+
const rawResults = await this.dialect.query(explainSql, { raw: true });
|
|
49
|
+
const duration = Date.now() - startTime;
|
|
50
|
+
// Parse the explain output
|
|
51
|
+
const parsedPlan = this.parseExplainOutput(rawResults, mergedOptions.format || ExplainFormat.TEXT);
|
|
52
|
+
return {
|
|
53
|
+
sql,
|
|
54
|
+
plan: rawResults,
|
|
55
|
+
rawResults,
|
|
56
|
+
duration,
|
|
57
|
+
dialect: this.dialect.name,
|
|
58
|
+
parsedPlan,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the appropriate EXPLAIN SQL statement for the dialect
|
|
63
|
+
*/
|
|
64
|
+
buildExplainSql(sql, options) {
|
|
65
|
+
const dialectName = this.dialect.name.toLowerCase();
|
|
66
|
+
const format = options.format || ExplainFormat.TEXT;
|
|
67
|
+
switch (dialectName) {
|
|
68
|
+
case 'mysql':
|
|
69
|
+
case 'mariadb':
|
|
70
|
+
return this.buildMySQLExplain(sql, options);
|
|
71
|
+
case 'postgres':
|
|
72
|
+
case 'postgresql':
|
|
73
|
+
return this.buildPostgresExplain(sql, options);
|
|
74
|
+
case 'sqlite':
|
|
75
|
+
return this.buildSQLiteExplain(sql, options);
|
|
76
|
+
default:
|
|
77
|
+
return `EXPLAIN ${sql}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build MySQL EXPLAIN statement
|
|
82
|
+
*/
|
|
83
|
+
buildMySQLExplain(sql, options) {
|
|
84
|
+
let explain = 'EXPLAIN';
|
|
85
|
+
// Add options
|
|
86
|
+
if (options.analyze) {
|
|
87
|
+
explain += ' ANALYZE';
|
|
88
|
+
}
|
|
89
|
+
if (options.format === ExplainFormat.JSON) {
|
|
90
|
+
explain += ' FORMAT=JSON';
|
|
91
|
+
}
|
|
92
|
+
else if (options.format === ExplainFormat.TREE) {
|
|
93
|
+
explain += ' FORMAT=TREE';
|
|
94
|
+
}
|
|
95
|
+
// Add statement type if provided
|
|
96
|
+
if (options.type) {
|
|
97
|
+
explain += ` ${options.type}`;
|
|
98
|
+
}
|
|
99
|
+
return `${explain} ${sql}`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Build PostgreSQL EXPLAIN statement
|
|
103
|
+
*/
|
|
104
|
+
buildPostgresExplain(sql, options) {
|
|
105
|
+
let explain = 'EXPLAIN';
|
|
106
|
+
if (options.analyze) {
|
|
107
|
+
explain += ' ANALYZE';
|
|
108
|
+
}
|
|
109
|
+
if (options.buffers) {
|
|
110
|
+
explain += ' BUFFERS';
|
|
111
|
+
}
|
|
112
|
+
if (options.timing) {
|
|
113
|
+
explain += ' TIMING';
|
|
114
|
+
}
|
|
115
|
+
if (options.format === ExplainFormat.JSON) {
|
|
116
|
+
explain += ' (FORMAT JSON)';
|
|
117
|
+
}
|
|
118
|
+
else if (options.format === ExplainFormat.XML) {
|
|
119
|
+
explain += ' (FORMAT XML)';
|
|
120
|
+
}
|
|
121
|
+
else if (options.format === ExplainFormat.YAML) {
|
|
122
|
+
explain += ' (FORMAT YAML)';
|
|
123
|
+
}
|
|
124
|
+
return `${explain} ${sql}`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build SQLite EXPLAIN statement
|
|
128
|
+
*/
|
|
129
|
+
buildSQLiteExplain(sql, _options) {
|
|
130
|
+
// SQLite has QUERY_PLAN and EXPLAIN
|
|
131
|
+
return `EXPLAIN QUERY PLAN ${sql}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Parse EXPLAIN output into structured format
|
|
135
|
+
*/
|
|
136
|
+
parseExplainOutput(results, format) {
|
|
137
|
+
const rows = results.rows || [];
|
|
138
|
+
if (rows.length === 0) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
const dialectName = this.dialect.name.toLowerCase();
|
|
142
|
+
switch (dialectName) {
|
|
143
|
+
case 'mysql':
|
|
144
|
+
case 'mariadb':
|
|
145
|
+
return this.parseMySQLExplain(rows);
|
|
146
|
+
case 'postgres':
|
|
147
|
+
case 'postgresql':
|
|
148
|
+
return this.parsePostgresExplain(rows);
|
|
149
|
+
case 'sqlite':
|
|
150
|
+
return this.parseSQLiteExplain(rows);
|
|
151
|
+
default:
|
|
152
|
+
return this.parseGenericExplain(rows);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Parse MySQL EXPLAIN output
|
|
157
|
+
*/
|
|
158
|
+
parseMySQLExplain(rows) {
|
|
159
|
+
return rows.map((row) => ({
|
|
160
|
+
operation: row.type || row.select_type || 'UNKNOWN',
|
|
161
|
+
table: row.table,
|
|
162
|
+
index: row.possible_keys,
|
|
163
|
+
rows: row.rows ? parseInt(String(row.rows), 10) : undefined,
|
|
164
|
+
cost: row.key_len ? parseInt(String(row.key_len), 10) : undefined,
|
|
165
|
+
details: {
|
|
166
|
+
selectId: row.id,
|
|
167
|
+
selectType: row.select_type,
|
|
168
|
+
key: row.key,
|
|
169
|
+
keyLength: row.key_len,
|
|
170
|
+
ref: row.ref,
|
|
171
|
+
extra: row.Extra,
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Parse PostgreSQL EXPLAIN output
|
|
177
|
+
*/
|
|
178
|
+
parsePostgresExplain(rows) {
|
|
179
|
+
return rows.map((row) => {
|
|
180
|
+
// Check if it's a JSON format result
|
|
181
|
+
if (row.Plan) {
|
|
182
|
+
return this.parsePostgresPlanNode(row.Plan);
|
|
183
|
+
}
|
|
184
|
+
// Text format - parse the output
|
|
185
|
+
const planText = row['Query Plan'] || row.plan || row;
|
|
186
|
+
return {
|
|
187
|
+
operation: 'UNKNOWN',
|
|
188
|
+
details: { raw: planText },
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Recursively parse PostgreSQL plan nodes
|
|
194
|
+
*/
|
|
195
|
+
parsePostgresPlanNode(plan) {
|
|
196
|
+
const step = {
|
|
197
|
+
operation: plan.NodeType || 'OPERATION',
|
|
198
|
+
table: plan.RelationName,
|
|
199
|
+
index: plan.IndexName,
|
|
200
|
+
rows: plan.PlanRows ? parseInt(String(plan.PlanRows), 10) : undefined,
|
|
201
|
+
cost: plan.TotalCost ? parseFloat(String(plan.TotalCost)) : undefined,
|
|
202
|
+
details: {
|
|
203
|
+
startupCost: plan.StartupCost,
|
|
204
|
+
totalCost: plan.TotalCost,
|
|
205
|
+
planWidth: plan.PlanWidth,
|
|
206
|
+
actualStartupTime: plan.ActualStartupTime,
|
|
207
|
+
actualTotalTime: plan.ActualTotalTime,
|
|
208
|
+
actualRows: plan.ActualRows,
|
|
209
|
+
sharedHitBlocks: plan.SharedHitBlocks,
|
|
210
|
+
sharedReadBlocks: plan.SharedReadBlocks,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
if (plan.Plans && plan.Plans.length > 0) {
|
|
214
|
+
step.children = plan.Plans.map((p) => this.parsePostgresPlanNode(p));
|
|
215
|
+
}
|
|
216
|
+
return step;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Parse SQLite EXPLAIN QUERY PLAN output
|
|
220
|
+
*/
|
|
221
|
+
parseSQLiteExplain(rows) {
|
|
222
|
+
return rows.map((row) => {
|
|
223
|
+
// SQLite returns: id, order, from, detail
|
|
224
|
+
const detail = row.detail || row.DETAIL || '';
|
|
225
|
+
const operation = this.extractSQLiteOperation(detail);
|
|
226
|
+
const table = this.extractSQLiteTable(detail);
|
|
227
|
+
const index = this.extractSQLiteIndex(detail);
|
|
228
|
+
return {
|
|
229
|
+
operation,
|
|
230
|
+
table,
|
|
231
|
+
index,
|
|
232
|
+
details: { detail },
|
|
233
|
+
};
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Extract operation type from SQLite detail
|
|
238
|
+
*/
|
|
239
|
+
extractSQLiteOperation(detail) {
|
|
240
|
+
if (detail.includes('SCAN'))
|
|
241
|
+
return 'SCAN';
|
|
242
|
+
if (detail.includes('SEARCH'))
|
|
243
|
+
return 'SEARCH';
|
|
244
|
+
if (detail.includes('USING INDEX'))
|
|
245
|
+
return 'INDEX';
|
|
246
|
+
if (detail.includes('USING COVERING INDEX'))
|
|
247
|
+
return 'COVERING INDEX';
|
|
248
|
+
if (detail.includes('USING TEMP'))
|
|
249
|
+
return 'TEMP';
|
|
250
|
+
if (detail.includes('USING FILESORT'))
|
|
251
|
+
return 'FILESORT';
|
|
252
|
+
if (detail.includes('COMPOUND'))
|
|
253
|
+
return 'COMPOUND';
|
|
254
|
+
return 'OPERATION';
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Extract table name from SQLite detail
|
|
258
|
+
*/
|
|
259
|
+
extractSQLiteTable(detail) {
|
|
260
|
+
const match = detail.match(/(?:SCAN|SEARCH)\s+(\w+)/i);
|
|
261
|
+
return match ? match[1] : undefined;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Extract index name from SQLite detail
|
|
265
|
+
*/
|
|
266
|
+
extractSQLiteIndex(detail) {
|
|
267
|
+
const match = detail.match(/USING\s+INDEX\s+(\w+)/i);
|
|
268
|
+
return match ? match[1] : undefined;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Generic explain output parser
|
|
272
|
+
*/
|
|
273
|
+
parseGenericExplain(rows) {
|
|
274
|
+
return rows.map((row) => ({
|
|
275
|
+
operation: 'ROW',
|
|
276
|
+
details: { ...row },
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Analyze a query and provide optimization recommendations
|
|
281
|
+
*/
|
|
282
|
+
async analyzeQuery(sql, options) {
|
|
283
|
+
const plan = await this.explain(sql, options);
|
|
284
|
+
const recommendations = this.generateRecommendations(plan);
|
|
285
|
+
return { plan, recommendations };
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Generate optimization recommendations based on explain plan
|
|
289
|
+
*/
|
|
290
|
+
generateRecommendations(plan) {
|
|
291
|
+
const recommendations = [];
|
|
292
|
+
const dialectName = plan.dialect.toLowerCase();
|
|
293
|
+
if (!plan.parsedPlan || plan.parsedPlan.length === 0) {
|
|
294
|
+
return recommendations;
|
|
295
|
+
}
|
|
296
|
+
switch (dialectName) {
|
|
297
|
+
case 'mysql':
|
|
298
|
+
case 'mariadb':
|
|
299
|
+
return this.generateMySQLRecommendations(plan.parsedPlan);
|
|
300
|
+
case 'postgres':
|
|
301
|
+
case 'postgresql':
|
|
302
|
+
return this.generatePostgresRecommendations(plan.parsedPlan);
|
|
303
|
+
case 'sqlite':
|
|
304
|
+
return this.generateSQLiteRecommendations(plan.parsedPlan);
|
|
305
|
+
default:
|
|
306
|
+
return recommendations;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Generate MySQL-specific recommendations
|
|
311
|
+
*/
|
|
312
|
+
generateMySQLRecommendations(plan) {
|
|
313
|
+
const recommendations = [];
|
|
314
|
+
for (const step of plan) {
|
|
315
|
+
// Check for full table scans
|
|
316
|
+
if (step.operation === 'ALL' || step.details?.extra?.includes('Using where')) {
|
|
317
|
+
recommendations.push({
|
|
318
|
+
type: 'INDEX',
|
|
319
|
+
severity: 'HIGH',
|
|
320
|
+
message: 'Full table scan detected. Consider adding an index.',
|
|
321
|
+
table: step.table,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
// Check for missing indexes on WHERE
|
|
325
|
+
if (step.details?.possible_keys === null && step.details?.key === null) {
|
|
326
|
+
recommendations.push({
|
|
327
|
+
type: 'INDEX',
|
|
328
|
+
severity: 'MEDIUM',
|
|
329
|
+
message: 'No suitable index found for query conditions.',
|
|
330
|
+
table: step.table,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
// Check for filesort
|
|
334
|
+
if (step.details?.extra?.includes('Using filesort')) {
|
|
335
|
+
recommendations.push({
|
|
336
|
+
type: 'OPTIMIZATION',
|
|
337
|
+
severity: 'MEDIUM',
|
|
338
|
+
message: 'Filesort detected. Consider adding an index on the ORDER BY column.',
|
|
339
|
+
table: step.table,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
// Check for temporary tables
|
|
343
|
+
if (step.details?.extra?.includes('Using temporary')) {
|
|
344
|
+
recommendations.push({
|
|
345
|
+
type: 'OPTIMIZATION',
|
|
346
|
+
severity: 'LOW',
|
|
347
|
+
message: 'Temporary table used. Query may benefit from optimization.',
|
|
348
|
+
table: step.table,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return recommendations;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Generate PostgreSQL-specific recommendations
|
|
356
|
+
*/
|
|
357
|
+
generatePostgresRecommendations(plan) {
|
|
358
|
+
const recommendations = [];
|
|
359
|
+
const checkNode = (node) => {
|
|
360
|
+
// Check for sequential scans
|
|
361
|
+
if (node.operation === 'Seq Scan') {
|
|
362
|
+
recommendations.push({
|
|
363
|
+
type: 'INDEX',
|
|
364
|
+
severity: 'HIGH',
|
|
365
|
+
message: 'Sequential scan detected on table.',
|
|
366
|
+
table: node.table,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
// Check for high row estimates
|
|
370
|
+
if (node.rows && node.rows > 10000) {
|
|
371
|
+
recommendations.push({
|
|
372
|
+
type: 'OPTIMIZATION',
|
|
373
|
+
severity: 'MEDIUM',
|
|
374
|
+
message: `High row estimate (${node.rows}). Consider using an index.`,
|
|
375
|
+
table: node.table,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
// Check children
|
|
379
|
+
if (node.children) {
|
|
380
|
+
node.children.forEach(checkNode);
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
plan.forEach(checkNode);
|
|
384
|
+
return recommendations;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Generate SQLite-specific recommendations
|
|
388
|
+
*/
|
|
389
|
+
generateSQLiteRecommendations(plan) {
|
|
390
|
+
const recommendations = [];
|
|
391
|
+
for (const step of plan) {
|
|
392
|
+
if (step.operation === 'SCAN') {
|
|
393
|
+
recommendations.push({
|
|
394
|
+
type: 'INDEX',
|
|
395
|
+
severity: 'HIGH',
|
|
396
|
+
message: 'Full table scan detected.',
|
|
397
|
+
table: step.table,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return recommendations;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
exports.ExplainPlanGenerator = ExplainPlanGenerator;
|
|
405
|
+
/**
|
|
406
|
+
* Create an ExplainPlanGenerator instance
|
|
407
|
+
*/
|
|
408
|
+
function createExplainPlanGenerator(dialect, options) {
|
|
409
|
+
return new ExplainPlanGenerator(dialect, options);
|
|
410
|
+
}
|
|
411
|
+
exports.default = {
|
|
412
|
+
ExplainPlanGenerator,
|
|
413
|
+
ExplainFormat,
|
|
414
|
+
createExplainPlanGenerator,
|
|
415
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Query Optimizers Module
|
|
4
|
+
* Provides various query optimization features including:
|
|
5
|
+
* - Query hint support
|
|
6
|
+
* - Explain query plans
|
|
7
|
+
* - Slow query logging
|
|
8
|
+
* - Query batch/bulk optimization
|
|
9
|
+
* - Prepared statement caching
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.defaultOptimizerConfig = exports.createQueryOptimizer = exports.QueryOptimizer = exports.createPreparedStatementCache = exports.PreparedStatementCache = exports.optimizeBatchDelete = exports.optimizeBatchUpdate = exports.optimizeBatchInsert = exports.BatchQueryOptimizer = exports.createSlowQueryLogger = exports.SlowQueryLogger = exports.createExplainPlanGenerator = exports.ExplainFormat = exports.ExplainPlanGenerator = exports.NO_MERGE = exports.MERGE_HASH = exports.JOIN_FIXED_ORDER = exports.USE_INDEX = exports.FORCE_INDEX = exports.INDEX_HINT = exports.HintType = exports.QueryHintManager = void 0;
|
|
13
|
+
var query_hints_1 = require("./query-hints");
|
|
14
|
+
Object.defineProperty(exports, "QueryHintManager", { enumerable: true, get: function () { return query_hints_1.QueryHintManager; } });
|
|
15
|
+
Object.defineProperty(exports, "HintType", { enumerable: true, get: function () { return query_hints_1.HintType; } });
|
|
16
|
+
Object.defineProperty(exports, "INDEX_HINT", { enumerable: true, get: function () { return query_hints_1.INDEX_HINT; } });
|
|
17
|
+
Object.defineProperty(exports, "FORCE_INDEX", { enumerable: true, get: function () { return query_hints_1.FORCE_INDEX; } });
|
|
18
|
+
Object.defineProperty(exports, "USE_INDEX", { enumerable: true, get: function () { return query_hints_1.USE_INDEX; } });
|
|
19
|
+
Object.defineProperty(exports, "JOIN_FIXED_ORDER", { enumerable: true, get: function () { return query_hints_1.JOIN_FIXED_ORDER; } });
|
|
20
|
+
Object.defineProperty(exports, "MERGE_HASH", { enumerable: true, get: function () { return query_hints_1.MERGE_HASH; } });
|
|
21
|
+
Object.defineProperty(exports, "NO_MERGE", { enumerable: true, get: function () { return query_hints_1.NO_MERGE; } });
|
|
22
|
+
var explain_plans_1 = require("./explain-plans");
|
|
23
|
+
Object.defineProperty(exports, "ExplainPlanGenerator", { enumerable: true, get: function () { return explain_plans_1.ExplainPlanGenerator; } });
|
|
24
|
+
Object.defineProperty(exports, "ExplainFormat", { enumerable: true, get: function () { return explain_plans_1.ExplainFormat; } });
|
|
25
|
+
Object.defineProperty(exports, "createExplainPlanGenerator", { enumerable: true, get: function () { return explain_plans_1.createExplainPlanGenerator; } });
|
|
26
|
+
var slow_query_logger_1 = require("./slow-query-logger");
|
|
27
|
+
Object.defineProperty(exports, "SlowQueryLogger", { enumerable: true, get: function () { return slow_query_logger_1.SlowQueryLogger; } });
|
|
28
|
+
Object.defineProperty(exports, "createSlowQueryLogger", { enumerable: true, get: function () { return slow_query_logger_1.createSlowQueryLogger; } });
|
|
29
|
+
var batch_optimizer_1 = require("./batch-optimizer");
|
|
30
|
+
Object.defineProperty(exports, "BatchQueryOptimizer", { enumerable: true, get: function () { return batch_optimizer_1.BatchQueryOptimizer; } });
|
|
31
|
+
Object.defineProperty(exports, "optimizeBatchInsert", { enumerable: true, get: function () { return batch_optimizer_1.optimizeBatchInsert; } });
|
|
32
|
+
Object.defineProperty(exports, "optimizeBatchUpdate", { enumerable: true, get: function () { return batch_optimizer_1.optimizeBatchUpdate; } });
|
|
33
|
+
Object.defineProperty(exports, "optimizeBatchDelete", { enumerable: true, get: function () { return batch_optimizer_1.optimizeBatchDelete; } });
|
|
34
|
+
var prepared_statement_cache_1 = require("./prepared-statement-cache");
|
|
35
|
+
Object.defineProperty(exports, "PreparedStatementCache", { enumerable: true, get: function () { return prepared_statement_cache_1.PreparedStatementCache; } });
|
|
36
|
+
Object.defineProperty(exports, "createPreparedStatementCache", { enumerable: true, get: function () { return prepared_statement_cache_1.createPreparedStatementCache; } });
|
|
37
|
+
var query_optimizer_1 = require("./query-optimizer");
|
|
38
|
+
Object.defineProperty(exports, "QueryOptimizer", { enumerable: true, get: function () { return query_optimizer_1.QueryOptimizer; } });
|
|
39
|
+
Object.defineProperty(exports, "createQueryOptimizer", { enumerable: true, get: function () { return query_optimizer_1.createQueryOptimizer; } });
|
|
40
|
+
/**
|
|
41
|
+
* Default configuration for query optimizers
|
|
42
|
+
*/
|
|
43
|
+
exports.defaultOptimizerConfig = {
|
|
44
|
+
slowQueryThreshold: 1000, // ms
|
|
45
|
+
preparedStatementCacheSize: 500,
|
|
46
|
+
batchInsertChunkSize: 1000,
|
|
47
|
+
batchUpdateChunkSize: 500,
|
|
48
|
+
batchDeleteChunkSize: 500,
|
|
49
|
+
enableExplainPlans: process.env.NODE_ENV === 'development',
|
|
50
|
+
enableQueryHints: true,
|
|
51
|
+
};
|