Coverage for tests / test_select_typing.py: 100%
75 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-11-09 00:02 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-11-09 00:02 +0000
1from sqlalchemy import Engine 1BCDEFGHIJ
2from sqlalchemy.engine import ScalarResult, TupleResult 1BCDEFGHIJ
3from sqlalchemy.sql.elements import UnaryExpression 1BCDEFGHIJ
4from sqlmodel import ( 1BCDEFGHIJ
5 Field,
6 Session,
7 SQLModel,
8 asc,
9 col,
10 desc,
11 nulls_first,
12 nulls_last,
13 select,
14)
15from typing_extensions import assert_type 1BCDEFGHIJ
18def test_fields(database_engine: Engine) -> None: 1BCDEFGHIJ
19 class Hero(SQLModel, table=True): 1abcdefghi
20 id: int | None = Field(default=None, primary_key=True) 1abcdefghi
21 name: str 1abcdefghi
22 secret_name: str 1abcdefghi
23 age: int | None = None 1abcdefghi
24 food: str | None = None 1abcdefghi
26 engine = database_engine 1abcdefghi
28 SQLModel.metadata.create_all(engine) 1abcdefghi
30 with Session(engine) as session: 1abcdefghi
31 session.add(Hero(name="Deadpond", secret_name="Dive Wilson")) 1abcdefghi
32 session.add( 1abcdefghi
33 Hero(name="Spider-Boy", secret_name="Pedro Parqueador", food="pizza")
34 )
35 session.add(Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)) 1abcdefghi
37 session.commit() 1abcdefghi
39 # check typing of select with 3 fields
40 with Session(engine) as session: 1abcdefghi
41 statement_3 = select(col(Hero.id), Hero.name, Hero.secret_name) 1abcdefghi
42 results_3 = session.exec(statement_3) 1abcdefghi
43 assert_type(results_3, TupleResult[tuple[int | None, str, str]]) 1abcdefghi
44 for hero_3 in results_3: 1abcdefghi
45 assert len(hero_3) == 3 1abcdefghi
46 name_3: str = hero_3[1] 1abcdefghi
47 assert type(name_3) is str 1abcdefghi
48 assert type(hero_3[0]) is int 1abcdefghi
49 assert type(hero_3[2]) is str 1abcdefghi
51 # check typing of select with 4 fields
52 with Session(engine) as session: 1abcdefghi
53 statement_4 = select(col(Hero.id), Hero.name, Hero.secret_name, col(Hero.age)) 1abcdefghi
54 results_4 = session.exec(statement_4) 1abcdefghi
55 assert_type(results_4, TupleResult[tuple[int | None, str, str, int | None]]) 1abcdefghi
56 for hero_4 in results_4: 1abcdefghi
57 assert len(hero_4) == 4 1abcdefghi
58 name_4: str = hero_4[1] 1abcdefghi
59 assert type(name_4) is str 1abcdefghi
60 assert type(hero_4[0]) is int 1abcdefghi
61 assert type(hero_4[2]) is str 1abcdefghi
62 assert type(hero_4[3]) in [int, type(None)] 1abcdefghi
64 # check typing of select with 5 fields: currently runs but doesn't pass mypy
65 # with Session(engine) as session:
66 # statement_5 = select(Hero.id, Hero.name, Hero.secret_name, Hero.age, Hero.food)
67 # results_5 = session.exec(statement_5)
68 # for hero_5 in results_5:
69 # assert len(hero_5) == 5
70 # name_5: str = hero_5[1]
71 # assert type(name_5) is str
72 # assert type(hero_5[0]) is int
73 # assert type(hero_5[2]) is str
74 # assert type(hero_5[3]) in [int, type(None)]
75 # assert type(hero_5[4]) in [str, type(None)]
78def test_scalar_results(database_engine: Engine) -> None: 1BCDEFGHIJ
79 class Hero(SQLModel, table=True): 1jklmnopqr
80 id: int | None = Field(default=None, primary_key=True) 1jklmnopqr
81 name: str 1jklmnopqr
83 SQLModel.metadata.create_all(database_engine) 1jklmnopqr
84 with Session(database_engine) as session: 1jklmnopqr
85 session.add(Hero(name="Deadpond")) 1jklmnopqr
86 session.commit() 1jklmnopqr
88 statement = select(Hero) 1jklmnopqr
89 result = session.exec(statement) 1jklmnopqr
90 assert_type(result, ScalarResult[Hero]) 1jklmnopqr
91 assert result.one().name == "Deadpond" 1jklmnopqr
93 scalars = session.scalars(statement) 1jklmnopqr
94 assert_type(scalars, ScalarResult[Hero]) 1jklmnopqr
95 assert scalars.one().name == "Deadpond" 1jklmnopqr
97 scalar_subquery = ( 1jklmnopqr
98 select(Hero.name)
99 .where(Hero.name == "Deadpond")
100 .group_by(Hero.name)
101 .having(Hero.name == "Deadpond")
102 .scalar_subquery()
103 )
104 name = session.exec(select(scalar_subquery)).one() 1jklmnopqr
105 assert_type(name, str) 1jklmnopqr
106 assert name == "Deadpond" 1jklmnopqr
109def test_ordering_types() -> None: 1BCDEFGHIJ
110 class Hero(SQLModel, table=True): 1stuvwxyzA
111 id: int = Field(primary_key=True) 1stuvwxyzA
112 name: str 1stuvwxyzA
114 ascending = asc(Hero.id) 1stuvwxyzA
115 assert_type(ascending, UnaryExpression[int]) 1stuvwxyzA
116 assert str(ascending) == "hero.id ASC" 1stuvwxyzA
118 descending = desc(Hero.id) 1stuvwxyzA
119 assert_type(descending, UnaryExpression[int]) 1stuvwxyzA
120 assert str(descending) == "hero.id DESC" 1stuvwxyzA
122 first = nulls_first(Hero.name) 1stuvwxyzA
123 assert_type(first, UnaryExpression[str]) 1stuvwxyzA
124 assert str(first) == "hero.name NULLS FIRST" 1stuvwxyzA
126 last = nulls_last(Hero.name) 1stuvwxyzA
127 assert_type(last, UnaryExpression[str]) 1stuvwxyzA
128 assert str(last) == "hero.name NULLS LAST" 1stuvwxyzA