| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891 |
- use crate::{
- auth::{Auth, Authentication},
- error::AppError,
- request::{
- EntryRequestBody, RequestBody, RequestHeader, RequestHeaderInsert, RequestHeaderUpdate,
- RequestParams, RequestPathParam, WorkspaceRequest,
- },
- workspace::{
- Workspace, WorkspaceEntry, WorkspaceEntryBase, WorkspaceEntryCreate, WorkspaceEntryType,
- WorkspaceEntryUpdate, WorkspaceEnvVariable, WorkspaceEnvironment,
- },
- AppResult,
- };
- use serde::Deserialize;
- use sqlx::{sqlite::SqlitePool, types::Json, QueryBuilder};
- use std::collections::HashMap;
- use tauri_plugin_log::log;
- /// Used in update DTOs for **optional** properties. A value indicates a parameter needs to be updated to whatever is contained in it, a null indicates to set the field to null.
- #[derive(Debug, Deserialize)]
- pub enum Update<T> {
- Value(T),
- Null,
- }
- impl<T: Clone> Clone for Update<T> {
- fn clone(&self) -> Self {
- match self {
- Self::Value(arg0) => Self::Value(arg0.clone()),
- Self::Null => Self::Null,
- }
- }
- }
- impl<T: Copy> Copy for Update<T> {}
- impl<T: Copy> Update<T> {
- pub fn value(self) -> Option<T> {
- match self {
- Update::Value(v) => Some(v),
- Update::Null => None,
- }
- }
- }
- pub async fn init(url: &str) -> SqlitePool {
- let pool = SqlitePool::connect(url)
- .await
- .expect("error while connecting to db");
- sqlx::migrate!()
- .run(&pool)
- .await
- .expect("error in migrations");
- pool
- }
- pub async fn create_workspace(db: SqlitePool, name: String) -> Result<Workspace, String> {
- match sqlx::query_as!(
- Workspace,
- "INSERT INTO workspaces (name) VALUES (?) RETURNING id, name",
- name
- )
- .fetch_one(&db)
- .await
- {
- Ok(workspace) => Ok(workspace),
- Err(e) => Err(e.to_string()),
- }
- }
- pub async fn list_workspaces(db: SqlitePool) -> AppResult<Vec<Workspace>> {
- Ok(
- sqlx::query_as!(Workspace, "SELECT id, name FROM workspaces")
- .fetch_all(&db)
- .await?,
- )
- }
- /// Check whether the entry whose `id` == `parent_id` supports children.
- async fn check_parent(db: &SqlitePool, parent_id: Option<i64>) -> AppResult<()> {
- let Some(parent_id) = parent_id else {
- return Ok(());
- };
- let ty = sqlx::query!("SELECT type FROM workspace_entries WHERE id = ?", parent_id)
- .fetch_one(db)
- .await?
- .r#type;
- if !matches!(WorkspaceEntryType::from(ty), WorkspaceEntryType::Collection) {
- return Err(AppError::InvalidUpdate(format!(
- "{parent_id} is not a valid parent ID (type: {ty})"
- )));
- }
- Ok(())
- }
- pub async fn create_workspace_entry(
- db: SqlitePool,
- entry: WorkspaceEntryCreate,
- ) -> AppResult<WorkspaceEntryBase> {
- match entry {
- WorkspaceEntryCreate::Collection {
- name,
- workspace_id,
- parent_id,
- } => {
- check_parent(&db, parent_id).await?;
- let entry = sqlx::query_as!(
- WorkspaceEntryBase,
- r#"INSERT INTO workspace_entries(name, workspace_id, parent_id, type) VALUES (?, ?, ?, ?)
- RETURNING id, workspace_id, parent_id, name, type, auth, auth_inherit"#,
- name,
- workspace_id,
- parent_id,
- 1)
- .fetch_one(&db).await?;
- Ok(entry)
- }
- WorkspaceEntryCreate::Request {
- name,
- workspace_id,
- parent_id,
- method,
- url,
- } => {
- if let Some(parent) = parent_id {
- let ty = sqlx::query!("SELECT type FROM workspace_entries WHERE id = ?", parent)
- .fetch_one(&db)
- .await?
- .r#type;
- if !matches!(WorkspaceEntryType::from(ty), WorkspaceEntryType::Collection) {
- return Err(AppError::InvalidUpdate(format!(
- "{parent} is not a valid parent ID (type: {ty})"
- )));
- }
- }
- let mut tx = db.begin().await?;
- let entry = match sqlx::query_as!(
- WorkspaceEntryBase,
- r#"INSERT INTO workspace_entries(name, workspace_id, parent_id, type) VALUES (?, ?, ?, ?)
- RETURNING id, workspace_id, name, parent_id, type, auth, auth_inherit"#,
- name,
- workspace_id,
- parent_id,
- 0)
- .fetch_one(&mut *tx).await {
- Ok(entry) => entry,
- Err(e) => {
- tx.rollback().await?;
- return Err(e.into());
- }
- };
- match sqlx::query!(
- "INSERT INTO request_params(workspace_id, request_id, method, url) VALUES (?, ?, ?, ?)",
- workspace_id,
- entry.id,
- method,
- url
- )
- .execute(&mut *tx)
- .await {
- Ok(_) => {},
- Err(e) => {
- tx.rollback().await?;
- return Err(e.into());
- }
- }
- ;
- tx.commit().await?;
- Ok(entry)
- }
- }
- }
- pub async fn insert_request_body(
- db: SqlitePool,
- entry_id: i64,
- body: RequestBody,
- ) -> AppResult<EntryRequestBody> {
- Ok(sqlx::query_as!(EntryRequestBody, r#"INSERT INTO request_bodies(request_id, content_type, body) VALUES (?, ?, ?) RETURNING id, content_type AS "content_type: _", body"#, entry_id, body.ty, body.content).fetch_one(&db).await?)
- }
- pub async fn update_request_body(
- db: SqlitePool,
- id: i64,
- body: Update<RequestBody>,
- ) -> AppResult<()> {
- match body {
- Update::Value(body) => {
- sqlx::query!(
- "UPDATE request_bodies SET content_type = ?, body = ? WHERE id = ?",
- body.ty,
- body.content,
- id,
- )
- .execute(&db)
- .await?;
- }
- Update::Null => {
- sqlx::query!("DELETE FROM request_bodies WHERE id = ?", id)
- .execute(&db)
- .await?;
- }
- }
- Ok(())
- }
- pub async fn update_workspace_entry(
- db: SqlitePool,
- entry_id: i64,
- update: WorkspaceEntryUpdate,
- ) -> AppResult<()> {
- match update {
- WorkspaceEntryUpdate::Collection(update) => {
- let mut sql = sqlx::query_builder::QueryBuilder::new("UPDATE workspace_entries SET ");
- if let Some(parent) = update.parent_id {
- check_parent(&db, parent.value()).await?;
- }
- match (update.name, update.parent_id) {
- (None, None) => {
- return Err(AppError::InvalidUpdate(
- "cannot update entry: no updates present".to_string(),
- ))
- }
- (None, Some(parent_id)) => match parent_id {
- Update::Value(v) => {
- sql.push("parent_id = ").push_bind(v);
- }
- Update::Null => {
- sql.push("parent_id = NULL ");
- }
- },
- (Some(name), None) => {
- sql.push("name = ").push_bind(name);
- }
- (Some(name), Some(parent_id)) => {
- match parent_id {
- Update::Value(v) => {
- sql.push("parent_id = ").push_bind(v);
- }
- Update::Null => {
- sql.push("parent_id = NULL ");
- }
- };
- sql.push(", name = ").push_bind(name);
- }
- }
- sql.push("WHERE id = ")
- .push_bind(entry_id)
- .build()
- .execute(&db)
- .await?;
- Ok(())
- }
- WorkspaceEntryUpdate::Request {
- base,
- method,
- url,
- path_params,
- } => {
- let mut tx = db.begin().await?;
- 'entry: {
- if let Some(parent) = base.parent_id {
- check_parent(&db, parent.value()).await?;
- }
- let mut sql =
- sqlx::query_builder::QueryBuilder::new("UPDATE workspace_entries SET ");
- match (base.name, base.parent_id) {
- (None, None) => break 'entry,
- (None, Some(parent_id)) => match parent_id {
- Update::Value(v) => {
- sql.push("parent_id = ").push_bind(v);
- }
- Update::Null => {
- sql.push("parent_id = NULL ");
- }
- },
- (Some(name), None) => {
- sql.push("name = ").push_bind(name);
- }
- (Some(name), Some(parent_id)) => {
- match parent_id {
- Update::Value(v) => {
- sql.push("parent_id = ").push_bind(v);
- }
- Update::Null => {
- sql.push("parent_id = NULL ");
- }
- };
- sql.push(", name = ").push_bind(name);
- }
- }
- sql.push("WHERE id = ")
- .push_bind(entry_id)
- .build()
- .execute(&mut *tx)
- .await?;
- };
- 'param: {
- let mut sql = sqlx::query_builder::QueryBuilder::new("UPDATE request_params ");
- match (method, url) {
- (None, None) => break 'param,
- (None, Some(url)) => {
- sql.push("SET url = ").push_bind(url);
- }
- (Some(method), None) => {
- sql.push("SET method = ").push_bind(method);
- }
- (Some(method), Some(url)) => {
- sql.push("SET method = ")
- .push_bind(method)
- .push(", url = ")
- .push_bind(url);
- }
- }
- sql.push("WHERE request_id = ")
- .push_bind(entry_id)
- .build()
- .execute(&mut *tx)
- .await?;
- };
- if let Some(path_params) = path_params {
- if path_params.is_empty() {
- sqlx::query!(
- "DELETE FROM request_path_params WHERE request_id = ?",
- entry_id
- )
- .execute(&mut *tx)
- .await?;
- } else {
- let mut sql = QueryBuilder::new(
- "INSERT INTO request_path_params(position, request_id, name, value) ",
- );
- sql.push_values(path_params.iter(), |mut b, path| {
- b.push_bind(path.position as i64)
- .push_bind(entry_id)
- .push_bind(&path.name);
- if let Some(ref path) = path.value {
- b.push_bind(path);
- } else {
- b.push_bind("");
- }
- });
- sql.push(
- r#"
- ON CONFLICT(position, request_id) DO UPDATE
- SET
- value = excluded.value,
- name = excluded.name;
- DELETE FROM request_path_params
- WHERE request_id = "#,
- )
- .push_bind(entry_id)
- .push(" AND position NOT IN (");
- let mut sep = sql.separated(", ");
- for param in path_params.iter() {
- sep.push_bind(param.position as i64);
- }
- sep.push_unseparated(")");
- sql.build().execute(&mut *tx).await?;
- }
- }
- tx.commit().await?;
- Ok(())
- }
- }
- }
- pub async fn get_workspace_request(db: SqlitePool, id: i64) -> AppResult<WorkspaceRequest> {
- let entry = sqlx::query_as!(
- WorkspaceEntryBase,
- "SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit FROM workspace_entries WHERE id = ?",
- id,
- )
- .fetch_one(&db)
- .await?;
- let params = sqlx::query_as!(
- RequestParams,
- r#"
- SELECT
- rp.request_id as id,
- method as 'method!',
- url as 'url!',
- content_type as "content_type: _",
- body AS "body: _",
- rb.id AS "body_id: _"
- FROM request_params rp
- LEFT JOIN request_bodies rb ON rp.request_id = rb.request_id
- WHERE rp.request_id = ?
- "#,
- id
- )
- .fetch_one(&db)
- .await?;
- let headers = sqlx::query_as!(
- RequestHeader,
- "SELECT id, name, value FROM request_headers WHERE request_id = ?",
- entry.id
- )
- .fetch_all(&db)
- .await?;
- let path_params = sqlx::query_as!(
- RequestPathParam,
- "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
- entry.id
- )
- .fetch_all(&db)
- .await?;
- Ok(WorkspaceRequest::from_params_and_headers(
- entry,
- params,
- headers,
- path_params,
- ))
- }
- pub async fn list_workspace_entries(
- db: SqlitePool,
- workspace_id: i64,
- ) -> AppResult<Vec<WorkspaceEntry>> {
- let entries = sqlx::query_as!(
- WorkspaceEntryBase,
- "SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit FROM workspace_entries WHERE workspace_id = ? ORDER BY type DESC",
- workspace_id,
- )
- .fetch_all(&db)
- .await?;
- let mut request_params: HashMap<i64, RequestParams> = sqlx::query_as!(
- RequestParams,
- r#"
- SELECT rp.request_id as id, method as 'method!', url as 'url!', content_type as "content_type: _", body, rb.id as "body_id: _"
- FROM request_params rp
- LEFT JOIN request_bodies rb ON rp.request_id = rb.request_id
- WHERE workspace_id = ?
- "#,
- workspace_id
- )
- .fetch_all(&db)
- .await?
- .into_iter()
- .map(|req| (req.id, req))
- .collect();
- let mut out: Vec<WorkspaceEntry> = vec![];
- for entry in entries {
- match entry.r#type {
- WorkspaceEntryType::Request => {
- let headers = sqlx::query_as!(
- RequestHeader,
- "SELECT id, name, value FROM request_headers WHERE request_id = ?",
- entry.id
- )
- .fetch_all(&db)
- .await?;
- let path_params = sqlx::query_as!(
- RequestPathParam,
- "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
- entry.id
- )
- .fetch_all(&db)
- .await?;
- let Some(params) = request_params.remove(&entry.id) else {
- log::warn!("request {} has no params!", entry.id);
- continue;
- };
- let req =
- WorkspaceRequest::from_params_and_headers(entry, params, headers, path_params);
- out.push(WorkspaceEntry::new_req(req));
- }
- WorkspaceEntryType::Collection => {
- out.push(WorkspaceEntry::new_col(entry));
- }
- }
- }
- Ok(out)
- }
- pub async fn list_environments(
- db: SqlitePool,
- workspace_id: i64,
- ) -> AppResult<Vec<WorkspaceEnvironment>> {
- let records = sqlx::query!(
- r#"
- SELECT
- env.workspace_id,
- env.id AS env_id,
- env.name AS env_name,
- var.id AS "var_id?",
- var.name AS "var_name?",
- var.value AS "var_value?",
- var.secret AS "var_secret?"
- FROM workspace_envs env
- LEFT JOIN workspace_env_variables var ON env.id = var.env_id
- WHERE env.workspace_id = $1"#,
- workspace_id
- )
- .fetch_all(&db)
- .await?;
- let mut environments: HashMap<i64, WorkspaceEnvironment> = HashMap::new();
- for record in records {
- if let Some(env) = environments.get_mut(&record.env_id) {
- if record.var_id.is_some() {
- env.variables.push(WorkspaceEnvVariable {
- id: record.var_id.unwrap(),
- workspace_id,
- env_id: record.env_id,
- name: record.var_name.unwrap(),
- value: record.var_value.unwrap(),
- secret: record.var_secret.unwrap(),
- })
- }
- } else {
- let mut env = WorkspaceEnvironment {
- id: record.env_id,
- name: record.env_name,
- workspace_id,
- variables: vec![],
- };
- if record.var_id.is_some() {
- env.variables.push(WorkspaceEnvVariable {
- id: record.var_id.unwrap(),
- workspace_id,
- env_id: record.env_id,
- name: record.var_name.unwrap(),
- value: record.var_value.unwrap(),
- secret: record.var_secret.unwrap(),
- })
- }
- environments.insert(record.env_id, env);
- }
- }
- Ok(environments.into_values().collect())
- }
- pub async fn get_env_variables(
- db: &SqlitePool,
- env_id: i64,
- names: &[&str],
- ) -> AppResult<Vec<(String, String)>> {
- let mut query =
- QueryBuilder::new("SELECT name, value FROM workspace_env_variables WHERE env_id = ");
- query.push_bind(env_id);
- let mut separated = query.push(" AND name IN (").separated(", ");
- for name in names {
- separated.push_bind(name);
- }
- separated.push_unseparated(")");
- Ok(query
- .build_query_as::<(String, String)>()
- .fetch_all(db)
- .await?)
- }
- pub async fn create_environment(
- db: SqlitePool,
- workspace_id: i64,
- name: String,
- ) -> AppResult<WorkspaceEnvironment> {
- let row = sqlx::query!(
- r#"
- INSERT INTO workspace_envs (workspace_id, name)
- VALUES (?, ?)
- RETURNING id, workspace_id, name
- "#,
- workspace_id,
- name
- )
- .fetch_one(&db)
- .await?;
- Ok(WorkspaceEnvironment {
- id: row.id,
- workspace_id: row.workspace_id,
- name: row.name,
- variables: vec![],
- })
- }
- pub async fn update_environment(db: SqlitePool, env_id: i64, name: String) -> AppResult<()> {
- sqlx::query!(
- r#"
- UPDATE workspace_envs SET name = ? WHERE id = ?
- "#,
- name,
- env_id,
- )
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn insert_env_var(
- db: SqlitePool,
- workspace_id: i64,
- env_id: i64,
- name: String,
- value: String,
- secret: bool,
- ) -> AppResult<WorkspaceEnvVariable> {
- Ok(sqlx::query_as!(
- WorkspaceEnvVariable,
- r#"
- INSERT INTO workspace_env_variables (workspace_id, env_id, name, value, secret)
- VALUES (?, ?, ?, ?, ?)
- RETURNING id, workspace_id, env_id, name, value, secret
- "#,
- workspace_id,
- env_id,
- name,
- value,
- secret,
- )
- .fetch_one(&db)
- .await?)
- }
- pub async fn update_env_var(
- db: SqlitePool,
- id: i64,
- name: Option<String>,
- value: Option<String>,
- secret: Option<bool>,
- ) -> AppResult<()> {
- sqlx::query_as!(
- WorkspaceEnvVariable,
- r#"
- UPDATE workspace_env_variables
- SET
- name = COALESCE(?, name),
- value = COALESCE(?, value),
- secret = COALESCE(?, secret)
- WHERE id = ?
- "#,
- name,
- value,
- secret,
- id,
- )
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn delete_env_var(db: SqlitePool, id: i64) -> AppResult<()> {
- sqlx::query_as!(
- WorkspaceEnvVariable,
- r#"
- DELETE FROM workspace_env_variables
- WHERE id = ?
- "#,
- id,
- )
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn list_request_path_params(db: SqlitePool, id: i64) -> AppResult<Vec<RequestPathParam>> {
- Ok(sqlx::query_as!(
- RequestPathParam,
- "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
- id
- )
- .fetch_all(&db)
- .await?)
- }
- pub async fn insert_headers(
- db: SqlitePool,
- entry_id: i64,
- headers: Vec<RequestHeaderInsert>,
- ) -> AppResult<RequestHeader> {
- let mut insert = QueryBuilder::new("INSERT INTO request_headers(request_id, name, value) ");
- insert.push_values(headers, |mut b, header| {
- b.push_bind(entry_id)
- .push_bind(header.name)
- .push_bind(header.value);
- });
- Ok(insert
- .push("RETURNING id, name, value")
- .build_query_as()
- .fetch_one(&db)
- .await?)
- }
- pub async fn update_header(db: SqlitePool, header: RequestHeaderUpdate) -> AppResult<()> {
- sqlx::query!(
- "UPDATE request_headers SET name = COALESCE(?, ''), value = COALESCE(?, '') WHERE id = ?",
- header.name,
- header.value,
- header.id
- )
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn delete_header(db: SqlitePool, header_id: i64) -> AppResult<()> {
- sqlx::query!("DELETE FROM request_headers WHERE id = ?", header_id)
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn insert_auth(
- db: SqlitePool,
- workspace_id: i64,
- params: Auth,
- ) -> AppResult<Authentication> {
- let json = Json(¶ms);
- let record = sqlx::query!(
- "INSERT INTO auth(workspace_id, name, params) VALUES (?, 'New authentication', ?) RETURNING id, name",
- workspace_id,
- json
- )
- .fetch_one(&db)
- .await?;
- Ok(Authentication {
- id: record.id,
- workspace_id,
- name: record.name,
- params,
- })
- }
- pub async fn delete_auth(db: SqlitePool, id: i64) -> AppResult<()> {
- sqlx::query!("DELETE FROM auth WHERE id = ?", id)
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn list_auth(db: SqlitePool, workspace_id: i64) -> AppResult<Vec<Authentication>> {
- let records = sqlx::query!(
- r#"
- SELECT id, name, workspace_id, params as "params: Json<Auth>"
- FROM auth
- WHERE workspace_id = ?
- "#,
- workspace_id
- )
- .fetch_all(&db)
- .await?;
- Ok(records
- .into_iter()
- .map(|record| Authentication {
- id: record.id,
- name: record.name,
- workspace_id: record.workspace_id,
- params: record.params.0,
- })
- .collect())
- }
- pub async fn get_auth(db: SqlitePool, id: i64) -> AppResult<Authentication> {
- let record = sqlx::query!(
- r#"
- SELECT id, workspace_id, name, params as "params: Json<Auth>"
- FROM auth
- WHERE id = ?
- "#,
- id
- )
- .fetch_one(&db)
- .await?;
- Ok(Authentication {
- id: record.id,
- name: record.name,
- workspace_id: record.workspace_id,
- params: record.params.0,
- })
- }
- pub async fn set_workspace_entry_auth(
- db: SqlitePool,
- entry_id: i64,
- auth_id: Option<i64>,
- inherit: Option<bool>,
- ) -> AppResult<()> {
- sqlx::query!(
- "UPDATE workspace_entries SET auth = ?, auth_inherit = COALESCE(?, auth_inherit) WHERE id = ?",
- auth_id,
- inherit,
- entry_id
- )
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn update_auth(db: SqlitePool, auth_id: i64, params: Auth) -> AppResult<()> {
- let params = Json(params);
- sqlx::query!("UPDATE auth SET params = ? WHERE id = ?", params, auth_id)
- .execute(&db)
- .await?;
- Ok(())
- }
- pub async fn rename_auth(db: SqlitePool, auth_id: i64, name: String) -> AppResult<()> {
- sqlx::query!("UPDATE auth SET name = ? WHERE id = ?", name, auth_id)
- .execute(&db)
- .await?;
- Ok(())
- }
- /// Check for the existence of an auth ID in the workspace entry. If one does not exist,
- /// traverse its parents and attempt to find the first one that is present. If none exist,
- /// returns `None`.
- pub async fn get_auth_inherited(
- db: SqlitePool,
- mut parent_id: Option<i64>,
- ) -> AppResult<Option<i64>> {
- while let Some(id) = parent_id {
- let record = sqlx::query!(
- "SELECT auth, auth_inherit, parent_id FROM workspace_entries WHERE id = ?",
- id
- )
- .fetch_one(&db)
- .await?;
- if !record.auth_inherit {
- return Ok(record.auth);
- }
- parent_id = record.parent_id;
- }
- Ok(None)
- }
|