Skip to content

Commit 1e222fd

Browse files
author
Matthias Zimmermann
committed
add entity_exists
1 parent 6b723c6 commit 1e222fd

File tree

5 files changed

+165
-1
lines changed

5 files changed

+165
-1
lines changed

src/arkiv/module.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,23 @@ def create_entities(
157157
entity_keys = [create.entity_key for create in receipt.creates]
158158
return entity_keys, receipt.tx_hash
159159

160+
def entity_exists(self, entity_key: EntityKey) -> bool:
161+
"""
162+
Check if an entity exists storage.
163+
164+
Args:
165+
entity_key: The entity key to check
166+
167+
Returns:
168+
True if the entity exists, False otherwise
169+
"""
170+
try:
171+
self.client.eth.get_entity_metadata(entity_key) # type: ignore[attr-defined]
172+
return True
173+
174+
except Exception:
175+
return False
176+
160177
def get_entity(self, entity_key: EntityKey, fields: int = ALL) -> Entity:
161178
"""
162179
Get an entity by its entity key.

src/arkiv/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
PAYLOAD = 1
1212
ANNOTATIONS = 2
1313
METADATA = 4
14+
NONE = 0
1415
ALL = PAYLOAD | ANNOTATIONS | METADATA
1516

1617
# Transaction hash type

src/arkiv/utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ def check_entity_key(entity_key: Any | None, label: str | None = None) -> None:
6767
raise EntityKeyException("Entity key should be a valid hex string")
6868

6969

70+
def is_entity_key(entity_key: Any | None) -> bool:
71+
"""Check if the provided value is a valid EntityKey."""
72+
try:
73+
check_entity_key(entity_key)
74+
return True
75+
except EntityKeyException:
76+
return False
77+
78+
7079
def is_hex_str(value: str) -> bool:
7180
if not isinstance(value, str):
7281
return False

tests/test_entity_create_parallel.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,11 @@ def get_parallel_entity_creation_parameters(
445445
if verify_sample_size_env:
446446
verify_sample_size = int(verify_sample_size_env)
447447

448-
return (clients, txs, batch_size, verify_sample_size)
448+
parameters = (clients, txs, batch_size, verify_sample_size)
449+
logger.info(
450+
f"Using parallel entity creation parameters (clients, txs, batch_size, verify_sample_size): {parameters}"
451+
)
452+
return parameters
449453

450454

451455
@pytest.mark.parametrize(

tests/test_entity_exists.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""Tests for entity_exists functionality."""
2+
3+
import logging
4+
5+
from arkiv import Arkiv
6+
from arkiv.types import Annotations, EntityKey
7+
from arkiv.utils import is_entity_key
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
class TestEntityExists:
13+
"""Test entity existence checking."""
14+
15+
def test_entity_exists_for_non_existent_entity(
16+
self, arkiv_client_http: Arkiv
17+
) -> None:
18+
"""Test entity_exists with malformed entity key."""
19+
fake_key = EntityKey(
20+
"0x0000000000000000000000000000000000000000000000000000000000000999"
21+
)
22+
assert is_entity_key(fake_key) is True
23+
assert arkiv_client_http.arkiv.entity_exists(fake_key) is False
24+
25+
def test_entity_exists_with_invalid_entity_key_format(
26+
self, arkiv_client_http: Arkiv
27+
) -> None:
28+
"""Test entity_exists with malformed entity key."""
29+
invalid_key = EntityKey("0xinvalid")
30+
assert is_entity_key(invalid_key) is False
31+
assert not arkiv_client_http.arkiv.entity_exists(invalid_key)
32+
33+
def test_entity_exists_returns_true_for_created_entity(
34+
self, arkiv_client_http: Arkiv
35+
) -> None:
36+
"""Test that entity_exists returns True for a created entity."""
37+
# Create an entity
38+
entity_key, _ = arkiv_client_http.arkiv.create_entity(
39+
payload=b"test data", btl=1000
40+
)
41+
42+
# Check it exists
43+
assert arkiv_client_http.arkiv.entity_exists(entity_key) is True
44+
45+
def test_entity_exists_multiple_entities(self, arkiv_client_http: Arkiv) -> None:
46+
"""Test entity_exists works correctly with multiple entities."""
47+
# Create multiple entities
48+
entity_keys = []
49+
for i in range(5):
50+
payload = f"entity {i}".encode()
51+
entity_key, _ = arkiv_client_http.arkiv.create_entity(
52+
payload=payload, btl=1000
53+
)
54+
entity_keys.append(entity_key)
55+
56+
# Verify all exist
57+
for entity_key in entity_keys:
58+
assert arkiv_client_http.arkiv.entity_exists(entity_key) is True
59+
60+
# Verify a non-existent one doesn't exist
61+
62+
def test_entity_exists_is_idempotent(self, arkiv_client_http: Arkiv) -> None:
63+
"""Test that calling entity_exists multiple times gives same result."""
64+
payload = b"test idempotency"
65+
entity_key, _ = arkiv_client_http.arkiv.create_entity(payload=payload, btl=1000)
66+
67+
# Call multiple times
68+
result1 = arkiv_client_http.arkiv.entity_exists(entity_key)
69+
result2 = arkiv_client_http.arkiv.entity_exists(entity_key)
70+
result3 = arkiv_client_http.arkiv.entity_exists(entity_key)
71+
72+
assert result1 is True
73+
assert result2 is True
74+
assert result3 is True
75+
76+
def test_entity_exists_after_creation_of_next_entity(
77+
self, arkiv_client_http: Arkiv
78+
) -> None:
79+
"""Test entity_exists transitions from False to True on creation."""
80+
# Generate a unique entity key by creating and noting it
81+
payload = b"transition test"
82+
entity_key, _ = arkiv_client_http.arkiv.create_entity(payload=payload, btl=1000)
83+
84+
# Now it should exist
85+
assert arkiv_client_http.arkiv.entity_exists(entity_key) is True
86+
87+
# Create a different one to verify the first is still there
88+
entity_key2, _ = arkiv_client_http.arkiv.create_entity(
89+
payload=b"second entity", btl=1000
90+
)
91+
assert arkiv_client_http.arkiv.entity_exists(entity_key) is True
92+
assert arkiv_client_http.arkiv.entity_exists(entity_key2) is True
93+
94+
def test_entity_exists_consistency_with_get_entity(
95+
self, arkiv_client_http: Arkiv
96+
) -> None:
97+
"""Test that entity_exists and get_entity are consistent."""
98+
# Create entity
99+
payload = b"consistency test"
100+
annotations = Annotations({"test": "consistency"})
101+
entity_key, _ = arkiv_client_http.arkiv.create_entity(
102+
payload=payload, annotations=annotations, btl=1000
103+
)
104+
105+
# Both methods should agree it exists
106+
exists = arkiv_client_http.arkiv.entity_exists(entity_key)
107+
entity = arkiv_client_http.arkiv.get_entity(entity_key)
108+
109+
assert exists is True
110+
assert entity.entity_key == entity_key
111+
assert entity.payload == payload
112+
assert entity.annotations == annotations
113+
114+
def test_entity_exists_with_bulk_created_entities(
115+
self, arkiv_client_http: Arkiv
116+
) -> None:
117+
"""Test entity_exists works with entities created via create_entities."""
118+
from arkiv.types import CreateOp
119+
120+
# Create multiple entities in one transaction
121+
create_ops = [
122+
CreateOp(
123+
payload=f"bulk entity {i}".encode(),
124+
annotations=Annotations({}),
125+
btl=1000,
126+
)
127+
for i in range(5)
128+
]
129+
entity_keys, _ = arkiv_client_http.arkiv.create_entities(create_ops)
130+
131+
# Verify all exist
132+
for entity_key in entity_keys:
133+
assert arkiv_client_http.arkiv.entity_exists(entity_key) is True

0 commit comments

Comments
 (0)