Skip to content

Commit 224653f

Browse files
committed
implement autoscroll for all fetches
1 parent 0235c2c commit 224653f

File tree

3 files changed

+247
-76
lines changed

3 files changed

+247
-76
lines changed

tests/conftest.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -151,18 +151,17 @@ async def session_pool(
151151
) -> AsyncGenerator[ydb.aio.QuerySessionPool]:
152152
session_pool = ydb.aio.QuerySessionPool(driver)
153153
async with session_pool:
154-
await session_pool.execute_with_retries(
155-
"""DROP TABLE IF EXISTS table"""
156-
)
157-
await session_pool.execute_with_retries(
158-
"""
159-
CREATE TABLE table (
160-
id Int64 NOT NULL,
161-
val Int64,
162-
PRIMARY KEY(id)
154+
for name in ["table", "table1", "table2"]:
155+
await session_pool.execute_with_retries(
156+
f"""
157+
DROP TABLE IF EXISTS {name};
158+
CREATE TABLE {name} (
159+
id Int64 NOT NULL,
160+
val Int64,
161+
PRIMARY KEY(id)
162+
)
163+
"""
163164
)
164-
"""
165-
)
166165

167166
yield session_pool
168167

@@ -173,14 +172,16 @@ def session_pool_sync(
173172
) -> Generator[ydb.QuerySessionPool]:
174173
session_pool = ydb.QuerySessionPool(driver_sync)
175174
with session_pool:
176-
session_pool.execute_with_retries("""DROP TABLE IF EXISTS table""")
177-
session_pool.execute_with_retries(
178-
"""
179-
CREATE TABLE table (
180-
id Int64 NOT NULL,
181-
val Int64,
182-
PRIMARY KEY(id)
175+
for name in ["table", "table1", "table2"]:
176+
session_pool.execute_with_retries(
177+
f"""
178+
DROP TABLE IF EXISTS {name};
179+
CREATE TABLE {name} (
180+
id Int64 NOT NULL,
181+
val Int64,
182+
PRIMARY KEY(id)
183+
)
184+
"""
183185
)
184-
"""
185-
)
186+
186187
yield session_pool

tests/test_cursor.py

Lines changed: 166 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@
55
import ydb
66
import ydb_dbapi
77

8-
INSERT_YQL = """
9-
DELETE FROM table;
10-
INSERT INTO table (id, val) VALUES
11-
(1, 1),
12-
(2, 2),
13-
(3, 3),
14-
(4, 4)
15-
"""
16-
178

189
@pytest.fixture
1910
async def session(
2011
session_pool: ydb.aio.QuerySessionPool,
2112
) -> AsyncGenerator[ydb.aio.QuerySession]:
22-
await session_pool.execute_with_retries(INSERT_YQL)
13+
for name in ["table", "table1", "table2"]:
14+
await session_pool.execute_with_retries(
15+
f"""
16+
DELETE FROM {name};
17+
INSERT INTO {name} (id, val) VALUES
18+
(0, 0),
19+
(1, 1),
20+
(2, 2),
21+
(3, 3)
22+
"""
23+
)
2324

2425
session = await session_pool.acquire()
2526
yield session
@@ -30,13 +31,27 @@ async def session(
3031
def session_sync(
3132
session_pool_sync: ydb.QuerySessionPool,
3233
) -> Generator[ydb.QuerySession]:
33-
session_pool_sync.execute_with_retries(INSERT_YQL)
34+
for name in ["table", "table1", "table2"]:
35+
session_pool_sync.execute_with_retries(
36+
f"""
37+
DELETE FROM {name};
38+
INSERT INTO {name} (id, val) VALUES
39+
(0, 0),
40+
(1, 1),
41+
(2, 2),
42+
(3, 3)
43+
"""
44+
)
3445

3546
session = session_pool_sync.acquire()
3647
yield session
3748
session_pool_sync.release(session)
3849

3950

51+
RESULT_SET_LENGTH = 4
52+
RESULT_SET_COUNT = 3
53+
54+
4055
class TestAsyncCursor:
4156
@pytest.mark.asyncio
4257
async def test_cursor_fetch_one(
@@ -48,10 +63,10 @@ async def test_cursor_fetch_one(
4863
"""
4964
await cursor.execute(query=yql_text)
5065

51-
for i in range(4):
66+
for i in range(RESULT_SET_LENGTH):
5267
res = await cursor.fetchone()
5368
assert res is not None
54-
assert res[0] == i + 1
69+
assert res[0] == i
5570

5671
assert await cursor.fetchone() is None
5772

@@ -68,20 +83,20 @@ async def test_cursor_fetch_many(
6883
res = await cursor.fetchmany()
6984
assert res is not None
7085
assert len(res) == 1
71-
assert res[0][0] == 1
86+
assert res[0][0] == 0
7287

7388
res = await cursor.fetchmany(size=2)
7489
assert res is not None
7590
assert len(res) == 2
76-
assert res[0][0] == 2
77-
assert res[1][0] == 3
91+
assert res[0][0] == 1
92+
assert res[1][0] == 2
7893

7994
res = await cursor.fetchmany(size=2)
8095
assert res is not None
8196
assert len(res) == 1
82-
assert res[0][0] == 4
97+
assert res[0][0] == 3
8398

84-
assert await cursor.fetchmany(size=2) is None
99+
assert await cursor.fetchmany(size=2) == []
85100

86101
@pytest.mark.asyncio
87102
async def test_cursor_fetch_all(
@@ -93,15 +108,15 @@ async def test_cursor_fetch_all(
93108
"""
94109
await cursor.execute(query=yql_text)
95110

96-
assert cursor.rowcount == 4
111+
assert cursor.rowcount == RESULT_SET_LENGTH
97112

98113
res = await cursor.fetchall()
99114
assert res is not None
100-
assert len(res) == 4
101-
for i in range(4):
102-
assert res[i][0] == i + 1
115+
assert len(res) == RESULT_SET_LENGTH
116+
for i in range(RESULT_SET_LENGTH):
117+
assert res[i][0] == i
103118

104-
assert await cursor.fetchall() is None
119+
assert await cursor.fetchall() == []
105120

106121
@pytest.mark.asyncio
107122
async def test_cursor_next_set(
@@ -127,11 +142,77 @@ async def test_cursor_next_set(
127142
nextset = await cursor.nextset()
128143
assert nextset
129144

130-
assert await cursor.fetchall() is None
145+
assert await cursor.fetchall() == []
131146

132147
nextset = await cursor.nextset()
133148
assert not nextset
134149

150+
@pytest.mark.asyncio
151+
async def test_cursor_fetch_one_autoscroll(
152+
self, session: ydb.aio.QuerySession
153+
) -> None:
154+
async with ydb_dbapi.AsyncCursor(
155+
session=session, auto_scroll_result_sets=True
156+
) as cursor:
157+
yql_text = """
158+
SELECT id, val FROM table;
159+
SELECT id, val FROM table1;
160+
SELECT id, val FROM table2;
161+
"""
162+
await cursor.execute(query=yql_text)
163+
164+
for i in range(RESULT_SET_LENGTH * RESULT_SET_COUNT):
165+
res = await cursor.fetchone()
166+
assert res is not None
167+
assert res[0] == i % RESULT_SET_LENGTH
168+
169+
assert await cursor.fetchone() is None
170+
assert not await cursor.nextset()
171+
172+
@pytest.mark.asyncio
173+
async def test_cursor_fetch_many_autoscroll(
174+
self, session: ydb.aio.QuerySession
175+
) -> None:
176+
async with ydb_dbapi.AsyncCursor(
177+
session=session, auto_scroll_result_sets=True
178+
) as cursor:
179+
yql_text = """
180+
SELECT id, val FROM table;
181+
SELECT id, val FROM table1;
182+
SELECT id, val FROM table2;
183+
"""
184+
await cursor.execute(query=yql_text)
185+
186+
halfsize = (RESULT_SET_LENGTH * RESULT_SET_COUNT) // 2
187+
for _ in range(2):
188+
res = await cursor.fetchmany(size=halfsize)
189+
assert res is not None
190+
assert len(res) == halfsize
191+
192+
assert await cursor.fetchmany(2) == []
193+
assert not await cursor.nextset()
194+
195+
@pytest.mark.asyncio
196+
async def test_cursor_fetch_all_autoscroll(
197+
self, session: ydb.aio.QuerySession
198+
) -> None:
199+
async with ydb_dbapi.AsyncCursor(
200+
session=session, auto_scroll_result_sets=True
201+
) as cursor:
202+
yql_text = """
203+
SELECT id, val FROM table;
204+
SELECT id, val FROM table1;
205+
SELECT id, val FROM table2;
206+
"""
207+
await cursor.execute(query=yql_text)
208+
209+
res = await cursor.fetchall()
210+
211+
assert len(res) == RESULT_SET_COUNT * RESULT_SET_LENGTH
212+
213+
assert await cursor.fetchall() == []
214+
assert not await cursor.nextset()
215+
135216

136217
# The same test class as above but for Cursor
137218

@@ -147,7 +228,7 @@ def test_cursor_fetch_one(self, session_sync: ydb.QuerySession) -> None:
147228
for i in range(4):
148229
res = cursor.fetchone()
149230
assert res is not None
150-
assert res[0] == i + 1
231+
assert res[0] == i
151232

152233
assert cursor.fetchone() is None
153234

@@ -161,20 +242,20 @@ def test_cursor_fetch_many(self, session_sync: ydb.QuerySession) -> None:
161242
res = cursor.fetchmany()
162243
assert res is not None
163244
assert len(res) == 1
164-
assert res[0][0] == 1
245+
assert res[0][0] == 0
165246

166247
res = cursor.fetchmany(size=2)
167248
assert res is not None
168249
assert len(res) == 2
169-
assert res[0][0] == 2
170-
assert res[1][0] == 3
250+
assert res[0][0] == 1
251+
assert res[1][0] == 2
171252

172253
res = cursor.fetchmany(size=2)
173254
assert res is not None
174255
assert len(res) == 1
175-
assert res[0][0] == 4
256+
assert res[0][0] == 3
176257

177-
assert cursor.fetchmany(size=2) is None
258+
assert cursor.fetchmany(size=2) == []
178259

179260
def test_cursor_fetch_all(self, session_sync: ydb.QuerySession) -> None:
180261
with ydb_dbapi.Cursor(session=session_sync) as cursor:
@@ -189,9 +270,9 @@ def test_cursor_fetch_all(self, session_sync: ydb.QuerySession) -> None:
189270
assert res is not None
190271
assert len(res) == 4
191272
for i in range(4):
192-
assert res[i][0] == i + 1
273+
assert res[i][0] == i
193274

194-
assert cursor.fetchall() is None
275+
assert cursor.fetchall() == []
195276

196277
def test_cursor_next_set(self, session_sync: ydb.QuerySession) -> None:
197278
with ydb_dbapi.Cursor(session=session_sync) as cursor:
@@ -214,22 +295,70 @@ def test_cursor_next_set(self, session_sync: ydb.QuerySession) -> None:
214295
nextset = cursor.nextset()
215296
assert nextset
216297

217-
assert cursor.fetchall() is None
298+
assert cursor.fetchall() == []
218299

219300
nextset = cursor.nextset()
220301
assert not nextset
221302

222-
def test_cursor_autoscroll(self, session_sync: ydb.QuerySession) -> None:
303+
def test_cursor_fetch_one_autoscroll(
304+
self, session_sync: ydb.QuerySession
305+
) -> None:
223306
with ydb_dbapi.Cursor(
224307
session=session_sync, auto_scroll_result_sets=True
225308
) as cursor:
226-
yql_text = "SELECT 1 as val; SELECT 2 as val; SELECT 3 as val;"
309+
yql_text = """
310+
SELECT id, val FROM table;
311+
SELECT id, val FROM table1;
312+
SELECT id, val FROM table2;
313+
"""
227314
cursor.execute(query=yql_text)
228315

229-
for i in range(3):
316+
for i in range(RESULT_SET_LENGTH * RESULT_SET_COUNT):
230317
res = cursor.fetchone()
231318
assert res is not None
232-
assert res[0] == i + 1
319+
assert res[0] == i % RESULT_SET_LENGTH
233320

234321
assert cursor.fetchone() is None
235322
assert not cursor.nextset()
323+
324+
def test_cursor_fetch_many_autoscroll(
325+
self, session_sync: ydb.QuerySession
326+
) -> None:
327+
with ydb_dbapi.Cursor(
328+
session=session_sync, auto_scroll_result_sets=True
329+
) as cursor:
330+
yql_text = """
331+
SELECT id, val FROM table;
332+
SELECT id, val FROM table1;
333+
SELECT id, val FROM table2;
334+
"""
335+
cursor.execute(query=yql_text)
336+
337+
halfsize = (RESULT_SET_LENGTH * RESULT_SET_COUNT) // 2
338+
for _ in range(2):
339+
res = cursor.fetchmany(size=halfsize)
340+
assert res is not None
341+
assert len(res) == halfsize
342+
343+
assert cursor.fetchmany(2) == []
344+
assert not cursor.nextset()
345+
346+
def test_cursor_fetch_all_autoscroll(
347+
self, session_sync: ydb.QuerySession
348+
) -> None:
349+
with ydb_dbapi.Cursor(
350+
session=session_sync, auto_scroll_result_sets=True
351+
) as cursor:
352+
yql_text = """
353+
SELECT id, val FROM table;
354+
SELECT id, val FROM table1;
355+
SELECT id, val FROM table2;
356+
"""
357+
cursor.execute(query=yql_text)
358+
359+
res = cursor.fetchall()
360+
361+
assert len(res) == RESULT_SET_COUNT * RESULT_SET_LENGTH
362+
363+
assert cursor.fetchall() == []
364+
assert not cursor.nextset()

0 commit comments

Comments
 (0)