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,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Qdrant store implementation.
|
|
4
|
+
*
|
|
5
|
+
* Qdrant is a vector-similarity search engine: collections hold points
|
|
6
|
+
* (an ID, one or more dense/sparse vectors, and an arbitrary JSON payload),
|
|
7
|
+
* and the primary query shape is "find the points whose vector is closest
|
|
8
|
+
* to this query vector" (optionally constrained by a payload filter) -
|
|
9
|
+
* not SQL, not `WHERE`, not joins. It does not fit the SQL-shaped `Dialect`
|
|
10
|
+
* interface used by the SQL dialects in this repo, so this class implements
|
|
11
|
+
* the minimal `NoSqlStore` marker interface and exposes Qdrant's real
|
|
12
|
+
* collection/point/payload/alias operations instead of forcing them into a
|
|
13
|
+
* `query(sql)` shape.
|
|
14
|
+
*
|
|
15
|
+
* Uses the official `@qdrant/js-client-rest` driver, which talks to Qdrant's
|
|
16
|
+
* HTTP REST API (there is also a gRPC client, `@qdrant/js-client-grpc`, not
|
|
17
|
+
* used here). The REST client is stateless (plain HTTP requests, no
|
|
18
|
+
* persistent socket) - `connect()` verifies the server is reachable and the
|
|
19
|
+
* API key (if any) is accepted by calling `versionInfo()`, and
|
|
20
|
+
* `disconnect()` simply drops the client reference.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.QdrantStore = void 0;
|
|
24
|
+
const js_client_rest_1 = require("@qdrant/js-client-rest");
|
|
25
|
+
const errors_1 = require("../../errors");
|
|
26
|
+
function wrapConnectionError(err, host) {
|
|
27
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
28
|
+
const message = /fetch failed|ECONNREFUSED/i.test(parent.message)
|
|
29
|
+
? 'Connection refused'
|
|
30
|
+
: `Unable to connect to Qdrant: ${parent.message}`;
|
|
31
|
+
return new errors_1.ConnectionError(message, { parent, database: 'qdrant', host });
|
|
32
|
+
}
|
|
33
|
+
function wrapDatabaseError(err, message) {
|
|
34
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
35
|
+
// Keep the `action` context (e.g. "Qdrant SEARCH failed") but don't discard
|
|
36
|
+
// the real underlying Qdrant error text (e.g. "Collection `foo` doesn't
|
|
37
|
+
// exist") - append it so callers inspecting `err.message` still see what
|
|
38
|
+
// actually went wrong.
|
|
39
|
+
const combined = message ? `${message}: ${parent.message}` : parent.message;
|
|
40
|
+
return errors_1.DatabaseError.from(parent, { message: combined });
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `QdrantStore` wraps a `@qdrant/js-client-rest` `QdrantClient` and exposes
|
|
44
|
+
* Qdrant's collection management, point upsert/search/scroll/retrieve/delete,
|
|
45
|
+
* payload management, and collection-alias operations as a typed,
|
|
46
|
+
* promise-based API.
|
|
47
|
+
*/
|
|
48
|
+
class QdrantStore {
|
|
49
|
+
constructor(options = {}) {
|
|
50
|
+
this.name = 'qdrant';
|
|
51
|
+
this.library = '@qdrant/js-client-rest';
|
|
52
|
+
this.client = null;
|
|
53
|
+
this.connected = false;
|
|
54
|
+
this.options = options;
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------
|
|
57
|
+
// Connection lifecycle
|
|
58
|
+
// ---------------------------------------------------------------------
|
|
59
|
+
async connect() {
|
|
60
|
+
if (this.connected && this.client) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const client = new js_client_rest_1.QdrantClient(this.options);
|
|
64
|
+
try {
|
|
65
|
+
// The REST client has no persistent socket to open, so "connecting"
|
|
66
|
+
// means eagerly verifying the server is reachable and (if configured)
|
|
67
|
+
// that the API key is accepted, rather than deferring failures to the
|
|
68
|
+
// first real call.
|
|
69
|
+
await client.versionInfo();
|
|
70
|
+
this.client = client;
|
|
71
|
+
this.connected = true;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
this.client = null;
|
|
75
|
+
this.connected = false;
|
|
76
|
+
throw wrapConnectionError(err, this.options.host ?? this.options.url);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async disconnect() {
|
|
80
|
+
this.client = null;
|
|
81
|
+
this.connected = false;
|
|
82
|
+
}
|
|
83
|
+
isConnected() {
|
|
84
|
+
return this.connected && this.client !== null;
|
|
85
|
+
}
|
|
86
|
+
/** Returns the underlying `QdrantClient` for anything not wrapped here. */
|
|
87
|
+
getClient() {
|
|
88
|
+
return this.requireClient();
|
|
89
|
+
}
|
|
90
|
+
requireClient() {
|
|
91
|
+
if (!this.client) {
|
|
92
|
+
throw new errors_1.ConnectionError('Not connected to Qdrant', { database: 'qdrant' });
|
|
93
|
+
}
|
|
94
|
+
return this.client;
|
|
95
|
+
}
|
|
96
|
+
async exec(fn, action) {
|
|
97
|
+
const client = this.requireClient();
|
|
98
|
+
try {
|
|
99
|
+
return await fn(client);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
throw wrapDatabaseError(err, `Qdrant ${action} failed`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------
|
|
106
|
+
// Collection management
|
|
107
|
+
// ---------------------------------------------------------------------
|
|
108
|
+
/**
|
|
109
|
+
* Create a new, empty collection. `vectors` is either a single
|
|
110
|
+
* `{ size, distance }` (unnamed/default vector space) or a map of named
|
|
111
|
+
* vector spaces (for collections with multiple vector fields per point).
|
|
112
|
+
*/
|
|
113
|
+
async createCollection(collectionName, vectors, options = {}) {
|
|
114
|
+
return this.exec((c) => c.createCollection(collectionName, { vectors, ...options }), 'CREATE COLLECTION');
|
|
115
|
+
}
|
|
116
|
+
/** Delete a collection and all of its data. */
|
|
117
|
+
async deleteCollection(collectionName, options = {}) {
|
|
118
|
+
return this.exec((c) => c.deleteCollection(collectionName, options), 'DELETE COLLECTION');
|
|
119
|
+
}
|
|
120
|
+
/** Detailed status, point counts, and configuration for a collection. */
|
|
121
|
+
async getCollection(collectionName) {
|
|
122
|
+
return this.exec((c) => c.getCollection(collectionName), 'GET COLLECTION');
|
|
123
|
+
}
|
|
124
|
+
/** List the names of all collections. */
|
|
125
|
+
async listCollections() {
|
|
126
|
+
return this.exec(async (c) => (await c.getCollections()).collections, 'LIST COLLECTIONS');
|
|
127
|
+
}
|
|
128
|
+
/** Whether a collection with this name exists. */
|
|
129
|
+
async collectionExists(collectionName) {
|
|
130
|
+
return this.exec(async (c) => (await c.collectionExists(collectionName)).exists, 'COLLECTION EXISTS');
|
|
131
|
+
}
|
|
132
|
+
/** Update mutable collection parameters (optimizer config, HNSW params, etc). */
|
|
133
|
+
async updateCollection(collectionName, args = {}) {
|
|
134
|
+
return this.exec((c) => c.updateCollection(collectionName, args), 'UPDATE COLLECTION');
|
|
135
|
+
}
|
|
136
|
+
/** Create an index on a payload field so filtered search on it is fast. */
|
|
137
|
+
async createPayloadIndex(collectionName, fieldName, fieldSchema, options = {}) {
|
|
138
|
+
return this.exec((c) => c.createPayloadIndex(collectionName, {
|
|
139
|
+
field_name: fieldName,
|
|
140
|
+
field_schema: fieldSchema,
|
|
141
|
+
...options,
|
|
142
|
+
}), 'CREATE PAYLOAD INDEX');
|
|
143
|
+
}
|
|
144
|
+
/** Remove an index previously created with `createPayloadIndex()`. */
|
|
145
|
+
async deletePayloadIndex(collectionName, fieldName, options = {}) {
|
|
146
|
+
return this.exec((c) => c.deletePayloadIndex(collectionName, fieldName, options), 'DELETE PAYLOAD INDEX');
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------
|
|
149
|
+
// Point upsert
|
|
150
|
+
// ---------------------------------------------------------------------
|
|
151
|
+
/** Insert or update one or more points (matched by ID). */
|
|
152
|
+
async upsert(collectionName, points, options = {}) {
|
|
153
|
+
return this.exec((c) => c.upsert(collectionName, { points, ...options }), 'UPSERT');
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Insert or update points given in Qdrant's columnar "batch" shape
|
|
157
|
+
* (`{ ids, vectors, payloads }`, index-aligned across the three arrays)
|
|
158
|
+
* rather than an array of `{ id, vector, payload }` objects. Equivalent
|
|
159
|
+
* to `upsert()`, just a more compact wire format for large batches.
|
|
160
|
+
*/
|
|
161
|
+
async upsertBatch(collectionName, batch, options = {}) {
|
|
162
|
+
return this.exec((c) => c.upsert(collectionName, { batch, ...options }), 'UPSERT BATCH');
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------
|
|
165
|
+
// Search
|
|
166
|
+
// ---------------------------------------------------------------------
|
|
167
|
+
/** Find the points whose vector is closest to `vector`, optionally constrained by a filter. */
|
|
168
|
+
async search(collectionName, vector, options = {}) {
|
|
169
|
+
const { vectorName, withPayload, withVector, scoreThreshold, ...rest } = options;
|
|
170
|
+
return this.exec((c) => c.search(collectionName, {
|
|
171
|
+
vector: vectorName ? { name: vectorName, vector } : vector,
|
|
172
|
+
with_payload: withPayload,
|
|
173
|
+
with_vector: withVector,
|
|
174
|
+
score_threshold: scoreThreshold,
|
|
175
|
+
...rest,
|
|
176
|
+
}), 'SEARCH');
|
|
177
|
+
}
|
|
178
|
+
/** Run several `search()` requests against the same collection in a single round trip. */
|
|
179
|
+
async searchBatch(collectionName, searches, options = {}) {
|
|
180
|
+
return this.exec((c) => c.searchBatch(collectionName, { searches, ...options }), 'SEARCH BATCH');
|
|
181
|
+
}
|
|
182
|
+
// ---------------------------------------------------------------------
|
|
183
|
+
// Scroll (paginated retrieval)
|
|
184
|
+
// ---------------------------------------------------------------------
|
|
185
|
+
/**
|
|
186
|
+
* Page through all (optionally filtered) points in a collection without
|
|
187
|
+
* doing a similarity search. Pass the returned `nextPageOffset` back in
|
|
188
|
+
* as `options.offset` to fetch the next page; a `null` `nextPageOffset`
|
|
189
|
+
* means there's no more data.
|
|
190
|
+
*/
|
|
191
|
+
async scroll(collectionName, options = {}) {
|
|
192
|
+
const { withPayload, withVector, ...rest } = options;
|
|
193
|
+
const result = await this.exec((c) => c.scroll(collectionName, {
|
|
194
|
+
with_payload: withPayload,
|
|
195
|
+
with_vector: withVector,
|
|
196
|
+
...rest,
|
|
197
|
+
}), 'SCROLL');
|
|
198
|
+
return { points: result.points, nextPageOffset: result.next_page_offset ?? null };
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------
|
|
201
|
+
// Retrieve / count
|
|
202
|
+
// ---------------------------------------------------------------------
|
|
203
|
+
/** Fetch specific points by ID. IDs not found are simply omitted from the result. */
|
|
204
|
+
async retrieve(collectionName, ids, options = {}) {
|
|
205
|
+
const { withPayload, withVector, ...rest } = options;
|
|
206
|
+
return this.exec((c) => c.retrieve(collectionName, {
|
|
207
|
+
ids,
|
|
208
|
+
with_payload: withPayload,
|
|
209
|
+
with_vector: withVector,
|
|
210
|
+
...rest,
|
|
211
|
+
}), 'RETRIEVE');
|
|
212
|
+
}
|
|
213
|
+
/** Count points in a collection, optionally matching a filter. */
|
|
214
|
+
async count(collectionName, filter, options = {}) {
|
|
215
|
+
const result = await this.exec((c) => c.count(collectionName, { filter, ...options }), 'COUNT');
|
|
216
|
+
return result.count;
|
|
217
|
+
}
|
|
218
|
+
// ---------------------------------------------------------------------
|
|
219
|
+
// Delete
|
|
220
|
+
// ---------------------------------------------------------------------
|
|
221
|
+
/** Delete points by explicit ID list. */
|
|
222
|
+
async deleteByIds(collectionName, ids, options = {}) {
|
|
223
|
+
return this.exec((c) => c.delete(collectionName, { points: ids, ...options }), 'DELETE');
|
|
224
|
+
}
|
|
225
|
+
/** Delete every point matching a filter. */
|
|
226
|
+
async deleteByFilter(collectionName, filter, options = {}) {
|
|
227
|
+
return this.exec((c) => c.delete(collectionName, { filter, ...options }), 'DELETE');
|
|
228
|
+
}
|
|
229
|
+
// ---------------------------------------------------------------------
|
|
230
|
+
// Payload management
|
|
231
|
+
// ---------------------------------------------------------------------
|
|
232
|
+
/**
|
|
233
|
+
* Merge `payload` into the existing payload of the selected points
|
|
234
|
+
* (existing keys not present in `payload` are left untouched).
|
|
235
|
+
*/
|
|
236
|
+
async setPayload(collectionName, payload, selector, options = {}) {
|
|
237
|
+
return this.exec((c) => c.setPayload(collectionName, { payload, ...selectorArgs(selector), ...options }), 'SET PAYLOAD');
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Replace the entire payload of the selected points with `payload`
|
|
241
|
+
* (unlike `setPayload()`, keys not present in `payload` are removed).
|
|
242
|
+
*/
|
|
243
|
+
async overwritePayload(collectionName, payload, selector, options = {}) {
|
|
244
|
+
return this.exec((c) => c.overwritePayload(collectionName, { payload, ...selectorArgs(selector), ...options }), 'OVERWRITE PAYLOAD');
|
|
245
|
+
}
|
|
246
|
+
/** Remove specific payload keys from the selected points. */
|
|
247
|
+
async deletePayload(collectionName, keys, selector, options = {}) {
|
|
248
|
+
return this.exec((c) => c.deletePayload(collectionName, { keys, ...selectorArgs(selector), ...options }), 'DELETE PAYLOAD');
|
|
249
|
+
}
|
|
250
|
+
/** Remove the entire payload (all keys) from the selected points. */
|
|
251
|
+
async clearPayload(collectionName, selector, options = {}) {
|
|
252
|
+
return this.exec((c) => c.clearPayload(collectionName, { ...selectorArgs(selector), ...options }), 'CLEAR PAYLOAD');
|
|
253
|
+
}
|
|
254
|
+
// ---------------------------------------------------------------------
|
|
255
|
+
// Collection aliasing
|
|
256
|
+
// ---------------------------------------------------------------------
|
|
257
|
+
/** Create an alternative name (`aliasName`) for a collection; the collection is queryable under both names. */
|
|
258
|
+
async createAlias(collectionName, aliasName, timeout) {
|
|
259
|
+
return this.exec((c) => c.updateCollectionAliases({
|
|
260
|
+
actions: [{ create_alias: { collection_name: collectionName, alias_name: aliasName } }],
|
|
261
|
+
timeout,
|
|
262
|
+
}), 'CREATE ALIAS');
|
|
263
|
+
}
|
|
264
|
+
/** Delete an alias (the underlying collection and its other aliases are unaffected). */
|
|
265
|
+
async deleteAlias(aliasName, timeout) {
|
|
266
|
+
return this.exec((c) => c.updateCollectionAliases({
|
|
267
|
+
actions: [{ delete_alias: { alias_name: aliasName } }],
|
|
268
|
+
timeout,
|
|
269
|
+
}), 'DELETE ALIAS');
|
|
270
|
+
}
|
|
271
|
+
/** Atomically rename an alias (equivalent to delete + create in one operation). */
|
|
272
|
+
async renameAlias(oldAliasName, newAliasName, timeout) {
|
|
273
|
+
return this.exec((c) => c.updateCollectionAliases({
|
|
274
|
+
actions: [{ rename_alias: { old_alias_name: oldAliasName, new_alias_name: newAliasName } }],
|
|
275
|
+
timeout,
|
|
276
|
+
}), 'RENAME ALIAS');
|
|
277
|
+
}
|
|
278
|
+
/** List the aliases pointing at a specific collection. */
|
|
279
|
+
async getCollectionAliases(collectionName) {
|
|
280
|
+
return this.exec((c) => c.getCollectionAliases(collectionName), 'GET COLLECTION ALIASES');
|
|
281
|
+
}
|
|
282
|
+
/** List every alias across all collections. */
|
|
283
|
+
async getAliases() {
|
|
284
|
+
return this.exec((c) => c.getAliases(), 'GET ALIASES');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.QdrantStore = QdrantStore;
|
|
288
|
+
/** Spread a `PointsSelector` (`{ points }` or `{ filter }`, plus optional `shard_key`) into request args. */
|
|
289
|
+
function selectorArgs(selector) {
|
|
290
|
+
if ('points' in selector) {
|
|
291
|
+
return { points: selector.points };
|
|
292
|
+
}
|
|
293
|
+
return { filter: selector.filter };
|
|
294
|
+
}
|
|
295
|
+
exports.default = QdrantStore;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Amazon QLDB store implementation.
|
|
4
|
+
*
|
|
5
|
+
* Amazon QLDB (Quantum Ledger Database) is a fully managed, append-only,
|
|
6
|
+
* cryptographically verifiable ledger database. Data is written as documents
|
|
7
|
+
* into ledger tables and queried with PartiQL (a SQL-compatible query
|
|
8
|
+
* language). Every revision of every document is retained in an immutable
|
|
9
|
+
* journal; the built-in `history(<table>)` PartiQL function exposes prior
|
|
10
|
+
* revisions, and each revision carries `metadata` (document id, version,
|
|
11
|
+
* transaction time, and a content hash) that forms the basis of QLDB's
|
|
12
|
+
* tamper-evidence.
|
|
13
|
+
*
|
|
14
|
+
* QLDB is not a SQL `Dialect` (no client-side DDL escaping, no row-level
|
|
15
|
+
* UPDATE/DELETE semantics beyond PartiQL), so this class implements the
|
|
16
|
+
* minimal `NoSqlStore` marker interface plus the ledger surface shared by
|
|
17
|
+
* this family of stores: `append`/`get`/`history`/`verify`/`query`.
|
|
18
|
+
*
|
|
19
|
+
* ## Lazy driver loading
|
|
20
|
+
*
|
|
21
|
+
* The official `amazon-qldb-driver-nodejs` package is loaded lazily inside
|
|
22
|
+
* `connect()`, so importing this module never requires the driver to be
|
|
23
|
+
* installed. Tests (and callers with their own transport) inject a pre-built
|
|
24
|
+
* driver via `QldbStoreOptions.client`, which bypasses the `require` entirely.
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.QldbStore = void 0;
|
|
28
|
+
const errors_1 = require("../../errors");
|
|
29
|
+
/** A validated PartiQL identifier - QLDB cannot parameterize table names. */
|
|
30
|
+
const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
31
|
+
function assertIdentifier(name) {
|
|
32
|
+
if (!IDENTIFIER.test(name)) {
|
|
33
|
+
throw new errors_1.DatabaseError(`Invalid QLDB table name: ${JSON.stringify(name)}`, {
|
|
34
|
+
code: 'VALIDATION_ERROR',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return name;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* `QldbStore` wraps an `amazon-qldb-driver-nodejs` driver behind the shared
|
|
41
|
+
* ledger surface. `append` inserts a new document (returning its QLDB
|
|
42
|
+
* document id), `get` reads the current revision by document id, `history`
|
|
43
|
+
* returns every prior revision via the `history()` PartiQL function,
|
|
44
|
+
* `verify` returns a document's revision metadata (content hash +
|
|
45
|
+
* block address - QLDB's tamper-evidence proof material), and `query` is the
|
|
46
|
+
* raw PartiQL escape hatch.
|
|
47
|
+
*/
|
|
48
|
+
class QldbStore {
|
|
49
|
+
constructor(options) {
|
|
50
|
+
this.name = 'qldb';
|
|
51
|
+
this.library = 'amazon-qldb-driver-nodejs';
|
|
52
|
+
this.driver = null;
|
|
53
|
+
this.connected = false;
|
|
54
|
+
if (!options || !options.ledgerName) {
|
|
55
|
+
throw new errors_1.DatabaseError('QldbStore requires a `ledgerName`', {
|
|
56
|
+
code: 'INVALID_CONNECTION',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
this.options = options;
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------
|
|
62
|
+
// Connection lifecycle
|
|
63
|
+
// ---------------------------------------------------------------------
|
|
64
|
+
async connect() {
|
|
65
|
+
if (this.connected && this.driver) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
if (this.options.client) {
|
|
70
|
+
this.driver = this.options.client;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
74
|
+
const mod = require('amazon-qldb-driver-nodejs');
|
|
75
|
+
const QldbDriver = mod.QldbDriver ?? mod.default?.QldbDriver ?? mod.default;
|
|
76
|
+
this.driver = new QldbDriver(this.options.ledgerName, this.options.region ? { region: this.options.region } : undefined);
|
|
77
|
+
}
|
|
78
|
+
this.connected = true;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
this.driver = null;
|
|
82
|
+
this.connected = false;
|
|
83
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
84
|
+
throw new errors_1.ConnectionError(`Unable to connect to QLDB: ${parent.message}`, {
|
|
85
|
+
parent,
|
|
86
|
+
database: 'qldb',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async disconnect() {
|
|
91
|
+
if (this.driver && typeof this.driver.close === 'function') {
|
|
92
|
+
try {
|
|
93
|
+
await this.driver.close();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// best-effort close
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.driver = null;
|
|
100
|
+
this.connected = false;
|
|
101
|
+
}
|
|
102
|
+
isConnected() {
|
|
103
|
+
return this.connected && this.driver !== null;
|
|
104
|
+
}
|
|
105
|
+
/** Returns the underlying `QldbDriver` for anything not wrapped here. */
|
|
106
|
+
getClient() {
|
|
107
|
+
return this.requireDriver();
|
|
108
|
+
}
|
|
109
|
+
requireDriver() {
|
|
110
|
+
if (!this.driver || !this.connected) {
|
|
111
|
+
throw new errors_1.ConnectionError('Not connected to QLDB. Call connect() first.', {
|
|
112
|
+
database: 'qldb',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return this.driver;
|
|
116
|
+
}
|
|
117
|
+
/** Run a PartiQL statement inside a managed transaction and return the rows. */
|
|
118
|
+
async execute(statement, params, action) {
|
|
119
|
+
const driver = this.requireDriver();
|
|
120
|
+
try {
|
|
121
|
+
return await driver.executeLambda(async (txn) => {
|
|
122
|
+
const result = await txn.execute(statement, ...params);
|
|
123
|
+
return result.getResultList();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
128
|
+
throw errors_1.DatabaseError.from(parent, { message: `QLDB ${action} failed: ${parent.message}` });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------
|
|
132
|
+
// Ledger surface
|
|
133
|
+
// ---------------------------------------------------------------------
|
|
134
|
+
/**
|
|
135
|
+
* Insert `data` as a new document into `table`, returning its QLDB document
|
|
136
|
+
* id (the stable identifier every revision of the document shares). Runs
|
|
137
|
+
* `INSERT INTO <table> ?`.
|
|
138
|
+
*/
|
|
139
|
+
async append(table, data) {
|
|
140
|
+
const rows = await this.execute(`INSERT INTO ${assertIdentifier(table)} ?`, [data], 'append');
|
|
141
|
+
const first = rows[0];
|
|
142
|
+
return first?.documentId ?? String(first?.documentId ?? '');
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Read the current revision of the document with QLDB document id `id`,
|
|
146
|
+
* addressed via PartiQL's `BY` clause. Returns the row or `null`.
|
|
147
|
+
*/
|
|
148
|
+
async get(table, id) {
|
|
149
|
+
const rows = await this.execute(`SELECT * FROM ${assertIdentifier(table)} BY docId WHERE docId = ?`, [id], 'get');
|
|
150
|
+
return rows[0] ?? null;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Return every revision (including deletions) of the document with id `id`
|
|
154
|
+
* via the `history(<table>)` PartiQL function. Each entry carries `data`,
|
|
155
|
+
* `metadata`, `blockAddress` and `hash`.
|
|
156
|
+
*/
|
|
157
|
+
async history(table, id) {
|
|
158
|
+
return this.execute(`SELECT * FROM history(${assertIdentifier(table)}) AS h WHERE h.metadata.id = ?`, [id], 'history');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Return the tamper-evidence proof material for document `id`: its revision
|
|
162
|
+
* `metadata` (content hash + version) and `blockAddress` from the journal,
|
|
163
|
+
* pulled from `history()`. This is the data QLDB's server-side digest/proof
|
|
164
|
+
* APIs cryptographically verify a revision against.
|
|
165
|
+
*/
|
|
166
|
+
async verify(table, id) {
|
|
167
|
+
const rows = await this.execute(`SELECT metadata, blockAddress, hash FROM history(${assertIdentifier(table)}) AS h WHERE h.metadata.id = ?`, [id], 'verify');
|
|
168
|
+
return { documentId: id, revisions: rows };
|
|
169
|
+
}
|
|
170
|
+
/** Run a raw PartiQL `statement` with optional positional `params`. */
|
|
171
|
+
async query(statement, params = []) {
|
|
172
|
+
return this.execute(statement, params, 'query');
|
|
173
|
+
}
|
|
174
|
+
/** List the active table names in the ledger (thin passthrough). */
|
|
175
|
+
async tableNames() {
|
|
176
|
+
const driver = this.requireDriver();
|
|
177
|
+
if (typeof driver.getTableNames !== 'function') {
|
|
178
|
+
throw new errors_1.DatabaseError('QLDB driver does not support getTableNames()', {
|
|
179
|
+
code: 'QUERY_ERROR',
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
return await driver.getTableNames();
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
187
|
+
throw errors_1.DatabaseError.from(parent, { message: `QLDB tableNames failed: ${parent.message}` });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.QldbStore = QldbStore;
|
|
192
|
+
exports.default = QldbStore;
|