Last active
August 14, 2024 10:39
-
-
Save PiotrCzapla/579f76bdf95a485eaaafed1492d9a70e to your computer and use it in GitHub Desktop.
How to use JSON_EACH / JSONB_EACH in sqlalchemy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pytest | |
from sqlalchemy.exc import SAWarning | |
from sqlalchemy import Column, func, create_engine, Integer, JSON | |
from sqlalchemy.orm import declarative_base, Session | |
Base = declarative_base() | |
class EventHistory(Base): | |
__tablename__ = 'event_history' | |
id = Column(Integer, nullable=False, primary_key=True) | |
event = Column(JSON, nullable=False) | |
e = create_engine("sqlite://", echo=True) | |
Base.metadata.create_all(e) | |
s = Session(e) | |
s.add_all(EventHistory(id=ix, event=e) for ix,e in enumerate([ | |
{"about": ["antenna", "connection", "modem", "network"]}, | |
{"about": ["connection", "network"]}, | |
{"about": ["other", "keywords"]}])) | |
s.commit() | |
def assert_results_ok(events, issue_warning=False): | |
with pytest.warns(None) as record: | |
result = events.order_by(EventHistory.id).limit(3).all() | |
assert len(result) == 2 | |
assert result[0].id == 0 | |
assert result[1].id == 1 | |
if issue_warning: | |
assert len(record) == 1 | |
assert 'cartesian product between' in str(record[0].message) | |
else: | |
assert list(r.message for r in record) == [] | |
def test_ok_column(): | |
from sqlalchemy import column | |
about_exp = func.json_each(EventHistory.event, '$.about') | |
value = column('value') | |
events = s.query(EventHistory).select_from(about_exp).filter(value == 'connection') | |
assert_results_ok(events, issue_warning=False) # for some odd reason it does not issue a warning | |
def test_ok_literal_column(): | |
from sqlalchemy import literal_column | |
about_exp = func.json_each(EventHistory.event, '$.about').alias('b') | |
value = literal_column('b.value') | |
events = s.query(EventHistory).select_from(about_exp).filter(value == 'connection') | |
assert_results_ok(events, issue_warning=True) | |
def test_ok_column_valued(): | |
about_exp = func.json_each(EventHistory.event, '$.about').column_valued('value') | |
events = s.query(EventHistory).filter(about_exp == 'connection') | |
assert_results_ok(events, issue_warning=True) | |
def test_ok_table_valued(): | |
about_exp = func.json_each(EventHistory.event, '$.about').table_valued('value') | |
events = s.query(EventHistory).filter(about_exp.c.value == 'connection') | |
assert_results_ok(events, issue_warning=True) | |
def test_ok_table_valued_join_with_true_func(): | |
from sqlalchemy import true | |
about_exp = func.json_each(EventHistory.event, '$.about').table_valued('value') | |
events = s.query(EventHistory).join(about_exp, true()).filter(about_exp.c.value == 'connection') | |
assert_results_ok(events) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment