Skip to content

Commit

Permalink
Merge pull request #60 from cicekhayri/migration-command-enchane
Browse files Browse the repository at this point in the history
Migration command enchane
  • Loading branch information
cicekhayri committed Jan 13, 2024
2 parents 0257c03 + 68a92b9 commit d45e406
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 32 deletions.
11 changes: 9 additions & 2 deletions inspira/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from inspira.cli.generate_repository_file import generate_repository_file
from inspira.cli.generate_service_file import generate_service_file
from inspira.migrations.migrations import create_migrations, run_migrations
from inspira.migrations.utils import get_all_module_names

DATABASE_TYPES = ["postgres", "mysql", "sqlite", "mssql"]

Expand Down Expand Up @@ -71,9 +72,15 @@ def createmigrations(module_name, empty):


@cli.command()
@click.argument("module_name")
@click.argument("module_name", required=False)
def migrate(module_name):
run_migrations(module_name)
if module_name:
module_names = [module_name]
else:
module_names = get_all_module_names()

for module_name in module_names:
run_migrations(module_name)


@cli.command()
Expand Down
11 changes: 5 additions & 6 deletions inspira/cli/create_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@

from inspira.cli.create_app import generate_project
from inspira.cli.init_file import create_init_file
from inspira.constants import SRC_DIRECTORY
from inspira.utils import singularize


def create_src_directory():
src_directory = "src"
app_file_path = "main.py"

if not os.path.exists(app_file_path):
generate_project()
if not os.path.exists(src_directory):
os.makedirs(src_directory)
create_init_file(src_directory)
if not os.path.exists(SRC_DIRECTORY):
os.makedirs(SRC_DIRECTORY)
create_init_file(SRC_DIRECTORY)


def create_test_directory(controller_directory):
Expand All @@ -26,8 +26,7 @@ def create_test_directory(controller_directory):


def create_controller_file(name, is_websocket):
src_directory = "src"
controller_directory = os.path.join(src_directory, name)
controller_directory = os.path.join(SRC_DIRECTORY, name)
singularize_name = singularize(name.lower())

os.makedirs(controller_directory)
Expand Down
5 changes: 2 additions & 3 deletions inspira/cli/generate_model_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

import click

from inspira.constants import SRC_DIRECTORY
from inspira.utils import pluralize_word, singularize


def generate_model_file(module_name):
base_path = "src"
# Specify the directory path
model_directory = os.path.join(base_path, module_name.lower())
model_directory = os.path.join(SRC_DIRECTORY, module_name.lower())

template_path = os.path.join(
os.path.dirname(__file__), "templates", "model_template.txt"
Expand Down
9 changes: 5 additions & 4 deletions inspira/cli/generate_repository_file.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import os
import re

from inspira.constants import SRC_DIRECTORY
from inspira.utils import pluralize_word, singularize


def generate_repository_file(module_name):
base_path = "src"
# Specify the directory path
model_directory = os.path.join(base_path, module_name.lower())
model_directory = os.path.join(SRC_DIRECTORY, module_name.lower())

template_path = os.path.join(
os.path.dirname(__file__), "templates", "repository_template.txt"
Expand All @@ -33,7 +32,9 @@ def generate_repository_file(module_name):

def add_repository_dependency_to_service(module_name):
controller_file_path = os.path.join(
"src", module_name.lower(), f"{singularize(module_name.lower())}_service.py"
SRC_DIRECTORY,
module_name.lower(),
f"{singularize(module_name.lower())}_service.py",
)
module_name_capitalized = singularize(module_name.lower()).capitalize()
singularized_module_name = singularize(module_name.lower())
Expand Down
9 changes: 5 additions & 4 deletions inspira/cli/generate_service_file.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import os
import re

from inspira.constants import SRC_DIRECTORY
from inspira.utils import pluralize_word, singularize


def generate_service_file(module_name):
base_path = "src"
# Specify the directory path
model_directory = os.path.join(base_path, module_name.lower())
model_directory = os.path.join(SRC_DIRECTORY, module_name.lower())

template_path = os.path.join(
os.path.dirname(__file__), "templates", "service_template.txt"
Expand All @@ -33,7 +32,9 @@ def generate_service_file(module_name):

def add_service_dependency_to_controller(module_name):
controller_file_path = os.path.join(
"src", module_name.lower(), f"{singularize(module_name.lower())}_controller.py"
SRC_DIRECTORY,
module_name.lower(),
f"{singularize(module_name.lower())}_controller.py",
)
module_name_capitalized = singularize(module_name.lower()).capitalize()
singularized_module_name = singularize(module_name.lower())
Expand Down
2 changes: 2 additions & 0 deletions inspira/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@
WEBSOCKET_RECEIVE_TYPE = "websocket.receive"
WEBSOCKET_DISCONNECT_TYPE = "websocket.disconnect"
WEBSOCKET_TYPE = "websocket"

SRC_DIRECTORY = "src"
3 changes: 2 additions & 1 deletion inspira/inspira.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Any, Callable, Dict, List

from inspira.config import Config
from inspira.constants import SRC_DIRECTORY
from inspira.enums import HttpMethod
from inspira.globals import set_global_app
from inspira.helpers.error_handlers import (
Expand Down Expand Up @@ -52,7 +53,7 @@ def add_route(self, path: str, method: HttpMethod, handler: Callable) -> None:

def discover_controllers(self) -> None:
current_dir = os.getcwd()
src_dir = os.path.join(current_dir, "src")
src_dir = os.path.join(current_dir, SRC_DIRECTORY)

for root, _, files in os.walk(src_dir):
for file_name in files:
Expand Down
5 changes: 5 additions & 0 deletions inspira/migrations/migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ def create_migrations(entity_name, empty_migration_file):
generate_empty_sql_file(entity_name, empty_migration_file)

module = load_model_file(entity_name)

if module is None:
log.error(f"Module '{entity_name}' not found.")
return

model = getattr(module, module.__name__)

if not get_existing_columns(entity_name):
Expand Down
33 changes: 29 additions & 4 deletions inspira/migrations/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
from sqlalchemy import String, Integer

from inspira.cli.create_controller import create_init_file
from inspira.constants import SRC_DIRECTORY
from inspira.logging import log
from inspira.utils import singularize


def get_or_create_migration_directory(name: str):
src_directory = "src"
controller_directory = os.path.join(src_directory, name)
controller_directory = os.path.join(SRC_DIRECTORY, name)
migration_directory = os.path.join(controller_directory, "migrations")

if not os.path.exists(migration_directory):
log.error(f"Module '{name}' doesn't exists.")
return

os.makedirs(migration_directory, exist_ok=True)

create_init_file(migration_directory)
Expand All @@ -20,12 +25,19 @@ def get_or_create_migration_directory(name: str):


def load_model_file(entity_name):
module_path = os.path.join("src", entity_name.replace(".", "/" + entity_name))
module_path = os.path.join(
SRC_DIRECTORY, entity_name.replace(".", "/" + entity_name)
)
model_file_path = os.path.join(module_path, f"{singularize(entity_name)}.py")
model_name = singularize(entity_name).capitalize()
spec = importlib.util.spec_from_file_location(model_name, model_file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

try:
spec.loader.exec_module(module)
except FileNotFoundError:
return None

return module


Expand Down Expand Up @@ -178,3 +190,16 @@ def get_columns_from_model(model_class):

def get_indexes_from_model(model_class):
return model_class.__table__.indexes


def get_all_module_names():
module_names = []

for dir_entry in os.listdir(SRC_DIRECTORY):
full_path = os.path.join(SRC_DIRECTORY, dir_entry)
if os.path.isdir(full_path):
migrations_dir = os.path.join(full_path, "migrations")
if os.path.exists(migrations_dir):
module_names.append(dir_entry)

return module_names
18 changes: 17 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from inspira import Inspira
from inspira.config import Config
from inspira.constants import SRC_DIRECTORY
from inspira.requests import Request
from inspira.testclient import TestClient

Expand Down Expand Up @@ -48,7 +49,7 @@ def teardown_app_file():
@pytest.fixture
def teardown_src_directory():
yield
shutil.rmtree("src")
shutil.rmtree(SRC_DIRECTORY)


@pytest.fixture
Expand Down Expand Up @@ -145,3 +146,18 @@ def setup_teardown_db_session():
initialize_database(engine)
yield db_session
db_session.rollback()


@pytest.fixture
def setup_test_environment():
os.makedirs(SRC_DIRECTORY)

dirs_to_simulate = ["module1", "module2", "module3"]

for module in dirs_to_simulate:
module_dir = os.path.join(SRC_DIRECTORY, module)
os.makedirs(module_dir)
migrations_dir = os.path.join(module_dir, "migrations")
os.makedirs(migrations_dir)

yield SRC_DIRECTORY
63 changes: 56 additions & 7 deletions tests/test_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from sqlalchemy import Column, Integer, String, inspect

from inspira.constants import SRC_DIRECTORY
from inspira.migrations.migrations import (
execute_sql_file,
engine,
Expand All @@ -23,17 +24,37 @@
load_model_file,
generate_column_sql,
get_latest_migration_number,
get_all_module_names,
)


def test_get_or_create_migration_directory(teardown_src_directory):
controller_name = "test_controller"
result = get_or_create_migration_directory(controller_name)
expected_directory = os.path.join("src", controller_name, "migrations")
assert result == expected_directory
def test_get_or_create_migration_directory(
setup_test_environment, teardown_src_directory
):
controller_name = "module1"
controller_directory = os.path.join(SRC_DIRECTORY, controller_name)
migration_directory = os.path.join(controller_directory, "migrations")
with patch("inspira.logging.log.error") as log_error_mock:
result = get_or_create_migration_directory(controller_name)

assert result == migration_directory
assert os.path.exists(result)
assert os.path.isdir(result)
assert os.path.exists(os.path.join(result, "__init__.py"))
log_error_mock.assert_not_called()


def test_get_or_create_migration_directory_missing_module(
setup_test_environment, teardown_src_directory
):
controller_name = "Module"

with patch("inspira.logging.log.error") as log_error_mock:
result = get_or_create_migration_directory(controller_name)

assert result is None
assert not os.path.exists(result) if result else True
assert log_error_mock.called


@patch("inspira.migrations.utils.generate_migration_file")
Expand Down Expand Up @@ -142,7 +163,9 @@ def test_load_model_file(

result = load_model_file(entity_name)

mock_join.assert_any_call("src", entity_name.replace(".", "/" + entity_name))
mock_join.assert_any_call(
SRC_DIRECTORY, entity_name.replace(".", "/" + entity_name)
)
mock_join.assert_any_call(
mock_join.return_value, f"{mock_singularize.return_value}.py"
)
Expand Down Expand Up @@ -216,9 +239,35 @@ def test_insert_migration(setup_teardown_db_session):
assert result.migration_name == migration_name


def test_get_existing_indexes(add_index_users):
def test_get_existing_indexes(
setup_test_environment, teardown_src_directory, add_index_users
):
execute_sql_file(add_index_users)
indexes = get_existing_indexes("users")

assert len(indexes) == 1
assert "ix_users_name" in indexes


def test_get_all_module_names_with_migration_folder(
setup_test_environment, teardown_src_directory
):
expected_module_names = ["module1", "module2", "module3"]

module_names = get_all_module_names()

assert set(module_names) == set(expected_module_names)


def test_get_all_module_names_without_migrations(
setup_test_environment, teardown_src_directory
):
module3_migrations_dir = os.path.join(
setup_test_environment, "module3", "migrations"
)
os.rmdir(module3_migrations_dir)

expected_module_names = ["module1", "module2"]
module_names = get_all_module_names()

assert set(module_names) == set(expected_module_names)

0 comments on commit d45e406

Please sign in to comment.