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.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,426 @@
1
+ "use strict";
2
+ /**
3
+ * Query Batch/Bulk Optimization
4
+ * Provides functionality to optimize batch operations for better performance
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.BatchQueryOptimizer = void 0;
8
+ exports.optimizeBatchInsert = optimizeBatchInsert;
9
+ exports.optimizeBatchUpdate = optimizeBatchUpdate;
10
+ exports.optimizeBatchDelete = optimizeBatchDelete;
11
+ /**
12
+ * Batch query optimizer
13
+ */
14
+ class BatchQueryOptimizer {
15
+ constructor(dialect, defaultOptions) {
16
+ this.dialect = dialect;
17
+ this.defaultOptions = {
18
+ chunkSize: 1000,
19
+ useTransaction: true,
20
+ validate: true,
21
+ skipDuplicates: false,
22
+ stopOnError: false,
23
+ ...defaultOptions,
24
+ };
25
+ }
26
+ /**
27
+ * Set default options for batch operations
28
+ */
29
+ setDefaultOptions(options) {
30
+ this.defaultOptions = { ...this.defaultOptions, ...options };
31
+ }
32
+ /**
33
+ * Optimize batch insert by combining multiple INSERT statements
34
+ * @param tableName - Name of the table to insert into
35
+ * @param records - Array of records to insert
36
+ * @param options - Batch options
37
+ */
38
+ async optimizeBatchInsert(tableName, records, options) {
39
+ const opts = { ...this.defaultOptions, ...options };
40
+ const startTime = Date.now();
41
+ if (records.length === 0) {
42
+ return {
43
+ success: [],
44
+ failed: [],
45
+ total: 0,
46
+ chunkSize: opts.chunkSize,
47
+ batches: 0,
48
+ duration: 0,
49
+ };
50
+ }
51
+ const success = [];
52
+ const failed = [];
53
+ const chunks = this.chunkArray(records, opts.chunkSize);
54
+ const totalBatches = Math.ceil(records.length / opts.chunkSize);
55
+ for (let batchIndex = 0; batchIndex < chunks.length; batchIndex++) {
56
+ const chunk = chunks[batchIndex];
57
+ try {
58
+ // Try multi-value INSERT first (most efficient)
59
+ const result = await this.executeBatchInsert(tableName, chunk, opts);
60
+ success.push(...chunk);
61
+ this.logProgress(opts, {
62
+ total: records.length,
63
+ processed: success.length + failed.length,
64
+ success: success.length,
65
+ failed: failed.length,
66
+ batchIndex,
67
+ totalBatches,
68
+ });
69
+ }
70
+ catch (error) {
71
+ if (opts.stopOnError) {
72
+ throw error;
73
+ }
74
+ // Fall back to individual inserts
75
+ for (const record of chunk) {
76
+ try {
77
+ await this.executeSingleInsert(tableName, record, opts);
78
+ success.push(record);
79
+ }
80
+ catch (individualError) {
81
+ if (!opts.skipDuplicates || !this.isDuplicateKeyError(individualError)) {
82
+ failed.push({ record, error: individualError });
83
+ }
84
+ }
85
+ }
86
+ this.logProgress(opts, {
87
+ total: records.length,
88
+ processed: success.length + failed.length,
89
+ success: success.length,
90
+ failed: failed.length,
91
+ batchIndex,
92
+ totalBatches,
93
+ });
94
+ }
95
+ }
96
+ return {
97
+ success,
98
+ failed,
99
+ total: records.length,
100
+ chunkSize: opts.chunkSize,
101
+ batches: totalBatches,
102
+ duration: Date.now() - startTime,
103
+ };
104
+ }
105
+ /**
106
+ * Build the next placeholder token for a bound parameter, given the running
107
+ * 1-based parameter index. Matches the placeholder convention each dialect's
108
+ * own buildInsertQuery/buildUpdateQuery/buildDeleteQuery already uses:
109
+ * - postgres: $1, $2, ...
110
+ * - mssql: @p1, @p2, ...
111
+ * - oracle: :1, :2, ...
112
+ * - others (mysql/mariadb/sqlite): ?
113
+ */
114
+ nextPlaceholder(paramIndex) {
115
+ switch (this.dialect.name) {
116
+ case 'postgres':
117
+ return `$${paramIndex}`;
118
+ case 'mssql':
119
+ return `@p${paramIndex}`;
120
+ case 'oracle':
121
+ return `:${paramIndex}`;
122
+ default:
123
+ return '?';
124
+ }
125
+ }
126
+ /**
127
+ * Execute a batch insert using multi-value INSERT
128
+ * Uses bound parameters with dialect-correct placeholders ($1, $2, ... for
129
+ * PostgreSQL, `?` for the other dialects) instead of interpolating values.
130
+ */
131
+ async executeBatchInsert(tableName, records, options) {
132
+ if (records.length === 0)
133
+ return;
134
+ const columns = Object.keys(records[0]);
135
+ const quotedTable = this.dialect.quoteTable(tableName);
136
+ const quotedColumns = columns.map((c) => this.dialect.quoteIdentifier(c)).join(', ');
137
+ // Build multi-value INSERT
138
+ const valuesClauses = [];
139
+ const allParams = [];
140
+ let paramIndex = 1;
141
+ for (const record of records) {
142
+ const placeholders = [];
143
+ for (const col of columns) {
144
+ placeholders.push(this.nextPlaceholder(paramIndex++));
145
+ allParams.push(record[col]);
146
+ }
147
+ valuesClauses.push(`(${placeholders.join(', ')})`);
148
+ }
149
+ const sql = `INSERT INTO ${quotedTable} (${quotedColumns}) VALUES ${valuesClauses.join(', ')}`;
150
+ await this.dialect.query(sql, { raw: true, replacements: allParams });
151
+ }
152
+ /**
153
+ * Execute a single record insert
154
+ */
155
+ async executeSingleInsert(tableName, record, options) {
156
+ const { sql, values } = this.dialect.buildInsertQuery(tableName, record);
157
+ await this.dialect.query(sql, { raw: true, replacements: values });
158
+ }
159
+ /**
160
+ * Optimize batch update
161
+ * @param tableName - Name of the table to update
162
+ * @param records - Records to update (must have primary key or unique identifier)
163
+ * @param identifierColumn - Column to use for identifying records
164
+ * @param options - Batch options
165
+ */
166
+ async optimizeBatchUpdate(tableName, records, identifierColumn = 'id', options) {
167
+ const opts = { ...this.defaultOptions, ...options };
168
+ const startTime = Date.now();
169
+ if (records.length === 0) {
170
+ return {
171
+ success: [],
172
+ failed: [],
173
+ total: 0,
174
+ chunkSize: opts.chunkSize,
175
+ batches: 0,
176
+ duration: 0,
177
+ };
178
+ }
179
+ const success = [];
180
+ const failed = [];
181
+ const chunks = this.chunkArray(records, opts.chunkSize);
182
+ const totalBatches = Math.ceil(records.length / opts.chunkSize);
183
+ for (let batchIndex = 0; batchIndex < chunks.length; batchIndex++) {
184
+ const chunk = chunks[batchIndex];
185
+ try {
186
+ // Try batch UPDATE with CASE expressions (more efficient)
187
+ await this.executeBatchUpdate(tableName, chunk, identifierColumn, opts);
188
+ success.push(...chunk);
189
+ this.logProgress(opts, {
190
+ total: records.length,
191
+ processed: success.length + failed.length,
192
+ success: success.length,
193
+ failed: failed.length,
194
+ batchIndex,
195
+ totalBatches,
196
+ });
197
+ }
198
+ catch (error) {
199
+ if (opts.stopOnError) {
200
+ throw error;
201
+ }
202
+ // Fall back to individual updates
203
+ for (const record of chunk) {
204
+ try {
205
+ const idValue = record[identifierColumn];
206
+ const updateValues = { ...record };
207
+ delete updateValues[identifierColumn];
208
+ await this.executeSingleUpdate(tableName, updateValues, { [identifierColumn]: idValue }, opts);
209
+ success.push(record);
210
+ }
211
+ catch (individualError) {
212
+ failed.push({ record, error: individualError });
213
+ }
214
+ }
215
+ this.logProgress(opts, {
216
+ total: records.length,
217
+ processed: success.length + failed.length,
218
+ success: success.length,
219
+ failed: failed.length,
220
+ batchIndex,
221
+ totalBatches,
222
+ });
223
+ }
224
+ }
225
+ return {
226
+ success,
227
+ failed,
228
+ total: records.length,
229
+ chunkSize: opts.chunkSize,
230
+ batches: totalBatches,
231
+ duration: Date.now() - startTime,
232
+ };
233
+ }
234
+ /**
235
+ * Execute batch update using CASE expressions
236
+ * Uses bound parameters with dialect-correct placeholders instead of
237
+ * interpolating escaped literals directly into the SQL string.
238
+ */
239
+ async executeBatchUpdate(tableName, records, identifierColumn, options) {
240
+ if (records.length === 0)
241
+ return;
242
+ const columns = Object.keys(records[0]).filter((col) => col !== identifierColumn);
243
+ const quotedTable = this.dialect.quoteTable(tableName);
244
+ // Build CASE expressions for each column
245
+ const caseClauses = [];
246
+ const params = [];
247
+ let paramIndex = 1;
248
+ for (const column of columns) {
249
+ const whenClauses = [];
250
+ for (const record of records) {
251
+ const idPlaceholder = this.nextPlaceholder(paramIndex++);
252
+ params.push(record[identifierColumn]);
253
+ const valuePlaceholder = this.nextPlaceholder(paramIndex++);
254
+ params.push(record[column]);
255
+ whenClauses.push(`WHEN ${idPlaceholder} THEN ${valuePlaceholder}`);
256
+ }
257
+ caseClauses.push(`${this.dialect.quoteIdentifier(column)} = CASE ${whenClauses.join(' ')} END`);
258
+ }
259
+ // Get unique IDs for WHERE clause
260
+ const ids = records.map((r) => r[identifierColumn]);
261
+ const idPlaceholders = ids.map(() => this.nextPlaceholder(paramIndex++));
262
+ params.push(...ids);
263
+ const whereClause = `WHERE ${this.dialect.quoteIdentifier(identifierColumn)} IN (${idPlaceholders.join(', ')})`;
264
+ const sql = `UPDATE ${quotedTable} SET ${caseClauses.join(', ')} ${whereClause}`;
265
+ await this.dialect.query(sql, { raw: true, replacements: params });
266
+ }
267
+ /**
268
+ * Execute a single record update
269
+ */
270
+ async executeSingleUpdate(tableName, values, where, options) {
271
+ const { sql, values: queryValues } = this.dialect.buildUpdateQuery(tableName, values, where);
272
+ await this.dialect.query(sql, { raw: true, replacements: queryValues });
273
+ }
274
+ /**
275
+ * Optimize batch delete
276
+ * @param tableName - Name of the table to delete from
277
+ * @param identifiers - Array of identifiers for records to delete
278
+ * @param identifierColumn - Column to use for identifying records
279
+ * @param options - Batch options
280
+ */
281
+ async optimizeBatchDelete(tableName, identifiers, identifierColumn = 'id', options) {
282
+ const opts = { ...this.defaultOptions, ...options };
283
+ const startTime = Date.now();
284
+ if (identifiers.length === 0) {
285
+ return {
286
+ success: [],
287
+ failed: [],
288
+ total: 0,
289
+ chunkSize: opts.chunkSize,
290
+ batches: 0,
291
+ duration: 0,
292
+ };
293
+ }
294
+ const success = [];
295
+ const failed = [];
296
+ const chunks = this.chunkArray(identifiers, opts.chunkSize);
297
+ const totalBatches = Math.ceil(identifiers.length / opts.chunkSize);
298
+ for (let batchIndex = 0; batchIndex < chunks.length; batchIndex++) {
299
+ const chunk = chunks[batchIndex];
300
+ try {
301
+ await this.executeBatchDelete(tableName, chunk, identifierColumn);
302
+ success.push(...chunk);
303
+ this.logProgress(opts, {
304
+ total: identifiers.length,
305
+ processed: success.length + failed.length,
306
+ success: success.length,
307
+ failed: failed.length,
308
+ batchIndex,
309
+ totalBatches,
310
+ });
311
+ }
312
+ catch (error) {
313
+ if (opts.stopOnError) {
314
+ throw error;
315
+ }
316
+ // Fall back to individual deletes
317
+ for (const id of chunk) {
318
+ try {
319
+ await this.executeSingleDelete(tableName, { [identifierColumn]: id });
320
+ success.push(id);
321
+ }
322
+ catch (individualError) {
323
+ failed.push({ record: id, error: individualError });
324
+ }
325
+ }
326
+ this.logProgress(opts, {
327
+ total: identifiers.length,
328
+ processed: success.length + failed.length,
329
+ success: success.length,
330
+ failed: failed.length,
331
+ batchIndex,
332
+ totalBatches,
333
+ });
334
+ }
335
+ }
336
+ return {
337
+ success,
338
+ failed,
339
+ total: identifiers.length,
340
+ chunkSize: opts.chunkSize,
341
+ batches: totalBatches,
342
+ duration: Date.now() - startTime,
343
+ };
344
+ }
345
+ /**
346
+ * Execute batch delete using IN clause
347
+ * Uses bound parameters with dialect-correct placeholders instead of
348
+ * interpolating escaped literals directly into the SQL string.
349
+ */
350
+ async executeBatchDelete(tableName, identifiers, identifierColumn) {
351
+ if (identifiers.length === 0)
352
+ return;
353
+ const quotedTable = this.dialect.quoteTable(tableName);
354
+ let paramIndex = 1;
355
+ const placeholders = identifiers.map(() => this.nextPlaceholder(paramIndex++));
356
+ const whereClause = `WHERE ${this.dialect.quoteIdentifier(identifierColumn)} IN (${placeholders.join(', ')})`;
357
+ const sql = `DELETE FROM ${quotedTable} ${whereClause}`;
358
+ await this.dialect.query(sql, { raw: true, replacements: identifiers });
359
+ }
360
+ /**
361
+ * Execute a single record delete
362
+ */
363
+ async executeSingleDelete(tableName, where) {
364
+ const { sql, values } = this.dialect.buildDeleteQuery(tableName, where);
365
+ await this.dialect.query(sql, { raw: true, replacements: values });
366
+ }
367
+ /**
368
+ * Check if error is a duplicate key error
369
+ */
370
+ isDuplicateKeyError(error) {
371
+ const errorMessage = error?.message?.toLowerCase() || '';
372
+ return (errorMessage.includes('duplicate') ||
373
+ errorMessage.includes('unique constraint') ||
374
+ errorMessage.includes('unique key'));
375
+ }
376
+ /**
377
+ * Chunk an array into smaller arrays
378
+ */
379
+ chunkArray(array, size) {
380
+ const chunks = [];
381
+ for (let i = 0; i < array.length; i += size) {
382
+ chunks.push(array.slice(i, i + size));
383
+ }
384
+ return chunks;
385
+ }
386
+ /**
387
+ * Log progress
388
+ */
389
+ logProgress(options, progress) {
390
+ if (options.logging) {
391
+ const percent = Math.round((progress.processed / progress.total) * 100);
392
+ options.logging(`Batch progress: ${progress.processed}/${progress.total} (${percent}%)`);
393
+ }
394
+ if (options.onProgress) {
395
+ options.onProgress(progress);
396
+ }
397
+ }
398
+ }
399
+ exports.BatchQueryOptimizer = BatchQueryOptimizer;
400
+ /**
401
+ * Optimize a batch insert operation
402
+ */
403
+ async function optimizeBatchInsert(dialect, tableName, records, options) {
404
+ const optimizer = new BatchQueryOptimizer(dialect, options);
405
+ return optimizer.optimizeBatchInsert(tableName, records, options);
406
+ }
407
+ /**
408
+ * Optimize a batch update operation
409
+ */
410
+ async function optimizeBatchUpdate(dialect, tableName, records, identifierColumn, options) {
411
+ const optimizer = new BatchQueryOptimizer(dialect, options);
412
+ return optimizer.optimizeBatchUpdate(tableName, records, identifierColumn, options);
413
+ }
414
+ /**
415
+ * Optimize a batch delete operation
416
+ */
417
+ async function optimizeBatchDelete(dialect, tableName, identifiers, identifierColumn, options) {
418
+ const optimizer = new BatchQueryOptimizer(dialect, options);
419
+ return optimizer.optimizeBatchDelete(tableName, identifiers, identifierColumn, options);
420
+ }
421
+ exports.default = {
422
+ BatchQueryOptimizer,
423
+ optimizeBatchInsert,
424
+ optimizeBatchUpdate,
425
+ optimizeBatchDelete,
426
+ };