statikk 0.1.8__tar.gz → 0.1.9__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.
Files changed (43) hide show
  1. {statikk-0.1.8 → statikk-0.1.9}/PKG-INFO +1 -1
  2. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/engine.py +24 -2
  3. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/models.py +11 -0
  4. {statikk-0.1.8 → statikk-0.1.9}/src/statikk.egg-info/PKG-INFO +1 -1
  5. {statikk-0.1.8 → statikk-0.1.9}/tests/test_engine.py +23 -2
  6. {statikk-0.1.8 → statikk-0.1.9}/.coveragerc +0 -0
  7. {statikk-0.1.8 → statikk-0.1.9}/.gitignore +0 -0
  8. {statikk-0.1.8 → statikk-0.1.9}/.readthedocs.yml +0 -0
  9. {statikk-0.1.8 → statikk-0.1.9}/AUTHORS.rst +0 -0
  10. {statikk-0.1.8 → statikk-0.1.9}/CHANGELOG.rst +0 -0
  11. {statikk-0.1.8 → statikk-0.1.9}/CONTRIBUTING.rst +0 -0
  12. {statikk-0.1.8 → statikk-0.1.9}/LICENSE.txt +0 -0
  13. {statikk-0.1.8 → statikk-0.1.9}/README.rst +0 -0
  14. {statikk-0.1.8 → statikk-0.1.9}/assets/favicon.png +0 -0
  15. {statikk-0.1.8 → statikk-0.1.9}/assets/logo.png +0 -0
  16. {statikk-0.1.8 → statikk-0.1.9}/docs/Makefile +0 -0
  17. {statikk-0.1.8 → statikk-0.1.9}/docs/_static/.gitignore +0 -0
  18. {statikk-0.1.8 → statikk-0.1.9}/docs/authors.rst +0 -0
  19. {statikk-0.1.8 → statikk-0.1.9}/docs/changelog.rst +0 -0
  20. {statikk-0.1.8 → statikk-0.1.9}/docs/conf.py +0 -0
  21. {statikk-0.1.8 → statikk-0.1.9}/docs/contributing.rst +0 -0
  22. {statikk-0.1.8 → statikk-0.1.9}/docs/index.rst +0 -0
  23. {statikk-0.1.8 → statikk-0.1.9}/docs/license.rst +0 -0
  24. {statikk-0.1.8 → statikk-0.1.9}/docs/readme.rst +0 -0
  25. {statikk-0.1.8 → statikk-0.1.9}/docs/requirements.txt +0 -0
  26. {statikk-0.1.8 → statikk-0.1.9}/docs/usage.rst +0 -0
  27. {statikk-0.1.8 → statikk-0.1.9}/pyproject.toml +0 -0
  28. {statikk-0.1.8 → statikk-0.1.9}/setup.cfg +0 -0
  29. {statikk-0.1.8 → statikk-0.1.9}/setup.py +0 -0
  30. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/__init__.py +0 -0
  31. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/conditions.py +0 -0
  32. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/expressions.py +0 -0
  33. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/fields.py +0 -0
  34. {statikk-0.1.8 → statikk-0.1.9}/src/statikk/typing.py +0 -0
  35. {statikk-0.1.8 → statikk-0.1.9}/src/statikk.egg-info/SOURCES.txt +0 -0
  36. {statikk-0.1.8 → statikk-0.1.9}/src/statikk.egg-info/dependency_links.txt +0 -0
  37. {statikk-0.1.8 → statikk-0.1.9}/src/statikk.egg-info/not-zip-safe +0 -0
  38. {statikk-0.1.8 → statikk-0.1.9}/src/statikk.egg-info/requires.txt +0 -0
  39. {statikk-0.1.8 → statikk-0.1.9}/src/statikk.egg-info/top_level.txt +0 -0
  40. {statikk-0.1.8 → statikk-0.1.9}/tests/conftest.py +0 -0
  41. {statikk-0.1.8 → statikk-0.1.9}/tests/test_expressions.py +0 -0
  42. {statikk-0.1.8 → statikk-0.1.9}/tests/test_models.py +0 -0
  43. {statikk-0.1.8 → statikk-0.1.9}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: statikk
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: statikk is a single table application (STA) library for DynamoDb.
5
5
  Home-page: https://github.com/terinia/statikk
6
6
  Author: Balint Biro
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from datetime import datetime
3
- from typing import Any, Dict, Type, Optional, List, Union
3
+ from typing import Any, Dict, Type, Optional, List, Union, get_type_hints, get_origin, get_args
4
4
 
5
5
  import boto3
6
6
  from botocore.config import Config
@@ -623,6 +623,26 @@ class Table:
623
623
  data = self._serialize_item(enriched_item)
624
624
  batch.delete_item(Key=data)
625
625
 
626
+ def inspect_optional_field(self, model_class, field_name):
627
+ field_type = model_class.model_fields[field_name].annotation
628
+
629
+ is_optional = False
630
+ inner_type = field_type
631
+
632
+ if get_origin(field_type) is Union:
633
+ args = get_args(field_type)
634
+ if len(args) == 2 and args[1] is type(None):
635
+ is_optional = True
636
+ inner_type = args[0]
637
+
638
+ elif hasattr(field_type, "__origin__") and field_type.__origin__ is Union:
639
+ args = getattr(field_type, "__args__", [])
640
+ if len(args) == 2 and args[1] is type(None):
641
+ is_optional = True
642
+ inner_type = args[0]
643
+
644
+ return (is_optional, inner_type)
645
+
626
646
  def reconstruct_hierarchy(self, items: list[dict]) -> Optional[dict]:
627
647
  """
628
648
  Reconstructs a hierarchical dictionary structure from a flat list of dictionaries
@@ -704,7 +724,9 @@ class Table:
704
724
  if field_name.startswith("_"):
705
725
  continue
706
726
 
707
- field_type = field_info.annotation
727
+ is_optional, inner_type = self.inspect_optional_field(parent_model_class, field_name)
728
+
729
+ field_type = inner_type if is_optional else field_info.annotation
708
730
 
709
731
  if field_type == child_model_class:
710
732
  matching_fields.append((field_name, "single"))
@@ -204,8 +204,19 @@ class DatabaseModel(BaseModel, TrackingMixin, extra=Extra.allow):
204
204
 
205
205
  @property
206
206
  def should_delete(self) -> bool:
207
+ if self._is_any_parent_marked_for_deletion():
208
+ return True
209
+
207
210
  return self._should_delete or self.is_parent_changed()
208
211
 
212
+ def _is_any_parent_marked_for_deletion(self) -> bool:
213
+ current = self._parent
214
+ while current is not None:
215
+ if current._should_delete:
216
+ return True
217
+ current = current._parent
218
+ return False
219
+
209
220
  @classmethod
210
221
  def query(
211
222
  cls: Type[T],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: statikk
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: statikk is a single table application (STA) library for DynamoDb.
5
5
  Home-page: https://github.com/terinia/statikk
6
6
  Author: Balint Biro
@@ -775,8 +775,20 @@ def test_nested_raw_models():
775
775
 
776
776
 
777
777
  def test_nested_hierarchies():
778
+ class OptionalModel(DatabaseModel):
779
+ xax: str = "xax"
780
+
781
+ @classmethod
782
+ def index_definitions(cls) -> dict[str, IndexFieldConfig]:
783
+ return {"main-index": IndexFieldConfig(sk_fields=["xax"])}
784
+
785
+ @classmethod
786
+ def is_nested(cls) -> bool:
787
+ return True
788
+
778
789
  class TriplyNested(DatabaseModel):
779
790
  faz: str = "faz"
791
+ optional: Optional[OptionalModel] = None
780
792
 
781
793
  @classmethod
782
794
  def index_definitions(cls) -> dict[str, IndexFieldConfig]:
@@ -833,10 +845,10 @@ def test_nested_hierarchies():
833
845
  sort_key=Key(name="gsi_sk"),
834
846
  )
835
847
  ],
836
- models=[ModelHierarchy, NestedModel, DoublyNestedModel, TriplyNested],
848
+ models=[ModelHierarchy, NestedModel, DoublyNestedModel, TriplyNested, OptionalModel],
837
849
  )
838
850
  _create_dynamodb_table(table)
839
- triple_nested_model = TriplyNested(faz="faz")
851
+ triple_nested_model = TriplyNested(faz="faz", optional=OptionalModel(xax="xax"))
840
852
  doubly_nested = DoublyNestedModel(bar="bar", items=[triple_nested_model])
841
853
  double_nested_no_write = DoublyNestedModel(bar="far", items=[TriplyNested(faz="faz")])
842
854
  nested = NestedModel(foo="foo", doubly_nested=[doubly_nested, double_nested_no_write])
@@ -851,6 +863,15 @@ def test_nested_hierarchies():
851
863
  assert hierarchy.nested.doubly_nested[0].gsi_pk == "foo_id"
852
864
  assert hierarchy.nested.doubly_nested[0].gsi_sk == "ModelHierarchy|state|NestedModel|foo|DoublyNestedModel|bar"
853
865
  assert hierarchy.nested.doubly_nested[0].items[0].gsi_pk == "foo_id"
866
+ assert (
867
+ hierarchy.nested.doubly_nested[0].items[0].gsi_sk
868
+ == "ModelHierarchy|state|NestedModel|foo|DoublyNestedModel|bar|TriplyNested|faz"
869
+ )
870
+ assert hierarchy.nested.doubly_nested[0].items[0].optional.gsi_pk == "foo_id"
871
+ assert (
872
+ hierarchy.nested.doubly_nested[0].items[0].optional.gsi_sk
873
+ == "ModelHierarchy|state|NestedModel|foo|DoublyNestedModel|bar|TriplyNested|faz|OptionalModel|xax"
874
+ )
854
875
  hierarchy.nested.doubly_nested[0].items[0].mark_for_delete()
855
876
  hierarchy.save()
856
877
  hierarchy = ModelHierarchy.query_hierarchy(hash_key=Equals("foo_id"))
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