amsdal 0.3.0__cp312-cp312-macosx_10_13_universal2.whl → 0.3.2__cp312-cp312-macosx_10_13_universal2.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.

Potentially problematic release.


This version of amsdal might be problematic. Click here for more details.

Files changed (82) hide show
  1. amsdal/__about__.py +1 -1
  2. amsdal/cloud/__init__.cpython-312-darwin.so +0 -0
  3. amsdal/cloud/client.cpython-312-darwin.so +0 -0
  4. amsdal/cloud/constants.cpython-312-darwin.so +0 -0
  5. amsdal/cloud/enums.cpython-312-darwin.so +0 -0
  6. amsdal/cloud/models/__init__.cpython-312-darwin.so +0 -0
  7. amsdal/cloud/models/base.cpython-312-darwin.so +0 -0
  8. amsdal/cloud/services/__init__.cpython-312-darwin.so +0 -0
  9. amsdal/cloud/services/actions/__init__.cpython-312-darwin.so +0 -0
  10. amsdal/cloud/services/actions/add_allowlist_ip.cpython-312-darwin.so +0 -0
  11. amsdal/cloud/services/actions/add_basic_auth.cpython-312-darwin.so +0 -0
  12. amsdal/cloud/services/actions/add_dependency.cpython-312-darwin.so +0 -0
  13. amsdal/cloud/services/actions/add_secret.cpython-312-darwin.so +0 -0
  14. amsdal/cloud/services/actions/base.cpython-312-darwin.so +0 -0
  15. amsdal/cloud/services/actions/create_deploy.cpython-312-darwin.so +0 -0
  16. amsdal/cloud/services/actions/create_env.cpython-312-darwin.so +0 -0
  17. amsdal/cloud/services/actions/create_session.cpython-312-darwin.so +0 -0
  18. amsdal/cloud/services/actions/delete_allowlist_ip.cpython-312-darwin.so +0 -0
  19. amsdal/cloud/services/actions/delete_basic_auth.cpython-312-darwin.so +0 -0
  20. amsdal/cloud/services/actions/delete_dependency.cpython-312-darwin.so +0 -0
  21. amsdal/cloud/services/actions/delete_env.cpython-312-darwin.so +0 -0
  22. amsdal/cloud/services/actions/delete_secret.cpython-312-darwin.so +0 -0
  23. amsdal/cloud/services/actions/destroy_deploy.cpython-312-darwin.so +0 -0
  24. amsdal/cloud/services/actions/expose_db.cpython-312-darwin.so +0 -0
  25. amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-312-darwin.so +0 -0
  26. amsdal/cloud/services/actions/get_monitoring_info.cpython-312-darwin.so +0 -0
  27. amsdal/cloud/services/actions/list_dependencies.cpython-312-darwin.so +0 -0
  28. amsdal/cloud/services/actions/list_deploys.cpython-312-darwin.so +0 -0
  29. amsdal/cloud/services/actions/list_envs.cpython-312-darwin.so +0 -0
  30. amsdal/cloud/services/actions/list_secrets.cpython-312-darwin.so +0 -0
  31. amsdal/cloud/services/actions/manager.cpython-312-darwin.so +0 -0
  32. amsdal/cloud/services/actions/signup_action.cpython-312-darwin.so +0 -0
  33. amsdal/cloud/services/actions/update_deploy.cpython-312-darwin.so +0 -0
  34. amsdal/cloud/services/auth/__init__.cpython-312-darwin.so +0 -0
  35. amsdal/cloud/services/auth/base.cpython-312-darwin.so +0 -0
  36. amsdal/cloud/services/auth/credentials.cpython-312-darwin.so +0 -0
  37. amsdal/cloud/services/auth/manager.cpython-312-darwin.so +0 -0
  38. amsdal/cloud/services/auth/signup_service.cpython-312-darwin.so +0 -0
  39. amsdal/cloud/services/auth/token.cpython-312-darwin.so +0 -0
  40. amsdal/contrib/__init__.cpython-312-darwin.so +0 -0
  41. amsdal/contrib/auth/lifecycle/consumer.py +172 -0
  42. amsdal/contrib/auth/lifecycle/consumer.pyi +36 -0
  43. amsdal/contrib/auth/models/login_session/hooks/pre_init.py +14 -10
  44. amsdal/contrib/frontend_configs/lifecycle/consumer.py +45 -0
  45. amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +12 -0
  46. amsdal/fixtures/__init__.cpython-312-darwin.so +0 -0
  47. amsdal/fixtures/manager.cpython-312-darwin.so +0 -0
  48. amsdal/fixtures/manager.pyi +102 -0
  49. amsdal/manager.cpython-312-darwin.so +0 -0
  50. amsdal/manager.pyi +170 -1
  51. amsdal/migration/__init__.cpython-312-darwin.so +0 -0
  52. amsdal/migration/base_migration_schemas.cpython-312-darwin.so +0 -0
  53. amsdal/migration/data_classes.cpython-312-darwin.so +0 -0
  54. amsdal/migration/executors/__init__.cpython-312-darwin.so +0 -0
  55. amsdal/migration/executors/base.cpython-312-darwin.so +0 -0
  56. amsdal/migration/executors/base.pyi +12 -0
  57. amsdal/migration/executors/default_executor.cpython-312-darwin.so +0 -0
  58. amsdal/migration/executors/default_executor.pyi +88 -1
  59. amsdal/migration/executors/state_executor.cpython-312-darwin.so +0 -0
  60. amsdal/migration/file_migration_executor.cpython-312-darwin.so +0 -0
  61. amsdal/migration/file_migration_generator.cpython-312-darwin.so +0 -0
  62. amsdal/migration/file_migration_store.cpython-312-darwin.so +0 -0
  63. amsdal/migration/file_migration_writer.cpython-312-darwin.so +0 -0
  64. amsdal/migration/migrations.cpython-312-darwin.so +0 -0
  65. amsdal/migration/migrations_loader.cpython-312-darwin.so +0 -0
  66. amsdal/migration/schemas_loaders.cpython-312-darwin.so +0 -0
  67. amsdal/migration/utils.cpython-312-darwin.so +0 -0
  68. amsdal/mixins/__init__.cpython-312-darwin.so +0 -0
  69. amsdal/mixins/build_mixin.cpython-312-darwin.so +0 -0
  70. amsdal/mixins/class_versions_mixin.cpython-312-darwin.so +0 -0
  71. amsdal/mixins/class_versions_mixin.pyi +7 -1
  72. amsdal/schemas/manager.cpython-312-darwin.so +0 -0
  73. amsdal/services/__init__.cpython-312-darwin.so +0 -0
  74. amsdal/services/transaction_execution.cpython-312-darwin.so +0 -0
  75. amsdal/utils/rollback/__init__.py +195 -0
  76. amsdal/utils/rollback/__init__.pyi +16 -0
  77. {amsdal-0.3.0.dist-info → amsdal-0.3.2.dist-info}/METADATA +5 -3
  78. {amsdal-0.3.0.dist-info → amsdal-0.3.2.dist-info}/RECORD +82 -82
  79. {amsdal-0.3.0.dist-info → amsdal-0.3.2.dist-info}/LICENSE.txt +0 -0
  80. {amsdal-0.3.0.dist-info → amsdal-0.3.2.dist-info}/WHEEL +0 -0
  81. {amsdal-0.3.0.dist-info → amsdal-0.3.2.dist-info}/licenses/LICENSE.txt +0 -0
  82. {amsdal-0.3.0.dist-info → amsdal-0.3.2.dist-info}/top_level.txt +0 -0
amsdal/manager.pyi CHANGED
@@ -4,7 +4,7 @@ from amsdal.cloud.services.auth.manager import AuthManager as AuthManager
4
4
  from amsdal.cloud.services.auth.signup_service import SignupService as SignupService
5
5
  from amsdal.configs.main import settings as settings
6
6
  from amsdal.errors import AmsdalAuthenticationError as AmsdalAuthenticationError, AmsdalMissingCredentialsError as AmsdalMissingCredentialsError, AmsdalRuntimeError as AmsdalRuntimeError, AmsdalSignupError as AmsdalSignupError
7
- from amsdal.fixtures.manager import FixturesManager as FixturesManager
7
+ from amsdal.fixtures.manager import AsyncFixturesManager as AsyncFixturesManager, FixturesManager as FixturesManager
8
8
  from amsdal.mixins.build_mixin import BuildMixin as BuildMixin
9
9
  from amsdal.mixins.class_versions_mixin import ClassVersionsMixin as ClassVersionsMixin
10
10
  from amsdal.schemas.manager import SchemaManager as SchemaManager
@@ -181,3 +181,172 @@ class AmsdalManager(BuildMixin, ClassVersionsMixin, metaclass=Singleton):
181
181
  Returns:
182
182
  None
183
183
  """
184
+
185
+ class AsyncAmsdalManager(BuildMixin, ClassVersionsMixin, metaclass=Singleton):
186
+ """
187
+ Manages the AMSDAL framework components and operations.
188
+
189
+ This class is responsible for initializing, setting up, and managing various components
190
+ of the AMSDAL framework, including connections, data management, schema management,
191
+ and authentication. It also provides methods for building and tearing down the framework.
192
+ """
193
+ _class_manager: ClassManager
194
+ _config_manager: Incomplete
195
+ _config: Incomplete
196
+ _data_application: Incomplete
197
+ _is_setup: bool
198
+ __is_authenticated: bool
199
+ _schema_manager: Incomplete
200
+ _metadata_manager: Incomplete
201
+ _auth_manager: Incomplete
202
+ def __init__(self, *, raise_on_new_signup: bool = False) -> None:
203
+ """
204
+ Initializes all sub managers. Reads the configuration.
205
+
206
+ Returns:
207
+ None
208
+ """
209
+ @property
210
+ def is_setup(self) -> bool: ...
211
+ @property
212
+ def is_authenticated(self) -> bool:
213
+ """
214
+ Indicates if the AMSDAL license authentication process has been passed.
215
+
216
+ This property returns a boolean value indicating whether the AMSDAL license
217
+ authentication process has been successfully completed.
218
+
219
+ Returns:
220
+ bool: True if authenticated, False otherwise.
221
+ """
222
+ def pre_setup(self) -> None:
223
+ """
224
+ Initiates models root path and adds it into sys.path.
225
+
226
+ This method initializes the class manager and sets up the models root path
227
+ as specified in the settings. It ensures that the models root path is added
228
+ to the system path for proper module resolution.
229
+
230
+ Returns:
231
+ None
232
+ """
233
+ async def setup(self) -> None:
234
+ """
235
+ Initiates models root path and the connections.
236
+
237
+ This method sets up the AMSDAL framework by initializing the models root path and
238
+ establishing connections. It ensures that the setup process is only performed once.
239
+
240
+ Raises:
241
+ AmsdalRuntimeError: If the AMSDAL manager is already set up.
242
+
243
+ Returns:
244
+ None
245
+ """
246
+ async def post_setup(self) -> None:
247
+ """
248
+ Registers internal classes and prepares connections (creates internal tables).
249
+ """
250
+ def build(self, source_models_path: Path, source_transactions_path: Path, source_static_files_path: Path, source_fixtures_path: Path, source_migrations_path: Path) -> None:
251
+ """
252
+ Builds the necessary components for the Amsdal framework.
253
+
254
+ This method is used to build the necessary components for the Amsdal framework.
255
+ It takes five parameters which are all of type `Path`.
256
+ These parameters represent the paths to the directories where the corresponding components are located.
257
+
258
+ Args:
259
+ source_models_path (Path): Path to the directory where the source models are located.
260
+ source_transactions_path (Path): Path to the directory where the source transactions are located.
261
+ source_static_files_path (Path): Path to the directory where the source static files are located.
262
+ source_fixtures_path (Path): Path to the directory where the source fixtures are located.
263
+ source_migrations_path (Path): Path to the directory where the source migrations are located.
264
+
265
+ Returns:
266
+ None
267
+
268
+ The method performs the following build steps in order:
269
+ - Builds the models from the `source_models_path` by calling the `build_models` method.
270
+ - Builds the transactions from the `source_transactions_path` by calling the `build_transactions` method.
271
+ - Builds the static files from the `source_static_files_path` by calling the `build_static_files` method.
272
+ - Builds the fixtures from the `source_fixtures_path` by calling the `build_fixtures` method.
273
+
274
+ Note:
275
+ This method is part of the `AmsdalManager` class which includes mixins for `BuildMixin`
276
+ and `ClassVersionsMixin`. It is intended to be used in the Amsdal framework for managing
277
+ and building components.
278
+ """
279
+ def migrate(self) -> None:
280
+ """
281
+ DEPRECATED: Check changes in the models and apply them to the database.
282
+
283
+ This method is deprecated and should not be used. It checks for changes in the models
284
+ and applies them to the database. Use `amsdal.migration.file_migration_generator.FileMigrationGenerator`
285
+ instead.
286
+
287
+ Raises:
288
+ DeprecationWarning: Always raised to indicate that this method is deprecated.
289
+
290
+ Returns:
291
+ None
292
+ """
293
+ def _check_auth(self) -> None: ...
294
+ @property
295
+ def cloud_actions_manager(self) -> CloudActionsManager:
296
+ """
297
+ Provides access to the CloudActionsManager.
298
+
299
+ This property checks if the AMSDAL manager is authenticated and then returns
300
+ an instance of the CloudActionsManager.
301
+
302
+ Returns:
303
+ CloudActionsManager: An instance of the CloudActionsManager.
304
+
305
+ Raises:
306
+ AmsdalAuthenticationError: If the AMSDAL manager is not authenticated.
307
+ """
308
+ def authenticate(self) -> None:
309
+ """
310
+ Run AMSDAL license authentication process.
311
+
312
+ This method runs the AMSDAL license authentication process and sets the
313
+ authentication status accordingly.
314
+
315
+ Returns:
316
+ None
317
+ """
318
+ async def apply_fixtures(self) -> None:
319
+ """
320
+ Loads and applies fixtures defined in your application.
321
+
322
+ This method loads the fixtures from the specified path and applies them to the
323
+ AMSDAL framework. It uses the `FixturesManager` to manage the loading and application
324
+ of the fixtures.
325
+
326
+ Returns:
327
+ None
328
+ """
329
+ def init_classes(self) -> None:
330
+ """
331
+ Initializes and imports classes based on the schema manager's class schemas.
332
+
333
+ This method iterates over the class schemas provided by the schema manager and imports
334
+ the classes into the class manager, excluding those of type `SchemaTypes.TYPE`.
335
+
336
+ Returns:
337
+ None
338
+ """
339
+ async def teardown(self) -> None:
340
+ """
341
+ Clean up everything on the application exit.
342
+
343
+ This method performs a cleanup of all components managed by the AMSDAL framework
344
+ when the application exits. It disconnects and invalidates connections, clears caches,
345
+ and resets the setup status.
346
+
347
+ Raises:
348
+ AmsdalRuntimeError: If the AMSDAL manager is not set up.
349
+
350
+ Returns:
351
+ None
352
+ """
@@ -104,3 +104,15 @@ class BaseMigrationExecutor(ABC, metaclass=abc.ABCMeta):
104
104
  Returns:
105
105
  None
106
106
  """
107
+
108
+ class AsyncBaseMigrationExecutor(BaseMigrationExecutor, metaclass=abc.ABCMeta):
109
+ async def flush_buffer(self) -> None:
110
+ """
111
+ Flushes the migration buffer.
112
+
113
+ This method clears all entries from the main migration buffer, effectively
114
+ resetting it for future migration operations.
115
+
116
+ Returns:
117
+ None
118
+ """
@@ -3,7 +3,7 @@ from _typeshed import Incomplete
3
3
  from amsdal.errors import MigrationsError as MigrationsError
4
4
  from amsdal.migration.base_migration_schemas import BaseMigrationSchemas as BaseMigrationSchemas
5
5
  from amsdal.migration.data_classes import Action as Action
6
- from amsdal.migration.executors.base import BaseMigrationExecutor as BaseMigrationExecutor
6
+ from amsdal.migration.executors.base import AsyncBaseMigrationExecutor as AsyncBaseMigrationExecutor, BaseMigrationExecutor as BaseMigrationExecutor
7
7
  from amsdal_models.classes.model import Model
8
8
  from amsdal_utils.models.data_models.schema import ObjectSchema
9
9
  from amsdal_utils.models.enums import SchemaTypes, Versions
@@ -95,3 +95,90 @@ class DefaultMigrationExecutor(BaseMigrationExecutor):
95
95
  Returns:
96
96
  None
97
97
  """
98
+
99
+ class DefaultAsyncMigrationExecutor(AsyncBaseMigrationExecutor):
100
+ """
101
+ Default implementation of the BaseMigrationExecutor for handling database schema migrations.
102
+
103
+ This class provides concrete implementations for creating, updating, and deleting classes
104
+ in the database schema. It also manages schema migration buffers and processes object schemas.
105
+ """
106
+ schemas: Incomplete
107
+ _table_schemas_manager: Incomplete
108
+ def __init__(self, schemas: BaseMigrationSchemas) -> None: ...
109
+ def create_class(self, schemas: BaseMigrationSchemas, class_name: str, object_schema: ObjectSchema, schema_type: SchemaTypes) -> None:
110
+ """
111
+ Creates a class in the database schema.
112
+
113
+ This method registers a new class version if the schema type is `TYPE` and the class name
114
+ is not `BaseClasses.OBJECT`.
115
+ Otherwise, it buffers the class migration operation for further processing.
116
+
117
+ Args:
118
+ schemas (BaseMigrationSchemas): The migration schemas used for the operations.
119
+ class_name (str): The name of the class to be created.
120
+ object_schema (ObjectSchema): The schema of the object to be created.
121
+ schema_type (SchemaTypes): The type of the schema.
122
+
123
+ Returns:
124
+ None
125
+ """
126
+ def update_class(self, schemas: BaseMigrationSchemas, class_name: str, object_schema: ObjectSchema, schema_type: SchemaTypes) -> None:
127
+ """
128
+ Buffers the class update operation.
129
+
130
+ This method appends the given class name, object schema, and schema type to both
131
+ the non-flushable buffer and the main buffer for further processing.
132
+
133
+ Args:
134
+ schemas (BaseMigrationSchemas): The migration schemas used for the operations.
135
+ class_name (str): The name of the class to be updated.
136
+ object_schema (ObjectSchema): The current object schema.
137
+ schema_type (SchemaTypes): The type of the schema.
138
+
139
+ Returns:
140
+ None
141
+ """
142
+ async def delete_class(self, schemas: BaseMigrationSchemas, class_name: str, schema_type: SchemaTypes) -> None:
143
+ """
144
+ Deletes a class from the database schema.
145
+
146
+ This method removes the specified class from the database schema and unregisters it from the migration schemas.
147
+
148
+ Args:
149
+ schemas (BaseMigrationSchemas): The migration schemas used for the operations.
150
+ class_name (str): The name of the class to be deleted.
151
+ schema_type (SchemaTypes): The type of the schema.
152
+
153
+ Returns:
154
+ None
155
+ """
156
+ async def flush_buffer(self) -> None:
157
+ """
158
+ Flushes the migration buffer and processes the buffered classes.
159
+
160
+ This method registers the buffered classes in the migration schemas, compiles the buffered classes,
161
+ and processes each class in the buffer to create tables, save class objects, and migrate historical data.
162
+ Finally, it clears the main migration buffer.
163
+
164
+ Returns:
165
+ None
166
+ """
167
+ async def _check_class(self, schema_reference: glue.SchemaReference, object_schema: ObjectSchema, base_class: type[Model]) -> Action: ...
168
+ async def _save_class(self, schema_reference: glue.SchemaReference, base_class: type[Model], object_schema: ObjectSchema, action: Action) -> dict[str, Any]: ...
169
+ async def _save_object_class_meta(self, base_class: type[Model], object_schema: ObjectSchema, schema_type: SchemaTypes) -> None: ...
170
+ async def _create_table(self, object_schema: ObjectSchema, class_version: str | Versions, using: str | None = None) -> None: ...
171
+ async def _migrate_historical_data(self, schemas: BaseMigrationSchemas, class_name: str, prior_version: str, new_version: str) -> None: ...
172
+ def _clean_data(self, model_class: type[Model], data: dict[str, Any]) -> dict[str, Any]: ...
173
+ def _process_object_schema(self, object_schema: ObjectSchema, class_name: str, buffer: list[tuple[str, ObjectSchema, SchemaTypes]]) -> ObjectSchema: ...
174
+ async def register_schemas(self) -> None:
175
+ """
176
+ Registers the schemas in the table schemas manager.
177
+
178
+ This method retrieves the object schemas from the database, processes them, and registers
179
+ them in the table schemas manager. It handles both `ClassObject` and `ClassObjectMeta` schemas,
180
+ and ensures that all necessary references are loaded and processed.
181
+
182
+ Returns:
183
+ None
184
+ """
@@ -1,6 +1,12 @@
1
+ from amsdal_data.connections.historical.schema_version_manager import AsyncHistoricalSchemaVersionManager, HistoricalSchemaVersionManager
2
+
1
3
  class ClassVersionsMixin:
2
4
  """
3
5
  Mixin class to manage class versions and related table schemas.
4
6
  """
5
7
  @staticmethod
6
- def register_internal_classes() -> None: ...
8
+ def _register_internal_classes(schema_version_manager: HistoricalSchemaVersionManager | AsyncHistoricalSchemaVersionManager) -> None: ...
9
+ @classmethod
10
+ def register_internal_classes(cls) -> None: ...
11
+ @classmethod
12
+ def aregister_internal_classes(cls) -> None: ...
@@ -1,5 +1,7 @@
1
1
  import amsdal_glue as glue
2
+ from amsdal_data.application import AsyncDataApplication
2
3
  from amsdal_data.application import DataApplication
4
+ from amsdal_data.transactions.decorators import async_transaction
3
5
  from amsdal_data.transactions.decorators import transaction
4
6
  from amsdal_data.transactions.errors import AmsdalTransactionError
5
7
  from amsdal_models.classes.manager import ClassManager
@@ -198,3 +200,196 @@ def rollback_transaction(transaction_id: str) -> None:
198
200
 
199
201
  updated_at = metadatas_to_revert[0].data['updated_at']
200
202
  rollback_to_timestamp(updated_at)
203
+
204
+
205
+ @async_transaction
206
+ async def async_rollback_to_timestamp(timestamp: float) -> None:
207
+ """
208
+ Rollback the data to the given timestamp
209
+ Args:
210
+ timestamp (float): The timestamp to rollback the data to.
211
+ Returns:
212
+ None
213
+ """
214
+ class_manager = ClassManager()
215
+
216
+ lakehouse_connection = await (
217
+ AsyncDataApplication()._application.lakehouse_connection_manager.get_connection_pool('Company').get_connection()
218
+ )
219
+
220
+ metadatas_to_delete = await lakehouse_connection.query(
221
+ query=glue.QueryStatement(
222
+ table=glue.SchemaReference(name='Metadata', version=glue.Version.LATEST),
223
+ where=glue.Conditions(
224
+ glue.Condition(
225
+ field=glue.FieldReference(field=glue.Field(name='updated_at'), table_name='Metadata'),
226
+ lookup=glue.FieldLookup.GT,
227
+ value=glue.Value(timestamp),
228
+ ),
229
+ glue.Condition(
230
+ field=glue.FieldReference(field=glue.Field(name='prior_version'), table_name='Metadata'),
231
+ lookup=glue.FieldLookup.ISNULL,
232
+ value=glue.Value(True),
233
+ ),
234
+ ),
235
+ )
236
+ )
237
+
238
+ ids_to_ignore = [m.data['object_id'] for m in metadatas_to_delete]
239
+
240
+ metadatas_to_revert = await lakehouse_connection.query(
241
+ query=glue.QueryStatement(
242
+ table=glue.SchemaReference(name='Metadata', version=glue.Version.LATEST),
243
+ where=glue.Conditions(
244
+ glue.Condition(
245
+ field=glue.FieldReference(field=glue.Field(name='updated_at'), table_name='Metadata'),
246
+ lookup=glue.FieldLookup.GT,
247
+ value=glue.Value(timestamp),
248
+ ),
249
+ glue.Condition(
250
+ field=glue.FieldReference(field=glue.Field(name='prior_version'), table_name='Metadata'),
251
+ lookup=glue.FieldLookup.ISNULL,
252
+ value=glue.Value(False),
253
+ ),
254
+ ),
255
+ )
256
+ )
257
+
258
+ transaction_ids = {m.data['transaction']['ref']['object_id'] for m in metadatas_to_revert}
259
+ transaction_ids.update({m.data['transaction']['ref']['object_id'] for m in metadatas_to_delete})
260
+ ids_to_revert = [
261
+ (m.data['object_id'], m.data['class_schema_reference']['ref']['object_id'])
262
+ for m in metadatas_to_revert
263
+ if m.data['object_id'] not in ids_to_ignore
264
+ ]
265
+
266
+ if transaction_ids:
267
+ _conditions = []
268
+ for transaction_id in transaction_ids:
269
+ _parent_field = glue.Field(
270
+ name='transaction',
271
+ child=glue.Field(
272
+ name='ref',
273
+ child=glue.Field(name='object_id'),
274
+ ),
275
+ )
276
+ _parent_field.child.parent = _parent_field # type: ignore[union-attr]
277
+ _parent_field.child.child.parent = _parent_field.child # type: ignore[union-attr]
278
+ _conditions.append(
279
+ glue.Condition(
280
+ field=glue.FieldReference(field=_parent_field, table_name='Metadata'),
281
+ lookup=glue.FieldLookup.EQ,
282
+ value=glue.Value(transaction_id),
283
+ )
284
+ )
285
+
286
+ conflict_metadata = await lakehouse_connection.query(
287
+ query=glue.QueryStatement(
288
+ table=glue.SchemaReference(name='Metadata', version=glue.Version.LATEST),
289
+ where=glue.Conditions(
290
+ glue.Condition(
291
+ field=glue.FieldReference(field=glue.Field(name='updated_at'), table_name='Metadata'),
292
+ lookup=glue.FieldLookup.LTE,
293
+ value=glue.Value(timestamp),
294
+ ),
295
+ glue.Conditions(*_conditions, connector=glue.FilterConnector.OR),
296
+ ),
297
+ )
298
+ )
299
+ if conflict_metadata:
300
+ msg = 'Cannot rollback to this timestamp because it will conflict with other transactions'
301
+ raise AmsdalTransactionError(msg)
302
+
303
+ for m in metadatas_to_delete:
304
+ class_name = m.data['class_schema_reference']['ref']['object_id']
305
+ schema_type = class_manager.resolve_schema_type(class_name)
306
+
307
+ model_class = class_manager.import_model_class(class_name, schema_type)
308
+ obj = await (
309
+ model_class.objects.filter(_address__object_id=m.data['object_id'])
310
+ .using(LAKEHOUSE_DB_ALIAS)
311
+ .latest()
312
+ .first()
313
+ .aexecute()
314
+ )
315
+
316
+ if obj and not (await obj.aget_metadata()).is_deleted:
317
+ await obj.adelete()
318
+
319
+ for object_id, class_name in ids_to_revert:
320
+ schema_type = class_manager.resolve_schema_type(class_name)
321
+ model_class = class_manager.import_model_class(class_name, schema_type)
322
+
323
+ obj = await (
324
+ model_class.objects.filter(_address__object_id=object_id)
325
+ .using(LAKEHOUSE_DB_ALIAS)
326
+ .latest()
327
+ .first()
328
+ .aexecute()
329
+ )
330
+ old_obj = await (
331
+ model_class.objects.filter(_address__object_id=object_id, _metadata__updated_at__lte=timestamp)
332
+ .using(LAKEHOUSE_DB_ALIAS)
333
+ .order_by('-_metadata__updated_at')
334
+ .first()
335
+ .aexecute()
336
+ )
337
+
338
+ if obj and old_obj:
339
+ for field, value in old_obj.model_dump().items():
340
+ setattr(obj, field, value)
341
+
342
+ await obj.asave()
343
+
344
+ if (await old_obj.aget_metadata()).is_deleted:
345
+ await obj.adelete()
346
+
347
+
348
+ @async_transaction
349
+ async def async_rollback_transaction(transaction_id: str) -> None:
350
+ """
351
+ Rollback the data to the point in time before the given transaction
352
+ Args:
353
+ transaction_id (str): The transaction ID to rollback the data to.
354
+ Returns:
355
+ None
356
+ """
357
+ lakehouse_connection = await (
358
+ AsyncDataApplication()._application.lakehouse_connection_manager.get_connection_pool('Company').get_connection()
359
+ )
360
+
361
+ _parent_field = glue.Field(
362
+ name='transaction',
363
+ child=glue.Field(
364
+ name='ref',
365
+ child=glue.Field(name='object_id'),
366
+ ),
367
+ )
368
+ _parent_field.child.parent = _parent_field # type: ignore[union-attr]
369
+ _parent_field.child.child.parent = _parent_field.child # type: ignore[union-attr]
370
+
371
+ metadatas_to_revert = await lakehouse_connection.query(
372
+ query=glue.QueryStatement(
373
+ table=glue.SchemaReference(name='Metadata', version=glue.Version.LATEST),
374
+ where=glue.Conditions(
375
+ glue.Condition(
376
+ field=glue.FieldReference(field=_parent_field, table_name='Metadata'),
377
+ lookup=glue.FieldLookup.EQ,
378
+ value=glue.Value(transaction_id),
379
+ )
380
+ ),
381
+ order_by=[
382
+ glue.OrderByQuery(
383
+ field=glue.FieldReference(field=glue.Field(name='updated_at'), table_name='Metadata'),
384
+ direction=glue.OrderDirection.DESC,
385
+ )
386
+ ],
387
+ )
388
+ )
389
+
390
+ if not metadatas_to_revert:
391
+ msg = 'Transaction not found'
392
+ raise AmsdalTransactionError(msg)
393
+
394
+ updated_at = metadatas_to_revert[0].data['updated_at']
395
+ await async_rollback_to_timestamp(updated_at) # type: ignore[misc]
@@ -14,3 +14,19 @@ def rollback_transaction(transaction_id: str) -> None:
14
14
  Returns:
15
15
  None
16
16
  """
17
+ async def async_rollback_to_timestamp(timestamp: float) -> None:
18
+ """
19
+ Rollback the data to the given timestamp
20
+ Args:
21
+ timestamp (float): The timestamp to rollback the data to.
22
+ Returns:
23
+ None
24
+ """
25
+ async def async_rollback_transaction(transaction_id: str) -> None:
26
+ """
27
+ Rollback the data to the point in time before the given transaction
28
+ Args:
29
+ transaction_id (str): The transaction ID to rollback the data to.
30
+ Returns:
31
+ None
32
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amsdal
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: AMSDAL
5
5
  License: AMSDAL End User License Agreement
6
6
 
@@ -133,13 +133,15 @@ Requires-Dist: amsdal_utils==0.3.*
133
133
  Requires-Dist: amsdal_data[postgres-binary]==0.3.*
134
134
  Requires-Dist: amsdal_models==0.3.*
135
135
  Provides-Extra: cli
136
- Requires-Dist: amsdal-cli==0.2.*; extra == "cli"
136
+ Requires-Dist: amsdal-cli==0.3.*; extra == "cli"
137
137
  Provides-Extra: server
138
- Requires-Dist: amsdal-server==0.2.*; extra == "server"
138
+ Requires-Dist: amsdal-server==0.3.*; extra == "server"
139
139
  Provides-Extra: factory
140
140
  Requires-Dist: polyfactory==2.*; extra == "factory"
141
141
  Provides-Extra: celery
142
142
  Requires-Dist: celery==5.4.0; extra == "celery"
143
+ Provides-Extra: aiosqlite
144
+ Requires-Dist: aiosqlite>=0.20.0; extra == "aiosqlite"
143
145
 
144
146
  # AMSDAL
145
147