Skip to content

Commit 8d0589d

Browse files
authored
Use Text for UUID (#44)
* Use text as UUID type Change-Id: I72add7222d1003b31466f7823d9838389ca08829 * append will not work for now Change-Id: Ie29412bf3855f3be2aebc789cdec967dc42e2a84
1 parent f3fc8da commit 8d0589d

File tree

6 files changed

+116
-10
lines changed

6 files changed

+116
-10
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ modern-full = [
2929
"serde_json",
3030
"url",
3131
"r2d2",
32+
"uuid",
3233
]
3334

3435
[dependencies]

src/appender.rs

+21
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,25 @@ mod test {
183183
assert_eq!(val, (25, 30));
184184
Ok(())
185185
}
186+
187+
// Waiting https://github.com/duckdb/duckdb/pull/3405
188+
#[cfg(feature = "uuid")]
189+
#[test]
190+
#[ignore = "not supported for now"]
191+
fn test_append_uuid() -> Result<()> {
192+
use uuid::Uuid;
193+
194+
let db = Connection::open_in_memory()?;
195+
db.execute_batch("CREATE TABLE foo(x UUID)")?;
196+
197+
let id = Uuid::new_v4();
198+
{
199+
let mut app = db.appender("foo")?;
200+
app.append_row([id])?;
201+
}
202+
203+
let val = db.query_row("SELECT x FROM foo", [], |row| <(Uuid,)>::try_from(row))?;
204+
assert_eq!(val, (id,));
205+
Ok(())
206+
}
186207
}

src/types/from_sql.rs

+50-4
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,18 @@ impl FromSql for Vec<u8> {
223223
impl FromSql for uuid::Uuid {
224224
#[inline]
225225
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
226-
value
227-
.as_blob()
228-
.and_then(|bytes| uuid::Builder::from_slice(bytes).map_err(|_| FromSqlError::InvalidUuidSize(bytes.len())))
229-
.map(|mut builder| builder.build())
226+
match value {
227+
ValueRef::Text(..) => value
228+
.as_str()
229+
.and_then(|s| uuid::Uuid::parse_str(s).map_err(|_| FromSqlError::InvalidUuidSize(s.len()))),
230+
ValueRef::Blob(..) => value
231+
.as_blob()
232+
.and_then(|bytes| {
233+
uuid::Builder::from_slice(bytes).map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
234+
})
235+
.map(|mut builder| builder.build()),
236+
_ => Err(FromSqlError::InvalidType),
237+
}
230238
}
231239
}
232240

@@ -359,4 +367,42 @@ mod test {
359367
check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
360368
Ok(())
361369
}
370+
371+
// Don't need uuid crate if we only care about the string value of uuid
372+
#[test]
373+
fn test_uuid_string() -> Result<()> {
374+
let db = Connection::open_in_memory()?;
375+
let sql = "BEGIN;
376+
CREATE TABLE uuid (u uuid);
377+
INSERT INTO uuid VALUES ('10203040-5060-7080-0102-030405060708'),(NULL),('47183823-2574-4bfd-b411-99ed177d3e43');
378+
END;";
379+
db.execute_batch(sql)?;
380+
let v = db.query_row("SELECT u FROM uuid order by u desc nulls last limit 1", [], |row| {
381+
<(String,)>::try_from(row)
382+
})?;
383+
assert_eq!(v, ("47183823-2574-4bfd-b411-99ed177d3e43".to_string(),));
384+
let v = db.query_row(
385+
"SELECT u FROM uuid where u>?",
386+
["10203040-5060-7080-0102-030405060708"],
387+
|row| <(String,)>::try_from(row),
388+
)?;
389+
assert_eq!(v, ("47183823-2574-4bfd-b411-99ed177d3e43".to_string(),));
390+
Ok(())
391+
}
392+
393+
#[cfg(feature = "uuid")]
394+
#[test]
395+
fn test_uuid_from_string() -> crate::Result<()> {
396+
let db = Connection::open_in_memory()?;
397+
let sql = "BEGIN;
398+
CREATE TABLE uuid (u uuid);
399+
INSERT INTO uuid VALUES ('10203040-5060-7080-0102-030405060708'),(NULL),('47183823-2574-4bfd-b411-99ed177d3e43');
400+
END;";
401+
db.execute_batch(sql)?;
402+
let v = db.query_row("SELECT u FROM uuid order by u desc nulls last limit 1", [], |row| {
403+
<(uuid::Uuid,)>::try_from(row)
404+
})?;
405+
assert_eq!(v.0.to_string(), "47183823-2574-4bfd-b411-99ed177d3e43");
406+
Ok(())
407+
}
362408
}

src/types/to_sql.rs

+42-5
Original file line numberDiff line numberDiff line change
@@ -297,27 +297,64 @@ mod test {
297297
assert!(r.is_ok());
298298
}
299299

300+
// Use gen_random_uuid() to generate uuid
301+
#[test]
302+
fn test_uuid_gen() -> crate::Result<()> {
303+
use crate::Connection;
304+
305+
let db = Connection::open_in_memory()?;
306+
db.execute_batch("CREATE TABLE foo (id uuid NOT NULL);")?;
307+
308+
db.execute("INSERT INTO foo (id) VALUES (gen_random_uuid())", [])?;
309+
310+
let mut stmt = db.prepare("SELECT id FROM foo")?;
311+
let mut rows = stmt.query([])?;
312+
let row = rows.next()?.unwrap();
313+
let found_id: String = row.get_unwrap(0);
314+
assert_eq!(found_id.len(), 36);
315+
Ok(())
316+
}
317+
300318
#[cfg(feature = "uuid")]
301319
#[test]
302-
fn test_uuid() -> crate::Result<()> {
320+
fn test_uuid_blob_type() -> crate::Result<()> {
303321
use crate::{params, Connection};
304322
use uuid::Uuid;
305323

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

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

331+
let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?")?;
332+
let mut rows = stmt.query(params![id_vec])?;
333+
let row = rows.next()?.unwrap();
334+
let found_id: Uuid = row.get_unwrap(0);
335+
let found_label: String = row.get_unwrap(1);
336+
assert_eq!(found_id, id);
337+
assert_eq!(found_label, "target");
338+
Ok(())
339+
}
340+
341+
#[cfg(feature = "uuid")]
342+
#[test]
343+
fn test_uuid_type() -> crate::Result<()> {
344+
use crate::{params, Connection};
345+
use uuid::Uuid;
346+
347+
let db = Connection::open_in_memory()?;
348+
db.execute_batch("CREATE TABLE foo (id uuid, label TEXT);")?;
349+
350+
let id = Uuid::new_v4();
311351
db.execute("INSERT INTO foo (id, label) VALUES (?, ?)", params![id, "target"])?;
312352

313353
let mut stmt = db.prepare("SELECT id, label FROM foo WHERE id = ?")?;
314-
315354
let mut rows = stmt.query(params![id])?;
316355
let row = rows.next()?.unwrap();
317-
318356
let found_id: Uuid = row.get_unwrap(0);
319357
let found_label: String = row.get_unwrap(1);
320-
321358
assert_eq!(found_id, id);
322359
assert_eq!(found_label, "target");
323360
Ok(())

src/types/value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ impl From<isize> for Value {
8181
impl From<uuid::Uuid> for Value {
8282
#[inline]
8383
fn from(id: uuid::Uuid) -> Value {
84-
Value::Blob(id.as_bytes().to_vec())
84+
Value::Text(id.to_string())
8585
}
8686
}
8787

src/types/value_ref.rs

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ impl<'a> ValueRef<'a> {
108108
pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
109109
match *self {
110110
ValueRef::Blob(b) => Ok(b),
111+
ValueRef::Text(t) => Ok(t),
111112
_ => Err(FromSqlError::InvalidType),
112113
}
113114
}

0 commit comments

Comments
 (0)