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 +11 -31
- statikk/models.py +32 -1
- statikk/typing.py +22 -1
- {statikk-0.1.11.dist-info → statikk-0.1.13.dist-info}/METADATA +3 -2
- statikk-0.1.13.dist-info/RECORD +12 -0
- {statikk-0.1.11.dist-info → statikk-0.1.13.dist-info}/WHEEL +1 -1
- statikk-0.1.11.dist-info/RECORD +0 -12
- {statikk-0.1.11.dist-info → statikk-0.1.13.dist-info/licenses}/LICENSE.txt +0 -0
- {statikk-0.1.11.dist-info → statikk-0.1.13.dist-info}/top_level.txt +0 -0
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
|
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
|
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 =
|
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.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: statikk
|
3
|
-
Version: 0.1.
|
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,,
|
statikk-0.1.11.dist-info/RECORD
DELETED
@@ -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,,
|
File without changes
|
File without changes
|