statikk 0.1.11__py3-none-any.whl → 0.1.13__py3-none-any.whl

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/engine.py CHANGED
@@ -1,14 +1,14 @@
1
1
  import os
2
2
  from datetime import datetime
3
- from typing import Any, Dict, Type, Optional, List, Union, get_type_hints, get_origin, get_args
3
+ from typing import Any, Dict, Type, Optional, List, Union
4
4
 
5
5
  import boto3
6
6
  from botocore.config import Config
7
7
  from pydantic.fields import FieldInfo
8
- from boto3.dynamodb.conditions import ComparisonCondition, Key
8
+ from boto3.dynamodb.conditions import ComparisonCondition
9
9
  from boto3.dynamodb.types import TypeDeserializer, Decimal
10
10
 
11
- from statikk.typing import T
11
+ from statikk.typing import T, inspect_optional_field
12
12
  from statikk.conditions import Condition, Equals, BeginsWith
13
13
  from statikk.expressions import UpdateExpressionBuilder
14
14
  from statikk.models import (
@@ -609,6 +609,13 @@ class Table:
609
609
 
610
610
  dynamodb_table = self._get_dynamodb_table()
611
611
 
612
+ if len(delete_items) > 0:
613
+ with dynamodb_table.batch_writer() as batch:
614
+ for item in delete_items:
615
+ enriched_item = self._prepare_model_data(item, self.indexes)
616
+ data = self._serialize_item(enriched_item)
617
+ batch.delete_item(Key=data)
618
+
612
619
  if len(put_items) > 0:
613
620
  with dynamodb_table.batch_writer() as batch:
614
621
  for item in put_items:
@@ -620,33 +627,6 @@ class Table:
620
627
  data = self._serialize_item(enriched_item)
621
628
  batch.put_item(Item=data)
622
629
 
623
- if len(delete_items) > 0:
624
- with dynamodb_table.batch_writer() as batch:
625
- for item in delete_items:
626
- enriched_item = self._prepare_model_data(item, self.indexes)
627
- data = self._serialize_item(enriched_item)
628
- batch.delete_item(Key=data)
629
-
630
- def inspect_optional_field(self, model_class, field_name):
631
- field_type = model_class.model_fields[field_name].annotation
632
-
633
- is_optional = False
634
- inner_type = field_type
635
-
636
- if get_origin(field_type) is Union:
637
- args = get_args(field_type)
638
- if len(args) == 2 and args[1] is type(None):
639
- is_optional = True
640
- inner_type = args[0]
641
-
642
- elif hasattr(field_type, "__origin__") and field_type.__origin__ is Union:
643
- args = getattr(field_type, "__args__", [])
644
- if len(args) == 2 and args[1] is type(None):
645
- is_optional = True
646
- inner_type = args[0]
647
-
648
- return (is_optional, inner_type)
649
-
650
630
  def reconstruct_hierarchy(self, items: list[dict]) -> Optional[dict]:
651
631
  """
652
632
  Reconstructs a hierarchical dictionary structure from a flat list of dictionaries
@@ -728,7 +708,7 @@ class Table:
728
708
  if field_name.startswith("_"):
729
709
  continue
730
710
 
731
- is_optional, inner_type = self.inspect_optional_field(parent_model_class, field_name)
711
+ is_optional, inner_type = inspect_optional_field(parent_model_class, field_name)
732
712
 
733
713
  field_type = inner_type if is_optional else field_info.annotation
734
714
 
statikk/models.py CHANGED
@@ -4,7 +4,7 @@ import typing
4
4
  import logging
5
5
  from uuid import uuid4
6
6
  from typing import Optional, List, Any, Set, Type
7
- from statikk.typing import T
7
+ from statikk.typing import T, inspect_optional_field
8
8
 
9
9
  from boto3.dynamodb.conditions import ComparisonCondition
10
10
  from pydantic import BaseModel, model_serializer, model_validator, Field, Extra
@@ -296,6 +296,37 @@ class DatabaseModel(BaseModel, TrackingMixin, extra=Extra.allow):
296
296
  def change_parent_to(self, new_parent: DatabaseModel) -> T:
297
297
  return self._table.reparent_subtree(self, new_parent)
298
298
 
299
+ def add_child_node(self, field_name: str, child_node: DatabaseModel):
300
+ if not child_node.is_nested():
301
+ raise ValueError("Child node must be nested.")
302
+
303
+ if not hasattr(self, field_name):
304
+ raise ValueError(f"Field {field_name} does not exist on {self.__class__.__name__}")
305
+
306
+ is_optional, inner_type = inspect_optional_field(self.__class__, field_name)
307
+ field_type = inner_type if is_optional else self.model_fields[field_name].annotation
308
+
309
+ if hasattr(field_type, "__origin__") and field_type.__origin__ == list:
310
+ if not isinstance(getattr(self, field_name), list):
311
+ setattr(self, field_name, [])
312
+ reparented = child_node.change_parent_to(self)
313
+ getattr(self, field_name).append(reparented)
314
+ return reparented
315
+
316
+ elif hasattr(field_type, "__origin__") and field_type.__origin__ == set:
317
+ if not isinstance(getattr(self, field_name), set):
318
+ setattr(self, field_name, set())
319
+ reparented = child_node.change_parent_to(self)
320
+ getattr(self, field_name).add(reparented)
321
+ return reparented
322
+
323
+ elif issubclass(field_type, DatabaseModel):
324
+ reparented = child_node.change_parent_to(self)
325
+ setattr(self, field_name, reparented)
326
+ return reparented
327
+
328
+ raise ValueError(f"Unsupported field type: {field_type}")
329
+
299
330
  @classmethod
300
331
  def scan(
301
332
  cls,
statikk/typing.py CHANGED
@@ -1,3 +1,24 @@
1
- from typing import TypeVar
1
+ from typing import TypeVar, get_origin, Union, get_args
2
2
 
3
3
  T = TypeVar("T", bound="DatabaseModel")
4
+
5
+
6
+ def inspect_optional_field(model_class, field_name):
7
+ field_type = model_class.model_fields[field_name].annotation
8
+
9
+ is_optional = False
10
+ inner_type = field_type
11
+
12
+ if get_origin(field_type) is Union:
13
+ args = get_args(field_type)
14
+ if len(args) == 2 and args[1] is type(None):
15
+ is_optional = True
16
+ inner_type = args[0]
17
+
18
+ elif hasattr(field_type, "__origin__") and field_type.__origin__ is Union:
19
+ args = getattr(field_type, "__args__", [])
20
+ if len(args) == 2 and args[1] is type(None):
21
+ is_optional = True
22
+ inner_type = args[0]
23
+
24
+ return (is_optional, inner_type)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: statikk
3
- Version: 0.1.11
3
+ Version: 0.1.13
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
@@ -22,6 +22,7 @@ Requires-Dist: setuptools; extra == "testing"
22
22
  Requires-Dist: pytest; extra == "testing"
23
23
  Requires-Dist: pytest-cov; extra == "testing"
24
24
  Requires-Dist: moto[dynamodb]==4.2.14; extra == "testing"
25
+ Dynamic: license-file
25
26
 
26
27
  .. image:: ./assets/logo.png
27
28
  :alt: Statikk
@@ -0,0 +1,12 @@
1
+ statikk/__init__.py,sha256=pH5i4Fj1tbXLqLtTVIdoojiplZssQn0nnud8-HXodRE,577
2
+ statikk/conditions.py,sha256=63FYMR-UUaE-ZJEb_8CU721CQTwhajq39-BbokmKeMA,2166
3
+ statikk/engine.py,sha256=xH8vbUcup3FmZ3h3RL6-j1hxVDSQwrRASp8ILhoKXn8,32604
4
+ statikk/expressions.py,sha256=boAeGxZj2cDsXxoiX3IIEzfX9voSMQngi4-rE_jYeuE,12233
5
+ statikk/fields.py,sha256=LkMP5NnX7WS0HSLxI3Q-dMOrfaJ0SD7SayZxJU5Acgg,86
6
+ statikk/models.py,sha256=fU5SwxKP1Afsy91RhYiJSD58CCF92s4YxX-fwH6p7ZI,17705
7
+ statikk/typing.py,sha256=laOlOpWOm9_sOj4hhdZnGTUZRiq8760_B9I9B3wBhz8,750
8
+ statikk-0.1.13.dist-info/licenses/LICENSE.txt,sha256=uSH_2Hpb2Bigy5_HhBliN2fZbBU64G3ERM5zzhKPUEE,1078
9
+ statikk-0.1.13.dist-info/METADATA,sha256=pv7MrB9Svi22O1z--jDhW8DkEvdxNP4nErQLt7HqQpg,3183
10
+ statikk-0.1.13.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
11
+ statikk-0.1.13.dist-info/top_level.txt,sha256=etKmBbjzIlLpSefXoiOfhWGEgvqUEALaFwCjFDBD9YI,8
12
+ statikk-0.1.13.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.1.0)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,12 +0,0 @@
1
- statikk/__init__.py,sha256=pH5i4Fj1tbXLqLtTVIdoojiplZssQn0nnud8-HXodRE,577
2
- statikk/conditions.py,sha256=63FYMR-UUaE-ZJEb_8CU721CQTwhajq39-BbokmKeMA,2166
3
- statikk/engine.py,sha256=FB0eNNGE9ZHz43HbI0Op-7N2cY88Ec1-w68JkdHFDpE,33346
4
- statikk/expressions.py,sha256=boAeGxZj2cDsXxoiX3IIEzfX9voSMQngi4-rE_jYeuE,12233
5
- statikk/fields.py,sha256=LkMP5NnX7WS0HSLxI3Q-dMOrfaJ0SD7SayZxJU5Acgg,86
6
- statikk/models.py,sha256=REipaPzo5dIq4InXbWuP48aDZdImO5fXGkALenbf7Ng,16257
7
- statikk/typing.py,sha256=qfpegORcdODuILK3gvuD4SdcZA1a7Myn0yvscOLPHOM,68
8
- statikk-0.1.11.dist-info/LICENSE.txt,sha256=uSH_2Hpb2Bigy5_HhBliN2fZbBU64G3ERM5zzhKPUEE,1078
9
- statikk-0.1.11.dist-info/METADATA,sha256=eDwlysQ8a42xVr-zOFJHW8s9tcHM9Tqm_fOD_eWGanw,3161
10
- statikk-0.1.11.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
11
- statikk-0.1.11.dist-info/top_level.txt,sha256=etKmBbjzIlLpSefXoiOfhWGEgvqUEALaFwCjFDBD9YI,8
12
- statikk-0.1.11.dist-info/RECORD,,