Skip to content

Commit 29bc7d6

Browse files
feat: add batch api
1 parent 54014d1 commit 29bc7d6

File tree

6 files changed

+1192
-7
lines changed

6 files changed

+1192
-7
lines changed

README.md

Lines changed: 170 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@ entity_key, receipt = client.arkiv.create_entity(
4848
entity = client.arkiv.get_entity(entity_key)
4949
print(f"Creation TX: {receipt.tx_hash}")
5050
print(f"Entity: {entity}")
51-
52-
# Clean up - delete entity
53-
client.arkiv.delete_entity(entity_key)
54-
print("Entity deleted")
5551
```
5652

5753
### Asynchronous API
@@ -76,9 +72,6 @@ async def main():
7672
entity = await client.arkiv.get_entity(entity_key)
7773
exists = await client.arkiv.entity_exists(entity_key)
7874

79-
# Clean up - delete entity
80-
await client.arkiv.delete_entity(entity_key)
81-
8275
asyncio.run(main())
8376
```
8477

@@ -93,6 +86,55 @@ balance = client.eth.get_balance(client.eth.default_account)
9386
tx = client.eth.get_transaction(tx_hash)
9487
```
9588

89+
### Entity Operations
90+
91+
Beyond creating and reading entities, Arkiv supports updating, extending, transferring ownership, and deleting entities.
92+
93+
#### Update Entity
94+
95+
Modify an entity's payload, attributes, or expiration:
96+
97+
```python
98+
# Update entity with new payload and attributes
99+
entity_key, receipt = client.arkiv.update_entity(
100+
entity_key,
101+
payload=b"Updated content",
102+
attributes={"type": "greeting", "version": 2},
103+
expires_in=client.arkiv.to_seconds(days=7)
104+
)
105+
```
106+
107+
#### Extend Entity Lifetime
108+
109+
Extend an entity's expiration without modifying its content:
110+
111+
```python
112+
# Extend entity lifetime by 30 days
113+
entity_key, receipt = client.arkiv.extend_entity(
114+
entity_key,
115+
extend_by=client.arkiv.to_seconds(days=30)
116+
)
117+
```
118+
119+
#### Change Entity Owner
120+
121+
Transfer ownership of an entity to another address:
122+
123+
```python
124+
# Transfer entity to a new owner
125+
new_owner = "0x1234567890abcdef1234567890abcdef12345678"
126+
entity_key, receipt = client.arkiv.change_owner(entity_key, new_owner)
127+
```
128+
129+
#### Delete Entity
130+
131+
Permanently remove an entity (only the owner can delete):
132+
133+
```python
134+
# Delete entity
135+
receipt = client.arkiv.delete_entity(entity_key)
136+
```
137+
96138
## Advanced Features
97139

98140
### Query Builder
@@ -237,6 +279,127 @@ results = client.arkiv.select() \
237279
.fetch()
238280
```
239281

282+
### Batch Operations
283+
284+
Batch operations allow you to group multiple entity operations (create, update, extend, delete, change_owner) into a single atomic transaction. This is more efficient and ensures all operations either succeed or fail together.
285+
286+
#### Basic Usage
287+
288+
```python
289+
from arkiv import Arkiv
290+
291+
client = Arkiv()
292+
293+
# Using context manager (recommended)
294+
with client.arkiv.batch() as batch:
295+
batch.create_entity(payload=b"item 1", expires_in=3600)
296+
batch.create_entity(payload=b"item 2", expires_in=3600)
297+
batch.create_entity(payload=b"item 3", expires_in=3600)
298+
299+
# Batch is automatically executed on exit
300+
print(f"Created {len(batch.receipt.creates)} entities")
301+
302+
# Access created entity keys
303+
for create_event in batch.receipt.creates:
304+
print(f"Created: {create_event.key}")
305+
```
306+
307+
#### Loop-Based Creation
308+
309+
Batch operations work naturally with loops:
310+
311+
```python
312+
items = [
313+
{"name": "alice", "role": "admin"},
314+
{"name": "bob", "role": "user"},
315+
{"name": "charlie", "role": "user"},
316+
]
317+
318+
with client.arkiv.batch() as batch:
319+
for item in items:
320+
batch.create_entity(
321+
payload=item["name"].encode(),
322+
attributes={"role": item["role"]},
323+
expires_in=3600,
324+
)
325+
326+
print(f"Created {len(batch.receipt.creates)} users")
327+
```
328+
329+
#### Mixed Operations
330+
331+
A single batch can contain different operation types:
332+
333+
```python
334+
with client.arkiv.batch() as batch:
335+
# Create new entities
336+
batch.create_entity(payload=b"new item", expires_in=3600)
337+
338+
# Update existing entities
339+
batch.update_entity(existing_key, payload=b"updated", expires_in=3600)
340+
341+
# Extend entity lifetime
342+
batch.extend_entity(another_key, extend_by=7200)
343+
344+
# Change ownership
345+
batch.change_owner(some_key, new_owner_address)
346+
347+
# Delete entities
348+
batch.delete_entity(old_key)
349+
350+
# Check results
351+
print(f"Creates: {len(batch.receipt.creates)}")
352+
print(f"Updates: {len(batch.receipt.updates)}")
353+
print(f"Extensions: {len(batch.receipt.extensions)}")
354+
print(f"Deletes: {len(batch.receipt.deletes)}")
355+
```
356+
357+
#### Manual Execution
358+
359+
For more control, you can execute batches manually:
360+
361+
```python
362+
batch = client.arkiv.batch()
363+
batch.create_entity(payload=b"data", expires_in=3600)
364+
batch.create_entity(payload=b"more data", expires_in=3600)
365+
366+
# Execute explicitly
367+
receipt = batch.execute()
368+
print(f"Transaction: {receipt.tx_hash}")
369+
```
370+
371+
#### Async Support
372+
373+
Batch operations work with `AsyncArkiv`:
374+
375+
```python
376+
async with AsyncArkiv() as client:
377+
async with client.arkiv.batch() as batch:
378+
batch.create_entity(payload=b"async item 1", expires_in=3600)
379+
batch.create_entity(payload=b"async item 2", expires_in=3600)
380+
381+
print(f"Created {len(batch.receipt.creates)} entities")
382+
```
383+
384+
#### Error Handling
385+
386+
- If an exception occurs inside the context manager, the batch is **not** executed
387+
- Empty batches are silently skipped (no-op)
388+
- All operations in a batch are atomic: if any operation fails, the entire batch is rolled back
389+
390+
```python
391+
try:
392+
with client.arkiv.batch() as batch:
393+
batch.create_entity(payload=b"item 1", expires_in=3600)
394+
raise ValueError("Something went wrong")
395+
batch.create_entity(payload=b"item 2", expires_in=3600)
396+
except ValueError:
397+
pass
398+
399+
# Batch was not executed - no entities created
400+
assert batch.receipt is None
401+
```
402+
240403
### Provider Builder
241404

242405
The `ProviderBuilder` provides a fluent API for creating providers to connect to various Arkiv networks:

src/arkiv/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from importlib.metadata import PackageNotFoundError, version
44

55
from .account import NamedAccount
6+
from .batch import AsyncBatchBuilder, BatchBuilder
67
from .client import Arkiv, AsyncArkiv
78
from .events import EventFilter
89
from .events_async import AsyncEventFilter
@@ -44,8 +45,10 @@
4445
"Arkiv",
4546
"ArkivNode",
4647
"AsyncArkiv",
48+
"AsyncBatchBuilder",
4749
"AsyncEventFilter",
4850
"AsyncQueryBuilder",
51+
"BatchBuilder",
4952
"CreateEvent",
5053
"DeleteEvent",
5154
"EventFilter",

0 commit comments

Comments
 (0)