DgraphStore — Dgraph native graph database
Read this page in the documentation
DgraphStore — Dgraph native graph database Overview Dgraph is a distributed, native graph database queried with DQL (its GraphQL-derived query language) rather than SQL. Data is modeled as nodes (identified by UIDs) and typed predicates/edges between them, with an optional schema defined via alter. It has no Dialect-shaped query(sql) / identifier-escaping surface, so it does not fit the SQL dialect interface used elsewhere in this repo. Instead, DgraphStore implements the minimal NoSqlStore marker interface (src/nosql/store.ts) — connection lifecycle plus a getClient() escape hatch — and exposes Dgraph's real primitives (parameterized DQL queries, JSON mutations, and schema alter/dropAll) directly. Identity: Property | Value | --------- | ------------ | name | 'dgraph' | library | 'dgraph-js' | The store is built on the official dgraph-js gRPC driver: connect() builds a DgraphClientStub(address) and wraps it in a DgraphClient. Lazy loading — not a hard dependency dgraph-js is an optional peer dependency, loaded lazily via require('dgraph-js') inside connect(), rather than a top-level import. Importing this module therefore never forces the driver to be installed — it is only needed when a Dgraph store is actually connected against a real cluster. Injected client DgraphStoreOptions accepts a pre-built client (a dgraph-js DgraphClient, or a compatible DgraphClientLike mock). When provided, connect() uses it directly and never touches the real driver (require('dgraph-js') is skipped, and no stub is created). This is how the test suite injects a mock (no driver, no network), and how callers can supply a custom-configured client. Connection Build a store from connection options and call connect(): DgraphStoreOptions: Option | Type | Purpose | --------- | ------------------ | ----------------------------------------------------------------------------- | address | string | Dgraph Alpha gRPC address, e.g. 'localhost:9080'. | client | DgraphClientLike | A pre-built DgraphClient (or mock). When set, the driver is never required. | connect() is idempotent: if already connected with a live client, it returns immediately. Connection failures are wrapped in a ConnectionError (message Unable to connect to Dgraph: ...), and connection state is reset. Injected-client form Supply your own client (or a mock) to bypass driver-based client construction: Methods Using any operation before connect() (or after disconnect()) throws a ConnectionError via the internal requireClient() guard. Operation failures are wrapped in a DatabaseError (message Dgraph <action> failed: ..., preserving the original error). Lifecycle Method | Signature | Behavior | ------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | connect | connect(): Promise<void> | Uses an injected client if provided, otherwise lazy-requires dgraph-js, builds a DgraphClientStub(address), and wraps it in a DgraphClient. Idempotent. Wraps failures in ConnectionError. | disconnect | disconnect(): Promise<void> | Closes the client stub's gRPC channel (stub.close()) if one was created, then clears the client and connection state. (No stub exists for an injected client.) | isConnected | isConnected(): boolean | true only when connected and a client is present. | getClient | getClient(): DgraphClientLike | Returns the underlying DgraphClient for operations not wrapped here. Throws ConnectionError if not connected. | Query / mutate Both open a fresh transaction via client.newTxn() and always discard() it in a finally. Method | Signature | Behavior | -------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | query | query<T = Record<string, unknown>>(dql: string, vars?: Record<string, string>): Promise<T> | Runs a parameterized DQL query (txn.queryWithVars(dql, vars)) in a fresh transaction and returns the parsed JSON result (JSON.parse(res.getJson())). vars binds DQL query variables (e.g. { $name: 'alice' }) and defaults to {}. The read-only txn is always discarded in finally (no commit needed). | mutate | mutate(setJson: Record<string, unknown> \| unknown[]): Promise<unknown> | Applies a JSON mutation (txn.mutate({ setJson, commitNow: true })), committing immediately so no separate commit round trip is needed. The txn is discarded in finally as a safety net (a no-op after commit). | Schema / data management Method | Signature | Behavior | --------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------- | alter | alter(schema: string): Promise<unknown> | Alters the schema by forwarding a DQL schema definition to client.alter({ schema }), e.g. 'name: string @index(exact) .'. | dropAll | dropAll(): Promise<unknown> | Drops all data and schema in the cluster via client.alter({ dropAll: true }). | Example Verification status Unit / mock-verified only. The tests in tests/nosql/dgraph.test.ts are pure unit tests: a fake DgraphClient whose newTxn() returns a spy-backed transaction (queryWithVars/mutate/discard) and whose alter is a jest spy is injected via DgraphStoreOptions.client. The real dgraph-js driver is not installed and there is no network — because a client is injected, connect() never reaches require('dgraph-js'). What this proves: query() runs DQL in a new txn (newTxn() called once), calls queryWithVars(dql, vars), parses getJson(), and returns the object; vars defaults to {}; the txn is discarded in finally even when the query throws (wrapped in DatabaseError). mutate() calls txn.mutate({ setJson, commitNow: true }), returns the result, and discards the txn in finally (including when the mutation throws, wrapped in DatabaseError). alter() forwards { schema }; dropAll() forwards { dropAll: true }; alter failures are wrapped in DatabaseError. Lifecycle: connecting via the injected client without loading the driver, idempotent connect/disconnect, and ConnectionError from getClient() / operations before connect(). What this does not prove: live execution against a real Dgraph cluster, nor the real-driver connect() path that builds a DgraphClientStub/DgraphClient and the gRPC channel closed by disconnect(). The call shapes are verified against the dgraph-js API contract, but end-to-end graph access over the wire has not been exercised here. Related reading All data stores — the full catalogue, grouped by purpose Database types — where this sits among the 22 categories