@@ -239,6 +239,29 @@ def test_select_with_limit(self):
239239 assert execution_plan .limit_stage == 10
240240 assert execution_plan .projection_stage == {"name" : 1 }
241241
242+ def test_select_with_offset (self ):
243+ """Test SELECT with OFFSET clause"""
244+ sql = "SELECT name FROM users OFFSET 5"
245+ parser = SQLParser (sql )
246+
247+ assert not parser .has_errors , f"Parser errors: { parser .errors } "
248+ execution_plan = parser .get_execution_plan ()
249+ assert execution_plan .collection == "users"
250+ assert execution_plan .skip_stage == 5
251+ assert execution_plan .projection_stage == {"name" : 1 }
252+
253+ def test_select_with_limit_and_offset (self ):
254+ """Test SELECT with both LIMIT and OFFSET clauses"""
255+ sql = "SELECT name, email FROM users LIMIT 10 OFFSET 5"
256+ parser = SQLParser (sql )
257+
258+ assert not parser .has_errors , f"Parser errors: { parser .errors } "
259+ execution_plan = parser .get_execution_plan ()
260+ assert execution_plan .collection == "users"
261+ assert execution_plan .limit_stage == 10
262+ assert execution_plan .skip_stage == 5
263+ assert execution_plan .projection_stage == {"name" : 1 , "email" : 1 }
264+
242265 def test_complex_query_combination (self ):
243266 """Test complex query with multiple clauses"""
244267 sql = """
@@ -277,83 +300,6 @@ def test_parser_error_handling(self):
277300 parser = SQLParser ("INVALID SQL SYNTAX" )
278301 parser .get_execution_plan ()
279302
280- def test_select_with_as_aliases (self ):
281- """Test SELECT with AS aliases"""
282- sql = "SELECT name AS username, email AS user_email FROM customers"
283- parser = SQLParser (sql )
284-
285- assert not parser .has_errors , f"Parser errors: { parser .errors } "
286-
287- execution_plan = parser .get_execution_plan ()
288- assert execution_plan .collection == "customers"
289- assert execution_plan .filter_stage == {}
290- assert execution_plan .projection_stage == {
291- "name" : 1 ,
292- "email" : 1 ,
293- }
294-
295- def test_select_with_mixed_aliases (self ):
296- """Test SELECT with mixed alias formats"""
297- sql = "SELECT name AS username, age user_age, status FROM users"
298- parser = SQLParser (sql )
299-
300- assert not parser .has_errors , f"Parser errors: { parser .errors } "
301-
302- execution_plan = parser .get_execution_plan ()
303- assert execution_plan .collection == "users"
304- assert execution_plan .filter_stage == {}
305- assert execution_plan .projection_stage == {
306- "name" : 1 , # AS alias
307- "age" : 1 , # Space-separated alias
308- "status" : 1 , # No alias (field included)
309- }
310-
311- def test_select_with_space_separated_aliases (self ):
312- """Test SELECT with space-separated aliases"""
313- sql = "SELECT first_name fname, last_name lname, created_at creation_date FROM users"
314- parser = SQLParser (sql )
315-
316- assert not parser .has_errors , f"Parser errors: { parser .errors } "
317-
318- execution_plan = parser .get_execution_plan ()
319- assert execution_plan .collection == "users"
320- assert execution_plan .filter_stage == {}
321- assert execution_plan .projection_stage == {
322- "first_name" : 1 ,
323- "last_name" : 1 ,
324- "created_at" : 1 ,
325- }
326-
327- def test_select_with_complex_field_names_and_aliases (self ):
328- """Test SELECT with complex field names and aliases"""
329- sql = "SELECT user_profile.name AS display_name, account_settings.theme user_theme FROM users"
330- parser = SQLParser (sql )
331-
332- assert not parser .has_errors , f"Parser errors: { parser .errors } "
333-
334- execution_plan = parser .get_execution_plan ()
335- assert execution_plan .collection == "users"
336- assert execution_plan .filter_stage == {}
337- assert execution_plan .projection_stage == {
338- "user_profile.name" : 1 ,
339- "account_settings.theme" : 1 ,
340- }
341-
342- def test_select_function_with_aliases (self ):
343- """Test SELECT with functions and aliases"""
344- sql = "SELECT COUNT(*) AS total_count, MAX(age) max_age FROM users"
345- parser = SQLParser (sql )
346-
347- assert not parser .has_errors , f"Parser errors: { parser .errors } "
348-
349- execution_plan = parser .get_execution_plan ()
350- assert execution_plan .collection == "users"
351- assert execution_plan .filter_stage == {}
352- assert execution_plan .projection_stage == {
353- "COUNT(*)" : 1 ,
354- "MAX(age)" : 1 ,
355- }
356-
357303 def test_superset_wrapped_subquery (self ):
358304 """Support Superset wrapping subquery with alias 'virtual'"""
359305 sql = "SELECT virtual.a, virtual.b FROM (SELECT a, b FROM users WHERE c = 1) virtual"
@@ -369,49 +315,6 @@ def test_superset_wrapped_subquery(self):
369315 # Inner filter should be preserved
370316 assert execution_plan .filter_stage == {"c" : 1 }
371317
372- def test_select_single_field_with_alias (self ):
373- """Test SELECT with single field and alias"""
374- sql = "SELECT email AS contact_email FROM customers"
375- parser = SQLParser (sql )
376-
377- assert not parser .has_errors , f"Parser errors: { parser .errors } "
378-
379- execution_plan = parser .get_execution_plan ()
380- assert execution_plan .collection == "customers"
381- assert execution_plan .filter_stage == {}
382- assert execution_plan .projection_stage == {"email" : 1 }
383-
384- def test_select_aliases_with_where_clause (self ):
385- """Test SELECT with aliases and WHERE clause"""
386- sql = "SELECT name AS username, status AS account_status FROM users WHERE age > 18"
387- parser = SQLParser (sql )
388-
389- assert not parser .has_errors , f"Parser errors: { parser .errors } "
390-
391- execution_plan = parser .get_execution_plan ()
392- assert execution_plan .collection == "users"
393- assert execution_plan .filter_stage == {"age" : {"$gt" : 18 }}
394- assert execution_plan .projection_stage == {
395- "name" : 1 ,
396- "status" : 1 ,
397- }
398-
399- def test_select_case_insensitive_as_alias (self ):
400- """Test SELECT with case insensitive AS keyword"""
401- sql = "SELECT name as username, email As user_email, status AS account_status FROM users"
402- parser = SQLParser (sql )
403-
404- assert not parser .has_errors , f"Parser errors: { parser .errors } "
405-
406- execution_plan = parser .get_execution_plan ()
407- assert execution_plan .collection == "users"
408- assert execution_plan .filter_stage == {}
409- assert execution_plan .projection_stage == {
410- "name" : 1 ,
411- "email" : 1 ,
412- "status" : 1 ,
413- }
414-
415318 def test_different_collection_names (self ):
416319 """Test parsing with different collection names"""
417320 test_cases = [
0 commit comments