Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use dynaminc imports to not require unnecessary deps #22

Merged
merged 2 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
key: venv-${{ hashFiles('poetry.lock') }}
- name: Install the project dependencies
run: poetry install
- name: Install specific test mysql dependencies
run: poetry add mysqlclient
- name: Run lint
run: poetry run ruff --output-format=github .
- name: Run unit tests
Expand All @@ -33,6 +35,15 @@ jobs:
strategy:
matrix:
dialect: [ mysql, postgresql, sqlite, mssql ]
include:
- dialect: mysql
deps: [mysqlclient]
- dialect: postgresql
deps: [psycopg2]
- dialect: sqlite
deps: ''
- dialect: mssql
deps: [mssql-django, pyodbc]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -53,6 +64,9 @@ jobs:
key: venv-${{ hashFiles('poetry.lock') }}
- name: Install the project dependencies
run: poetry install
- name: Install specific dialect dependencies
if: ${{ matrix.deps != '' }}
run: poetry add ${{ join(matrix.deps, ' ') }}
- name: Install atlas
uses: ariga/setup-atlas@master
- name: Run migrate diff
Expand Down
116 changes: 67 additions & 49 deletions atlas_provider_django/management/commands/atlas-provider-django.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@
from django.core.management.commands.sqlmigrate import Command as SqlMigrateCommand
from django.db.backends.sqlite3.base import DatabaseWrapper as Sqlite3DatabaseWrapper
from django.db.backends.sqlite3.schema import DatabaseSchemaEditor as SqliteSchemaEditor
from django.db.backends.postgresql.schema import DatabaseSchemaEditor as PGDatabaseSchemaEditor
from django.db.backends.postgresql.base import DatabaseWrapper as PGDatabaseWrapper
from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper
from django.db.backends.mysql.schema import DatabaseSchemaEditor as MySQLDatabaseSchemaEditor
from django.db.backends.mysql.features import DatabaseFeatures as MySQLDatabaseFeatures

from atlas_provider_django.management.commands.migrations import get_migrations

Expand Down Expand Up @@ -46,50 +41,6 @@ def __exit__(self, exc_type, exc_value, traceback):
return super(SqliteSchemaEditor, self).__exit__(exc_type, exc_value, traceback)


class MockPGDatabaseSchemaEditor(PGDatabaseSchemaEditor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def execute(self, sql, params=()):
return super(PGDatabaseSchemaEditor, self).execute(sql, params)


class MockMySQLDatabaseSchemaEditor(MySQLDatabaseSchemaEditor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Override the method of MySQLDatabaseSchemaEditor since it checks the storage engine.
# We assume that the storage engine is InnoDB.
def _field_should_be_indexed(self, model, field):
if not super(MySQLDatabaseSchemaEditor, self)._field_should_be_indexed(model, field):
return False
if field.get_internal_type() == "ForeignKey" and field.db_constraint:
return False
return not self._is_limited_data_type(field)

def _supports_limited_data_type_defaults(self):
return True


class MockMySQLDatabaseFeatures(MySQLDatabaseFeatures):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def has_native_uuid_field(self):
return False

def _mysql_storage_engine(self):
return "InnoDB"


class MockMariaDBDatabaseFeatures(MySQLDatabaseFeatures):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def has_native_uuid_field(self):
return True


# Returns the database connection wrapper for the given dialect.
# Mocks some methods in order to get the sql statements without db connection.
def get_connection_by_dialect(dialect):
Expand All @@ -101,17 +52,84 @@ def get_connection_by_dialect(dialect):
}, "sqlite3")
conn.SchemaEditorClass = MockSqliteSchemaEditor
case Dialect.postgresql:
from django.db.backends.postgresql.base import DatabaseWrapper as PGDatabaseWrapper
from django.db.backends.postgresql.schema import DatabaseSchemaEditor as PGDatabaseSchemaEditor

class MockPGDatabaseSchemaEditor(PGDatabaseSchemaEditor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def execute(self, sql, params=()):
return super(PGDatabaseSchemaEditor, self).execute(sql, params)

conn = PGDatabaseWrapper({
"ENGINE": "django.db.backends.postgresql",
}, "postgresql")
conn.SchemaEditorClass = MockPGDatabaseSchemaEditor
case Dialect.mysql:
from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper
from django.db.backends.mysql.schema import DatabaseSchemaEditor as MySQLDatabaseSchemaEditor
from django.db.backends.mysql.features import DatabaseFeatures as MySQLDatabaseFeatures

class MockMySQLDatabaseSchemaEditor(MySQLDatabaseSchemaEditor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Override the method of MySQLDatabaseSchemaEditor since it checks the storage engine.
# We assume that the storage engine is InnoDB.
def _field_should_be_indexed(self, model, field):
if not super(MySQLDatabaseSchemaEditor, self)._field_should_be_indexed(model, field):
return False
if field.get_internal_type() == "ForeignKey" and field.db_constraint:
return False
return not self._is_limited_data_type(field)

def _supports_limited_data_type_defaults(self):
return True

class MockMySQLDatabaseFeatures(MySQLDatabaseFeatures):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def has_native_uuid_field(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is besically checking if the mysql driver is 8 or lower, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true, but In order to determine the mysql version I need to call the DB (what I cannot do). so I mock this method

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should think about maybe adding the target version to the query string / arguments in addition to the dialect

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats good point, but lets discuss is in seperate PR

return False

def _mysql_storage_engine(self):
return "InnoDB"

conn = MySQLDatabaseWrapper({
"ENGINE": "django.db.backends.mysql",
}, "mysql")
conn.SchemaEditorClass = MockMySQLDatabaseSchemaEditor
conn.features = MockMySQLDatabaseFeatures(conn)
case Dialect.mariadb:
from django.db.backends.mysql.base import DatabaseWrapper as MySQLDatabaseWrapper
from django.db.backends.mysql.schema import DatabaseSchemaEditor as MySQLDatabaseSchemaEditor
from django.db.backends.mysql.features import DatabaseFeatures as MySQLDatabaseFeatures

class MockMySQLDatabaseSchemaEditor(MySQLDatabaseSchemaEditor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Override the method of MySQLDatabaseSchemaEditor since it checks the storage engine.
# We assume that the storage engine is InnoDB.
def _field_should_be_indexed(self, model, field):
if not super(MySQLDatabaseSchemaEditor, self)._field_should_be_indexed(model, field):
return False
if field.get_internal_type() == "ForeignKey" and field.db_constraint:
return False
return not self._is_limited_data_type(field)

def _supports_limited_data_type_defaults(self):
return True

class MockMariaDBDatabaseFeatures(MySQLDatabaseFeatures):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def has_native_uuid_field(self):
return True

conn = MySQLDatabaseWrapper({
"ENGINE": "django.db.backends.mysql",
}, "mysql")
Expand Down
Loading
Loading