From ec5b7b94a3c91db21cb2fa11356ef3f1d5eb6274 Mon Sep 17 00:00:00 2001 From: David Baumgold Date: Thu, 25 Feb 2016 11:22:01 -0500 Subject: [PATCH 1/3] Add GenderType --- sqlalchemy_utils/types/__init__.py | 1 + sqlalchemy_utils/types/gender.py | 17 +++++++++++++ tests/types/test_gender.py | 41 ++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 sqlalchemy_utils/types/gender.py create mode 100644 tests/types/test_gender.py diff --git a/sqlalchemy_utils/types/__init__.py b/sqlalchemy_utils/types/__init__.py index 272b0017..93ca8f6d 100644 --- a/sqlalchemy_utils/types/__init__.py +++ b/sqlalchemy_utils/types/__init__.py @@ -9,6 +9,7 @@ from .currency import CurrencyType # noqa from .email import EmailType # noqa from .encrypted import EncryptedType # noqa +from .gender import GenderType # noqa from .ip_address import IPAddressType # noqa from .json import JSONType # noqa from .locale import LocaleType # noqa diff --git a/sqlalchemy_utils/types/gender.py b/sqlalchemy_utils/types/gender.py new file mode 100644 index 00000000..6de9bd4a --- /dev/null +++ b/sqlalchemy_utils/types/gender.py @@ -0,0 +1,17 @@ +import sqlalchemy as sa + +from ..operators import CaseInsensitiveComparator + + +class GenderType(sa.types.TypeDecorator): + impl = sa.Unicode(255) + comparator_factory = CaseInsensitiveComparator + + def process_bind_param(self, value, dialect): + if value is not None: + return value.lower() + return value + + @property + def python_type(self): + return self.impl.type.python_type diff --git a/tests/types/test_gender.py b/tests/types/test_gender.py new file mode 100644 index 00000000..55efaeb6 --- /dev/null +++ b/tests/types/test_gender.py @@ -0,0 +1,41 @@ +import pytest +import sqlalchemy as sa + +from sqlalchemy_utils import GenderType + + +@pytest.fixture +def User(Base): + class User(Base): + __tablename__ = 'user' + id = sa.Column(sa.Integer, primary_key=True) + gender = sa.Column(GenderType) + + def __repr__(self): + return 'User(%r)' % self.id + return User + + +class TestGenderType(object): + def test_saves_gender_as_lowercased(self, session, User): + user = User(gender=u'Male') + + session.add(user) + session.commit() + + user = session.query(User).first() + assert user.gender == u'male' + + def test_literal_param(self, session, User): + clause = User.gender == 'Female' + compiled = str(clause.compile(compile_kwargs={'literal_binds': True})) + assert compiled == '"user".gender = lower(\'Female\')' + + def test_nonbinary_gender(self, session, User): + user = User(gender=u'non-binary') + + session.add(user) + session.commit() + + user = session.query(User).first() + assert user.gender == u'non-binary' From a963900817d96c6c4766c5856a2ddf6da8f0185d Mon Sep 17 00:00:00 2001 From: David Baumgold Date: Thu, 25 Feb 2016 11:27:43 -0500 Subject: [PATCH 2/3] Added documentation for GenderType --- docs/data_types.rst | 8 ++++++++ sqlalchemy_utils/types/gender.py | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/docs/data_types.rst b/docs/data_types.rst index 87fc895d..5295bb86 100644 --- a/docs/data_types.rst +++ b/docs/data_types.rst @@ -70,6 +70,14 @@ EncryptedType .. autoclass:: EncryptedType + +GenderType +---------- + +.. module:: sqlalchemy_utils.types.gender + +.. autoclass:: GenderType + JSONType -------- diff --git a/sqlalchemy_utils/types/gender.py b/sqlalchemy_utils/types/gender.py index 6de9bd4a..f5ce4084 100644 --- a/sqlalchemy_utils/types/gender.py +++ b/sqlalchemy_utils/types/gender.py @@ -4,6 +4,17 @@ class GenderType(sa.types.TypeDecorator): + """ + GenderType represents the gender identity of a person. It is as inclusive + as possible, suggesting "simple" genders like "male" and "female" + but also supporting arbitrary text input for non-binary gender identities. + This data is stored in the database as a lowercase string. + + This database type is primarily useful so that form libraries like wtforms + can detect that this column represents a person's gender, which allows + the form library to render an inclusive HTML form field that allows the + user to select their gender. + """ impl = sa.Unicode(255) comparator_factory = CaseInsensitiveComparator From f058bcf539adc8429be4d40cde1a1447d553e4f4 Mon Sep 17 00:00:00 2001 From: David Baumgold Date: Thu, 25 Feb 2016 13:42:37 -0500 Subject: [PATCH 3/3] Import GenderType to top level module --- sqlalchemy_utils/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlalchemy_utils/__init__.py b/sqlalchemy_utils/__init__.py index d406431f..6967f7ba 100644 --- a/sqlalchemy_utils/__init__.py +++ b/sqlalchemy_utils/__init__.py @@ -71,6 +71,7 @@ DateTimeRangeType, EmailType, EncryptedType, + GenderType, instrumented_list, InstrumentedList, IntRangeType,