Skip to content

Commit 4861c20

Browse files
committed
Fix order by primaary_key by defualt, add pagination tests for IRIS, covering single table, ordered pagination, joins, and total count
1 parent 056b8db commit 4861c20

File tree

2 files changed

+170
-1
lines changed

2 files changed

+170
-1
lines changed

sqlalchemy_iris/base.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,17 @@ def translate_select_structure(self, select_stmt, **kwargs):
550550
for elem in select._order_by_clause.clauses
551551
]
552552
if not _order_by_clauses:
553-
_order_by_clauses = [text("%id")]
553+
# If no ORDER BY clause, use the primary key
554+
if select_stmt.froms and isinstance(select_stmt.froms[0], schema.Table):
555+
table = select.froms[0]
556+
if table.primary_key and table.primary_key.columns:
557+
_order_by_clauses = [
558+
sql_util.unwrap_label_reference(c)
559+
for c in table.primary_key.columns
560+
]
561+
else:
562+
# If no primary key, use the id column
563+
_order_by_clauses = [text("%id")]
554564

555565
limit_clause = self._get_limit_or_fetch(select)
556566
offset_clause = select._offset_clause

tests/test_suite.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,3 +515,162 @@ def test_add_table_comment(self, connection):
515515

516516
def test_drop_table_comment(self, connection):
517517
pass
518+
519+
class IRISPaginationTest(fixtures.TablesTest):
520+
521+
@classmethod
522+
def define_tables(cls, metadata):
523+
Table(
524+
"data",
525+
metadata,
526+
Column("id", Integer, primary_key=True),
527+
Column("value", String(50)),
528+
)
529+
Table(
530+
"users",
531+
metadata,
532+
Column("user_id", Integer, primary_key=True),
533+
Column("username", String(30)),
534+
Column("email", String(100)),
535+
)
536+
537+
@classmethod
538+
def insert_data(cls, connection):
539+
connection.execute(
540+
cls.tables.data.insert(),
541+
[
542+
{"id": i, "value": f"value_{i}"} for i in range(1, 21)
543+
],
544+
)
545+
connection.execute(
546+
cls.tables.users.insert(),
547+
[
548+
{"user_id": i, "username": f"user_{i}", "email": f"user_{i}@example.com"}
549+
for i in range(1, 31)
550+
],
551+
)
552+
553+
def test_pagination_single_table(self):
554+
"""Test basic pagination on single table"""
555+
with config.db.connect() as conn:
556+
# Test first page
557+
result = conn.execute(
558+
select(self.tables.data).limit(10).offset(0)
559+
).fetchall()
560+
assert len(result) == 10
561+
assert result[0].value == "value_1"
562+
assert result[9].value == "value_10"
563+
564+
# Test second page
565+
result = conn.execute(
566+
select(self.tables.data).limit(10).offset(10)
567+
).fetchall()
568+
assert len(result) == 10
569+
assert result[0].value == "value_11"
570+
assert result[9].value == "value_20"
571+
572+
def test_pagination_with_order(self):
573+
"""Test pagination with explicit ordering"""
574+
with config.db.connect() as conn:
575+
# Test ordered pagination on users table by user_id (numeric order)
576+
result = conn.execute(
577+
select(self.tables.users)
578+
.order_by(self.tables.users.c.user_id)
579+
.limit(5)
580+
.offset(0)
581+
).fetchall()
582+
assert len(result) == 5
583+
assert result[0].username == "user_1"
584+
assert result[4].username == "user_5"
585+
586+
# Test second page with ordering
587+
result = conn.execute(
588+
select(self.tables.users)
589+
.order_by(self.tables.users.c.user_id)
590+
.limit(5)
591+
.offset(5)
592+
).fetchall()
593+
assert len(result) == 5
594+
assert result[0].username == "user_6"
595+
assert result[4].username == "user_10"
596+
597+
def test_pagination_two_tables_join(self):
598+
"""Test pagination with JOIN between two tables"""
599+
with config.db.connect() as conn:
600+
# Create a join query with pagination
601+
# Join where data.id matches user.user_id for first 20 records
602+
query = (
603+
select(
604+
self.tables.data.c.value,
605+
self.tables.users.c.username,
606+
self.tables.users.c.email
607+
)
608+
.select_from(
609+
self.tables.data.join(
610+
self.tables.users,
611+
self.tables.data.c.id == self.tables.users.c.user_id
612+
)
613+
)
614+
.order_by(self.tables.data.c.id)
615+
.limit(5)
616+
.offset(5)
617+
)
618+
619+
result = conn.execute(query).fetchall()
620+
assert len(result) == 5
621+
assert result[0].value == "value_6"
622+
assert result[0].username == "user_6"
623+
assert result[4].value == "value_10"
624+
assert result[4].username == "user_10"
625+
626+
def test_pagination_large_offset(self):
627+
"""Test pagination with larger offset values"""
628+
with config.db.connect() as conn:
629+
# Test pagination near the end of users table
630+
result = conn.execute(
631+
select(self.tables.users)
632+
.order_by(self.tables.users.c.user_id)
633+
.limit(5)
634+
.offset(25)
635+
).fetchall()
636+
assert len(result) == 5
637+
assert result[0].user_id == 26
638+
assert result[4].user_id == 30
639+
640+
# Test offset beyond available data
641+
result = conn.execute(
642+
select(self.tables.users)
643+
.order_by(self.tables.users.c.user_id)
644+
.limit(10)
645+
.offset(35)
646+
).fetchall()
647+
assert len(result) == 0
648+
649+
def test_pagination_count_total(self):
650+
"""Test getting total count for pagination metadata"""
651+
with config.db.connect() as conn:
652+
# Get total count of data table
653+
total_data = conn.execute(
654+
select(func.count()).select_from(self.tables.data)
655+
).scalar()
656+
assert total_data == 20
657+
658+
# Get total count of users table
659+
total_users = conn.execute(
660+
select(func.count()).select_from(self.tables.users)
661+
).scalar()
662+
assert total_users == 30
663+
664+
# Verify pagination math
665+
page_size = 7
666+
total_pages_data = (total_data + page_size - 1) // page_size
667+
assert total_pages_data == 3 # 20 records / 7 per page = 3 pages
668+
669+
# Test last page
670+
result = conn.execute(
671+
select(self.tables.data)
672+
.order_by(self.tables.data.c.id)
673+
.limit(page_size)
674+
.offset((total_pages_data - 1) * page_size)
675+
).fetchall()
676+
assert len(result) == 6 # Last page has 6 records (20 - 14)

0 commit comments

Comments
 (0)