From 6bd851651110fa30c8956f36d487ea51d4cdcedd Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 8 Mar 2017 11:26:25 -0500 Subject: [PATCH] Roll convenient.rs into statement.rs. --- src/convenient.rs | 121 ---------------------------------------------- src/lib.rs | 1 - src/statement.rs | 119 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 112 insertions(+), 129 deletions(-) delete mode 100644 src/convenient.rs diff --git a/src/convenient.rs b/src/convenient.rs deleted file mode 100644 index de5c25c..0000000 --- a/src/convenient.rs +++ /dev/null @@ -1,121 +0,0 @@ -use {Error, Result, Row, Statement}; -use types::ToSql; -use statement::StatementCrateImpl; - -impl<'conn> Statement<'conn> { - /// Execute an INSERT and return the ROWID. - /// - /// # Note - /// - /// This function is a convenience wrapper around `execute()` intended for queries that - /// insert a single item. It is possible to misuse this function in a way that it cannot - /// detect, such as by calling it on a statement which _updates_ a single item rather than - /// inserting one. Please don't do that. - /// - /// # Failure - /// - /// Will return `Err` if no row is inserted or many rows are inserted. - pub fn insert(&mut self, params: &[&ToSql]) -> Result { - let changes = try!(self.execute(params)); - match changes { - 1 => Ok(self.last_insert_rowid()), - _ => Err(Error::StatementChangedRows(changes)), - } - } - - /// Return `true` if a query in the SQL statement it executes returns one or more rows - /// and `false` if the SQL returns an empty set. - pub fn exists(&mut self, params: &[&ToSql]) -> Result { - let mut rows = try!(self.query(params)); - let exists = { - match rows.next() { - Some(_) => true, - None => false, - } - }; - Ok(exists) - } - - /// Convenience method to execute a query that is expected to return a single row. - /// - /// If the query returns more than one row, all rows except the first are ignored. - /// - /// # Failure - /// - /// Will return `Err` if the underlying SQLite call fails. - pub fn query_row(&mut self, params: &[&ToSql], f: F) -> Result - where F: FnOnce(&Row) -> T - { - let mut rows = try!(self.query(params)); - - rows.get_expected_row().map(|r| f(&r)) - } -} - -#[cfg(test)] -mod test { - use {Connection, Error, Result}; - - #[test] - fn test_insert() { - let db = Connection::open_in_memory().unwrap(); - db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)").unwrap(); - let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)").unwrap(); - assert_eq!(stmt.insert(&[&1i32]).unwrap(), 1); - assert_eq!(stmt.insert(&[&2i32]).unwrap(), 2); - match stmt.insert(&[&1i32]).unwrap_err() { - Error::StatementChangedRows(0) => (), - err => panic!("Unexpected error {}", err), - } - let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4").unwrap(); - match multi.insert(&[]).unwrap_err() { - Error::StatementChangedRows(2) => (), - err => panic!("Unexpected error {}", err), - } - } - - #[test] - fn test_insert_different_tables() { - // Test for https://github.com/jgallagher/rusqlite/issues/171 - let db = Connection::open_in_memory().unwrap(); - db.execute_batch(r" - CREATE TABLE foo(x INTEGER); - CREATE TABLE bar(x INTEGER); - ") - .unwrap(); - - assert_eq!(db.prepare("INSERT INTO foo VALUES (10)").unwrap().insert(&[]).unwrap(), - 1); - assert_eq!(db.prepare("INSERT INTO bar VALUES (10)").unwrap().insert(&[]).unwrap(), - 1); - } - - #[test] - fn test_exists() { - let db = Connection::open_in_memory().unwrap(); - let sql = "BEGIN; - CREATE TABLE foo(x INTEGER); - INSERT INTO foo VALUES(1); - INSERT INTO foo VALUES(2); - END;"; - db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?").unwrap(); - assert!(stmt.exists(&[&1i32]).unwrap()); - assert!(stmt.exists(&[&2i32]).unwrap()); - assert!(!stmt.exists(&[&0i32]).unwrap()); - } - - #[test] - fn test_query_row() { - let db = Connection::open_in_memory().unwrap(); - let sql = "BEGIN; - CREATE TABLE foo(x INTEGER, y INTEGER); - INSERT INTO foo VALUES(1, 3); - INSERT INTO foo VALUES(2, 4); - END;"; - db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?").unwrap(); - let y: Result = stmt.query_row(&[&1i32], |r| r.get(0)); - assert_eq!(3i64, y.unwrap()); - } -} diff --git a/src/lib.rs b/src/lib.rs index 536b7da..ad919e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,6 @@ mod version; mod transaction; mod cache; mod error; -mod convenient; mod raw_statement; mod statement; #[cfg(feature = "load_extension")] diff --git a/src/statement.rs b/src/statement.rs index dc70bda..5e5b94d 100644 --- a/src/statement.rs +++ b/src/statement.rs @@ -106,6 +106,26 @@ impl<'conn> Statement<'conn> { self.execute_with_bound_parameters() } + /// Execute an INSERT and return the ROWID. + /// + /// # Note + /// + /// This function is a convenience wrapper around `execute()` intended for queries that + /// insert a single item. It is possible to misuse this function in a way that it cannot + /// detect, such as by calling it on a statement which _updates_ a single item rather than + /// inserting one. Please don't do that. + /// + /// # Failure + /// + /// Will return `Err` if no row is inserted or many rows are inserted. + pub fn insert(&mut self, params: &[&ToSql]) -> Result { + let changes = try!(self.execute(params)); + match changes { + 1 => Ok(self.conn.last_insert_rowid()), + _ => Err(Error::StatementChangedRows(changes)), + } + } + /// Execute the prepared statement, returning a handle to the resulting rows. /// /// Due to lifetime restricts, the rows handle returned by `query` does not @@ -309,6 +329,34 @@ impl<'conn> Statement<'conn> { }) } + /// Return `true` if a query in the SQL statement it executes returns one or more rows + /// and `false` if the SQL returns an empty set. + pub fn exists(&mut self, params: &[&ToSql]) -> Result { + let mut rows = try!(self.query(params)); + let exists = { + match rows.next() { + Some(_) => true, + None => false, + } + }; + Ok(exists) + } + + /// Convenience method to execute a query that is expected to return a single row. + /// + /// If the query returns more than one row, all rows except the first are ignored. + /// + /// # Failure + /// + /// Will return `Err` if the underlying SQLite call fails. + pub fn query_row(&mut self, params: &[&ToSql], f: F) -> Result + where F: FnOnce(&Row) -> T + { + let mut rows = try!(self.query(params)); + + rows.get_expected_row().map(|r| f(&r)) + } + /// Consumes the statement. /// /// Functionally equivalent to the `Drop` implementation, but allows callers to see any errors @@ -458,7 +506,6 @@ impl<'conn> Drop for Statement<'conn> { // once pub(crate) is stable. pub trait StatementCrateImpl<'conn> { fn new(conn: &'conn Connection, stmt: RawStatement) -> Self; - fn last_insert_rowid(&self) -> i64; fn value_ref(&self, col: c_int) -> ValueRef; fn step(&self) -> Result; fn reset(&self) -> c_int; @@ -472,10 +519,6 @@ impl<'conn> StatementCrateImpl<'conn> for Statement<'conn> { } } - fn last_insert_rowid(&self) -> i64 { - self.conn.last_insert_rowid() - } - fn value_ref(&self, col: c_int) -> ValueRef { let raw = unsafe { self.stmt.ptr() }; @@ -533,8 +576,7 @@ impl<'conn> StatementCrateImpl<'conn> for Statement<'conn> { #[cfg(test)] mod test { - use Connection; - use error::Error; + use {Connection, Error, Result}; #[test] fn test_execute_named() { @@ -671,4 +713,67 @@ mod test { .unwrap(); assert_eq!(result, "one"); } + + #[test] + fn test_insert() { + let db = Connection::open_in_memory().unwrap(); + db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)").unwrap(); + let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?)").unwrap(); + assert_eq!(stmt.insert(&[&1i32]).unwrap(), 1); + assert_eq!(stmt.insert(&[&2i32]).unwrap(), 2); + match stmt.insert(&[&1i32]).unwrap_err() { + Error::StatementChangedRows(0) => (), + err => panic!("Unexpected error {}", err), + } + let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4").unwrap(); + match multi.insert(&[]).unwrap_err() { + Error::StatementChangedRows(2) => (), + err => panic!("Unexpected error {}", err), + } + } + + #[test] + fn test_insert_different_tables() { + // Test for https://github.com/jgallagher/rusqlite/issues/171 + let db = Connection::open_in_memory().unwrap(); + db.execute_batch(r" + CREATE TABLE foo(x INTEGER); + CREATE TABLE bar(x INTEGER); + ") + .unwrap(); + + assert_eq!(db.prepare("INSERT INTO foo VALUES (10)").unwrap().insert(&[]).unwrap(), + 1); + assert_eq!(db.prepare("INSERT INTO bar VALUES (10)").unwrap().insert(&[]).unwrap(), + 1); + } + + #[test] + fn test_exists() { + let db = Connection::open_in_memory().unwrap(); + let sql = "BEGIN; + CREATE TABLE foo(x INTEGER); + INSERT INTO foo VALUES(1); + INSERT INTO foo VALUES(2); + END;"; + db.execute_batch(sql).unwrap(); + let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?").unwrap(); + assert!(stmt.exists(&[&1i32]).unwrap()); + assert!(stmt.exists(&[&2i32]).unwrap()); + assert!(!stmt.exists(&[&0i32]).unwrap()); + } + + #[test] + fn test_query_row() { + let db = Connection::open_in_memory().unwrap(); + let sql = "BEGIN; + CREATE TABLE foo(x INTEGER, y INTEGER); + INSERT INTO foo VALUES(1, 3); + INSERT INTO foo VALUES(2, 4); + END;"; + db.execute_batch(sql).unwrap(); + let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?").unwrap(); + let y: Result = stmt.query_row(&[&1i32], |r| r.get(0)); + assert_eq!(3i64, y.unwrap()); + } }