Skip to content

Commit d723faf

Browse files
feat: add key, collection, and version fields to serialized documents (#204)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: William Easton <strawgate@users.noreply.github.com>
1 parent ae0c639 commit d723faf

File tree

45 files changed

+413
-77
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+413
-77
lines changed

key-value/key-value-aio/src/key_value/aio/stores/disk/multi_store.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,11 @@ async def _put_managed_entry(
132132
collection: str,
133133
managed_entry: ManagedEntry,
134134
) -> None:
135-
_ = self._cache[collection].set(key=key, value=self._serialization_adapter.dump_json(entry=managed_entry), expire=managed_entry.ttl)
135+
_ = self._cache[collection].set(
136+
key=key,
137+
value=self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection),
138+
expire=managed_entry.ttl,
139+
)
136140

137141
@override
138142
async def _delete_managed_entry(self, *, key: str, collection: str) -> bool:

key-value/key-value-aio/src/key_value/aio/stores/disk/store.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ async def _put_managed_entry(
107107
) -> None:
108108
combo_key: str = compound_key(collection=collection, key=key)
109109

110-
_ = self._cache.set(key=combo_key, value=self._serialization_adapter.dump_json(entry=managed_entry), expire=managed_entry.ttl)
110+
_ = self._cache.set(
111+
key=combo_key,
112+
value=self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection),
113+
expire=managed_entry.ttl,
114+
)
111115

112116
@override
113117
async def _delete_managed_entry(self, *, key: str, collection: str) -> bool:

key-value/key-value-aio/src/key_value/aio/stores/dynamodb/store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ async def _put_managed_entry(
219219
managed_entry: ManagedEntry,
220220
) -> None:
221221
"""Store a managed entry in DynamoDB."""
222-
json_value = self._serialization_adapter.dump_json(entry=managed_entry)
222+
json_value = self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection)
223223

224224
item: dict[str, Any] = {
225225
"collection": {"S": collection},

key-value/key-value-aio/src/key_value/aio/stores/elasticsearch/store.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@
6767
"key": {
6868
"type": "keyword",
6969
},
70+
"version": {
71+
"type": "integer",
72+
},
7073
"value": {
7174
"properties": {
7275
"flattened": {
@@ -357,7 +360,7 @@ async def _put_managed_entry(
357360
index_name: str = self._get_index_name(collection=collection)
358361
document_id: str = self._get_document_id(key=key)
359362

360-
document: dict[str, Any] = self._serializer.dump_dict(entry=managed_entry)
363+
document: dict[str, Any] = self._serializer.dump_dict(entry=managed_entry, key=key, collection=collection)
361364

362365
try:
363366
_ = await self._client.index(
@@ -395,7 +398,7 @@ async def _put_managed_entries(
395398

396399
index_action: dict[str, Any] = new_bulk_action(action="index", index=index_name, document_id=document_id)
397400

398-
document: dict[str, Any] = self._serializer.dump_dict(entry=managed_entry)
401+
document: dict[str, Any] = self._serializer.dump_dict(entry=managed_entry, key=key, collection=collection)
399402

400403
operations.extend([index_action, document])
401404

key-value/key-value-aio/src/key_value/aio/stores/keyring/store.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""Python keyring-based key-value store."""
22

3+
import os
4+
5+
from key_value.shared.errors.key_value import ValueTooLargeError
36
from key_value.shared.utils.compound import compound_key
47
from key_value.shared.utils.managed_entry import ManagedEntry
58
from key_value.shared.utils.sanitization import HybridSanitizationStrategy, SanitizationStrategy
@@ -17,6 +20,16 @@
1720

1821
DEFAULT_KEYCHAIN_SERVICE = "py-key-value"
1922

23+
24+
def is_value_too_large(value: bytes) -> bool:
25+
value_length = len(value)
26+
if os.name == "nt":
27+
return value_length > WINDOWS_MAX_VALUE_LENGTH
28+
return False
29+
30+
31+
WINDOWS_MAX_VALUE_LENGTH = 2560 # bytes
32+
2033
MAX_KEY_COLLECTION_LENGTH = 256
2134
ALLOWED_KEY_COLLECTION_CHARACTERS: str = ALPHANUMERIC_CHARACTERS
2235

@@ -105,7 +118,11 @@ async def _put_managed_entry(self, *, key: str, collection: str, managed_entry:
105118

106119
combo_key: str = compound_key(collection=sanitized_collection, key=sanitized_key)
107120

108-
json_str: str = self._serialization_adapter.dump_json(entry=managed_entry)
121+
json_str: str = self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection)
122+
encoded_json_bytes: bytes = json_str.encode(encoding="utf-8")
123+
124+
if is_value_too_large(value=encoded_json_bytes):
125+
raise ValueTooLargeError(size=len(encoded_json_bytes), max_size=2560, collection=sanitized_collection, key=sanitized_key)
109126

110127
keyring.set_password(service_name=self._service_name, username=combo_key, password=json_str)
111128

key-value/key-value-aio/src/key_value/aio/stores/memcached/store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ async def _put_managed_entry(
125125
else:
126126
exptime = max(int(managed_entry.ttl), 1)
127127

128-
json_value: str = self._serialization_adapter.dump_json(entry=managed_entry)
128+
json_value: str = self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection)
129129

130130
_ = await self._client.set(
131131
key=combo_key.encode(encoding="utf-8"),

key-value/key-value-aio/src/key_value/aio/stores/mongodb/store.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ async def _setup_collection(self, *, collection: str) -> None:
219219
# Ensure index on the unique combo key and supporting queries
220220
sanitized_collection = self._sanitize_collection(collection=collection)
221221

222-
collection_filter: dict[str, str] = {"name": collection}
222+
collection_filter: dict[str, str] = {"name": sanitized_collection}
223223
matching_collections: list[str] = await self._db.list_collection_names(filter=collection_filter)
224224

225225
if matching_collections:
@@ -273,7 +273,7 @@ async def _put_managed_entry(
273273
collection: str,
274274
managed_entry: ManagedEntry,
275275
) -> None:
276-
mongo_doc = self._adapter.dump_dict(entry=managed_entry)
276+
mongo_doc = self._adapter.dump_dict(entry=managed_entry, key=key, collection=collection)
277277

278278
try:
279279
# Ensure that the value is serializable to JSON
@@ -308,7 +308,7 @@ async def _put_managed_entries(
308308

309309
operations: list[UpdateOne] = []
310310
for key, managed_entry in zip(keys, managed_entries, strict=True):
311-
mongo_doc = self._adapter.dump_dict(entry=managed_entry)
311+
mongo_doc = self._adapter.dump_dict(entry=managed_entry, key=key, collection=collection)
312312

313313
operations.append(
314314
UpdateOne(
@@ -346,8 +346,7 @@ async def _delete_collection(self, *, collection: str) -> bool:
346346

347347
_ = await self._db.drop_collection(name_or_collection=collection_name)
348348

349-
if collection_name in self._collections_by_name:
350-
del self._collections_by_name[collection]
349+
self._collections_by_name.pop(collection, None)
351350

352351
return True
353352

key-value/key-value-aio/src/key_value/aio/stores/redis/store.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ async def _put_managed_entry(
132132
) -> None:
133133
combo_key: str = compound_key(collection=collection, key=key)
134134

135-
json_value: str = self._adapter.dump_json(entry=managed_entry)
135+
json_value: str = self._adapter.dump_json(entry=managed_entry, key=key, collection=collection)
136136

137137
if managed_entry.ttl is not None:
138138
# Redis does not support <= 0 TTLs
@@ -160,7 +160,7 @@ async def _put_managed_entries(
160160
# If there is no TTL, we can just do a simple mset
161161
mapping: dict[str, str] = {}
162162
for key, managed_entry in zip(keys, managed_entries, strict=True):
163-
json_value = self._adapter.dump_json(entry=managed_entry)
163+
json_value = self._adapter.dump_json(entry=managed_entry, key=key, collection=collection)
164164
mapping[compound_key(collection=collection, key=key)] = json_value
165165

166166
await self._client.mset(mapping=mapping)
@@ -175,7 +175,7 @@ async def _put_managed_entries(
175175

176176
for key, managed_entry in zip(keys, managed_entries, strict=True):
177177
combo_key: str = compound_key(collection=collection, key=key)
178-
json_value = self._adapter.dump_json(entry=managed_entry)
178+
json_value = self._adapter.dump_json(entry=managed_entry, key=key, collection=collection)
179179

180180
pipeline.setex(name=combo_key, time=ttl_seconds, value=json_value)
181181

key-value/key-value-aio/src/key_value/aio/stores/rocksdb/store.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ async def _put_managed_entry(
124124
self._fail_on_closed_store()
125125

126126
combo_key: str = compound_key(collection=collection, key=key)
127-
json_value: str = self._serialization_adapter.dump_json(entry=managed_entry)
127+
json_value: str = self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection)
128128

129129
self._db[combo_key] = json_value.encode("utf-8")
130130

@@ -147,7 +147,7 @@ async def _put_managed_entries(
147147
batch = WriteBatch()
148148
for key, managed_entry in zip(keys, managed_entries, strict=True):
149149
combo_key: str = compound_key(collection=collection, key=key)
150-
json_value: str = self._serialization_adapter.dump_json(entry=managed_entry)
150+
json_value: str = self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection)
151151
batch.put(combo_key, json_value.encode("utf-8"))
152152

153153
self._db.write(batch)

key-value/key-value-aio/src/key_value/aio/stores/simple/store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ async def _put_managed_entry(self, *, key: str, collection: str, managed_entry:
6969
_ = self._data.pop(next(iter(self._data)))
7070

7171
self._data[combo_key] = SimpleStoreEntry(
72-
json_str=self._serialization_adapter.dump_json(entry=managed_entry),
72+
json_str=self._serialization_adapter.dump_json(entry=managed_entry, key=key, collection=collection),
7373
expires_at=managed_entry.expires_at,
7474
created_at=managed_entry.created_at,
7575
)

0 commit comments

Comments
 (0)