statikk 0.1.4__tar.gz → 0.1.6__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.
- {statikk-0.1.4 → statikk-0.1.6}/PKG-INFO +1 -1
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/engine.py +3 -1
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/models.py +19 -3
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk.egg-info/PKG-INFO +1 -1
- {statikk-0.1.4 → statikk-0.1.6}/tests/test_engine.py +3 -2
- {statikk-0.1.4 → statikk-0.1.6}/tests/test_models.py +49 -0
- {statikk-0.1.4 → statikk-0.1.6}/.coveragerc +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/.gitignore +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/.readthedocs.yml +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/AUTHORS.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/CHANGELOG.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/CONTRIBUTING.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/LICENSE.txt +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/README.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/assets/favicon.png +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/assets/logo.png +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/Makefile +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/_static/.gitignore +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/authors.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/changelog.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/conf.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/contributing.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/index.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/license.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/readme.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/requirements.txt +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/docs/usage.rst +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/pyproject.toml +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/setup.cfg +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/setup.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/__init__.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/conditions.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/expressions.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/fields.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk/typing.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk.egg-info/SOURCES.txt +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk.egg-info/dependency_links.txt +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk.egg-info/not-zip-safe +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk.egg-info/requires.txt +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/src/statikk.egg-info/top_level.txt +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/tests/conftest.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/tests/test_expressions.py +0 -0
- {statikk-0.1.4 → statikk-0.1.6}/tox.ini +0 -0
@@ -313,7 +313,9 @@ class Table:
|
|
313
313
|
raise InvalidIndexNameError(f"The provided index name '{index_name}' is not configured on the table.")
|
314
314
|
index = index_filter[0]
|
315
315
|
key_condition = hash_key.evaluate(index.hash_key.name)
|
316
|
-
if
|
316
|
+
if (
|
317
|
+
not range_key or (range_key and range_key.value != model_class.type())
|
318
|
+
) and FIELD_STATIKK_TYPE not in model_class.index_definitions()[index_name].pk_fields:
|
317
319
|
range_key = BeginsWith(model_class.type())
|
318
320
|
if range_key:
|
319
321
|
if not model_class.is_nested():
|
@@ -67,16 +67,18 @@ class TrackingMixin:
|
|
67
67
|
|
68
68
|
def _recursive_hash(self) -> int:
|
69
69
|
"""
|
70
|
-
Compute a hash value for the model, ignoring nested DatabaseModel instances.
|
70
|
+
Compute a hash value for the model, ignoring specified fields and nested DatabaseModel instances.
|
71
71
|
|
72
|
-
This ensures that changes to child models don't affect the parent's hash.
|
72
|
+
This ensures that changes to ignored fields or child models don't affect the parent's hash.
|
73
73
|
|
74
74
|
Returns:
|
75
|
-
A hash value representing the model's non-
|
75
|
+
A hash value representing the model's non-ignored fields.
|
76
76
|
"""
|
77
77
|
if not self.should_track:
|
78
78
|
return 0
|
79
79
|
|
80
|
+
ignored_fields = self.ignore_tracking_fields()
|
81
|
+
|
80
82
|
values = []
|
81
83
|
for field_name in self.model_fields:
|
82
84
|
if not hasattr(self, field_name):
|
@@ -85,6 +87,9 @@ class TrackingMixin:
|
|
85
87
|
if field_name.startswith("_"):
|
86
88
|
continue
|
87
89
|
|
90
|
+
if field_name in ignored_fields:
|
91
|
+
continue
|
92
|
+
|
88
93
|
value = getattr(self, field_name)
|
89
94
|
|
90
95
|
if hasattr(value, "__class__") and issubclass(value.__class__, DatabaseModel):
|
@@ -141,6 +146,17 @@ class TrackingMixin:
|
|
141
146
|
|
142
147
|
return True
|
143
148
|
|
149
|
+
def ignore_tracking_fields(self) -> set:
|
150
|
+
"""
|
151
|
+
Override this method to specify fields to ignore when tracking changes.
|
152
|
+
|
153
|
+
Returns:
|
154
|
+
A set specifying fields to ignore.
|
155
|
+
Example:
|
156
|
+
{"field1", "field2"}
|
157
|
+
"""
|
158
|
+
return {}
|
159
|
+
|
144
160
|
|
145
161
|
class DatabaseModel(BaseModel, TrackingMixin, extra=Extra.allow):
|
146
162
|
id: str = Field(default_factory=lambda: str(uuid4()))
|
@@ -13,6 +13,7 @@ from statikk.engine import (
|
|
13
13
|
InvalidIndexNameError,
|
14
14
|
ItemNotFoundError,
|
15
15
|
)
|
16
|
+
from statikk.fields import FIELD_STATIKK_TYPE
|
16
17
|
from statikk.models import (
|
17
18
|
DatabaseModel,
|
18
19
|
KeySchema,
|
@@ -670,13 +671,13 @@ def test_query_no_range_key_provided():
|
|
670
671
|
mock_dynamodb().stop()
|
671
672
|
|
672
673
|
|
673
|
-
def
|
674
|
+
def test_query_hash_key_is_type():
|
674
675
|
class Model(DatabaseModel):
|
675
676
|
tier: str
|
676
677
|
|
677
678
|
@classmethod
|
678
679
|
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
679
|
-
return {"main-index": IndexFieldConfig(pk_fields=[
|
680
|
+
return {"main-index": IndexFieldConfig(pk_fields=[FIELD_STATIKK_TYPE], sk_fields=["tier"])}
|
680
681
|
|
681
682
|
mock_dynamodb().start()
|
682
683
|
table = Table(
|
@@ -106,3 +106,52 @@ def test_tracking_disabled():
|
|
106
106
|
assert my_database_model.was_modified is True # untracked models should always be marked as modified
|
107
107
|
my_database_model.foo = "bar"
|
108
108
|
assert my_database_model.was_modified is True
|
109
|
+
|
110
|
+
|
111
|
+
def test_testing_configuration():
|
112
|
+
class MyOtherNestedDatabaseModel(DatabaseModel):
|
113
|
+
baz: str = "baz"
|
114
|
+
qux: str = "qux"
|
115
|
+
xax: str = "xax"
|
116
|
+
|
117
|
+
@classmethod
|
118
|
+
def is_nested(cls) -> bool:
|
119
|
+
return True
|
120
|
+
|
121
|
+
def ignore_tracking_fields(self) -> set:
|
122
|
+
return {"baz", "qux"}
|
123
|
+
|
124
|
+
class MyNestedDatabaseModel(DatabaseModel):
|
125
|
+
bar: str = "bar"
|
126
|
+
other_nested: MyOtherNestedDatabaseModel
|
127
|
+
|
128
|
+
@classmethod
|
129
|
+
def is_nested(cls) -> bool:
|
130
|
+
return True
|
131
|
+
|
132
|
+
class MyDatabaseModel(DatabaseModel):
|
133
|
+
foo: str = "foo"
|
134
|
+
nested: MyNestedDatabaseModel
|
135
|
+
|
136
|
+
@property
|
137
|
+
def should_track(self) -> bool:
|
138
|
+
return True
|
139
|
+
|
140
|
+
def ignore_tracking_fields(self) -> set:
|
141
|
+
return {"foo"}
|
142
|
+
|
143
|
+
my_database_model = MyDatabaseModel(
|
144
|
+
foo="foo",
|
145
|
+
nested=MyNestedDatabaseModel(
|
146
|
+
bar="bar", other_nested=MyOtherNestedDatabaseModel(baz="baz", qux="qux", xax="xax")
|
147
|
+
),
|
148
|
+
)
|
149
|
+
assert my_database_model.was_modified is False
|
150
|
+
my_database_model.foo = "bar"
|
151
|
+
assert my_database_model.was_modified is False
|
152
|
+
my_database_model.nested.other_nested.baz = "qux"
|
153
|
+
assert my_database_model.nested.other_nested.was_modified is False
|
154
|
+
my_database_model.nested.other_nested.qux = "xax"
|
155
|
+
assert my_database_model.nested.other_nested.was_modified is False
|
156
|
+
my_database_model.nested.bar = "baz"
|
157
|
+
assert my_database_model.nested.was_modified is True
|
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
|
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
|