@quereus/plugin-leveldb 4.0.0 → 4.2.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 +197 -197
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
|
-
# @quereus/plugin-leveldb
|
|
2
|
-
|
|
3
|
-
LevelDB storage plugin for Quereus. Provides persistent storage for Node.js environments using the [`@quereus/store`](../quereus-store/) module.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **Fast**: LevelDB offers excellent read/write performance for key-value workloads
|
|
8
|
-
- **Transaction isolation**: Read-your-own-writes and snapshot isolation by default
|
|
9
|
-
- **Sorted keys**: Efficient range queries with ordered iteration
|
|
10
|
-
- **Crash-safe commits**: A whole transaction's data + secondary-index writes commit in one atomic, durable LevelDB batch (see [Storage layout](#storage-layout))
|
|
11
|
-
- **Compression**: Built-in Snappy compression for reduced disk usage
|
|
12
|
-
|
|
13
|
-
## Storage layout
|
|
14
|
-
|
|
15
|
-
All of a database's stores live inside **one physical LevelDB** at `basePath`,
|
|
16
|
-
each as a [sublevel](https://github.com/Level/abstract-level#sublevel) keyed by
|
|
17
|
-
its store name:
|
|
18
|
-
|
|
19
|
-
| Logical store | Sublevel name |
|
|
20
|
-
|---|---|
|
|
21
|
-
| Table data | `{schema}.{table}` |
|
|
22
|
-
| Secondary index | `{schema}.{table}_idx_{name}` |
|
|
23
|
-
| Unified stats | `__stats__` |
|
|
24
|
-
| Catalog (DDL) | `__catalog__` |
|
|
25
|
-
|
|
26
|
-
Because every sublevel shares one physical store, a single chained batch commits
|
|
27
|
-
across all of a table's sublevels (data + every secondary index) **atomically and
|
|
28
|
-
durably** — closing the crash window where a per-store commit loop could leave a
|
|
29
|
-
table's rows and its indexes divergent on disk. By default each commit is
|
|
30
|
-
`fsync`'d so it survives power loss; see [`syncCommits`](#plugin-settings).
|
|
31
|
-
|
|
32
|
-
> **Hard cutover (no on-disk migration).** This shared-root layout is the only
|
|
33
|
-
> LevelDB layout. Databases written by the older per-directory layout
|
|
34
|
-
> (`{basePath}/{schema}/{table}`, a separate LevelDB per table) are **not** read
|
|
35
|
-
> by this version and must be re-created. Pre-1.0 dev data is expected to be
|
|
36
|
-
> thrown away; there is no migration importer.
|
|
37
|
-
|
|
38
|
-
## Installation
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm install @quereus/plugin-leveldb @quereus/store @quereus/isolation
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Quick Start
|
|
45
|
-
|
|
46
|
-
### With registerPlugin (Recommended)
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { Database, registerPlugin } from '@quereus/quereus';
|
|
50
|
-
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
|
|
51
|
-
|
|
52
|
-
const db = new Database();
|
|
53
|
-
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
|
|
54
|
-
|
|
55
|
-
await db.exec(`
|
|
56
|
-
create table users (id integer primary key, name text)
|
|
57
|
-
using store
|
|
58
|
-
`);
|
|
59
|
-
|
|
60
|
-
// Full transaction isolation enabled by default
|
|
61
|
-
await db.exec('BEGIN');
|
|
62
|
-
await db.exec(`INSERT INTO users VALUES (1, 'Alice')`);
|
|
63
|
-
const user = await db.get('SELECT * FROM users WHERE id = 1'); // Sees uncommitted insert
|
|
64
|
-
await db.exec('COMMIT');
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Disabling Isolation
|
|
68
|
-
|
|
69
|
-
If you need maximum performance and don't require read-your-own-writes within transactions:
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
await registerPlugin(db, leveldbPlugin, {
|
|
73
|
-
basePath: './data',
|
|
74
|
-
isolation: false // Disable isolation layer
|
|
75
|
-
});
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Direct Usage with Provider
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
import { Database } from '@quereus/quereus';
|
|
82
|
-
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
|
|
83
|
-
import { createIsolatedStoreModule } from '@quereus/store';
|
|
84
|
-
|
|
85
|
-
const db = new Database();
|
|
86
|
-
const provider = createLevelDBProvider({ basePath: './data' });
|
|
87
|
-
|
|
88
|
-
// With isolation (recommended)
|
|
89
|
-
const storeModule = createIsolatedStoreModule({ provider });
|
|
90
|
-
db.registerModule('store', storeModule);
|
|
91
|
-
|
|
92
|
-
await db.exec(`
|
|
93
|
-
create table users (id integer primary key, name text)
|
|
94
|
-
using store
|
|
95
|
-
`);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## API
|
|
99
|
-
|
|
100
|
-
### LevelDBStore
|
|
101
|
-
|
|
102
|
-
Low-level KVStore implementation. `LevelDBStore.open()` opens a **standalone**
|
|
103
|
-
single physical LevelDB database — useful for one-off key-value stores (e.g. sync
|
|
104
|
-
metadata). The multi-table StoreModule backend does not use this directly; it
|
|
105
|
-
opens one shared root and hands out sublevel-backed stores via `LevelDBProvider`.
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import { LevelDBStore } from '@quereus/plugin-leveldb';
|
|
109
|
-
|
|
110
|
-
const store = await LevelDBStore.open({ path: './data/mystore' });
|
|
111
|
-
|
|
112
|
-
await store.put(key, value);
|
|
113
|
-
const data = await store.get(key);
|
|
114
|
-
await store.delete(key);
|
|
115
|
-
|
|
116
|
-
// Range iteration
|
|
117
|
-
for await (const { key, value } of store.iterate({ gte: startKey, lt: endKey })) {
|
|
118
|
-
console.log(key, value);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Batch writes
|
|
122
|
-
const batch = store.batch();
|
|
123
|
-
batch.put(key1, value1);
|
|
124
|
-
batch.put(key2, value2);
|
|
125
|
-
batch.delete(key3);
|
|
126
|
-
await batch.write();
|
|
127
|
-
|
|
128
|
-
await store.close();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### LevelDBProvider
|
|
132
|
-
|
|
133
|
-
Factory for managing multiple stores:
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
|
|
137
|
-
|
|
138
|
-
const provider = createLevelDBProvider({ basePath: './data' });
|
|
139
|
-
|
|
140
|
-
// All stores are sublevels of the single LevelDB at ./data
|
|
141
|
-
const userStore = await provider.getStore('main', 'users'); // sublevel main.users
|
|
142
|
-
const catalogStore = await provider.getCatalogStore(); // sublevel __catalog__
|
|
143
|
-
|
|
144
|
-
await provider.closeStore('main', 'users'); // drops the sublevel handle
|
|
145
|
-
await provider.closeAll(); // closes the shared root
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Configuration
|
|
149
|
-
|
|
150
|
-
### Plugin Settings
|
|
151
|
-
|
|
152
|
-
| Setting | Type | Default | Description |
|
|
153
|
-
|---------|------|---------|-------------|
|
|
154
|
-
| `basePath` | string | `'./data'` | Directory of the single shared LevelDB database |
|
|
155
|
-
| `createIfMissing` | boolean | `true` | Create the database if it doesn't exist |
|
|
156
|
-
| `syncCommits` | boolean | `true` | `fsync` each transaction commit so it survives power loss (slower commits when on) |
|
|
157
|
-
| `moduleName` | string | `'store'` | Name to register the virtual table module under |
|
|
158
|
-
| `isolation` | boolean | `true` | Wrap with the isolation layer (read-your-own-writes, snapshot isolation) |
|
|
159
|
-
|
|
160
|
-
### LevelDBStore Options (standalone `open`)
|
|
161
|
-
|
|
162
|
-
| Option | Type | Default | Description |
|
|
163
|
-
|--------|------|---------|-------------|
|
|
164
|
-
| `path` | string | required | Directory path for the database |
|
|
165
|
-
| `createIfMissing` | boolean | `true` | Create database if it doesn't exist |
|
|
166
|
-
|
|
167
|
-
## Example with Transactions
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
import { Database, registerPlugin } from '@quereus/quereus';
|
|
171
|
-
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
|
|
172
|
-
|
|
173
|
-
const db = new Database();
|
|
174
|
-
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
|
|
175
|
-
|
|
176
|
-
await db.exec(`create table accounts (id integer primary key, balance real) using store`);
|
|
177
|
-
|
|
178
|
-
await db.exec('begin');
|
|
179
|
-
try {
|
|
180
|
-
await db.exec(`update accounts set balance = balance - 100 where id = 1`);
|
|
181
|
-
await db.exec(`update accounts set balance = balance + 100 where id = 2`);
|
|
182
|
-
await db.exec('commit');
|
|
183
|
-
} catch (e) {
|
|
184
|
-
await db.exec('rollback');
|
|
185
|
-
throw e;
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
## Related Packages
|
|
190
|
-
|
|
191
|
-
- [`@quereus/store`](../quereus-store/) - Core storage module (StoreModule, StoreTable)
|
|
192
|
-
- [`@quereus/plugin-indexeddb`](../quereus-plugin-indexeddb/) - IndexedDB plugin for browsers
|
|
193
|
-
|
|
194
|
-
## License
|
|
195
|
-
|
|
196
|
-
MIT
|
|
197
|
-
|
|
1
|
+
# @quereus/plugin-leveldb
|
|
2
|
+
|
|
3
|
+
LevelDB storage plugin for Quereus. Provides persistent storage for Node.js environments using the [`@quereus/store`](../quereus-store/) module.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Fast**: LevelDB offers excellent read/write performance for key-value workloads
|
|
8
|
+
- **Transaction isolation**: Read-your-own-writes and snapshot isolation by default
|
|
9
|
+
- **Sorted keys**: Efficient range queries with ordered iteration
|
|
10
|
+
- **Crash-safe commits**: A whole transaction's data + secondary-index writes commit in one atomic, durable LevelDB batch (see [Storage layout](#storage-layout))
|
|
11
|
+
- **Compression**: Built-in Snappy compression for reduced disk usage
|
|
12
|
+
|
|
13
|
+
## Storage layout
|
|
14
|
+
|
|
15
|
+
All of a database's stores live inside **one physical LevelDB** at `basePath`,
|
|
16
|
+
each as a [sublevel](https://github.com/Level/abstract-level#sublevel) keyed by
|
|
17
|
+
its store name:
|
|
18
|
+
|
|
19
|
+
| Logical store | Sublevel name |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Table data | `{schema}.{table}` |
|
|
22
|
+
| Secondary index | `{schema}.{table}_idx_{name}` |
|
|
23
|
+
| Unified stats | `__stats__` |
|
|
24
|
+
| Catalog (DDL) | `__catalog__` |
|
|
25
|
+
|
|
26
|
+
Because every sublevel shares one physical store, a single chained batch commits
|
|
27
|
+
across all of a table's sublevels (data + every secondary index) **atomically and
|
|
28
|
+
durably** — closing the crash window where a per-store commit loop could leave a
|
|
29
|
+
table's rows and its indexes divergent on disk. By default each commit is
|
|
30
|
+
`fsync`'d so it survives power loss; see [`syncCommits`](#plugin-settings).
|
|
31
|
+
|
|
32
|
+
> **Hard cutover (no on-disk migration).** This shared-root layout is the only
|
|
33
|
+
> LevelDB layout. Databases written by the older per-directory layout
|
|
34
|
+
> (`{basePath}/{schema}/{table}`, a separate LevelDB per table) are **not** read
|
|
35
|
+
> by this version and must be re-created. Pre-1.0 dev data is expected to be
|
|
36
|
+
> thrown away; there is no migration importer.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install @quereus/plugin-leveldb @quereus/store @quereus/isolation
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
### With registerPlugin (Recommended)
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Database, registerPlugin } from '@quereus/quereus';
|
|
50
|
+
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
|
|
51
|
+
|
|
52
|
+
const db = new Database();
|
|
53
|
+
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
|
|
54
|
+
|
|
55
|
+
await db.exec(`
|
|
56
|
+
create table users (id integer primary key, name text)
|
|
57
|
+
using store
|
|
58
|
+
`);
|
|
59
|
+
|
|
60
|
+
// Full transaction isolation enabled by default
|
|
61
|
+
await db.exec('BEGIN');
|
|
62
|
+
await db.exec(`INSERT INTO users VALUES (1, 'Alice')`);
|
|
63
|
+
const user = await db.get('SELECT * FROM users WHERE id = 1'); // Sees uncommitted insert
|
|
64
|
+
await db.exec('COMMIT');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Disabling Isolation
|
|
68
|
+
|
|
69
|
+
If you need maximum performance and don't require read-your-own-writes within transactions:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
await registerPlugin(db, leveldbPlugin, {
|
|
73
|
+
basePath: './data',
|
|
74
|
+
isolation: false // Disable isolation layer
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Direct Usage with Provider
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { Database } from '@quereus/quereus';
|
|
82
|
+
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
|
|
83
|
+
import { createIsolatedStoreModule } from '@quereus/store';
|
|
84
|
+
|
|
85
|
+
const db = new Database();
|
|
86
|
+
const provider = createLevelDBProvider({ basePath: './data' });
|
|
87
|
+
|
|
88
|
+
// With isolation (recommended)
|
|
89
|
+
const storeModule = createIsolatedStoreModule({ provider });
|
|
90
|
+
db.registerModule('store', storeModule);
|
|
91
|
+
|
|
92
|
+
await db.exec(`
|
|
93
|
+
create table users (id integer primary key, name text)
|
|
94
|
+
using store
|
|
95
|
+
`);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API
|
|
99
|
+
|
|
100
|
+
### LevelDBStore
|
|
101
|
+
|
|
102
|
+
Low-level KVStore implementation. `LevelDBStore.open()` opens a **standalone**
|
|
103
|
+
single physical LevelDB database — useful for one-off key-value stores (e.g. sync
|
|
104
|
+
metadata). The multi-table StoreModule backend does not use this directly; it
|
|
105
|
+
opens one shared root and hands out sublevel-backed stores via `LevelDBProvider`.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { LevelDBStore } from '@quereus/plugin-leveldb';
|
|
109
|
+
|
|
110
|
+
const store = await LevelDBStore.open({ path: './data/mystore' });
|
|
111
|
+
|
|
112
|
+
await store.put(key, value);
|
|
113
|
+
const data = await store.get(key);
|
|
114
|
+
await store.delete(key);
|
|
115
|
+
|
|
116
|
+
// Range iteration
|
|
117
|
+
for await (const { key, value } of store.iterate({ gte: startKey, lt: endKey })) {
|
|
118
|
+
console.log(key, value);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Batch writes
|
|
122
|
+
const batch = store.batch();
|
|
123
|
+
batch.put(key1, value1);
|
|
124
|
+
batch.put(key2, value2);
|
|
125
|
+
batch.delete(key3);
|
|
126
|
+
await batch.write();
|
|
127
|
+
|
|
128
|
+
await store.close();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### LevelDBProvider
|
|
132
|
+
|
|
133
|
+
Factory for managing multiple stores:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { createLevelDBProvider } from '@quereus/plugin-leveldb';
|
|
137
|
+
|
|
138
|
+
const provider = createLevelDBProvider({ basePath: './data' });
|
|
139
|
+
|
|
140
|
+
// All stores are sublevels of the single LevelDB at ./data
|
|
141
|
+
const userStore = await provider.getStore('main', 'users'); // sublevel main.users
|
|
142
|
+
const catalogStore = await provider.getCatalogStore(); // sublevel __catalog__
|
|
143
|
+
|
|
144
|
+
await provider.closeStore('main', 'users'); // drops the sublevel handle
|
|
145
|
+
await provider.closeAll(); // closes the shared root
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Configuration
|
|
149
|
+
|
|
150
|
+
### Plugin Settings
|
|
151
|
+
|
|
152
|
+
| Setting | Type | Default | Description |
|
|
153
|
+
|---------|------|---------|-------------|
|
|
154
|
+
| `basePath` | string | `'./data'` | Directory of the single shared LevelDB database |
|
|
155
|
+
| `createIfMissing` | boolean | `true` | Create the database if it doesn't exist |
|
|
156
|
+
| `syncCommits` | boolean | `true` | `fsync` each transaction commit so it survives power loss (slower commits when on) |
|
|
157
|
+
| `moduleName` | string | `'store'` | Name to register the virtual table module under |
|
|
158
|
+
| `isolation` | boolean | `true` | Wrap with the isolation layer (read-your-own-writes, snapshot isolation) |
|
|
159
|
+
|
|
160
|
+
### LevelDBStore Options (standalone `open`)
|
|
161
|
+
|
|
162
|
+
| Option | Type | Default | Description |
|
|
163
|
+
|--------|------|---------|-------------|
|
|
164
|
+
| `path` | string | required | Directory path for the database |
|
|
165
|
+
| `createIfMissing` | boolean | `true` | Create database if it doesn't exist |
|
|
166
|
+
|
|
167
|
+
## Example with Transactions
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { Database, registerPlugin } from '@quereus/quereus';
|
|
171
|
+
import leveldbPlugin from '@quereus/plugin-leveldb/plugin';
|
|
172
|
+
|
|
173
|
+
const db = new Database();
|
|
174
|
+
await registerPlugin(db, leveldbPlugin, { basePath: './data' });
|
|
175
|
+
|
|
176
|
+
await db.exec(`create table accounts (id integer primary key, balance real) using store`);
|
|
177
|
+
|
|
178
|
+
await db.exec('begin');
|
|
179
|
+
try {
|
|
180
|
+
await db.exec(`update accounts set balance = balance - 100 where id = 1`);
|
|
181
|
+
await db.exec(`update accounts set balance = balance + 100 where id = 2`);
|
|
182
|
+
await db.exec('commit');
|
|
183
|
+
} catch (e) {
|
|
184
|
+
await db.exec('rollback');
|
|
185
|
+
throw e;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Related Packages
|
|
190
|
+
|
|
191
|
+
- [`@quereus/store`](../quereus-store/) - Core storage module (StoreModule, StoreTable)
|
|
192
|
+
- [`@quereus/plugin-indexeddb`](../quereus-plugin-indexeddb/) - IndexedDB plugin for browsers
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
|
197
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quereus/plugin-leveldb",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "LevelDB storage plugin for Quereus - Node.js persistent storage",
|
|
6
6
|
"keywords": [
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@quereus/isolation": "^4.
|
|
41
|
-
"@quereus/quereus": "^4.
|
|
42
|
-
"@quereus/store": "^4.
|
|
40
|
+
"@quereus/isolation": "^4.2.0",
|
|
41
|
+
"@quereus/quereus": "^4.2.0",
|
|
42
|
+
"@quereus/store": "^4.2.0"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"quereus": "^0.24.0"
|
|
@@ -95,18 +95,18 @@
|
|
|
95
95
|
"test": "cd ../.. && node --import ./packages/quereus-plugin-leveldb/register.mjs node_modules/mocha/bin/mocha.js \"packages/quereus-plugin-leveldb/test/**/*.spec.ts\" --reporter min --colors"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@quereus/quereus": "^4.
|
|
99
|
-
"@quereus/store": "^4.
|
|
98
|
+
"@quereus/quereus": "^4.2.0",
|
|
99
|
+
"@quereus/store": "^4.2.0",
|
|
100
100
|
"abstract-level": "^3.1.0",
|
|
101
101
|
"classic-level": "^3.0.0"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@quereus/isolation": "*",
|
|
105
105
|
"@types/mocha": "^10.0.10",
|
|
106
|
-
"@types/node": "^25.
|
|
106
|
+
"@types/node": "^25.9.3",
|
|
107
107
|
"chai": "^6.2.2",
|
|
108
|
-
"mocha": "^11.7.
|
|
109
|
-
"rimraf": "^6.1.
|
|
108
|
+
"mocha": "^11.7.6",
|
|
109
|
+
"rimraf": "^6.1.3",
|
|
110
110
|
"ts-node": "^10.9.2",
|
|
111
111
|
"typescript": "^5.9.3"
|
|
112
112
|
}
|