Skip to content

Commit f963517

Browse files
author
Danil Tolmachev
committed
add partial write
1 parent 8940e49 commit f963517

File tree

3 files changed

+82
-46
lines changed

3 files changed

+82
-46
lines changed

dictdatabase/io_unsafe.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from . import config
1212
from . import indexing
1313
from . import io_bytes
14+
from . import searching
1415
from . import utils
1516
from .index_manager import IndexManager
16-
from .searching import KeySearcher
1717

1818

1919
@dataclass(frozen=True) # slots=True not supported by python 3.8 and 3.9
@@ -88,7 +88,7 @@ def partial_read_only(db_name: str, key: str) -> dict | None:
8888

8989
# Not found in index file, search for key in the entire file
9090
all_file_bytes = io_bytes.read(db_name)
91-
start, end, found = KeySearcher().search(all_file_bytes, key)
91+
start, end, found = searching.search_value_by_key(all_file_bytes, key)
9292
if not found:
9393
return None
9494
value_bytes = all_file_bytes[start:end]
@@ -185,9 +185,9 @@ def get_partial_file_handle(db_name: str, key: str) -> PartialFileHandle:
185185
return partial_handle
186186

187187
# Not found in index file, search for key in the entire file
188-
key_start, key_end = utils.find_outermost_key_in_json_bytes(all_file_bytes, key)
188+
key_start, key_end, found = searching.search_key(all_file_bytes, key)
189189

190-
if key_end == -1:
190+
if not found:
191191
raise KeyError(f"Key \"{key}\" not found in db \"{db_name}\"")
192192

193193
# Key found, now determine the bounding byte indices of the value

dictdatabase/searching.py

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,71 @@
11
from typing import Tuple
22

3+
import orjson
4+
35
from dictdatabase import byte_codes
46
from dictdatabase import utils
57

68

7-
class KeySearcher:
8-
@staticmethod
9-
def find_start_end_in_bytes(file: bytes, key: str) -> Tuple[int, int, bool]:
10-
"""
11-
It finds the start and end indices of the value of a key in a JSON file
9+
def find_start_end_in_bytes(file: bytes, key: str) -> Tuple[int, int, bool]:
10+
"""
11+
It finds the start and end indices of the value of a key in a JSON file
12+
13+
Args:
14+
file (bytes): bytes
15+
key (str): The key to find in the JSON file.
1216
13-
Args:
14-
file (bytes): bytes
15-
key (str): The key to find in the JSON file.
17+
Returns:
18+
A tuple of the start and end index of the key, and a boolean value indicating whether the key was found.
19+
"""
20+
key_start, key_end = utils.find_outermost_key_in_json_bytes(file, key)
21+
if key_end == -1:
22+
return -1, -1, False
23+
start = key_end + (1 if file[key_end] == byte_codes.SPACE else 0)
24+
end = utils.seek_index_through_value_bytes(file, start)
25+
return start, end, True
1626

17-
Returns:
18-
A tuple of the start and end index of the key, and a boolean value indicating whether the key was found.
19-
"""
20-
key_start, key_end = utils.find_outermost_key_in_json_bytes(file, key)
27+
28+
def search_key(file: bytes, key: str, glom_searching=True) -> Tuple[int, int, bool]:
29+
original_value_start = 0
30+
original_value_end = len(file)
31+
original_key_start = 0
32+
original_key_end = len(file)
33+
for k in key.split(".") if glom_searching else [key]:
34+
key_start, key_end = utils.find_outermost_key_in_json_bytes(file, k)
2135
if key_end == -1:
2236
return -1, -1, False
23-
start = key_end + (1 if file[key_end] == byte_codes.SPACE else 0)
24-
end = utils.seek_index_through_value_bytes(file, start)
25-
return start, end, True
26-
27-
def search(
28-
self, all_file_bytes: bytes, key: str, glom_searching=True
29-
) -> Tuple[int, int, bool]:
30-
"""
31-
It takes a byte string, a key, and a boolean, and returns a tuple of three integers
32-
33-
Args:
34-
all_file_bytes (bytes): The bytes of the file you're searching in.
35-
key (str): The key to search for.
36-
glom_searching: If True, then the key is a glom path, and we need to search for each part of the path. Defaults to
37-
True
38-
39-
Returns:
40-
The start and end of the key in the file.
41-
"""
42-
original_start = 0
43-
original_end = len(all_file_bytes)
44-
for k in key.split(".") if glom_searching else [key]:
45-
start, end, found = self.find_start_end_in_bytes(
46-
all_file_bytes[original_start:original_end], k
47-
)
48-
if not found:
49-
return -1, -1, False
50-
original_end = original_start + end
51-
original_start += start
52-
return original_start, original_end, True
37+
original_key_end = original_value_start + key_end
38+
original_key_start = original_value_start + key_start
39+
value_start, value_end, found = find_start_end_in_bytes(file, k)
40+
original_value_end = original_value_start + original_value_end
41+
original_value_start += value_start
42+
file = file[original_value_start:original_value_end]
43+
return original_key_start, original_key_end, True
44+
45+
46+
def search_value_by_key(
47+
all_file_bytes: bytes, key: str, glom_searching=True
48+
) -> Tuple[int, int, bool]:
49+
"""
50+
It takes a byte string, a key, and a boolean, and returns a tuple of three integers
51+
52+
Args:
53+
all_file_bytes (bytes): The bytes of the file you're searching in.
54+
key (str): The key to search for.
55+
glom_searching: If True, then the key is a glom path, and we need to search for each part of the path. Defaults to
56+
True
57+
58+
Returns:
59+
The start and end of the key in the file.
60+
"""
61+
original_start = 0
62+
original_end = len(all_file_bytes)
63+
for k in key.split(".") if glom_searching else [key]:
64+
start, end, found = find_start_end_in_bytes(
65+
all_file_bytes[original_start:original_end], k
66+
)
67+
if not found:
68+
return -1, -1, False
69+
original_end = original_start + end
70+
original_start += start
71+
return original_start, original_end, True

tests/test_glom_writing.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import dictdatabase as DDB
2+
3+
data = {
4+
"users": {
5+
"Ben": {"age": 30, "job": "Software Engineer"},
6+
"Bob": {"age": 30, "job": "Plumbers"},
7+
},
8+
"Ben": {"job": {"age": 30, "job": "Software Engineer"}},
9+
}
10+
11+
12+
def test_glom_writing():
13+
DDB.at("users").create(data, force_overwrite=True)
14+
with DDB.at("users", key="users.Ben").session() as (session, purchase):
15+
purchase["status"] = "cancelled"
16+
session.write()
17+
assert DDB.at("users", key="users.Ben.status").read() == "cancelled"

0 commit comments

Comments
 (0)