@oxilite/d1 0.1.0 → 0.3.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/README.md CHANGED
@@ -1,20 +1,140 @@
1
+ <p align="center">
2
+ <a href="https://oxilitedb.com"><img src="https://raw.githubusercontent.com/Volland/oxilite/main/site/assets/logo.png" alt="oxilite" width="120"></a>
3
+ </p>
4
+
1
5
  # @oxilite/d1
2
6
 
3
- An Oxigraph-compatible SPARQL 1.1 store on a Cloudflare D1 database. The oxilite core runs as WebAssembly: SPARQL is compiled to SQL and sent to your `env.DB` binding, so every query is one D1 call and every update is one atomic batch.
7
+ [![npm](https://img.shields.io/npm/v/@oxilite/d1.svg)](https://www.npmjs.com/package/@oxilite/d1) [![license](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](https://github.com/Volland/oxilite#license)
8
+
9
+ **An Oxigraph-compatible SPARQL 1.1 and openCypher store on Cloudflare D1 and Durable Objects.** The oxilite core runs as WebAssembly: it compiles each query to SQL for your `env.DB` binding, so a query is one D1 call and an update is one atomic batch. No Rust toolchain needed.
10
+
11
+ **[Website](https://oxilitedb.com)** · [npm](https://www.npmjs.com/package/@oxilite/d1) · **[Guide and architecture](https://github.com/Volland/oxilite#readme)** · [Changelog and issues](https://github.com/Volland/oxilite/issues)
12
+
13
+ ```bash
14
+ npm install @oxilite/d1
15
+ ```
16
+
17
+ ## 1. Create the schema
18
+
19
+ ```bash
20
+ npx wrangler d1 create my-graph
21
+ npx oxilite-d1 schema > migrations/0001_oxilite.sql # --no-graph-index to save writes
22
+ # --jsonld for JSON-LD / credential tables
23
+ npx wrangler d1 migrations apply my-graph --remote
24
+ ```
25
+
26
+ > **Upgrading to 0.3.0 from 0.2.x:** 0.3.0 adds the `schema_graphs`, `shapes_index`,
27
+ > `shapes_in` and `datalog_work` tables. A D1 store is opened with `open_existing`, so no
28
+ > DDL runs per request and an existing database will report `no such table: schema_graphs`
29
+ > until you apply a new migration. Regenerate and apply it:
30
+ >
31
+ > ```bash
32
+ > npx wrangler d1 migrations create my-graph oxilite-0-3-0
33
+ > npx oxilite-d1 schema > migrations/0002_oxilite-0-3-0.sql
34
+ > npx wrangler d1 migrations apply my-graph --remote
35
+ > ```
36
+ >
37
+ > Every statement is `CREATE TABLE IF NOT EXISTS`, so re-applying it is safe and your data
38
+ > is untouched.
39
+
40
+ ## 2. Query it from a Worker
4
41
 
5
42
  ```ts
6
43
  import { D1Store } from "@oxilite/d1";
7
44
  import wasm from "@oxilite/d1/oxilite.wasm";
8
45
 
9
46
  export default {
10
- async fetch(req: Request, env: { DB: D1Database }) {
47
+ async fetch(req: Request, env: { DB: D1Database }): Promise<Response> {
11
48
  const store = await D1Store.open(env.DB, { wasm, migrated: true });
12
- const q = new URL(req.url).searchParams.get("query") ?? "SELECT * WHERE { ?s ?p ?o } LIMIT 10";
13
- return new Response(await store.queryJson(q), { headers: { "content-type": "application/sparql-results+json" } });
49
+ const url = new URL(req.url);
50
+
51
+ if (req.method === "POST" && url.pathname === "/update") {
52
+ await store.update(await req.text()); // one atomic D1 batch
53
+ return new Response(null, { status: 204 });
54
+ }
55
+ const q = url.searchParams.get("query") ?? "SELECT * WHERE { ?s ?p ?o } LIMIT 10";
56
+ return new Response(await store.queryJson(q), {
57
+ headers: { "content-type": "application/sparql-results+json" },
58
+ });
14
59
  },
15
60
  };
16
61
  ```
17
62
 
18
- Create the schema as a migration with `npx oxilite-d1 schema > migrations/0001_oxilite.sql`. In Node (tests, Miniflare), import from `@oxilite/d1/node`.
63
+ ## Cypher on D1
64
+
65
+ ```ts
66
+ await store.cypher(
67
+ "UNWIND $rows AS row MERGE (p:Person {id: row.id}) SET p.name = row.name",
68
+ { rows: [{ id: 1, name: "Ada" }, { id: 2, name: "Alan" }] },
69
+ { base: "https://example.com/" },
70
+ );
71
+ const r = await store.cypher(
72
+ "MATCH p = shortestPath((a:Person {id: 1})-[:KNOWS*]-(b:Person {id: 2})) RETURN length(p) AS hops",
73
+ {}, { base: "https://example.com/" },
74
+ );
75
+ ```
76
+
77
+ Every Cypher write is one atomic batch; `shortestPath` is a breadth-first search with one request per level. SPARQL and Cypher see the same data.
78
+
79
+ ## JSON-LD documents and Verifiable Credentials on D1
80
+
81
+ ```ts
82
+ const vcs = store.credentials(); // W3C credential contexts are bundled
83
+ const id = await vcs.put(credentialJson); // one D1 batch: JSON row + RDF in graph <id>
84
+ await vcs.putPresentation(presentationJson); // embedded credentials stored too, same batch
85
+ const valid = await vcs.find({ issuer: "did:example:issuer", validAt: new Date() });
86
+ const raw = (await vcs.get(id))?.json; // the exact bytes
87
+
88
+ const docs = store.jsonld(); // any JSON-LD document
89
+ await docs.putContext("https://example.org/my-context", myContext); // persisted in D1
90
+ await docs.put(documentJson);
91
+ ```
92
+
93
+ Contexts load offline: bundled credential contexts, contexts passed in `options.contexts`, and contexts persisted in D1 with `putContext`. A Worker never fetches contexts. Every write is one batch, and a document too large for one batch fails with `document-too-large` rather than being split. Pass `migrated: true` to `jsonld()` / `credentials()` when your migration already created the tables (`oxilite-d1 schema --jsonld`). JSON-LD and credential support adds about 1.7 MB (0.4 MB gzipped) to the wasm module, which stays well within the Workers size limits.
94
+
95
+ ## Durable Objects
96
+
97
+ The same store runs on a Durable Object's embedded SQLite through a small adapter over `ctx.storage.sql`, which gives every agent or user a private graph. [`examples/do-agent-memory-ts`](https://github.com/Volland/oxilite/tree/main/examples/do-agent-memory-ts) is a tested agent-memory Worker built this way.
98
+
99
+ ## API
100
+
101
+ `D1Store` mirrors Oxigraph's JavaScript `Store`, asynchronously: `query`, `queryJson`, `update`, `load`, `bulkLoad`, `dump`, `add`, `delete`, `has`, `match`, `size`, `clear`, plus `cypher`, `explain`, `explainUpdate`, `explainCypher`, `optimize`, `materialize` (OWL 2 RL as SQL rules), `clearInferences`, `jsonld(options)` and `credentials(options)`. Query options add `reasoning: "rdfs" | "owl-ql"` and `include_inferred`; create the store with `textIndex: true` for FTS5 search with `oxl:textMatch`.
102
+
103
+ | Import | Use |
104
+ |---|---|
105
+ | `@oxilite/d1` | Workers: pass the wasm module (`@oxilite/d1/oxilite.wasm`) to `D1Store.open` |
106
+ | `@oxilite/d1/node` | Node.js, tests and Miniflare: the wasm core loads itself |
107
+ | `npx oxilite-d1 schema [--jsonld]` | Print the schema as a D1 migration (with the JSON-LD tables) |
108
+
109
+ ## Tips
110
+
111
+ - Run `store.optimize()` after large imports, not on every request: it refreshes planner statistics.
112
+ - Drop the graph index (`--no-graph-index`, `graphIndex: false`) if you only use the default graph: one fewer index write per triple.
113
+ - Use `explain()` in development to check a query compiles fully to SQL. Queries that need the Rust fallback evaluator report "unsupported" on D1.
114
+
115
+ More in the [D1 guide](https://github.com/Volland/oxilite#using-oxilite-with-cloudflare-d1). A complete Worker with its migration and a Miniflare test is in [`examples/d1-worker-ts`](https://github.com/Volland/oxilite/tree/main/examples/d1-worker-ts).
116
+
117
+ ## The oxilite family
118
+
119
+ oxilite is an Oxigraph-compatible RDF database and SPARQL 1.1 engine that stores its data in SQLite, so it runs anywhere SQLite runs: in-process, on a system or vendor `libsqlite3`, on Cloudflare D1 and in Durable Objects. The same data can be queried with SPARQL and openCypher, reasoned over with RDFS / OWL, and validated with SHACL and ShEx. Read the overview on **[oxilitedb.com](https://oxilitedb.com)** and the full guide in the [main README](https://github.com/Volland/oxilite#readme).
120
+
121
+ | Package | What it is for |
122
+ |---|---|
123
+ | [`oxilite`](https://crates.io/crates/oxilite) | The store: a drop-in for `oxigraph::store::Store`, plus `AsyncStore` for D1 |
124
+ | [`oxilite-core`](https://crates.io/crates/oxilite-core) | The sans-IO core: term encoding, schema, SPARQL → SQL compiler and planner |
125
+ | [`oxilite-rusqlite`](https://crates.io/crates/oxilite-rusqlite) | In-process backend with a bundled SQLite (the default) |
126
+ | [`oxilite-dylib`](https://crates.io/crates/oxilite-dylib) | Backend that loads your own `libsqlite3` at runtime |
127
+ | [`oxilite-d1`](https://crates.io/crates/oxilite-d1) | Cloudflare D1 backend for Rust Workers |
128
+ | [`oxilite-cypher`](https://crates.io/crates/oxilite-cypher) | openCypher over the same data, OWL- and SHACL-aware |
129
+ | [`oxilite-jsonld`](https://crates.io/crates/oxilite-jsonld) | JSON-LD documents stored verbatim, one named graph each |
130
+ | [`oxilite-vc`](https://crates.io/crates/oxilite-vc) | Verifiable Credentials: stored under their id, indexed, queryable |
131
+ | [`oxilite-reason`](https://crates.io/crates/oxilite-reason) | OWL 2 RL materialization with `reasonable` |
132
+ | [`oxilite-validate`](https://crates.io/crates/oxilite-validate) | SHACL and ShEx validation with rudof |
133
+ | [`oxilite-cli`](https://crates.io/crates/oxilite-cli) | The `oxilite` command and a SPARQL endpoint like `oxigraph serve` |
134
+ | [`@oxilite/node`](https://www.npmjs.com/package/@oxilite/node) | Node.js bindings, API of Oxigraph's JS package |
135
+ | [`@oxilite/d1`](https://www.npmjs.com/package/@oxilite/d1) | Cloudflare D1 and Durable Objects from TypeScript (WebAssembly core) |
136
+ | [`@oxilite/common`](https://www.npmjs.com/package/@oxilite/common) | RDF/JS terms and shared TypeScript types |
137
+
138
+ ## License
19
139
 
20
- The API mirrors Oxigraph's JavaScript `Store` (`query`, `update`, `load`, `dump`, `add`, `delete`, `has`, `match`, `size`), asynchronously, plus `explain`, `bulkLoad`, `optimize`, `materialize` (OWL 2 RL) and query options for RDFS / OWL reasoning and full-text search. See the [oxilite repository](https://github.com/Volland/oxilite).
140
+ Dual-licensed under [MIT](https://github.com/Volland/oxilite/blob/main/LICENSE-MIT) or [Apache-2.0](https://github.com/Volland/oxilite/blob/main/LICENSE-APACHE), at your option, like Oxigraph.
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env node
2
- // Usage: npx oxilite-d1 schema [--no-graph-index] > migrations/0001_oxilite.sql
2
+ // Usage: npx oxilite-d1 schema [--no-graph-index] [--jsonld] [--no-metadata-indexes] > migrations/0001_oxilite.sql
3
3
  import { D1Store } from "../dist/node.js";
4
4
 
5
5
  const [command, ...args] = process.argv.slice(2);
6
6
  if (command === "schema") {
7
- process.stdout.write(D1Store.schemaSql({ graphIndex: !args.includes("--no-graph-index") }));
7
+ const jsonld = args.includes("--jsonld")
8
+ ? args.includes("--no-metadata-indexes")
9
+ ? { issuer: false, subject: false, validUntil: false }
10
+ : true
11
+ : false;
12
+ process.stdout.write(D1Store.schemaSql({ graphIndex: !args.includes("--no-graph-index"), jsonld }));
8
13
  } else {
9
- console.error("usage: oxilite-d1 schema [--no-graph-index]");
14
+ console.error("usage: oxilite-d1 schema [--no-graph-index] [--jsonld] [--no-metadata-indexes]");
10
15
  process.exit(1);
11
16
  }
package/dist/driver.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type DumpOptions, type LoadData, type LoadOptions, type Quad, type QueryOptions, type QueryResult, type TermLike } from "@oxilite/common";
1
+ import { type CypherOptions, type DatalogMaterializeResult, type DatalogOptions, type DatalogResult, type CypherResult, type CypherValue, type CredentialOptions, type DocumentFilter, type Drift, type JsonLdOptions, type PresentationKeys, type StoredDocument, type Term, type DumpOptions, type LoadData, type LoadOptions, type Quad, type QueryOptions, type QueryResult, type TermLike } from "@oxilite/common";
2
2
  /** The subset of the Cloudflare D1 binding API used by oxilite. */
3
3
  export interface D1PreparedStatementLike {
4
4
  raw(): Promise<unknown[][]>;
@@ -25,6 +25,11 @@ export interface WasmEngine {
25
25
  query(sparql: string, options?: string | null): WasmJob;
26
26
  queryJson(sparql: string): WasmJob;
27
27
  explain(sparql: string): string;
28
+ cypher(query: string, params?: string | null, options?: string | null): WasmJob;
29
+ datalog?(program: string, options?: string | null): WasmJob;
30
+ datalog_materialize?(program: string, options?: string | null): WasmJob;
31
+ explain_datalog?(program: string, options?: string | null): string;
32
+ explainCypher(query: string, params?: string | null, options?: string | null): string;
28
33
  update(sparql: string, baseIri?: string | null): WasmJob;
29
34
  explainUpdate(sparql: string): string;
30
35
  load(data: string, format: string, base?: string | null, graph?: string | null): WasmJob;
@@ -39,6 +44,8 @@ export interface WasmEngine {
39
44
  materialize(): WasmJob;
40
45
  clearInferences(): WasmJob;
41
46
  schemaSql(): string;
47
+ jsonld(op: string, args: string, options?: string | null): WasmJob;
48
+ jsonldSchemaSql(indexes?: string | null): string;
42
49
  }
43
50
  export type EngineConstructor = new (capabilities?: string | null, options?: string | null) => WasmEngine;
44
51
  /** A term hash collision (two different terms with the same 59-bit id). */
@@ -60,6 +67,49 @@ export declare class D1Store {
60
67
  static openWith(Engine: EngineConstructor, db: D1DatabaseLike, options?: D1StoreOptions): Promise<D1Store>;
61
68
  private execute;
62
69
  private run;
70
+ /**
71
+ * JSON-LD documents: each stored verbatim under a key (by default its `@id`), its RDF in a
72
+ * named graph (by default the key). Every write is one D1 batch. Contexts load offline:
73
+ * persist the ones your documents use with `putContext`.
74
+ */
75
+ jsonld(options?: JsonLdOptions & {
76
+ migrated?: boolean;
77
+ }): D1JsonLdDocuments;
78
+ /**
79
+ * Verifiable Credentials (VCDM 1.1 and 2.0) stored under their `id`, RDF in the graph of the
80
+ * same IRI; the W3C credential contexts are bundled. Proofs are not verified.
81
+ */
82
+ credentials(options?: CredentialOptions & {
83
+ migrated?: boolean;
84
+ }): D1Credentials;
85
+ private jsonldCall;
86
+ /**
87
+ * A Cypher statement over the property-graph view of the dataset. Reads compile to SQL; a
88
+ * writing statement reads, then applies its changes as one D1 batch.
89
+ */
90
+ cypher(query: string, params?: Record<string, CypherValue>, options?: CypherOptions): Promise<CypherResult>;
91
+ /**
92
+ * A Datalog program over the same quads: recursive rules with stratified negation,
93
+ * constraints and aggregation. A program whose recursion is linear is one SQL statement, so
94
+ * it costs one round trip here as it does anywhere; a component that has to be iterated
95
+ * costs one per round, which `rounds` reports.
96
+ */
97
+ datalog(program: string, options?: DatalogOptions): Promise<DatalogResult>;
98
+ /**
99
+ * Stores what a Datalog program derives as inferences, in the table OWL 2 RL
100
+ * materialization uses, so SPARQL and Cypher see them with `includeInferred`. The writes
101
+ * are one D1 batch.
102
+ */
103
+ datalogMaterialize(program: string, options?: DatalogOptions): Promise<DatalogMaterializeResult>;
104
+ /** How a Datalog program runs: its strata, the strategy per recursive component, the SQL. */
105
+ explainDatalog(program: string, options?: DatalogOptions): string;
106
+ /**
107
+ * The Datalog frontend is an opt-in feature of the WebAssembly core, so say which build is
108
+ * needed rather than failing with "not a function".
109
+ */
110
+ private requireDatalog;
111
+ /** How a Cypher statement runs: its SPARQL, the SQL, and what runs in Rust. */
112
+ explainCypher(query: string, params?: Record<string, CypherValue>, options?: CypherOptions): string;
63
113
  /** SPARQL query: `Map[]` for SELECT, `boolean` for ASK, `Quad[]` for CONSTRUCT/DESCRIBE, or a string with `results_format`. */
64
114
  query(query: string, options?: QueryOptions): Promise<QueryResult>;
65
115
  /** SPARQL query returning SPARQL 1.1 JSON results. */
@@ -100,3 +150,46 @@ export declare class D1Store {
100
150
  /** The schema SQL of this store (for `wrangler d1 migrations`). */
101
151
  schemaSql(): string;
102
152
  }
153
+ type AsyncCall = (op: string, args: object) => Promise<unknown>;
154
+ /** JSON-LD documents of a D1 store (see `D1Store.jsonld`). */
155
+ export declare class D1JsonLdDocuments {
156
+ private readonly call;
157
+ constructor(call: AsyncCall);
158
+ /** Stores a document (replacing one with the same key) and returns its key. JSON text is stored byte for byte. */
159
+ put(document: string | object, key?: string): Promise<string>;
160
+ /** Stores several documents in one D1 batch; returns their keys. */
161
+ putAll(documents: {
162
+ document: string | object;
163
+ key?: string;
164
+ }[]): Promise<string[]>;
165
+ get(key: string): Promise<StoredDocument | null>;
166
+ /** Removes a document and the graphs it owns; false when it was not stored. */
167
+ remove(key: string): Promise<boolean>;
168
+ list(options?: {
169
+ after?: string;
170
+ limit?: number;
171
+ }): Promise<StoredDocument[]>;
172
+ find(filter?: DocumentFilter): Promise<StoredDocument[]>;
173
+ graphs(key: string): Promise<Term[]>;
174
+ documentForGraph(graph: TermLike): Promise<StoredDocument | null>;
175
+ /** Persists a context in D1, so documents that reference `iri` convert offline. */
176
+ putContext(iri: string, context: object | string): Promise<void>;
177
+ removeContext(iri: string): Promise<void>;
178
+ contexts(): Promise<string[]>;
179
+ rebuild(key: string): Promise<boolean>;
180
+ check(): Promise<Drift[]>;
181
+ }
182
+ /** Verifiable Credentials of a D1 store (see `D1Store.credentials`). */
183
+ export declare class D1Credentials {
184
+ private readonly call;
185
+ readonly documents: D1JsonLdDocuments;
186
+ constructor(call: AsyncCall);
187
+ /** Checks and stores a credential; returns its key. */
188
+ put(credential: string | object, key?: string): Promise<string>;
189
+ /** Stores a presentation and each credential it embeds, in one D1 batch. */
190
+ putPresentation(presentation: string | object): Promise<PresentationKeys>;
191
+ get(key: string): Promise<StoredDocument | null>;
192
+ remove(key: string): Promise<boolean>;
193
+ find(filter?: DocumentFilter): Promise<StoredDocument[]>;
194
+ }
195
+ export {};
package/dist/driver.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // The core (WebAssembly) never touches the database. Each operation is a job: the driver
4
4
  // feeds it the response of every request it asks for, until it is done. Atomic requests
5
5
  // become one `db.batch()` — D1's only transaction.
6
- import { loadDataToString, outputToResult, toJson, } from "@oxilite/common";
6
+ import { JsonLdError, cypherResult, datalogResult, documentText, filterJson, fromJson, jsonLdError, storedDocument, loadDataToString, outputToResult, toJson, } from "@oxilite/common";
7
7
  /** A term hash collision (two different terms with the same 59-bit id). */
8
8
  export class OxiliteCollisionError extends Error {
9
9
  }
@@ -15,6 +15,9 @@ function mapError(e) {
15
15
  return new Error("the graph does not exist");
16
16
  if (message.includes("graph_already_exists"))
17
17
  return new Error("the graph already exists");
18
+ if (message.includes("jsonld_graphs.g")) {
19
+ return new JsonLdError("graph-owned", `a graph of this document is already owned by another document: ${message}`);
20
+ }
18
21
  if (message.includes("computed_value_not_storable")) {
19
22
  return new Error("an update template stores a computed non-integer value, which cannot be done on D1");
20
23
  }
@@ -66,6 +69,85 @@ export class D1Store {
66
69
  job.free?.();
67
70
  }
68
71
  }
72
+ /**
73
+ * JSON-LD documents: each stored verbatim under a key (by default its `@id`), its RDF in a
74
+ * named graph (by default the key). Every write is one D1 batch. Contexts load offline:
75
+ * persist the ones your documents use with `putContext`.
76
+ */
77
+ jsonld(options = {}) {
78
+ return new D1JsonLdDocuments(this.jsonldCall(options));
79
+ }
80
+ /**
81
+ * Verifiable Credentials (VCDM 1.1 and 2.0) stored under their `id`, RDF in the graph of the
82
+ * same IRI; the W3C credential contexts are bundled. Proofs are not verified.
83
+ */
84
+ credentials(options = {}) {
85
+ return new D1Credentials(this.jsonldCall({ ...options, credentials: true }));
86
+ }
87
+ jsonldCall(options) {
88
+ const { migrated, ...opts } = options;
89
+ const json = JSON.stringify(opts);
90
+ let ready = migrated ? Promise.resolve() : null;
91
+ const call = async (op, args) => {
92
+ try {
93
+ return await this.run(this.engine.jsonld(op, JSON.stringify(args), json));
94
+ }
95
+ catch (e) {
96
+ throw jsonLdError(e);
97
+ }
98
+ };
99
+ return async (op, args) => {
100
+ ready ??= call("schema", {});
101
+ await ready;
102
+ return call(op, args);
103
+ };
104
+ }
105
+ /**
106
+ * A Cypher statement over the property-graph view of the dataset. Reads compile to SQL; a
107
+ * writing statement reads, then applies its changes as one D1 batch.
108
+ */
109
+ async cypher(query, params = {}, options = {}) {
110
+ const out = (await this.run(this.engine.cypher(query, JSON.stringify(params), JSON.stringify(options))));
111
+ return cypherResult(out);
112
+ }
113
+ /**
114
+ * A Datalog program over the same quads: recursive rules with stratified negation,
115
+ * constraints and aggregation. A program whose recursion is linear is one SQL statement, so
116
+ * it costs one round trip here as it does anywhere; a component that has to be iterated
117
+ * costs one per round, which `rounds` reports.
118
+ */
119
+ async datalog(program, options = {}) {
120
+ const datalog = this.requireDatalog(this.engine.datalog);
121
+ const out = (await this.run(datalog(program, JSON.stringify(options))));
122
+ return datalogResult(out);
123
+ }
124
+ /**
125
+ * Stores what a Datalog program derives as inferences, in the table OWL 2 RL
126
+ * materialization uses, so SPARQL and Cypher see them with `includeInferred`. The writes
127
+ * are one D1 batch.
128
+ */
129
+ async datalogMaterialize(program, options = {}) {
130
+ const materialize = this.requireDatalog(this.engine.datalog_materialize);
131
+ return (await this.run(materialize(program, JSON.stringify(options))));
132
+ }
133
+ /** How a Datalog program runs: its strata, the strategy per recursive component, the SQL. */
134
+ explainDatalog(program, options = {}) {
135
+ return this.requireDatalog(this.engine.explain_datalog)(program, JSON.stringify(options));
136
+ }
137
+ /**
138
+ * The Datalog frontend is an opt-in feature of the WebAssembly core, so say which build is
139
+ * needed rather than failing with "not a function".
140
+ */
141
+ requireDatalog(method) {
142
+ if (method === undefined) {
143
+ throw new Error("this build of the oxilite WebAssembly core has no Datalog frontend; rebuild it with the `datalog` feature");
144
+ }
145
+ return method.bind(this.engine);
146
+ }
147
+ /** How a Cypher statement runs: its SPARQL, the SQL, and what runs in Rust. */
148
+ explainCypher(query, params = {}, options = {}) {
149
+ return this.engine.explainCypher(query, JSON.stringify(params), JSON.stringify(options));
150
+ }
69
151
  /** SPARQL query: `Map[]` for SELECT, `boolean` for ASK, `Quad[]` for CONSTRUCT/DESCRIBE, or a string with `results_format`. */
70
152
  async query(query, options = {}) {
71
153
  const js = {
@@ -159,3 +241,82 @@ export class D1Store {
159
241
  return this.engine.schemaSql();
160
242
  }
161
243
  }
244
+ /** JSON-LD documents of a D1 store (see `D1Store.jsonld`). */
245
+ export class D1JsonLdDocuments {
246
+ call;
247
+ constructor(call) {
248
+ this.call = call;
249
+ }
250
+ /** Stores a document (replacing one with the same key) and returns its key. JSON text is stored byte for byte. */
251
+ async put(document, key) {
252
+ return (await this.putAll([{ document, key }]))[0];
253
+ }
254
+ /** Stores several documents in one D1 batch; returns their keys. */
255
+ async putAll(documents) {
256
+ const out = (await this.call("put", {
257
+ documents: documents.map((d) => ({ json: documentText(d.document), key: d.key })),
258
+ }));
259
+ return out.keys;
260
+ }
261
+ async get(key) {
262
+ return storedDocument((await this.call("get", { key })));
263
+ }
264
+ /** Removes a document and the graphs it owns; false when it was not stored. */
265
+ async remove(key) {
266
+ return (await this.call("remove", { key }));
267
+ }
268
+ async list(options = {}) {
269
+ return (await this.call("list", options)).map((d) => storedDocument(d));
270
+ }
271
+ async find(filter = {}) {
272
+ return (await this.call("find", filterJson(filter))).map((d) => storedDocument(d));
273
+ }
274
+ async graphs(key) {
275
+ return (await this.call("graphs", { key })).map(fromJson);
276
+ }
277
+ async documentForGraph(graph) {
278
+ return storedDocument((await this.call("documentForGraph", { graph: toJson(graph) })));
279
+ }
280
+ /** Persists a context in D1, so documents that reference `iri` convert offline. */
281
+ async putContext(iri, context) {
282
+ await this.call("putContext", { iri, context });
283
+ }
284
+ async removeContext(iri) {
285
+ await this.call("removeContext", { iri });
286
+ }
287
+ async contexts() {
288
+ return (await this.call("contexts", {}));
289
+ }
290
+ async rebuild(key) {
291
+ return (await this.call("rebuild", { key }));
292
+ }
293
+ async check() {
294
+ return (await this.call("check", {}));
295
+ }
296
+ }
297
+ /** Verifiable Credentials of a D1 store (see `D1Store.credentials`). */
298
+ export class D1Credentials {
299
+ call;
300
+ documents;
301
+ constructor(call) {
302
+ this.call = call;
303
+ this.documents = new D1JsonLdDocuments(call);
304
+ }
305
+ /** Checks and stores a credential; returns its key. */
306
+ async put(credential, key) {
307
+ return (await this.call("putCredential", { json: documentText(credential), key }));
308
+ }
309
+ /** Stores a presentation and each credential it embeds, in one D1 batch. */
310
+ async putPresentation(presentation) {
311
+ return (await this.call("putPresentation", { json: documentText(presentation) }));
312
+ }
313
+ get(key) {
314
+ return this.documents.get(key);
315
+ }
316
+ remove(key) {
317
+ return this.documents.remove(key);
318
+ }
319
+ async find(filter = {}) {
320
+ return (await this.call("find", filterJson(filter))).map((d) => storedDocument(d));
321
+ }
322
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { D1Store as Base, type D1DatabaseLike, type D1StoreOptions } from "./driver.js";
2
2
  export * from "@oxilite/common";
3
- export { OxiliteCollisionError, type D1DatabaseLike, type D1StoreOptions } from "./driver.js";
3
+ export { OxiliteCollisionError, D1Credentials, D1JsonLdDocuments, type D1DatabaseLike, type D1StoreOptions, } from "./driver.js";
4
4
  /** Initializes the WebAssembly core (a `WebAssembly.Module`, bytes, or a URL/Response). */
5
5
  export declare function initOxilite(wasm?: WebAssembly.Module | BufferSource | Response | URL | string): Promise<void>;
6
6
  export declare class D1Store {
@@ -8,9 +8,17 @@ export declare class D1Store {
8
8
  static open(db: D1DatabaseLike, options?: D1StoreOptions & {
9
9
  wasm?: WebAssembly.Module | BufferSource | Response | URL | string;
10
10
  }): Promise<Base>;
11
- /** The schema as SQL (for `wrangler d1 migrations`). */
11
+ /**
12
+ * The schema as SQL (for `wrangler d1 migrations`); `jsonld` adds the JSON-LD document
13
+ * tables (`true`, or the metadata indexes to create).
14
+ */
12
15
  static schemaSql(options?: {
13
16
  graphIndex?: boolean;
17
+ jsonld?: boolean | {
18
+ issuer?: boolean;
19
+ subject?: boolean;
20
+ validUntil?: boolean;
21
+ };
14
22
  wasm?: WebAssembly.Module | BufferSource;
15
23
  }): Promise<string>;
16
24
  }
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import init, { Engine, initSync } from "../wasm/web/oxilite_wasm.js";
7
7
  import { D1Store as Base } from "./driver.js";
8
8
  export * from "@oxilite/common";
9
- export { OxiliteCollisionError } from "./driver.js";
9
+ export { OxiliteCollisionError, D1Credentials, D1JsonLdDocuments, } from "./driver.js";
10
10
  let ready = false;
11
11
  /** Initializes the WebAssembly core (a `WebAssembly.Module`, bytes, or a URL/Response). */
12
12
  export async function initOxilite(wasm) {
@@ -26,10 +26,15 @@ export class D1Store {
26
26
  await initOxilite(options.wasm);
27
27
  return Base.openWith(Engine, db, options);
28
28
  }
29
- /** The schema as SQL (for `wrangler d1 migrations`). */
29
+ /**
30
+ * The schema as SQL (for `wrangler d1 migrations`); `jsonld` adds the JSON-LD document
31
+ * tables (`true`, or the metadata indexes to create).
32
+ */
30
33
  static async schemaSql(options = {}) {
31
34
  await initOxilite(options.wasm);
32
35
  const e = new Engine(null, JSON.stringify({ graphIndex: options.graphIndex ?? true }));
36
+ if (options.jsonld)
37
+ return e.jsonldSchemaSql(JSON.stringify(options.jsonld === true ? {} : options.jsonld));
33
38
  return e.schemaSql();
34
39
  }
35
40
  }
package/dist/node.d.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  import { D1Store as Base, type D1DatabaseLike, type D1StoreOptions } from "./driver.js";
2
2
  export * from "@oxilite/common";
3
- export { OxiliteCollisionError, type D1DatabaseLike, type D1StoreOptions } from "./driver.js";
3
+ export { OxiliteCollisionError, D1Credentials, D1JsonLdDocuments, type D1DatabaseLike, type D1StoreOptions, } from "./driver.js";
4
4
  export declare class D1Store {
5
5
  static open(db: D1DatabaseLike, options?: D1StoreOptions): Promise<Base>;
6
+ /** The schema as SQL; `jsonld` adds the JSON-LD document tables. */
6
7
  static schemaSql(options?: {
7
8
  graphIndex?: boolean;
9
+ jsonld?: boolean | {
10
+ issuer?: boolean;
11
+ subject?: boolean;
12
+ validUntil?: boolean;
13
+ };
8
14
  }): string;
9
15
  }
package/dist/node.js CHANGED
@@ -2,14 +2,18 @@
2
2
  import { createRequire } from "node:module";
3
3
  import { D1Store as Base } from "./driver.js";
4
4
  export * from "@oxilite/common";
5
- export { OxiliteCollisionError } from "./driver.js";
5
+ export { OxiliteCollisionError, D1Credentials, D1JsonLdDocuments, } from "./driver.js";
6
6
  const require = createRequire(import.meta.url);
7
7
  const { Engine } = require("../wasm/node/oxilite_wasm.js");
8
8
  export class D1Store {
9
9
  static async open(db, options = {}) {
10
10
  return Base.openWith(Engine, db, options);
11
11
  }
12
+ /** The schema as SQL; `jsonld` adds the JSON-LD document tables. */
12
13
  static schemaSql(options = {}) {
13
- return new Engine(null, JSON.stringify({ graphIndex: options.graphIndex ?? true })).schemaSql();
14
+ const e = new Engine(null, JSON.stringify({ graphIndex: options.graphIndex ?? true }));
15
+ if (options.jsonld)
16
+ return e.jsonldSchemaSql(JSON.stringify(options.jsonld === true ? {} : options.jsonld));
17
+ return e.schemaSql();
14
18
  }
15
19
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oxilite/d1",
3
- "version": "0.1.0",
4
- "description": "oxilite on Cloudflare D1: an Oxigraph-compatible SPARQL store running on a D1 binding",
3
+ "version": "0.3.0",
4
+ "description": "oxilite on Cloudflare D1 and Durable Objects: an Oxigraph-compatible SPARQL 1.1 and openCypher store (WebAssembly core)",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -32,7 +32,7 @@
32
32
  "test": "vitest run"
33
33
  },
34
34
  "dependencies": {
35
- "@oxilite/common": "0.1.0"
35
+ "@oxilite/common": "0.3.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "miniflare": "^4"
@@ -42,18 +42,23 @@
42
42
  "url": "git+https://github.com/Volland/oxilite.git",
43
43
  "directory": "packages/d1"
44
44
  },
45
- "homepage": "https://github.com/Volland/oxilite#readme",
45
+ "homepage": "https://oxilitedb.com",
46
46
  "bugs": "https://github.com/Volland/oxilite/issues",
47
47
  "author": "Volodymyr Pavlyshyn",
48
48
  "keywords": [
49
49
  "rdf",
50
50
  "sparql",
51
+ "cypher",
52
+ "opencypher",
53
+ "property-graph",
51
54
  "sqlite",
52
55
  "oxigraph",
53
56
  "rdfjs",
54
57
  "cloudflare",
55
58
  "d1",
56
- "workers"
59
+ "durable-objects",
60
+ "workers",
61
+ "knowledge-graph"
57
62
  ],
58
63
  "publishConfig": {
59
64
  "access": "public"
@@ -23,6 +23,13 @@ export class Engine {
23
23
  * Removes everything.
24
24
  */
25
25
  clear(): Job;
26
+ /**
27
+ * A Cypher statement over the property-graph view (see `oxilite-cypher`). `params` and
28
+ * `options` are JSON (`oxilite_cypher::json`). The result is `{"kind": "cypher",
29
+ * "columns", "rows", "stats"}`; a writing statement applies its changes as one atomic
30
+ * request (one D1 batch).
31
+ */
32
+ cypher(query: string, params?: string | null, options?: string | null): Job;
26
33
  /**
27
34
  * Removes quads (JSON array of RDF/JS quads) atomically.
28
35
  */
@@ -31,6 +38,10 @@ export class Engine {
31
38
  * Serializes the dataset (or one graph, JSON graph term) in an RDF format.
32
39
  */
33
40
  dump(format_name: string, graph?: string | null): Job;
41
+ /**
42
+ * How a Cypher statement runs: its SPARQL, the SQL it compiles to, and what runs in Rust.
43
+ */
44
+ explainCypher(query: string, params?: string | null, options?: string | null): string;
34
45
  /**
35
46
  * How an update would run (SQL per operation).
36
47
  */
@@ -43,6 +54,19 @@ export class Engine {
43
54
  * Does the store contain a quad (JSON RDF/JS quad)?
44
55
  */
45
56
  has(quad: string): Job;
57
+ /**
58
+ * The schema with the JSON-LD tables, as a SQL script; `indexes` (JSON) picks the
59
+ * metadata indexes.
60
+ */
61
+ jsonldSchemaSql(indexes?: string | null): string;
62
+ /**
63
+ * A JSON-LD document or (with `"credentials": true` in `options`) Verifiable Credentials
64
+ * operation: `schema`, `put`, `get`, `remove`, `list`, `find`, `graphs`,
65
+ * `documentForGraph`, `putContext`, `removeContext`, `contexts`, `rebuild`, `check`,
66
+ * `putCredential`, `putPresentation`. `args` and `options` are JSON
67
+ * (`oxilite_jsonld::json`); errors read `oxilite-jsonld:{"code", "message"}`.
68
+ */
69
+ jsonld(op: string, args: string, options?: string | null): Job;
46
70
  /**
47
71
  * Loads a document atomically (one batch). `graph` is a JSON graph term.
48
72
  */
@@ -67,6 +67,29 @@ class Engine {
67
67
  const ret = wasm.engine_clear(this.__wbg_ptr);
68
68
  return Job.__wrap(ret);
69
69
  }
70
+ /**
71
+ * A Cypher statement over the property-graph view (see `oxilite-cypher`). `params` and
72
+ * `options` are JSON (`oxilite_cypher::json`). The result is `{"kind": "cypher",
73
+ * "columns", "rows", "stats"}`; a writing statement applies its changes as one atomic
74
+ * request (one D1 batch).
75
+ * @param {string} query
76
+ * @param {string | null} [params]
77
+ * @param {string | null} [options]
78
+ * @returns {Job}
79
+ */
80
+ cypher(query, params, options) {
81
+ const ptr0 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
82
+ const len0 = WASM_VECTOR_LEN;
83
+ var ptr1 = isLikeNone(params) ? 0 : passStringToWasm0(params, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
84
+ var len1 = WASM_VECTOR_LEN;
85
+ var ptr2 = isLikeNone(options) ? 0 : passStringToWasm0(options, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
86
+ var len2 = WASM_VECTOR_LEN;
87
+ const ret = wasm.engine_cypher(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
88
+ if (ret[2]) {
89
+ throw takeFromExternrefTable0(ret[1]);
90
+ }
91
+ return Job.__wrap(ret[0]);
92
+ }
70
93
  /**
71
94
  * Removes quads (JSON array of RDF/JS quads) atomically.
72
95
  * @param {string} quads
@@ -98,6 +121,37 @@ class Engine {
98
121
  }
99
122
  return Job.__wrap(ret[0]);
100
123
  }
124
+ /**
125
+ * How a Cypher statement runs: its SPARQL, the SQL it compiles to, and what runs in Rust.
126
+ * @param {string} query
127
+ * @param {string | null} [params]
128
+ * @param {string | null} [options]
129
+ * @returns {string}
130
+ */
131
+ explainCypher(query, params, options) {
132
+ let deferred5_0;
133
+ let deferred5_1;
134
+ try {
135
+ const ptr0 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
136
+ const len0 = WASM_VECTOR_LEN;
137
+ var ptr1 = isLikeNone(params) ? 0 : passStringToWasm0(params, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
138
+ var len1 = WASM_VECTOR_LEN;
139
+ var ptr2 = isLikeNone(options) ? 0 : passStringToWasm0(options, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
140
+ var len2 = WASM_VECTOR_LEN;
141
+ const ret = wasm.engine_explainCypher(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
142
+ var ptr4 = ret[0];
143
+ var len4 = ret[1];
144
+ if (ret[3]) {
145
+ ptr4 = 0; len4 = 0;
146
+ throw takeFromExternrefTable0(ret[2]);
147
+ }
148
+ deferred5_0 = ptr4;
149
+ deferred5_1 = len4;
150
+ return getStringFromWasm0(ptr4, len4);
151
+ } finally {
152
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
153
+ }
154
+ }
101
155
  /**
102
156
  * How an update would run (SQL per operation).
103
157
  * @param {string} sparql
@@ -162,6 +216,56 @@ class Engine {
162
216
  }
163
217
  return Job.__wrap(ret[0]);
164
218
  }
219
+ /**
220
+ * The schema with the JSON-LD tables, as a SQL script; `indexes` (JSON) picks the
221
+ * metadata indexes.
222
+ * @param {string | null} [indexes]
223
+ * @returns {string}
224
+ */
225
+ jsonldSchemaSql(indexes) {
226
+ let deferred3_0;
227
+ let deferred3_1;
228
+ try {
229
+ var ptr0 = isLikeNone(indexes) ? 0 : passStringToWasm0(indexes, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
230
+ var len0 = WASM_VECTOR_LEN;
231
+ const ret = wasm.engine_jsonldSchemaSql(this.__wbg_ptr, ptr0, len0);
232
+ var ptr2 = ret[0];
233
+ var len2 = ret[1];
234
+ if (ret[3]) {
235
+ ptr2 = 0; len2 = 0;
236
+ throw takeFromExternrefTable0(ret[2]);
237
+ }
238
+ deferred3_0 = ptr2;
239
+ deferred3_1 = len2;
240
+ return getStringFromWasm0(ptr2, len2);
241
+ } finally {
242
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
243
+ }
244
+ }
245
+ /**
246
+ * A JSON-LD document or (with `"credentials": true` in `options`) Verifiable Credentials
247
+ * operation: `schema`, `put`, `get`, `remove`, `list`, `find`, `graphs`,
248
+ * `documentForGraph`, `putContext`, `removeContext`, `contexts`, `rebuild`, `check`,
249
+ * `putCredential`, `putPresentation`. `args` and `options` are JSON
250
+ * (`oxilite_jsonld::json`); errors read `oxilite-jsonld:{"code", "message"}`.
251
+ * @param {string} op
252
+ * @param {string} args
253
+ * @param {string | null} [options]
254
+ * @returns {Job}
255
+ */
256
+ jsonld(op, args, options) {
257
+ const ptr0 = passStringToWasm0(op, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
258
+ const len0 = WASM_VECTOR_LEN;
259
+ const ptr1 = passStringToWasm0(args, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
260
+ const len1 = WASM_VECTOR_LEN;
261
+ var ptr2 = isLikeNone(options) ? 0 : passStringToWasm0(options, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
262
+ var len2 = WASM_VECTOR_LEN;
263
+ const ret = wasm.engine_jsonld(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
264
+ if (ret[2]) {
265
+ throw takeFromExternrefTable0(ret[1]);
266
+ }
267
+ return Job.__wrap(ret[0]);
268
+ }
165
269
  /**
166
270
  * Loads a document atomically (one batch). `graph` is a JSON graph term.
167
271
  * @param {string} data
Binary file
@@ -7,11 +7,15 @@ export const engine_add: (a: number, b: number, c: number) => [number, number, n
7
7
  export const engine_bulkLoad: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
8
8
  export const engine_clear: (a: number) => number;
9
9
  export const engine_clearInferences: (a: number) => number;
10
+ export const engine_cypher: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
10
11
  export const engine_delete: (a: number, b: number, c: number) => [number, number, number];
11
12
  export const engine_dump: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
12
13
  export const engine_explain: (a: number, b: number, c: number) => [number, number, number, number];
14
+ export const engine_explainCypher: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
13
15
  export const engine_explainUpdate: (a: number, b: number, c: number) => [number, number, number, number];
14
16
  export const engine_has: (a: number, b: number, c: number) => [number, number, number];
17
+ export const engine_jsonld: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
18
+ export const engine_jsonldSchemaSql: (a: number, b: number, c: number) => [number, number, number, number];
15
19
  export const engine_load: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
16
20
  export const engine_match: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
17
21
  export const engine_materialize: (a: number) => number;
@@ -23,6 +23,13 @@ export class Engine {
23
23
  * Removes everything.
24
24
  */
25
25
  clear(): Job;
26
+ /**
27
+ * A Cypher statement over the property-graph view (see `oxilite-cypher`). `params` and
28
+ * `options` are JSON (`oxilite_cypher::json`). The result is `{"kind": "cypher",
29
+ * "columns", "rows", "stats"}`; a writing statement applies its changes as one atomic
30
+ * request (one D1 batch).
31
+ */
32
+ cypher(query: string, params?: string | null, options?: string | null): Job;
26
33
  /**
27
34
  * Removes quads (JSON array of RDF/JS quads) atomically.
28
35
  */
@@ -31,6 +38,10 @@ export class Engine {
31
38
  * Serializes the dataset (or one graph, JSON graph term) in an RDF format.
32
39
  */
33
40
  dump(format_name: string, graph?: string | null): Job;
41
+ /**
42
+ * How a Cypher statement runs: its SPARQL, the SQL it compiles to, and what runs in Rust.
43
+ */
44
+ explainCypher(query: string, params?: string | null, options?: string | null): string;
34
45
  /**
35
46
  * How an update would run (SQL per operation).
36
47
  */
@@ -43,6 +54,19 @@ export class Engine {
43
54
  * Does the store contain a quad (JSON RDF/JS quad)?
44
55
  */
45
56
  has(quad: string): Job;
57
+ /**
58
+ * The schema with the JSON-LD tables, as a SQL script; `indexes` (JSON) picks the
59
+ * metadata indexes.
60
+ */
61
+ jsonldSchemaSql(indexes?: string | null): string;
62
+ /**
63
+ * A JSON-LD document or (with `"credentials": true` in `options`) Verifiable Credentials
64
+ * operation: `schema`, `put`, `get`, `remove`, `list`, `find`, `graphs`,
65
+ * `documentForGraph`, `putContext`, `removeContext`, `contexts`, `rebuild`, `check`,
66
+ * `putCredential`, `putPresentation`. `args` and `options` are JSON
67
+ * (`oxilite_jsonld::json`); errors read `oxilite-jsonld:{"code", "message"}`.
68
+ */
69
+ jsonld(op: string, args: string, options?: string | null): Job;
46
70
  /**
47
71
  * Loads a document atomically (one batch). `graph` is a JSON graph term.
48
72
  */
@@ -122,11 +146,15 @@ export interface InitOutput {
122
146
  readonly engine_bulkLoad: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
123
147
  readonly engine_clear: (a: number) => number;
124
148
  readonly engine_clearInferences: (a: number) => number;
149
+ readonly engine_cypher: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
125
150
  readonly engine_delete: (a: number, b: number, c: number) => [number, number, number];
126
151
  readonly engine_dump: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
127
152
  readonly engine_explain: (a: number, b: number, c: number) => [number, number, number, number];
153
+ readonly engine_explainCypher: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
128
154
  readonly engine_explainUpdate: (a: number, b: number, c: number) => [number, number, number, number];
129
155
  readonly engine_has: (a: number, b: number, c: number) => [number, number, number];
156
+ readonly engine_jsonld: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
157
+ readonly engine_jsonldSchemaSql: (a: number, b: number, c: number) => [number, number, number, number];
130
158
  readonly engine_load: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
131
159
  readonly engine_match: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
132
160
  readonly engine_materialize: (a: number) => number;
@@ -67,6 +67,29 @@ export class Engine {
67
67
  const ret = wasm.engine_clear(this.__wbg_ptr);
68
68
  return Job.__wrap(ret);
69
69
  }
70
+ /**
71
+ * A Cypher statement over the property-graph view (see `oxilite-cypher`). `params` and
72
+ * `options` are JSON (`oxilite_cypher::json`). The result is `{"kind": "cypher",
73
+ * "columns", "rows", "stats"}`; a writing statement applies its changes as one atomic
74
+ * request (one D1 batch).
75
+ * @param {string} query
76
+ * @param {string | null} [params]
77
+ * @param {string | null} [options]
78
+ * @returns {Job}
79
+ */
80
+ cypher(query, params, options) {
81
+ const ptr0 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
82
+ const len0 = WASM_VECTOR_LEN;
83
+ var ptr1 = isLikeNone(params) ? 0 : passStringToWasm0(params, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
84
+ var len1 = WASM_VECTOR_LEN;
85
+ var ptr2 = isLikeNone(options) ? 0 : passStringToWasm0(options, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
86
+ var len2 = WASM_VECTOR_LEN;
87
+ const ret = wasm.engine_cypher(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
88
+ if (ret[2]) {
89
+ throw takeFromExternrefTable0(ret[1]);
90
+ }
91
+ return Job.__wrap(ret[0]);
92
+ }
70
93
  /**
71
94
  * Removes quads (JSON array of RDF/JS quads) atomically.
72
95
  * @param {string} quads
@@ -98,6 +121,37 @@ export class Engine {
98
121
  }
99
122
  return Job.__wrap(ret[0]);
100
123
  }
124
+ /**
125
+ * How a Cypher statement runs: its SPARQL, the SQL it compiles to, and what runs in Rust.
126
+ * @param {string} query
127
+ * @param {string | null} [params]
128
+ * @param {string | null} [options]
129
+ * @returns {string}
130
+ */
131
+ explainCypher(query, params, options) {
132
+ let deferred5_0;
133
+ let deferred5_1;
134
+ try {
135
+ const ptr0 = passStringToWasm0(query, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
136
+ const len0 = WASM_VECTOR_LEN;
137
+ var ptr1 = isLikeNone(params) ? 0 : passStringToWasm0(params, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
138
+ var len1 = WASM_VECTOR_LEN;
139
+ var ptr2 = isLikeNone(options) ? 0 : passStringToWasm0(options, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
140
+ var len2 = WASM_VECTOR_LEN;
141
+ const ret = wasm.engine_explainCypher(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
142
+ var ptr4 = ret[0];
143
+ var len4 = ret[1];
144
+ if (ret[3]) {
145
+ ptr4 = 0; len4 = 0;
146
+ throw takeFromExternrefTable0(ret[2]);
147
+ }
148
+ deferred5_0 = ptr4;
149
+ deferred5_1 = len4;
150
+ return getStringFromWasm0(ptr4, len4);
151
+ } finally {
152
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
153
+ }
154
+ }
101
155
  /**
102
156
  * How an update would run (SQL per operation).
103
157
  * @param {string} sparql
@@ -162,6 +216,56 @@ export class Engine {
162
216
  }
163
217
  return Job.__wrap(ret[0]);
164
218
  }
219
+ /**
220
+ * The schema with the JSON-LD tables, as a SQL script; `indexes` (JSON) picks the
221
+ * metadata indexes.
222
+ * @param {string | null} [indexes]
223
+ * @returns {string}
224
+ */
225
+ jsonldSchemaSql(indexes) {
226
+ let deferred3_0;
227
+ let deferred3_1;
228
+ try {
229
+ var ptr0 = isLikeNone(indexes) ? 0 : passStringToWasm0(indexes, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
230
+ var len0 = WASM_VECTOR_LEN;
231
+ const ret = wasm.engine_jsonldSchemaSql(this.__wbg_ptr, ptr0, len0);
232
+ var ptr2 = ret[0];
233
+ var len2 = ret[1];
234
+ if (ret[3]) {
235
+ ptr2 = 0; len2 = 0;
236
+ throw takeFromExternrefTable0(ret[2]);
237
+ }
238
+ deferred3_0 = ptr2;
239
+ deferred3_1 = len2;
240
+ return getStringFromWasm0(ptr2, len2);
241
+ } finally {
242
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
243
+ }
244
+ }
245
+ /**
246
+ * A JSON-LD document or (with `"credentials": true` in `options`) Verifiable Credentials
247
+ * operation: `schema`, `put`, `get`, `remove`, `list`, `find`, `graphs`,
248
+ * `documentForGraph`, `putContext`, `removeContext`, `contexts`, `rebuild`, `check`,
249
+ * `putCredential`, `putPresentation`. `args` and `options` are JSON
250
+ * (`oxilite_jsonld::json`); errors read `oxilite-jsonld:{"code", "message"}`.
251
+ * @param {string} op
252
+ * @param {string} args
253
+ * @param {string | null} [options]
254
+ * @returns {Job}
255
+ */
256
+ jsonld(op, args, options) {
257
+ const ptr0 = passStringToWasm0(op, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
258
+ const len0 = WASM_VECTOR_LEN;
259
+ const ptr1 = passStringToWasm0(args, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
260
+ const len1 = WASM_VECTOR_LEN;
261
+ var ptr2 = isLikeNone(options) ? 0 : passStringToWasm0(options, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
262
+ var len2 = WASM_VECTOR_LEN;
263
+ const ret = wasm.engine_jsonld(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
264
+ if (ret[2]) {
265
+ throw takeFromExternrefTable0(ret[1]);
266
+ }
267
+ return Job.__wrap(ret[0]);
268
+ }
165
269
  /**
166
270
  * Loads a document atomically (one batch). `graph` is a JSON graph term.
167
271
  * @param {string} data
Binary file
@@ -7,11 +7,15 @@ export const engine_add: (a: number, b: number, c: number) => [number, number, n
7
7
  export const engine_bulkLoad: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
8
8
  export const engine_clear: (a: number) => number;
9
9
  export const engine_clearInferences: (a: number) => number;
10
+ export const engine_cypher: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
10
11
  export const engine_delete: (a: number, b: number, c: number) => [number, number, number];
11
12
  export const engine_dump: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
12
13
  export const engine_explain: (a: number, b: number, c: number) => [number, number, number, number];
14
+ export const engine_explainCypher: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
13
15
  export const engine_explainUpdate: (a: number, b: number, c: number) => [number, number, number, number];
14
16
  export const engine_has: (a: number, b: number, c: number) => [number, number, number];
17
+ export const engine_jsonld: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
18
+ export const engine_jsonldSchemaSql: (a: number, b: number, c: number) => [number, number, number, number];
15
19
  export const engine_load: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
16
20
  export const engine_match: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => [number, number, number];
17
21
  export const engine_materialize: (a: number) => number;