boto3-assist 0.22.0__tar.gz → 0.23.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 (146) hide show
  1. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.vscode/settings.json +1 -0
  2. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/PKG-INFO +1 -1
  3. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/pyproject.toml +1 -1
  4. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb.py +3 -1
  5. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_index.py +10 -5
  6. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_model_base.py +9 -1
  7. boto3_assist-0.23.0/src/boto3_assist/version.py +1 -0
  8. boto3_assist-0.23.0/tests/unit/dynamodb_tests/db_models/task.py +76 -0
  9. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_fail_if_exists_test.py +7 -9
  10. boto3_assist-0.23.0/tests/unit/dynamodb_tests/dynamodb_primary_key_sort_test.py +82 -0
  11. boto3_assist-0.22.0/src/boto3_assist/version.py +0 -1
  12. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.env.docker +0 -0
  13. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.env.docker.001 +0 -0
  14. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.env.docker.nosql.workbench +0 -0
  15. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.env.unittest +0 -0
  16. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.gitignore +0 -0
  17. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.vscode/launch.json +0 -0
  18. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/.vscode/tasks.json +0 -0
  19. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/LICENSE-EXPLAINED.txt +0 -0
  20. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/LICENSE.txt +0 -0
  21. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/README.md +0 -0
  22. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/aws_regions_with_status.csv +0 -0
  23. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/aws_regions_with_status.json +0 -0
  24. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/devops/build.py +0 -0
  25. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/devops/readme.md +0 -0
  26. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/__init__.py +0 -0
  27. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/cloudwatch/log_report.py +0 -0
  28. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/models/order_item_model.py +0 -0
  29. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/models/order_model.py +0 -0
  30. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/models/product_model.py +0 -0
  31. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/models/user_model.py +0 -0
  32. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/models/user_post_model.py +0 -0
  33. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/order_example/main.py +0 -0
  34. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/order_example/products.json +0 -0
  35. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/order_item_service.py +0 -0
  36. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/order_service.py +0 -0
  37. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/product_service.py +0 -0
  38. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/table_service.py +0 -0
  39. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/user_post_service.py +0 -0
  40. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/user_service.py +0 -0
  41. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/user_service_client_example.py +0 -0
  42. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/services/user_service_resource_example.py +0 -0
  43. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/dynamodb/user_post_example/main.py +0 -0
  44. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/examples/ec2/regions_report.py +0 -0
  45. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/module-headers.txt +0 -0
  46. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/mypy.ini +0 -0
  47. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/requirements-dev.txt +0 -0
  48. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/requirements.txt +0 -0
  49. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/run-checks.sh +0 -0
  50. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/run_unit_tests.sh +0 -0
  51. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/__init__.py +0 -0
  52. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/aws_config.py +0 -0
  53. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/aws_lambda/event_info.py +0 -0
  54. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/aws_lambda/mock_context.py +0 -0
  55. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/boto3session.py +0 -0
  56. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cloudwatch/cloudwatch_connection.py +0 -0
  57. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cloudwatch/cloudwatch_connection_tracker.py +0 -0
  58. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cloudwatch/cloudwatch_log_connection.py +0 -0
  59. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cloudwatch/cloudwatch_logs.py +0 -0
  60. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cloudwatch/cloudwatch_query.py +0 -0
  61. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cognito/cognito_authorizer.py +0 -0
  62. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cognito/cognito_connection.py +0 -0
  63. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cognito/cognito_utility.py +0 -0
  64. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cognito/jwks_cache.py +0 -0
  65. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/cognito/user.py +0 -0
  66. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/connection.py +0 -0
  67. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/connection_tracker.py +0 -0
  68. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_connection.py +0 -0
  69. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_helpers.py +0 -0
  70. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_importer.py +0 -0
  71. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_iservice.py +0 -0
  72. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_key.py +0 -0
  73. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_model_base_interfaces.py +0 -0
  74. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_re_indexer.py +0 -0
  75. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_reindexer.py +0 -0
  76. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.py +0 -0
  77. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/dynamodb_reserved_words.txt +0 -0
  78. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/readme.md +0 -0
  79. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/dynamodb/troubleshooting.md +0 -0
  80. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/ec2/ec2_connection.py +0 -0
  81. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/environment_services/__init__.py +0 -0
  82. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/environment_services/environment_loader.py +0 -0
  83. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/environment_services/environment_variables.py +0 -0
  84. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/errors/custom_exceptions.py +0 -0
  85. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/http_status_codes.py +0 -0
  86. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/models/serializable_model.py +0 -0
  87. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/role_assumption_mixin.py +0 -0
  88. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/s3/s3.py +0 -0
  89. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/s3/s3_bucket.py +0 -0
  90. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/s3/s3_connection.py +0 -0
  91. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/s3/s3_event_data.py +0 -0
  92. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/s3/s3_object.py +0 -0
  93. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/securityhub/securityhub.py +0 -0
  94. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/securityhub/securityhub_connection.py +0 -0
  95. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/session_setup_mixin.py +0 -0
  96. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/ssm/connection.py +0 -0
  97. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/ssm/parameter_store/parameter_store.py +0 -0
  98. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/datetime_utility.py +0 -0
  99. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/dictionary_utility.py +0 -0
  100. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/file_operations.py +0 -0
  101. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/http_utility.py +0 -0
  102. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/logging_utility.py +0 -0
  103. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/numbers_utility.py +0 -0
  104. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/serialization_utility.py +0 -0
  105. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/src/boto3_assist/utilities/string_utility.py +0 -0
  106. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/__init__.py +0 -0
  107. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/integration/cross_account_connection_test.py +0 -0
  108. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/integration/tenant.py +0 -0
  109. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/integration/tenant_services.py +0 -0
  110. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/aws_config_test.py +0 -0
  111. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/common/db_test_helpers.py +0 -0
  112. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/__init__.py +0 -0
  113. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/cms/base.py +0 -0
  114. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/cms/content_block.py +0 -0
  115. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/cms/page.py +0 -0
  116. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/cms/template.py +0 -0
  117. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/simple_model.py +0 -0
  118. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/user_model.py +0 -0
  119. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/db_models/user_required_fields_model.py +0 -0
  120. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_model_base_test.py +0 -0
  121. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_model_projections_test.py +0 -0
  122. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_model_serializtion_test.py +0 -0
  123. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_moto_sorting_test.py +0 -0
  124. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_query_test.py +0 -0
  125. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/dynamodb_tests/dynamodb_reindex_test.py +0 -0
  126. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/examples_test/__init__.py +0 -0
  127. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/examples_test/user_service_test.py +0 -0
  128. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/lambda_tests/__init__.py +0 -0
  129. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/lambda_tests/event_info_test.py +0 -0
  130. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/models_tests/__init__.py +0 -0
  131. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/models_tests/models/person.py +0 -0
  132. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/models_tests/models/user.py +0 -0
  133. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/models_tests/serializable_model_person_test.py +0 -0
  134. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/models_tests/serializable_model_user_test.py +0 -0
  135. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/models_tests/serializable_model_wide_test.py +0 -0
  136. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/parameter_store/__init__.py +0 -0
  137. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/parameter_store/parameter_store_test.py +0 -0
  138. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/s3/__init__.py +0 -0
  139. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/s3/files/test.txt +0 -0
  140. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/s3/s3_event_data_test.py +0 -0
  141. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/s3/s3_file_delete_test.py +0 -0
  142. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/s3/s3_file_upload_test.py +0 -0
  143. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/session_tests/test_boto3_session_manager.py +0 -0
  144. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/utilities/__init__.py +0 -0
  145. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/utilities/serialization_utility_test.py +0 -0
  146. {boto3_assist-0.22.0 → boto3_assist-0.23.0}/tests/unit/utilities/string_utility_test.py +0 -0
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "cSpell.words": [
30
30
  "addopts",
31
+ "dateutil",
31
32
  "geekcafe",
32
33
  "relativedelta"
33
34
  ],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.22.0
3
+ Version: 0.23.0
4
4
  Summary: Additional boto3 wrappers to make your life a little easier
5
5
  Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
6
  License-File: LICENSE-EXPLAINED.txt
@@ -15,7 +15,7 @@ addopts = "-m 'not integration'"
15
15
 
16
16
  [project]
17
17
  name = "boto3_assist"
18
- version = "0.22.0"
18
+ version = "0.23.0"
19
19
 
20
20
  authors = [
21
21
  { name="Eric Wilson", email="boto3-assist@geekcafe.com" }
@@ -355,7 +355,9 @@ class DynamoDB(DynamoDBConnection):
355
355
  key = key.key()
356
356
 
357
357
  kwargs: dict = {}
358
- if index_name:
358
+
359
+ if index_name and index_name != "primary":
360
+ # only include the index_name if we are not using our "primary" pk/sk
359
361
  kwargs["IndexName"] = f"{index_name}"
360
362
  kwargs["TableName"] = f"{table_name}"
361
363
  kwargs["KeyConditionExpression"] = key
@@ -37,7 +37,7 @@ class DynamoDBIndexes:
37
37
  if index.name in self.__indexes:
38
38
  raise ValueError(
39
39
  f"The index {index.name} is already defined in your model somewhere. "
40
- "This error is generated to protect you from unforseen issues. "
40
+ "This error is generated to protect you from unforeseen issues. "
41
41
  "If you models are inheriting from other models, you may have the primary defined twice."
42
42
  )
43
43
 
@@ -64,7 +64,7 @@ class DynamoDBIndexes:
64
64
  for _, v in self.__indexes.items():
65
65
  if v.partition_key.attribute_name == index.partition_key.attribute_name:
66
66
  raise ValueError(
67
- f"The attrubute {index.partition_key.attribute_name} is already being used by index "
67
+ f"The attribute {index.partition_key.attribute_name} is already being used by index "
68
68
  f"{v.name}. "
69
69
  f"Reusing this attribute would over write the value on index {v.name}"
70
70
  )
@@ -73,7 +73,7 @@ class DynamoDBIndexes:
73
73
  for _, v in self.__indexes.items():
74
74
  if v.sort_key.attribute_name == index.sort_key.attribute_name:
75
75
  raise ValueError(
76
- f"The attrubute {index.sort_key.attribute_name} is already being used by index "
76
+ f"The attribute {index.sort_key.attribute_name} is already being used by index "
77
77
  f"{v.name}. "
78
78
  f"Reusing this attribute would over write the value on index {v.name}"
79
79
  )
@@ -160,9 +160,14 @@ class DynamoDBIndex:
160
160
  ) -> dict | Key | ConditionBase | ComparisonCondition | Equals:
161
161
  """Get the key for a given index"""
162
162
  key: dict | Key | ConditionBase | ComparisonCondition | Equals
163
- if self.name == DynamoDBIndexes.PRIMARY_INDEX and include_sort_key:
163
+ if (
164
+ self.name == DynamoDBIndexes.PRIMARY_INDEX
165
+ and include_sort_key
166
+ # if it ends with a # we are assuming that we are doing a wild card mapping
167
+ and not str(self.sort_key.value).endswith("#")
168
+ ):
164
169
  # this is a direct primary key which is used in a get call
165
- # this is differenet than query keys
170
+ # this is different than query keys
166
171
  key = {}
167
172
  key[self.partition_key.attribute_name] = self.partition_key.value
168
173
 
@@ -21,6 +21,7 @@ from boto3_assist.dynamodb.dynamodb_index import (
21
21
  from boto3_assist.dynamodb.dynamodb_reserved_words import DynamoDBReservedWords
22
22
  from boto3_assist.utilities.datetime_utility import DatetimeUtility
23
23
  from boto3_assist.models.serializable_model import SerializableModel
24
+ from boto3_assist.utilities.string_utility import StringUtility
24
25
 
25
26
 
26
27
  def exclude_from_serialization(method):
@@ -190,7 +191,7 @@ class DynamoDBModelBase(SerializableModel):
190
191
  def to_dictionary(self, include_none: bool = True):
191
192
  """
192
193
  Convert the instance to a dictionary without an indexes/keys.
193
- Usefull for turning an object into a dictionary for serialization.
194
+ Useful for turning an object into a dictionary for serialization.
194
195
  This is the same as to_resource_dictionary(include_indexes=False)
195
196
  """
196
197
  return DynamoDBSerializer.to_resource_dictionary(
@@ -205,6 +206,13 @@ class DynamoDBModelBase(SerializableModel):
205
206
 
206
207
  return self.indexes.get(index_name)
207
208
 
209
+ @staticmethod
210
+ def generate_uuid(sortable: bool = True) -> str:
211
+ if sortable:
212
+ return StringUtility.generate_sortable_uuid()
213
+
214
+ return StringUtility.generate_uuid()
215
+
208
216
  @property
209
217
  @exclude_from_serialization
210
218
  def helpers(self) -> DynamoDBHelpers:
@@ -0,0 +1 @@
1
+ __version__ = '0.23.0'
@@ -0,0 +1,76 @@
1
+ from typing import Optional
2
+ from boto3_assist.dynamodb.dynamodb_model_base import DynamoDBModelBase
3
+ from boto3_assist.dynamodb.dynamodb_index import DynamoDBIndex
4
+ from boto3_assist.dynamodb.dynamodb_key import DynamoDBKey
5
+ from boto3_assist.utilities.string_utility import StringUtility
6
+
7
+
8
+ class Task(DynamoDBModelBase):
9
+ """
10
+ A Generic Task Model
11
+
12
+ Using the same task.id, you can chain child elements via task.step_id
13
+
14
+ """
15
+
16
+ def __init__(self, id: Optional[str] = None):
17
+ super().__init__()
18
+ self.id: str = id or StringUtility.generate_uuid()
19
+ self._name: Optional[str] = None
20
+ self._step: Optional[str] = None
21
+ self._step_id: Optional[str] = None
22
+ self.metadata: dict = {}
23
+ self._setup_pk()
24
+
25
+ @property
26
+ def name(self) -> Optional[str]:
27
+ """
28
+ Returns the name for this task
29
+ """
30
+ return self._name
31
+
32
+ @name.setter
33
+ def name(self, value: str):
34
+ """
35
+ Sets the name for this task
36
+ """
37
+ self._name = value
38
+
39
+ @property
40
+ def step(self) -> Optional[str]:
41
+ """
42
+ Returns the step for this task
43
+ """
44
+ return self._step
45
+
46
+ @step.setter
47
+ def step(self, value: str):
48
+ """
49
+ Sets the step for this task
50
+ """
51
+ self._step = value
52
+
53
+ @property
54
+ def step_id(self) -> str | None:
55
+
56
+ return self._step_id
57
+
58
+ @step_id.setter
59
+ def step_id(self, value: str):
60
+ """
61
+ Sets the step_id for this task
62
+ """
63
+
64
+ self._step_id = value
65
+
66
+ def _setup_pk(self):
67
+ primary: DynamoDBIndex = DynamoDBIndex()
68
+ primary.name = "primary"
69
+ primary.partition_key.attribute_name = "pk"
70
+ primary.partition_key.value = lambda: DynamoDBKey.build_key(
71
+ (self.__class__.__name__, self.id)
72
+ )
73
+
74
+ primary.sort_key.attribute_name = "sk"
75
+ primary.sort_key.value = lambda: DynamoDBKey.build_key(("step", self.step_id))
76
+ self.indexes.add_primary(primary)
@@ -6,8 +6,8 @@ MIT License. See Project Root for the license information.
6
6
 
7
7
  import unittest
8
8
  import moto
9
-
10
- from tests.unit.dynamodb_tests.db_models.user_model import User
9
+ from typing import Optional
10
+ from tests.unit.dynamodb_tests.db_models.task import Task
11
11
  from boto3_assist.environment_services.environment_loader import EnvironmentLoader
12
12
  from boto3_assist.dynamodb.dynamodb import DynamoDB
13
13
  from tests.unit.common.db_test_helpers import DbTestHelper
@@ -38,12 +38,10 @@ class DbQueryTest(unittest.TestCase):
38
38
 
39
39
  def test_fail_if_exists(self):
40
40
 
41
- # create a few users
42
-
43
- user_id: str = "123456789"
41
+ task_id: str = "123456789"
44
42
 
45
- user = User(user_id)
46
- response = self.db.save(table_name=self.__table_name, item=user)
43
+ task = Task(task_id)
44
+ response = self.db.save(table_name=self.__table_name, item=task)
47
45
 
48
46
  self.assertEqual(response["ResponseMetadata"]["HTTPStatusCode"], 200)
49
47
 
@@ -52,10 +50,10 @@ class DbQueryTest(unittest.TestCase):
52
50
  Exception,
53
51
  self.db.save,
54
52
  table_name=self.__table_name,
55
- item=user,
53
+ item=task,
56
54
  fail_if_exists=True,
57
55
  )
58
56
 
59
57
  # this does not
60
- response = self.db.save(table_name=self.__table_name, item=user)
58
+ response = self.db.save(table_name=self.__table_name, item=task)
61
59
  self.assertEqual(response["ResponseMetadata"]["HTTPStatusCode"], 200)
@@ -0,0 +1,82 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import unittest
8
+ import moto
9
+ from typing import Optional
10
+ from tests.unit.dynamodb_tests.db_models.task import Task
11
+ from boto3_assist.environment_services.environment_loader import EnvironmentLoader
12
+ from boto3_assist.dynamodb.dynamodb import DynamoDB
13
+ from tests.unit.common.db_test_helpers import DbTestHelper
14
+
15
+
16
+ @moto.mock_aws
17
+ class DbQueryTest(unittest.TestCase):
18
+ "Serialization Tests"
19
+
20
+ def __init__(self, methodName="runTest"):
21
+ super().__init__(methodName)
22
+
23
+ ev: EnvironmentLoader = EnvironmentLoader()
24
+ # NOTE: you need to make sure the the env file below exists or you will get an error
25
+ ev.load_environment_file(file_name=".env.unittest")
26
+ self.__table_name = "mock_test_table"
27
+
28
+ self.db: DynamoDB = DynamoDB()
29
+
30
+ def setUp(self):
31
+ # load our test environment file to make sure we override any default AWS Environment Vars setup
32
+ # we don't want to accidentally connect to live environments
33
+ # https://docs.getmoto.org/en/latest/docs/getting_started.html
34
+
35
+ self.db: DynamoDB = self.db or DynamoDB()
36
+ DbTestHelper().helper_create_mock_table(self.__table_name, self.db.client)
37
+ print("Setup Complete")
38
+
39
+ def create_data_process_task(
40
+ self,
41
+ name: str,
42
+ step: str,
43
+ task_id: Optional[str] = None,
44
+ metadata: Optional[dict] = None,
45
+ ) -> Task:
46
+ task = Task()
47
+ if task_id:
48
+ task.id = task_id
49
+ task.step_id = Task.generate_uuid()
50
+ else:
51
+ task.step_id = task.id
52
+ task.name = name
53
+ task.step = step
54
+
55
+ task.metadata = metadata
56
+ response = self.db.save(
57
+ table_name=self.__table_name, item=task, fail_if_exists=True
58
+ )
59
+ assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
60
+ return task
61
+
62
+ def test_primary_key_query_sort(self):
63
+ task: Task = self.create_data_process_task(
64
+ name="test", step="test", task_id=None
65
+ )
66
+
67
+ # no create a bunch of children
68
+ for i in range(0, 10):
69
+ self.create_data_process_task(
70
+ name="test",
71
+ step=f"child-{i}",
72
+ task_id=task.id,
73
+ metadata={"child": f"i"},
74
+ )
75
+
76
+ query_model: Task = Task()
77
+ query_model.id = task.id
78
+ key = query_model.get_key("primary")
79
+ query_response = self.db.query(table_name=self.__table_name, key=key)
80
+
81
+ # primary task and 10 children == 11
82
+ assert len(query_response["Items"]) == 11
@@ -1 +0,0 @@
1
- __version__ = '0.22.0'
File without changes
File without changes
File without changes
File without changes
File without changes