Skip to content

Commit

Permalink
Add support for composite unique constraint
Browse files Browse the repository at this point in the history
  • Loading branch information
atkei committed Apr 10, 2024
1 parent 363d683 commit ca4c4a2
Show file tree
Hide file tree
Showing 12 changed files with 888 additions and 7 deletions.
73 changes: 70 additions & 3 deletions piccolo/apps/migrations/auto/diffable_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@

from piccolo.apps.migrations.auto.operations import (
AddColumn,
AddConstraint,
AlterColumn,
DropColumn,
DropConstraint,
)
from piccolo.apps.migrations.auto.serialisation import (
deserialise_params,
serialise_params,
)
from piccolo.columns.base import Column
from piccolo.constraint import Constraint
from piccolo.table import Table, create_table_class


Expand Down Expand Up @@ -55,6 +58,8 @@ class TableDelta:
add_columns: t.List[AddColumn] = field(default_factory=list)
drop_columns: t.List[DropColumn] = field(default_factory=list)
alter_columns: t.List[AlterColumn] = field(default_factory=list)
add_constraints: t.List[AddConstraint] = field(default_factory=list)
drop_constraints: t.List[DropConstraint] = field(default_factory=list)

def __eq__(self, value: TableDelta) -> bool: # type: ignore
"""
Expand Down Expand Up @@ -85,6 +90,19 @@ def __eq__(self, value) -> bool:
return False


@dataclass
class ConstraintComparison:
constraint: Constraint

def __hash__(self) -> int:
return self.constraint.__hash__()

def __eq__(self, value) -> bool:
if isinstance(value, ConstraintComparison):
return self.constraint._meta.name == value.constraint._meta.name
return False


@dataclass
class DiffableTable:
"""
Expand All @@ -96,6 +114,7 @@ class DiffableTable:
tablename: str
schema: t.Optional[str] = None
columns: t.List[Column] = field(default_factory=list)
constraints: t.List[Constraint] = field(default_factory=list)
previous_class_name: t.Optional[str] = None

def __post_init__(self) -> None:
Expand Down Expand Up @@ -189,10 +208,54 @@ def __sub__(self, value: DiffableTable) -> TableDelta:
)
)

add_constraints = [
AddConstraint(
table_class_name=self.class_name,
constraint_name=i.constraint._meta.name,
constraint_class_name=i.constraint.__class__.__name__,
constraint_class=i.constraint.__class__,
params=i.constraint._meta.params,
schema=self.schema,
)
for i in sorted(
{
ConstraintComparison(constraint=constraint)
for constraint in self.constraints
}
- {
ConstraintComparison(constraint=constraint)
for constraint in value.constraints
},
key=lambda x: x.constraint._meta.name,
)
]

drop_constraints = [
DropConstraint(
table_class_name=self.class_name,
constraint_name=i.constraint._meta.name,
tablename=value.tablename,
schema=self.schema,
)
for i in sorted(
{
ConstraintComparison(constraint=constraint)
for constraint in value.constraints
}
- {
ConstraintComparison(constraint=constraint)
for constraint in self.constraints
},
key=lambda x: x.constraint._meta.name,
)
]

return TableDelta(
add_columns=add_columns,
drop_columns=drop_columns,
alter_columns=alter_columns,
add_constraints=add_constraints,
drop_constraints=drop_constraints,
)

def __hash__(self) -> int:
Expand All @@ -218,10 +281,14 @@ def to_table_class(self) -> t.Type[Table]:
"""
Converts the DiffableTable into a Table subclass.
"""
class_members: t.Dict[str, t.Any] = {}
for column in self.columns:
class_members[column._meta.name] = column
for constraint in self.constraints:
class_members[constraint._meta.name] = constraint

return create_table_class(
class_name=self.class_name,
class_kwargs={"tablename": self.tablename, "schema": self.schema},
class_members={
column._meta.name: column for column in self.columns
},
class_members=class_members,
)

3 comments on commit ca4c4a2

@sinisaos
Copy link
Member

Choose a reason for hiding this comment

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

@atkei Sorry to bother you, but I think this is great. I tried this branch and everything works and looks great. Migrations work, constraints are correctly added to the database. I removed the constraints by simply deleting (or commenting out) the constraints from the table definition (hope I did it right) and that works too. I don't know if you want to add anything else, but my opinion is that you should made PR.

@atkei
Copy link
Author

@atkei atkei commented on ca4c4a2 Apr 12, 2024

Choose a reason for hiding this comment

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

@sinisaos
Thank you for caring about me.
I'll create a PR to get feedback.

@sinisaos
Copy link
Member

Choose a reason for hiding this comment

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

@atkei No problem 😃 . I think this is great, but feedback from maintainer is most important. You probably need to write docs for this, but there is time for that if the feedback is positive. Thanks again for your effort.

Please sign in to comment.