ts-prorm-orm 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,469 @@
1
+ "use strict";
2
+ /**
3
+ * TigerGraph store implementation.
4
+ *
5
+ * TigerGraph is a native graph database (vertices/edges/GSQL), not a SQL
6
+ * engine, so this class does not implement the SQL-shaped `Dialect`
7
+ * interface (see `src/dialects/dialect.ts`). It implements the minimal
8
+ * `NoSqlStore` marker interface (`src/nosql/store.ts`) and exposes
9
+ * TigerGraph's real capabilities directly: installed-query execution,
10
+ * vertex/edge upsert and retrieval, ad-hoc "interpreted" GSQL queries, and
11
+ * schema introspection.
12
+ *
13
+ * ## Why `fetch`, not a driver
14
+ *
15
+ * Unlike every sibling in `src/nosql/` (MongoDB -> `mongodb`, Redis ->
16
+ * `ioredis`, DynamoDB -> `@aws-sdk/*`), there is no official,
17
+ * actively-maintained Node.js/JavaScript SDK for TigerGraph on npm as of
18
+ * this writing. The only packages found (`tigergraph.js`, `tiger-graph`)
19
+ * are small, unmaintained community wrappers last published in 2022, not
20
+ * published or endorsed by TigerGraph Inc, and TigerGraph's own GitHub org
21
+ * ships `pyTigerGraph` (Python) but nothing for Node. TigerGraph *is*
22
+ * fully usable from Node, though: it's a plain HTTP/JSON REST API
23
+ * ("REST++", plus the GSQL server's own HTTP endpoints), so this store
24
+ * talks to it with Node's built-in global `fetch` (Node >=18, this repo's
25
+ * minimum engine) instead of adding a new npm dependency for a thin HTTP
26
+ * wrapper. This is a deliberate choice, not an oversight - see the
27
+ * package's README for the endpoint shapes this was verified against.
28
+ *
29
+ * `library` is reported as `'fetch'` (there is no driver name to report).
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.TigerGraphStore = void 0;
33
+ const errors_1 = require("../../errors");
34
+ // ---------------------------------------------------------------------
35
+ // Error helpers
36
+ // ---------------------------------------------------------------------
37
+ function wrapConnectionError(err, host) {
38
+ const parent = err instanceof Error ? err : new Error(String(err));
39
+ const message = /fetch failed|econnrefused/i.test(parent.message)
40
+ ? 'Connection refused'
41
+ : `Unable to connect to TigerGraph: ${parent.message}`;
42
+ return new errors_1.ConnectionError(message, { parent, database: 'tigergraph', host });
43
+ }
44
+ function wrapDatabaseError(err, message) {
45
+ const parent = err instanceof Error ? err : new Error(String(err));
46
+ const combined = message ? `${message}: ${parent.message}` : parent.message;
47
+ return errors_1.DatabaseError.from(parent, { message: combined });
48
+ }
49
+ /** Convert plain attribute values into TigerGraph's `{"value": x}` wire format, passing already-wrapped values through unchanged. */
50
+ function toWireAttributes(attrs = {}) {
51
+ const wire = {};
52
+ for (const [key, value] of Object.entries(attrs)) {
53
+ if (value !== null && typeof value === 'object' && 'value' in value) {
54
+ wire[key] = value;
55
+ }
56
+ else {
57
+ wire[key] = { value };
58
+ }
59
+ }
60
+ return wire;
61
+ }
62
+ // ---------------------------------------------------------------------
63
+ // Store
64
+ // ---------------------------------------------------------------------
65
+ /**
66
+ * `TigerGraphStore` wraps TigerGraph's REST++ and GSQL-server HTTP APIs
67
+ * behind a typed, promise-based interface: token-based auth, installed
68
+ * (pre-compiled GSQL) query execution, vertex/edge upsert and retrieval,
69
+ * ad-hoc interpreted queries, and vertex/edge-type schema introspection.
70
+ */
71
+ class TigerGraphStore {
72
+ constructor(options) {
73
+ this.name = 'tigergraph';
74
+ this.library = 'fetch';
75
+ this.token = null;
76
+ this.connected = false;
77
+ if (!options.host) {
78
+ throw new errors_1.ConnectionError('TigerGraphStore requires a "host"', { database: 'tigergraph' });
79
+ }
80
+ if (!options.graph) {
81
+ throw new errors_1.ConnectionError('TigerGraphStore requires a "graph"', { database: 'tigergraph' });
82
+ }
83
+ this.options = options;
84
+ this.restBaseUrl = `${options.host}:${options.restPort ?? 9000}`;
85
+ this.gsqlBaseUrl = `${options.host}:${options.gsqlPort ?? 14240}`;
86
+ this.restPathPrefix = options.restPathPrefix ?? '';
87
+ }
88
+ // ---------------------------------------------------------------------
89
+ // Connection lifecycle
90
+ // ---------------------------------------------------------------------
91
+ async connect() {
92
+ if (this.connected) {
93
+ return;
94
+ }
95
+ try {
96
+ if (this.options.token) {
97
+ this.token = this.options.token;
98
+ }
99
+ else if (this.options.secret) {
100
+ this.token = await this.requestToken(this.options.secret, this.options.tokenLifetime);
101
+ }
102
+ else if (!this.options.username || !this.options.password) {
103
+ throw new Error('no "token", "secret", or "username"/"password" provided - TigerGraph requires one of these to authenticate');
104
+ }
105
+ this.connected = true;
106
+ }
107
+ catch (err) {
108
+ this.token = null;
109
+ this.connected = false;
110
+ throw wrapConnectionError(err, this.options.host);
111
+ }
112
+ }
113
+ async disconnect() {
114
+ this.token = null;
115
+ this.connected = false;
116
+ }
117
+ isConnected() {
118
+ return this.connected;
119
+ }
120
+ /**
121
+ * Returns a small facade over the underlying HTTP transport for
122
+ * operations not wrapped here - there is no native driver client to
123
+ * expose, since this store talks to TigerGraph over plain `fetch`.
124
+ */
125
+ getClient() {
126
+ this.requireConnected();
127
+ return {
128
+ token: this.token,
129
+ restBaseUrl: this.restBaseUrl,
130
+ gsqlBaseUrl: this.gsqlBaseUrl,
131
+ restRequest: (path, init) => this.restRequest(path, init),
132
+ gsqlRequest: (path, init) => this.gsqlRequest(path, init),
133
+ };
134
+ }
135
+ requireConnected() {
136
+ if (!this.connected) {
137
+ throw new errors_1.ConnectionError('Not connected to TigerGraph', { database: 'tigergraph' });
138
+ }
139
+ }
140
+ getFetch() {
141
+ // Resolved per-call (not cached at construction time) so tests can
142
+ // swap `global.fetch` per-test (`jest.spyOn(global, 'fetch')` or
143
+ // reassigning `global.fetch`) and have it take effect immediately.
144
+ return this.options.fetch ?? globalThis.fetch;
145
+ }
146
+ // ---------------------------------------------------------------------
147
+ // Auth
148
+ // ---------------------------------------------------------------------
149
+ /**
150
+ * `POST /requesttoken` - exchange a GSQL secret for a REST++ bearer
151
+ * token. Confirmed request/response shape (pre-4.1 REST++; TigerGraph
152
+ * 4.1+ additionally offers `POST /gsql/v1/tokens` on the unified GSQL
153
+ * port, whose exact request/response shape was not independently
154
+ * confirmed while building this store - see README "Known
155
+ * limitations").
156
+ */
157
+ async requestToken(secret, lifetime) {
158
+ const body = { secret };
159
+ if (lifetime !== undefined) {
160
+ body.lifetime = String(lifetime);
161
+ }
162
+ const fetchImpl = this.getFetch();
163
+ let response;
164
+ try {
165
+ response = await fetchImpl(`${this.restBaseUrl}/requesttoken`, {
166
+ method: 'POST',
167
+ headers: { 'Content-Type': 'application/json' },
168
+ body: JSON.stringify(body),
169
+ });
170
+ }
171
+ catch (err) {
172
+ throw wrapConnectionError(err, this.options.host);
173
+ }
174
+ const json = await this.parseEnvelope(response, 'requesttoken');
175
+ if (!json.token) {
176
+ throw new errors_1.DatabaseError(json.message || 'TigerGraph did not return a token', {
177
+ original: json.message,
178
+ });
179
+ }
180
+ return json.token;
181
+ }
182
+ // ---------------------------------------------------------------------
183
+ // Low-level HTTP helpers
184
+ // ---------------------------------------------------------------------
185
+ async parseEnvelope(response, action) {
186
+ let json;
187
+ try {
188
+ json = (await response.json());
189
+ }
190
+ catch (err) {
191
+ // Non-JSON body (e.g. a gateway/proxy error page). Whether TigerGraph
192
+ // itself ever returns a non-2xx status was not confirmed during
193
+ // research (see README) - surface both the HTTP status and body-parse
194
+ // failure so callers can tell the two failure modes apart.
195
+ throw wrapDatabaseError(err, `TigerGraph ${action} failed (HTTP ${response.status} ${response.statusText}, non-JSON response)`);
196
+ }
197
+ // TigerGraph's documented error signal is `error: true` in the JSON
198
+ // envelope; treat a non-2xx HTTP status as a failure too, since it was
199
+ // not confirmed whether every deployment/version always replies 200
200
+ // with `error: true` (see README "Known limitations").
201
+ if (!response.ok || json.error) {
202
+ const code = json.code ? ` (${json.code})` : '';
203
+ throw new errors_1.DatabaseError(`TigerGraph ${action} failed${code}: ${json.message ?? response.statusText}`, {
204
+ original: json.message,
205
+ });
206
+ }
207
+ return json;
208
+ }
209
+ authHeaders() {
210
+ if (this.token) {
211
+ return { Authorization: `Bearer ${this.token}` };
212
+ }
213
+ return {};
214
+ }
215
+ basicAuthHeaders() {
216
+ const { username, password } = this.options;
217
+ if (username && password) {
218
+ const encoded = Buffer.from(`${username}:${password}`).toString('base64');
219
+ return { Authorization: `Basic ${encoded}` };
220
+ }
221
+ // Fall back to the REST++ bearer token if no Basic-auth credentials
222
+ // were configured. TigerGraph 4.1+ unifies REST++/GSQL auth behind
223
+ // the same token in some configurations, but this fallback was not
224
+ // independently confirmed - prefer configuring `username`/`password`
225
+ // for GSQL-server calls when possible (see README).
226
+ return this.authHeaders();
227
+ }
228
+ /** Issue a request against the REST++ API (vertex/edge/query endpoints), with bearer-token auth. */
229
+ async restRequest(path, init = {}, action = path) {
230
+ this.requireConnected();
231
+ const fetchImpl = this.getFetch();
232
+ let response;
233
+ try {
234
+ response = await fetchImpl(`${this.restBaseUrl}${this.restPathPrefix}${path}`, {
235
+ ...init,
236
+ headers: { ...this.authHeaders(), ...init.headers },
237
+ });
238
+ }
239
+ catch (err) {
240
+ throw wrapConnectionError(err, this.options.host);
241
+ }
242
+ return this.parseEnvelope(response, action);
243
+ }
244
+ /** Issue a request against the GSQL server (interpreted queries, schema), with Basic auth. */
245
+ async gsqlRequest(path, init = {}, action = path) {
246
+ this.requireConnected();
247
+ const fetchImpl = this.getFetch();
248
+ let response;
249
+ try {
250
+ response = await fetchImpl(`${this.gsqlBaseUrl}${path}`, {
251
+ ...init,
252
+ headers: { ...this.basicAuthHeaders(), ...init.headers },
253
+ });
254
+ }
255
+ catch (err) {
256
+ throw wrapConnectionError(err, this.options.host);
257
+ }
258
+ return this.parseEnvelope(response, action);
259
+ }
260
+ // ---------------------------------------------------------------------
261
+ // Installed (pre-compiled GSQL) queries
262
+ // ---------------------------------------------------------------------
263
+ /**
264
+ * Run an installed GSQL query: `GET /query/{graph}/{queryName}?param=value`
265
+ * (simple/scalar params) or `POST /query/{graph}/{queryName}` with a JSON
266
+ * body (complex params, e.g. sets/vertex lists). Confirmed endpoint
267
+ * shape and response envelope (`{version, error, message, results}`).
268
+ */
269
+ async runInstalledQuery(queryName, params = {}, options = {}) {
270
+ const graph = options.graph ?? this.options.graph;
271
+ const method = options.method ?? 'GET';
272
+ const path = `/query/${encodeURIComponent(graph)}/${encodeURIComponent(queryName)}`;
273
+ if (method === 'GET') {
274
+ const qs = new URLSearchParams(params).toString();
275
+ const envelope = await this.restRequest(qs ? `${path}?${qs}` : path, { method: 'GET' }, `installed query "${queryName}"`);
276
+ return envelope.results;
277
+ }
278
+ const envelope = await this.restRequest(path, {
279
+ method: 'POST',
280
+ headers: { 'Content-Type': 'application/json' },
281
+ body: JSON.stringify(params),
282
+ }, `installed query "${queryName}"`);
283
+ return envelope.results;
284
+ }
285
+ // ---------------------------------------------------------------------
286
+ // Vertex/edge upsert
287
+ // ---------------------------------------------------------------------
288
+ /**
289
+ * `POST /graph/{graph}` - raw upsert matching TigerGraph's documented
290
+ * wire format exactly (attribute values pre-wrapped as `{value: x}`).
291
+ * Prefer `upsertVertex`/`upsertVertices`/`upsertEdge`/`upsertEdges` for
292
+ * the common case of plain attribute values.
293
+ */
294
+ async upsert(payload, graph = this.options.graph) {
295
+ const envelope = await this.restRequest(`/graph/${encodeURIComponent(graph)}`, {
296
+ method: 'POST',
297
+ headers: { 'Content-Type': 'application/json' },
298
+ body: JSON.stringify(payload),
299
+ }, 'upsert');
300
+ return envelope.results;
301
+ }
302
+ /** Upsert a single vertex with plain (unwrapped) attribute values. */
303
+ async upsertVertex(vertexType, id, attributes = {}, graph) {
304
+ return this.upsert({ vertices: { [vertexType]: { [id]: toWireAttributes(attributes) } } }, graph ?? this.options.graph);
305
+ }
306
+ /** Upsert multiple vertices of the same type in one round trip. */
307
+ async upsertVertices(vertexType, vertices, graph) {
308
+ const wired = {};
309
+ for (const [id, attrs] of Object.entries(vertices)) {
310
+ wired[id] = toWireAttributes(attrs);
311
+ }
312
+ return this.upsert({ vertices: { [vertexType]: wired } }, graph ?? this.options.graph);
313
+ }
314
+ /** Upsert a single edge with plain (unwrapped) attribute values. */
315
+ async upsertEdge(fromType, fromId, edgeType, toType, toId, attributes = {}, graph) {
316
+ return this.upsertEdges([{ fromType, fromId, edgeType, toType, toId, attributes }], graph);
317
+ }
318
+ /** Upsert multiple edges (possibly spanning different types/vertices) in one round trip. */
319
+ async upsertEdges(edges, graph) {
320
+ var _a, _b, _c;
321
+ const edgeMap = {};
322
+ for (const { fromType, fromId, edgeType, toType, toId, attributes } of edges) {
323
+ edgeMap[fromType] ?? (edgeMap[fromType] = {});
324
+ (_a = edgeMap[fromType])[fromId] ?? (_a[fromId] = {});
325
+ (_b = edgeMap[fromType][fromId])[edgeType] ?? (_b[edgeType] = {});
326
+ (_c = edgeMap[fromType][fromId][edgeType])[toType] ?? (_c[toType] = {});
327
+ edgeMap[fromType][fromId][edgeType][toType][toId] = toWireAttributes(attributes);
328
+ }
329
+ return this.upsert({ edges: edgeMap }, graph ?? this.options.graph);
330
+ }
331
+ // ---------------------------------------------------------------------
332
+ // Vertex/edge retrieval
333
+ // ---------------------------------------------------------------------
334
+ /**
335
+ * `GET /graph/{graph}/vertices/{type}/{id}` - fetch a single vertex by
336
+ * ID. Confirmed endpoint/response shape. Returns `null` if the vertex
337
+ * does not exist (TigerGraph reports this as `error: true` with a
338
+ * "does not exist" message rather than an empty result set).
339
+ */
340
+ async getVertex(vertexType, id, graph) {
341
+ const g = graph ?? this.options.graph;
342
+ const path = `/graph/${encodeURIComponent(g)}/vertices/${encodeURIComponent(vertexType)}/${encodeURIComponent(id)}`;
343
+ try {
344
+ const envelope = await this.restRequest(path, { method: 'GET' }, `get vertex "${vertexType}/${id}"`);
345
+ const results = envelope.results ?? [];
346
+ return results[0] ?? null;
347
+ }
348
+ catch (err) {
349
+ if (err instanceof errors_1.DatabaseError && /does not exist/i.test(err.message)) {
350
+ return null;
351
+ }
352
+ throw err;
353
+ }
354
+ }
355
+ /**
356
+ * `GET /graph/{graph}/vertices/{type}` - list vertices of a type
357
+ * (omitting the ID segment of the single-vertex endpoint above).
358
+ * TigerGraph's built-in-endpoints documentation confirms the
359
+ * single-vertex form; the list form (same resource without an ID, plus
360
+ * an optional `limit` query parameter) follows the standard REST++
361
+ * collection-resource pattern but its full parameter set (`filter`,
362
+ * `select`, `sort`, etc.) was not independently re-verified while
363
+ * building this store - only `limit` is wired up here (see README).
364
+ */
365
+ async listVerticesByType(vertexType, options = {}) {
366
+ const graph = options.graph ?? this.options.graph;
367
+ let path = `/graph/${encodeURIComponent(graph)}/vertices/${encodeURIComponent(vertexType)}`;
368
+ if (options.limit !== undefined) {
369
+ path += `?limit=${encodeURIComponent(options.limit)}`;
370
+ }
371
+ const envelope = await this.restRequest(path, { method: 'GET' }, `list vertices "${vertexType}"`);
372
+ return envelope.results ?? [];
373
+ }
374
+ /** `DELETE /graph/{graph}/vertices/{type}/{id}` - delete a single vertex (and its incident edges). Returns the number of vertices deleted (`0` or `1`). */
375
+ async deleteVertex(vertexType, id, graph) {
376
+ const g = graph ?? this.options.graph;
377
+ const path = `/graph/${encodeURIComponent(g)}/vertices/${encodeURIComponent(vertexType)}/${encodeURIComponent(id)}`;
378
+ const envelope = await this.restRequest(path, { method: 'DELETE' }, `delete vertex "${vertexType}/${id}"`);
379
+ return envelope.results?.deleted_vertices ?? 0;
380
+ }
381
+ /**
382
+ * `GET /graph/{graph}/edges/{fromType}/{fromId}/{edgeType}/{toType}/{toId}`
383
+ * - fetch the edge(s) between two specific vertices. Confirmed
384
+ * endpoint/response shape. Returns an empty array if no such edge
385
+ * exists.
386
+ */
387
+ async getEdge(fromType, fromId, edgeType, toType, toId, graph) {
388
+ const g = graph ?? this.options.graph;
389
+ const path = `/graph/${encodeURIComponent(g)}/edges/${encodeURIComponent(fromType)}/${encodeURIComponent(fromId)}/${encodeURIComponent(edgeType)}/${encodeURIComponent(toType)}/${encodeURIComponent(toId)}`;
390
+ try {
391
+ const envelope = await this.restRequest(path, { method: 'GET' }, `get edge "${fromType}/${fromId}->${toType}/${toId}"`);
392
+ return envelope.results ?? [];
393
+ }
394
+ catch (err) {
395
+ if (err instanceof errors_1.DatabaseError && /does not exist/i.test(err.message)) {
396
+ return [];
397
+ }
398
+ throw err;
399
+ }
400
+ }
401
+ /**
402
+ * `GET /graph/{graph}/edges/{fromType}/{fromId}[/{edgeType}]` - list all
403
+ * edges (of the given type, if provided) originating from a vertex.
404
+ * Same confidence note as `getEdge()`'s partial-path collection form.
405
+ */
406
+ async listEdgesFrom(fromType, fromId, edgeType, graph) {
407
+ const g = graph ?? this.options.graph;
408
+ let path = `/graph/${encodeURIComponent(g)}/edges/${encodeURIComponent(fromType)}/${encodeURIComponent(fromId)}`;
409
+ if (edgeType) {
410
+ path += `/${encodeURIComponent(edgeType)}`;
411
+ }
412
+ const envelope = await this.restRequest(path, { method: 'GET' }, `list edges from "${fromType}/${fromId}"`);
413
+ return envelope.results ?? [];
414
+ }
415
+ /** `DELETE /graph/{graph}/edges/{fromType}/{fromId}/{edgeType}/{toType}/{toId}` - delete a single edge. Returns the number of edges deleted. */
416
+ async deleteEdge(fromType, fromId, edgeType, toType, toId, graph) {
417
+ const g = graph ?? this.options.graph;
418
+ const path = `/graph/${encodeURIComponent(g)}/edges/${encodeURIComponent(fromType)}/${encodeURIComponent(fromId)}/${encodeURIComponent(edgeType)}/${encodeURIComponent(toType)}/${encodeURIComponent(toId)}`;
419
+ const envelope = await this.restRequest(path, { method: 'DELETE' }, `delete edge "${fromType}/${fromId}->${toType}/${toId}"`);
420
+ return envelope.results?.deleted_edges ?? 0;
421
+ }
422
+ // ---------------------------------------------------------------------
423
+ // Ad-hoc "interpreted" GSQL queries
424
+ // ---------------------------------------------------------------------
425
+ /**
426
+ * `POST /gsql/v1/queries/interpret` - compile and run a GSQL query
427
+ * string on the fly, without installing it first. Confirmed endpoint,
428
+ * auth (HTTP Basic, not the REST++ bearer token), and request shape:
429
+ * the request body is the raw GSQL text (`Content-Type: text/plain`),
430
+ * and GSQL query parameters are passed as URL query-string parameters.
431
+ *
432
+ * The older path `/gsqlserver/interpreted_query` (used by some
433
+ * pre-4.x deployments) is documented only in community sources, not in
434
+ * TigerGraph's current official docs, and its exact request shape was
435
+ * not independently confirmed - this store intentionally does not
436
+ * implement that alias rather than guess at its shape. If you're on a
437
+ * version that needs it, issue the request yourself via
438
+ * `getClient().restRequest()`/`gsqlRequest()` (or plain `fetch`) once
439
+ * you've confirmed the shape against your deployment.
440
+ */
441
+ async runInterpretedQuery(gsql, options = {}) {
442
+ const params = options.params ?? {};
443
+ const qs = new URLSearchParams(params).toString();
444
+ const path = qs ? `/gsql/v1/queries/interpret?${qs}` : '/gsql/v1/queries/interpret';
445
+ const envelope = await this.gsqlRequest(path, {
446
+ method: 'POST',
447
+ headers: { 'Content-Type': 'text/plain' },
448
+ body: gsql,
449
+ }, 'interpreted query');
450
+ return envelope.results;
451
+ }
452
+ // ---------------------------------------------------------------------
453
+ // Schema introspection
454
+ // ---------------------------------------------------------------------
455
+ /** `GET /gsql/v1/schema/vertices?graph={graph}` - list the graph's vertex types. Confirmed endpoint/response shape. */
456
+ async listVertexTypes(graph) {
457
+ const g = graph ?? this.options.graph;
458
+ const envelope = await this.gsqlRequest(`/gsql/v1/schema/vertices?graph=${encodeURIComponent(g)}`, { method: 'GET' }, 'list vertex types');
459
+ return envelope.results ?? [];
460
+ }
461
+ /** `GET /gsql/v1/schema/edges?graph={graph}` - list the graph's edge types. Confirmed endpoint/response shape. */
462
+ async listEdgeTypes(graph) {
463
+ const g = graph ?? this.options.graph;
464
+ const envelope = await this.gsqlRequest(`/gsql/v1/schema/edges?graph=${encodeURIComponent(g)}`, { method: 'GET' }, 'list edge types');
465
+ return envelope.results ?? [];
466
+ }
467
+ }
468
+ exports.TigerGraphStore = TigerGraphStore;
469
+ exports.default = TigerGraphStore;
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ /**
3
+ * Typesense store implementation.
4
+ *
5
+ * Typesense is a typo-tolerant search engine built around an inverted index
6
+ * with faceting, filtering and ranking rather than SQL: no `JOIN`, no
7
+ * transaction log, documents grouped into strongly-typed collections (each
8
+ * described by a schema of fields). It therefore does not fit the SQL-shaped
9
+ * `Dialect` interface used by the SQL dialects in this repo. Instead it
10
+ * implements the minimal `NoSqlStore` marker interface (`src/nosql/store.ts`)
11
+ * and exposes Typesense's real capabilities grouped by concern: connection
12
+ * lifecycle, collection management and document CRUD/search.
13
+ *
14
+ * Uses the official `typesense` JS driver. The driver is loaded lazily via
15
+ * `require` so importing this module does not force the dependency to be
16
+ * resolved unless a Typesense store is actually constructed. For unit-testing
17
+ * without a live server, the constructor also accepts an already-built
18
+ * `client`, which `connect()` will use as-is instead of instantiating a new
19
+ * one.
20
+ *
21
+ * Operations are reached through the driver's fluent, resource-scoped API:
22
+ * `client.collections()` / `client.collections(name)` for collections and
23
+ * `client.collections(name).documents()` / `.documents(id)` for documents.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.TypesenseStore = void 0;
27
+ const errors_1 = require("../../errors");
28
+ function wrapConnectionError(err, nodes) {
29
+ const parent = err instanceof Error ? err : new Error(String(err));
30
+ const message = /econnrefused/i.test(parent.message)
31
+ ? 'Connection refused'
32
+ : `Unable to connect to Typesense: ${parent.message}`;
33
+ const first = Array.isArray(nodes) ? nodes[0] : undefined;
34
+ return new errors_1.ConnectionError(message, {
35
+ parent,
36
+ database: 'typesense',
37
+ host: first?.host,
38
+ });
39
+ }
40
+ function wrapDatabaseError(err, message) {
41
+ const parent = err instanceof Error ? err : new Error(String(err));
42
+ const statusCode = err?.httpStatus;
43
+ const detail = statusCode ? `${parent.message} (HTTP ${statusCode})` : parent.message;
44
+ const combined = message ? `${message}: ${detail}` : detail;
45
+ return errors_1.DatabaseError.from(parent, { message: combined });
46
+ }
47
+ /**
48
+ * `TypesenseStore` wraps the official `typesense` client and exposes
49
+ * collection management, document CRUD, and search as a typed, promise-based
50
+ * API.
51
+ */
52
+ class TypesenseStore {
53
+ constructor(options) {
54
+ this.name = 'typesense';
55
+ this.library = 'typesense';
56
+ this.client = null;
57
+ this.connected = false;
58
+ this.options = options;
59
+ }
60
+ // ---------------------------------------------------------------------
61
+ // Connection lifecycle
62
+ // ---------------------------------------------------------------------
63
+ async connect() {
64
+ if (this.connected && this.client) {
65
+ return;
66
+ }
67
+ let client = this.options.client;
68
+ if (!client) {
69
+ // Lazy-load the driver so importing this module doesn't require the
70
+ // dependency to be present unless a store is actually constructed.
71
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
72
+ const Typesense = require('typesense');
73
+ client = new Typesense.Client({ nodes: this.options.nodes, apiKey: this.options.apiKey });
74
+ }
75
+ try {
76
+ // `health.retrieve()` surfaces connection failures (bad host, refused
77
+ // connection) immediately instead of on the caller's first real
78
+ // operation.
79
+ await client.health.retrieve();
80
+ this.client = client;
81
+ this.connected = true;
82
+ }
83
+ catch (err) {
84
+ this.client = null;
85
+ this.connected = false;
86
+ throw wrapConnectionError(err, this.options.nodes);
87
+ }
88
+ }
89
+ async disconnect() {
90
+ // The Typesense client is stateless HTTP; there's no socket to close.
91
+ this.client = null;
92
+ this.connected = false;
93
+ }
94
+ isConnected() {
95
+ return this.connected && this.client !== null;
96
+ }
97
+ /** Returns the underlying `typesense` client for anything not wrapped here. */
98
+ getClient() {
99
+ return this.requireClient();
100
+ }
101
+ requireClient() {
102
+ if (!this.client) {
103
+ throw new errors_1.ConnectionError('Not connected to Typesense', { database: 'typesense' });
104
+ }
105
+ return this.client;
106
+ }
107
+ async exec(fn, action) {
108
+ const client = this.requireClient();
109
+ try {
110
+ return await fn(client);
111
+ }
112
+ catch (err) {
113
+ throw wrapDatabaseError(err, `Typesense ${action} failed`);
114
+ }
115
+ }
116
+ // ---------------------------------------------------------------------
117
+ // Collection management
118
+ // ---------------------------------------------------------------------
119
+ /** Create a collection from a schema (`{ name, fields, default_sorting_field? }`). */
120
+ async createCollection(schema) {
121
+ return this.exec((c) => c.collections().create(schema), 'CREATE COLLECTION');
122
+ }
123
+ /** Delete a collection by name. */
124
+ async deleteCollection(name) {
125
+ return this.exec((c) => c.collections(name).delete(), 'DELETE COLLECTION');
126
+ }
127
+ // ---------------------------------------------------------------------
128
+ // Document CRUD + search
129
+ // ---------------------------------------------------------------------
130
+ /** Index (create) a single document in a collection. */
131
+ async indexDocument(collection, document) {
132
+ return this.exec((c) => c.collections(collection).documents().create(document), 'INDEX DOCUMENT');
133
+ }
134
+ /** Run a search against a collection's documents. */
135
+ async search(collection, params) {
136
+ return this.exec((c) => c.collections(collection).documents().search(params), 'SEARCH');
137
+ }
138
+ /** Retrieve a single document by its `id`. */
139
+ async getDocument(collection, id) {
140
+ return this.exec((c) => c.collections(collection).documents(id).retrieve(), 'GET DOCUMENT');
141
+ }
142
+ /** Delete a single document by its `id`. */
143
+ async deleteDocument(collection, id) {
144
+ return this.exec((c) => c.collections(collection).documents(id).delete(), 'DELETE DOCUMENT');
145
+ }
146
+ }
147
+ exports.TypesenseStore = TypesenseStore;
148
+ exports.default = TypesenseStore;