use chrono::{DateTime, Utc};
use foundation_db::core::storage_provider::{AsyncQueryStore, DataValue, SqlRow};
use crate::core::error::AppResult;
use crate::core::store::{parse_ts, store_err};
#[derive(Debug, Clone)]
pub struct DeviceRow {
pub uuid: String,
pub user_uuid: String,
pub identifier: String,
pub name: Option<String>,
pub atype: i64,
pub refresh_token: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
const COLUMNS: &str = "uuid, user_uuid, identifier, name, atype, refresh_token, created_at, updated_at";
fn map_row(row: &SqlRow) -> AppResult<DeviceRow> {
let created_at: String = row.get_by_name("created_at").map_err(store_err)?;
let updated_at: String = row.get_by_name("updated_at").map_err(store_err)?;
Ok(DeviceRow {
uuid: row.get_by_name("uuid").map_err(store_err)?,
user_uuid: row.get_by_name("user_uuid").map_err(store_err)?,
identifier: row.get_by_name("identifier").map_err(store_err)?,
name: row.get_by_name("name").map_err(store_err)?,
atype: row.get_by_name("atype").map_err(store_err)?,
refresh_token: row.get_by_name("refresh_token").map_err(store_err)?,
created_at: parse_ts(&created_at)?,
updated_at: parse_ts(&updated_at)?,
})
}
pub async fn find(
db: &dyn AsyncQueryStore,
user_uuid: &str,
identifier: &str,
) -> AppResult<Option<DeviceRow>> {
let rows = db
.query_async(
&format!("SELECT {COLUMNS} FROM vault_devices WHERE user_uuid = ? AND identifier = ?"),
&[
DataValue::Text(user_uuid.to_string()),
DataValue::Text(identifier.to_string()),
],
)
.await
.map_err(store_err)?
.collect_all()
.await
.map_err(store_err)?;
rows.first().map(map_row).transpose()
}
pub async fn find_by_user_identifier(
db: &dyn AsyncQueryStore,
user_uuid: &str,
identifier: &str,
) -> AppResult<Option<DeviceRow>> {
find(db, user_uuid, identifier).await
}
pub async fn insert(db: &dyn AsyncQueryStore, row: &DeviceRow) -> AppResult<()> {
db.execute_async(
"INSERT INTO vault_devices \
(uuid, user_uuid, identifier, name, atype, refresh_token, created_at, updated_at) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
&[
DataValue::Text(row.uuid.clone()),
DataValue::Text(row.user_uuid.clone()),
DataValue::Text(row.identifier.clone()),
match &row.name {
Some(n) => DataValue::Text(n.clone()),
None => DataValue::Null,
},
DataValue::Integer(row.atype),
DataValue::Text(row.refresh_token.clone()),
DataValue::Text(row.created_at.to_rfc3339()),
DataValue::Text(row.updated_at.to_rfc3339()),
],
)
.await
.map_err(store_err)?;
Ok(())
}
pub async fn update_refresh_token(
db: &dyn AsyncQueryStore,
uuid: &str,
refresh_token: &str,
updated_at: DateTime<Utc>,
) -> AppResult<()> {
db.execute_async(
"UPDATE vault_devices SET refresh_token = ?, updated_at = ? WHERE uuid = ?",
&[
DataValue::Text(refresh_token.to_string()),
DataValue::Text(updated_at.to_rfc3339()),
DataValue::Text(uuid.to_string()),
],
)
.await
.map_err(store_err)?;
Ok(())
}