我有一个返回SQLAlchemy查询对象的函数,我想测试该函数以构建正确的查询。
例如:
import sqlalchemy
metadata = sqlalchemy.MetaData()
users = sqlalchemy.Table(
"users",
metadata,
sqlalchemy.Column("email", sqlalchemy.String(255), nullable=False, unique=True),
sqlalchemy.Column("username", sqlalchemy.String(50), nullable=False, unique=True),
)
def select_first_users(n):
return users.select().limit(n)
def test_queries_are_equal(self):
expected_query = users.select().limit(10)
assert select_first_users(10) == expected_query # fails here
assert select_first_users(10).compare(expected_query) # fails here too
我不知道如何比较两个查询是否相等。 ==
在这里不起作用,因为据我所知,该对象未定义__eq__
方法,因此它按内存中的地址比较对象,肯定会失败。 compare
method也进行is
比较。
我看到的唯一解决方案是:
assert str(q1.compile()) == str(q2.compile())
,但很奇怪,它包含占位符而不是实际值。
那么如何比较两个SQLAlchemy查询的相等性?
我使用Python 3.7.4 SQLAlchemy==1.3.10
。
答案 0 :(得分:1)
编译函数有一个参数可以解决占位符问题 query.compile(compile_kwargs = {“ literal_binds”:True}),所以代替
SELECT users.email,
users.username
FROM users
LIMIT :param_1
你得到
SELECT users.email,
users.username
FROM users
LIMIT 10
所以我认为您可以做类似的事情
import sqlparse
def format_query(query):
return sqlparse.format(str(query.compile(compile_kwargs={"literal_binds": True})),
reindent=True, keyword_case='upper')
def test_queries_are_equal():
expected_query = users.select().limit(10)
assert format_query(expected_query) == format_query(select_first_users(10))
如果比较基于完全匹配的字符串,则我认为最好确保格式一致,因此最好使用sqlparse。
本机只处理int和字符串,但可以扩展,有关更多信息,请参阅文档 https://docs.sqlalchemy.org/en/13/faq/sqlexpressions.html#faq-sql-expression-string