Changeset - 94624f7df6f5
[Not reviewed]
0 8 1
Lance Edgar (lance) - 3 months ago 2024-07-14 16:20:59
lance@edbob.org
fix: rename some constraints per wutta model

we will not (yet?) be able to "inherit" from the wutta model Base
which means basically the two are "not related" at this point.

but we do want to *match* whatever wutta has defined so far. the
rattail auth tables may contain more columns but will at least include
those columns present for the wutta model.

part of matching is the constraint names, which have been manually
specified in rattail for a while now. finally wutta has bothered to
define a proper naming convention so we can simply omit the names for
future changes. however it also means we must add an explicit
migration for any models we must match to wutta, to abandon the names
we had previously set which are now "incorrect"

most constraint names can remain as-is i think, since most tables will
never exist in the wutta model. eventually might be good to rename
all at once but that can wait
9 files changed with 128 insertions and 59 deletions:
0 comments (0 inline, 0 general)
rattail/db/alembic/versions/f6e95c74d8db_rename_constraints_per_wutta.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8; -*-
 
"""rename constraints per wutta
 

	
 
Revision ID: f6e95c74d8db
 
Revises: 4e7b6d8e71a4
 
Create Date: 2024-07-14 14:09:27.178397
 

	
 
"""
 

	
 
# revision identifiers, used by Alembic.
 
revision = 'f6e95c74d8db'
 
down_revision = '4e7b6d8e71a4'
 
branch_labels = None
 
depends_on = None
 

	
 
from alembic import op
 
import sqlalchemy as sa
 
import rattail.db.types
 

	
 

	
 

	
 
def upgrade():
 

	
 
    # uq_role_name
 
    op.drop_constraint('role_uq_name', 'role', type_='unique')
 
    op.create_unique_constraint(op.f('uq_role_name'), 'role', ['name'])
 

	
 
    # fk_permission_role_uuid_role
 
    op.drop_constraint('permission_fk_role', 'permission', type_='foreignkey')
 
    op.create_foreign_key('fk_permission_role_uuid_role',
 
                          'permission', 'role',
 
                          ['role_uuid'], ['uuid'])
 

	
 
    # fk_user_person_uuid_person
 
    op.drop_constraint('user_fk_person', 'user', type_='foreignkey')
 
    op.create_foreign_key('fk_user_person_uuid_person',
 
                          'user', 'person',
 
                          ['person_uuid'], ['uuid'])
 

	
 
    # uq_user_username
 
    op.drop_constraint('user_uq_username', 'user', type_='unique')
 
    op.create_unique_constraint(op.f('uq_user_username'), 'user', ['username'])
 

	
 
    # fk_user_x_role_role_uuid_role
 
    op.drop_constraint('user_x_role_fk_role', 'user_x_role', type_='foreignkey')
 
    op.create_foreign_key('fk_user_x_role_role_uuid_role',
 
                          'user_x_role', 'role',
 
                          ['role_uuid'], ['uuid'])
 

	
 
    # fk_user_x_role_user_uuid_user
 
    op.drop_constraint('user_x_role_fk_user', 'user_x_role', type_='foreignkey')
 
    op.create_foreign_key('fk_user_x_role_user_uuid_user',
 
                          'user_x_role', 'user',
 
                          ['user_uuid'], ['uuid'])
 

	
 

	
 
def downgrade():
 

	
 
    # fk_user_x_role_user_uuid_user
 
    op.drop_constraint('fk_user_x_role_user_uuid_user', 'user_x_role', type_='foreignkey')
 
    op.create_foreign_key('user_x_role_fk_user',
 
                          'user_x_role', 'user',
 
                          ['user_uuid'], ['uuid'])
 

	
 
    # fk_user_x_role_role_uuid_role
 
    op.drop_constraint('fk_user_x_role_role_uuid_role', 'user_x_role', type_='foreignkey')
 
    op.create_foreign_key('user_x_role_fk_role',
 
                          'user_x_role', 'role',
 
                          ['role_uuid'], ['uuid'])
 

	
 
    # uq_user_username
 
    op.drop_constraint(op.f('uq_user_username'), 'user', type_='unique')
 
    op.create_unique_constraint('user_uq_username', 'user', ['username'])
 

	
 
    # fk_user_person_uuid_person
 
    op.drop_constraint('fk_user_person_uuid_person', 'user', type_='foreignkey')
 
    op.create_foreign_key('user_fk_person',
 
                          'user', 'person',
 
                          ['person_uuid'], ['uuid'])
 

	
 
    # fk_permission_role_uuid_role
 
    op.drop_constraint('fk_permission_role_uuid_role', 'permission', type_='foreignkey')
 
    op.create_foreign_key('permission_fk_role',
 
                          'permission', 'role',
 
                          ['role_uuid'], ['uuid'])
 

	
 
    # uq_role_name
 
    op.drop_constraint(op.f('uq_role_name'), 'role', type_='unique')
 
    op.create_unique_constraint('role_uq_name', 'role', ['name'])
rattail/db/core.py
Show inline comments
 
@@ -24,20 +24,23 @@
 
Core Data Stuff
 
"""
 

	
 
import sqlalchemy as sa
 
import warnings
 

	
 
from wuttjamaican.util import make_uuid
 
import sqlalchemy as sa
 

	
 

	
 
def uuid_column(*args, **kwargs):
 
    """
 
    Returns a UUID column for use as a table's primary key.
 
    DEPRECATED; use :func:`rattail.db.model.core.uuid_column()`
 
    instead.
 
    """
 
    warnings.warn("rattail.db.core.uuid_column() is deprecated; "
 
                  "please use rattail.db.model.uuid_column() instead",
 
                  DeprecationWarning, stacklevel=2)
 

	
 
    from rattail.db.model import uuid_column
 

	
 
    kwargs.setdefault('primary_key', True)
 
    kwargs.setdefault('nullable', False)
 
    kwargs.setdefault('default', make_uuid)
 
    return sa.Column(sa.String(length=32), *args, **kwargs)
 
    return uuid_column(*args, **kwargs)
 

	
 

	
 
def filename_column(*args, **kwargs):
rattail/db/model/__init__.py
Show inline comments
 
@@ -27,7 +27,8 @@ This namespace will be populated with all data model classes defined
 
by Rattail.
 
"""
 

	
 
from .core import Base, ModelBase, uuid_column, getset_factory, GPCType, Setting, Change, Note
 
from .core import (uuid_column, uuid_fk_column,
 
                   Base, ModelBase, getset_factory, GPCType, Setting, Change, Note)
 
from .contact import PhoneNumber, EmailAddress, MailingAddress
 

	
 
from .people import (Person, PersonNote,
rattail/db/model/batch/core.py
Show inline comments
 
@@ -2,7 +2,7 @@
 
################################################################################
 
#
 
#  Rattail -- Retail Software Framework
 
#  Copyright © 2010-2023 Lance Edgar
 
#  Copyright © 2010-2024 Lance Edgar
 
#
 
#  This file is part of Rattail.
 
#
 
@@ -38,9 +38,9 @@ from sqlalchemy.orm import relationship, object_session
 
from sqlalchemy.ext.declarative import declared_attr
 
from sqlalchemy.ext.orderinglist import ordering_list
 

	
 
from rattail.db.core import uuid_column, filename_column
 
from rattail.db.core import filename_column
 
from rattail.db.types import GPCType, JSONTextDict
 
from rattail.db.model import User, Product
 
from rattail.db.model import uuid_column, User, Product
 
from rattail.time import make_utc
 

	
 

	
rattail/db/model/batch/labels.py
Show inline comments
 
@@ -2,7 +2,7 @@
 
################################################################################
 
#
 
#  Rattail -- Retail Software Framework
 
#  Copyright © 2010-2023 Lance Edgar
 
#  Copyright © 2010-2024 Lance Edgar
 
#
 
#  This file is part of Rattail.
 
#
 
@@ -30,8 +30,9 @@ from sqlalchemy.ext.declarative import declared_attr
 
from sqlalchemy.ext.associationproxy import association_proxy
 
from sqlalchemy.ext.orderinglist import ordering_list
 

	
 
from rattail.db.model import Base, LabelProfile, BatchMixin, ProductBatchRowMixin, getset_factory
 
from rattail.db.core import uuid_column, filename_column
 
from rattail.db.model import (Base, LabelProfile, BatchMixin, ProductBatchRowMixin,
 
                              getset_factory, uuid_column)
 
from rattail.db.core import filename_column
 

	
 

	
 
class LabelBatch(BatchMixin, Base):
rattail/db/model/batch/purchase.py
Show inline comments
 
@@ -2,7 +2,7 @@
 
################################################################################
 
#
 
#  Rattail -- Retail Software Framework
 
#  Copyright © 2010-2023 Lance Edgar
 
#  Copyright © 2010-2024 Lance Edgar
 
#
 
#  This file is part of Rattail.
 
#
 
@@ -28,10 +28,11 @@ import sqlalchemy as sa
 
from sqlalchemy import orm
 
from sqlalchemy.ext.declarative import declared_attr
 

	
 
from rattail.db.model import (Base, BatchMixin, BatchRowMixin,
 
from rattail.db.model import (Base, uuid_column,
 
                              BatchMixin, BatchRowMixin,
 
                              PurchaseBase, PurchaseItemBase, PurchaseCreditBase,
 
                              Purchase, PurchaseItem)
 
from rattail.db.core import uuid_column, filename_column
 
from rattail.db.core import filename_column
 

	
 

	
 
class PurchaseBatch(BatchMixin, PurchaseBase, Base):
rattail/db/model/core.py
Show inline comments
 
@@ -2,7 +2,7 @@
 
################################################################################
 
#
 
#  Rattail -- Retail Software Framework
 
#  Copyright © 2010-2023 Lance Edgar
 
#  Copyright © 2010-2024 Lance Edgar
 
#
 
#  This file is part of Rattail.
 
#
 
@@ -34,13 +34,15 @@ except ImportError:
 
    from sqlalchemy.ext.declarative import declarative_base
 
from sqlalchemy.ext.associationproxy import association_proxy
 

	
 
from wuttjamaican.db.model.base import naming_convention, uuid_column, uuid_fk_column
 

	
 
from rattail.core import Object
 
from rattail.time import make_utc
 

	
 
# These are imported because most sibling modules import them *from* here (if
 
# that makes sense).  Probably need to think harder about the "best" place for
 
# these things to live.
 
from rattail.db.core import uuid_column, getset_factory
 
from rattail.db.core import getset_factory
 
from rattail.db.types import GPCType
 

	
 

	
 
@@ -105,7 +107,9 @@ class ModelBase(Object):
 
            getset_factory=getset_factory))
 

	
 

	
 
Base = declarative_base(cls=ModelBase)
 
metadata = sa.MetaData(naming_convention=naming_convention)
 

	
 
Base = declarative_base(metadata=metadata, cls=ModelBase)
 

	
 

	
 
class Setting(Base):
rattail/db/model/users.py
Show inline comments
 
@@ -2,7 +2,7 @@
 
################################################################################
 
#
 
#  Rattail -- Retail Software Framework
 
#  Copyright © 2010-2023 Lance Edgar
 
#  Copyright © 2010-2024 Lance Edgar
 
#
 
#  This file is part of Rattail.
 
#
 
@@ -31,7 +31,7 @@ import sqlalchemy as sa
 
from sqlalchemy import orm
 
from sqlalchemy.ext.associationproxy import association_proxy
 

	
 
from rattail.db.model import Base, uuid_column, getset_factory, Person
 
from rattail.db.model import Base, uuid_column, uuid_fk_column, getset_factory, Person
 
 
 

	
 
class Role(Base):
 
@@ -39,14 +39,11 @@ class Role(Base):
 
    Represents a role within the system; used to manage permissions.
 
    """
 
    __tablename__ = 'role'
 
    __table_args__ = (
 
        sa.UniqueConstraint('name', name='role_uq_name'),
 
    )
 
    __versioned__ = {}
 

	
 
    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.
 
    """)
 

	
 
@@ -131,12 +128,10 @@ class Permission(Base):
 
    Represents permission a role has to do a particular thing.
 
    """
 
    __tablename__ = 'permission'
 
    __table_args__ = (
 
        sa.ForeignKeyConstraint(['role_uuid'], ['role.uuid'], name='permission_fk_role'),
 
        )
 
    # __versioned__ = {}
 

	
 
    role_uuid = sa.Column(sa.String(length=32), primary_key=True)
 
    role_uuid = uuid_fk_column('role.uuid', primary_key=True, nullable=False)
 

	
 
    permission = sa.Column(sa.String(length=254), primary_key=True)
 

	
 
    def __str__(self):
 
@@ -162,18 +157,16 @@ class User(Base):
 
    """
 
    __tablename__ = 'user'
 
    __table_args__ = (
 
        sa.ForeignKeyConstraint(['person_uuid'], ['person.uuid'], name='user_fk_person'),
 
        sa.UniqueConstraint('username', name='user_uq_username'),
 
        sa.Index('user_ix_person', 'person_uuid'),
 
    )
 
    __versioned__ = {'exclude': ['password', 'salt', 'last_login']}
 

	
 
    uuid = uuid_column()
 
    username = sa.Column(sa.String(length=25), nullable=False)
 
    username = sa.Column(sa.String(length=25), nullable=False, unique=True)
 
    password = sa.Column(sa.String(length=60))
 
    salt = sa.Column(sa.String(length=29))
 

	
 
    person_uuid = sa.Column(sa.String(length=32))
 
    person_uuid = uuid_fk_column('person.uuid', nullable=True)
 
    person = orm.relationship(
 
        Person,
 
        uselist=False,
 
@@ -330,16 +323,12 @@ class UserRole(Base):
 
    Represents the association between a :class:`User` and a :class:`Role`.
 
    """
 
    __tablename__ = 'user_x_role'
 
    __table_args__ = (
 
        sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'], name='user_x_role_fk_user'),
 
        sa.ForeignKeyConstraint(['role_uuid'], ['role.uuid'], name='user_x_role_fk_role'),
 
        )
 
    __versioned__ = {}
 

	
 
    uuid = uuid_column()
 
    user_uuid = sa.Column(sa.String(length=32), nullable=False)
 
    user_uuid = uuid_fk_column('user.uuid', nullable=False)
 

	
 
    role_uuid = sa.Column(sa.String(length=32), nullable=False)
 
    role_uuid = uuid_fk_column('role.uuid', nullable=False)
 
    role = orm.relationship(Role, back_populates='_users')
 

	
 

	
tests/db/test_core.py
Show inline comments
 
@@ -13,25 +13,6 @@ except ImportError:
 
    pass
 
else:
 

	
 
    class TestCore(TestCase):
 

	
 
        def test_uuid_column(self):
 
            column = core.uuid_column()
 
            self.assertTrue(isinstance(column, Column))
 
            self.assertEqual(column.name, None)
 
            self.assertTrue(column.primary_key)
 
            self.assertFalse(column.nullable)
 
            self.assertFalse(column.default is None)
 

	
 
        def test_uuid_column_no_default(self):
 
            column = core.uuid_column(default=None)
 
            self.assertTrue(column.default is None)
 

	
 
        def test_uuid_column_nullable(self):
 
            column = core.uuid_column(nullable=True)
 
            self.assertTrue(column.nullable)
 

	
 

	
 
    class TestGetSetFactory(TestCase):
 

	
 
        def setUp(self):
0 comments (0 inline, 0 general)