Skip to content

Commit

Permalink
Merge pull request SeaQL#117 from nappa85/master
Browse files Browse the repository at this point in the history
Initial lock support
  • Loading branch information
tyt2y3 authored Aug 31, 2021
2 parents e177960 + a38696f commit 3312a1f
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/backend/query_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ pub trait QueryBuilder: QuotedBuilder {
write!(sql, " OFFSET ").unwrap();
self.prepare_value(offset, sql, collector);
}

if let Some(lock) = &select.lock {
write!(sql, " ").unwrap();
self.prepare_select_lock(lock, sql, collector);
}
}

/// Translate [`UpdateStatement`] into SQL statement.
Expand Down Expand Up @@ -338,6 +343,24 @@ pub trait QueryBuilder: QuotedBuilder {
.unwrap();
}

/// Translate [`LockType`] into SQL statement.
fn prepare_select_lock(
&self,
select_lock: &LockType,
sql: &mut SqlWriter,
_collector: &mut dyn FnMut(Value),
) {
write!(
sql,
"{}",
match select_lock {
LockType::Shared => "FOR SHARE",
LockType::Exclusive => "FOR UPDATE",
}
)
.unwrap();
}

/// Translate [`SelectExpr`] into SQL statement.
fn prepare_select_expr(
&self,
Expand Down
9 changes: 9 additions & 0 deletions src/backend/sqlite/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,13 @@ impl QueryBuilder for SqliteQueryBuilder {
fn char_length_function(&self) -> &str {
"LENGTH"
}

fn prepare_select_lock(
&self,
_select_lock: &LockType,
_sql: &mut SqlWriter,
_collector: &mut dyn FnMut(Value),
) {
// SQLite doesn't supports row locking
}
}
106 changes: 106 additions & 0 deletions src/query/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub struct SelectStatement {
pub(crate) orders: Vec<OrderExpr>,
pub(crate) limit: Option<Value>,
pub(crate) offset: Option<Value>,
pub(crate) lock: Option<LockType>,
}

/// List of distinct keywords that can be used in select statement
Expand Down Expand Up @@ -104,6 +105,7 @@ impl SelectStatement {
orders: Vec::new(),
limit: None,
offset: None,
lock: None,
}
}

Expand All @@ -120,6 +122,7 @@ impl SelectStatement {
orders: std::mem::take(&mut self.orders),
limit: self.limit.take(),
offset: self.offset.take(),
lock: self.lock.take(),
}
}

Expand Down Expand Up @@ -1268,6 +1271,102 @@ impl SelectStatement {
self.offset = None;
self
}

/// Row locking (if supported).
///
/// # Examples
///
/// ```
/// use sea_query::{*, tests_cfg::*};
///
/// let query = Query::select()
/// .column(Char::Character)
/// .from(Char::Table)
/// .and_where(Expr::col(Char::FontId).eq(5))
/// .lock(LockType::Exclusive)
/// .to_owned();
///
/// assert_eq!(
/// query.to_string(MysqlQueryBuilder),
/// r#"SELECT `character` FROM `character` WHERE `font_id` = 5 FOR UPDATE"#
/// );
/// assert_eq!(
/// query.to_string(PostgresQueryBuilder),
/// r#"SELECT "character" FROM "character" WHERE "font_id" = 5 FOR UPDATE"#
/// );
/// assert_eq!(
/// query.to_string(SqliteQueryBuilder),
/// r#"SELECT `character` FROM `character` WHERE `font_id` = 5 "#
/// );
/// ```
pub fn lock(&mut self, lock_type: LockType) -> &mut Self {
self.lock = Some(lock_type);
self
}

/// Shared row locking (if supported).
///
/// # Examples
///
/// ```
/// use sea_query::{*, tests_cfg::*};
///
/// let query = Query::select()
/// .column(Char::Character)
/// .from(Char::Table)
/// .and_where(Expr::col(Char::FontId).eq(5))
/// .lock_shared()
/// .to_owned();
///
/// assert_eq!(
/// query.to_string(MysqlQueryBuilder),
/// r#"SELECT `character` FROM `character` WHERE `font_id` = 5 FOR SHARE"#
/// );
/// assert_eq!(
/// query.to_string(PostgresQueryBuilder),
/// r#"SELECT "character" FROM "character" WHERE "font_id" = 5 FOR SHARE"#
/// );
/// assert_eq!(
/// query.to_string(SqliteQueryBuilder),
/// r#"SELECT `character` FROM `character` WHERE `font_id` = 5 "#
/// );
/// ```
pub fn lock_shared(&mut self) -> &mut Self {
self.lock = Some(LockType::Shared);
self
}

/// Exclusive row locking (if supported).
///
/// # Examples
///
/// ```
/// use sea_query::{*, tests_cfg::*};
///
/// let query = Query::select()
/// .column(Char::Character)
/// .from(Char::Table)
/// .and_where(Expr::col(Char::FontId).eq(5))
/// .lock_exclusive()
/// .to_owned();
///
/// assert_eq!(
/// query.to_string(MysqlQueryBuilder),
/// r#"SELECT `character` FROM `character` WHERE `font_id` = 5 FOR UPDATE"#
/// );
/// assert_eq!(
/// query.to_string(PostgresQueryBuilder),
/// r#"SELECT "character" FROM "character" WHERE "font_id" = 5 FOR UPDATE"#
/// );
/// assert_eq!(
/// query.to_string(SqliteQueryBuilder),
/// r#"SELECT `character` FROM `character` WHERE `font_id` = 5 "#
/// );
/// ```
pub fn lock_exclusive(&mut self) -> &mut Self {
self.lock = Some(LockType::Exclusive);
self
}
}

impl QueryStatementBuilder for SelectStatement {
Expand Down Expand Up @@ -1345,3 +1444,10 @@ impl ConditionalStatement for SelectStatement {
self
}
}

/// List of lock types that can be used in select statement
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LockType {
Shared,
Exclusive,
}

0 comments on commit 3312a1f

Please sign in to comment.