fix: add migration for auth tables
having now fixed the constraint naming convention
This commit is contained in:
parent
1995095627
commit
60d3fcd13b
|
@ -0,0 +1,73 @@
|
|||
"""add users, roles
|
||||
|
||||
Revision ID: d686f7abe3e0
|
||||
Revises: fc3a3bcaa069
|
||||
Create Date: 2024-07-14 13:27:22.703093
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'd686f7abe3e0'
|
||||
down_revision: Union[str, None] = 'fc3a3bcaa069'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
|
||||
# role
|
||||
op.create_table('role',
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('uuid'),
|
||||
sa.UniqueConstraint('name', name=op.f('uq_role_name'))
|
||||
)
|
||||
|
||||
# user
|
||||
op.create_table('user',
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('username', sa.String(length=25), nullable=False),
|
||||
sa.Column('password', sa.String(length=60), nullable=True),
|
||||
sa.Column('active', sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('uuid'),
|
||||
sa.UniqueConstraint('username', name=op.f('uq_user_username'))
|
||||
)
|
||||
|
||||
# permission
|
||||
op.create_table('permission',
|
||||
sa.Column('role_uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('permission', sa.String(length=254), nullable=False),
|
||||
sa.ForeignKeyConstraint(['role_uuid'], ['role.uuid'], name=op.f('fk_permission_role_uuid_role')),
|
||||
sa.PrimaryKeyConstraint('role_uuid', 'permission')
|
||||
)
|
||||
|
||||
# user_x_role
|
||||
op.create_table('user_x_role',
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('user_uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('role_uuid', sa.String(length=32), nullable=False),
|
||||
sa.ForeignKeyConstraint(['role_uuid'], ['role.uuid'], name=op.f('fk_user_x_role_role_uuid_role')),
|
||||
sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'], name=op.f('fk_user_x_role_user_uuid_user')),
|
||||
sa.PrimaryKeyConstraint('uuid')
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
|
||||
# user_x_role
|
||||
op.drop_table('user_x_role')
|
||||
|
||||
# permission
|
||||
op.drop_table('permission')
|
||||
|
||||
# user
|
||||
op.drop_table('user')
|
||||
|
||||
# role
|
||||
op.drop_table('role')
|
|
@ -65,16 +65,10 @@ class Role(Base):
|
|||
See also :attr:`user_refs`.
|
||||
"""
|
||||
__tablename__ = 'role'
|
||||
__table_args__ = (
|
||||
sa.UniqueConstraint('name',
|
||||
# TODO
|
||||
# name='role_uq_name',
|
||||
),
|
||||
)
|
||||
|
||||
uuid = uuid_column()
|
||||
|
||||
name = sa.Column(sa.String(length=100), nullable=False, doc="""
|
||||
name = sa.Column(sa.String(length=100), nullable=False, unique=True, doc="""
|
||||
Name for the role. Each role must have a name, which must be
|
||||
unique.
|
||||
""")
|
||||
|
@ -86,6 +80,8 @@ class Role(Base):
|
|||
permission_refs = orm.relationship(
|
||||
'Permission',
|
||||
back_populates='role',
|
||||
# TODO
|
||||
# cascade='save-update, merge, delete, delete-orphan',
|
||||
doc="""
|
||||
List of :class:`Permission` references for the role.
|
||||
|
||||
|
@ -127,14 +123,8 @@ class Permission(Base):
|
|||
Represents a permission granted to a role.
|
||||
"""
|
||||
__tablename__ = 'permission'
|
||||
__table_args__ = (
|
||||
sa.ForeignKeyConstraint(['role_uuid'], ['role.uuid'],
|
||||
# TODO
|
||||
# name='permission_fk_role',
|
||||
),
|
||||
)
|
||||
|
||||
role_uuid = uuid_fk_column(primary_key=True, nullable=False)
|
||||
role_uuid = uuid_fk_column('role.uuid', primary_key=True, nullable=False)
|
||||
role = orm.relationship(
|
||||
Role,
|
||||
back_populates='permission_refs',
|
||||
|
@ -157,18 +147,18 @@ class User(Base):
|
|||
|
||||
This may or may not correspond to a real person, i.e. some users
|
||||
may exist solely for automated tasks.
|
||||
|
||||
.. attribute:: roles
|
||||
|
||||
List of :class:`Role` instances to which the user belongs.
|
||||
|
||||
See also :attr:`role_refs`.
|
||||
"""
|
||||
__tablename__ = 'user'
|
||||
__table_args__ = (
|
||||
sa.UniqueConstraint('username',
|
||||
# TODO
|
||||
# name='user_uq_username',
|
||||
),
|
||||
)
|
||||
|
||||
uuid = uuid_column()
|
||||
|
||||
username = sa.Column(sa.String(length=25), nullable=False, doc="""
|
||||
username = sa.Column(sa.String(length=25), nullable=False, unique=True, doc="""
|
||||
Account username. This is required and must be unique.
|
||||
""")
|
||||
|
||||
|
@ -186,33 +176,35 @@ class User(Base):
|
|||
role_refs = orm.relationship(
|
||||
'UserRole',
|
||||
back_populates='user',
|
||||
# TODO
|
||||
# cascade='all, delete-orphan',
|
||||
doc="""
|
||||
List of :class:`UserRole` records.
|
||||
List of :class:`UserRole` instances belonging to the user.
|
||||
|
||||
See also :attr:`roles`.
|
||||
""")
|
||||
|
||||
roles = association_proxy(
|
||||
'role_refs', 'role',
|
||||
creator=lambda r: UserRole(role=r),
|
||||
# TODO
|
||||
# getset_factory=getset_factory,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.username or ""
|
||||
|
||||
|
||||
class UserRole(Base):
|
||||
"""
|
||||
Represents the association between a user and a role.
|
||||
Represents the association between a user and a role; i.e. the
|
||||
user "belongs" or "is assigned" to the role.
|
||||
"""
|
||||
__tablename__ = 'user_x_role'
|
||||
__table_args__ = (
|
||||
sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'],
|
||||
# TODO
|
||||
# name='user_x_role_fk_user',
|
||||
),
|
||||
sa.ForeignKeyConstraint(['role_uuid'], ['role.uuid'],
|
||||
# TODO
|
||||
# name='user_x_role_fk_role',
|
||||
),
|
||||
)
|
||||
|
||||
uuid = uuid_column()
|
||||
|
||||
user_uuid = uuid_fk_column(nullable=False)
|
||||
user_uuid = uuid_fk_column('user.uuid', nullable=False)
|
||||
user = orm.relationship(
|
||||
User,
|
||||
back_populates='role_refs',
|
||||
|
@ -220,7 +212,7 @@ class UserRole(Base):
|
|||
Reference to the :class:`User` involved.
|
||||
""")
|
||||
|
||||
role_uuid = uuid_fk_column(nullable=False)
|
||||
role_uuid = uuid_fk_column('role.uuid', nullable=False)
|
||||
role = orm.relationship(
|
||||
Role,
|
||||
back_populates='user_refs',
|
||||
|
|
|
@ -34,7 +34,19 @@ from sqlalchemy import orm
|
|||
from wuttjamaican.util import make_uuid
|
||||
|
||||
|
||||
Base = orm.declarative_base()
|
||||
# nb. this convention comes from upstream docs
|
||||
# https://docs.sqlalchemy.org/en/14/core/constraints.html#constraint-naming-conventions
|
||||
naming_convention = {
|
||||
'ix': 'ix_%(column_0_label)s',
|
||||
'uq': 'uq_%(table_name)s_%(column_0_name)s',
|
||||
'ck': 'ck_%(table_name)s_%(constraint_name)s',
|
||||
'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s',
|
||||
'pk': 'pk_%(table_name)s',
|
||||
}
|
||||
|
||||
metadata = sa.MetaData(naming_convention=naming_convention)
|
||||
|
||||
Base = orm.declarative_base(metadata=metadata)
|
||||
|
||||
|
||||
def uuid_column(*args, **kwargs):
|
||||
|
@ -47,11 +59,14 @@ def uuid_column(*args, **kwargs):
|
|||
return sa.Column(sa.String(length=32), *args, **kwargs)
|
||||
|
||||
|
||||
def uuid_fk_column(*args, **kwargs):
|
||||
def uuid_fk_column(target_column, *args, **kwargs):
|
||||
"""
|
||||
Returns a UUID column for use as a foreign key to another table.
|
||||
|
||||
:param target_column: Name of the table column on the remote side,
|
||||
e.g. ``'user.uuid'``.
|
||||
"""
|
||||
return sa.Column(sa.String(length=32), *args, **kwargs)
|
||||
return sa.Column(sa.String(length=32), sa.ForeignKey(target_column), *args, **kwargs)
|
||||
|
||||
|
||||
class Setting(Base):
|
||||
|
|
|
@ -20,7 +20,7 @@ else:
|
|||
class TestUUIDFKColumn(TestCase):
|
||||
|
||||
def test_basic(self):
|
||||
column = model.uuid_column()
|
||||
column = model.uuid_fk_column('foo.bar')
|
||||
self.assertIsInstance(column, sa.Column)
|
||||
self.assertIsInstance(column.type, sa.String)
|
||||
self.assertEqual(column.type.length, 32)
|
||||
|
|
Loading…
Reference in a new issue