sqlite where IN for id entry (#1988)

Fixes #258
This commit is contained in:
James Hodgkinson 2023-08-17 13:32:41 +10:00 committed by GitHub
parent 003234c2d0
commit 46f9a36a1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 41 deletions

View file

@ -24,7 +24,7 @@ members = [
"libs/file_permissions", "libs/file_permissions",
"libs/profiles", "libs/profiles",
"libs/sketching", "libs/sketching",
"libs/users" "libs/users",
] ]
[workspace.package] [workspace.package]
@ -32,7 +32,7 @@ version = "1.1.0-rc.14-dev"
authors = [ authors = [
"William Brown <william@blackhats.net.au>", "William Brown <william@blackhats.net.au>",
"James Hodgkinson <james@terminaloutcomes.com>", "James Hodgkinson <james@terminaloutcomes.com>",
] ]
rust-version = "1.66" rust-version = "1.66"
edition = "2021" edition = "2021"
license = "MPL-2.0" license = "MPL-2.0"
@ -55,7 +55,17 @@ serde_with = "3.2.0"
argon2 = { version = "0.5.1", features = ["alloc"] } argon2 = { version = "0.5.1", features = ["alloc"] }
async-recursion = "1.0.4" async-recursion = "1.0.4"
async-trait = "^0.1.73" async-trait = "^0.1.73"
axum = {version = "0.6.20", features = ["json", "http2", "macros", "tracing", "headers", "original-uri", "query", "form", "http2"]} axum = { version = "0.6.20", features = [
"json",
"http2",
"macros",
"tracing",
"headers",
"original-uri",
"query",
"form",
"http2",
] }
axum-csp = { version = "0.0.5" } axum-csp = { version = "0.0.5" }
base32 = "^0.4.0" base32 = "^0.4.0"
base64 = "^0.21.0" base64 = "^0.21.0"
@ -117,7 +127,13 @@ qrcode = "^0.12.0"
quote = "1" quote = "1"
rand = "^0.8.5" rand = "^0.8.5"
regex = "1.9.3" regex = "1.9.3"
reqwest = { version = "0.11.18", default-features = false, features=["cookies", "json", "gzip", "native-tls", "native-tls-alpn"] } reqwest = { version = "0.11.18", default-features = false, features = [
"cookies",
"json",
"gzip",
"native-tls",
"native-tls-alpn",
] }
rpassword = "^7.2.0" rpassword = "^7.2.0"
rusqlite = "^0.28.0" rusqlite = "^0.28.0"

View file

@ -79,11 +79,11 @@ serde_with = { workspace = true }
# because windows really can't build without the bundled one # because windows really can't build without the bundled one
[target.'cfg(target_family = "windows")'.dependencies] [target.'cfg(target_family = "windows")'.dependencies]
rusqlite = { workspace = true, features = ["bundled"] } rusqlite = { workspace = true, features = ["array", "bundled"] }
whoami = { workspace = true } whoami = { workspace = true }
[target.'cfg(not(target_family = "windows"))'.dependencies] [target.'cfg(not(target_family = "windows"))'.dependencies]
rusqlite = { workspace = true } rusqlite = { workspace = true, features = ["array"] }
kanidm_utils_users = { workspace = true } kanidm_utils_users = { workspace = true }
[features] [features]

View file

@ -8,6 +8,7 @@ use std::time::Duration;
use hashbrown::HashMap; use hashbrown::HashMap;
use idlset::v2::IDLBitRange; use idlset::v2::IDLBitRange;
use kanidm_proto::v1::{ConsistencyError, OperationError}; use kanidm_proto::v1::{ConsistencyError, OperationError};
use rusqlite::vtab::array::Array;
use rusqlite::{Connection, OpenFlags, OptionalExtension}; use rusqlite::{Connection, OpenFlags, OptionalExtension};
use uuid::Uuid; use uuid::Uuid;
@ -157,47 +158,31 @@ pub trait IdlSqliteTransaction {
.collect() .collect()
} }
IdList::Partial(idli) | IdList::PartialThreshold(idli) | IdList::Indexed(idli) => { IdList::Partial(idli) | IdList::PartialThreshold(idli) | IdList::Indexed(idli) => {
let mut id_list: Vec<rusqlite::types::Value> = vec![];
for item in idli.into_iter() {
id_list.push(rusqlite::types::Value::Integer(
i64::try_from(item).map_err(|_| OperationError::InvalidEntryId)?,
));
}
let mut stmt = self let mut stmt = self
.get_conn()? .get_conn()?
.prepare(&format!( .prepare(&format!(
"SELECT id, data FROM {}.id2entry WHERE id = :idl", "SELECT id, data FROM {}.id2entry WHERE id IN (:idl)",
self.get_db_name() self.get_db_name()
)) ))
.map_err(sqlite_error)?; .map_err(sqlite_error)?;
// TODO #258: Can this actually just load in a single select? let mut results: Vec<IdRawEntry> = vec![];
// TODO #258: I have no idea how to make this an iterator chain ... so what let _ = stmt
// I have now is probably really bad :( .query_map(&[(":idl", &Array::from(id_list))], |row| {
let mut results = Vec::new(); results.push(IdRawEntry {
/*
let decompressed: Result<Vec<i64>, _> = idli.into_iter()
.map(|u| i64::try_from(u).map_err(|_| OperationError::InvalidEntryId))
.collect();
*/
for id in idli {
let iid = i64::try_from(id).map_err(|_| OperationError::InvalidEntryId)?;
let id2entry_iter = stmt
.query_map([&iid], |row| {
Ok(IdSqliteEntry {
id: row.get(0)?, id: row.get(0)?,
data: row.get(1)?, data: row.get(1)?,
}) });
Ok(())
}) })
.map_err(sqlite_error)?; .map_err(sqlite_error)?;
let r: Result<Vec<_>, _> = id2entry_iter
.map(|v| {
v.map_err(sqlite_error).and_then(|ise| {
// Convert the idsqlite to id raw
ise.try_into()
})
})
.collect();
let mut r = r?;
results.append(&mut r);
}
Ok(results) Ok(results)
} }
} }

View file

@ -65,7 +65,15 @@ serde_json = { workspace = true }
sketching = { workspace = true } sketching = { workspace = true }
toml = { workspace = true } toml = { workspace = true }
tokio = { workspace = true, features = ["rt", "fs", "macros", "sync", "time", "net", "io-util"] } tokio = { workspace = true, features = [
"rt",
"fs",
"macros",
"sync",
"time",
"net",
"io-util",
] }
tokio-util = { workspace = true, features = ["codec"] } tokio-util = { workspace = true, features = ["codec"] }
tracing = { workspace = true } tracing = { workspace = true }
tss-esapi = { workspace = true, optional = true } tss-esapi = { workspace = true, optional = true }