SQLAlchemy 自定义布尔值

发布于 2025-01-12 22:40:06 字数 560 浏览 1 评论 0原文

我有一个以这种方式实现布尔逻辑的 Oracle 数据库:

MYCOL NUMBER(1,0)

0 = False
-1 or 1 = True
NULL = None

使用默认的 SQLAlchemy 布尔列,-1 表值与 FalseTrue 不匹配。 是否可以创建一个 SQLAlchemy 自定义类型,将此类列映射到 bool python 属性?

困难在于有多个与 true 关联的值。 例如:

session.query(User).filter_by(active=True)

应该生成以下查询之一:

select * from user where active != 0;
select * from user where active in (-1, 1);
select * from user where 1 = (CASE WHEN active != 0 THEN 1 ELSE active end);

I have an Oracle database with boolean logic implemented this way:

MYCOL NUMBER(1,0)

0 = False
-1 or 1 = True
NULL = None

With a default SQLAlchemy boolean column, -1 table value doesn't match False or True.
Is it possible to create an SQLAlchemy custom type that maps such a column to a bool python attribute?

The difficulty relies in having multiple values associated with true.
Ex:

session.query(User).filter_by(active=True)

Should generate one of these queries:

select * from user where active != 0;
select * from user where active in (-1, 1);
select * from user where 1 = (CASE WHEN active != 0 THEN 1 ELSE active end);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

可遇━不可求 2025-01-19 22:40:06

此实现似乎适用于基本查询。
Case when 表达式似乎是最简单的解决方案,因为运算符逻辑没有改变。

class CustomBoolean(sqlalchemy.types.TypeDecorator):
    """0 = False
    -1 or 1 = True
    NULL = None
    By default, SQLAlchemy only supports 0 and 1"""

    impl = Boolean
    cache_ok = True

    # In select or group by clause, replace col with expression: (CASE WHEN col != 0 THEN 1 ELSE col end)
    def column_expression(self, col):
        expr = col.expr
        if isinstance(expr.type, CustomBoolean):
            res = sqlalchemy.case(
                (type_coerce(expr, Integer()) != sqlalchemy.literal_column("0", type_=Integer), sqlalchemy.literal_column("1", type_=Integer)),
                else_=type_coerce(expr, Integer())
            )
            return type_coerce(res, Boolean())

        expr.type = Boolean()
        return expr

    # In where clause, replace col with expression: (CASE WHEN col != 0 THEN 1 ELSE col end)
    class comparator_factory(Boolean.Comparator):
        def operate(self, op, other, **kwargs):
            op1 = self
            if hasattr(op1, "__clause_element__"):
                clause = op1.__clause_element__()
                if isinstance(clause.type, CustomBoolean):
                    op1 = self.normalise(clause)

            op2 = other
            if hasattr(op2, "__clause_element__"):
                clause = op2.__clause_element__()
                if isinstance(clause.type, CustomBoolean):
                    op2 = self.normalise(clause)

            return op(
                op1, op2, **kwargs
            )

        @staticmethod
        def normalise(expr):
            res = sqlalchemy.case(
                (type_coerce(expr, Integer()) != sqlalchemy.literal_column("0", type_=Integer), sqlalchemy.literal_column("1", type_=Integer)),
                else_=type_coerce(expr, Integer())
            )
            return type_coerce(res, Boolean())

This implementation seems to work for basic queries.
Case when expression seems to be the easiest solution because operator logic isn't altered.

class CustomBoolean(sqlalchemy.types.TypeDecorator):
    """0 = False
    -1 or 1 = True
    NULL = None
    By default, SQLAlchemy only supports 0 and 1"""

    impl = Boolean
    cache_ok = True

    # In select or group by clause, replace col with expression: (CASE WHEN col != 0 THEN 1 ELSE col end)
    def column_expression(self, col):
        expr = col.expr
        if isinstance(expr.type, CustomBoolean):
            res = sqlalchemy.case(
                (type_coerce(expr, Integer()) != sqlalchemy.literal_column("0", type_=Integer), sqlalchemy.literal_column("1", type_=Integer)),
                else_=type_coerce(expr, Integer())
            )
            return type_coerce(res, Boolean())

        expr.type = Boolean()
        return expr

    # In where clause, replace col with expression: (CASE WHEN col != 0 THEN 1 ELSE col end)
    class comparator_factory(Boolean.Comparator):
        def operate(self, op, other, **kwargs):
            op1 = self
            if hasattr(op1, "__clause_element__"):
                clause = op1.__clause_element__()
                if isinstance(clause.type, CustomBoolean):
                    op1 = self.normalise(clause)

            op2 = other
            if hasattr(op2, "__clause_element__"):
                clause = op2.__clause_element__()
                if isinstance(clause.type, CustomBoolean):
                    op2 = self.normalise(clause)

            return op(
                op1, op2, **kwargs
            )

        @staticmethod
        def normalise(expr):
            res = sqlalchemy.case(
                (type_coerce(expr, Integer()) != sqlalchemy.literal_column("0", type_=Integer), sqlalchemy.literal_column("1", type_=Integer)),
                else_=type_coerce(expr, Integer())
            )
            return type_coerce(res, Boolean())
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文