@antelopejs/interface-database 0.1.9 → 0.1.10

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,29 +1,104 @@
1
- # Interface Database
1
+ # @antelopejs/interface-database
2
2
 
3
3
  <div align="center">
4
- <a href="https://www.npmjs.com/package/@antelopejs/interface-database"><img src="https://img.shields.io/npm/v/@antelopejs/interface-database?style=for-the-badge&labelColor=000000&color=000000" alt="npm"></a>
5
- <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=for-the-badge&labelColor=000000"></a>
6
- <a href="https://discord.gg/sjK28QHrA7"><img src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000" alt="Discord"></a>
7
- <a href="./docs/index.md"><img src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000" alt="Documentation"></a>
4
+ <a href="https://www.npmjs.com/package/@antelopejs/interface-database"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-database?style=for-the-badge&labelColor=000000&color=000000"></a>
5
+ <a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-database?style=for-the-badge&labelColor=000000&color=000000"></a>
6
+ <a href="https://discord.gg/sjK28QHrA7"><img alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
7
+ <a href="https://interfaces.antelopejs.com/docs/database"><img alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
8
8
  </div>
9
9
 
10
- A database-agnostic query interface that provides consistent operations across different database implementations. Interface Database brings AQL (Antelope Query Language) to your projects, enabling you to write database code that works seamlessly with multiple database backends through a chainable, type-safe API inspired by ReQL.
10
+ AQL (Antelope Query Language), the database-agnostic query builder of AntelopeJS: write a chainable, typed query once and run it on any database module that implements the interface.
11
11
 
12
- ## Installation
12
+ ## What it offers
13
+
14
+ - `Schema` declares tables, fields and indexes; each schema can hold several isolated instances.
15
+ - `Table`, `Selection` and `SingleSelection` insert, read, update and delete documents.
16
+ - `Stream` filters, maps, joins, groups and aggregates; `ValueProxy` builds the expressions inside them.
17
+ - `changes()` streams inserts, updates and deletions as they happen.
18
+ - Queries are lazy: nothing runs until you `await` them, call `.run()` or iterate them.
19
+
20
+ ## Implementations
21
+
22
+ | Module | Notes |
23
+ | ------------------------------------------------------------------ | ------------------------------------------------------------ |
24
+ | [`@antelopejs/mongodb`](https://github.com/AntelopeJS/mongodb) | MongoDB; also implements `@antelopejs/interface-mongodb` |
25
+ | [`@antelopejs/rethinkdb`](https://github.com/AntelopeJS/rethinkdb) | RethinkDB; also implements `@antelopejs/interface-rethinkdb` |
26
+
27
+ ## Install
28
+
29
+ Add the interface to the module that runs queries:
13
30
 
14
31
  ```bash
15
- npm install @antelopejs/interface-database
32
+ pnpm add @antelopejs/interface-database
33
+ ```
34
+
35
+ Then add an implementation to the project:
36
+
37
+ ```bash
38
+ ajs project modules add @antelopejs/mongodb
39
+ ```
40
+
41
+ ## Quick start
42
+
43
+ ```ts
44
+ import { Schema } from "@antelopejs/interface-database";
45
+
46
+ interface Novel {
47
+ _id?: string;
48
+ title: string;
49
+ pageCount: number;
50
+ }
51
+
52
+ const schema = new Schema<{ novels: Novel }>("library", {
53
+ novels: {
54
+ fields: { title: "string", pageCount: "number" },
55
+ indexes: { pageCount: {} },
56
+ },
57
+ });
58
+
59
+ const novels = schema.instance().table("novels");
60
+
61
+ export async function addNovel(title: string, pageCount: number) {
62
+ return await novels.insert({ title, pageCount });
63
+ }
64
+
65
+ export async function listLongNovels() {
66
+ return await novels
67
+ .filter((novel) => novel.key("pageCount").ge(300))
68
+ .orderBy("pageCount", "desc");
69
+ }
16
70
  ```
17
71
 
72
+ Callbacks such as the `filter` above receive a `ValueProxy`, not a document: only its methods travel to the database.
73
+
18
74
  ## Documentation
19
75
 
20
- Detailed documentation is available in the `docs` directory:
76
+ - [Overview and import paths](./docs/index.md)
77
+ - [Query types](./docs/1.query_types/1.index.md)
78
+ - [Operations](./docs/2.operations/1.index.md)
79
+ - [Atomic mutations](./docs/2.operations/8.atomic_mutations.md)
80
+ - [Results](./docs/3.results/1.index.md)
81
+
82
+ ## Compatibility
83
+
84
+ Requires AntelopeJS core `1.x` and the following peer dependency:
21
85
 
22
- - [Overview](./docs/index.md) - Introduction and documentation structure
23
- - [Query Types](./docs/1.query_types/1.index.md) - Table, Selection, Stream, Datum, ValueProxy, and other query types
24
- - [Operations](./docs/2.operations/1.index.md) - Schema management, CRUD operations, filtering, and lookups
25
- - [Results](./docs/3.results/1.index.md) - Result types and change feed handling
86
+ <!-- docs-compat: ./package.json#peerDependencies -->
87
+
88
+ | Package | Range |
89
+ | ---------------------------- | ---------------- |
90
+ | `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` |
91
+
92
+ ## Contributing
93
+
94
+ Read [CONTRIBUTING.md](./CONTRIBUTING.md) before you open a pull request. The local checks are:
95
+
96
+ ```bash
97
+ pnpm install
98
+ pnpm lint
99
+ pnpm test
100
+ ```
26
101
 
27
102
  ## License
28
103
 
29
- This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
104
+ [Apache-2.0](./LICENSE)
@@ -6,6 +6,10 @@ The `Table<T>` class represents a database table and provides methods for insert
6
6
 
7
7
  ```typescript
8
8
  class Table<T> extends Selection<T> {
9
+ atomicMutation(
10
+ id: string,
11
+ request: AtomicMutation<T>,
12
+ ): Query<AtomicMutationOutcome>;
9
13
  insert(
10
14
  obj: DeepPartial<T> | DeepPartial<T>[],
11
15
  options?: InsertOptions,
@@ -74,6 +78,8 @@ const upsertIds = await users.insert(
74
78
 
75
79
  Retrieve a single document by its primary key. Returns a `SingleSelection<T>`.
76
80
 
81
+ Awaiting this selection is declared as `T`, not `T | null`. The declaration does not prove a row exists; providers can return `null` for missing keys, so check before reading fields.
82
+
77
83
  ```typescript
78
84
  const user = await users.get("user-123");
79
85
 
@@ -108,6 +114,8 @@ const recent = await users.between(
108
114
 
109
115
  ## Inherited Methods
110
116
 
117
+ For conditional single-record writes, see [Atomic Mutations](../2.operations/8.atomic_mutations.md). `atomicMutation()` is a table method, not a selection method; it returns an explicit outcome rather than a modified count.
118
+
111
119
  Since `Table` extends `Selection`, which extends `Stream`, it inherits:
112
120
 
113
121
  - **Selection methods**: `update()`, `replace()`, `delete()` -- see [Selection](./3.selection.md)
@@ -32,6 +32,8 @@ const user = users.get("user-123");
32
32
 
33
33
  Since `SingleSelection` extends `Datum`, you can execute it directly to retrieve the document value:
34
34
 
35
+ The declared result is `T`, even though a provider can return `null` for a missing key. Check for absence before accessing the document; the generic type is not an existence guarantee.
36
+
35
37
  ```typescript
36
38
  const user = await users.get("user-123");
37
39
 
@@ -98,9 +100,7 @@ if (count === 1) {
98
100
  The `changes` method returns change events for the document. Each event contains a `changeType` and the `oldValue`/`newValue` of the document.
99
101
 
100
102
  ```typescript
101
- const changes = await users.get("user-123").changes();
102
-
103
- for (const change of changes) {
103
+ for await (const change of users.get("user-123").changes()) {
104
104
  console.log("Type:", change.changeType); // "added" | "removed" | "modified"
105
105
  console.log("Old:", change.oldValue);
106
106
  console.log("New:", change.newValue);
@@ -10,7 +10,9 @@ class Stream<T> extends Query<T[]> {
10
10
  cast<U>(): Stream<U>;
11
11
 
12
12
  // Field access
13
- key<K extends keyof T>(key: K, def?: unknown): Stream<T[K]>;
13
+ key<K extends keyof T, U = undefined>(key: K, def?: U): Stream<
14
+ U extends undefined ? T[K] : Exclude<T[K], undefined | null> | U
15
+ >;
14
16
  default<U>(val: Value<U>): Stream<Exclude<T, undefined | null> | U>;
15
17
 
16
18
  // Transformation
@@ -53,6 +55,8 @@ class Stream<T> extends Query<T[]> {
53
55
 
54
56
  Access a specific field from all documents in the stream with `key()`, or provide a default value for null fields with `default()`.
55
57
 
58
+ `key(field, fallback)` also accepts a fallback. When it is not `undefined`, the result type excludes `null` and `undefined` from the field type and includes the fallback's type; without it, the declared field type is unchanged.
59
+
56
60
  ```typescript
57
61
  const users = schema.instance().table("users");
58
62
 
@@ -20,7 +20,7 @@ interface Changes<T> {
20
20
 
21
21
  ## Create a Change Feed
22
22
 
23
- Call `changes()` on any stream or single selection to subscribe to change events:
23
+ Call `changes()` on a stream or single selection to build a feed query. Consume it with async iteration to receive events as they arrive:
24
24
 
25
25
  ```typescript
26
26
  import { Schema } from "@antelopejs/interface-database";
@@ -29,10 +29,10 @@ const schema = Schema.get("myapp")!;
29
29
  const users = schema.instance().table("users");
30
30
 
31
31
  // Monitor all changes to a table
32
- const allChanges = await users.changes();
32
+ const allChanges = users.changes();
33
33
 
34
34
  // Monitor changes to a specific document
35
- const userChanges = await users.get("user-123").changes();
35
+ const userChanges = users.get("user-123").changes();
36
36
  ```
37
37
 
38
38
  ## Process Change Events
@@ -40,38 +40,45 @@ const userChanges = await users.get("user-123").changes();
40
40
  Each change event includes a `changeType` field that indicates the nature of the change:
41
41
 
42
42
  ```typescript
43
- const changes = await users.changes();
44
-
45
- for (const change of changes) {
46
- switch (change.changeType) {
47
- case "added":
48
- console.log("New document:", change.newValue);
49
- break;
50
- case "modified":
51
- console.log("Updated from:", change.oldValue);
52
- console.log("Updated to:", change.newValue);
53
- break;
54
- case "removed":
55
- console.log("Deleted document:", change.oldValue);
56
- break;
43
+ for await (const change of users.changes()) {
44
+ if (change.changeType === "added") {
45
+ console.log("New document:", change.newValue);
46
+ } else if (change.changeType === "modified") {
47
+ console.log("Updated from:", change.oldValue);
48
+ console.log("Updated to:", change.newValue);
49
+ } else {
50
+ console.log("Deleted document:", change.oldValue);
57
51
  }
58
52
  }
59
53
  ```
60
54
 
61
55
  ## Use with Async Iteration
62
56
 
63
- Since `changes()` returns a `Query`, you can use the cursor for streaming results:
57
+ `changes()` returns `Query<Changes<T>[]>`, but `Query`'s cursor and async iterator yield each array element: one `Changes<T>` event, not a batch. A direct `await` uses `run()` and asks the provider for a completed result; an open-ended feed may never complete, so use iteration for continuous monitoring.
64
58
 
65
- ```typescript
66
- const feed = users.changes();
59
+ ```ts docs-check
60
+ import { Schema } from "@antelopejs/interface-database";
61
+ import type { Changes } from "@antelopejs/interface-database/common";
62
+
63
+ interface User {
64
+ _id: string;
65
+ name: string;
66
+ }
67
+
68
+ export async function watchUsers(onChange: (change: Changes<User>) => boolean) {
69
+ const schema = Schema.get<{ users: User }>("myapp");
70
+ if (!schema) throw new Error("Register the myapp schema first");
71
+ const feed = schema.instance().table("users").changes();
67
72
 
68
- for await (const batch of feed) {
69
- for (const change of batch) {
73
+ for await (const change of feed) {
70
74
  console.log(`${change.changeType}:`, change.newValue ?? change.oldValue);
75
+ if (!onChange(change)) break;
71
76
  }
72
77
  }
73
78
  ```
74
79
 
80
+ Breaking out of the loop closes its cursor. When using `cursor()` manually, call `return()` when finished.
81
+
75
82
  ## Use Cases
76
83
 
77
84
  Change feeds are well suited for:
@@ -41,6 +41,8 @@ Both approaches are equivalent. Use whichever reads better in context.
41
41
 
42
42
  ## Async Iteration
43
43
 
44
+ Array-valued queries yield one element at a time, including one `Changes<T>` event per iteration of a change feed. [Atomic mutations](../2.operations/8.atomic_mutations.md) are an exception: they reject cursor execution and must be awaited directly or executed with `run()`.
45
+
44
46
  ### `cursor()`
45
47
 
46
48
  Return an `AsyncGenerator` that yields results one at a time. This is useful for processing large result sets without loading everything into memory.
@@ -7,7 +7,9 @@ The `Datum<T>` class represents a single value in the query system. It extends `
7
7
  ```typescript
8
8
  class Datum<T> extends Query<T> {
9
9
  cast<U>(): Datum<U>;
10
- key<K extends keyof NonNullable<T>>(key: K, def?: unknown): Datum<NonNullable<T>[K]>;
10
+ key<K extends keyof NonNullable<T>, U = undefined>(key: K, def?: U): Datum<
11
+ U extends undefined ? NonNullable<T>[K] : NonNullable<NonNullable<T>[K]> | U
12
+ >;
11
13
  default<U>(val: Value<U>): Datum<Exclude<T, undefined | null> | U>;
12
14
  do<U>(mapper: (val: ValueProxy<T>) => U): Datum<ExtractType<U>>;
13
15
  lookup<U>(other: Selection<U>, localKey: keyof T, otherKey: keyof U): Datum<...>;
@@ -17,7 +19,7 @@ class Datum<T> extends Query<T> {
17
19
 
18
20
  ## Field Access
19
21
 
20
- The `key` method retrieves a field from a document datum. You can chain `key` calls for nested field access. An optional default value can be provided for the case when the field is undefined.
22
+ The `key` method retrieves a field from a document datum. You can chain `key` calls for nested field access. A non-undefined fallback removes `null` and `undefined` from the declared field result and adds the fallback's type. Omitting the fallback preserves the declared field type.
21
23
 
22
24
  ```typescript
23
25
  import { Schema } from "@antelopejs/interface-database";
@@ -75,11 +77,12 @@ interface User {
75
77
  name: string;
76
78
  }
77
79
 
78
- const post = await schema
80
+ const blog = Schema.get<{ posts: Post; users: User }>("blog")!;
81
+ const post = await blog
79
82
  .instance()
80
- .table<Post>("posts")
83
+ .table("posts")
81
84
  .get("post-1")
82
- .lookup(schema.instance().table<User>("users"), "authorId", "_id");
85
+ .lookup(blog.instance().table("users"), "authorId", "_id");
83
86
 
84
87
  // post.authorId is now the full User object
85
88
  console.log(post.authorId.name);
@@ -200,6 +200,8 @@ const highest = scores.max();
200
200
 
201
201
  Available when the proxy wraps a record/object value.
202
202
 
203
+ `key(field, fallback)` preserves the declared field type when the fallback is omitted or `undefined`. Otherwise, the proxy's value type is `Exclude<FieldType, undefined | null> | FallbackType`. The fallback may itself be a `ValueProxy`, so its value type participates in the result.
204
+
203
205
  ```typescript
204
206
  const email = user.key("email");
205
207
  const emailOrDefault = user.key("email", "none@example.com");
@@ -19,6 +19,7 @@ Tables live inside schema instances:
19
19
  Documents are the fundamental unit of data in AQL:
20
20
 
21
21
  - [4. CRUD Operations](./4.crud.md) - Insert, read, update, replace, and delete documents
22
+ - [8. Atomic Mutations](./8.atomic_mutations.md) - Conditional single-record updates and deletes, with explicit outcomes
22
23
 
23
24
  ## Index Operations
24
25
 
@@ -107,7 +107,7 @@ if (schema) {
107
107
 
108
108
  ## Work with Tables
109
109
 
110
- Once you have a `SchemaInstance`, access tables by name. The generic type parameter provides type safety for your documents:
110
+ Put the table-to-document mapping on `Schema`, then access tables by name. The generic parameter of `table()` is a key of that mapping, not a document type:
111
111
 
112
112
  ```typescript
113
113
  interface User {
@@ -124,11 +124,14 @@ interface Post {
124
124
  authorId: string;
125
125
  }
126
126
 
127
- const db = schema.instance();
128
- const users = db.table<User>("users");
129
- const posts = db.table<Post>("posts");
127
+ const typedSchema = Schema.get<{ users: User; posts: Post }>("myapp")!;
128
+ const db = typedSchema.instance();
129
+ const users = db.table("users"); // Table<User>
130
+ const posts = db.table("posts"); // Table<Post>
130
131
  ```
131
132
 
133
+ Use the same mapping when declaring a schema: `new Schema<{ users: User; posts: Post }>("myapp", definition)`. This type argument describes the schema; it does not validate stored data.
134
+
132
135
  ## Multi-Tenant Pattern
133
136
 
134
137
  Schemas with multiple instances support multi-tenant architectures. Each tenant gets an isolated instance of the same schema:
@@ -16,23 +16,46 @@ const users = db.table("users");
16
16
 
17
17
  ## Type-Safe Tables
18
18
 
19
- Provide a generic type parameter to get type-safe operations:
19
+ Provide the table-to-document mapping to `Schema`, not to `table()`:
20
+
21
+ ```ts docs-check
22
+ import { Schema } from "@antelopejs/interface-database";
20
23
 
21
- ```typescript
22
24
  interface User {
23
25
  _id: string;
24
26
  name: string;
25
27
  email: string;
26
28
  status: string;
29
+ role: string;
30
+ createdAt: Date;
31
+ age: number;
27
32
  }
28
33
 
29
- const users = db.table<User>("users");
34
+ const schema = new Schema<{ users: User }>("myapp", {
35
+ users: {
36
+ fields: {
37
+ name: "string",
38
+ email: "string",
39
+ status: "string",
40
+ role: "string",
41
+ createdAt: "date",
42
+ age: "number",
43
+ },
44
+ indexes: { role: {}, createdAt: {}, name: {} },
45
+ },
46
+ });
47
+ const users = schema.instance().table("users");
30
48
 
31
49
  // TypeScript now validates field names and types
32
- const user = await users.get("user-123"); // user is User | null
33
- const emails = await users.key("email"); // string[]
50
+ export async function readUser() {
51
+ const user = await users.get("user-123"); // Declared as User
52
+ const emails = await users.key("email"); // string[]
53
+ return { user, emails };
54
+ }
34
55
  ```
35
56
 
57
+ `get()` declares `SingleSelection<User>`, so awaiting it is typed as `User`, not `User | null`. This declaration does not guarantee that a row exists: a provider may return `null` for a missing key. Check the result before accessing fields. `Schema`'s generic mapping describes documents but does not validate database contents.
58
+
36
59
  ## Basic Operations
37
60
 
38
61
  ### Retrieve All Documents
@@ -37,12 +37,12 @@ interface User {
37
37
  email: string;
38
38
  }
39
39
 
40
- const schema = Schema.get("blog")!;
40
+ const schema = Schema.get<{ posts: Post; users: User }>("blog")!;
41
41
  const db = schema.instance();
42
42
 
43
43
  const postsWithAuthors = await db
44
- .table<Post>("posts")
45
- .lookup(db.table<User>("users"), "authorId", "_id");
44
+ .table("posts")
45
+ .lookup(db.table("users"), "authorId", "_id");
46
46
 
47
47
  // Result type: { _id: string, title: string, authorId: User }
48
48
  for (const post of postsWithAuthors) {
@@ -68,9 +68,12 @@ interface Product {
68
68
  price: number;
69
69
  }
70
70
 
71
- const ordersWithProducts = await db
72
- .table<Order>("orders")
73
- .lookup(db.table<Product>("products"), "productIds", "_id");
71
+ const shop = Schema.get<{ orders: Order; products: Product }>(
72
+ "shop",
73
+ )!.instance();
74
+ const ordersWithProducts = await shop
75
+ .table("orders")
76
+ .lookup(shop.table("products"), "productIds", "_id");
74
77
 
75
78
  // Result type: { ..., productIds: Product[] }
76
79
  for (const order of ordersWithProducts) {
@@ -85,6 +88,9 @@ for (const order of ordersWithProducts) {
85
88
  Lookup works seamlessly with filters, sorting, and other stream operations:
86
89
 
87
90
  ```typescript
91
+ // The shop schema also declares customers and orders.createdAt.
92
+ const db = Schema.get("shop")!.instance();
93
+
88
94
  // Filter before lookup
89
95
  const recentWithCustomers = await db
90
96
  .table("orders")
@@ -92,10 +98,11 @@ const recentWithCustomers = await db
92
98
  .lookup(db.table("customers"), "customerId", "_id");
93
99
 
94
100
  // Lookup on a single document
95
- const post = await db
96
- .table<Post>("posts")
101
+ const blog = Schema.get<{ posts: Post; users: User }>("blog")!.instance();
102
+ const post = await blog
103
+ .table("posts")
97
104
  .get("post-1")
98
- .lookup(db.table<User>("users"), "authorId", "_id");
105
+ .lookup(blog.table("users"), "authorId", "_id");
99
106
  ```
100
107
 
101
108
  ## Lookup vs Join
@@ -89,7 +89,7 @@ const users = schema.instance().table("users");
89
89
  const posts = schema.instance().table("posts");
90
90
  ```
91
91
 
92
- For type-safe access, provide a generic type parameter:
92
+ For type-safe access, provide the table mapping when declaring or retrieving the schema. `table()` infers the document type from the table name:
93
93
 
94
94
  ```typescript
95
95
  interface User {
@@ -99,7 +99,8 @@ interface User {
99
99
  age: number;
100
100
  }
101
101
 
102
- const users = schema.instance().table<User>("users");
102
+ const typedSchema = Schema.get<{ users: User }>("myapp")!;
103
+ const users = typedSchema.instance().table("users"); // Table<User>
103
104
  ```
104
105
 
105
106
  For more details on table operations, see [Table Operations](../2.operations/3.table_operations.md).
@@ -36,9 +36,7 @@ import { Schema } from "@antelopejs/interface-database";
36
36
  const schema = Schema.get("myapp")!;
37
37
  const users = schema.instance().table("users");
38
38
 
39
- const changes = await users.changes();
40
-
41
- for (const change of changes) {
39
+ for await (const change of users.changes()) {
42
40
  switch (change.changeType) {
43
41
  case "added":
44
42
  console.log("New document:", change.newValue);
@@ -56,9 +54,7 @@ for (const change of changes) {
56
54
  ## Monitor a Single Document
57
55
 
58
56
  ```typescript
59
- const userChanges = await users.get("user-123").changes();
60
-
61
- for (const change of userChanges) {
57
+ for await (const change of users.get("user-123").changes()) {
62
58
  if (change.changeType === "modified") {
63
59
  console.log("User updated:", change.newValue);
64
60
  } else if (change.changeType === "removed") {
package/docs/index.md CHANGED
@@ -4,6 +4,14 @@
4
4
 
5
5
  The Database interface provides AQL (Antelope Query Language), a database-agnostic query API. Each module implements this generic interface with the database engine of its choice. AQL offers a chainable, type-safe query builder that works identically across all supported backends, so your application code remains portable regardless of the underlying database.
6
6
 
7
+ ## Import Paths
8
+
9
+ Import `Schema`, `Query`, `Table`, `Datum`, `Stream`, and `ValueProxy` from `@antelopejs/interface-database` in an AntelopeJS module. This entry point registers schemas with the bound provider and installs query execution (`run()`, `then()`, `cursor()`, and async iteration).
10
+
11
+ Supporting types have dedicated paths: import `Changes`, `DeepPartial`, `ExtractType`, and `Value` from `@antelopejs/interface-database/common`, and `FieldType`, `TableDefinition`, and `IndexDefinition` from `@antelopejs/interface-database/schema`. Atomic mutation types are available from the package root and `/atomic`.
12
+
13
+ `@antelopejs/interface-database/staged-query` is the build-only entry point for tools that construct and inspect query stages without the AntelopeJS runtime. Its schema does not register with a provider, and its queries expose `build()` but no execution methods when loaded on their own. Do not `await` a build-only query expecting database results. The runtime entry point augments the same staged classes; keep build-only consumers separate from runtime imports when that isolation matters.
14
+
7
15
  ## Documentation Structure
8
16
 
9
17
  - [**1. Query Types**](./1.query_types/1.index.md) - Detailed reference for each query type:
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "..",
5
+ "noEmit": true,
6
+ "composite": false,
7
+ "incremental": false,
8
+ "paths": {
9
+ "@antelopejs/interface-database": ["../src/index.ts"],
10
+ "@antelopejs/interface-database/*": ["../src/*"]
11
+ }
12
+ },
13
+ "include": ["../src/**/*.ts", "./**/*.ts"]
14
+ }
package/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "@antelopejs/interface-database",
3
- "version": "0.1.9",
4
- "description": "AntelopeJS interface for database-agnostic query operations",
3
+ "version": "0.1.10",
4
+ "description": "AQL, the AntelopeJS database-agnostic query builder: schemas, CRUD, joins, aggregations and change feeds",
5
5
  "keywords": [
6
6
  "antelopejs",
7
+ "aql",
7
8
  "database",
8
- "interface"
9
+ "interface",
10
+ "query-builder"
9
11
  ],
12
+ "homepage": "https://interfaces.antelopejs.com/docs/database",
13
+ "bugs": {
14
+ "url": "https://github.com/AntelopeJS/interface-database/issues"
15
+ },
10
16
  "license": "Apache-2.0",
11
17
  "repository": {
12
18
  "type": "git",
@@ -110,9 +116,9 @@
110
116
  "knip": "knip"
111
117
  },
112
118
  "devDependencies": {
113
- "@antelopejs/core": "^1.13.4",
114
- "@antelopejs/interface-core": ">=0.1.1 <1.0.0",
115
- "@antelopejs/tooling-configs": "^0.0.6",
119
+ "@antelopejs/core": "^1.16.0",
120
+ "@antelopejs/interface-core": ">=0.2.4 <1.0.0",
121
+ "@antelopejs/tooling-configs": "^0.0.9",
116
122
  "@types/chai": "^4.3.20",
117
123
  "@types/mocha": "^10.0.10",
118
124
  "@types/node": "^22.19.15",
@@ -132,7 +138,7 @@
132
138
  "typescript": "^5.9.3"
133
139
  },
134
140
  "peerDependencies": {
135
- "@antelopejs/interface-core": ">=0.1.1 <1.0.0"
141
+ "@antelopejs/interface-core": ">=0.2.4 <1.0.0"
136
142
  },
137
143
  "packageManager": "pnpm@10.6.5",
138
144
  "antelopeJs": {