shelfdb 2.0.0__tar.gz → 2.0.0.dev0__tar.gz
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.
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/PKG-INFO +1 -1
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/pyproject.toml +2 -2
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/SKILL.md +90 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/embedded-mode.md +2 -3
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/server-mode.md +7 -10
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/transactions.md +4 -12
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/client/_impl.py +2 -24
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/server/rpc.py +3 -2
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/shelf/core.py +1 -7
- shelfdb-2.0.0/src/shelfdb/ai_skill/shelfdb-usage/SKILL.md +0 -115
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/LICENSE +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/README.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/agents/openai.yaml +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/api-reference.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/getting-started.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/index.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/protocol.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/query-model.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/security.md +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/cli.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/client/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/log.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/protocol/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/protocol/codec.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/protocol/payload.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/protocol/query.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/protocol/schema.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/server/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/server/runtime.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/shelf/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/shelf/normalize.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/shelf/query.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/shelf/storage/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/shelf/storage/lmdb.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/util/__init__.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/util/transport.py +0 -0
- {shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/util/validation.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "shelfdb"
|
|
7
|
-
version = "2.0.0"
|
|
7
|
+
version = "2.0.0.dev0"
|
|
8
8
|
description = "A tiny documents database for Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -38,7 +38,7 @@ dev = [
|
|
|
38
38
|
"mkdocs>=1.6.1,<2",
|
|
39
39
|
"mkdocs-shadcn>=0.10.4,<0.11",
|
|
40
40
|
"mkdocstrings[python]>=0.29.0,<0.30",
|
|
41
|
-
"pytest>=8.4.2,<
|
|
41
|
+
"pytest>=8.4.2,<9",
|
|
42
42
|
]
|
|
43
43
|
|
|
44
44
|
[tool.uv.build-backend]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shelfdb-usage
|
|
3
|
+
description: "ShelfDB developer workflow for running the local server and querying it from sync or async Python clients. Use when Codex needs to write or debug ShelfDB server-mode code, client queries, transactions, logging, or examples that call `shelfdb.connect`, `connect_async`, `.run()`, or `tx.commit()`."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ShelfDB usage
|
|
7
|
+
|
|
8
|
+
Prefer the simplest mode that fits the task.
|
|
9
|
+
|
|
10
|
+
## Reference docs
|
|
11
|
+
|
|
12
|
+
- Read `references/docs/` for mirrored ShelfDB documentation when you need the full narrative docs.
|
|
13
|
+
- Prefer the most specific page for the task: `server-mode.md`, `query-model.md`, `transactions.md`, and `security.md` are the usual first reads.
|
|
14
|
+
|
|
15
|
+
## Choose the mode
|
|
16
|
+
|
|
17
|
+
- Use embedded mode with `shelfdb.open(...)` when the process can access the LMDB directory directly.
|
|
18
|
+
- Use server mode only when a separate process or multi-client access is required.
|
|
19
|
+
|
|
20
|
+
## Start the server
|
|
21
|
+
|
|
22
|
+
- Run `shelfdb` for the default TCP server on `127.0.0.1:17000` with the `db/` directory.
|
|
23
|
+
- Use `shelfdb --url tcp://HOST:PORT` or `shelfdb --url unix:///path/to/socket.sock` when an explicit transport is needed.
|
|
24
|
+
- Keep the server on loopback or a Unix socket. Treat the RPC layer as trusted-local only.
|
|
25
|
+
|
|
26
|
+
## Connect from Python
|
|
27
|
+
|
|
28
|
+
- Use `shelfdb.connect(url)` in sync code.
|
|
29
|
+
- Use `await shelfdb.connect_async(url)` in async code.
|
|
30
|
+
- Await only `connect_async(...)`, `query.run()` in async code, and `tx.commit()`.
|
|
31
|
+
|
|
32
|
+
## Build queries lazily
|
|
33
|
+
|
|
34
|
+
- Chain query methods and execute only with `.run()`.
|
|
35
|
+
- Reuse the same query object when you need to run the same pipeline again.
|
|
36
|
+
- Use the same query style in embedded and remote code.
|
|
37
|
+
|
|
38
|
+
Available operations:
|
|
39
|
+
|
|
40
|
+
- Read: `key`, `key_range`, `keys_in`, `filter`, `slice`, `first`, `count`
|
|
41
|
+
- Write: `put`, `put_many`, `update`, `replace`, `edit`, `delete`
|
|
42
|
+
|
|
43
|
+
## Handle results correctly
|
|
44
|
+
|
|
45
|
+
- Local multi-item `.run()` returns a one-shot iterator of `['key', data]` items; wrap it in `list(...)` if you need reuse.
|
|
46
|
+
- Remote results are normalized into plain Python values.
|
|
47
|
+
- `first()` returns one item or `None`.
|
|
48
|
+
- `put_many()` returns `None`.
|
|
49
|
+
|
|
50
|
+
## Respect batch and transaction behavior
|
|
51
|
+
|
|
52
|
+
- Pass iterables to `put_many()` and `keys_in()`, but assume the client materializes them before send.
|
|
53
|
+
- `keys_in()` keeps the requested key order and may repeat keys.
|
|
54
|
+
- Use `client.transaction(write=True)` for remote batches; queue queries with `.run()` and send them with `tx.commit()`.
|
|
55
|
+
- Use `db.transaction(write=True)` for embedded atomic writes; inside a local transaction, use `tx.shelf(...)`, not `db.shelf(...)`.
|
|
56
|
+
|
|
57
|
+
## Safety checks
|
|
58
|
+
|
|
59
|
+
- Keep callable `filter()` and `edit()` functions simple and trusted; the protocol uses `dill`.
|
|
60
|
+
- Configure debug logs with `shelfdb.log.configure_logging("debug")` when diagnosing client or server behavior.
|
|
61
|
+
- Do not expose the server to untrusted networks.
|
|
62
|
+
|
|
63
|
+
## Minimal patterns
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import shelfdb
|
|
67
|
+
|
|
68
|
+
client = shelfdb.connect("tcp://127.0.0.1:17000")
|
|
69
|
+
note = client.shelf("note").key("note-1").first().run()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import asyncio
|
|
74
|
+
import shelfdb
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def main():
|
|
78
|
+
client = await shelfdb.connect_async("unix:///tmp/shelfdb.sock")
|
|
79
|
+
rows = await client.shelf("note").keys_in(["note-1", "note-2"]).run()
|
|
80
|
+
print(rows)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
asyncio.run(main())
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
tx = client.transaction(write=True)
|
|
88
|
+
tx.shelf("note").put("note-1", {"title": "ShelfDB"}).run()
|
|
89
|
+
tx.commit()
|
|
90
|
+
```
|
|
@@ -149,8 +149,7 @@ db.close()
|
|
|
149
149
|
For consistent reads and atomic writes, use `with db.transaction(...) as tx:` and create
|
|
150
150
|
transaction-scoped queries with `tx.shelf(...)`.
|
|
151
151
|
|
|
152
|
-
Inside the block, embedded `.run()` calls execute immediately
|
|
153
|
-
|
|
154
|
-
stores the commit result on `tx.result`.
|
|
152
|
+
Inside the block, embedded `.run()` calls execute immediately. Remote client transactions queue
|
|
153
|
+
their steps until `tx.commit()`.
|
|
155
154
|
|
|
156
155
|
See [Transactions](transactions.md) for the full behavior and examples.
|
|
@@ -147,21 +147,18 @@ Remote transaction queries queue their steps when you call `.run()`, unlike embe
|
|
|
147
147
|
where `.run()` executes immediately inside the `with` block.
|
|
148
148
|
|
|
149
149
|
!!! info "Information:"
|
|
150
|
-
Call `tx.commit()` to send the batch
|
|
151
|
-
to auto-commit and store the commit result on `tx.result`.
|
|
150
|
+
Call `tx.commit()` to send the batch.
|
|
152
151
|
|
|
153
152
|
```python
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
print(tx.result)
|
|
153
|
+
tx = client.transaction(write=True)
|
|
154
|
+
tx.shelf("note").put("note-1", {"title": "ShelfDB"}).run()
|
|
155
|
+
tx.shelf("user").put("user-1", {"name": "alice"}).run()
|
|
156
|
+
tx.commit()
|
|
159
157
|
```
|
|
160
158
|
|
|
161
|
-
`tx.commit()` returns the last queued query result, or `None` for an empty transaction
|
|
162
|
-
that value on `tx.result`.
|
|
159
|
+
`tx.commit()` returns the last queued query result, or `None` for an empty transaction.
|
|
163
160
|
|
|
164
|
-
For async code, use `
|
|
161
|
+
For async code, use `await tx.commit()` instead.
|
|
165
162
|
|
|
166
163
|
Transaction queries must belong to the transaction they are queued into.
|
|
167
164
|
|
|
@@ -5,8 +5,8 @@ ShelfDB supports database transactions for two main purposes:
|
|
|
5
5
|
- **consistent reads** with a stable snapshot
|
|
6
6
|
- **atomic writes** that either all commit or all roll back
|
|
7
7
|
|
|
8
|
-
Embedded transactions execute each query when you call `.run()` inside the `with` block
|
|
9
|
-
Client transactions queue each query on `.run()` and
|
|
8
|
+
Embedded transactions execute each query when you call `.run()` inside the `with` block.
|
|
9
|
+
Client transactions queue each query on `.run()` and execute the batch later with `tx.commit()`.
|
|
10
10
|
|
|
11
11
|
## Read transactions
|
|
12
12
|
|
|
@@ -56,7 +56,6 @@ except RuntimeError:
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
After that error, the update is not committed.
|
|
59
|
-
`tx.result` still reflects the last successful query result from inside the aborted block.
|
|
60
59
|
|
|
61
60
|
## Read your own writes
|
|
62
61
|
|
|
@@ -114,15 +113,8 @@ tx.shelf("note").put("note-1", {"title": "hello"}).run()
|
|
|
114
113
|
tx.commit()
|
|
115
114
|
```
|
|
116
115
|
|
|
117
|
-
`tx.commit()` returns the last queued query result, or `None` for an empty transaction
|
|
116
|
+
`tx.commit()` returns the last queued query result, or `None` for an empty transaction.
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
```python
|
|
122
|
-
with client.transaction(write=True) as tx:
|
|
123
|
-
tx.shelf("note").put("note-1", {"title": "hello"}).run()
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
For async code, use `async with` or `await tx.commit()` instead.
|
|
118
|
+
For async code, use `await tx.commit()` instead.
|
|
127
119
|
|
|
128
120
|
See [Server Mode](server-mode.md) for connection setup and the shared remote query model.
|
|
@@ -174,7 +174,6 @@ class AsyncClientTransaction:
|
|
|
174
174
|
self._write = write
|
|
175
175
|
self._txs: list[TransactionShelfRequest] = []
|
|
176
176
|
self._ran = False
|
|
177
|
-
self.result = None
|
|
178
177
|
|
|
179
178
|
def _enqueue(self, query: AsyncTransactionQuery):
|
|
180
179
|
if self._ran:
|
|
@@ -195,23 +194,13 @@ class AsyncClientTransaction:
|
|
|
195
194
|
|
|
196
195
|
return AsyncTransactionQuery(self, require_shelf_name(shelf_name))
|
|
197
196
|
|
|
198
|
-
async def __aenter__(self):
|
|
199
|
-
return self
|
|
200
|
-
|
|
201
|
-
async def __aexit__(self, exc_type, exc, tb):
|
|
202
|
-
if exc_type is None and not self._ran:
|
|
203
|
-
await self.commit()
|
|
204
|
-
return False
|
|
205
|
-
|
|
206
197
|
async def commit(self):
|
|
207
198
|
if self._ran:
|
|
208
199
|
raise RuntimeError("Transaction already ran.")
|
|
209
200
|
|
|
210
201
|
self._ran = True
|
|
211
202
|
payload = make_transaction_request(self._write, self._txs)
|
|
212
|
-
|
|
213
|
-
self.result = result
|
|
214
|
-
return result
|
|
203
|
+
return await self._client._request(payload)
|
|
215
204
|
|
|
216
205
|
async def run(self):
|
|
217
206
|
return await self.commit()
|
|
@@ -320,7 +309,6 @@ class SyncClientTransaction:
|
|
|
320
309
|
self._write = write
|
|
321
310
|
self._txs: list[TransactionShelfRequest] = []
|
|
322
311
|
self._ran = False
|
|
323
|
-
self.result = None
|
|
324
312
|
|
|
325
313
|
def _enqueue(self, query: SyncTransactionQuery):
|
|
326
314
|
if self._ran:
|
|
@@ -341,23 +329,13 @@ class SyncClientTransaction:
|
|
|
341
329
|
|
|
342
330
|
return SyncTransactionQuery(self, require_shelf_name(shelf_name))
|
|
343
331
|
|
|
344
|
-
def __enter__(self):
|
|
345
|
-
return self
|
|
346
|
-
|
|
347
|
-
def __exit__(self, exc_type, exc, tb):
|
|
348
|
-
if exc_type is None and not self._ran:
|
|
349
|
-
self.commit()
|
|
350
|
-
return False
|
|
351
|
-
|
|
352
332
|
def commit(self):
|
|
353
333
|
if self._ran:
|
|
354
334
|
raise RuntimeError("Transaction already ran.")
|
|
355
335
|
|
|
356
336
|
self._ran = True
|
|
357
337
|
payload = make_transaction_request(self._write, self._txs)
|
|
358
|
-
|
|
359
|
-
self.result = result
|
|
360
|
-
return result
|
|
338
|
+
return self._client._request(payload)
|
|
361
339
|
|
|
362
340
|
def run(self):
|
|
363
341
|
return self.commit()
|
|
@@ -11,14 +11,15 @@ def run_query_request(db, shelf, queries):
|
|
|
11
11
|
|
|
12
12
|
def run_transaction_request(db, write, txs):
|
|
13
13
|
"""Execute one transaction request and return its last result."""
|
|
14
|
+
last_result = None
|
|
14
15
|
with db.transaction(write=write) as tx:
|
|
15
16
|
for tx_payload in txs:
|
|
16
17
|
match tx_payload:
|
|
17
18
|
case {"shelf": shelf, "queries": queries}:
|
|
18
|
-
replay_queries(tx.shelf(shelf), queries).run()
|
|
19
|
+
last_result = replay_queries(tx.shelf(shelf), queries).run()
|
|
19
20
|
case _:
|
|
20
21
|
raise ValueError("Transaction payload item is invalid.")
|
|
21
|
-
return
|
|
22
|
+
return last_result
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def run_request(db, payload):
|
|
@@ -34,7 +34,6 @@ class Transaction:
|
|
|
34
34
|
self._db = db
|
|
35
35
|
self.txn = txn
|
|
36
36
|
self.write = write
|
|
37
|
-
self.result = None
|
|
38
37
|
|
|
39
38
|
def shelf(self, shelf_name: str) -> "ShelfQuery":
|
|
40
39
|
"""Create one query builder bound to this active transaction."""
|
|
@@ -322,12 +321,7 @@ class ShelfQuery(QueryBuilderMixin):
|
|
|
322
321
|
with self._db.transaction(write=True):
|
|
323
322
|
return self._run_queries()
|
|
324
323
|
|
|
325
|
-
|
|
326
|
-
if self._tx_context is not None:
|
|
327
|
-
if isinstance(result, Iterator):
|
|
328
|
-
result = list(result)
|
|
329
|
-
self._tx_context.result = result
|
|
330
|
-
return result
|
|
324
|
+
return self._run_queries()
|
|
331
325
|
|
|
332
326
|
def _has_write_step(self) -> bool:
|
|
333
327
|
return any(query.get("write") is True for query in self.queries)
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: shelfdb-usage
|
|
3
|
-
description: "ShelfDB developer workflow for embedded and server-mode usage, including local transactions, client queries, logging, and examples that call `shelfdb.open`, `connect`, `connect_async`, `.run()`, or `tx.commit()`."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ShelfDB usage
|
|
7
|
-
|
|
8
|
-
Prefer embedded mode first; use server mode only when you need a separate process or multiple trusted local clients.
|
|
9
|
-
|
|
10
|
-
## Reference docs
|
|
11
|
-
|
|
12
|
-
- Read `references/docs/` for mirrored ShelfDB documentation when you need the full narrative docs.
|
|
13
|
-
- Prefer the most specific page for the task: `embedded-mode.md`, `server-mode.md`, `transactions.md`, `query-model.md`, and `security.md` are the usual first reads.
|
|
14
|
-
|
|
15
|
-
## Choose the mode
|
|
16
|
-
|
|
17
|
-
- Use `shelfdb.open(path)` when the Python process can access the LMDB directory directly.
|
|
18
|
-
- Use server mode when you need a process boundary, a remote client, or shared access from several trusted local processes.
|
|
19
|
-
- Keep server mode on loopback or a Unix socket. Treat the RPC layer as trusted-local only.
|
|
20
|
-
|
|
21
|
-
## Start the server
|
|
22
|
-
|
|
23
|
-
- Run `shelfdb` for the default TCP server on `127.0.0.1:17000` with the `db` directory.
|
|
24
|
-
- Use `shelfdb --url tcp://HOST:PORT` or `shelfdb --url unix:///path/to/socket.sock` when an explicit transport is needed.
|
|
25
|
-
- Use `shelfdb --db ./data/app-db` to choose a different database path.
|
|
26
|
-
- Use `shelfdb --log-level debug` when you need server-side diagnostics.
|
|
27
|
-
|
|
28
|
-
## Connect from Python
|
|
29
|
-
|
|
30
|
-
- Use `shelfdb.connect(url)` in sync code.
|
|
31
|
-
- Use `await shelfdb.connect_async(url)` in async code.
|
|
32
|
-
- Await only `connect_async(...)`, remote query `.run()` calls, and `tx.commit()`.
|
|
33
|
-
- Embedded transactions are sync `with db.transaction(...)` blocks, and their `.run()` calls execute immediately inside the block.
|
|
34
|
-
- Remote transaction queries like `tx.shelf(...).run()` only queue work and return `None`; remote transactions also support `with` / `async with`, and `tx.commit()` returns the last queued result and stores it on `tx.result`.
|
|
35
|
-
|
|
36
|
-
## Build queries lazily
|
|
37
|
-
|
|
38
|
-
- Chain query methods and execute only with `.run()`.
|
|
39
|
-
- Reuse the same query object when you need to run the same pipeline again.
|
|
40
|
-
- Use the same query style in embedded and remote code.
|
|
41
|
-
|
|
42
|
-
Available operations:
|
|
43
|
-
|
|
44
|
-
- Read: `key`, `key_range`, `keys_in`, `filter`, `slice`, `first`, `count`
|
|
45
|
-
- Write: `put`, `put_many`, `update`, `replace`, `edit`, `delete`
|
|
46
|
-
|
|
47
|
-
Selection rules:
|
|
48
|
-
|
|
49
|
-
- Call `keys_in()` on the base shelf before chaining other selection steps.
|
|
50
|
-
- `replace()`, `update()`, and `edit()` require an existing selection.
|
|
51
|
-
- `delete()` is the mutator that is safe on a missing key.
|
|
52
|
-
|
|
53
|
-
## Handle results correctly
|
|
54
|
-
|
|
55
|
-
- Local multi-item `.run()` returns a one-shot iterator of `['key', data]` items; wrap it in `list(...)` if you need reuse.
|
|
56
|
-
- Remote results are normalized into plain Python values.
|
|
57
|
-
- `first()` returns one item or `None`.
|
|
58
|
-
- `put_many()` returns `None`.
|
|
59
|
-
- In transactions, `tx.result` stores the latest result; for remote transactions, `tx.commit()` returns the last queued result or `None`.
|
|
60
|
-
|
|
61
|
-
## Respect batch and transaction behavior
|
|
62
|
-
|
|
63
|
-
- Pass iterables to `put_many()` and `keys_in()`, but assume the client materializes them before send.
|
|
64
|
-
- `keys_in()` keeps the requested key order and may repeat keys.
|
|
65
|
-
- Use `db.transaction()` when you need a consistent snapshot.
|
|
66
|
-
- Use `db.transaction(write=True)` when you need several local queries to commit together.
|
|
67
|
-
- Single embedded write queries are already atomic by default. Inside a local transaction, use `tx.shelf(...)`, not `db.shelf(...)`.
|
|
68
|
-
- Use `client.transaction(write=True)` for remote batches; queue queries with `.run()` and send them with `tx.commit()` or `await tx.commit()`.
|
|
69
|
-
- Local transaction blocks commit on success and roll back on error.
|
|
70
|
-
- Nested local transactions are not supported.
|
|
71
|
-
|
|
72
|
-
## Safety checks
|
|
73
|
-
|
|
74
|
-
- Keep callable `filter()` and `edit()` functions simple and trusted; the protocol uses `dill`.
|
|
75
|
-
- Configure debug logs with `shelfdb.log.configure_logging("debug")` when diagnosing client or server behavior.
|
|
76
|
-
- Do not expose the server to untrusted networks.
|
|
77
|
-
|
|
78
|
-
## Minimal patterns
|
|
79
|
-
|
|
80
|
-
```python
|
|
81
|
-
import shelfdb
|
|
82
|
-
|
|
83
|
-
db = shelfdb.open("db")
|
|
84
|
-
note = db.shelf("note").key("note-1").first().run()
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
```python
|
|
88
|
-
import shelfdb
|
|
89
|
-
|
|
90
|
-
client = shelfdb.connect("tcp://127.0.0.1:17000")
|
|
91
|
-
note = client.shelf("note").key("note-1").first().run()
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
```python
|
|
95
|
-
import asyncio
|
|
96
|
-
import shelfdb
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
async def main():
|
|
100
|
-
client = await shelfdb.connect_async("unix:///tmp/shelfdb.sock")
|
|
101
|
-
rows = await client.shelf("note").keys_in(["note-1", "note-2"]).run()
|
|
102
|
-
print(rows)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
asyncio.run(main())
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
```python
|
|
109
|
-
import shelfdb
|
|
110
|
-
|
|
111
|
-
client = shelfdb.connect("tcp://127.0.0.1:17000")
|
|
112
|
-
tx = client.transaction(write=True)
|
|
113
|
-
tx.shelf("note").put("note-1", {"title": "ShelfDB"}).run()
|
|
114
|
-
tx.commit()
|
|
115
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/index.md
RENAMED
|
File without changes
|
{shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/protocol.md
RENAMED
|
File without changes
|
|
File without changes
|
{shelfdb-2.0.0 → shelfdb-2.0.0.dev0}/src/shelfdb/ai_skill/shelfdb-usage/references/docs/security.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|