mod common;
use common::open_with_extension;
use sqlite_vector_rs::types::VectorType;
#[test]
fn vector_from_json_and_back() {
let conn = open_with_extension();
let json: String = conn
.query_row(
"SELECT vector_to_json(vector_from_json('[1.0, 2.0, 3.0]', 'float4'), 'float4')",
[],
|row| row.get(0),
)
.unwrap();
assert_eq!(json, "[1.0,2.0,3.0]");
}
#[test]
fn vector_distance_l2() {
let conn = open_with_extension();
let a = VectorType::Float4.slice_to_blob(&[1.0f32, 0.0, 0.0]);
let b = VectorType::Float4.slice_to_blob(&[0.0f32, 1.0, 0.0]);
let dist: f64 = conn
.query_row(
"SELECT vector_distance(?, ?, 'l2', 'float4')",
[a.as_slice(), b.as_slice()],
|row| row.get(0),
)
.unwrap();
assert!((dist - 2.0).abs() < 1e-6);
}
#[test]
fn vector_dims() {
let conn = open_with_extension();
let v = VectorType::Float4.slice_to_blob(&[1.0f32, 2.0, 3.0, 4.0]);
let dims: i64 = conn
.query_row("SELECT vector_dims(?, 'float4')", [v.as_slice()], |row| {
row.get(0)
})
.unwrap();
assert_eq!(dims, 4);
}
#[test]
fn rebuild_index_on_existing_table() {
let conn = open_with_extension();
conn.execute_batch("CREATE VIRTUAL TABLE emb USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let v1 = VectorType::Float4.slice_to_blob(&[1.0f32, 0.0, 0.0]);
let v2 = VectorType::Float4.slice_to_blob(&[0.0f32, 1.0, 0.0]);
let v3 = VectorType::Float4.slice_to_blob(&[0.0f32, 0.0, 1.0]);
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v1.as_slice()])
.unwrap();
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v2.as_slice()])
.unwrap();
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v3.as_slice()])
.unwrap();
let count: i64 = conn
.query_row(
"SELECT vector_rebuild_index('emb', 'float4', 'l2')",
[],
|row| row.get(0),
)
.unwrap();
assert_eq!(count, 3);
}
#[test]
fn rebuild_index_empty_table() {
let conn = open_with_extension();
conn.execute_batch("CREATE VIRTUAL TABLE emb USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let count: i64 = conn
.query_row(
"SELECT vector_rebuild_index('emb', 'float4', 'l2')",
[],
|row| row.get(0),
)
.unwrap();
assert_eq!(count, 0);
}
#[test]
fn export_and_import_arrow() {
let conn = open_with_extension();
conn.execute_batch("CREATE VIRTUAL TABLE emb USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let v1 = VectorType::Float4.slice_to_blob(&[1.0f32, 2.0, 3.0]);
let v2 = VectorType::Float4.slice_to_blob(&[4.0f32, 5.0, 6.0]);
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v1.as_slice()])
.unwrap();
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v2.as_slice()])
.unwrap();
let ipc_blob: Vec<u8> = conn
.query_row("SELECT vector_export_arrow('emb', 'float4')", [], |row| {
row.get(0)
})
.unwrap();
assert!(!ipc_blob.is_empty(), "Arrow IPC blob should not be empty");
conn.execute_batch("CREATE VIRTUAL TABLE emb2 USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let imported: i64 = conn
.query_row(
"SELECT vector_insert_arrow('emb2', 'float4', ?)",
[ipc_blob.as_slice()],
|row| row.get(0),
)
.unwrap();
assert_eq!(imported, 2);
let count: i64 = conn
.query_row("SELECT COUNT(*) FROM emb2", [], |row| row.get(0))
.unwrap();
assert_eq!(count, 2);
}
#[test]
fn export_arrow_empty_table() {
let conn = open_with_extension();
conn.execute_batch("CREATE VIRTUAL TABLE emb USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let ipc_blob: Vec<u8> = conn
.query_row("SELECT vector_export_arrow('emb', 'float4')", [], |row| {
row.get(0)
})
.unwrap();
assert!(ipc_blob.is_empty(), "Empty table should return empty blob");
}
#[test]
fn import_arrow_empty_blob() {
let conn = open_with_extension();
conn.execute_batch("CREATE VIRTUAL TABLE emb USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let empty: &[u8] = &[];
let imported: i64 = conn
.query_row(
"SELECT vector_insert_arrow('emb', 'float4', ?)",
[empty],
|row| row.get(0),
)
.unwrap();
assert_eq!(imported, 0);
}
#[test]
fn rebuild_index_preserves_shadow_data() {
let conn = open_with_extension();
conn.execute_batch("CREATE VIRTUAL TABLE emb USING vector(dim=3, type=float4, metric=l2)")
.unwrap();
let v1 = VectorType::Float4.slice_to_blob(&[1.0f32, 0.0, 0.0]);
let v2 = VectorType::Float4.slice_to_blob(&[0.0f32, 1.0, 0.0]);
let v3 = VectorType::Float4.slice_to_blob(&[0.0f32, 0.0, 1.0]);
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v1.as_slice()])
.unwrap();
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v2.as_slice()])
.unwrap();
conn.execute("INSERT INTO emb(vector) VALUES(?)", [v3.as_slice()])
.unwrap();
conn.query_row(
"SELECT vector_rebuild_index('emb', 'float4', 'l2')",
[],
|row| row.get::<_, i64>(0),
)
.unwrap();
let count: i64 = conn
.query_row("SELECT COUNT(*) FROM emb", [], |row| row.get(0))
.unwrap();
assert_eq!(count, 3);
}