diff --git a/Cargo.toml b/Cargo.toml index 5695470..2f96347 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusqlite" -version = "0.6.0" +version = "0.7.2" authors = ["John Gallagher "] description = "Ergonomic wrapper for SQLite" repository = "https://github.com/jgallagher/rusqlite" @@ -37,7 +37,7 @@ regex = "~0.1.41" [dependencies.libsqlite3-sys] path = "libsqlite3-sys" -version = "0.4.0" +version = "0.5.0" [dependencies.csv] version = "~0.14.3" diff --git a/Changelog.md b/Changelog.md index df401e1..358d93f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -# Version UPCOMING (...) +# Version 0.7.2 (2016-05-19) * BREAKING CHANGE: `Rows` no longer implements `Iterator`. It still has a `next()` method, but the lifetime of the returned `Row` is now tied to the lifetime of the vending `Rows` object. diff --git a/README.md b/README.md index 05635c7..2f8d23c 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,12 @@ features](http://doc.crates.io/manifest.html#the-features-section). They are: allows hooks into SQLite's tracing and profiling APIs. * [`blob`](http://jgallagher.github.io/rusqlite/rusqlite/blob/index.html) gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. +* `chrono` implements [`FromSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.FromSql.html) + and [`ToSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.ToSql.html) for various + types from the [`chrono` crate](https://crates.io/crates/chrono). +* `serde_json` implements [`FromSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.FromSql.html) + and [`ToSql`](http://jgallagher.github.io/rusqlite/rusqlite/types/trait.ToSql.html) for the + `Value` type from the [`serde_json` crate](https://crates.io/crates/serde_json). ## Author diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..82447d9 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = ["SQLite", "lang_transaction"] diff --git a/libsqlite3-sys/Cargo.toml b/libsqlite3-sys/Cargo.toml index b93650b..90e2813 100644 --- a/libsqlite3-sys/Cargo.toml +++ b/libsqlite3-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libsqlite3-sys" -version = "0.4.0" +version = "0.5.0" authors = ["John Gallagher "] repository = "https://github.com/jgallagher/rusqlite" description = "Native bindings to the libsqlite3 library" diff --git a/publish-ghp-docs.sh b/publish-ghp-docs.sh index c8fc790..a6883bc 100755 --- a/publish-ghp-docs.sh +++ b/publish-ghp-docs.sh @@ -8,7 +8,7 @@ fi cd $(git rev-parse --show-toplevel) rm -rf target/doc/ -multirust run nightly cargo doc --no-deps --features "backup cache functions load_extension trace blob" +rustup run nightly cargo doc --no-deps --features "backup blob chrono functions load_extension serde_json trace" echo '' > target/doc/index.html ghp-import target/doc git push origin gh-pages:gh-pages diff --git a/src/blob.rs b/src/blob.rs index c24fce9..548e5c9 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -235,7 +235,10 @@ impl<'conn> Drop for Blob<'conn> { } /// BLOB of length N that is filled with zeroes. -/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using incremental BLOB I/O routines. +/// +/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using +/// incremental BLOB I/O routines. +/// /// A negative value for the zeroblob results in a zero-length BLOB. #[derive(Copy,Clone)] pub struct ZeroBlob(pub i32); diff --git a/src/cache.rs b/src/cache.rs index f5fade3..d246e8e 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -34,7 +34,7 @@ impl Connection { /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the /// underlying SQLite call fails. pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result> { - self.cache.get(&self, sql) + self.cache.get(self, sql) } /// Set the maximum number of cached prepared statements this connection will hold. @@ -90,6 +90,8 @@ impl<'conn> CachedStatement<'conn> { } } + /// Discard the statement, preventing it from being returned to its `Connection`'s collection + /// of cached statements. pub fn discard(mut self) { self.stmt = None; } diff --git a/src/error.rs b/src/error.rs index 901de41..1b0bb50 100644 --- a/src/error.rs +++ b/src/error.rs @@ -170,8 +170,8 @@ impl error::Error for Error { Error::InvalidColumnIndex(_) | Error::InvalidColumnName(_) | Error::InvalidColumnType(_, _) | - Error::InvalidPath(_) => None, - Error::StatementChangedRows(_) => None, + Error::InvalidPath(_) | + Error::StatementChangedRows(_) | Error::StatementFailedToInsertRow => None, #[cfg(feature = "functions")] diff --git a/src/functions.rs b/src/functions.rs index 40c529a..6ae5710 100644 --- a/src/functions.rs +++ b/src/functions.rs @@ -111,7 +111,8 @@ impl<'a> ToResult for &'a str { length as c_int, ffi::SQLITE_TRANSIENT()) } - Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error + // TODO sqlite3_result_error + Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), } } } @@ -730,9 +731,10 @@ mod test { assert_eq!(true, result.unwrap()); - let result: Result = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", - &[], - |r| r.get(0)); + let result: Result = + db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", + &[], + |r| r.get(0)); assert_eq!(2, result.unwrap()); } @@ -780,9 +782,10 @@ mod test { assert_eq!(true, result.unwrap()); - let result: Result = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", - &[], - |r| r.get(0)); + let result: Result = + db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1", + &[], + |r| r.get(0)); assert_eq!(2, result.unwrap()); } diff --git a/src/lib.rs b/src/lib.rs index aa4e067..8a1ad7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,8 @@ use error::{error_from_sqlite_code, error_from_handle}; use raw_statement::RawStatement; use cache::StatementCache; -pub use transaction::{SqliteTransaction, Transaction, TransactionBehavior}; +pub use transaction::{SqliteTransaction, SqliteTransactionBehavior, DropBehavior, Savepoint, + Transaction, TransactionBehavior}; pub use error::{SqliteError, Error}; pub use cache::CachedStatement; @@ -320,7 +321,9 @@ impl Connection { /// ```rust,no_run /// # use rusqlite::{Result,Connection}; /// fn preferred_locale(conn: &Connection) -> Result { - /// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'", &[], |row| { + /// conn.query_row_and_then("SELECT value FROM preferences WHERE name='locale'", + /// &[], + /// |row| { /// row.get_checked(0) /// }) /// } @@ -710,9 +713,12 @@ impl<'conn> Statement<'conn> { } /// Returns the column index in the result set for a given column name. - /// If there is no AS clause then the name of the column is unspecified and may change from one release of SQLite to the next. + /// + /// If there is no AS clause then the name of the column is unspecified and may change from one + /// release of SQLite to the next. /// /// # Failure + /// /// Will return an `Error::InvalidColumnName` when there is no column with the specified `name`. pub fn column_index(&self, name: &str) -> Result { let bytes = name.as_bytes(); @@ -966,9 +972,7 @@ pub struct Rows<'stmt> { impl<'stmt> Rows<'stmt> { fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> { - Rows { - stmt: Some(stmt), - } + Rows { stmt: Some(stmt) } } fn get_expected_row<'a>(&'a mut self) -> Result> { @@ -1372,19 +1376,6 @@ mod test { } } - #[test] - #[should_panic] - fn test_rows_dropped() { - let db = checked_memory_handle(); - db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap(); - db.execute_batch("INSERT INTO foo(x) VALUES(1)").unwrap(); - - let mut stmt = db.prepare("SELECT x FROM foo").unwrap(); - let row = stmt.query(&[]).unwrap().next().unwrap().unwrap(); - - assert_eq!(1i32, row.get(0)); - } - mod query_and_then_tests { extern crate libsqlite3_sys as ffi; use super::*; diff --git a/src/named_params.rs b/src/named_params.rs index 04ebcbd..d89cc6e 100644 --- a/src/named_params.rs +++ b/src/named_params.rs @@ -279,9 +279,10 @@ mod test { let mut stmt = db.prepare("SELECT id FROM test where name = :name").unwrap(); let mut rows = stmt.query_map_named(&[(":name", &"one")], |row| { - let id: i32 = row.get(0); - 2 * id - }).unwrap(); + let id: i32 = row.get(0); + 2 * id + }) + .unwrap(); let doubled_id: i32 = rows.next().unwrap().unwrap(); assert_eq!(2, doubled_id); @@ -298,15 +299,17 @@ mod test { "#; db.execute_batch(sql).unwrap(); - let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC").unwrap(); + let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC") + .unwrap(); let mut rows = stmt.query_and_then_named(&[(":name", &"one")], |row| { - let id: i32 = row.get(0); - if id == 1 { - Ok(id) - } else { - Err(Error::SqliteSingleThreadedMode) - } - }).unwrap(); + let id: i32 = row.get(0); + if id == 1 { + Ok(id) + } else { + Err(Error::SqliteSingleThreadedMode) + } + }) + .unwrap(); // first row should be Ok let doubled_id: i32 = rows.next().unwrap().unwrap(); diff --git a/src/trace.rs b/src/trace.rs index 4cea711..32382a2 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -59,7 +59,8 @@ pub fn log(err_code: c_int, msg: &str) { } impl Connection { - /// Register or clear a callback function that can be used for tracing the execution of SQL statements. + /// Register or clear a callback function that can be used for tracing the execution of SQL + /// statements. /// /// Prepared statement placeholders are replaced/logged with their assigned values. /// There can only be a single tracer defined for each database connection. @@ -83,7 +84,8 @@ impl Connection { } } - /// Register or clear a callback function that can be used for profiling the execution of SQL statements. + /// Register or clear a callback function that can be used for profiling the execution of SQL + /// statements. /// /// There can only be a single profiler defined for each database connection. /// Setting a new profiler clears the old one. diff --git a/src/transaction.rs b/src/transaction.rs index 3bdae80..e678215 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -209,7 +209,10 @@ impl<'conn> Drop for Transaction<'conn> { } impl<'conn> Savepoint<'conn> { - fn with_depth_and_name>(conn: &Connection, depth: u32, name: T) -> Result { + fn with_depth_and_name>(conn: &Connection, + depth: u32, + name: T) + -> Result { let name = name.into(); conn.execute_batch(&format!("SAVEPOINT {}", name)).map(|_| { Savepoint { @@ -349,7 +352,9 @@ impl Connection { /// # Failure /// /// Will return `Err` if the underlying SQLite call fails. - pub fn transaction_with_behavior(&mut self, behavior: TransactionBehavior) -> Result { + pub fn transaction_with_behavior(&mut self, + behavior: TransactionBehavior) + -> Result { Transaction::new(self, behavior) } diff --git a/src/vtab/csvtab.rs b/src/vtab/csvtab.rs index 7de0059..d220b2c 100644 --- a/src/vtab/csvtab.rs +++ b/src/vtab/csvtab.rs @@ -228,7 +228,7 @@ impl From for Error { #[cfg(test)] mod test { - use Connection; + use {Connection,Result}; use vtab::csvtab; #[test] @@ -244,13 +244,8 @@ mod test { assert_eq!(vec!["rowid", "colA", "colB", "colC"], headers); } - let rows = s.query(&[]).unwrap(); - let mut sum = 0; - for row in rows { - let row = row.unwrap(); - let id: i64 = row.get(0); - sum = sum + id; - } + let ids: Result> = s.query_map(&[], |row| row.get::(0)).unwrap().collect(); + let sum = ids.unwrap().iter().fold(0, |acc, &id| acc + id); assert_eq!(sum, 15); } db.execute_batch("DROP TABLE vtab").unwrap(); diff --git a/src/vtab/int_array.rs b/src/vtab/int_array.rs index 9929426..07d2109 100644 --- a/src/vtab/int_array.rs +++ b/src/vtab/int_array.rs @@ -163,14 +163,12 @@ mod test { p3.borrow_mut().append(&mut vec![-1, -5, -10]); { - let rows = s.query(&[]).unwrap(); - for row in rows { - let row = row.unwrap(); + s.query_map(&[], |row| { let i1: i64 = row.get(0); assert!(i1 == 1 || i1 == 3); assert_eq!(11, row.get(1)); assert_eq!(-5, row.get(2)); - } + }).unwrap(); } p1.borrow_mut().clear();