Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
Limit/offset special case with no defined order by
Browse files Browse the repository at this point in the history
  • Loading branch information
Julius de Bruijn committed May 12, 2020
1 parent 923832b commit 3838d16
Showing 1 changed file with 87 additions and 4 deletions.
91 changes: 87 additions & 4 deletions src/visitor/mssql.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use super::Visitor;
use crate::{
ast::{OnConflict, Row, Values},
ast::{Column, OnConflict, Order, Ordering, Row, Values},
Value,
};
use std::fmt::{self, Write};

pub struct Mssql<'a> {
query: String,
parameters: Vec<Value<'a>>,
order_by_set: bool,
}

impl<'a> Visitor<'a> for Mssql<'a> {
Expand All @@ -21,6 +22,7 @@ impl<'a> Visitor<'a> for Mssql<'a> {
let mut this = Mssql {
query: String::with_capacity(4096),
parameters: Vec::with_capacity(128),
order_by_set: false,
};

Mssql::visit_query(&mut this, query.into());
Expand All @@ -37,25 +39,40 @@ impl<'a> Visitor<'a> for Mssql<'a> {
}

fn visit_limit_and_offset(&mut self, limit: Option<Value<'a>>, offset: Option<Value<'a>>) -> fmt::Result {
let add_ordering = |this: &mut Self| {
if !this.order_by_set {
this.write(" ORDER BY ")?;
this.visit_ordering(Ordering::new(vec![(Column::from("1").into(), None)]))?;
}

Ok::<(), fmt::Error>(())
};

match (limit, offset) {
(Some(limit), Some(offset)) => {
add_ordering(self)?;

self.write(" OFFSET ")?;
self.visit_parameterized(offset)?;
self.write(" ROWS FETCH NEXT ")?;
self.visit_parameterized(limit)?;
self.write(" ROWS ONLY ")
self.write(" ROWS ONLY")
}
(None, Some(offset)) => {
add_ordering(self)?;

self.write(" OFFSET ")?;
self.visit_parameterized(offset)?;
self.write(" ROWS ")
self.write(" ROWS")
}
(Some(limit), None) => {
add_ordering(self)?;

self.write(" OFFSET ")?;
self.visit_parameterized(Value::from(0))?;
self.write(" ROWS FETCH NEXT ")?;
self.visit_parameterized(limit)?;
self.write(" ROWS ONLY ")
self.write(" ROWS ONLY")
}
(None, None) => Ok(()),
}
Expand Down Expand Up @@ -147,6 +164,28 @@ impl<'a> Visitor<'a> for Mssql<'a> {
Ok(())
})
}

fn visit_ordering(&mut self, ordering: Ordering<'a>) -> fmt::Result {
let len = ordering.0.len();

for (i, (value, ordering)) in ordering.0.into_iter().enumerate() {
let direction = ordering.map(|dir| match dir {
Order::Asc => " ASC",
Order::Desc => " DESC",
});

self.visit_expression(value)?;
self.write(direction.unwrap_or(""))?;

if i < (len - 1) {
self.write(", ")?;
}
}

self.order_by_set = true;

Ok(())
}
}

#[cfg(test)]
Expand Down Expand Up @@ -552,4 +591,48 @@ mod tests {

assert_eq!(expected_sql, sql);
}

#[test]
fn test_limit_with_no_offset() {
let expected_sql = "SELECT foo FROM bar ORDER BY id OFFSET @P1 ROWS FETCH NEXT @P2 ROWS ONLY";
let query = Select::from_table("bar").column("foo").order_by("id").limit(10);
let (sql, params) = Mssql::build(query);

assert_eq!(expected_sql, sql);
assert_eq!(vec![Value::Integer(0), Value::Integer(10)], params);
}

#[test]
fn test_offset_no_limit() {
let expected_sql = "SELECT foo FROM bar ORDER BY id OFFSET @P1 ROWS";
let query = Select::from_table("bar").column("foo").order_by("id").offset(10);
let (sql, params) = Mssql::build(query);

assert_eq!(expected_sql, sql);
assert_eq!(vec![Value::Integer(10)], params);
}

#[test]
fn test_limit_with_offset() {
let expected_sql = "SELECT foo FROM bar ORDER BY id OFFSET @P1 ROWS FETCH NEXT @P2 ROWS ONLY";
let query = Select::from_table("bar")
.column("foo")
.order_by("id")
.limit(9)
.offset(10);
let (sql, params) = Mssql::build(query);

assert_eq!(expected_sql, sql);
assert_eq!(vec![Value::Integer(10), Value::Integer(9)], params);
}

#[test]
fn test_limit_with_offset_no_given_order() {
let expected_sql = "SELECT foo FROM bar ORDER BY 1 OFFSET @P1 ROWS FETCH NEXT @P2 ROWS ONLY";
let query = Select::from_table("bar").column("foo").limit(9).offset(10);
let (sql, params) = Mssql::build(query);

assert_eq!(expected_sql, sql);
assert_eq!(vec![Value::Integer(10), Value::Integer(9)], params);
}
}

0 comments on commit 3838d16

Please sign in to comment.