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,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Operator symbols for the ORM
|
|
4
|
+
* Provides all Prorm operators for query building
|
|
5
|
+
* This file re-exports from the main operators.ts for consistency
|
|
6
|
+
*
|
|
7
|
+
* Usage Examples:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Op, and, or, eq, gte } from 'orm';
|
|
10
|
+
*
|
|
11
|
+
* // Using Op directly (recommended)
|
|
12
|
+
* User.findAll({ where: { age: { [Op.gte]: 18 } } })
|
|
13
|
+
* User.findAll({ where: { name: { [Op.like]: '%john%' } } })
|
|
14
|
+
*
|
|
15
|
+
* // Using helper functions
|
|
16
|
+
* User.findAll({ where: and({ name: 'John' }, { age: gte('age', 18) }) })
|
|
17
|
+
*
|
|
18
|
+
* // Column comparison
|
|
19
|
+
* User.findAll({ where: { balance: { [Op.eq]: Op.col('credit_limit') } } })
|
|
20
|
+
*
|
|
21
|
+
* // JSON column queries
|
|
22
|
+
* User.findAll({ where: { settings: Op.json({ theme: 'dark' }) } })
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.default = exports.Op = exports.isOrderExpression = exports.random = exports.desc = exports.asc = exports.Cast = exports.cast = exports.overlap = exports.contains = exports.notIRegexp = exports.iRegexp = exports.notRegexp = exports.regexp = exports.notILike = exports.iLike = exports.isOperator = exports.operatorToWhereKey = exports.where = exports.isNotNull = exports.isNull = exports.notBetween = exports.between = exports.notIn = exports.in = exports.notLike = exports.like = exports.lte = exports.lt = exports.gte = exports.gt = exports.ne = exports.eq = exports.not = exports.or = exports.and = void 0;
|
|
27
|
+
// Re-export helper functions from main operators.ts
|
|
28
|
+
var operators_1 = require("../operators");
|
|
29
|
+
Object.defineProperty(exports, "and", { enumerable: true, get: function () { return operators_1.and; } });
|
|
30
|
+
Object.defineProperty(exports, "or", { enumerable: true, get: function () { return operators_1.or; } });
|
|
31
|
+
Object.defineProperty(exports, "not", { enumerable: true, get: function () { return operators_1.not; } });
|
|
32
|
+
Object.defineProperty(exports, "eq", { enumerable: true, get: function () { return operators_1.eq; } });
|
|
33
|
+
Object.defineProperty(exports, "ne", { enumerable: true, get: function () { return operators_1.ne; } });
|
|
34
|
+
Object.defineProperty(exports, "gt", { enumerable: true, get: function () { return operators_1.gt; } });
|
|
35
|
+
Object.defineProperty(exports, "gte", { enumerable: true, get: function () { return operators_1.gte; } });
|
|
36
|
+
Object.defineProperty(exports, "lt", { enumerable: true, get: function () { return operators_1.lt; } });
|
|
37
|
+
Object.defineProperty(exports, "lte", { enumerable: true, get: function () { return operators_1.lte; } });
|
|
38
|
+
Object.defineProperty(exports, "like", { enumerable: true, get: function () { return operators_1.like; } });
|
|
39
|
+
Object.defineProperty(exports, "notLike", { enumerable: true, get: function () { return operators_1.notLike; } });
|
|
40
|
+
Object.defineProperty(exports, "in", { enumerable: true, get: function () { return operators_1.inOp; } });
|
|
41
|
+
Object.defineProperty(exports, "notIn", { enumerable: true, get: function () { return operators_1.notIn; } });
|
|
42
|
+
Object.defineProperty(exports, "between", { enumerable: true, get: function () { return operators_1.between; } });
|
|
43
|
+
Object.defineProperty(exports, "notBetween", { enumerable: true, get: function () { return operators_1.notBetween; } });
|
|
44
|
+
Object.defineProperty(exports, "isNull", { enumerable: true, get: function () { return operators_1.isNull; } });
|
|
45
|
+
Object.defineProperty(exports, "isNotNull", { enumerable: true, get: function () { return operators_1.isNotNull; } });
|
|
46
|
+
Object.defineProperty(exports, "where", { enumerable: true, get: function () { return operators_1.where; } });
|
|
47
|
+
Object.defineProperty(exports, "operatorToWhereKey", { enumerable: true, get: function () { return operators_1.operatorToWhereKey; } });
|
|
48
|
+
Object.defineProperty(exports, "isOperator", { enumerable: true, get: function () { return operators_1.isOperator; } });
|
|
49
|
+
Object.defineProperty(exports, "iLike", { enumerable: true, get: function () { return operators_1.iLike; } });
|
|
50
|
+
Object.defineProperty(exports, "notILike", { enumerable: true, get: function () { return operators_1.notILike; } });
|
|
51
|
+
Object.defineProperty(exports, "regexp", { enumerable: true, get: function () { return operators_1.regexp; } });
|
|
52
|
+
Object.defineProperty(exports, "notRegexp", { enumerable: true, get: function () { return operators_1.notRegexp; } });
|
|
53
|
+
Object.defineProperty(exports, "iRegexp", { enumerable: true, get: function () { return operators_1.iRegexp; } });
|
|
54
|
+
Object.defineProperty(exports, "notIRegexp", { enumerable: true, get: function () { return operators_1.notIRegexp; } });
|
|
55
|
+
Object.defineProperty(exports, "contains", { enumerable: true, get: function () { return operators_1.contains; } });
|
|
56
|
+
Object.defineProperty(exports, "overlap", { enumerable: true, get: function () { return operators_1.overlap; } });
|
|
57
|
+
Object.defineProperty(exports, "cast", { enumerable: true, get: function () { return operators_1.cast; } });
|
|
58
|
+
Object.defineProperty(exports, "Cast", { enumerable: true, get: function () { return operators_1.Cast; } });
|
|
59
|
+
// Order helpers
|
|
60
|
+
Object.defineProperty(exports, "asc", { enumerable: true, get: function () { return operators_1.asc; } });
|
|
61
|
+
Object.defineProperty(exports, "desc", { enumerable: true, get: function () { return operators_1.desc; } });
|
|
62
|
+
Object.defineProperty(exports, "random", { enumerable: true, get: function () { return operators_1.random; } });
|
|
63
|
+
Object.defineProperty(exports, "isOrderExpression", { enumerable: true, get: function () { return operators_1.isOrderExpression; } });
|
|
64
|
+
// Import Op and re-export it (needed for default export)
|
|
65
|
+
const operators_2 = require("../operators");
|
|
66
|
+
Object.defineProperty(exports, "Op", { enumerable: true, get: function () { return operators_2.Op; } });
|
|
67
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return operators_2.Op; } });
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Scope management for the ORM
|
|
4
|
+
* Provides defaultScope, named scopes, and scoped model access
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ScopeManager = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Scope manager for model scoping
|
|
10
|
+
*/
|
|
11
|
+
class ScopeManager {
|
|
12
|
+
constructor(model) {
|
|
13
|
+
this.scopes = new Map();
|
|
14
|
+
this.defaultScope = null;
|
|
15
|
+
this._currentScope = null;
|
|
16
|
+
this.model = model;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Add a named scope
|
|
20
|
+
*/
|
|
21
|
+
addScope(name, options) {
|
|
22
|
+
this.scopes.set(name, options);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Set the default scope
|
|
26
|
+
*/
|
|
27
|
+
setDefaultScope(options) {
|
|
28
|
+
this.defaultScope = options;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get a scope by name
|
|
32
|
+
*/
|
|
33
|
+
getScope(name) {
|
|
34
|
+
return this.scopes.get(name);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if a scope exists
|
|
38
|
+
*/
|
|
39
|
+
hasScope(name) {
|
|
40
|
+
return this.scopes.has(name);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Remove a scope by name
|
|
44
|
+
*/
|
|
45
|
+
removeScope(name) {
|
|
46
|
+
if (!this.scopes.has(name)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
this.scopes.delete(name);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Clear all named scopes
|
|
54
|
+
*/
|
|
55
|
+
clearScopes() {
|
|
56
|
+
this.scopes.clear();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get the count of defined scopes
|
|
60
|
+
*/
|
|
61
|
+
getScopeCount() {
|
|
62
|
+
return this.scopes.size;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get all defined scopes
|
|
66
|
+
*/
|
|
67
|
+
getAllScopes() {
|
|
68
|
+
return new Map(this.scopes);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the default scope
|
|
72
|
+
*/
|
|
73
|
+
getDefaultScope() {
|
|
74
|
+
return this.defaultScope;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Apply a scope to options
|
|
78
|
+
*/
|
|
79
|
+
applyScope(scopeName, options = {}) {
|
|
80
|
+
const scope = this.scopes.get(scopeName);
|
|
81
|
+
if (!scope) {
|
|
82
|
+
throw new Error(`Scope '${scopeName}' not found`);
|
|
83
|
+
}
|
|
84
|
+
this._currentScope = scopeName;
|
|
85
|
+
// Merge scope options with provided options
|
|
86
|
+
return this.mergeScopeOptions(options, scope);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get the current active scope name
|
|
90
|
+
*/
|
|
91
|
+
getCurrentScope() {
|
|
92
|
+
return this._currentScope;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Clear the current scope
|
|
96
|
+
*/
|
|
97
|
+
clearScope() {
|
|
98
|
+
this._currentScope = null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Merge scope options with query options
|
|
102
|
+
*/
|
|
103
|
+
mergeScopeOptions(options, scope) {
|
|
104
|
+
const merged = { ...options };
|
|
105
|
+
// Merge attributes
|
|
106
|
+
if (scope.attributes) {
|
|
107
|
+
merged.attributes = scope.attributes;
|
|
108
|
+
}
|
|
109
|
+
// Merge where conditions
|
|
110
|
+
if (scope.where) {
|
|
111
|
+
if (merged.where) {
|
|
112
|
+
merged.where = this.mergeWhere(merged.where, scope.where);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
merged.where = scope.where;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Merge include
|
|
119
|
+
if (scope.include) {
|
|
120
|
+
if (merged.include) {
|
|
121
|
+
merged.include = [...merged.include, ...scope.include];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
merged.include = scope.include;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Merge order
|
|
128
|
+
if (scope.order) {
|
|
129
|
+
if (merged.order) {
|
|
130
|
+
const mergedOrder = Array.isArray(merged.order) ? merged.order : [merged.order];
|
|
131
|
+
const scopeOrder = Array.isArray(scope.order) ? scope.order : [scope.order];
|
|
132
|
+
merged.order = [...mergedOrder, ...scopeOrder];
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
merged.order = scope.order;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Merge limit (only if not already set)
|
|
139
|
+
if (scope.limit !== undefined && merged.limit === undefined) {
|
|
140
|
+
merged.limit = scope.limit;
|
|
141
|
+
}
|
|
142
|
+
// Merge offset (only if not already set)
|
|
143
|
+
if (scope.offset !== undefined && merged.offset === undefined) {
|
|
144
|
+
merged.offset = scope.offset;
|
|
145
|
+
}
|
|
146
|
+
return merged;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Merge where conditions
|
|
150
|
+
*/
|
|
151
|
+
mergeWhere(a, b) {
|
|
152
|
+
const aObj = a;
|
|
153
|
+
const bObj = b;
|
|
154
|
+
const aKeys = Object.keys(aObj);
|
|
155
|
+
const bKeys = Object.keys(bObj);
|
|
156
|
+
// Detect whether the two where clauses interact in a way that a shallow
|
|
157
|
+
// spread would silently drop constraints: either they share a field key
|
|
158
|
+
// (b would clobber a), or either side uses a logical operator whose value
|
|
159
|
+
// is an array/nested clause that a spread cannot combine.
|
|
160
|
+
const logicalKeys = ['$and', '$or', '$not'];
|
|
161
|
+
const hasSharedKey = bKeys.some((k) => aKeys.includes(k));
|
|
162
|
+
const hasLogical = aKeys.some((k) => logicalKeys.includes(k)) ||
|
|
163
|
+
bKeys.some((k) => logicalKeys.includes(k));
|
|
164
|
+
// Backward-compatible fast path: no overlap and no logical operators, so a
|
|
165
|
+
// shallow merge is equivalent to ANDing both sets of constraints.
|
|
166
|
+
if (!hasSharedKey && !hasLogical) {
|
|
167
|
+
return { ...aObj, ...bObj };
|
|
168
|
+
}
|
|
169
|
+
// Otherwise combine both clauses under $and so the caller's constraints and
|
|
170
|
+
// the scope's constraints both apply. Flatten an existing top-level $and on
|
|
171
|
+
// either side to avoid needless nesting.
|
|
172
|
+
const combine = [];
|
|
173
|
+
const flatten = (where) => {
|
|
174
|
+
const keys = Object.keys(where);
|
|
175
|
+
if (keys.length === 1 && keys[0] === '$and' && Array.isArray(where.$and)) {
|
|
176
|
+
for (const clause of where.$and) {
|
|
177
|
+
combine.push(clause);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
combine.push(where);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
flatten(aObj);
|
|
185
|
+
flatten(bObj);
|
|
186
|
+
return { $and: combine };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
exports.ScopeManager = ScopeManager;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TypeScript Type Utilities for Model Definitions
|
|
4
|
+
*
|
|
5
|
+
* This module provides TypeScript type utilities:
|
|
6
|
+
* - InferAttributes<T>: Extracts attribute types from a Model
|
|
7
|
+
* - InferCreationAttributes<T>: Extracts creation attributes (with optional ID, etc.)
|
|
8
|
+
* - CreationOptional<T>: Marks an attribute as optional during creation
|
|
9
|
+
* - NonAttribute<T>: Excludes non-database fields (methods, getters)
|
|
10
|
+
* - ForeignKey<T, TModel>: Branded type for foreign key relationships
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { Model, InferAttributes, InferCreationAttributes, CreationOptional } from 'orm';
|
|
15
|
+
*
|
|
16
|
+
* export class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
|
|
17
|
+
* declare id: CreationOptional<number>;
|
|
18
|
+
* declare name: string;
|
|
19
|
+
* declare email: string;
|
|
20
|
+
*
|
|
21
|
+
* // Non-database property
|
|
22
|
+
* declare getFullName(): NonAttribute<string>;
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AerospikeStore = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Aerospike store.
|
|
6
|
+
*
|
|
7
|
+
* Aerospike is a distributed, flash-optimized key-value store. Records are
|
|
8
|
+
* addressed by a `(namespace, set, key)` tuple and hold a flat map of named
|
|
9
|
+
* "bins" (Aerospike's term for columns/fields). It has no query language and
|
|
10
|
+
* no SQL-shaped surface (no `query(sql)`, identifier escaping, or DDL), so it
|
|
11
|
+
* does not fit the `Dialect` interface used by the SQL dialects in this repo.
|
|
12
|
+
* Instead it implements the minimal `NoSqlStore` marker interface
|
|
13
|
+
* (`src/nosql/store.ts`) and exposes Aerospike's real record primitives —
|
|
14
|
+
* `put`/`get`/`remove`/`exists`/`operate` addressed by key — directly.
|
|
15
|
+
*
|
|
16
|
+
* Built on the official `aerospike` npm driver. That driver is an optional
|
|
17
|
+
* peer dependency loaded lazily inside `connect()` (via `require`) so importing
|
|
18
|
+
* this module never forces the driver to be installed; tests inject a pre-built
|
|
19
|
+
* mock `client` instead and never reach the `require`.
|
|
20
|
+
*/
|
|
21
|
+
const errors_1 = require("../../errors");
|
|
22
|
+
/**
|
|
23
|
+
* `AerospikeStore` wraps an `aerospike` client and exposes Aerospike's record
|
|
24
|
+
* surface: `put`/`get`/`remove`/`exists` for single-record operations,
|
|
25
|
+
* `operate` for atomic multi-op transactions on a record, and `truncate` for
|
|
26
|
+
* clearing a set. Records are addressed by a `(namespace, set, key)` tuple,
|
|
27
|
+
* built by `makeKey()`.
|
|
28
|
+
*/
|
|
29
|
+
class AerospikeStore {
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
this.name = 'aerospike';
|
|
32
|
+
this.library = 'aerospike';
|
|
33
|
+
this.client = null;
|
|
34
|
+
this.connected = false;
|
|
35
|
+
/**
|
|
36
|
+
* The required `aerospike` module, kept so `makeKey()` can build a real
|
|
37
|
+
* `Aerospike.Key`. Stays `null` when a client is injected (tests), in which
|
|
38
|
+
* case `makeKey()` returns a plain `{ ns, set, key }` tuple instead.
|
|
39
|
+
*/
|
|
40
|
+
this.aerospike = null;
|
|
41
|
+
this.options = options;
|
|
42
|
+
this.namespace = options.namespace ?? '';
|
|
43
|
+
this.set = options.set ?? '';
|
|
44
|
+
}
|
|
45
|
+
// ---------------------------------------------------------------------
|
|
46
|
+
// NoSqlStore lifecycle
|
|
47
|
+
// ---------------------------------------------------------------------
|
|
48
|
+
async connect() {
|
|
49
|
+
if (this.connected && this.client) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
if (this.options.client) {
|
|
54
|
+
// Injected mock: use it directly and never touch the real driver.
|
|
55
|
+
this.client = this.options.client;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Lazy-load the optional driver so importing this module never
|
|
59
|
+
// requires `aerospike` to be installed.
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
61
|
+
const Aerospike = require('aerospike');
|
|
62
|
+
this.aerospike = Aerospike;
|
|
63
|
+
this.client = (await Aerospike.connect({
|
|
64
|
+
hosts: this.options.hosts,
|
|
65
|
+
...this.options.config,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
this.connected = true;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
this.client = null;
|
|
72
|
+
this.aerospike = null;
|
|
73
|
+
this.connected = false;
|
|
74
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
75
|
+
throw new errors_1.ConnectionError(`Unable to connect to Aerospike: ${parent.message}`, {
|
|
76
|
+
parent,
|
|
77
|
+
database: 'aerospike',
|
|
78
|
+
host: this.options.hosts?.[0]?.addr,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async disconnect() {
|
|
83
|
+
if (this.client) {
|
|
84
|
+
this.client.close(false);
|
|
85
|
+
this.client = null;
|
|
86
|
+
}
|
|
87
|
+
this.aerospike = null;
|
|
88
|
+
this.connected = false;
|
|
89
|
+
}
|
|
90
|
+
isConnected() {
|
|
91
|
+
return this.connected && this.client !== null;
|
|
92
|
+
}
|
|
93
|
+
/** Returns the underlying `aerospike` client for anything not wrapped here. */
|
|
94
|
+
getClient() {
|
|
95
|
+
return this.requireClient();
|
|
96
|
+
}
|
|
97
|
+
requireClient() {
|
|
98
|
+
if (!this.client || !this.connected) {
|
|
99
|
+
throw new errors_1.ConnectionError('Aerospike client is not connected. Call connect() first.', {
|
|
100
|
+
database: 'aerospike',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return this.client;
|
|
104
|
+
}
|
|
105
|
+
wrapError(action, err) {
|
|
106
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
107
|
+
return errors_1.DatabaseError.from(parent, { message: `Aerospike ${action} failed: ${parent.message}` });
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Builds the key object the driver expects from a `(namespace, set, key)`
|
|
111
|
+
* tuple, filling in the store's default namespace/set for anything the
|
|
112
|
+
* caller omits. When the real driver is loaded this returns a
|
|
113
|
+
* `new Aerospike.Key(namespace, set, key)`; when a mock client is injected
|
|
114
|
+
* (no module) it returns a plain `{ ns, set, key }` tuple.
|
|
115
|
+
*/
|
|
116
|
+
makeKey(input) {
|
|
117
|
+
const ns = typeof input === 'object' ? input.namespace ?? this.namespace : this.namespace;
|
|
118
|
+
const set = typeof input === 'object' ? input.set ?? this.set : this.set;
|
|
119
|
+
const key = typeof input === 'object' ? input.key : input;
|
|
120
|
+
if (this.aerospike && this.aerospike.Key) {
|
|
121
|
+
return new this.aerospike.Key(ns, set, key);
|
|
122
|
+
}
|
|
123
|
+
return { ns, set, key };
|
|
124
|
+
}
|
|
125
|
+
// ---------------------------------------------------------------------
|
|
126
|
+
// Record operations
|
|
127
|
+
// ---------------------------------------------------------------------
|
|
128
|
+
/** Writes (puts) a record's bins. Optionally accepts write metadata (TTL/generation). */
|
|
129
|
+
async put(key, bins, meta) {
|
|
130
|
+
const client = this.requireClient();
|
|
131
|
+
try {
|
|
132
|
+
return await client.put(this.makeKey(key), bins, meta);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
throw this.wrapError('put', err);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Reads a record by key, returning its bins (`record.bins`), or throws if it doesn't exist. */
|
|
139
|
+
async get(key) {
|
|
140
|
+
const client = this.requireClient();
|
|
141
|
+
try {
|
|
142
|
+
const record = await client.get(this.makeKey(key));
|
|
143
|
+
return record.bins;
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
throw this.wrapError('get', err);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Removes a record by key. */
|
|
150
|
+
async remove(key) {
|
|
151
|
+
const client = this.requireClient();
|
|
152
|
+
try {
|
|
153
|
+
return await client.remove(this.makeKey(key));
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
throw this.wrapError('remove', err);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Returns whether a record exists for the given key. */
|
|
160
|
+
async exists(key) {
|
|
161
|
+
const client = this.requireClient();
|
|
162
|
+
try {
|
|
163
|
+
return await client.exists(this.makeKey(key));
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
throw this.wrapError('exists', err);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Runs an ordered list of operations atomically against a single record
|
|
171
|
+
* (Aerospike's `operate` — increment, append, read-back, etc). `ops` is
|
|
172
|
+
* passed straight through to the driver; build them with the driver's own
|
|
173
|
+
* operation helpers.
|
|
174
|
+
*/
|
|
175
|
+
async operate(key, ops) {
|
|
176
|
+
const client = this.requireClient();
|
|
177
|
+
try {
|
|
178
|
+
return await client.operate(this.makeKey(key), ops);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
throw this.wrapError('operate', err);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Truncates a set (or the store's default set), deleting every record in it.
|
|
186
|
+
* `beforeNanos` of `0` means "everything up to now". Requires a driver whose
|
|
187
|
+
* client exposes `truncate()`.
|
|
188
|
+
*/
|
|
189
|
+
async truncate(set) {
|
|
190
|
+
const client = this.requireClient();
|
|
191
|
+
if (typeof client.truncate !== 'function') {
|
|
192
|
+
throw new errors_1.DatabaseError('Aerospike truncate() is not supported by this client', {
|
|
193
|
+
original: 'client.truncate is not a function',
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
return await client.truncate(this.namespace, set ?? this.set ?? null, 0);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
throw this.wrapError('truncate', err);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.AerospikeStore = AerospikeStore;
|
|
205
|
+
exports.default = AerospikeStore;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AllegroGraph store implementation.
|
|
4
|
+
*
|
|
5
|
+
* AllegroGraph is a semantic-graph / RDF triplestore. Its repositories are
|
|
6
|
+
* queried over the SPARQL 1.1 Protocol via a per-repository HTTP endpoint
|
|
7
|
+
* (`/repositories/<repo>`) used for both queries and updates. There is no
|
|
8
|
+
* SQL-shaped surface, so it implements the minimal `NoSqlStore` marker
|
|
9
|
+
* interface (`src/nosql/store.ts`) rather than the SQL `Dialect` interface.
|
|
10
|
+
*
|
|
11
|
+
* ## Driver strategy - prefer HTTP over `fetch`
|
|
12
|
+
*
|
|
13
|
+
* AllegroGraph ships an `agraph-js` client, but this store prefers the plain
|
|
14
|
+
* SPARQL/HTTP protocol over the global `fetch` so it has no hard dependency
|
|
15
|
+
* (`library='fetch'`). For tests (and for callers who want their own
|
|
16
|
+
* transport) an alternative client can be injected via
|
|
17
|
+
* `AllegrographStoreOptions.client`; when omitted, a tiny internal client over
|
|
18
|
+
* `fetch` + `endpoint` is built at connect time.
|
|
19
|
+
*
|
|
20
|
+
* ## Surface
|
|
21
|
+
*
|
|
22
|
+
* - `query(sparql)` -> POST to `/repositories/<repo>`, returns bindings
|
|
23
|
+
* - `update(sparql)` -> POST to `/repositories/<repo>`
|
|
24
|
+
* - `ask(sparql)` -> POST an ASK query, returns the boolean
|
|
25
|
+
* - `add(triples)` -> `INSERT DATA { ... }` update
|
|
26
|
+
* - `drop(graph?)` -> `DROP GRAPH <g>` / `DROP ALL` update
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.AllegrographStore = exports.DEFAULT_ALLEGROGRAPH_REPOSITORY = exports.DEFAULT_ALLEGROGRAPH_ENDPOINT = void 0;
|
|
30
|
+
exports.createFetchClient = createFetchClient;
|
|
31
|
+
const errors_1 = require("../../errors");
|
|
32
|
+
/** Default AllegroGraph base URL. */
|
|
33
|
+
exports.DEFAULT_ALLEGROGRAPH_ENDPOINT = 'http://localhost:10035';
|
|
34
|
+
/** Default repository id. */
|
|
35
|
+
exports.DEFAULT_ALLEGROGRAPH_REPOSITORY = 'repo';
|
|
36
|
+
/** Build a `fetch`-backed SPARQL client for the given endpoint. */
|
|
37
|
+
function createFetchClient(endpoint, headers) {
|
|
38
|
+
const base = endpoint.endsWith('/') ? endpoint : `${endpoint}/`;
|
|
39
|
+
const buildUrl = (path) => new URL(path.replace(/^\//, ''), base).toString();
|
|
40
|
+
return {
|
|
41
|
+
async query(path, sparql) {
|
|
42
|
+
const res = await fetch(buildUrl(path), {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'application/sparql-query',
|
|
46
|
+
Accept: 'application/sparql-results+json',
|
|
47
|
+
...(headers ?? {}),
|
|
48
|
+
},
|
|
49
|
+
body: sparql,
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok)
|
|
52
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
53
|
+
return res.json();
|
|
54
|
+
},
|
|
55
|
+
async update(path, sparql) {
|
|
56
|
+
const res = await fetch(buildUrl(path), {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: { 'Content-Type': 'application/sparql-update', ...(headers ?? {}) },
|
|
59
|
+
body: sparql,
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok)
|
|
62
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
63
|
+
const text = await res.text();
|
|
64
|
+
return text || undefined;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `AllegrographStore` wraps an AllegroGraph repository's SPARQL endpoint behind
|
|
70
|
+
* the `NoSqlStore` lifecycle.
|
|
71
|
+
*/
|
|
72
|
+
class AllegrographStore {
|
|
73
|
+
constructor(options = {}) {
|
|
74
|
+
this.name = 'allegrograph';
|
|
75
|
+
this.library = 'fetch';
|
|
76
|
+
this.client = null;
|
|
77
|
+
this.connected = false;
|
|
78
|
+
this.endpoint = options.endpoint ?? exports.DEFAULT_ALLEGROGRAPH_ENDPOINT;
|
|
79
|
+
this.repository = options.repository ?? exports.DEFAULT_ALLEGROGRAPH_REPOSITORY;
|
|
80
|
+
this.injectedClient = options.client;
|
|
81
|
+
this.headers = options.headers;
|
|
82
|
+
}
|
|
83
|
+
/** SPARQL query endpoint path for the configured repository. */
|
|
84
|
+
get queryPath() {
|
|
85
|
+
return `/repositories/${this.repository}`;
|
|
86
|
+
}
|
|
87
|
+
/** SPARQL update endpoint path for the configured repository (same endpoint). */
|
|
88
|
+
get updatePath() {
|
|
89
|
+
return `/repositories/${this.repository}`;
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------
|
|
92
|
+
// Connection lifecycle
|
|
93
|
+
// ---------------------------------------------------------------------
|
|
94
|
+
async connect() {
|
|
95
|
+
if (this.connected && this.client)
|
|
96
|
+
return;
|
|
97
|
+
this.client = this.injectedClient ?? createFetchClient(this.endpoint, this.headers);
|
|
98
|
+
this.connected = true;
|
|
99
|
+
}
|
|
100
|
+
async disconnect() {
|
|
101
|
+
this.client = null;
|
|
102
|
+
this.connected = false;
|
|
103
|
+
}
|
|
104
|
+
isConnected() {
|
|
105
|
+
return this.connected && this.client !== null;
|
|
106
|
+
}
|
|
107
|
+
/** Returns the underlying (internal or injected) SPARQL HTTP client. */
|
|
108
|
+
getClient() {
|
|
109
|
+
return this.requireClient();
|
|
110
|
+
}
|
|
111
|
+
requireClient() {
|
|
112
|
+
if (!this.client) {
|
|
113
|
+
throw new errors_1.ConnectionError('Not connected to AllegroGraph', {
|
|
114
|
+
database: 'allegrograph',
|
|
115
|
+
host: this.endpoint,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return this.client;
|
|
119
|
+
}
|
|
120
|
+
// ---------------------------------------------------------------------
|
|
121
|
+
// SPARQL surface
|
|
122
|
+
// ---------------------------------------------------------------------
|
|
123
|
+
/** Runs a SPARQL SELECT/CONSTRUCT query; returns the result bindings. */
|
|
124
|
+
async query(sparql) {
|
|
125
|
+
const client = this.requireClient();
|
|
126
|
+
try {
|
|
127
|
+
const body = await client.query(this.queryPath, sparql);
|
|
128
|
+
return body?.results?.bindings ?? [];
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
132
|
+
throw errors_1.DatabaseError.from(parent, { message: `AllegroGraph query failed: ${parent.message}`, sql: sparql });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** Runs a SPARQL ASK query; returns the boolean answer. */
|
|
136
|
+
async ask(sparql) {
|
|
137
|
+
const client = this.requireClient();
|
|
138
|
+
try {
|
|
139
|
+
const body = await client.query(this.queryPath, sparql);
|
|
140
|
+
return Boolean(body?.boolean);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
144
|
+
throw errors_1.DatabaseError.from(parent, { message: `AllegroGraph ask failed: ${parent.message}`, sql: sparql });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Runs a SPARQL UPDATE (INSERT/DELETE/DROP/...). */
|
|
148
|
+
async update(sparql) {
|
|
149
|
+
const client = this.requireClient();
|
|
150
|
+
try {
|
|
151
|
+
return await client.update(this.updatePath, sparql);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
const parent = err instanceof Error ? err : new Error(String(err));
|
|
155
|
+
throw errors_1.DatabaseError.from(parent, { message: `AllegroGraph update failed: ${parent.message}`, sql: sparql });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** Inserts triples via `INSERT DATA { ... }`. Accepts a triple string or array. */
|
|
159
|
+
async add(triples, graph) {
|
|
160
|
+
const body = Array.isArray(triples) ? triples.join('\n') : triples;
|
|
161
|
+
const inner = graph ? `GRAPH <${graph}> { ${body} }` : body;
|
|
162
|
+
return this.update(`INSERT DATA { ${inner} }`);
|
|
163
|
+
}
|
|
164
|
+
/** Drops a named graph, or all graphs when no graph is given. */
|
|
165
|
+
async drop(graph) {
|
|
166
|
+
return this.update(graph ? `DROP GRAPH <${graph}>` : 'DROP ALL');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.AllegrographStore = AllegrographStore;
|