@antelopejs/interface-database 0.1.3 → 0.1.5
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/dist/antelope.test.js +2 -2
- package/dist/antelope.test.js.map +1 -1
- package/dist/atomic.d.ts +41 -0
- package/dist/atomic.js +135 -0
- package/dist/atomic.js.map +1 -0
- package/dist/common.js.map +1 -1
- package/dist/datum.d.ts +2 -2
- package/dist/datum.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/query.js +1 -1
- package/dist/query.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/selection.d.ts +4 -1
- package/dist/selection.js +7 -0
- package/dist/selection.js.map +1 -1
- package/dist/stream.d.ts +1 -1
- package/dist/stream.js.map +1 -1
- package/dist/tests/aggregation_operations.test.js +1 -1
- package/dist/tests/aggregation_operations.test.js.map +1 -1
- package/dist/tests/atomic_mutation.test.d.ts +1 -0
- package/dist/tests/atomic_mutation.test.js +185 -0
- package/dist/tests/atomic_mutation.test.js.map +1 -0
- package/dist/tests/basic_operations.test.js +1 -1
- package/dist/tests/basic_operations.test.js.map +1 -1
- package/dist/tests/between_operations.test.js +1 -1
- package/dist/tests/between_operations.test.js.map +1 -1
- package/dist/tests/change_feeds.test.js +1 -1
- package/dist/tests/change_feeds.test.js.map +1 -1
- package/dist/tests/datasets/codec_fields.js.map +1 -1
- package/dist/tests/date_operations.test.js +1 -1
- package/dist/tests/date_operations.test.js.map +1 -1
- package/dist/tests/do_operations.test.js +1 -1
- package/dist/tests/do_operations.test.js.map +1 -1
- package/dist/tests/filters.test.js +1 -1
- package/dist/tests/filters.test.js.map +1 -1
- package/dist/tests/group_operations.test.js +1 -1
- package/dist/tests/group_operations.test.js.map +1 -1
- package/dist/tests/instance_modes.test.js +1 -1
- package/dist/tests/instance_modes.test.js.map +1 -1
- package/dist/tests/joins.test.js +2 -2
- package/dist/tests/joins.test.js.map +1 -1
- package/dist/tests/lookup_operations.test.js +2 -2
- package/dist/tests/lookup_operations.test.js.map +1 -1
- package/dist/tests/merge_operations.test.js +2 -2
- package/dist/tests/merge_operations.test.js.map +1 -1
- package/dist/tests/sorting.test.js +1 -1
- package/dist/tests/sorting.test.js.map +1 -1
- package/dist/tests/union_operations.test.js +2 -2
- package/dist/tests/union_operations.test.js.map +1 -1
- package/docs/1.query_types/1.index.md +53 -0
- package/docs/1.query_types/2.table.md +114 -0
- package/docs/1.query_types/3.selection.md +92 -0
- package/docs/1.query_types/4.single_selection.md +121 -0
- package/docs/1.query_types/5.stream.md +234 -0
- package/docs/1.query_types/6.feed.md +82 -0
- package/docs/1.query_types/7.query.md +82 -0
- package/docs/1.query_types/8.datum.md +102 -0
- package/docs/1.query_types/9.valueproxy.md +232 -0
- package/docs/2.operations/1.index.md +34 -0
- package/docs/2.operations/2.database_management.md +151 -0
- package/docs/2.operations/3.table_operations.md +117 -0
- package/docs/2.operations/4.crud.md +214 -0
- package/docs/2.operations/5.indexes.md +110 -0
- package/docs/2.operations/6.filtering.md +172 -0
- package/docs/2.operations/7.lookup.md +135 -0
- package/docs/2.operations/8.atomic_mutations.md +71 -0
- package/docs/3.results/1.index.md +38 -0
- package/docs/3.results/2.write_results.md +86 -0
- package/docs/3.results/3.index_changes.md +82 -0
- package/docs/3.results/4.table_changes.md +105 -0
- package/docs/3.results/5.database_changes.md +96 -0
- package/docs/3.results/6.value_changes.md +75 -0
- package/docs/index.md +51 -0
- package/package.json +62 -42
- package/skills/database-interface/SKILL.md +101 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Results
|
|
2
|
+
|
|
3
|
+
AQL operations return structured result values that communicate what happened during execution. This section covers the result types produced by write operations and change feeds.
|
|
4
|
+
|
|
5
|
+
## Result Types
|
|
6
|
+
|
|
7
|
+
- [2. Insert Results](./2.write_results.md) - Return values from insert operations
|
|
8
|
+
- [3. Index Definitions](./3.index_changes.md) - Index configuration in schema definitions
|
|
9
|
+
- [4. Table Definitions](./4.table_changes.md) - Table structure and field types
|
|
10
|
+
- [5. Schema and Instance Management](./5.database_changes.md) - Schema lifecycle and instance management
|
|
11
|
+
- [6. Change Events](./6.value_changes.md) - Structure of change feed notifications
|
|
12
|
+
|
|
13
|
+
## Common Patterns
|
|
14
|
+
|
|
15
|
+
All AQL operations follow a consistent pattern:
|
|
16
|
+
|
|
17
|
+
1. Build a query by chaining operations.
|
|
18
|
+
2. Execute the query with `run()` or `await` to get the result.
|
|
19
|
+
3. Process the structured result.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { Schema } from "@antelopejs/interface-database";
|
|
23
|
+
|
|
24
|
+
const schema = Schema.get("myapp")!;
|
|
25
|
+
const users = schema.instance().table("users");
|
|
26
|
+
|
|
27
|
+
// Insert returns an array of generated IDs
|
|
28
|
+
const ids = await users.insert({ name: "Alice", email: "alice@example.com" });
|
|
29
|
+
console.log("New ID:", ids[0]);
|
|
30
|
+
|
|
31
|
+
// Update/delete return the number of affected documents
|
|
32
|
+
const count = await users.get("user-123").update({ status: "active" });
|
|
33
|
+
console.log(`Modified ${count} documents`);
|
|
34
|
+
|
|
35
|
+
// Delete returns the number of deleted documents
|
|
36
|
+
const deleted = await users.get("user-123").delete();
|
|
37
|
+
console.log(`Deleted ${deleted} documents`);
|
|
38
|
+
```
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Insert Results
|
|
2
|
+
|
|
3
|
+
The `insert` method on `Table<T>` returns a `Query<string[]>` that resolves to an array of the generated or provided primary keys for the inserted documents.
|
|
4
|
+
|
|
5
|
+
## Return Value
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Insert returns string[] (the IDs of inserted documents)
|
|
9
|
+
const ids: string[] = await users.insert({
|
|
10
|
+
name: "Alice",
|
|
11
|
+
email: "alice@example.com",
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### Single Document Insert
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Schema } from "@antelopejs/interface-database";
|
|
21
|
+
|
|
22
|
+
const schema = Schema.get("myapp")!;
|
|
23
|
+
const users = schema.instance().table("users");
|
|
24
|
+
|
|
25
|
+
const ids = await users.insert({
|
|
26
|
+
name: "John Doe",
|
|
27
|
+
email: "john@example.com",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log("Inserted document ID:", ids[0]);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Multiple Document Insert
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const ids = await users.insert([
|
|
37
|
+
{ name: "Alice", email: "alice@example.com" },
|
|
38
|
+
{ name: "Bob", email: "bob@example.com" },
|
|
39
|
+
{ name: "Carol", email: "carol@example.com" },
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
console.log(`Inserted ${ids.length} documents`);
|
|
43
|
+
console.log("IDs:", ids);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Insert with Conflict Handling
|
|
47
|
+
|
|
48
|
+
Use the `conflict` option to control behavior when a document with the same primary key already exists:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Update matching fields on conflict
|
|
52
|
+
const ids = await users.insert(
|
|
53
|
+
{ _id: "user-123", name: "Updated Name", lastSeen: new Date() },
|
|
54
|
+
{ conflict: "update" },
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Replace the entire document on conflict
|
|
58
|
+
const ids2 = await users.insert(
|
|
59
|
+
{ _id: "user-123", name: "Replaced", email: "new@example.com" },
|
|
60
|
+
{ conflict: "replace" },
|
|
61
|
+
);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Update and Delete Results
|
|
65
|
+
|
|
66
|
+
The `update`, `replace`, and `delete` methods return a `Query<number>` that resolves to the count of affected documents:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Update returns the number of modified documents
|
|
70
|
+
const updated = await users.get("user-123").update({ status: "active" });
|
|
71
|
+
console.log(`Modified: ${updated}`);
|
|
72
|
+
|
|
73
|
+
// Replace returns the number of replaced documents
|
|
74
|
+
const replaced = await users.get("user-123").replace({
|
|
75
|
+
_id: "user-123",
|
|
76
|
+
name: "New",
|
|
77
|
+
email: "new@example.com",
|
|
78
|
+
});
|
|
79
|
+
console.log(`Replaced: ${replaced}`);
|
|
80
|
+
|
|
81
|
+
// Delete returns the number of deleted documents
|
|
82
|
+
const deleted = await users
|
|
83
|
+
.filter((u) => u.key("status").eq("inactive"))
|
|
84
|
+
.delete();
|
|
85
|
+
console.log(`Deleted: ${deleted}`);
|
|
86
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Index Definitions
|
|
2
|
+
|
|
3
|
+
In AQL, indexes are defined as part of the schema definition rather than created at runtime. The schema declaration specifies which fields to index and what type of index to use.
|
|
4
|
+
|
|
5
|
+
## `IndexDefinition`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface IndexDefinition {
|
|
9
|
+
fields?: string[]; // Fields for compound indexes
|
|
10
|
+
multi?: boolean; // Multi-valued index
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Define Indexes
|
|
15
|
+
|
|
16
|
+
Indexes are declared in the `indexes` property of each table definition:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Schema } from "@antelopejs/interface-database";
|
|
20
|
+
|
|
21
|
+
const schema = new Schema("myapp", {
|
|
22
|
+
users: {
|
|
23
|
+
fields: { name: "string", email: "string", role: "string" },
|
|
24
|
+
indexes: {
|
|
25
|
+
email: {}, // Simple index (field name = index name)
|
|
26
|
+
role: {}, // Simple index
|
|
27
|
+
name_role: { fields: ["name", "role"] }, // Compound index
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Simple Indexes
|
|
34
|
+
|
|
35
|
+
When `fields` is omitted, the index name is used as the field name:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
indexes: {
|
|
39
|
+
email: {}, // Creates an index on the "email" field
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Compound Indexes
|
|
44
|
+
|
|
45
|
+
Provide the `fields` array for indexes spanning multiple fields:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
indexes: {
|
|
49
|
+
full_name: { fields: ["firstName", "lastName"] },
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Multi Indexes
|
|
54
|
+
|
|
55
|
+
Set `multi: true` for array fields where each element should be individually indexed:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
indexes: {
|
|
59
|
+
tags: { multi: true },
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Use Indexes in Queries
|
|
64
|
+
|
|
65
|
+
Once defined, indexes are available for `getAll()` and `between()` operations:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const db = schema.instance();
|
|
69
|
+
const users = db.table("users");
|
|
70
|
+
|
|
71
|
+
// Lookup by secondary index
|
|
72
|
+
const admins = await users.getAll("admin", "role");
|
|
73
|
+
|
|
74
|
+
// Range query on an indexed field
|
|
75
|
+
const recent = await users.between(
|
|
76
|
+
"createdAt",
|
|
77
|
+
new Date("2024-01-01"),
|
|
78
|
+
new Date(),
|
|
79
|
+
);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For more details, see [Index Management](../2.operations/5.indexes.md).
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Table Definitions
|
|
2
|
+
|
|
3
|
+
In AQL, tables are defined as part of a schema. Each table definition specifies the fields and indexes for that table.
|
|
4
|
+
|
|
5
|
+
## `TableDefinition`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface TableDefinition {
|
|
9
|
+
fields: Record<string, FieldType>;
|
|
10
|
+
indexes: Record<string, IndexDefinition>;
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### `FieldType`
|
|
15
|
+
|
|
16
|
+
Field types describe the structure of each field:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
type FieldType =
|
|
20
|
+
| string // Primitive type name (e.g., "string", "number")
|
|
21
|
+
| Array<StringFieldType> // Array of a given type
|
|
22
|
+
| { [subfield: string]: StringFieldType } // Nested object
|
|
23
|
+
| import("io-ts").Mixed; // io-ts codec at the field root
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A field can be described either with the string-token vocabulary (primitives, arrays, nested records) or with a single [io-ts](https://github.com/gcanti/io-ts) codec at the root of the field. Codecs are not mixed inside string-tree records — use io-ts combinators (`t.type`, `t.array`, …) to nest within a codec.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import * as t from "io-ts";
|
|
30
|
+
|
|
31
|
+
const Order = {
|
|
32
|
+
fields: {
|
|
33
|
+
id: "string",
|
|
34
|
+
status: t.union([t.literal("open"), t.literal("closed")]),
|
|
35
|
+
meta: t.type({ source: t.string, retries: t.number }),
|
|
36
|
+
},
|
|
37
|
+
indexes: {},
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Define Tables in a Schema
|
|
42
|
+
|
|
43
|
+
Tables are declared in the `SchemaDefinition` passed to the `Schema` constructor:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { Schema } from "@antelopejs/interface-database";
|
|
47
|
+
|
|
48
|
+
const schema = new Schema("myapp", {
|
|
49
|
+
users: {
|
|
50
|
+
fields: {
|
|
51
|
+
name: "string",
|
|
52
|
+
email: "string",
|
|
53
|
+
age: "number",
|
|
54
|
+
address: {
|
|
55
|
+
street: "string",
|
|
56
|
+
city: "string",
|
|
57
|
+
zip: "string",
|
|
58
|
+
},
|
|
59
|
+
tags: ["string"],
|
|
60
|
+
},
|
|
61
|
+
indexes: {
|
|
62
|
+
email: {},
|
|
63
|
+
age: {},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
posts: {
|
|
67
|
+
fields: {
|
|
68
|
+
title: "string",
|
|
69
|
+
content: "string",
|
|
70
|
+
authorId: "string",
|
|
71
|
+
publishedAt: "date",
|
|
72
|
+
},
|
|
73
|
+
indexes: {
|
|
74
|
+
authorId: {},
|
|
75
|
+
publishedAt: {},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Access Tables
|
|
82
|
+
|
|
83
|
+
After creating a schema instance, access tables by name:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
await schema.createInstance();
|
|
87
|
+
|
|
88
|
+
const users = schema.instance().table("users");
|
|
89
|
+
const posts = schema.instance().table("posts");
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
For type-safe access, provide a generic type parameter:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface User {
|
|
96
|
+
_id: string;
|
|
97
|
+
name: string;
|
|
98
|
+
email: string;
|
|
99
|
+
age: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const users = schema.instance().table<User>("users");
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For more details on table operations, see [Table Operations](../2.operations/3.table_operations.md).
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Schema and Instance Management
|
|
2
|
+
|
|
3
|
+
This page covers the `Schema`, `SchemaInstance`, and related types that control database structure and lifecycle.
|
|
4
|
+
|
|
5
|
+
## Schema
|
|
6
|
+
|
|
7
|
+
The `Schema<T>` class defines the structure of a database and manages its instances.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
class Schema<T = any> extends StagedObject {
|
|
11
|
+
static get(id: string): Schema | undefined;
|
|
12
|
+
constructor(id: string, definition: SchemaDefinition);
|
|
13
|
+
instance(id?: InstanceId): SchemaInstance<T>;
|
|
14
|
+
createInstance(id?: string): Query<string>;
|
|
15
|
+
destroyInstance(id?: string): Query<void>;
|
|
16
|
+
listInstances(): Query<string[]>;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### `SchemaDefinition`
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
interface SchemaDefinition {
|
|
24
|
+
[tableName: string]: TableDefinition;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### `InstanceId` and `CROSS_INSTANCE`
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const CROSS_INSTANCE: unique symbol;
|
|
32
|
+
type InstanceId = string | typeof CROSS_INSTANCE;
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`schema.instance(CROSS_INSTANCE)` returns a query stage that operates across every instance of the schema. Adapters skip the per-instance filter on read/update/delete and reject inserts.
|
|
36
|
+
|
|
37
|
+
## Create and Manage Instances
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { Schema } from "@antelopejs/interface-database";
|
|
41
|
+
|
|
42
|
+
// Define a schema
|
|
43
|
+
const schema = new Schema("myapp", {
|
|
44
|
+
users: {
|
|
45
|
+
fields: { name: "string" },
|
|
46
|
+
indexes: {},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Create the default instance
|
|
51
|
+
const instanceId = await schema.createInstance();
|
|
52
|
+
|
|
53
|
+
// Create a named instance
|
|
54
|
+
await schema.createInstance("tenant-1");
|
|
55
|
+
|
|
56
|
+
// Access instances
|
|
57
|
+
const defaultDb = schema.instance();
|
|
58
|
+
const tenantDb = schema.instance("tenant-1");
|
|
59
|
+
|
|
60
|
+
// Destroy an instance
|
|
61
|
+
await schema.destroyInstance("tenant-1");
|
|
62
|
+
|
|
63
|
+
// List named instances
|
|
64
|
+
const ids = await schema.listInstances();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Retrieve a Schema
|
|
68
|
+
|
|
69
|
+
Use `Schema.get()` to look up a previously defined schema anywhere in your application:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const schema = Schema.get("myapp");
|
|
73
|
+
|
|
74
|
+
if (schema) {
|
|
75
|
+
const db = schema.instance();
|
|
76
|
+
const users = db.table("users");
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## SchemaInstance
|
|
81
|
+
|
|
82
|
+
The `SchemaInstance<T>` class represents a single instance of a schema. Its primary method is `table()`, which returns a `Table` for the specified table name.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
class SchemaInstance<T> extends StagedObject {
|
|
86
|
+
table<TK extends keyof T>(id: TK): Table<T[TK]>;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const db = schema.instance();
|
|
92
|
+
const users = db.table("users");
|
|
93
|
+
const posts = db.table("posts");
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
For practical usage patterns, see [Schema Management](../2.operations/2.database_management.md).
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Change Events
|
|
2
|
+
|
|
3
|
+
The `Changes<T>` interface represents a change event emitted by change feeds. It includes the type of change and the document values before and after the change.
|
|
4
|
+
|
|
5
|
+
## Interface Definition
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface Changes<T> {
|
|
9
|
+
changeType: "added" | "removed" | "modified";
|
|
10
|
+
oldValue?: T;
|
|
11
|
+
newValue?: T;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Properties
|
|
16
|
+
|
|
17
|
+
| Property | Type | Description |
|
|
18
|
+
| ------------ | ------------------------------------ | ------------------------------------------------------ |
|
|
19
|
+
| `changeType` | `"added" \| "removed" \| "modified"` | The kind of change that occurred. |
|
|
20
|
+
| `oldValue` | `T \| undefined` | The document before the change. Undefined for inserts. |
|
|
21
|
+
| `newValue` | `T \| undefined` | The document after the change. Undefined for deletes. |
|
|
22
|
+
|
|
23
|
+
## Determine the Change Type
|
|
24
|
+
|
|
25
|
+
The `changeType` field indicates what happened:
|
|
26
|
+
|
|
27
|
+
- **`"added"`** - A new document was inserted. `newValue` contains the document; `oldValue` is undefined.
|
|
28
|
+
- **`"modified"`** - An existing document was updated. Both `oldValue` and `newValue` are present.
|
|
29
|
+
- **`"removed"`** - A document was deleted. `oldValue` contains the deleted document; `newValue` is undefined.
|
|
30
|
+
|
|
31
|
+
## Process Change Events
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { Schema } from "@antelopejs/interface-database";
|
|
35
|
+
|
|
36
|
+
const schema = Schema.get("myapp")!;
|
|
37
|
+
const users = schema.instance().table("users");
|
|
38
|
+
|
|
39
|
+
const changes = await users.changes();
|
|
40
|
+
|
|
41
|
+
for (const change of changes) {
|
|
42
|
+
switch (change.changeType) {
|
|
43
|
+
case "added":
|
|
44
|
+
console.log("New document:", change.newValue);
|
|
45
|
+
break;
|
|
46
|
+
case "modified":
|
|
47
|
+
console.log("Updated:", change.oldValue, "->", change.newValue);
|
|
48
|
+
break;
|
|
49
|
+
case "removed":
|
|
50
|
+
console.log("Deleted:", change.oldValue);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Monitor a Single Document
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const userChanges = await users.get("user-123").changes();
|
|
60
|
+
|
|
61
|
+
for (const change of userChanges) {
|
|
62
|
+
if (change.changeType === "modified") {
|
|
63
|
+
console.log("User updated:", change.newValue);
|
|
64
|
+
} else if (change.changeType === "removed") {
|
|
65
|
+
console.log("User deleted");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Use Cases
|
|
71
|
+
|
|
72
|
+
- **Real-time notifications** - Push updates to connected clients when data changes.
|
|
73
|
+
- **Audit logging** - Record every modification with before/after snapshots.
|
|
74
|
+
- **Cache invalidation** - Clear or refresh caches when underlying data is modified.
|
|
75
|
+
- **Event-driven workflows** - Trigger downstream processing based on data changes.
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Database Interface
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
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
|
+
|
|
7
|
+
## Documentation Structure
|
|
8
|
+
|
|
9
|
+
- [**1. Query Types**](./1.query_types/1.index.md) - Detailed reference for each query type:
|
|
10
|
+
|
|
11
|
+
- [Table](./1.query_types/2.table.md) - Table-level operations (insert, get, getAll, between)
|
|
12
|
+
- [Selection](./1.query_types/3.selection.md) - Multi-document operations (update, replace, delete)
|
|
13
|
+
- [SingleSelection](./1.query_types/4.single_selection.md) - Single-document operations
|
|
14
|
+
- [Stream](./1.query_types/5.stream.md) - Transformation, filtering, aggregation, joins, and grouping
|
|
15
|
+
- [Change Feeds](./1.query_types/6.feed.md) - Real-time change notifications
|
|
16
|
+
- [Query](./1.query_types/7.query.md) - Base query execution and async iteration
|
|
17
|
+
- [Datum](./1.query_types/8.datum.md) - Single-value manipulation
|
|
18
|
+
- [ValueProxy](./1.query_types/9.valueproxy.md) - In-query value operations (arithmetic, string, date, array, object)
|
|
19
|
+
|
|
20
|
+
- [**2. Operations**](./2.operations/1.index.md) - Practical guides:
|
|
21
|
+
|
|
22
|
+
- [Schema Management](./2.operations/2.database_management.md) - Create and manage schema instances
|
|
23
|
+
- [Table Operations](./2.operations/3.table_operations.md) - Access and work with tables
|
|
24
|
+
- [CRUD Operations](./2.operations/4.crud.md) - Create, read, update, and delete documents
|
|
25
|
+
- [Index Management](./2.operations/5.indexes.md) - Define and use secondary indexes
|
|
26
|
+
- [Filtering and Querying](./2.operations/6.filtering.md) - Filter, compare, and transform data
|
|
27
|
+
- [Lookup](./2.operations/7.lookup.md) - Foreign key joins and data population
|
|
28
|
+
- [Atomic Mutations](./2.operations/8.atomic_mutations.md) - Conditional single-record mutations and outcomes
|
|
29
|
+
|
|
30
|
+
- [**3. Results**](./3.results/1.index.md) - Result types and handling:
|
|
31
|
+
- [Insert Results](./3.results/2.write_results.md) - Results from insert operations
|
|
32
|
+
- [Index Definitions](./3.results/3.index_changes.md) - Index configuration in schema definitions
|
|
33
|
+
- [Table Definitions](./3.results/4.table_changes.md) - Table structure and field types
|
|
34
|
+
- [Schema and Instance Management](./3.results/5.database_changes.md) - Schema lifecycle and instance management
|
|
35
|
+
- [Change Events](./3.results/6.value_changes.md) - Change feed event structure
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- Database-agnostic query interface
|
|
40
|
+
- Consistent API across different database implementations
|
|
41
|
+
- Type-safe operations using TypeScript generics
|
|
42
|
+
- Schema-based database structure definition
|
|
43
|
+
- Multi-instance support per schema
|
|
44
|
+
- Secondary index support
|
|
45
|
+
- Change feeds for real-time updates
|
|
46
|
+
- Async iteration with cursor support
|
|
47
|
+
- Chainable query builder with lazy evaluation
|
|
48
|
+
|
|
49
|
+
## Database Interoperability
|
|
50
|
+
|
|
51
|
+
AQL decouples your application logic from the database engine. The same query code works with any backend that implements the interface, such as MongoDB, RethinkDB, or other community-provided implementations. This reduces migration cost and keeps your code portable.
|
package/package.json
CHANGED
|
@@ -1,28 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-database",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "AntelopeJS interface for database-agnostic query operations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"database",
|
|
8
|
+
"interface"
|
|
9
9
|
],
|
|
10
|
+
"license": "Apache-2.0",
|
|
10
11
|
"repository": {
|
|
11
12
|
"type": "git",
|
|
12
13
|
"url": "git+https://github.com/AntelopeJS/interface-database.git"
|
|
13
14
|
},
|
|
14
|
-
"license": "Apache-2.0",
|
|
15
|
-
"packageManager": "pnpm@10.6.5",
|
|
16
|
-
"main": "dist/index.js",
|
|
17
|
-
"types": "dist/index.d.ts",
|
|
18
15
|
"files": [
|
|
19
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"docs",
|
|
18
|
+
"skills"
|
|
20
19
|
],
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"typesVersions": {
|
|
23
|
+
"*": {
|
|
24
|
+
"atomic": [
|
|
25
|
+
"dist/atomic.d.ts"
|
|
26
|
+
],
|
|
27
|
+
"common": [
|
|
28
|
+
"dist/common.d.ts"
|
|
29
|
+
],
|
|
30
|
+
"datum": [
|
|
31
|
+
"dist/datum.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"query": [
|
|
34
|
+
"dist/query.d.ts"
|
|
35
|
+
],
|
|
36
|
+
"schema": [
|
|
37
|
+
"dist/schema.d.ts"
|
|
38
|
+
],
|
|
39
|
+
"selection": [
|
|
40
|
+
"dist/selection.d.ts"
|
|
41
|
+
],
|
|
42
|
+
"stream": [
|
|
43
|
+
"dist/stream.d.ts"
|
|
44
|
+
],
|
|
45
|
+
"valueproxy": [
|
|
46
|
+
"dist/valueproxy.d.ts"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
21
50
|
"exports": {
|
|
22
51
|
".": {
|
|
23
52
|
"types": "./dist/index.d.ts",
|
|
24
53
|
"default": "./dist/index.js"
|
|
25
54
|
},
|
|
55
|
+
"./atomic": {
|
|
56
|
+
"types": "./dist/atomic.d.ts",
|
|
57
|
+
"default": "./dist/atomic.js"
|
|
58
|
+
},
|
|
26
59
|
"./common": {
|
|
27
60
|
"types": "./dist/common.d.ts",
|
|
28
61
|
"default": "./dist/common.js"
|
|
@@ -53,26 +86,37 @@
|
|
|
53
86
|
},
|
|
54
87
|
"./package.json": "./package.json"
|
|
55
88
|
},
|
|
89
|
+
"publishConfig": {
|
|
90
|
+
"access": "public",
|
|
91
|
+
"provenance": true
|
|
92
|
+
},
|
|
56
93
|
"scripts": {
|
|
57
94
|
"build": "rimraf dist && tsc",
|
|
58
|
-
"format": "
|
|
59
|
-
"lint:fix": "
|
|
60
|
-
"lint": "
|
|
95
|
+
"format": "oxfmt .",
|
|
96
|
+
"lint:fix": "oxlint --fix",
|
|
97
|
+
"lint": "oxlint",
|
|
61
98
|
"prepack": "pnpm run build",
|
|
62
99
|
"release": "pnpm run lint && pnpm run prepack && release-it",
|
|
63
|
-
"test": "pnpm run build && ajs module test ."
|
|
100
|
+
"test": "pnpm run build && ajs module test .",
|
|
101
|
+
"format:check": "oxfmt --check .",
|
|
102
|
+
"knip": "knip"
|
|
64
103
|
},
|
|
65
104
|
"devDependencies": {
|
|
66
105
|
"@antelopejs/interface-core": ">=0.0.3 <1.0.0",
|
|
67
|
-
"@
|
|
106
|
+
"@antelopejs/tooling-configs": "^0.0.4",
|
|
68
107
|
"@types/chai": "^4.3.20",
|
|
69
108
|
"@types/mocha": "^10.0.10",
|
|
70
109
|
"@types/node": "^22.19.15",
|
|
71
110
|
"@types/semver": "^7.7.1",
|
|
72
111
|
"chai": "^4.5.0",
|
|
112
|
+
"eslint-plugin-perfectionist": "^5.11.0",
|
|
73
113
|
"fp-ts": "^2.16.0",
|
|
74
114
|
"io-ts": "^2.2.0",
|
|
115
|
+
"knip": "^6.34.0",
|
|
75
116
|
"mongodb-memory-server-core": "^11.0.1",
|
|
117
|
+
"oxfmt": "^0.66.0",
|
|
118
|
+
"oxlint": "1.81.0",
|
|
119
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
76
120
|
"release-it": "^19.2.4",
|
|
77
121
|
"release-it-changelogen": "^0.1.0",
|
|
78
122
|
"rimraf": "^6.1.3",
|
|
@@ -81,35 +125,11 @@
|
|
|
81
125
|
"peerDependencies": {
|
|
82
126
|
"@antelopejs/interface-core": ">=0.0.3 <1.0.0"
|
|
83
127
|
},
|
|
84
|
-
"
|
|
85
|
-
"access": "public"
|
|
86
|
-
},
|
|
87
|
-
"typesVersions": {
|
|
88
|
-
"*": {
|
|
89
|
-
"common": [
|
|
90
|
-
"dist/common.d.ts"
|
|
91
|
-
],
|
|
92
|
-
"datum": [
|
|
93
|
-
"dist/datum.d.ts"
|
|
94
|
-
],
|
|
95
|
-
"query": [
|
|
96
|
-
"dist/query.d.ts"
|
|
97
|
-
],
|
|
98
|
-
"schema": [
|
|
99
|
-
"dist/schema.d.ts"
|
|
100
|
-
],
|
|
101
|
-
"selection": [
|
|
102
|
-
"dist/selection.d.ts"
|
|
103
|
-
],
|
|
104
|
-
"stream": [
|
|
105
|
-
"dist/stream.d.ts"
|
|
106
|
-
],
|
|
107
|
-
"valueproxy": [
|
|
108
|
-
"dist/valueproxy.d.ts"
|
|
109
|
-
]
|
|
110
|
-
}
|
|
111
|
-
},
|
|
128
|
+
"packageManager": "pnpm@10.6.5",
|
|
112
129
|
"antelopeJs": {
|
|
113
|
-
"test": "src/antelope.test.ts"
|
|
130
|
+
"test": "src/antelope.test.ts",
|
|
131
|
+
"skills": [
|
|
132
|
+
"./skills"
|
|
133
|
+
]
|
|
114
134
|
}
|
|
115
135
|
}
|