db.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. use crate::{
  2. auth::{Auth, Authentication},
  3. error::AppError,
  4. request::{
  5. EntryRequestBody, PathParamRead, PathParamWrite, QueryParamRead, RequestBody,
  6. RequestHeader, RequestHeaderInsert, RequestHeaderUpdate, RequestParams, RequestPathUpdate,
  7. RequestQueryUpdate, WorkspaceRequest,
  8. },
  9. workspace::{
  10. Workspace, WorkspaceEntry, WorkspaceEntryBase, WorkspaceEntryCreate, WorkspaceEntryDisplay,
  11. WorkspaceEntryType, WorkspaceEnvVariable, WorkspaceEnvironment,
  12. },
  13. AppResult,
  14. };
  15. use serde::Deserialize;
  16. use sqlx::{
  17. sqlite::{SqliteConnectOptions, SqlitePool},
  18. types::Json,
  19. ConnectOptions, QueryBuilder,
  20. };
  21. use std::{collections::HashMap, str::FromStr};
  22. /// 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.
  23. #[derive(Debug, Deserialize)]
  24. pub enum Update<T> {
  25. Value(T),
  26. Null,
  27. }
  28. impl<T: Clone> Clone for Update<T> {
  29. fn clone(&self) -> Self {
  30. match self {
  31. Self::Value(arg0) => Self::Value(arg0.clone()),
  32. Self::Null => Self::Null,
  33. }
  34. }
  35. }
  36. impl<T: Copy> Copy for Update<T> {}
  37. pub async fn init(url: &str) -> SqlitePool {
  38. let mut opts = SqliteConnectOptions::from_str(url).unwrap();
  39. opts = ConnectOptions::log_statements(opts, tauri_plugin_log::log::LevelFilter::Off);
  40. let pool = SqlitePool::connect_with(opts)
  41. .await
  42. .expect("error while connecting to db");
  43. sqlx::migrate!()
  44. .run(&pool)
  45. .await
  46. .expect("error in migrations");
  47. pool
  48. }
  49. pub async fn create_workspace(db: SqlitePool, name: String) -> Result<Workspace, String> {
  50. match sqlx::query_as!(
  51. Workspace,
  52. "INSERT INTO workspaces (name) VALUES (?) RETURNING id, name",
  53. name
  54. )
  55. .fetch_one(&db)
  56. .await
  57. {
  58. Ok(workspace) => Ok(workspace),
  59. Err(e) => Err(e.to_string()),
  60. }
  61. }
  62. pub async fn list_workspaces(db: SqlitePool) -> AppResult<Vec<Workspace>> {
  63. Ok(
  64. sqlx::query_as!(Workspace, "SELECT id, name FROM workspaces")
  65. .fetch_all(&db)
  66. .await?,
  67. )
  68. }
  69. /// Check whether the entry whose `id` == `parent_id` supports children.
  70. async fn check_parent(db: &SqlitePool, parent_id: Option<i64>) -> AppResult<()> {
  71. let Some(parent_id) = parent_id else {
  72. return Ok(());
  73. };
  74. let ty = sqlx::query!("SELECT type FROM workspace_entries WHERE id = ?", parent_id)
  75. .fetch_one(db)
  76. .await?
  77. .r#type;
  78. if !matches!(WorkspaceEntryType::from(ty), WorkspaceEntryType::Collection) {
  79. return Err(AppError::InvalidUpdate(format!(
  80. "{parent_id} is not a valid parent ID (type: {ty})"
  81. )));
  82. }
  83. Ok(())
  84. }
  85. pub async fn create_workspace_entry(
  86. db: SqlitePool,
  87. entry: WorkspaceEntryCreate,
  88. ) -> AppResult<WorkspaceEntryBase> {
  89. match entry {
  90. WorkspaceEntryCreate::Collection {
  91. name,
  92. workspace_id,
  93. parent_id,
  94. auth_inherit,
  95. } => {
  96. check_parent(&db, parent_id).await?;
  97. let entry = sqlx::query_as!(
  98. WorkspaceEntryBase,
  99. r#"INSERT INTO workspace_entries(name, workspace_id, parent_id, type, auth_inherit) VALUES (?, ?, ?, ?, ?)
  100. RETURNING id, workspace_id, parent_id, name, type, auth, auth_inherit"#,
  101. name,
  102. workspace_id,
  103. parent_id,
  104. 1,
  105. auth_inherit,
  106. )
  107. .fetch_one(&db).await?;
  108. Ok(entry)
  109. }
  110. WorkspaceEntryCreate::Request {
  111. name,
  112. workspace_id,
  113. parent_id,
  114. method,
  115. url,
  116. auth_inherit,
  117. } => {
  118. check_parent(&db, parent_id).await?;
  119. let mut tx = db.begin().await?;
  120. let entry = match sqlx::query_as!(
  121. WorkspaceEntryBase,
  122. r#"INSERT INTO workspace_entries(name, workspace_id, parent_id, type, auth_inherit) VALUES (?, ?, ?, ?, ?)
  123. RETURNING id, workspace_id, name, parent_id, type, auth, auth_inherit"#,
  124. name,
  125. workspace_id,
  126. parent_id,
  127. 0,
  128. auth_inherit
  129. )
  130. .fetch_one(&mut *tx).await {
  131. Ok(entry) => entry,
  132. Err(e) => {
  133. tx.rollback().await?;
  134. return Err(e.into());
  135. }
  136. };
  137. match sqlx::query!(
  138. "INSERT INTO request_params(workspace_id, request_id, method, url) VALUES (?, ?, ?, ?)",
  139. workspace_id,
  140. entry.id,
  141. method,
  142. url
  143. )
  144. .execute(&mut *tx)
  145. .await {
  146. Ok(_) => {},
  147. Err(e) => {
  148. tx.rollback().await?;
  149. return Err(e.into());
  150. }
  151. }
  152. ;
  153. tx.commit().await?;
  154. Ok(entry)
  155. }
  156. }
  157. }
  158. pub async fn insert_request_body(
  159. db: SqlitePool,
  160. entry_id: i64,
  161. body: RequestBody,
  162. ) -> AppResult<EntryRequestBody> {
  163. Ok(sqlx::query_as!(EntryRequestBody, r#"INSERT INTO request_bodies(request_id, ty, content) VALUES (?, ?, ?) RETURNING id, ty AS "ty: _", content"#, entry_id, body.ty, body.content).fetch_one(&db).await?)
  164. }
  165. pub async fn update_request_body(
  166. db: SqlitePool,
  167. id: i64,
  168. body: Update<RequestBody>,
  169. ) -> AppResult<()> {
  170. match body {
  171. Update::Value(body) => {
  172. sqlx::query!(
  173. "UPDATE request_bodies SET ty = ?, content = ? WHERE id = ?",
  174. body.ty,
  175. body.content,
  176. id,
  177. )
  178. .execute(&db)
  179. .await?;
  180. }
  181. Update::Null => {
  182. sqlx::query!("DELETE FROM request_bodies WHERE id = ?", id)
  183. .execute(&db)
  184. .await?;
  185. }
  186. }
  187. Ok(())
  188. }
  189. pub async fn update_request_method(db: SqlitePool, request_id: i64, method: &str) -> AppResult<()> {
  190. sqlx::query!(
  191. "UPDATE request_params SET method = ? WHERE request_id = ?",
  192. method,
  193. request_id
  194. )
  195. .execute(&db)
  196. .await?;
  197. Ok(())
  198. }
  199. pub async fn get_query_param(db: &SqlitePool, qp_id: i64) -> AppResult<QueryParamRead> {
  200. Ok(sqlx::query_as!(
  201. QueryParamRead,
  202. "SELECT id, position, key, value FROM request_query_params WHERE id = ?",
  203. qp_id
  204. )
  205. .fetch_one(db)
  206. .await?)
  207. }
  208. pub async fn delete_query_param(db: &SqlitePool, id: i64) -> AppResult<()> {
  209. sqlx::query!("DELETE FROM request_query_params WHERE id = ?", id)
  210. .execute(db)
  211. .await?;
  212. Ok(())
  213. }
  214. pub async fn update_query_param_values(
  215. db: &SqlitePool,
  216. id: i64,
  217. key: &str,
  218. value: &str,
  219. ) -> AppResult<()> {
  220. sqlx::query!(
  221. "UPDATE request_query_params SET key = ?, value = ? WHERE id = ?",
  222. key,
  223. value,
  224. id
  225. )
  226. .execute(db)
  227. .await?;
  228. Ok(())
  229. }
  230. pub async fn update_query_param_enabled(
  231. db: &SqlitePool,
  232. qp_id: i64,
  233. position: Option<i64>,
  234. ) -> AppResult<QueryParamRead> {
  235. Ok(sqlx::query_as!(
  236. QueryParamRead,
  237. "UPDATE request_query_params SET position = ? WHERE id = ? RETURNING id, position, key, value",
  238. position,
  239. qp_id
  240. )
  241. .fetch_one(db)
  242. .await?)
  243. }
  244. pub async fn update_query_param_position(
  245. db: &SqlitePool,
  246. req_id: i64,
  247. // Offset by amount
  248. offset: i64,
  249. // Start from position
  250. position: i64,
  251. ) -> AppResult<()> {
  252. sqlx::query!(
  253. "UPDATE request_query_params SET position = position + ? WHERE request_id = ? AND position > ?",
  254. offset,
  255. req_id,
  256. position,
  257. )
  258. .execute(db)
  259. .await?;
  260. Ok(())
  261. }
  262. /// Return only the active request params.
  263. pub async fn get_request_url_params(
  264. db: &SqlitePool,
  265. request_id: i64,
  266. ) -> AppResult<(Vec<PathParamRead>, Vec<QueryParamRead>)> {
  267. let mut path = vec![];
  268. let mut query = vec![];
  269. let params = sqlx::query!(
  270. r#"
  271. SELECT id, position, name, value, 0 AS type
  272. FROM request_path_params WHERE request_id = ?
  273. UNION
  274. SELECT id, position, key AS "name", value, 1 AS type
  275. FROM request_query_params WHERE request_id = ?
  276. "#,
  277. request_id,
  278. request_id
  279. )
  280. .fetch_all(db)
  281. .await?;
  282. for param in params {
  283. match param.r#type {
  284. 0 => path.push(PathParamRead::new(
  285. param.id,
  286. // Path positions can never be null
  287. param.position.unwrap(),
  288. param.name,
  289. param.value,
  290. )),
  291. 1 => query.push(QueryParamRead::new(
  292. param.id,
  293. param.position,
  294. param.name,
  295. param.value,
  296. )),
  297. _ => unreachable!(),
  298. }
  299. }
  300. Ok((path, query))
  301. }
  302. pub async fn update_request_url(
  303. db: &SqlitePool,
  304. request_id: i64,
  305. url: &str,
  306. path_params: Option<Vec<RequestPathUpdate<'_>>>,
  307. query_params: Option<Vec<RequestQueryUpdate<'_>>>,
  308. ) -> AppResult<()> {
  309. let mut tx = db.begin().await?;
  310. sqlx::query!(
  311. "UPDATE request_params SET url = ? WHERE request_id = ?",
  312. url,
  313. request_id
  314. )
  315. .execute(&mut *tx)
  316. .await?;
  317. if let Some(path_params) = path_params {
  318. // Empty path params means delete everything since they cannot be toggled
  319. // and their position is ALWAYS unique
  320. if path_params.is_empty() {
  321. sqlx::query!(
  322. "DELETE FROM request_path_params WHERE request_id = ?",
  323. request_id
  324. )
  325. .execute(&mut *tx)
  326. .await?;
  327. } else {
  328. let mut sql = QueryBuilder::new(
  329. "INSERT INTO request_path_params(position, request_id, name, value) ",
  330. );
  331. sql.push_values(path_params.iter(), |mut b, path| {
  332. b.push_bind(path.position as i64)
  333. .push_bind(request_id)
  334. .push_bind(path.name)
  335. .push("COALESCE(")
  336. .push_bind_unseparated(path.value)
  337. .push_unseparated(
  338. ", (SELECT value FROM request_path_params WHERE request_id = ",
  339. )
  340. .push_bind_unseparated(request_id)
  341. .push_unseparated("AND position = ")
  342. .push_bind_unseparated(path.position as i64)
  343. .push_unseparated("), '')");
  344. });
  345. // Delete any conflicting positions
  346. sql.push(
  347. r#"
  348. ON CONFLICT(position, request_id) DO UPDATE
  349. SET
  350. value = excluded.value,
  351. name = excluded.name;
  352. DELETE FROM request_path_params
  353. WHERE request_id = "#,
  354. )
  355. .push_bind(request_id)
  356. .push(" AND position NOT IN (");
  357. let mut sep = sql.separated(", ");
  358. for param in path_params.iter() {
  359. sep.push_bind(param.position as i64);
  360. }
  361. sep.push_unseparated(")");
  362. sql.build().execute(&mut *tx).await?;
  363. }
  364. }
  365. if let Some(query_params) = query_params {
  366. // Query param updates consider only the enabled QPs since toggling any
  367. // disabled ones always adds them to the end of the list
  368. if query_params.is_empty() {
  369. sqlx::query!(
  370. "DELETE FROM request_query_params WHERE request_id = ? AND position IS NOT NULL",
  371. request_id
  372. )
  373. .execute(&mut *tx)
  374. .await?;
  375. } else {
  376. let mut sql = QueryBuilder::new(
  377. "INSERT INTO request_query_params(position, request_id, key, value) ",
  378. );
  379. sql.push_values(query_params.iter(), |mut b, qp| {
  380. b.push_bind(qp.position as i64)
  381. .push_bind(request_id)
  382. .push_bind(qp.key)
  383. .push_bind(qp.value);
  384. });
  385. // Query params are unique by position and req_id
  386. sql.push(
  387. r#"
  388. ON CONFLICT(position, request_id) DO UPDATE
  389. SET
  390. value = excluded.value,
  391. key = excluded.key;
  392. DELETE FROM request_query_params
  393. WHERE request_id = "#,
  394. )
  395. .push_bind(request_id)
  396. .push(" AND position IS NOT NULL AND position NOT IN (");
  397. let mut sep = sql.separated(", ");
  398. for param in query_params.iter() {
  399. sep.push_bind(param.position as i64);
  400. }
  401. sep.push_unseparated(")");
  402. sql.build().execute(&mut *tx).await?;
  403. }
  404. }
  405. tx.commit().await?;
  406. Ok(())
  407. }
  408. pub async fn update_entry_name(db: SqlitePool, entry_id: i64, name: &str) -> AppResult<()> {
  409. sqlx::query!(
  410. "UPDATE workspace_entries SET name = ? WHERE id = ?",
  411. name,
  412. entry_id
  413. )
  414. .execute(&db)
  415. .await?;
  416. Ok(())
  417. }
  418. pub async fn get_workspace_request(db: SqlitePool, id: i64) -> AppResult<WorkspaceRequest> {
  419. let entry = sqlx::query_as!(
  420. WorkspaceEntryBase,
  421. "SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit FROM workspace_entries WHERE id = ?",
  422. id,
  423. )
  424. .fetch_one(&db)
  425. .await?;
  426. let params = sqlx::query_as!(
  427. RequestParams,
  428. r#"
  429. SELECT
  430. rp.request_id as id,
  431. method as 'method!',
  432. url as 'url!',
  433. rb.ty as "ty: _",
  434. rb.content AS "content: _",
  435. rb.id AS "body_id: _"
  436. FROM request_params rp
  437. LEFT JOIN request_bodies rb ON rp.request_id = rb.request_id
  438. WHERE rp.request_id = ?
  439. "#,
  440. id
  441. )
  442. .fetch_one(&db)
  443. .await?;
  444. let headers = sqlx::query_as!(
  445. RequestHeader,
  446. "SELECT id, name, value, enabled FROM request_headers WHERE request_id = ?",
  447. entry.id
  448. )
  449. .fetch_all(&db)
  450. .await?;
  451. let (path_params, query_params) = get_request_url_params(&db, id).await?;
  452. Ok(WorkspaceRequest::from_entry(
  453. entry,
  454. params,
  455. headers,
  456. path_params,
  457. query_params,
  458. ))
  459. }
  460. pub async fn get_workspace_entry(db: SqlitePool, id: i64) -> AppResult<WorkspaceEntry> {
  461. let entry = sqlx::query_as!(
  462. WorkspaceEntryBase,
  463. r#"
  464. SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit
  465. FROM workspace_entries
  466. WHERE id = ?
  467. LIMIT 1
  468. "#,
  469. id,
  470. )
  471. .fetch_one(&db)
  472. .await?;
  473. match entry.r#type {
  474. WorkspaceEntryType::Request => Ok(WorkspaceEntry::new_req(
  475. get_workspace_request(db, id).await?,
  476. )),
  477. WorkspaceEntryType::Collection => Ok(WorkspaceEntry::new_col(entry)),
  478. }
  479. }
  480. pub async fn list_workspace_entries_display(
  481. db: SqlitePool,
  482. workspace_id: i64,
  483. ) -> AppResult<Vec<WorkspaceEntryDisplay>> {
  484. let mut sql = QueryBuilder::new(
  485. r#"
  486. SELECT e.id, e.workspace_id, e.parent_id, e.name, e.type, e.auth, e.auth_inherit, rp.method
  487. FROM workspace_entries e
  488. LEFT JOIN request_params rp ON e.id = rp.request_id
  489. WHERE e.workspace_id = "#,
  490. );
  491. Ok(sql
  492. .push_bind(workspace_id)
  493. .push("ORDER BY type DESC")
  494. .build_query_as()
  495. .fetch_all(&db)
  496. .await?)
  497. }
  498. pub async fn list_workspace_entries(
  499. db: SqlitePool,
  500. workspace_id: i64,
  501. ) -> AppResult<Vec<WorkspaceEntryBase>> {
  502. Ok(sqlx::query_as!(
  503. WorkspaceEntryBase,
  504. "SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit FROM workspace_entries WHERE workspace_id = ? ORDER BY type DESC",
  505. workspace_id,
  506. )
  507. .fetch_all(&db)
  508. .await?)
  509. }
  510. pub async fn list_environments(
  511. db: SqlitePool,
  512. workspace_id: i64,
  513. ) -> AppResult<Vec<WorkspaceEnvironment>> {
  514. let records = sqlx::query!(
  515. r#"
  516. SELECT
  517. env.workspace_id,
  518. env.id AS env_id,
  519. env.name AS env_name,
  520. var.id AS "var_id?",
  521. var.name AS "var_name?",
  522. var.value AS "var_value?",
  523. var.secret AS "var_secret?"
  524. FROM workspace_envs env
  525. LEFT JOIN workspace_env_variables var ON env.id = var.env_id
  526. WHERE env.workspace_id = $1"#,
  527. workspace_id
  528. )
  529. .fetch_all(&db)
  530. .await?;
  531. let mut environments: HashMap<i64, WorkspaceEnvironment> = HashMap::new();
  532. for record in records {
  533. if let Some(env) = environments.get_mut(&record.env_id) {
  534. if record.var_id.is_some() {
  535. env.variables.push(WorkspaceEnvVariable {
  536. id: record.var_id.unwrap(),
  537. workspace_id,
  538. env_id: record.env_id,
  539. name: record.var_name.unwrap(),
  540. value: record.var_value.unwrap(),
  541. secret: record.var_secret.unwrap(),
  542. })
  543. }
  544. } else {
  545. let mut env = WorkspaceEnvironment {
  546. id: record.env_id,
  547. name: record.env_name,
  548. workspace_id,
  549. variables: vec![],
  550. };
  551. if record.var_id.is_some() {
  552. env.variables.push(WorkspaceEnvVariable {
  553. id: record.var_id.unwrap(),
  554. workspace_id,
  555. env_id: record.env_id,
  556. name: record.var_name.unwrap(),
  557. value: record.var_value.unwrap(),
  558. secret: record.var_secret.unwrap(),
  559. })
  560. }
  561. environments.insert(record.env_id, env);
  562. }
  563. }
  564. Ok(environments.into_values().collect())
  565. }
  566. pub async fn get_env_variables(
  567. db: &SqlitePool,
  568. env_id: i64,
  569. names: &[&str],
  570. ) -> AppResult<Vec<(String, String)>> {
  571. let mut query =
  572. QueryBuilder::new("SELECT name, value FROM workspace_env_variables WHERE env_id = ");
  573. query.push_bind(env_id);
  574. let mut separated = query.push(" AND name IN (").separated(", ");
  575. for name in names {
  576. separated.push_bind(name);
  577. }
  578. separated.push_unseparated(")");
  579. Ok(query
  580. .build_query_as::<(String, String)>()
  581. .fetch_all(db)
  582. .await?)
  583. }
  584. pub async fn create_environment(
  585. db: SqlitePool,
  586. workspace_id: i64,
  587. name: String,
  588. ) -> AppResult<WorkspaceEnvironment> {
  589. let row = sqlx::query!(
  590. r#"
  591. INSERT INTO workspace_envs (workspace_id, name)
  592. VALUES (?, ?)
  593. RETURNING id, workspace_id, name
  594. "#,
  595. workspace_id,
  596. name
  597. )
  598. .fetch_one(&db)
  599. .await?;
  600. Ok(WorkspaceEnvironment {
  601. id: row.id,
  602. workspace_id: row.workspace_id,
  603. name: row.name,
  604. variables: vec![],
  605. })
  606. }
  607. pub async fn update_environment(db: SqlitePool, env_id: i64, name: String) -> AppResult<()> {
  608. sqlx::query!(
  609. r#"
  610. UPDATE workspace_envs SET name = ? WHERE id = ?
  611. "#,
  612. name,
  613. env_id,
  614. )
  615. .execute(&db)
  616. .await?;
  617. Ok(())
  618. }
  619. pub async fn insert_env_var(
  620. db: SqlitePool,
  621. workspace_id: i64,
  622. env_id: i64,
  623. name: String,
  624. value: String,
  625. secret: bool,
  626. ) -> AppResult<WorkspaceEnvVariable> {
  627. Ok(sqlx::query_as!(
  628. WorkspaceEnvVariable,
  629. r#"
  630. INSERT INTO workspace_env_variables (workspace_id, env_id, name, value, secret)
  631. VALUES (?, ?, ?, ?, ?)
  632. RETURNING id, workspace_id, env_id, name, value, secret
  633. "#,
  634. workspace_id,
  635. env_id,
  636. name,
  637. value,
  638. secret,
  639. )
  640. .fetch_one(&db)
  641. .await?)
  642. }
  643. pub async fn update_env_var(
  644. db: SqlitePool,
  645. id: i64,
  646. name: Option<String>,
  647. value: Option<String>,
  648. secret: Option<bool>,
  649. ) -> AppResult<()> {
  650. sqlx::query_as!(
  651. WorkspaceEnvVariable,
  652. r#"
  653. UPDATE workspace_env_variables
  654. SET
  655. name = COALESCE(?, name),
  656. value = COALESCE(?, value),
  657. secret = COALESCE(?, secret)
  658. WHERE id = ?
  659. "#,
  660. name,
  661. value,
  662. secret,
  663. id,
  664. )
  665. .execute(&db)
  666. .await?;
  667. Ok(())
  668. }
  669. pub async fn delete_env_var(db: SqlitePool, id: i64) -> AppResult<()> {
  670. sqlx::query_as!(
  671. WorkspaceEnvVariable,
  672. r#"
  673. DELETE FROM workspace_env_variables
  674. WHERE id = ?
  675. "#,
  676. id,
  677. )
  678. .execute(&db)
  679. .await?;
  680. Ok(())
  681. }
  682. pub async fn list_request_path_params(db: SqlitePool, id: i64) -> AppResult<Vec<PathParamWrite>> {
  683. Ok(sqlx::query_as!(
  684. PathParamWrite,
  685. "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
  686. id
  687. )
  688. .fetch_all(&db)
  689. .await?)
  690. }
  691. pub async fn insert_headers(
  692. db: SqlitePool,
  693. entry_id: i64,
  694. headers: Vec<RequestHeaderInsert>,
  695. ) -> AppResult<RequestHeader> {
  696. let mut insert = QueryBuilder::new("INSERT INTO request_headers(request_id, name, value) ");
  697. insert.push_values(headers, |mut b, header| {
  698. b.push_bind(entry_id)
  699. .push_bind(header.name)
  700. .push_bind(header.value);
  701. });
  702. Ok(insert
  703. .push("RETURNING id, name, value, enabled")
  704. .build_query_as()
  705. .fetch_one(&db)
  706. .await?)
  707. }
  708. pub async fn update_header_enabled(db: SqlitePool, id: i64, enabled: bool) -> AppResult<()> {
  709. sqlx::query!(
  710. "UPDATE request_headers SET enabled = ? WHERE id = ?",
  711. enabled,
  712. id
  713. )
  714. .execute(&db)
  715. .await?;
  716. Ok(())
  717. }
  718. pub async fn update_header(db: SqlitePool, header: RequestHeaderUpdate) -> AppResult<()> {
  719. sqlx::query!(
  720. "UPDATE request_headers SET name = COALESCE(?, ''), value = COALESCE(?, '') WHERE id = ?",
  721. header.name,
  722. header.value,
  723. header.id
  724. )
  725. .execute(&db)
  726. .await?;
  727. Ok(())
  728. }
  729. pub async fn delete_header(db: SqlitePool, header_id: i64) -> AppResult<()> {
  730. sqlx::query!("DELETE FROM request_headers WHERE id = ?", header_id)
  731. .execute(&db)
  732. .await?;
  733. Ok(())
  734. }
  735. pub async fn insert_auth(
  736. db: SqlitePool,
  737. workspace_id: i64,
  738. params: Auth,
  739. ) -> AppResult<Authentication> {
  740. let json = Json(&params);
  741. let record = sqlx::query!(
  742. "INSERT INTO auth(workspace_id, name, params) VALUES (?, 'New authentication', ?) RETURNING id, name",
  743. workspace_id,
  744. json
  745. )
  746. .fetch_one(&db)
  747. .await?;
  748. Ok(Authentication {
  749. id: record.id,
  750. workspace_id,
  751. name: record.name,
  752. params,
  753. })
  754. }
  755. pub async fn delete_auth(db: SqlitePool, id: i64) -> AppResult<()> {
  756. sqlx::query!("DELETE FROM auth WHERE id = ?", id)
  757. .execute(&db)
  758. .await?;
  759. Ok(())
  760. }
  761. pub async fn list_auth(db: SqlitePool, workspace_id: i64) -> AppResult<Vec<Authentication>> {
  762. let records = sqlx::query!(
  763. r#"
  764. SELECT id, name, workspace_id, params as "params: Json<Auth>"
  765. FROM auth
  766. WHERE workspace_id = ?
  767. "#,
  768. workspace_id
  769. )
  770. .fetch_all(&db)
  771. .await?;
  772. Ok(records
  773. .into_iter()
  774. .map(|record| Authentication {
  775. id: record.id,
  776. name: record.name,
  777. workspace_id: record.workspace_id,
  778. params: record.params.0,
  779. })
  780. .collect())
  781. }
  782. pub async fn get_auth(db: SqlitePool, id: i64) -> AppResult<Authentication> {
  783. let record = sqlx::query!(
  784. r#"
  785. SELECT id, workspace_id, name, params as "params: Json<Auth>"
  786. FROM auth
  787. WHERE id = ?
  788. "#,
  789. id
  790. )
  791. .fetch_one(&db)
  792. .await?;
  793. Ok(Authentication {
  794. id: record.id,
  795. name: record.name,
  796. workspace_id: record.workspace_id,
  797. params: record.params.0,
  798. })
  799. }
  800. pub async fn set_workspace_entry_auth(
  801. db: SqlitePool,
  802. entry_id: i64,
  803. auth_id: Option<i64>,
  804. inherit: Option<bool>,
  805. ) -> AppResult<()> {
  806. sqlx::query!(
  807. "UPDATE workspace_entries SET auth = ?, auth_inherit = COALESCE(?, auth_inherit) WHERE id = ?",
  808. auth_id,
  809. inherit,
  810. entry_id
  811. )
  812. .execute(&db)
  813. .await?;
  814. Ok(())
  815. }
  816. pub async fn update_auth(db: SqlitePool, auth_id: i64, params: Auth) -> AppResult<()> {
  817. let params = Json(params);
  818. sqlx::query!("UPDATE auth SET params = ? WHERE id = ?", params, auth_id)
  819. .execute(&db)
  820. .await?;
  821. Ok(())
  822. }
  823. pub async fn rename_auth(db: SqlitePool, auth_id: i64, name: String) -> AppResult<()> {
  824. sqlx::query!("UPDATE auth SET name = ? WHERE id = ?", name, auth_id)
  825. .execute(&db)
  826. .await?;
  827. Ok(())
  828. }
  829. /// Check for the existence of an auth ID in the workspace entry. If one does not exist,
  830. /// traverse its parents and attempt to find the first one that is present. If none exist,
  831. /// returns `None`.
  832. pub async fn get_auth_inherited(
  833. db: SqlitePool,
  834. mut parent_id: Option<i64>,
  835. ) -> AppResult<Option<i64>> {
  836. while let Some(id) = parent_id {
  837. let record = sqlx::query!(
  838. "SELECT auth, auth_inherit, parent_id FROM workspace_entries WHERE id = ?",
  839. id
  840. )
  841. .fetch_one(&db)
  842. .await?;
  843. if !record.auth_inherit {
  844. return Ok(record.auth);
  845. }
  846. parent_id = record.parent_id;
  847. }
  848. Ok(None)
  849. }