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,439 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Typed, cross-dialect full-text-SEARCH-QUERY API.
|
|
4
|
+
*
|
|
5
|
+
* Several dialect drivers in this ORM already expose native FULLTEXT
|
|
6
|
+
* *index creation* helpers (grep `createFulltextIndex` in
|
|
7
|
+
* `src/dialects/*/index.ts`: mysql, mariadb, postgres, cockroachdb, mssql,
|
|
8
|
+
* oracle, sqlite, clickhouse all have one; db2/redshift throw a documented
|
|
9
|
+
* "not supported" error; snowflake is a documented no-op). What has been
|
|
10
|
+
* missing is a typed helper for the *query* side — the actual
|
|
11
|
+
* `MATCH() AGAINST()` / `@@ plainto_tsquery()` / `CONTAINS()` / `MATCH`
|
|
12
|
+
* predicate that goes in a `WHERE` (or `ORDER BY`, for relevance ranking).
|
|
13
|
+
* This module fills that gap.
|
|
14
|
+
*
|
|
15
|
+
* This module is intentionally self-contained: it does not add any new
|
|
16
|
+
* dispatch branches to `src/operators.ts`, `src/query-builders/sql-compiler.ts`,
|
|
17
|
+
* or any `src/dialects/**` file. Every function resolves directly to a final,
|
|
18
|
+
* dialect-correct SQL fragment string, which is then wrapped with the
|
|
19
|
+
* existing `literal()` helper from `src/operators.ts` (returns `{ $literal: sql }`,
|
|
20
|
+
* the same shape produced by `Op.literal(...)` and consumed throughout the
|
|
21
|
+
* where-builder/sql-compiler for raw-SQL escape hatches).
|
|
22
|
+
*
|
|
23
|
+
* IMPORTANT — verified limitation of the current WHERE-clause builder
|
|
24
|
+
* ---------------------------------------------------------------------
|
|
25
|
+
* `literal()`/`{ $literal }` is fully supported (and the recommended,
|
|
26
|
+
* documented way to inject raw SQL) when it is used as the *value* of a
|
|
27
|
+
* field/operator, e.g.:
|
|
28
|
+
* `where: { createdAt: { [Op.lt]: literal('NOW()') } }`
|
|
29
|
+
* However, at the time this module was written, `WhereBuilder`
|
|
30
|
+
* (`src/query-builders/where-builder.ts`) and the per-dialect
|
|
31
|
+
* `buildWhereClause()` implementations only support `{ $literal }` as an
|
|
32
|
+
* *operator value*; they do not currently accept a bare `{ $literal }` (or a
|
|
33
|
+
* plain raw-SQL string) as an entire standalone condition — whether at the
|
|
34
|
+
* top level of `where`, or nested inside `$and`/`Op.and`/`$or`/`Op.or`
|
|
35
|
+
* arrays. This was verified empirically: such conditions are silently
|
|
36
|
+
* dropped rather than raising an error (a pre-existing gap in the shared
|
|
37
|
+
* where-builder, not something this module can fix without editing that
|
|
38
|
+
* file, which is out of scope here).
|
|
39
|
+
*
|
|
40
|
+
* Because of that, the SQL fragments produced by `fullTextMatch()` /
|
|
41
|
+
* `fullTextRank()` are safe and correct to use:
|
|
42
|
+
* - directly in hand-built / raw SQL (`prorm.query(...)`), by reading
|
|
43
|
+
* `.$literal` off the returned value,
|
|
44
|
+
* - in `attributes: [...]` (SELECT) and `order: [...]` (ORDER BY) arrays,
|
|
45
|
+
* both of which DO correctly render raw literal SQL fragments today
|
|
46
|
+
* (verified against `sql-compiler.ts`'s `processAttributeValue()` and
|
|
47
|
+
* `order-limit-builder.ts`'s `buildOrderItem()`, which passes through
|
|
48
|
+
* plain strings/literal SQL unchanged).
|
|
49
|
+
* They are returned in the canonical `{ $literal: sql }` shape (rather than
|
|
50
|
+
* a bare string) so that call sites which build `where` conditions through
|
|
51
|
+
* `Op`-based helpers remain forward-compatible: if/when the WHERE-clause gap
|
|
52
|
+
* above is fixed, code using this module keeps working with no changes.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { fullTextMatch, fullTextRank } from './query-builders/functions/fulltext';
|
|
57
|
+
*
|
|
58
|
+
* const match = fullTextMatch('mysql', ['title', 'body'], 'red widgets');
|
|
59
|
+
* // match.$literal === "MATCH(`title`, `body`) AGAINST('red widgets' IN NATURAL LANGUAGE MODE)"
|
|
60
|
+
*
|
|
61
|
+
* // Use for scoring/ordering (works today via ORDER BY / attributes):
|
|
62
|
+
* const rank = fullTextRank('postgres', 'body', 'red widgets');
|
|
63
|
+
* Article.findAll({
|
|
64
|
+
* attributes: ['id', 'title', [rank, 'relevance']],
|
|
65
|
+
* order: [[rank.$literal, 'DESC']],
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // Use directly in a raw query for WHERE (recommended today):
|
|
69
|
+
* await prorm.query(
|
|
70
|
+
* `SELECT * FROM articles WHERE ${match.$literal}`
|
|
71
|
+
* );
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
75
|
+
exports.FullTextSearchMode = void 0;
|
|
76
|
+
exports.fullTextMatch = fullTextMatch;
|
|
77
|
+
exports.fullTextRank = fullTextRank;
|
|
78
|
+
const operators_1 = require("../../operators");
|
|
79
|
+
/**
|
|
80
|
+
* Companion enum for `FullTextMatchMode`. Provided for callers who prefer a
|
|
81
|
+
* typed enum over hand-written string literals (e.g. `FullTextSearchMode.Boolean`
|
|
82
|
+
* instead of `'boolean'`). The two are interchangeable: `FullTextSearchMode`'s
|
|
83
|
+
* members are assignable to `FullTextMatchMode` (and vice versa, since the
|
|
84
|
+
* enum is string-valued), and `FullTextMatchOptions.mode` accepts either.
|
|
85
|
+
* This is purely additive — no existing string-literal call sites need to
|
|
86
|
+
* change.
|
|
87
|
+
*/
|
|
88
|
+
var FullTextSearchMode;
|
|
89
|
+
(function (FullTextSearchMode) {
|
|
90
|
+
FullTextSearchMode["Natural"] = "natural";
|
|
91
|
+
FullTextSearchMode["Boolean"] = "boolean";
|
|
92
|
+
FullTextSearchMode["Phrase"] = "phrase";
|
|
93
|
+
})(FullTextSearchMode || (exports.FullTextSearchMode = FullTextSearchMode = {}));
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Local helpers (self-contained — do not import dialect escaping utilities)
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
function toColumnArray(columns) {
|
|
98
|
+
return Array.isArray(columns) ? columns : [columns];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Convert a column-reference argument to a dialect-appropriately-quoted SQL
|
|
102
|
+
* identifier fragment. Kept local/minimal (mirrors the quoting conventions
|
|
103
|
+
* already used by each dialect's own `escapeId`), since this module must not
|
|
104
|
+
* import from `src/dialects/**`.
|
|
105
|
+
*/
|
|
106
|
+
function toSqlFragment(dialect, columnName) {
|
|
107
|
+
const quote = (part) => {
|
|
108
|
+
switch (dialect) {
|
|
109
|
+
case 'mysql':
|
|
110
|
+
case 'mariadb':
|
|
111
|
+
return `\`${part.replace(/`/g, '``')}\``;
|
|
112
|
+
case 'mssql':
|
|
113
|
+
return `[${part.replace(/]/g, ']]')}]`;
|
|
114
|
+
default:
|
|
115
|
+
// postgres, cockroachdb, sqlite, oracle, db2, snowflake, redshift, clickhouse
|
|
116
|
+
return `"${part.replace(/"/g, '""')}"`;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
return columnName
|
|
120
|
+
.split('.')
|
|
121
|
+
.map((part) => quote(part))
|
|
122
|
+
.join('.');
|
|
123
|
+
}
|
|
124
|
+
/** Escape a plain string for embedding as a single-quoted SQL string literal. */
|
|
125
|
+
function escapeStringLiteral(value) {
|
|
126
|
+
return value.replace(/'/g, "''");
|
|
127
|
+
}
|
|
128
|
+
/** Splits on whitespace, ignoring surrounding whitespace, to detect multi-word search terms. */
|
|
129
|
+
function isMultiWord(term) {
|
|
130
|
+
return term.trim().split(/\s+/).filter(Boolean).length > 1;
|
|
131
|
+
}
|
|
132
|
+
function quotedColumnList(dialect, columns) {
|
|
133
|
+
return columns.map((c) => toSqlFragment(dialect, c)).join(', ');
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// fullTextMatch
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
/**
|
|
139
|
+
* Build a dialect-correct full-text-search WHERE-predicate SQL fragment.
|
|
140
|
+
*
|
|
141
|
+
* Returns `{ $literal: sql }` (see module header for the supported/verified
|
|
142
|
+
* usage patterns for this shape).
|
|
143
|
+
*
|
|
144
|
+
* Per-dialect behavior:
|
|
145
|
+
* - mysql/mariadb: `MATCH(col1, col2) AGAINST('term' IN NATURAL LANGUAGE MODE | IN BOOLEAN MODE)`.
|
|
146
|
+
* `mode: 'phrase'` uses boolean mode with the term wrapped in `"..."` for
|
|
147
|
+
* an exact-phrase match (MySQL boolean-mode phrase syntax).
|
|
148
|
+
* NOTE: requires a `FULLTEXT` index on the given column(s) — see
|
|
149
|
+
* `createFulltextIndex()` in `src/dialects/mysql/index.ts` / `mariadb/index.ts`.
|
|
150
|
+
* - postgres/cockroachdb: `to_tsvector('english', col1 || ' ' || col2) @@ plainto_tsquery('english', 'term')`.
|
|
151
|
+
* `mode: 'phrase'` uses `websearch_to_tsquery` instead of `plainto_tsquery`
|
|
152
|
+
* for more natural, phrase-aware parsing (supports quoted phrases, `-`,
|
|
153
|
+
* `OR`). NOTE: works on any text column; a GIN index
|
|
154
|
+
* (`createFulltextIndex()`) is only needed for performance, not correctness.
|
|
155
|
+
* - mssql: `mode: 'natural'` (default) uses `FREETEXT(col, 'term')`;
|
|
156
|
+
* `mode: 'boolean'` / `mode: 'phrase'` uses `CONTAINS(col, 'term')`
|
|
157
|
+
* (phrase mode wraps the term in `"..."`, which is exact-phrase syntax
|
|
158
|
+
* for `CONTAINS`). NOTE: requires a full-text index/catalog — see
|
|
159
|
+
* `createFulltextIndex()` in `src/dialects/mssql/index.ts`.
|
|
160
|
+
* - oracle: `CONTAINS(col, 'term', 1) > 0` (Oracle Text). Multiple columns
|
|
161
|
+
* are OR-ed together, since Oracle Text indexes and scores one column at
|
|
162
|
+
* a time. NOTE: requires an Oracle Text index — see `createFulltextIndex()`
|
|
163
|
+
* in `src/dialects/oracle/index.ts`.
|
|
164
|
+
* - sqlite: `col MATCH 'term'`. STRUCTURAL REQUIREMENT (unlike every other
|
|
165
|
+
* dialect above): this only works against an FTS5 virtual table/column
|
|
166
|
+
* (see `createFulltextIndex()` / `createFTS5Table()` in
|
|
167
|
+
* `src/dialects/sqlite/index.ts`) — SQLite has no secondary full-text
|
|
168
|
+
* index you can bolt onto an ordinary table the way MySQL/Postgres/MSSQL
|
|
169
|
+
* do; the table itself must be an `fts5` virtual table.
|
|
170
|
+
* - clickhouse: uses `hasToken(col, 'term')` for a single-token exact
|
|
171
|
+
* match, or `multiSearchAny(col, ['term1', 'term2', ...])` when
|
|
172
|
+
* `searchTerm` contains multiple whitespace-separated words. Multiple
|
|
173
|
+
* columns are OR-ed together. See `createFulltextIndex()` (ClickHouse
|
|
174
|
+
* `ngrambf_v1`/`tokenbf_v1` index) in `src/dialects/clickhouse/index.ts`.
|
|
175
|
+
* - db2: THROWS. Db2's optional Text Search feature (Net Search Extender)
|
|
176
|
+
* has its own `CONTAINS`-like predicate syntax, but it could not be
|
|
177
|
+
* verified with confidence here, and `createFulltextIndex()` in
|
|
178
|
+
* `src/dialects/db2/index.ts` itself throws
|
|
179
|
+
* "Fulltext indexes are not supported in Db2 LUW (requires Net Search
|
|
180
|
+
* Extender)" — so there is no verified index-creation path to pair a
|
|
181
|
+
* query against either. Throwing here rather than guessing avoids
|
|
182
|
+
* shipping silently-wrong SQL.
|
|
183
|
+
* - snowflake: FALLBACK, not true full-text search. Snowflake has no
|
|
184
|
+
* Postgres-style `tsvector`/`tsquery` full-text search primitive (its
|
|
185
|
+
* closest offerings are Cortex Search / Search Optimization Service,
|
|
186
|
+
* which are not plain-SQL predicates); `createFulltextIndex()` in
|
|
187
|
+
* `src/dialects/snowflake/index.ts` is a documented no-op for the same
|
|
188
|
+
* reason. Falls back to `ILIKE '%term%'` (case-insensitive substring
|
|
189
|
+
* match — no tokenization, stemming, or relevance ranking).
|
|
190
|
+
* - redshift: FALLBACK, not true full-text search. Redshift (unlike
|
|
191
|
+
* Postgres, which it forked from) does not implement `tsvector`/`tsquery`;
|
|
192
|
+
* `createFulltextIndex()` in `src/dialects/redshift/index.ts` throws
|
|
193
|
+
* accordingly. Falls back to `ILIKE '%term%'`, same caveat as Snowflake.
|
|
194
|
+
*
|
|
195
|
+
* @param dialect - Target SQL dialect.
|
|
196
|
+
* @param columns - Column name, or array of column names, to search.
|
|
197
|
+
* @param searchTerm - The user's search text.
|
|
198
|
+
* @param options - `{ mode, config }`, see `FullTextMatchOptions`.
|
|
199
|
+
*/
|
|
200
|
+
function fullTextMatch(dialect, columns, searchTerm, options) {
|
|
201
|
+
const cols = toColumnArray(columns);
|
|
202
|
+
const mode = options?.mode ?? 'natural';
|
|
203
|
+
const term = escapeStringLiteral(searchTerm);
|
|
204
|
+
switch (dialect) {
|
|
205
|
+
case 'mysql':
|
|
206
|
+
case 'mariadb':
|
|
207
|
+
// TiDB and SingleStore are MySQL-wire-compatible and implement the same
|
|
208
|
+
// MATCH(...) AGAINST(...) full-text syntax.
|
|
209
|
+
case 'tidb':
|
|
210
|
+
case 'singlestore': {
|
|
211
|
+
const colList = quotedColumnList(dialect, cols);
|
|
212
|
+
if (mode === 'phrase') {
|
|
213
|
+
return (0, operators_1.literal)(`MATCH(${colList}) AGAINST('"${term}"' IN BOOLEAN MODE)`);
|
|
214
|
+
}
|
|
215
|
+
if (mode === 'boolean') {
|
|
216
|
+
return (0, operators_1.literal)(`MATCH(${colList}) AGAINST('${term}' IN BOOLEAN MODE)`);
|
|
217
|
+
}
|
|
218
|
+
return (0, operators_1.literal)(`MATCH(${colList}) AGAINST('${term}' IN NATURAL LANGUAGE MODE)`);
|
|
219
|
+
}
|
|
220
|
+
case 'postgres':
|
|
221
|
+
case 'cockroachdb':
|
|
222
|
+
// YugabyteDB, TimescaleDB and Greenplum are PostgreSQL-derived and support
|
|
223
|
+
// the same tsvector/tsquery full-text search.
|
|
224
|
+
case 'yugabytedb':
|
|
225
|
+
case 'timescaledb':
|
|
226
|
+
case 'greenplum': {
|
|
227
|
+
const config = escapeStringLiteral(options?.config ?? 'english');
|
|
228
|
+
const tsvectorArg = cols.length === 1
|
|
229
|
+
? toSqlFragment(dialect, cols[0])
|
|
230
|
+
: cols.map((c) => toSqlFragment(dialect, c)).join(" || ' ' || ");
|
|
231
|
+
const tsqueryFn = mode === 'phrase' ? 'websearch_to_tsquery' : 'plainto_tsquery';
|
|
232
|
+
return (0, operators_1.literal)(`to_tsvector('${config}', ${tsvectorArg}) @@ ${tsqueryFn}('${config}', '${term}')`);
|
|
233
|
+
}
|
|
234
|
+
case 'mssql': {
|
|
235
|
+
// CONTAINS/FREETEXT accept a single column or a parenthesized column
|
|
236
|
+
// list: CONTAINS((col1, col2), 'term').
|
|
237
|
+
const colArg = cols.length === 1 ? toSqlFragment(dialect, cols[0]) : `(${quotedColumnList(dialect, cols)})`;
|
|
238
|
+
if (mode === 'natural') {
|
|
239
|
+
return (0, operators_1.literal)(`FREETEXT(${colArg}, '${term}')`);
|
|
240
|
+
}
|
|
241
|
+
const searchValue = mode === 'phrase' ? `"${term}"` : term;
|
|
242
|
+
return (0, operators_1.literal)(`CONTAINS(${colArg}, '${searchValue}')`);
|
|
243
|
+
}
|
|
244
|
+
case 'oracle': {
|
|
245
|
+
const searchValue = mode === 'phrase' ? `"${term}"` : term;
|
|
246
|
+
const predicates = cols.map((c) => `CONTAINS(${toSqlFragment(dialect, c)}, '${searchValue}', 1) > 0`);
|
|
247
|
+
return predicates.length === 1 ? (0, operators_1.literal)(predicates[0]) : (0, operators_1.literal)(`(${predicates.join(' OR ')})`);
|
|
248
|
+
}
|
|
249
|
+
case 'sqlite':
|
|
250
|
+
case 'turso': {
|
|
251
|
+
const searchValue = mode === 'phrase' ? `"${term}"` : term;
|
|
252
|
+
const predicates = cols.map((c) => `${toSqlFragment(dialect, c)} MATCH '${searchValue}'`);
|
|
253
|
+
return predicates.length === 1 ? (0, operators_1.literal)(predicates[0]) : (0, operators_1.literal)(`(${predicates.join(' OR ')})`);
|
|
254
|
+
}
|
|
255
|
+
case 'clickhouse': {
|
|
256
|
+
const multi = isMultiWord(searchTerm);
|
|
257
|
+
const predicates = cols.map((c) => {
|
|
258
|
+
const colSql = toSqlFragment(dialect, c);
|
|
259
|
+
if (multi) {
|
|
260
|
+
const words = searchTerm
|
|
261
|
+
.trim()
|
|
262
|
+
.split(/\s+/)
|
|
263
|
+
.filter(Boolean)
|
|
264
|
+
.map((w) => `'${escapeStringLiteral(w)}'`)
|
|
265
|
+
.join(', ');
|
|
266
|
+
return `multiSearchAny(${colSql}, [${words}])`;
|
|
267
|
+
}
|
|
268
|
+
return `hasToken(${colSql}, '${term}')`;
|
|
269
|
+
});
|
|
270
|
+
return predicates.length === 1 ? (0, operators_1.literal)(predicates[0]) : (0, operators_1.literal)(`(${predicates.join(' OR ')})`);
|
|
271
|
+
}
|
|
272
|
+
case 'db2': {
|
|
273
|
+
throw new Error('fullTextMatch: Db2 Text Search CONTAINS-equivalent syntax could not be verified with ' +
|
|
274
|
+
"confidence, and this ORM's own createFulltextIndex() throws for Db2 LUW (requires the " +
|
|
275
|
+
'optional Net Search Extender feature). Refusing to guess at SQL syntax — consult IBM Db2 ' +
|
|
276
|
+
'Text Search / Net Search Extender documentation and use a raw query instead.');
|
|
277
|
+
}
|
|
278
|
+
case 'duckdb': {
|
|
279
|
+
throw new Error("fullTextMatch: DuckDB's FTS extension (fts, match_bm25()) syntax was not verified with " +
|
|
280
|
+
'confidence in this pass. Refusing to guess at SQL syntax — consult the DuckDB FTS ' +
|
|
281
|
+
'extension documentation and use a raw query instead.');
|
|
282
|
+
}
|
|
283
|
+
case 'hana': {
|
|
284
|
+
throw new Error("fullTextMatch: SAP HANA's CONTAINS()/fuzzy-search full-text syntax was not verified with " +
|
|
285
|
+
'confidence in this pass. Refusing to guess at SQL syntax — consult SAP HANA Search ' +
|
|
286
|
+
'documentation and use a raw query instead.');
|
|
287
|
+
}
|
|
288
|
+
case 'spanner': {
|
|
289
|
+
throw new Error("fullTextMatch: Google Cloud Spanner's native full-text search (SEARCH/TOKENLIST) syntax " +
|
|
290
|
+
'was not verified with confidence in this pass. Refusing to guess at SQL syntax — ' +
|
|
291
|
+
'consult Spanner full-text search documentation and use a raw query instead.');
|
|
292
|
+
}
|
|
293
|
+
case 'snowflake': {
|
|
294
|
+
const predicates = cols.map((c) => `${toSqlFragment(dialect, c)} ILIKE '%${term}%'`);
|
|
295
|
+
// Documented fallback: Snowflake has no tsvector/tsquery-style full-text
|
|
296
|
+
// search; this is a plain case-insensitive substring match, not
|
|
297
|
+
// tokenized/relevance-ranked full-text search.
|
|
298
|
+
return predicates.length === 1 ? (0, operators_1.literal)(predicates[0]) : (0, operators_1.literal)(`(${predicates.join(' OR ')})`);
|
|
299
|
+
}
|
|
300
|
+
case 'redshift': {
|
|
301
|
+
const predicates = cols.map((c) => `${toSqlFragment(dialect, c)} ILIKE '%${term}%'`);
|
|
302
|
+
// Documented fallback: Redshift (despite being Postgres-derived) does
|
|
303
|
+
// not implement tsvector/tsquery full-text search.
|
|
304
|
+
return predicates.length === 1 ? (0, operators_1.literal)(predicates[0]) : (0, operators_1.literal)(`(${predicates.join(' OR ')})`);
|
|
305
|
+
}
|
|
306
|
+
// Extended dialects whose native full-text syntax was not verified with
|
|
307
|
+
// confidence in this pass (CrateDB MATCH, QuestDB, Trino, Vertica, Exasol,
|
|
308
|
+
// Firebird, Databricks/Spark all differ). Refusing to guess — use a raw query.
|
|
309
|
+
case 'vertica':
|
|
310
|
+
case 'trino':
|
|
311
|
+
case 'exasol':
|
|
312
|
+
case 'questdb':
|
|
313
|
+
case 'cratedb':
|
|
314
|
+
case 'firebird':
|
|
315
|
+
case 'databricks': {
|
|
316
|
+
throw new Error(`fullTextMatch: native full-text search for '${dialect}' is not implemented; ` +
|
|
317
|
+
'its syntax differs from the supported dialects and was not verified. ' +
|
|
318
|
+
'Use a raw query for full-text search on this dialect.');
|
|
319
|
+
}
|
|
320
|
+
default: {
|
|
321
|
+
const exhaustiveCheck = dialect;
|
|
322
|
+
throw new Error(`fullTextMatch: unsupported dialect '${String(exhaustiveCheck)}'`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// ---------------------------------------------------------------------------
|
|
327
|
+
// fullTextRank
|
|
328
|
+
// ---------------------------------------------------------------------------
|
|
329
|
+
/**
|
|
330
|
+
* Build a dialect-correct full-text relevance-SCORE SQL expression, for use
|
|
331
|
+
* in `SELECT`/`attributes` or `ORDER BY`/`order` — NOT a boolean WHERE
|
|
332
|
+
* predicate (use `fullTextMatch()` for that).
|
|
333
|
+
*
|
|
334
|
+
* Returns `{ $literal: sql }`. This shape is safe to use directly in
|
|
335
|
+
* `attributes: [...]` and `order: [...]` today (see module header) —
|
|
336
|
+
* both channels render raw literal SQL fragments correctly, unlike
|
|
337
|
+
* the WHERE-clause builder.
|
|
338
|
+
*
|
|
339
|
+
* Support by dialect:
|
|
340
|
+
* - postgres/cockroachdb: `ts_rank(to_tsvector('english', col), plainto_tsquery('english', 'term'))`.
|
|
341
|
+
* - mysql/mariadb: `MATCH(col1, col2) AGAINST('term')` — in MySQL/MariaDB,
|
|
342
|
+
* using `MATCH() AGAINST()` outside of a boolean context (e.g. in
|
|
343
|
+
* `SELECT`/`ORDER BY`) naturally evaluates to the relevance score
|
|
344
|
+
* (a floating point number), so the same construct doubles as both a
|
|
345
|
+
* predicate (via `fullTextMatch`) and a score.
|
|
346
|
+
* - oracle: `SCORE(1)` (Oracle Text). REQUIRES a `CONTAINS(col, 'term', 1) > 0`
|
|
347
|
+
* predicate using the *same* label (`1`) to appear in the query's WHERE
|
|
348
|
+
* clause (e.g. from `fullTextMatch(dialect, col, term)`), per Oracle Text
|
|
349
|
+
* rules — `SCORE(n)` reads the score computed by the `CONTAINS` call
|
|
350
|
+
* labeled `n` elsewhere in the same query.
|
|
351
|
+
* - mssql, sqlite, clickhouse, db2, redshift, snowflake: THROWS. None of
|
|
352
|
+
* these has a genuine, verifiable relevance-scoring mechanism usable as
|
|
353
|
+
* a plain SQL expression:
|
|
354
|
+
* - mssql: `CONTAINS`/`FREETEXT` are boolean predicates only; ranked
|
|
355
|
+
* results require `CONTAINSTABLE`/`FREETEXTTABLE` (table-valued
|
|
356
|
+
* functions joined in, not an expression usable inline).
|
|
357
|
+
* - sqlite FTS5: ranking requires the `bm25()` auxiliary function,
|
|
358
|
+
* which (like MSSQL's *TABLE functions) can only be selected from
|
|
359
|
+
* the FTS5 virtual table itself, not expressed against an arbitrary
|
|
360
|
+
* base-table column the way `fullTextMatch()`'s column argument
|
|
361
|
+
* implies — so it does not fit this API's per-column shape.
|
|
362
|
+
* - clickhouse: `hasToken`/`multiSearchAny` return booleans; there is
|
|
363
|
+
* no built-in relevance score function.
|
|
364
|
+
* - db2/redshift/snowflake: no native full-text search at all (see
|
|
365
|
+
* `fullTextMatch()` docs above), so there is nothing to rank.
|
|
366
|
+
*/
|
|
367
|
+
function fullTextRank(dialect, columns, searchTerm, options) {
|
|
368
|
+
const cols = toColumnArray(columns);
|
|
369
|
+
const term = escapeStringLiteral(searchTerm);
|
|
370
|
+
switch (dialect) {
|
|
371
|
+
case 'postgres':
|
|
372
|
+
case 'cockroachdb':
|
|
373
|
+
// PostgreSQL-derived: same ts_rank/tsvector relevance scoring.
|
|
374
|
+
case 'yugabytedb':
|
|
375
|
+
case 'timescaledb':
|
|
376
|
+
case 'greenplum': {
|
|
377
|
+
const config = escapeStringLiteral(options?.config ?? 'english');
|
|
378
|
+
const tsvectorArg = cols.length === 1
|
|
379
|
+
? toSqlFragment(dialect, cols[0])
|
|
380
|
+
: cols.map((c) => toSqlFragment(dialect, c)).join(" || ' ' || ");
|
|
381
|
+
return (0, operators_1.literal)(`ts_rank(to_tsvector('${config}', ${tsvectorArg}), plainto_tsquery('${config}', '${term}'))`);
|
|
382
|
+
}
|
|
383
|
+
case 'mysql':
|
|
384
|
+
case 'mariadb':
|
|
385
|
+
// MySQL-wire-compatible: same MATCH(...) AGAINST(...) relevance score.
|
|
386
|
+
case 'tidb':
|
|
387
|
+
case 'singlestore': {
|
|
388
|
+
const colList = quotedColumnList(dialect, cols);
|
|
389
|
+
return (0, operators_1.literal)(`MATCH(${colList}) AGAINST('${term}')`);
|
|
390
|
+
}
|
|
391
|
+
case 'oracle': {
|
|
392
|
+
return (0, operators_1.literal)('SCORE(1)');
|
|
393
|
+
}
|
|
394
|
+
case 'mssql':
|
|
395
|
+
throw new Error("fullTextRank: MSSQL has no relevance-score expression usable inline — CONTAINS/FREETEXT " +
|
|
396
|
+
'are boolean predicates only. Ranked results require CONTAINSTABLE()/FREETEXTTABLE() ' +
|
|
397
|
+
'(table-valued functions joined into the query), which does not fit a single SQL ' +
|
|
398
|
+
'expression; use a raw query instead.');
|
|
399
|
+
case 'sqlite':
|
|
400
|
+
case 'turso':
|
|
401
|
+
throw new Error('fullTextRank: SQLite FTS5 ranking requires the bm25() auxiliary function selected ' +
|
|
402
|
+
'directly from the FTS5 virtual table (not an expression against an arbitrary column); ' +
|
|
403
|
+
'use a raw query selecting bm25(<fts5_table>) instead.');
|
|
404
|
+
case 'clickhouse':
|
|
405
|
+
throw new Error('fullTextRank: ClickHouse has no built-in full-text relevance-score function — ' +
|
|
406
|
+
'hasToken()/multiSearchAny() return booleans, not scores.');
|
|
407
|
+
case 'db2':
|
|
408
|
+
throw new Error('fullTextRank: not supported — Db2 Text Search relevance-scoring syntax could not be ' +
|
|
409
|
+
'verified with confidence (see fullTextMatch() for details).');
|
|
410
|
+
case 'redshift':
|
|
411
|
+
throw new Error('fullTextRank: not supported — Redshift has no native full-text search/relevance-ranking ' +
|
|
412
|
+
"mechanism (see fullTextMatch()'s ILIKE fallback for a substring-match alternative).");
|
|
413
|
+
case 'snowflake':
|
|
414
|
+
throw new Error('fullTextRank: not supported — Snowflake has no native full-text search/relevance-ranking ' +
|
|
415
|
+
"mechanism (see fullTextMatch()'s ILIKE fallback for a substring-match alternative).");
|
|
416
|
+
case 'duckdb':
|
|
417
|
+
throw new Error('fullTextRank: not supported — DuckDB FTS relevance-scoring syntax was not verified with ' +
|
|
418
|
+
'confidence in this pass (see fullTextMatch()).');
|
|
419
|
+
case 'hana':
|
|
420
|
+
throw new Error('fullTextRank: not supported — SAP HANA relevance-scoring syntax was not verified with ' +
|
|
421
|
+
'confidence in this pass (see fullTextMatch()).');
|
|
422
|
+
case 'spanner':
|
|
423
|
+
throw new Error('fullTextRank: not supported — Google Cloud Spanner relevance-scoring syntax was not ' +
|
|
424
|
+
'verified with confidence in this pass (see fullTextMatch()).');
|
|
425
|
+
case 'vertica':
|
|
426
|
+
case 'trino':
|
|
427
|
+
case 'exasol':
|
|
428
|
+
case 'questdb':
|
|
429
|
+
case 'cratedb':
|
|
430
|
+
case 'firebird':
|
|
431
|
+
case 'databricks':
|
|
432
|
+
throw new Error(`fullTextRank: not supported — relevance-scoring syntax for '${dialect}' was not verified ` +
|
|
433
|
+
'with confidence in this pass (see fullTextMatch()). Use a raw query.');
|
|
434
|
+
default: {
|
|
435
|
+
const exhaustiveCheck = dialect;
|
|
436
|
+
throw new Error(`fullTextRank: unsupported dialect '${String(exhaustiveCheck)}'`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rpad = exports.lpad = exports.replace = exports.length = exports.lower = exports.upper = exports.rtrim = exports.ltrim = exports.trim = exports.substring = exports.concat = exports.truncate = exports.least = exports.greatest = exports.random = exports.mod = exports.sign = exports.abs = exports.sqrt = exports.power = exports.floor = exports.ceil = exports.round = exports.jsonTypeOf = exports.jsonKeys = exports.jsonHasKey = exports.jsonContains = exports.jsonExtract = exports.fullTextRank = exports.fullTextMatch = exports.formatDate = exports.currentTimestamp = exports.currentDate = exports.now = exports.dateDiff = exports.dateSub = exports.dateAdd = exports.dateTrunc = exports.caseOf = exports.caseWhen = exports.SimpleCaseBuilder = exports.CaseBuilder = exports.arrayAgg = exports.stringAgg = exports.max = exports.min = exports.avg = exports.sum = exports.countDistinct = exports.count = void 0;
|
|
4
|
+
exports.NullsOrder = exports.windowFn = exports.maxOver = exports.minOver = exports.countOver = exports.avgOver = exports.sumOver = exports.nthValue = exports.lastValue = exports.firstValue = exports.lead = exports.lag = exports.ntile = exports.cumeDist = exports.percentRank = exports.denseRank = exports.rank = exports.rowNumber = exports.WindowFunctionBuilder = exports.reverse = exports.repeat = exports.split = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* Barrel export for the typed SQL function-builder library.
|
|
7
|
+
* Lets callers do `import { rowNumber, jsonExtract, fullTextMatch } from 'prorm'`
|
|
8
|
+
* instead of hand-writing raw SQL fragments.
|
|
9
|
+
*
|
|
10
|
+
* Explicit (not `export *`) because several of these modules independently
|
|
11
|
+
* declare their own local `SqlExpr` type alias (same shape, different
|
|
12
|
+
* files) - re-exporting all three under one name is ambiguous.
|
|
13
|
+
*/
|
|
14
|
+
var aggregate_1 = require("./aggregate");
|
|
15
|
+
Object.defineProperty(exports, "count", { enumerable: true, get: function () { return aggregate_1.count; } });
|
|
16
|
+
Object.defineProperty(exports, "countDistinct", { enumerable: true, get: function () { return aggregate_1.countDistinct; } });
|
|
17
|
+
Object.defineProperty(exports, "sum", { enumerable: true, get: function () { return aggregate_1.sum; } });
|
|
18
|
+
Object.defineProperty(exports, "avg", { enumerable: true, get: function () { return aggregate_1.avg; } });
|
|
19
|
+
Object.defineProperty(exports, "min", { enumerable: true, get: function () { return aggregate_1.min; } });
|
|
20
|
+
Object.defineProperty(exports, "max", { enumerable: true, get: function () { return aggregate_1.max; } });
|
|
21
|
+
Object.defineProperty(exports, "stringAgg", { enumerable: true, get: function () { return aggregate_1.stringAgg; } });
|
|
22
|
+
Object.defineProperty(exports, "arrayAgg", { enumerable: true, get: function () { return aggregate_1.arrayAgg; } });
|
|
23
|
+
var conditional_1 = require("./conditional");
|
|
24
|
+
Object.defineProperty(exports, "CaseBuilder", { enumerable: true, get: function () { return conditional_1.CaseBuilder; } });
|
|
25
|
+
Object.defineProperty(exports, "SimpleCaseBuilder", { enumerable: true, get: function () { return conditional_1.SimpleCaseBuilder; } });
|
|
26
|
+
Object.defineProperty(exports, "caseWhen", { enumerable: true, get: function () { return conditional_1.caseWhen; } });
|
|
27
|
+
Object.defineProperty(exports, "caseOf", { enumerable: true, get: function () { return conditional_1.caseOf; } });
|
|
28
|
+
var datetime_1 = require("./datetime");
|
|
29
|
+
Object.defineProperty(exports, "dateTrunc", { enumerable: true, get: function () { return datetime_1.dateTrunc; } });
|
|
30
|
+
Object.defineProperty(exports, "dateAdd", { enumerable: true, get: function () { return datetime_1.dateAdd; } });
|
|
31
|
+
Object.defineProperty(exports, "dateSub", { enumerable: true, get: function () { return datetime_1.dateSub; } });
|
|
32
|
+
Object.defineProperty(exports, "dateDiff", { enumerable: true, get: function () { return datetime_1.dateDiff; } });
|
|
33
|
+
Object.defineProperty(exports, "now", { enumerable: true, get: function () { return datetime_1.now; } });
|
|
34
|
+
Object.defineProperty(exports, "currentDate", { enumerable: true, get: function () { return datetime_1.currentDate; } });
|
|
35
|
+
Object.defineProperty(exports, "currentTimestamp", { enumerable: true, get: function () { return datetime_1.currentTimestamp; } });
|
|
36
|
+
Object.defineProperty(exports, "formatDate", { enumerable: true, get: function () { return datetime_1.formatDate; } });
|
|
37
|
+
var fulltext_1 = require("./fulltext");
|
|
38
|
+
Object.defineProperty(exports, "fullTextMatch", { enumerable: true, get: function () { return fulltext_1.fullTextMatch; } });
|
|
39
|
+
Object.defineProperty(exports, "fullTextRank", { enumerable: true, get: function () { return fulltext_1.fullTextRank; } });
|
|
40
|
+
var json_1 = require("./json");
|
|
41
|
+
Object.defineProperty(exports, "jsonExtract", { enumerable: true, get: function () { return json_1.jsonExtract; } });
|
|
42
|
+
Object.defineProperty(exports, "jsonContains", { enumerable: true, get: function () { return json_1.jsonContains; } });
|
|
43
|
+
Object.defineProperty(exports, "jsonHasKey", { enumerable: true, get: function () { return json_1.jsonHasKey; } });
|
|
44
|
+
Object.defineProperty(exports, "jsonKeys", { enumerable: true, get: function () { return json_1.jsonKeys; } });
|
|
45
|
+
Object.defineProperty(exports, "jsonTypeOf", { enumerable: true, get: function () { return json_1.jsonTypeOf; } });
|
|
46
|
+
var math_1 = require("./math");
|
|
47
|
+
Object.defineProperty(exports, "round", { enumerable: true, get: function () { return math_1.round; } });
|
|
48
|
+
Object.defineProperty(exports, "ceil", { enumerable: true, get: function () { return math_1.ceil; } });
|
|
49
|
+
Object.defineProperty(exports, "floor", { enumerable: true, get: function () { return math_1.floor; } });
|
|
50
|
+
Object.defineProperty(exports, "power", { enumerable: true, get: function () { return math_1.power; } });
|
|
51
|
+
Object.defineProperty(exports, "sqrt", { enumerable: true, get: function () { return math_1.sqrt; } });
|
|
52
|
+
Object.defineProperty(exports, "abs", { enumerable: true, get: function () { return math_1.abs; } });
|
|
53
|
+
Object.defineProperty(exports, "sign", { enumerable: true, get: function () { return math_1.sign; } });
|
|
54
|
+
Object.defineProperty(exports, "mod", { enumerable: true, get: function () { return math_1.mod; } });
|
|
55
|
+
Object.defineProperty(exports, "random", { enumerable: true, get: function () { return math_1.random; } });
|
|
56
|
+
Object.defineProperty(exports, "greatest", { enumerable: true, get: function () { return math_1.greatest; } });
|
|
57
|
+
Object.defineProperty(exports, "least", { enumerable: true, get: function () { return math_1.least; } });
|
|
58
|
+
Object.defineProperty(exports, "truncate", { enumerable: true, get: function () { return math_1.truncate; } });
|
|
59
|
+
var string_1 = require("./string");
|
|
60
|
+
Object.defineProperty(exports, "concat", { enumerable: true, get: function () { return string_1.concat; } });
|
|
61
|
+
Object.defineProperty(exports, "substring", { enumerable: true, get: function () { return string_1.substring; } });
|
|
62
|
+
Object.defineProperty(exports, "trim", { enumerable: true, get: function () { return string_1.trim; } });
|
|
63
|
+
Object.defineProperty(exports, "ltrim", { enumerable: true, get: function () { return string_1.ltrim; } });
|
|
64
|
+
Object.defineProperty(exports, "rtrim", { enumerable: true, get: function () { return string_1.rtrim; } });
|
|
65
|
+
Object.defineProperty(exports, "upper", { enumerable: true, get: function () { return string_1.upper; } });
|
|
66
|
+
Object.defineProperty(exports, "lower", { enumerable: true, get: function () { return string_1.lower; } });
|
|
67
|
+
Object.defineProperty(exports, "length", { enumerable: true, get: function () { return string_1.length; } });
|
|
68
|
+
Object.defineProperty(exports, "replace", { enumerable: true, get: function () { return string_1.replace; } });
|
|
69
|
+
Object.defineProperty(exports, "lpad", { enumerable: true, get: function () { return string_1.lpad; } });
|
|
70
|
+
Object.defineProperty(exports, "rpad", { enumerable: true, get: function () { return string_1.rpad; } });
|
|
71
|
+
Object.defineProperty(exports, "split", { enumerable: true, get: function () { return string_1.split; } });
|
|
72
|
+
Object.defineProperty(exports, "repeat", { enumerable: true, get: function () { return string_1.repeat; } });
|
|
73
|
+
Object.defineProperty(exports, "reverse", { enumerable: true, get: function () { return string_1.reverse; } });
|
|
74
|
+
var window_1 = require("./window");
|
|
75
|
+
Object.defineProperty(exports, "WindowFunctionBuilder", { enumerable: true, get: function () { return window_1.WindowFunctionBuilder; } });
|
|
76
|
+
Object.defineProperty(exports, "rowNumber", { enumerable: true, get: function () { return window_1.rowNumber; } });
|
|
77
|
+
Object.defineProperty(exports, "rank", { enumerable: true, get: function () { return window_1.rank; } });
|
|
78
|
+
Object.defineProperty(exports, "denseRank", { enumerable: true, get: function () { return window_1.denseRank; } });
|
|
79
|
+
Object.defineProperty(exports, "percentRank", { enumerable: true, get: function () { return window_1.percentRank; } });
|
|
80
|
+
Object.defineProperty(exports, "cumeDist", { enumerable: true, get: function () { return window_1.cumeDist; } });
|
|
81
|
+
Object.defineProperty(exports, "ntile", { enumerable: true, get: function () { return window_1.ntile; } });
|
|
82
|
+
Object.defineProperty(exports, "lag", { enumerable: true, get: function () { return window_1.lag; } });
|
|
83
|
+
Object.defineProperty(exports, "lead", { enumerable: true, get: function () { return window_1.lead; } });
|
|
84
|
+
Object.defineProperty(exports, "firstValue", { enumerable: true, get: function () { return window_1.firstValue; } });
|
|
85
|
+
Object.defineProperty(exports, "lastValue", { enumerable: true, get: function () { return window_1.lastValue; } });
|
|
86
|
+
Object.defineProperty(exports, "nthValue", { enumerable: true, get: function () { return window_1.nthValue; } });
|
|
87
|
+
Object.defineProperty(exports, "sumOver", { enumerable: true, get: function () { return window_1.sumOver; } });
|
|
88
|
+
Object.defineProperty(exports, "avgOver", { enumerable: true, get: function () { return window_1.avgOver; } });
|
|
89
|
+
Object.defineProperty(exports, "countOver", { enumerable: true, get: function () { return window_1.countOver; } });
|
|
90
|
+
Object.defineProperty(exports, "minOver", { enumerable: true, get: function () { return window_1.minOver; } });
|
|
91
|
+
Object.defineProperty(exports, "maxOver", { enumerable: true, get: function () { return window_1.maxOver; } });
|
|
92
|
+
Object.defineProperty(exports, "windowFn", { enumerable: true, get: function () { return window_1.windowFn; } });
|
|
93
|
+
Object.defineProperty(exports, "NullsOrder", { enumerable: true, get: function () { return window_1.NullsOrder; } });
|