Python 是否有任何sqlalchemy列表插值语法可以在sqlite(用于测试)和mysql(用于prod)中使用?
这是我需要处理的最微小的代码示例我们在prod中使用mysql,我们喜欢原始sql查询来处理复杂的查询,因为数据分析师可以读取/修改/审计它们,我们使用sqlite进行单元测试Python 是否有任何sqlalchemy列表插值语法可以在sqlite(用于测试)和mysql(用于prod)中使用?,python,mysql,sqlite,sqlalchemy,Python,Mysql,Sqlite,Sqlalchemy,这是我需要处理的最微小的代码示例我们在prod中使用mysql,我们喜欢原始sql查询来处理复杂的查询,因为数据分析师可以读取/修改/审计它们,我们使用sqlite进行单元测试 from typing import List, Any def test_sqlite_params_demo(self, session): session.add(build_foo()) session.commit() query = "select * f
from typing import List, Any
def test_sqlite_params_demo(self, session):
session.add(build_foo())
session.commit()
query = "select * from foo where id not in :id_list"
result = session.execute(query, {"id_list": [9, 99, 999]})
result_dict: List[Any] = [dict(r) for r in result]
assert len(result_dict) is 1
以下是上述操作导致的错误:
def do_execute(self, cursor, statement, parameters, context=None):
> cursor.execute(statement, parameters)
E sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near "?": syntax error
E [SQL: select * from patient where id not in ?]
E [parameters: ([9, 99, 999],)]
E (Background on this error at: http://sqlalche.me/e/e3q8)
如果我使用一个元组result=session.executequery,{id_list:9,99,999},则错误为:
> cursor.execute(statement, parameters)
E sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near "?": syntax error
E [SQL: select * from foo where id not in ?]
E [parameters: ((9, 99, 999),)]
E (Background on this error at: http://sqlalche.me/e/e3q8)
注意:此问题仅在插入列表而不仅仅是单个值时发生
我在requirements.txt文件中使用SQLAlchemy==1.3.11
现在我面临着一个令人不快的选择,要么在添加测试之前将复杂的代码重写为不太理想的格式,要么添加跳过/模拟我最想测试的代码部分的测试。什么是更好的选择
这个问题以前一定有人问过,但我一直找不到。如果您知道它在哪里,请给我指一下:如果您将查询转换为sqlalchemy.text对象,应该可以 从sqlalchemy导入文本 结果=session.executetextquery,{id_list:[9,99999]}
我已经创造了一个适合我的答案
def is_test():
"""
Tests which want to run code that executes raw sql can override this to be True
Example:
@patch('my_app.helpers.raw_sql_runner.is_test', side_effect=lambda: True)
def test_run_raw_sql_string(self, is_test_mock, session):
"""
return False
def run_raw_sql(session, sql, params):
if is_test():
for key, val in params.items():
if isinstance(val, (list, tuple)):
interpolated_sql = sql.replace(f':{key}', f"({','.join(map(str, val))})")
elif isinstance(val, str):
interpolated_sql = sql.replace(f':{key}', f"'{str(val)}'")
else:
interpolated_sql = sql.replace(f':{key}', str(val))
return session.execute(interpolated_sql, params)
else:
return session.execute(sql, params)
我还需要创建一些mysql拥有的、sqlite没有的方法
# conftest.py
def fake_sqlite_concat(a, b):
return f'{a}{b}'
def create_sqlite_functions(con):
con.create_function("concat", 2, fake_sqlite_concat)
# more functions go here as needed
con = engine.connect().connection
create_sqlite_functions(con)
此解决方案不会更改我看到的错误消息:您使用的是什么版本的sqlalchemy?我有SQLAlchemy==1.3.11