Skip to content

Commit

Permalink
docs/tests: Add documentation and tests for migration interfaces and …
Browse files Browse the repository at this point in the history
…implementations

This commit adds documentation and tests for the migration interfaces and their implementations. The documentation explains the purpose and usage of each interface, and the tests verify that the implementations behave as expected. This will help developers understand the code and ensure that changes to the code do not inadvertently introduce bugs.
  • Loading branch information
InspiredImpact committed May 1, 2023
1 parent bb541ae commit 8dbef97
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 15 deletions.
8 changes: 4 additions & 4 deletions mongorunway/kernel/application/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ def remove_pending_migration(self, migration_version: int, /) -> None:
@requires_pending_migration
def upgrade_once(self) -> int:
upgrading_version = get_upgrading_version(self)
nowait_migration = self.pending.pop_nowait_migration()
nowait_migration = self.pending.pop_waiting_migration()

_LOGGER.info(
"%s: upgrading nowait migration (#%s -> #%s)...",
Expand All @@ -331,7 +331,7 @@ def upgrade_once(self) -> int:
@requires_applied_migration
def downgrade_once(self) -> int:
downgrading_version = get_downgrading_version(self)
nowait_migration = self.applied.pop_nowait_migration()
nowait_migration = self.applied.pop_waiting_migration()

_LOGGER.info(
"%s: downgrading nowait migration (#%s -> #%s)...",
Expand All @@ -356,7 +356,7 @@ def upgrade_while(self, predicate: typing.Callable[[Migration], bool], /) -> int

while self.pending.has_migrations():
upgrading_version = get_upgrading_version(self)
migration = self.pending.pop_nowait_migration()
migration = self.pending.pop_waiting_migration()

if not predicate(migration):
break
Expand Down Expand Up @@ -386,7 +386,7 @@ def downgrade_while(self, predicate: typing.Callable[[Migration], bool], /) -> i

while self.applied.has_migrations():
downgrading_version = get_downgrading_version(self)
migration = self.applied.pop_nowait_migration()
migration = self.applied.pop_waiting_migration()

_LOGGER.info(
"%s: downgrading nowait migration (#%s -> #%s)...",
Expand Down
137 changes: 131 additions & 6 deletions mongorunway/kernel/domain/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,65 +16,190 @@


class Migration(abc.ABC):
"""Interface for defining database migrations.
Notes
-----
This interface defines the methods and properties required to define a database
migration. A migration is a set of instructions for modifying a database schema
to support new features or fix issues.
Each migration consists of a version number, a name, and one or more commands
that describe how to upgrade or downgrade the schema.
"""

__slots__: typing.Sequence[str] = ()

@property
@abc.abstractmethod
def name(self):
def name(self) -> str:
"""Returns the name of the migration.
Returns
-------
str
The name of the migration.
"""
...

@property
@abc.abstractmethod
def version(self):
def version(self) -> int:
"""Get the version of the migration.
Returns
-------
int
The version of the migration.
"""
...

@property
@abc.abstractmethod
def checksum(self):
def checksum(self) -> str:
"""Get the checksum of the migration.
Returns
-------
str
The checksum of the migration.
"""
...

@property
@abc.abstractmethod
def description(self):
def description(self) -> str:
"""Get the description of the migration.
Returns
-------
str
The description of the migration.
"""
...

@property
@abc.abstractmethod
def upgrade_commands(self) -> typing.Sequence[MigrationCommand]:
"""Get the upgrade commands for the migration.
Returns
-------
Sequence[MigrationCommand]
A sequence of MigrationCommand objects representing the upgrade commands
for the migration.
"""
...

@property
@abc.abstractmethod
def downgrade_commands(self) -> typing.Sequence[MigrationCommand]:
"""Get the downgrade commands for the object.
Returns
-------
Sequence[MigrationCommand]
A sequence of MigrationCommand objects representing the downgrade commands
for the migration.
"""
...

@abc.abstractmethod
def downgrade(self, client: pymongo.MongoClient[typing.Dict[str, typing.Any]], /) -> None:
"""Downgrade the object to a previous version.
Parameters
----------
client : pymongo.MongoClient[Dict[str, Any]]
The MongoDB client object representing the connection to the database.
"""
...

@abc.abstractmethod
def upgrade(self, client: pymongo.MongoClient[typing.Dict[str, typing.Any]], /) -> None:
"""Upgrade the migration to a previous version.
Parameters
----------
client : pymongo.MongoClient[Dict[str, Any]]
The MongoDB client object representing the connection to the database.
"""
...

@abc.abstractmethod
def to_mongo_dict(self) -> typing.Dict[str, typing.Any]:
"""Convert the object to a dictionary representation for MongoDB.
Returns
-------
Dict[str, Any]
A dictionary representation of the object suitable for storing in a
MongoDB collection.
"""
...


@dataclasses.dataclass
class MigrationReadModel:
"""Represents a read model of a migration that provides information about the migration.
Attributes
----------
name : str
The name of the migration.
version : int
The version of the migration.
checksum : str
The checksum of the migration.
description : str
The description of the migration.
"""

name: str = dataclasses.field()
"""The name of the migration."""

version: int = dataclasses.field()
"""The version of the migration."""

checksum: str = dataclasses.field()
"""The checksum of the migration."""

description: str = dataclasses.field()
"""The description of the migration."""

@classmethod
def from_dict(cls, mapping):
def from_dict(cls, mapping: typing.MutableMapping[str, typing.Any], /) -> MigrationReadModel:
"""Create a MigrationReadModel instance from a dictionary.
Parameters
----------
mapping : typing.MutableMapping[str, typing.Any]
A dictionary containing the attributes of the migration.
Returns
-------
MigrationReadModel
An instance of MigrationReadModel initialized with the attributes
from the dictionary.
"""
mapping.pop("_id", None) # For mongo records
return cls(**mapping)

@classmethod
def from_migration(cls, migration):
def from_migration(cls, migration: Migration, /) -> MigrationReadModel:
"""Create a MigrationReadModel instance from a Migration instance.
Parameters
----------
migration : Migration
A Migration instance to create the MigrationReadModel instance from.
Returns
-------
MigrationReadModel
An instance of MigrationReadModel initialized with the attributes
from the Migration instance.
"""
return cls(
name=migration.name,
version=migration.version,
Expand Down
4 changes: 3 additions & 1 deletion mongorunway/kernel/domain/migration_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import abc
import typing

import pymongo


class MigrationCommand(abc.ABC):
__slots__: typing.Sequence[str] = ()

@abc.abstractmethod
def execute(self, conn, **kwargs) -> None:
def execute(self, conn: pymongo.MongoClient[typing.Dict[str, typing.Any]], **kwargs: typing.Any) -> None:
...
Loading

0 comments on commit 8dbef97

Please sign in to comment.