@@ -45,7 +45,7 @@ fn cypher_query(input: &str) -> IResult<&str, CypherQuery> {
4545 let ( input, where_clause) = opt ( where_clause) ( input) ?;
4646 let ( input, return_clause) = return_clause ( input) ?;
4747 let ( input, order_by) = opt ( order_by_clause) ( input) ?;
48- let ( input, limit) = opt ( limit_clause ) ( input) ?;
48+ let ( input, ( skip , limit) ) = pagination_clauses ( input) ?;
4949 let ( input, _) = multispace0 ( input) ?;
5050
5151 Ok ( (
@@ -56,6 +56,7 @@ fn cypher_query(input: &str) -> IResult<&str, CypherQuery> {
5656 return_clause,
5757 limit,
5858 order_by,
59+ skip,
5960 } ,
6061 ) )
6162}
@@ -389,6 +390,49 @@ fn limit_clause(input: &str) -> IResult<&str, u64> {
389390 Ok ( ( input, limit as u64 ) )
390391}
391392
393+ // Parse a SKIP clause
394+ fn skip_clause ( input : & str ) -> IResult < & str , u64 > {
395+ let ( input, _) = multispace0 ( input) ?;
396+ let ( input, _) = tag_no_case ( "SKIP" ) ( input) ?;
397+ let ( input, _) = multispace1 ( input) ?;
398+ let ( input, skip) = integer_literal ( input) ?;
399+
400+ Ok ( ( input, skip as u64 ) )
401+ }
402+
403+ // Parse pagination clauses (SKIP and LIMIT)
404+ fn pagination_clauses ( input : & str ) -> IResult < & str , ( Option < u64 > , Option < u64 > ) > {
405+ let ( mut remaining, _) = multispace0 ( input) ?;
406+ let mut skip: Option < u64 > = None ;
407+ let mut limit: Option < u64 > = None ;
408+
409+ loop {
410+ let before = remaining;
411+
412+ if skip. is_none ( ) {
413+ if let Ok ( ( i, s) ) = skip_clause ( remaining) {
414+ skip = Some ( s) ;
415+ remaining = i;
416+ continue ;
417+ }
418+ }
419+
420+ if limit. is_none ( ) {
421+ if let Ok ( ( i, l) ) = limit_clause ( remaining) {
422+ limit = Some ( l) ;
423+ remaining = i;
424+ continue ;
425+ }
426+ }
427+
428+ if before == remaining {
429+ break ;
430+ }
431+ }
432+
433+ Ok ( ( remaining, ( skip, limit) ) )
434+ }
435+
392436// Helper parsers
393437
394438// Parse an identifier
@@ -572,4 +616,41 @@ mod tests {
572616
573617 assert_eq ! ( result. limit, Some ( 10 ) ) ;
574618 }
619+
620+ #[ test]
621+ fn test_parse_query_with_skip ( ) {
622+ let query = "MATCH (n:Person) RETURN n.name SKIP 5" ;
623+ let result = parse_cypher_query ( query) . unwrap ( ) ;
624+
625+ assert_eq ! ( result. skip, Some ( 5 ) ) ;
626+ assert_eq ! ( result. limit, None ) ;
627+ }
628+
629+ #[ test]
630+ fn test_parse_query_with_skip_and_limit ( ) {
631+ let query = "MATCH (n:Person) RETURN n.name SKIP 5 LIMIT 10" ;
632+ let result = parse_cypher_query ( query) . unwrap ( ) ;
633+
634+ assert_eq ! ( result. skip, Some ( 5 ) ) ;
635+ assert_eq ! ( result. limit, Some ( 10 ) ) ;
636+ }
637+
638+ #[ test]
639+ fn test_parse_query_with_skip_and_order_by ( ) {
640+ let query = "MATCH (n:Person) RETURN n.name ORDER BY n.age SKIP 5" ;
641+ let result = parse_cypher_query ( query) . unwrap ( ) ;
642+
643+ assert_eq ! ( result. skip, Some ( 5 ) ) ;
644+ assert ! ( result. order_by. is_some( ) ) ;
645+ }
646+
647+ #[ test]
648+ fn test_parse_query_with_skip_order_by_and_limit ( ) {
649+ let query = "MATCH (n:Person) RETURN n.name ORDER BY n.age SKIP 5 LIMIT 10" ;
650+ let result = parse_cypher_query ( query) . unwrap ( ) ;
651+
652+ assert_eq ! ( result. skip, Some ( 5 ) ) ;
653+ assert_eq ! ( result. limit, Some ( 10 ) ) ;
654+ assert ! ( result. order_by. is_some( ) ) ;
655+ }
575656}
0 commit comments