From 15b71a57df421a4601ca070f4325533e57855385 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Mon, 7 Oct 2024 19:03:19 -0400 Subject: [PATCH 1/2] reclassify some test skips --- django_mongodb/features.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_mongodb/features.py b/django_mongodb/features.py index 335d49e3d..a2c058a80 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -495,6 +495,8 @@ def django_test_expected_failures(self): "delete.tests.DeletionTests.test_only_referenced_fields_selected", "lookup.tests.LookupTests.test_in_ignore_none", "lookup.tests.LookupTests.test_textfield_exact_null", + "migrations.test_commands.MigrateTests.test_migrate_syncdb_app_label", + "migrations.test_commands.MigrateTests.test_migrate_syncdb_deferred_sql_executed_with_schemaeditor", "queries.tests.ExistsSql.test_exists", "queries.tests.Queries6Tests.test_col_alias_quoted", "schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references", @@ -670,8 +672,6 @@ def django_test_expected_failures(self): }, "SchemaEditor doesn't log or collect queries.": { # https://github.com/mongodb-labs/django-mongodb/issues/141 - "migrations.test_commands.MigrateTests.test_migrate_syncdb_app_label", - "migrations.test_commands.MigrateTests.test_migrate_syncdb_deferred_sql_executed_with_schemaeditor", "migrations.test_commands.MigrateTests.test_sqlmigrate_backwards", "migrations.test_commands.MigrateTests.test_sqlmigrate_for_non_atomic_migration", "migrations.test_commands.MigrateTests.test_sqlmigrate_for_non_transactional_databases", From 2bd7459562d6dd231ed4992aa201e09792b7416c Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Mon, 7 Oct 2024 19:24:43 -0400 Subject: [PATCH 2/2] add support for sqlmigrate --- django_mongodb/features.py | 9 -------- django_mongodb/schema.py | 5 +++++ django_mongodb/utils.py | 46 ++++++++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/django_mongodb/features.py b/django_mongodb/features.py index a2c058a80..190f87b77 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -670,15 +670,6 @@ def django_test_expected_failures(self): "migrations.test_commands.MigrateTests.test_migrate_fake_split_initial", "migrations.test_executor.ExecutorTests.test_soft_apply", }, - "SchemaEditor doesn't log or collect queries.": { - # https://github.com/mongodb-labs/django-mongodb/issues/141 - "migrations.test_commands.MigrateTests.test_sqlmigrate_backwards", - "migrations.test_commands.MigrateTests.test_sqlmigrate_for_non_atomic_migration", - "migrations.test_commands.MigrateTests.test_sqlmigrate_for_non_transactional_databases", - "migrations.test_commands.MigrateTests.test_sqlmigrate_forwards", - "migrations.test_commands.MigrateTests.test_sqlmigrate_replaced_migration", - "migrations.test_commands.MigrateTests.test_sqlmigrate_squashed_migration", - }, } @cached_property diff --git a/django_mongodb/schema.py b/django_mongodb/schema.py index 3132ce20d..62655659c 100644 --- a/django_mongodb/schema.py +++ b/django_mongodb/schema.py @@ -1,13 +1,18 @@ from django.db.backends.base.schema import BaseDatabaseSchemaEditor from .query import wrap_database_errors +from .utils import OperationCollector class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): def get_collection(self, name): + if self.collect_sql: + return OperationCollector(self.collected_sql, collection=self.connection.database[name]) return self.connection.get_collection(name) def get_database(self): + if self.collect_sql: + return OperationCollector(self.collected_sql, db=self.connection.database) return self.connection.get_database() @wrap_database_errors diff --git a/django_mongodb/utils.py b/django_mongodb/utils.py index 10d745799..24bc5b23a 100644 --- a/django_mongodb/utils.py +++ b/django_mongodb/utils.py @@ -25,7 +25,28 @@ def check_django_compatability(): ) +def set_wrapped_methods(cls): + """Initialize the wrapped methods on cls.""" + if hasattr(cls, "logging_wrapper"): + for attr in cls.wrapped_methods: + setattr(cls, attr, cls.logging_wrapper(attr)) + del cls.logging_wrapper + return cls + + +@set_wrapped_methods class OperationDebugWrapper: + # The PyMongo database and collection methods that this backend uses. + wrapped_methods = { + "aggregate", + "create_collection", + "drop", + "insert_many", + "delete_many", + "rename", + "update_many", + } + def __init__(self, db, collection=None): self.collection = collection self.db = db @@ -79,13 +100,20 @@ def wrapper(self, *args, **kwargs): return wrapper - # These are the operations that this backend uses. - aggregate = logging_wrapper("aggregate") - create_collection = logging_wrapper("create_collection") - drop = logging_wrapper("drop") - insert_many = logging_wrapper("insert_many") - delete_many = logging_wrapper("delete_many") - rename = logging_wrapper("rename") - update_many = logging_wrapper("update_many") - del logging_wrapper +@set_wrapped_methods +class OperationCollector(OperationDebugWrapper): + def __init__(self, collected_sql=None, *, collection=None, db=None): + super().__init__(db, collection) + self.collected_sql = collected_sql + + def log(self, op, args, kwargs=None): + args = ", ".join(repr(arg) for arg in args) + operation = f"db.{self.collection_name}{op}({args})" + self.collected_sql.append(operation) + + def logging_wrapper(method): + def wrapper(self, *args, **kwargs): + self.log(method, args, kwargs) + + return wrapper