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.
Files changed (45) hide show
  1. {statikk-0.0.13 → statikk-0.1.0}/PKG-INFO +10 -8
  2. {statikk-0.0.13 → statikk-0.1.0}/README.rst +10 -8
  3. {statikk-0.0.13 → statikk-0.1.0}/docs/usage.rst +40 -33
  4. {statikk-0.0.13 → statikk-0.1.0}/setup.py +6 -5
  5. {statikk-0.0.13 → statikk-0.1.0}/src/statikk/conditions.py +3 -2
  6. {statikk-0.0.13 → statikk-0.1.0}/src/statikk/engine.py +294 -85
  7. statikk-0.1.0/src/statikk/fields.py +2 -0
  8. statikk-0.1.0/src/statikk/models.py +359 -0
  9. {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/PKG-INFO +10 -8
  10. {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/SOURCES.txt +1 -0
  11. statikk-0.1.0/tests/conftest.py +10 -0
  12. {statikk-0.0.13 → statikk-0.1.0}/tests/test_engine.py +200 -169
  13. statikk-0.1.0/tests/test_models.py +86 -0
  14. statikk-0.0.13/src/statikk/models.py +0 -190
  15. statikk-0.0.13/tests/conftest.py +0 -10
  16. statikk-0.0.13/tests/test_models.py +0 -66
  17. {statikk-0.0.13 → statikk-0.1.0}/.coveragerc +0 -0
  18. {statikk-0.0.13 → statikk-0.1.0}/.gitignore +0 -0
  19. {statikk-0.0.13 → statikk-0.1.0}/.readthedocs.yml +0 -0
  20. {statikk-0.0.13 → statikk-0.1.0}/AUTHORS.rst +0 -0
  21. {statikk-0.0.13 → statikk-0.1.0}/CHANGELOG.rst +0 -0
  22. {statikk-0.0.13 → statikk-0.1.0}/CONTRIBUTING.rst +0 -0
  23. {statikk-0.0.13 → statikk-0.1.0}/LICENSE.txt +0 -0
  24. {statikk-0.0.13 → statikk-0.1.0}/assets/favicon.png +0 -0
  25. {statikk-0.0.13 → statikk-0.1.0}/assets/logo.png +0 -0
  26. {statikk-0.0.13 → statikk-0.1.0}/docs/Makefile +0 -0
  27. {statikk-0.0.13 → statikk-0.1.0}/docs/_static/.gitignore +0 -0
  28. {statikk-0.0.13 → statikk-0.1.0}/docs/authors.rst +0 -0
  29. {statikk-0.0.13 → statikk-0.1.0}/docs/changelog.rst +0 -0
  30. {statikk-0.0.13 → statikk-0.1.0}/docs/conf.py +0 -0
  31. {statikk-0.0.13 → statikk-0.1.0}/docs/contributing.rst +0 -0
  32. {statikk-0.0.13 → statikk-0.1.0}/docs/index.rst +0 -0
  33. {statikk-0.0.13 → statikk-0.1.0}/docs/license.rst +0 -0
  34. {statikk-0.0.13 → statikk-0.1.0}/docs/readme.rst +0 -0
  35. {statikk-0.0.13 → statikk-0.1.0}/docs/requirements.txt +0 -0
  36. {statikk-0.0.13 → statikk-0.1.0}/pyproject.toml +0 -0
  37. {statikk-0.0.13 → statikk-0.1.0}/setup.cfg +0 -0
  38. {statikk-0.0.13 → statikk-0.1.0}/src/statikk/__init__.py +0 -0
  39. {statikk-0.0.13 → statikk-0.1.0}/src/statikk/expressions.py +0 -0
  40. {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/dependency_links.txt +0 -0
  41. {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/not-zip-safe +0 -0
  42. {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/requires.txt +0 -0
  43. {statikk-0.0.13 → statikk-0.1.0}/src/statikk.egg-info/top_level.txt +0 -0
  44. {statikk-0.0.13 → statikk-0.1.0}/tests/test_expressions.py +0 -0
  45. {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.13
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
- We built this library because we got fed up with all the boilerplate we needed to write to use DynamoDB in a Single Table Application architecture.
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
- This library is very much in alpha phase and is not yet recommended for production use. We are actively working on it and using it as a core library
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, IndexPrimaryKeyField, IndexSecondaryKeyField
56
+ from statikk.models import DatabaseModel, Table, GlobalSecondaryIndex, KeySchema
59
57
 
60
58
  class MyAwesomeModel(DatabaseModel):
61
- player_id: IndexPrimaryKeyField
62
- tier: IndexSecondaryKeyField
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
- We built this library because we got fed up with all the boilerplate we needed to write to use DynamoDB in a Single Table Application architecture.
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
- This library is very much in alpha phase and is not yet recommended for production use. We are actively working on it and using it as a core library
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, IndexPrimaryKeyField, IndexSecondaryKeyField
31
+ from statikk.models import DatabaseModel, Table, GlobalSecondaryIndex, KeySchema
34
32
 
35
33
  class MyAwesomeModel(DatabaseModel):
36
- player_id: IndexPrimaryKeyField
37
- tier: IndexSecondaryKeyField
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: IndexSecondaryKeyField
53
+ last_login_date: datetime
54
54
 
55
55
  @classmethod
56
- def type_is_primary_key(cls):
57
- # Makes the model's type the primary key. The model's type is the class name
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 include_type_in_sort_key(cls):
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: IndexPrimaryKeyField
76
- tier: IndexSecondaryKeyField
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: IndexPrimaryKeyField
172
- origin: IndexSecondaryKeyField
173
- tier: IndexSecondaryKeyField
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: IndexPrimaryKeyField
203
- tier: IndexSecondaryKeyField
204
- origin: IndexPrimaryKeyField = IndexPrimaryKeyField(index_names=["secondary-index"])
205
- unit_class: IndexSecondaryKeyField = IndexSecondaryKeyField(index_names=["main-index", "secondary-index"])
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: IndexPrimaryKeyField
235
- cost: IndexSecondaryKeyField(type=int)
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: IndexPrimaryKeyField
291
- tier: IndexSecondaryKeyField
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
- Setup file for statikk.
3
- Use setup.cfg to configure your project.
2
+ Setup file for statikk.
3
+ Use setup.cfg to configure your project.
4
4
 
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/
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.model_type()) and model_class.include_type_in_sort_key():
41
- self.value = f"{model_class.model_type()}|{self.value}"
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):