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,503 @@
1
+ "use strict";
2
+ /**
3
+ * Typed CASE WHEN ... THEN ... ELSE ... END expression builder.
4
+ *
5
+ * `CASE WHEN` is ANSI-standard SQL (SQL-92) and is supported identically,
6
+ * with no syntax variation, across every dialect this ORM targets:
7
+ * - mysql, mariadb: full support (searched + simple CASE)
8
+ * - postgres, cockroachdb, redshift: full support (Postgres-derived)
9
+ * - mssql: full support (T-SQL CASE is ANSI-compliant)
10
+ * - oracle: full support (in addition to the older DECODE() function,
11
+ * Oracle has supported standard CASE since 9i)
12
+ * - sqlite: full support
13
+ * - db2: full support
14
+ * - snowflake: full support
15
+ * - clickhouse: full support, including both the "searched" form
16
+ * (`CASE WHEN cond THEN a END`) and the "simple" form
17
+ * (`CASE expr WHEN val THEN a END`). ClickHouse also offers the
18
+ * `multiIf()`/`if()` functions as engine-native alternatives, but plain
19
+ * `CASE` works exactly as ANSI SQL specifies, so no dialect branching is
20
+ * required here (unlike window frame extensions or JSON path functions).
21
+ *
22
+ * This module is intentionally self-contained: it does not add any new
23
+ * dispatch branches to the shared SQL compiler (`src/query-builders/sql-compiler.ts`)
24
+ * or to `src/operators.ts`. Every builder resolves directly to a final SQL
25
+ * fragment string, which is then wrapped with the existing `literalExpr()`
26
+ * helper from `src/operators.ts` so it slots into `attributes: [...]` arrays
27
+ * exactly the way `fn()`/`col()`/`cast()`/the window-function builder do
28
+ * today (see `attributeToSql()` in `sql-compiler.ts`, which already knows
29
+ * how to render `{ __type: 'literal', sql }` and `[expr, alias]` tuples).
30
+ *
31
+ * Condition syntax: `.when()` on the searched-CASE builder (`caseWhen()`)
32
+ * accepts the SAME condition-object shape already used by `where:` clauses
33
+ * throughout this ORM (see `src/operators.ts`'s `Op` symbols and
34
+ * `src/query-builders/where-builder.ts`), e.g.:
35
+ *
36
+ * { age: { [Op.gte]: 18 } }
37
+ * { [Op.and]: [{ age: { [Op.gte]: 18 } }, { status: 'active' }] }
38
+ * { [Op.between]: [...] } // via a field key, see below
39
+ *
40
+ * rather than inventing a new mini-language. This keeps `caseWhen().when(...)`
41
+ * consistent with `Model.findAll({ where: ... })` conditions. A shorthand
42
+ * 3-arg form, `.when(column, operator, value, thenValue)`, is also supported
43
+ * for ergonomic simple comparisons (mirroring `Op.where(col, op, value)`).
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * import { caseWhen, caseOf } from './query-builders/functions/conditional';
48
+ * import { Op, col } from '../../operators';
49
+ *
50
+ * // Searched CASE (condition-object form, same shape as `where:`)
51
+ * User.findAll({
52
+ * attributes: [
53
+ * 'name',
54
+ * caseWhen()
55
+ * .when({ age: { [Op.gte]: 18 } }, 'adult')
56
+ * .when({ age: { [Op.gte]: 13 } }, 'teen')
57
+ * .else('child')
58
+ * .as('ageGroup'),
59
+ * ],
60
+ * });
61
+ *
62
+ * // Searched CASE (3-arg shorthand form)
63
+ * caseWhen().when('age', '>=', 18, 'adult').else('minor').as('ageGroup');
64
+ *
65
+ * // Simple CASE (CASE expr WHEN val THEN result ... END)
66
+ * caseOf(col('status'))
67
+ * .when('active', 1)
68
+ * .when('inactive', 0)
69
+ * .else(null)
70
+ * .as('statusFlag');
71
+ *
72
+ * // Nested CASE
73
+ * caseWhen()
74
+ * .when({ age: { [Op.gte]: 65 } }, 'senior')
75
+ * .else(caseWhen().when({ age: { [Op.gte]: 18 } }, 'adult').else('minor'))
76
+ * .as('category');
77
+ * ```
78
+ */
79
+ Object.defineProperty(exports, "__esModule", { value: true });
80
+ exports.SimpleCaseBuilder = exports.CaseBuilder = void 0;
81
+ exports.caseWhen = caseWhen;
82
+ exports.caseOf = caseOf;
83
+ const operators_1 = require("../../operators");
84
+ function escapeIdentifier(name) {
85
+ if (name.includes('.')) {
86
+ return name
87
+ .split('.')
88
+ .map((part) => `"${part.replace(/"/g, '""')}"`)
89
+ .join('.');
90
+ }
91
+ return `"${name.replace(/"/g, '""')}"`;
92
+ }
93
+ function escapeStringLiteral(value) {
94
+ return `'${value.replace(/'/g, "''")}'`;
95
+ }
96
+ /**
97
+ * Render a THEN/ELSE/simple-CASE value into a SQL fragment. Distinguishes
98
+ * plain value literals (strings get quoted/escaped, numbers/booleans are
99
+ * inlined, `null` becomes SQL NULL) from typed expressions (`col()`, `fn()`,
100
+ * `literal()`) and from nested CASE builders, which get rendered recursively.
101
+ */
102
+ function toSqlFragment(value) {
103
+ if (value === null)
104
+ return 'NULL';
105
+ if (value instanceof CaseBuilder || value instanceof SimpleCaseBuilder) {
106
+ return value.toSQL();
107
+ }
108
+ if (typeof value === 'number') {
109
+ return String(value);
110
+ }
111
+ if (typeof value === 'boolean') {
112
+ return value ? 'TRUE' : 'FALSE';
113
+ }
114
+ if (typeof value === 'string') {
115
+ return escapeStringLiteral(value);
116
+ }
117
+ if ((0, operators_1.isFnExpression)(value)) {
118
+ const args = value.args.map((a) => toSqlFragment(a)).join(', ');
119
+ return `${value.fn}(${args})`;
120
+ }
121
+ if ((0, operators_1.isColExpression)(value)) {
122
+ return escapeIdentifier(value.col);
123
+ }
124
+ if ((0, operators_1.isLiteralExpression)(value)) {
125
+ return value.sql ?? value.$literal;
126
+ }
127
+ if ((0, operators_1.isColumnReference)(value)) {
128
+ return escapeIdentifier(value.$col);
129
+ }
130
+ // Fallback: stringify.
131
+ return String(value);
132
+ }
133
+ /**
134
+ * Render a "condition target" — i.e. an argument that is either a plain
135
+ * value or a column reference — used when comparing a field to a value
136
+ * inside a condition operator (e.g. the right-hand side of `$gt`, or the
137
+ * two ends of a `$between`). Reuses `toSqlFragment` since the value shapes
138
+ * (`$col`, `$literal`, plain values) are the same.
139
+ */
140
+ function toComparisonSql(value) {
141
+ return toSqlFragment(value);
142
+ }
143
+ /**
144
+ * Compile a `where:`-shaped condition object into a raw (inline, non-
145
+ * parameterized) SQL boolean expression. This is a small, self-contained
146
+ * subset of the logic in `src/query-builders/where-builder.ts`'s
147
+ * `WhereBuilder`, adapted to produce inline SQL (values are escaped
148
+ * directly into the string) rather than `?` placeholders + a values array,
149
+ * since CASE expressions are embedded as raw SQL literals via
150
+ * `literalExpr()` rather than run through the parameterized query pipeline.
151
+ *
152
+ * Reuses `operatorToWhereKey()` and `isColumnReference()` from
153
+ * `src/operators.ts` (both already exported) instead of re-implementing the
154
+ * Symbol -> `$op` string mapping.
155
+ */
156
+ function compileCondition(condition) {
157
+ if (condition === null || condition === undefined) {
158
+ return '1=1';
159
+ }
160
+ if (typeof condition !== 'object') {
161
+ // A bare scalar condition doesn't make sense without a field; treat as
162
+ // a raw truthy/falsy literal for robustness.
163
+ return condition ? '1=1' : '1=0';
164
+ }
165
+ const cond = condition;
166
+ // Symbol-based Op.and / Op.or / Op.not
167
+ const symbolKeys = Object.getOwnPropertySymbols(cond);
168
+ for (const sym of symbolKeys) {
169
+ if (sym === operators_1.Op.and) {
170
+ const parts = cond[sym].map((c) => `(${compileCondition(c)})`);
171
+ return parts.join(' AND ');
172
+ }
173
+ if (sym === operators_1.Op.or) {
174
+ const parts = cond[sym].map((c) => `(${compileCondition(c)})`);
175
+ return parts.join(' OR ');
176
+ }
177
+ if (sym === operators_1.Op.not) {
178
+ return `NOT (${compileCondition(cond[sym])})`;
179
+ }
180
+ }
181
+ // String-based $and / $or / $not (same convention as WhereBuilder)
182
+ if ('$and' in cond) {
183
+ const parts = cond.$and.map((c) => `(${compileCondition(c)})`);
184
+ return parts.join(' AND ');
185
+ }
186
+ if ('$or' in cond) {
187
+ const parts = cond.$or.map((c) => `(${compileCondition(c)})`);
188
+ return parts.join(' OR ');
189
+ }
190
+ if ('$not' in cond) {
191
+ return `NOT (${compileCondition(cond.$not)})`;
192
+ }
193
+ // $where: { $col, $op: value } explicit column-reference condition
194
+ if ('$where' in cond) {
195
+ const whereClause = cond.$where;
196
+ const fieldSql = escapeIdentifier(whereClause.$col);
197
+ const opEntries = Object.entries(whereClause).filter(([k]) => k !== '$col');
198
+ const parts = opEntries.map(([opKey, val]) => compileFieldOperator(fieldSql, opKey, val));
199
+ return parts.join(' AND ') || fieldSql;
200
+ }
201
+ // Plain field conditions: { field: value } or { field: { [Op.x]: value } }
202
+ const fieldConditions = [];
203
+ for (const [field, value] of Object.entries(cond)) {
204
+ const fieldSql = escapeIdentifier(field);
205
+ if (value === null || value === undefined) {
206
+ fieldConditions.push(`${fieldSql} IS NULL`);
207
+ }
208
+ else if (typeof value === 'object' && !Array.isArray(value)) {
209
+ // Could contain Symbol operator keys (Op.gt, etc.) or string $op keys.
210
+ const opSymbolKeys = Object.getOwnPropertySymbols(value);
211
+ let handled = false;
212
+ for (const sym of opSymbolKeys) {
213
+ const opKey = (0, operators_1.operatorToWhereKey)(sym);
214
+ fieldConditions.push(compileFieldOperator(fieldSql, opKey, value[sym]));
215
+ handled = true;
216
+ }
217
+ for (const [opKey, opVal] of Object.entries(value)) {
218
+ fieldConditions.push(compileFieldOperator(fieldSql, opKey, opVal));
219
+ handled = true;
220
+ }
221
+ if (!handled) {
222
+ fieldConditions.push(`${fieldSql} IS NULL`);
223
+ }
224
+ }
225
+ else {
226
+ fieldConditions.push(`${fieldSql} = ${toComparisonSql(value)}`);
227
+ }
228
+ }
229
+ return fieldConditions.join(' AND ');
230
+ }
231
+ /**
232
+ * Compile a single `$op: value` pair (e.g. `$gt`, `$between`, `$isNull`)
233
+ * into a raw SQL fragment for the given already-escaped field SQL.
234
+ */
235
+ function compileFieldOperator(fieldSql, opKey, value) {
236
+ switch (opKey) {
237
+ case '$eq':
238
+ return `${fieldSql} = ${toComparisonSql(value)}`;
239
+ case '$ne':
240
+ return `${fieldSql} != ${toComparisonSql(value)}`;
241
+ case '$gt':
242
+ return `${fieldSql} > ${toComparisonSql(value)}`;
243
+ case '$gte':
244
+ return `${fieldSql} >= ${toComparisonSql(value)}`;
245
+ case '$lt':
246
+ return `${fieldSql} < ${toComparisonSql(value)}`;
247
+ case '$lte':
248
+ return `${fieldSql} <= ${toComparisonSql(value)}`;
249
+ case '$like':
250
+ return `${fieldSql} LIKE ${toComparisonSql(value)}`;
251
+ case '$notLike':
252
+ return `${fieldSql} NOT LIKE ${toComparisonSql(value)}`;
253
+ case '$iLike':
254
+ return `${fieldSql} ILIKE ${toComparisonSql(value)}`;
255
+ case '$notILike':
256
+ return `${fieldSql} NOT ILIKE ${toComparisonSql(value)}`;
257
+ case '$col':
258
+ return `${fieldSql} = ${escapeIdentifier(String(value))}`;
259
+ case '$in': {
260
+ const values = Array.isArray(value) ? value : [];
261
+ if (values.length === 0)
262
+ return '1=0';
263
+ return `${fieldSql} IN (${values.map((v) => toComparisonSql(v)).join(', ')})`;
264
+ }
265
+ case '$notIn': {
266
+ const values = Array.isArray(value) ? value : [];
267
+ if (values.length === 0)
268
+ return '1=1';
269
+ return `${fieldSql} NOT IN (${values.map((v) => toComparisonSql(v)).join(', ')})`;
270
+ }
271
+ case '$between': {
272
+ const [start, end] = value;
273
+ return `${fieldSql} BETWEEN ${toComparisonSql(start)} AND ${toComparisonSql(end)}`;
274
+ }
275
+ case '$notBetween': {
276
+ const [start, end] = value;
277
+ return `${fieldSql} NOT BETWEEN ${toComparisonSql(start)} AND ${toComparisonSql(end)}`;
278
+ }
279
+ case '$isNull':
280
+ return value ? `${fieldSql} IS NULL` : `${fieldSql} IS NOT NULL`;
281
+ case '$isNotNull':
282
+ return value ? `${fieldSql} IS NOT NULL` : `${fieldSql} IS NULL`;
283
+ case '$regexp':
284
+ return `${fieldSql} REGEXP ${toComparisonSql(value)}`;
285
+ case '$notRegexp':
286
+ return `${fieldSql} NOT REGEXP ${toComparisonSql(value)}`;
287
+ case '$startsWith':
288
+ return `${fieldSql} LIKE ${escapeStringLiteral(`${value}%`)}`;
289
+ case '$notStartsWith':
290
+ return `${fieldSql} NOT LIKE ${escapeStringLiteral(`${value}%`)}`;
291
+ case '$endsWith':
292
+ return `${fieldSql} LIKE ${escapeStringLiteral(`%${value}`)}`;
293
+ case '$notEndsWith':
294
+ return `${fieldSql} NOT LIKE ${escapeStringLiteral(`%${value}`)}`;
295
+ case '$substring':
296
+ return `${fieldSql} LIKE ${escapeStringLiteral(`%${value}%`)}`;
297
+ case '$notSubstring':
298
+ return `${fieldSql} NOT LIKE ${escapeStringLiteral(`%${value}%`)}`;
299
+ default:
300
+ // Unknown operator: fall back to equality against the raw value to
301
+ // avoid silently dropping the condition.
302
+ return `${fieldSql} = ${toComparisonSql(value)}`;
303
+ }
304
+ }
305
+ /**
306
+ * Map a string comparison operator (e.g. `'>='`, `'!='`) or an `Op.*`
307
+ * Symbol to the `$op` key used internally, reusing `operatorToWhereKey()`
308
+ * for the Symbol case (same convention as `Op.where()`).
309
+ */
310
+ function normalizeOperator(operator) {
311
+ if (typeof operator === 'symbol') {
312
+ return (0, operators_1.operatorToWhereKey)(operator);
313
+ }
314
+ switch (operator) {
315
+ case '=':
316
+ case '==':
317
+ return '$eq';
318
+ case '!=':
319
+ case '<>':
320
+ return '$ne';
321
+ case '>':
322
+ return '$gt';
323
+ case '>=':
324
+ return '$gte';
325
+ case '<':
326
+ return '$lt';
327
+ case '<=':
328
+ return '$lte';
329
+ case 'like':
330
+ return '$like';
331
+ case 'not like':
332
+ case 'not_like':
333
+ return '$notLike';
334
+ case 'in':
335
+ return '$in';
336
+ case 'not in':
337
+ case 'not_in':
338
+ return '$notIn';
339
+ case 'between':
340
+ return '$between';
341
+ case 'not between':
342
+ case 'not_between':
343
+ return '$notBetween';
344
+ case 'is null':
345
+ case 'is_null':
346
+ return '$isNull';
347
+ case 'is not null':
348
+ case 'is_not_null':
349
+ return '$isNotNull';
350
+ default:
351
+ return `$${operator}`;
352
+ }
353
+ }
354
+ /**
355
+ * Fluent builder for a "searched" CASE expression:
356
+ * CASE WHEN cond1 THEN result1 WHEN cond2 THEN result2 ... ELSE else END
357
+ *
358
+ * Build with `caseWhen()`. Terminate with `.as(alias)` (for use directly in
359
+ * an `attributes: [...]` array) or `.toSQL()` / `.toLiteral()`.
360
+ */
361
+ class CaseBuilder {
362
+ constructor() {
363
+ this.clauses = [];
364
+ this.hasElse = false;
365
+ }
366
+ when(conditionOrColumn, thenValueOrOperator, value, thenValue) {
367
+ // 4-arg shorthand form: .when(column, operator, value, thenValue)
368
+ if (typeof conditionOrColumn === 'string' && arguments.length >= 4) {
369
+ const opKey = normalizeOperator(thenValueOrOperator);
370
+ const fieldSql = escapeIdentifier(conditionOrColumn);
371
+ const conditionSql = compileFieldOperator(fieldSql, opKey, value);
372
+ this.clauses.push({ conditionSql, resultSql: toSqlFragment(thenValue) });
373
+ return this;
374
+ }
375
+ // 2-arg condition-object form: .when(condition, thenValue)
376
+ const conditionSql = compileCondition(conditionOrColumn);
377
+ this.clauses.push({
378
+ conditionSql,
379
+ resultSql: toSqlFragment(thenValueOrOperator),
380
+ });
381
+ return this;
382
+ }
383
+ /** Set the `ELSE <value>` branch. Optional — omitting it yields an implicit SQL NULL. */
384
+ else(value) {
385
+ this.elseSql = toSqlFragment(value);
386
+ this.hasElse = true;
387
+ return this;
388
+ }
389
+ /** Render the `CASE WHEN ... END` SQL fragment (no alias). */
390
+ toSQL() {
391
+ if (this.clauses.length === 0) {
392
+ throw new Error('caseWhen() requires at least one .when(condition, thenValue) branch');
393
+ }
394
+ const whenParts = this.clauses
395
+ .map((c) => `WHEN ${c.conditionSql} THEN ${c.resultSql}`)
396
+ .join(' ');
397
+ const elsePart = this.hasElse ? ` ELSE ${this.elseSql}` : '';
398
+ return `CASE ${whenParts}${elsePart} END`;
399
+ }
400
+ /**
401
+ * Terminal call: returns an `[expr, alias]` tuple compatible with the
402
+ * existing `attributes: [...]` pattern (see `attributeToSql()` in
403
+ * `sql-compiler.ts`, which already knows how to render
404
+ * `[LiteralExpression, alias]` tuples without any core changes).
405
+ */
406
+ as(alias) {
407
+ return [(0, operators_1.literalExpr)(this.toSQL()), alias];
408
+ }
409
+ /** Use the builder directly wherever a raw SQL literal expression is expected. */
410
+ toLiteral() {
411
+ return (0, operators_1.literalExpr)(this.toSQL());
412
+ }
413
+ }
414
+ exports.CaseBuilder = CaseBuilder;
415
+ /**
416
+ * Fluent builder for a "simple" CASE expression:
417
+ * CASE expr WHEN val1 THEN result1 WHEN val2 THEN result2 ... ELSE else END
418
+ *
419
+ * Build with `caseOf(expr)`. Terminate with `.as(alias)` or `.toSQL()` /
420
+ * `.toLiteral()`.
421
+ */
422
+ class SimpleCaseBuilder {
423
+ constructor(expr) {
424
+ this.clauses = [];
425
+ this.hasElse = false;
426
+ // `expr` is typically a column reference (string column name, col(), or
427
+ // any other CaseValue-compatible expression).
428
+ this.exprSql =
429
+ typeof expr === 'string' ? escapeIdentifier(expr) : toSqlFragment(expr);
430
+ }
431
+ /**
432
+ * Add a `WHEN <value> THEN <result>` branch. Repeatable — call multiple
433
+ * times to add multiple branches, evaluated in order.
434
+ */
435
+ when(value, result) {
436
+ this.clauses.push({ valueSql: toSqlFragment(value), resultSql: toSqlFragment(result) });
437
+ return this;
438
+ }
439
+ /** Set the `ELSE <value>` branch. Optional — omitting it yields an implicit SQL NULL. */
440
+ else(value) {
441
+ this.elseSql = toSqlFragment(value);
442
+ this.hasElse = true;
443
+ return this;
444
+ }
445
+ /** Render the `CASE expr WHEN ... END` SQL fragment (no alias). */
446
+ toSQL() {
447
+ if (this.clauses.length === 0) {
448
+ throw new Error('caseOf() requires at least one .when(value, result) branch');
449
+ }
450
+ const whenParts = this.clauses
451
+ .map((c) => `WHEN ${c.valueSql} THEN ${c.resultSql}`)
452
+ .join(' ');
453
+ const elsePart = this.hasElse ? ` ELSE ${this.elseSql}` : '';
454
+ return `CASE ${this.exprSql} ${whenParts}${elsePart} END`;
455
+ }
456
+ /**
457
+ * Terminal call: returns an `[expr, alias]` tuple compatible with the
458
+ * existing `attributes: [...]` pattern.
459
+ */
460
+ as(alias) {
461
+ return [(0, operators_1.literalExpr)(this.toSQL()), alias];
462
+ }
463
+ /** Use the builder directly wherever a raw SQL literal expression is expected. */
464
+ toLiteral() {
465
+ return (0, operators_1.literalExpr)(this.toSQL());
466
+ }
467
+ }
468
+ exports.SimpleCaseBuilder = SimpleCaseBuilder;
469
+ /**
470
+ * Start a "searched" CASE expression:
471
+ * CASE WHEN cond1 THEN result1 [WHEN cond2 THEN result2 ...] [ELSE else] END
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * caseWhen()
476
+ * .when({ age: { [Op.gte]: 18 } }, 'adult')
477
+ * .else('minor')
478
+ * .as('ageGroup')
479
+ * ```
480
+ */
481
+ function caseWhen() {
482
+ return new CaseBuilder();
483
+ }
484
+ /**
485
+ * Start a "simple" CASE expression:
486
+ * CASE expr WHEN val1 THEN result1 [WHEN val2 THEN result2 ...] [ELSE else] END
487
+ *
488
+ * @param expr - The expression being compared. A plain string is treated as
489
+ * a column name (identifier-escaped); pass `col('name')`, `fn(...)`, or
490
+ * `literal(...)` for other expression types.
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * caseOf('status')
495
+ * .when('active', 1)
496
+ * .when('inactive', 0)
497
+ * .else(null)
498
+ * .as('statusFlag')
499
+ * ```
500
+ */
501
+ function caseOf(expr) {
502
+ return new SimpleCaseBuilder(expr);
503
+ }