statikk 0.0.13__tar.gz → 0.1.0__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.0.13 → statikk-0.1.0}/PKG-INFO +10 -8
- {statikk-0.0.13 → statikk-0.1.0}/README.rst +10 -8
- {statikk-0.0.13 → statikk-0.1.0}/docs/usage.rst +40 -33
- {statikk-0.0.13 → statikk-0.1.0}/setup.py +6 -5
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk/conditions.py +3 -2
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk/engine.py +294 -85
- statikk-0.1.0/src/statikk/fields.py +2 -0
- statikk-0.1.0/src/statikk/models.py +359 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/PKG-INFO +10 -8
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/SOURCES.txt +1 -0
- statikk-0.1.0/tests/conftest.py +10 -0
- {statikk-0.0.13 → statikk-0.1.0}/tests/test_engine.py +200 -169
- statikk-0.1.0/tests/test_models.py +86 -0
- statikk-0.0.13/src/statikk/models.py +0 -190
- statikk-0.0.13/tests/conftest.py +0 -10
- statikk-0.0.13/tests/test_models.py +0 -66
- {statikk-0.0.13 → statikk-0.1.0}/.coveragerc +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/.gitignore +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/.readthedocs.yml +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/AUTHORS.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/CHANGELOG.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/CONTRIBUTING.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/LICENSE.txt +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/assets/favicon.png +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/assets/logo.png +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/Makefile +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/_static/.gitignore +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/authors.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/changelog.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/conf.py +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/contributing.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/index.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/license.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/readme.rst +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/docs/requirements.txt +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/pyproject.toml +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/setup.cfg +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk/__init__.py +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk/expressions.py +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/dependency_links.txt +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/not-zip-safe +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/requires.txt +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/top_level.txt +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/tests/test_expressions.py +0 -0
- {statikk-0.0.13 → statikk-0.1.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: statikk
|
3
|
-
Version: 0.0
|
3
|
+
Version: 0.1.0
|
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
|
@@ -27,11 +27,9 @@ Requires-Dist: moto[dynamodb]==4.2.14; extra == "testing"
|
|
27
27
|
:alt: Statikk
|
28
28
|
:align: center
|
29
29
|
|
30
|
-
|
31
|
-
We were originally using `PynamoDB <https://github.com/pynamodb/PynamoDB>`_ , but we found it to be too verbose for our liking.
|
30
|
+
An ORM-like Single Table Application (STA) architecture library for Python and DynamoDb. Makes it really eason to set up and work with STAs.
|
32
31
|
|
33
|
-
|
34
|
-
for our upcoming game, Conquests of Ethoas. Drastic API changes can still happen.
|
32
|
+
The library is in alpha. Constant work is being done on it as I'm developing my game.
|
35
33
|
|
36
34
|
=================
|
37
35
|
Requirements
|
@@ -55,15 +53,19 @@ Basic Usage
|
|
55
53
|
|
56
54
|
.. code-block:: python
|
57
55
|
|
58
|
-
from statikk.models import DatabaseModel, Table, GlobalSecondaryIndex, KeySchema
|
56
|
+
from statikk.models import DatabaseModel, Table, GlobalSecondaryIndex, KeySchema
|
59
57
|
|
60
58
|
class MyAwesomeModel(DatabaseModel):
|
61
|
-
player_id:
|
62
|
-
tier:
|
59
|
+
player_id: str
|
60
|
+
tier: str
|
63
61
|
name: str = "Foo"
|
64
62
|
values: set = {1, 2, 3, 4}
|
65
63
|
cost: int = 4
|
66
64
|
|
65
|
+
@classmethod
|
66
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
67
|
+
return {"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["tier"])}
|
68
|
+
|
67
69
|
table = Table(
|
68
70
|
name="my-dynamodb-table",
|
69
71
|
key_schema=KeySchema(hash_key="id"),
|
@@ -2,11 +2,9 @@
|
|
2
2
|
:alt: Statikk
|
3
3
|
:align: center
|
4
4
|
|
5
|
-
|
6
|
-
We were originally using `PynamoDB <https://github.com/pynamodb/PynamoDB>`_ , but we found it to be too verbose for our liking.
|
5
|
+
An ORM-like Single Table Application (STA) architecture library for Python and DynamoDb. Makes it really eason to set up and work with STAs.
|
7
6
|
|
8
|
-
|
9
|
-
for our upcoming game, Conquests of Ethoas. Drastic API changes can still happen.
|
7
|
+
The library is in alpha. Constant work is being done on it as I'm developing my game.
|
10
8
|
|
11
9
|
=================
|
12
10
|
Requirements
|
@@ -30,15 +28,19 @@ Basic Usage
|
|
30
28
|
|
31
29
|
.. code-block:: python
|
32
30
|
|
33
|
-
from statikk.models import DatabaseModel, Table, GlobalSecondaryIndex, KeySchema
|
31
|
+
from statikk.models import DatabaseModel, Table, GlobalSecondaryIndex, KeySchema
|
34
32
|
|
35
33
|
class MyAwesomeModel(DatabaseModel):
|
36
|
-
player_id:
|
37
|
-
tier:
|
34
|
+
player_id: str
|
35
|
+
tier: str
|
38
36
|
name: str = "Foo"
|
39
37
|
values: set = {1, 2, 3, 4}
|
40
38
|
cost: int = 4
|
41
39
|
|
40
|
+
@classmethod
|
41
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
42
|
+
return {"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["tier"])}
|
43
|
+
|
42
44
|
table = Table(
|
43
45
|
name="my-dynamodb-table",
|
44
46
|
key_schema=KeySchema(hash_key="id"),
|
@@ -71,4 +73,4 @@ Features
|
|
71
73
|
- `Single Table Application architecture <https://www.youtube.com/watch?v=HaEPXoXVf2k>`_
|
72
74
|
- Easy model definition using Pydantic
|
73
75
|
- Automatic index value construction based on marked fields.
|
74
|
-
- Get, Update, Delete, Batch Get, Batch Write, Query, and Scan operations
|
76
|
+
- Get, Update, Delete, Batch Get, Batch Write, Query, and Scan operations
|
@@ -50,21 +50,14 @@ Model definition
|
|
50
50
|
|
51
51
|
class Player(DatabaseModel):
|
52
52
|
# we don't define an id field, so a uuid will be automatically assigned to the model when it's created
|
53
|
-
last_login_date:
|
53
|
+
last_login_date: datetime
|
54
54
|
|
55
55
|
@classmethod
|
56
|
-
def
|
57
|
-
|
58
|
-
return True
|
56
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
57
|
+
return {"main-index": IndexFieldConfig(pk_fields=["type"], sk_fields=["last_login_date"])}
|
59
58
|
|
60
59
|
@classmethod
|
61
|
-
def
|
62
|
-
# By default, the model's type is alawys included in the sort key. This is useful to avoid collisions of similar
|
63
|
-
# models that share the same primary key. Here however, we want the type to be the primary key only.
|
64
|
-
return False
|
65
|
-
|
66
|
-
@classmethod
|
67
|
-
def model_type(cls):
|
60
|
+
def type(cls):
|
68
61
|
# The default return value for this method is the name of the class, but feel free to override it here to whatever
|
69
62
|
# you'd like present in the sort key.
|
70
63
|
return "Player"
|
@@ -72,11 +65,15 @@ Model definition
|
|
72
65
|
|
73
66
|
class Card(DatabaseModel):
|
74
67
|
id: str
|
75
|
-
player_id:
|
76
|
-
tier:
|
68
|
+
player_id: str
|
69
|
+
tier: str
|
77
70
|
values: list[int]
|
78
71
|
cost: int
|
79
72
|
|
73
|
+
@classmethod
|
74
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
75
|
+
return {"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["tier"])}
|
76
|
+
|
80
77
|
The above setup allows us to query the table in the following ways:
|
81
78
|
- Get all players
|
82
79
|
- Get all players by their last login date
|
@@ -168,9 +165,13 @@ Let's take a look at an example:
|
|
168
165
|
|
169
166
|
class MultiKeyCard(DatabaseModel):
|
170
167
|
id: str
|
171
|
-
player_id:
|
172
|
-
origin:
|
173
|
-
tier:
|
168
|
+
player_id: str
|
169
|
+
origin: str
|
170
|
+
tier: str
|
171
|
+
|
172
|
+
@classmethod
|
173
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
174
|
+
return {"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["origin", "tier"])}
|
174
175
|
|
175
176
|
This setup allows you to search using the following patterns:
|
176
177
|
- Get all cards belonging to a player
|
@@ -180,15 +181,6 @@ This setup allows you to search using the following patterns:
|
|
180
181
|
Note that the order is **REALLY** important here. Swapping up the order in on your production data will cause absolute havoc on your queries
|
181
182
|
and will taint your data.
|
182
183
|
|
183
|
-
It is **HIGHLY RECOMMENDED** to manually define the order property on your secondary index fields.
|
184
|
-
|
185
|
-
.. code-block:: python
|
186
|
-
|
187
|
-
class MultiKeyCard(DatabaseModel):
|
188
|
-
id: str
|
189
|
-
player_id: IndexPrimaryKeyField
|
190
|
-
origin: IndexSecondaryKeyField(order=1)
|
191
|
-
tier: IndexSecondaryKeyField(order=2)
|
192
184
|
|
193
185
|
====================
|
194
186
|
Multiple indexes
|
@@ -199,10 +191,17 @@ Statikk also supports multiple indexes. This is useful if you want to query your
|
|
199
191
|
.. code-block:: python
|
200
192
|
|
201
193
|
class MultiIndexModel(DatabaseModel):
|
202
|
-
player_id:
|
203
|
-
tier:
|
204
|
-
origin:
|
205
|
-
unit_class:
|
194
|
+
player_id: str
|
195
|
+
tier: str
|
196
|
+
origin: str
|
197
|
+
unit_class: str
|
198
|
+
|
199
|
+
@classmethod
|
200
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
201
|
+
return {
|
202
|
+
"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["tier", "unit_class"]),
|
203
|
+
"secondary-index": IndexFieldConfig(pk_fields=["origin"], sk_fields=["unit_class"]),
|
204
|
+
}
|
206
205
|
|
207
206
|
This setup requires the table to have two indexes defined: main-index and secondary index. Notice that the ``unit_class`` field
|
208
207
|
is actually part of both the main and the secondary index. So when Statikk constructs the index values for this model, it will include
|
@@ -231,8 +230,12 @@ For example:
|
|
231
230
|
.. code-block:: python
|
232
231
|
|
233
232
|
class Card(DatabaseModel):
|
234
|
-
player_id:
|
235
|
-
cost:
|
233
|
+
player_id: str
|
234
|
+
cost: int
|
235
|
+
|
236
|
+
@classmethod
|
237
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
238
|
+
return {"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["cost"])}
|
236
239
|
|
237
240
|
def query_data():
|
238
241
|
models = list(Card.query(hash_key=Equals(player.id), range_key=GreaterThan(4), filter_condition=Attr("type").gte("Card")))
|
@@ -287,12 +290,16 @@ Let's take a look at an example:
|
|
287
290
|
.. code-block:: python
|
288
291
|
|
289
292
|
class Card(DatabaseModel):
|
290
|
-
player_id:
|
291
|
-
tier:
|
293
|
+
player_id: str
|
294
|
+
tier: str
|
292
295
|
values: set[int]
|
293
296
|
cost: int
|
294
297
|
name: str = "Foo"
|
295
298
|
|
299
|
+
@classmethod
|
300
|
+
def index_definitions(cls) -> dict[str, IndexFieldConfig]:
|
301
|
+
return {"main-index": IndexFieldConfig(pk_fields=["player_id"], sk_fields=["tier"])}
|
302
|
+
|
296
303
|
card = Card(player_id=player.id, tier="EPIC", values={1, 2, 3, 4}, cost=5, name="FooFoo")
|
297
304
|
card.save()
|
298
305
|
card.update().set("tier", "LEGENDARY").delete("values", {1}).add("cost", 4).remove("name").execute()
|
@@ -1,11 +1,12 @@
|
|
1
1
|
"""
|
2
|
-
|
3
|
-
|
2
|
+
Setup file for statikk.
|
3
|
+
Use setup.cfg to configure your project.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
This file was generated with PyScaffold 4.5.
|
6
|
+
PyScaffold helps you to put up the scaffold of your new Python project.
|
7
|
+
Learn more under: https://pyscaffold.org/
|
8
8
|
"""
|
9
|
+
|
9
10
|
from setuptools import setup
|
10
11
|
|
11
12
|
if __name__ == "__main__":
|
@@ -10,6 +10,7 @@ Example usage of this module:
|
|
10
10
|
from statikk.conditions import Equals, BeginsWith
|
11
11
|
app.query(range_key=Equals("123"), hash_key=BeginsWith("abc"))
|
12
12
|
"""
|
13
|
+
|
13
14
|
from abc import ABC, abstractmethod
|
14
15
|
from boto3.dynamodb.conditions import Key, ComparisonCondition
|
15
16
|
from typing import Any
|
@@ -37,8 +38,8 @@ class BeginsWith(Condition):
|
|
37
38
|
return Key(key).begins_with(self.value)
|
38
39
|
|
39
40
|
def enrich(self, model_class, **kwargs):
|
40
|
-
if not self.value.startswith(model_class.
|
41
|
-
self.value = f"{model_class.
|
41
|
+
if not self.value.startswith(model_class.type()):
|
42
|
+
self.value = f"{model_class.type()}|{self.value}"
|
42
43
|
|
43
44
|
|
44
45
|
class LessThan(Condition):
|