@glmachado/any-store 0.3.0 → 0.4.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/dist/lib.es.js +1 -1
- package/dist/src/WDB.d.ts +1 -1
- package/package.json +4 -3
- package/readme.md +191 -35
package/dist/lib.es.js
CHANGED
|
@@ -128,7 +128,7 @@ var ops = {
|
|
|
128
128
|
return this.memory.buffer.byteLength / 2 ** 16;
|
|
129
129
|
}
|
|
130
130
|
createTable(e, _) {
|
|
131
|
-
return new Table(
|
|
131
|
+
return new Table(_, this.ops.createTable(e), this);
|
|
132
132
|
}
|
|
133
133
|
insertRowOnTable(e, _, v) {
|
|
134
134
|
v.forEach((e) => {
|
package/dist/src/WDB.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare class AnyStore {
|
|
|
17
17
|
static fromModule(workerData: WorkerData): Promise<AnyStore>;
|
|
18
18
|
getTable<T extends ColMap>(name: string, colMap: T): Table<T> | null;
|
|
19
19
|
memSize(): number;
|
|
20
|
-
createTable<T extends ColMap>(
|
|
20
|
+
createTable<T extends ColMap>(name: string, colMap: T): Table<T>;
|
|
21
21
|
insertRowOnTable(tableID: number, key: Something, values: Something[]): void;
|
|
22
22
|
insertOnTable(tableID: number, col: number, key: Something, value: Something): void;
|
|
23
23
|
addListenerToRow(tableID: number, key: Something, fn: () => void): number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glmachado/any-store",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"dev": "vite",
|
|
19
|
-
"build": "
|
|
19
|
+
"build": "npm run check && vite build",
|
|
20
20
|
"preview": "vite preview",
|
|
21
|
+
"check": "tsc --build",
|
|
21
22
|
"test": "vitest",
|
|
22
23
|
"bench": "vitest bench",
|
|
23
24
|
"test:browser": "vitest --config=vitest.browser.config.ts",
|
|
24
|
-
"test-ci": "cargo wasm && vitest --run & vitest --config=vitest.browser.config.ts --run & cargo test",
|
|
25
|
+
"test-ci": "cargo wasm && vitest --run & vitest --config=vitest.browser.config.ts --run --browser.headless & cargo test",
|
|
25
26
|
"publish": "npm run build && npm run test-ci && npm publish --access public"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
package/readme.md
CHANGED
|
@@ -1,59 +1,215 @@
|
|
|
1
1
|
## Any Store
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A simple in-memory, embedded database with key-value storage. Share data between different threads and workers without serialization costs. Data can be written and read from worker threads and the main thread using shared WebAssembly memory.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @glmachado/any-store
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
6
12
|
|
|
7
13
|
```ts
|
|
8
|
-
import {
|
|
14
|
+
import { AnyStore } from "@glmachado/any-store";
|
|
15
|
+
|
|
16
|
+
// Create a database
|
|
17
|
+
const db = await AnyStore.create();
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
const table = db.createTable({
|
|
12
|
-
|
|
19
|
+
// Create a table with name and schema
|
|
20
|
+
const table = db.createTable("users", {
|
|
21
|
+
name: "string",
|
|
22
|
+
age: "i32",
|
|
23
|
+
height: "f64",
|
|
13
24
|
});
|
|
14
|
-
const row = table.row(WDB.i32(1));
|
|
15
25
|
|
|
16
|
-
|
|
26
|
+
// Get a row handle
|
|
27
|
+
const row = table.row(AnyStore.i32(1));
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
// Update values
|
|
30
|
+
row.update("name", AnyStore.string("Alice"));
|
|
31
|
+
row.update("age", AnyStore.i32(30));
|
|
32
|
+
row.update("height", AnyStore.f64(1.75));
|
|
20
33
|
|
|
21
|
-
|
|
34
|
+
// Read values
|
|
35
|
+
console.log(row.get("name")); // "Alice"
|
|
36
|
+
console.log(row.get("age")); // 30
|
|
37
|
+
console.log(row.get("height")); // 1.75
|
|
38
|
+
|
|
39
|
+
// Delete a row
|
|
40
|
+
row.delete();
|
|
41
|
+
console.log(row.get("name")); // null
|
|
22
42
|
```
|
|
23
43
|
|
|
24
|
-
##
|
|
44
|
+
## Data Types
|
|
45
|
+
|
|
46
|
+
The library supports the following data types:
|
|
47
|
+
|
|
48
|
+
- `AnyStore.i32(number)` - 32-bit integer
|
|
49
|
+
- `AnyStore.f64(number)` - 64-bit float
|
|
50
|
+
- `AnyStore.string(string)` - UTF-8 string
|
|
51
|
+
- `AnyStore.blob(Uint8Array)` - Binary data
|
|
52
|
+
- `AnyStore.null()` - Null value
|
|
53
|
+
|
|
54
|
+
## Table Operations
|
|
25
55
|
|
|
26
56
|
```ts
|
|
27
|
-
|
|
28
|
-
|
|
57
|
+
const table = db.createTable("products", {
|
|
58
|
+
name: "string",
|
|
59
|
+
price: "f64",
|
|
60
|
+
stock: "i32",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Insert individual columns
|
|
64
|
+
const key = AnyStore.i32(1);
|
|
65
|
+
table.insert(key, AnyStore.string("Laptop"), "name");
|
|
66
|
+
table.insert(key, AnyStore.f64(999.99), "price");
|
|
67
|
+
table.insert(key, AnyStore.i32(5), "stock");
|
|
68
|
+
|
|
69
|
+
// Insert a complete row at once
|
|
70
|
+
table.insertRow(
|
|
71
|
+
AnyStore.i32(2),
|
|
72
|
+
[
|
|
73
|
+
AnyStore.string("Mouse"),
|
|
74
|
+
AnyStore.f64(29.99),
|
|
75
|
+
AnyStore.i32(100),
|
|
76
|
+
]
|
|
77
|
+
);
|
|
29
78
|
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
79
|
+
// Get a single value
|
|
80
|
+
const price = table.get(key, "price"); // 999.99
|
|
81
|
+
|
|
82
|
+
// Get the entire row
|
|
83
|
+
const row = table.getRow(key); // ["Laptop", 999.99, 5]
|
|
84
|
+
|
|
85
|
+
// Delete a row
|
|
86
|
+
table.deleteRow(key);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Reactive Updates with Listeners
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const table = db.createTable("counter", { value: "i32" });
|
|
93
|
+
const row = table.row(AnyStore.i32(1));
|
|
94
|
+
|
|
95
|
+
// Add a listener to be notified when the row changes
|
|
96
|
+
const listenerID = row.addListener(() => {
|
|
97
|
+
console.log("Row changed:", row.get("value"));
|
|
33
98
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
99
|
+
|
|
100
|
+
// Update triggers the listener on next notifyAll()
|
|
101
|
+
row.update("value", AnyStore.i32(10));
|
|
102
|
+
db.notifyAll(); // Triggers all listeners
|
|
103
|
+
|
|
104
|
+
// Remove the listener
|
|
105
|
+
row.removeListener(listenerID);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Cached Rows
|
|
109
|
+
|
|
110
|
+
Use cached rows for better performance when reading values frequently:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const row = table.row(AnyStore.i32(1));
|
|
114
|
+
|
|
115
|
+
// Enable caching with optional update callback
|
|
116
|
+
row.cached(() => {
|
|
117
|
+
console.log("Cache updated:", row.get("value"));
|
|
42
118
|
});
|
|
119
|
+
|
|
120
|
+
row.update("value", AnyStore.i32(10));
|
|
121
|
+
console.log(row.get("value")); // Still old value until notified
|
|
122
|
+
|
|
123
|
+
db.notifyAll(); // Updates cache and triggers callback
|
|
124
|
+
console.log(row.get("value")); // 10 (from cache)
|
|
43
125
|
```
|
|
44
126
|
|
|
127
|
+
## Usage with Workers
|
|
128
|
+
|
|
129
|
+
Share the database across multiple threads without serialization:
|
|
130
|
+
|
|
45
131
|
```ts
|
|
46
|
-
//
|
|
47
|
-
import {
|
|
132
|
+
// Main thread
|
|
133
|
+
import { AnyStore } from "@glmachado/any-store";
|
|
134
|
+
|
|
135
|
+
const db = await AnyStore.create(0); // Worker ID 0 for main thread
|
|
136
|
+
const table = db.createTable("shared", { counter: "i32" });
|
|
137
|
+
|
|
138
|
+
const row = table.row(AnyStore.i32(1));
|
|
139
|
+
row.update("counter", AnyStore.i32(0));
|
|
140
|
+
|
|
141
|
+
// Create worker data to share
|
|
142
|
+
const workerData = db.createWorker();
|
|
143
|
+
|
|
144
|
+
const worker = new Worker("./worker.js");
|
|
145
|
+
worker.postMessage(workerData);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
// Worker thread (worker.js)
|
|
150
|
+
import { AnyStore } from "@glmachado/any-store";
|
|
48
151
|
|
|
49
152
|
self.onmessage = async (event) => {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const db = await WDB.fromModule(module, memory, 1);
|
|
153
|
+
const workerData = event.data;
|
|
154
|
+
const db = await AnyStore.fromModule(workerData);
|
|
53
155
|
|
|
54
|
-
//
|
|
55
|
-
const table = db.getTable(
|
|
56
|
-
|
|
57
|
-
|
|
156
|
+
// Access the table created in the main thread
|
|
157
|
+
const table = db.getTable("shared", { counter: "i32" });
|
|
158
|
+
if (!table) {
|
|
159
|
+
throw new Error("Table not found");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const row = table.row(AnyStore.i32(1));
|
|
163
|
+
|
|
164
|
+
// Read and modify shared data
|
|
165
|
+
db.withLock(() => {
|
|
166
|
+
const current = row.get("counter") as number;
|
|
167
|
+
row.update("counter", AnyStore.i32(current + 1));
|
|
168
|
+
});
|
|
58
169
|
};
|
|
59
|
-
```
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Thread Safety
|
|
173
|
+
|
|
174
|
+
Use `withLock()` to ensure atomic operations when accessing shared data:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
db.withLock(() => {
|
|
178
|
+
const current = row.get("counter") as number;
|
|
179
|
+
row.update("counter", AnyStore.i32(current + 1));
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## API Reference
|
|
184
|
+
|
|
185
|
+
### AnyStore
|
|
186
|
+
|
|
187
|
+
- `static create(id?: number, bufferSource?: BufferSource): Promise<AnyStore>` - Create a new database
|
|
188
|
+
- `static fromModule(workerData: WorkerData): Promise<AnyStore>` - Create from worker data
|
|
189
|
+
- `createTable<T>(name: string, colMap: T): Table<T>` - Create a new table
|
|
190
|
+
- `getTable<T>(name: string, colMap: T): Table<T> | null` - Get an existing table by name
|
|
191
|
+
- `createWorker(): WorkerData` - Create worker data for sharing
|
|
192
|
+
- `withLock<T>(fn: () => T): T` - Execute function with lock
|
|
193
|
+
- `notifyAll(): void` - Notify all listeners
|
|
194
|
+
- `memSize(): number` - Get memory size in pages
|
|
195
|
+
|
|
196
|
+
### Table
|
|
197
|
+
|
|
198
|
+
- `row(key: Something): Row` - Get a row handle
|
|
199
|
+
- `insert(key: Something, value: Something, colName: string): void` - Insert a value
|
|
200
|
+
- `insertRow(key: Something, values: Something[]): void` - Insert a complete row
|
|
201
|
+
- `get(key: Something, colName: string): any` - Get a value
|
|
202
|
+
- `getRow(key: Something): any[]` - Get all values in a row
|
|
203
|
+
- `deleteRow(key: Something): void` - Delete a row
|
|
204
|
+
- `addListenerToRow(key: Something, fn: () => void): number` - Add a listener
|
|
205
|
+
- `removeListenerFromRow(key: Something, listenerID: number): void` - Remove a listener
|
|
206
|
+
|
|
207
|
+
### Row
|
|
208
|
+
|
|
209
|
+
- `get(colName: string): any` - Get a column value
|
|
210
|
+
- `update(colName: string, value: Something): void` - Update a column
|
|
211
|
+
- `delete(): void` - Delete the row
|
|
212
|
+
- `getRow(): any[]` - Get all values
|
|
213
|
+
- `addListener(fn: () => void): number` - Add a listener
|
|
214
|
+
- `cached(onUpdate?: () => void): number` - Enable caching
|
|
215
|
+
- `removeListener(listenerID: number): void` - Remove a listener
|