File tree Expand file tree Collapse file tree 9 files changed +125
-8
lines changed
Expand file tree Collapse file tree 9 files changed +125
-8
lines changed Original file line number Diff line number Diff line change @@ -8,6 +8,7 @@ Query Clauses
88
99 ./first
1010 ./limit
11+ ./offset
1112 ./order_by
1213 ./where
1314 ./batch
Original file line number Diff line number Diff line change 1+ .. _offset :
2+
3+ offset
4+ ======
5+
6+ You can use ``offset `` clauses with the following queries:
7+
8+ * :ref: `Objects `
9+ * :ref: `Select `
10+
11+ This will omit the first X rows from the response. It's useful for things like
12+ pagination.
13+
14+ It's highly recommended to use it along with an :ref: `order_by ` clause,
15+ otherwise the results returned could be different each time.
16+
17+ .. code-block :: python
18+
19+ >> > Band.select(Band.name).offset(1 ).order_by(Band.name).run_sync()
20+ [{' name' : ' Pythonistas' }, {' name' : ' Rustaceans' }]
21+
22+ Likewise, with objects:
23+
24+ .. code-block :: python
25+
26+ >> > Band.objects().offset(1 ).order_by(Band.name).run_sync()
27+ [Band2, Band3]
Original file line number Diff line number Diff line change 8484
8585See :ref: `limit `.
8686
87+ offset
88+ ~~~~~~
89+
90+ See :ref: `offset `.
91+
8792first
8893~~~~~
8994
Original file line number Diff line number Diff line change @@ -119,6 +119,11 @@ limit
119119
120120See :ref: `limit `.
121121
122+ offset
123+ ~~~~~~
124+
125+ See :ref: `offset `.
126+
122127order_by
123128~~~~~~~~
124129
Original file line number Diff line number Diff line change 66from piccolo .query .base import Query
77from piccolo .query .mixins import (
88 LimitDelegate ,
9+ OffsetDelegate ,
910 OrderByDelegate ,
1011 WhereDelegate ,
1112 OutputDelegate ,
@@ -26,13 +27,15 @@ class Objects(Query):
2627
2728 __slots__ = (
2829 "limit_delegate" ,
30+ "offset_delegate" ,
2931 "order_by_delegate" ,
3032 "output_delegate" ,
3133 "where_delegate" ,
3234 )
3335
3436 def _setup_delegates (self ):
3537 self .limit_delegate = LimitDelegate ()
38+ self .offset_delegate = OffsetDelegate ()
3639 self .order_by_delegate = OrderByDelegate ()
3740 self .output_delegate = OutputDelegate ()
3841 self .output_delegate ._output .as_objects = True
@@ -46,6 +49,10 @@ def first(self) -> Objects:
4649 self .limit_delegate .first ()
4750 return self
4851
52+ def offset (self , number : int ) -> Objects :
53+ self .offset_delegate .offset (number )
54+ return self
55+
4956 def order_by (self , * columns : Column , ascending = True ) -> Objects :
5057 self .order_by_delegate .order_by (* columns , ascending = ascending )
5158 return self
@@ -77,6 +84,7 @@ def querystring(self) -> QueryString:
7784 for attr in (
7885 "limit_delegate" ,
7986 "where_delegate" ,
87+ "offset_delegate" ,
8088 "output_delegate" ,
8189 "order_by_delegate" ,
8290 ):
Original file line number Diff line number Diff line change 1010 ColumnsDelegate ,
1111 DistinctDelegate ,
1212 LimitDelegate ,
13+ OffsetDelegate ,
1314 OrderByDelegate ,
1415 OutputDelegate ,
1516 WhereDelegate ,
@@ -27,6 +28,7 @@ class Select(Query):
2728 "columns_delegate" ,
2829 "distinct_delegate" ,
2930 "limit_delegate" ,
31+ "offset_delegate" ,
3032 "order_by_delegate" ,
3133 "output_delegate" ,
3234 "where_delegate" ,
@@ -45,6 +47,7 @@ def _setup_delegates(self):
4547 self .columns_delegate = ColumnsDelegate ()
4648 self .distinct_delegate = DistinctDelegate ()
4749 self .limit_delegate = LimitDelegate ()
50+ self .offset_delegate = OffsetDelegate ()
4851 self .order_by_delegate = OrderByDelegate ()
4952 self .output_delegate = OutputDelegate ()
5053 self .where_delegate = WhereDelegate ()
@@ -66,6 +69,10 @@ def first(self) -> Select:
6669 self .limit_delegate .first ()
6770 return self
6871
72+ def offset (self , number : int ) -> Select :
73+ self .offset_delegate .offset (number )
74+ return self
75+
6976 async def response_handler (self , response ):
7077 if self .limit_delegate ._first :
7178 if len (response ) == 0 :
@@ -210,6 +217,10 @@ def querystring(self) -> QueryString:
210217 query += " {}"
211218 args .append (self .limit_delegate ._limit .querystring )
212219
220+ if self .offset_delegate ._offset :
221+ query += " {}"
222+ args .append (self .offset_delegate ._offset .querystring )
223+
213224 querystring = QueryString (query , * args )
214225
215226 return querystring
Original file line number Diff line number Diff line change @@ -28,6 +28,24 @@ def __str__(self) -> str:
2828 return self .querystring .__str__ ()
2929
3030
31+ @dataclass
32+ class Offset :
33+ __slots__ = ("number" ,)
34+
35+ number : int
36+
37+ def __post_init__ (self ):
38+ if type (self .number ) != int :
39+ raise TypeError ("Limit must be an integer" )
40+
41+ @property
42+ def querystring (self ) -> QueryString :
43+ return QueryString (f" OFFSET { self .number } " )
44+
45+ def __str__ (self ) -> str :
46+ return self .querystring .__str__ ()
47+
48+
3149@dataclass
3250class OrderBy :
3351 __slots__ = ("columns" , "ascending" )
@@ -192,3 +210,21 @@ class ValuesDelegate:
192210
193211 def values (self , values : t .Dict [Column , t .Any ]):
194212 self ._values .update (values )
213+
214+
215+ @dataclass
216+ class OffsetDelegate :
217+ """
218+ Used to offset the results - for example, to return row 100 and onward.
219+
220+ Typically used in conjunction with order_by and limit.
221+
222+ Example usage:
223+
224+ .offset(100)
225+ """
226+
227+ _offset : t .Optional [Offset ] = None
228+
229+ def offset (self , number : int = 0 ):
230+ self ._offset = Offset (number )
Original file line number Diff line number Diff line change 33
44
55class TestObjects (DBTestCase ):
6-
76 def test_get_all (self ):
87 self .insert_row ()
98
@@ -14,17 +13,25 @@ def test_get_all(self):
1413 instance = response [0 ]
1514
1615 self .assertTrue (isinstance (instance , Band ))
17- self .assertTrue (instance .name == ' Pythonistas' )
16+ self .assertTrue (instance .name == " Pythonistas" )
1817
1918 # Now try changing the value and saving it.
20- instance .name = ' Rustaceans'
19+ instance .name = " Rustaceans"
2120 save_query = instance .save ()
2221 save_query .run_sync ()
2322
2423 self .assertTrue (
25- Band .select ().columns (
26- Band .name
27- ).output (
28- as_list = True
29- ).run_sync ()[0 ] == 'Rustaceans'
24+ Band .select ().columns (Band .name ).output (as_list = True ).run_sync ()[0 ]
25+ == "Rustaceans"
26+ )
27+
28+ def test_offset (self ):
29+ self .insert_rows ()
30+
31+ response = Band .objects ().order_by (Band .name ).offset (1 ).run_sync ()
32+
33+ print (f"response = { response } " )
34+
35+ self .assertEqual (
36+ [i .name for i in response ], ["Pythonistas" , "Rustaceans" ]
3037 )
Original file line number Diff line number Diff line change @@ -218,6 +218,23 @@ def test_limit(self):
218218
219219 self .assertEqual (response , [{"name" : "CSharps" }])
220220
221+ def test_offset (self ):
222+ self .insert_rows ()
223+
224+ response = (
225+ Band .select ()
226+ .columns (Band .name )
227+ .order_by (Band .name )
228+ .offset (1 )
229+ .run_sync ()
230+ )
231+
232+ print (f"response = { response } " )
233+
234+ self .assertEqual (
235+ response , [{"name" : "Pythonistas" }, {"name" : "Rustaceans" }]
236+ )
237+
221238 def test_first (self ):
222239 self .insert_rows ()
223240
You can’t perform that action at this time.
0 commit comments