Skip to content

Commit

Permalink
Use Text for UUID (#44)
Browse files Browse the repository at this point in the history
* Use text as UUID type

Change-Id: I72add7222d1003b31466f7823d9838389ca08829

* append will not work for now

Change-Id: Ie29412bf3855f3be2aebc789cdec967dc42e2a84
  • Loading branch information
wangfenjin authored Apr 12, 2022
1 parent f3fc8da commit 8d0589d
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ modern-full = [
"serde_json",
"url",
"r2d2",
"uuid",
]

[dependencies]
Expand Down
21 changes: 21 additions & 0 deletions src/appender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,25 @@ mod test {
assert_eq!(val, (25, 30));
Ok(())
}

// Waiting https://github.com/duckdb/duckdb/pull/3405
#[cfg(feature = "uuid")]
#[test]
#[ignore = "not supported for now"]
fn test_append_uuid() -> Result<()> {
use uuid::Uuid;

let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo(x UUID)")?;

let id = Uuid::new_v4();
{
let mut app = db.appender("foo")?;
app.append_row([id])?;
}

let val = db.query_row("SELECT x FROM foo", [], |row| <(Uuid,)>::try_from(row))?;
assert_eq!(val, (id,));
Ok(())
}
}
54 changes: 50 additions & 4 deletions src/types/from_sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,18 @@ impl FromSql for Vec<u8> {
impl FromSql for uuid::Uuid {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value
.as_blob()
.and_then(|bytes| uuid::Builder::from_slice(bytes).map_err(|_| FromSqlError::InvalidUuidSize(bytes.len())))
.map(|mut builder| builder.build())
match value {
ValueRef::Text(..) => value
.as_str()
.and_then(|s| uuid::Uuid::parse_str(s).map_err(|_| FromSqlError::InvalidUuidSize(s.len()))),
ValueRef::Blob(..) => value
.as_blob()
.and_then(|bytes| {
uuid::Builder::from_slice(bytes).map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
})
.map(|mut builder| builder.build()),
_ => Err(FromSqlError::InvalidType),
}
}
}

Expand Down Expand Up @@ -359,4 +367,42 @@ mod test {
check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
Ok(())
}

// Don't need uuid crate if we only care about the string value of uuid
#[test]
fn test_uuid_string() -> Result<()> {
let db = Connection::open_in_memory()?;
let sql = "BEGIN;
CREATE TABLE uuid (u uuid);
INSERT INTO uuid VALUES ('10203040-5060-7080-0102-030405060708'),(NULL),('47183823-2574-4bfd-b411-99ed177d3e43');
END;";
db.execute_batch(sql)?;
let v = db.query_row("SELECT u FROM uuid order by u desc nulls last limit 1", [], |row| {
<(String,)>::try_from(row)
})?;
assert_eq!(v, ("47183823-2574-4bfd-b411-99ed177d3e43".to_string(),));
let v = db.query_row(
"SELECT u FROM uuid where u>?",
["10203040-5060-7080-0102-030405060708"],
|row| <(String,)>::try_from(row),
)?;
assert_eq!(v, ("47183823-2574-4bfd-b411-99ed177d3e43".to_string(),));
Ok(())
}

#[cfg(feature = "uuid")]
#[test]
fn test_uuid_from_string() -> crate::Result<()> {
let db = Connection::open_in_memory()?;
let sql = "BEGIN;
CREATE TABLE uuid (u uuid);
INSERT INTO uuid VALUES ('10203040-5060-7080-0102-030405060708'),(NULL),('47183823-2574-4bfd-b411-99ed177d3e43');
END;";
db.execute_batch(sql)?;
let v = db.query_row("SELECT u FROM uuid order by u desc nulls last limit 1", [], |row| {
<(uuid::Uuid,)>::try_from(row)
})?;
assert_eq!(v.0.to_string(), "47183823-2574-4bfd-b411-99ed177d3e43");
Ok(())
}
}
47 changes: 42 additions & 5 deletions src/types/to_sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,27 +297,64 @@ mod test {
assert!(r.is_ok());
}

// Use gen_random_uuid() to generate uuid
#[test]
fn test_uuid_gen() -> crate::Result<()> {
use crate::Connection;

let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (id uuid NOT NULL);")?;

db.execute("INSERT INTO foo (id) VALUES (gen_random_uuid())", [])?;

let mut stmt = db.prepare("SELECT id FROM foo")?;
let mut rows = stmt.query([])?;
let row = rows.next()?.unwrap();
let found_id: String = row.get_unwrap(0);
assert_eq!(found_id.len(), 36);
Ok(())
}

#[cfg(feature = "uuid")]
#[test]
fn test_uuid() -> crate::Result<()> {
fn test_uuid_blob_type() -> crate::Result<()> {
use crate::{params, Connection};
use uuid::Uuid;

let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (id BLOB CONSTRAINT uuidchk CHECK (octet_length(id) <= 16), label TEXT);")?;
db.execute_batch("CREATE TABLE foo (id BLOB CONSTRAINT uuidchk CHECK (octet_length(id) = 16), label TEXT);")?;

let id = Uuid::new_v4();
let id_vec = id.as_bytes().to_vec();
db.execute("INSERT INTO foo (id, label) VALUES (?, ?)", params![id_vec, "target"])?;

let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?")?;
let mut rows = stmt.query(params![id_vec])?;
let row = rows.next()?.unwrap();
let found_id: Uuid = row.get_unwrap(0);
let found_label: String = row.get_unwrap(1);
assert_eq!(found_id, id);
assert_eq!(found_label, "target");
Ok(())
}

#[cfg(feature = "uuid")]
#[test]
fn test_uuid_type() -> crate::Result<()> {
use crate::{params, Connection};
use uuid::Uuid;

let db = Connection::open_in_memory()?;
db.execute_batch("CREATE TABLE foo (id uuid, label TEXT);")?;

let id = Uuid::new_v4();
db.execute("INSERT INTO foo (id, label) VALUES (?, ?)", params![id, "target"])?;

let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?")?;

let mut rows = stmt.query(params![id])?;
let row = rows.next()?.unwrap();

let found_id: Uuid = row.get_unwrap(0);
let found_label: String = row.get_unwrap(1);

assert_eq!(found_id, id);
assert_eq!(found_label, "target");
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion src/types/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl From<isize> for Value {
impl From<uuid::Uuid> for Value {
#[inline]
fn from(id: uuid::Uuid) -> Value {
Value::Blob(id.as_bytes().to_vec())
Value::Text(id.to_string())
}
}

Expand Down
1 change: 1 addition & 0 deletions src/types/value_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl<'a> ValueRef<'a> {
pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
match *self {
ValueRef::Blob(b) => Ok(b),
ValueRef::Text(t) => Ok(t),
_ => Err(FromSqlError::InvalidType),
}
}
Expand Down

0 comments on commit 8d0589d

Please sign in to comment.