mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-31 22:43:11 +02:00
Separate model for GQL introspection data (#222)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use crate::error::Error::GenericError;
|
||||
use crate::error::Result;
|
||||
use crate::models::{AnyModel, GrpcEvent, Settings, WebsocketEvent};
|
||||
use crate::models::{AnyModel, GraphQlIntrospection, GrpcEvent, Settings, WebsocketEvent};
|
||||
use crate::query_manager::QueryManagerExt;
|
||||
use crate::util::UpdateSource;
|
||||
use tauri::{AppHandle, Runtime, WebviewWindow};
|
||||
@@ -90,6 +90,26 @@ pub(crate) fn get_settings<R: Runtime>(app_handle: AppHandle<R>) -> Result<Setti
|
||||
Ok(app_handle.db().get_settings())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn get_graphql_introspection<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
request_id: &str,
|
||||
) -> Result<Option<GraphQlIntrospection>> {
|
||||
Ok(app_handle.db().get_graphql_introspection(request_id))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn upsert_graphql_introspection<R: Runtime>(
|
||||
app_handle: AppHandle<R>,
|
||||
request_id: &str,
|
||||
workspace_id: &str,
|
||||
content: Option<String>,
|
||||
window: WebviewWindow<R>,
|
||||
) -> Result<GraphQlIntrospection> {
|
||||
let source = UpdateSource::from_window(&window);
|
||||
Ok(app_handle.db().upsert_graphql_introspection(workspace_id, request_id, content, &source)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn workspace_models<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
@@ -121,11 +141,11 @@ pub(crate) fn workspace_models<R: Runtime>(
|
||||
}
|
||||
|
||||
let j = serde_json::to_string(&l)?;
|
||||
|
||||
|
||||
// NOTE: There's something weird that happens on Linux. If we send Cyrillic (or maybe other)
|
||||
// unicode characters in this response (doesn't matter where) then the following bug happens:
|
||||
// https://feedback.yaak.app/p/editing-the-url-sometimes-freezes-the-app
|
||||
//
|
||||
//
|
||||
// It's as if every string resulting from the JSON.parse of the models gets encoded slightly
|
||||
// wrong or something, causing the above bug where Codemirror can't calculate the cursor
|
||||
// position anymore (even when none of the characters are included directly in the input).
|
||||
@@ -137,19 +157,22 @@ pub(crate) fn workspace_models<R: Runtime>(
|
||||
}
|
||||
|
||||
fn escape_str_for_webview(input: &str) -> String {
|
||||
input.chars().map(|c| {
|
||||
let code = c as u32;
|
||||
// ASCII
|
||||
if code <= 0x7F {
|
||||
c.to_string()
|
||||
// BMP characters encoded normally
|
||||
} else if code < 0xFFFF {
|
||||
format!("\\u{:04X}", code)
|
||||
// Beyond BMP encoded a surrogate pairs
|
||||
} else {
|
||||
let high = ((code - 0x10000) >> 10) + 0xD800;
|
||||
let low = ((code - 0x10000) & 0x3FF) + 0xDC00;
|
||||
format!("\\u{:04X}\\u{:04X}", high, low)
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
input
|
||||
.chars()
|
||||
.map(|c| {
|
||||
let code = c as u32;
|
||||
// ASCII
|
||||
if code <= 0x7F {
|
||||
c.to_string()
|
||||
// BMP characters encoded normally
|
||||
} else if code < 0xFFFF {
|
||||
format!("\\u{:04X}", code)
|
||||
// Beyond BMP encoded a surrogate pairs
|
||||
} else {
|
||||
let high = ((code - 0x10000) >> 10) + 0xD800;
|
||||
let low = ((code - 0x10000) & 0x3FF) + 0xDC00;
|
||||
format!("\\u{:04X}\\u{:04X}", high, low)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ use crate::util::ModelChangeEvent;
|
||||
use log::info;
|
||||
use r2d2::Pool;
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::SqliteConnectOptions;
|
||||
use sqlx::SqlitePool;
|
||||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@@ -14,7 +14,7 @@ use std::time::Duration;
|
||||
use tauri::async_runtime::Mutex;
|
||||
use tauri::path::BaseDirectory;
|
||||
use tauri::plugin::TauriPlugin;
|
||||
use tauri::{generate_handler, AppHandle, Emitter, Manager, Runtime};
|
||||
use tauri::{AppHandle, Emitter, Manager, Runtime, generate_handler};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
mod commands;
|
||||
@@ -39,13 +39,15 @@ impl SqliteConnection {
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("yaak-models")
|
||||
.invoke_handler(generate_handler![
|
||||
upsert,
|
||||
delete,
|
||||
duplicate,
|
||||
workspace_models,
|
||||
grpc_events,
|
||||
websocket_events,
|
||||
get_graphql_introspection,
|
||||
get_settings,
|
||||
grpc_events,
|
||||
upsert,
|
||||
upsert_graphql_introspection,
|
||||
websocket_events,
|
||||
workspace_models,
|
||||
])
|
||||
.setup(|app_handle, _api| {
|
||||
let app_path = app_handle.path().app_data_dir().unwrap();
|
||||
|
||||
@@ -1342,6 +1342,79 @@ impl UpsertModelInfo for HttpResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_models.ts")]
|
||||
#[enum_def(table_name = "graphql_introspections")]
|
||||
pub struct GraphQlIntrospection {
|
||||
#[ts(type = "\"graphql_introspection\"")]
|
||||
pub model: String,
|
||||
pub id: String,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub updated_at: NaiveDateTime,
|
||||
pub workspace_id: String,
|
||||
pub request_id: String,
|
||||
pub content: Option<String>,
|
||||
}
|
||||
|
||||
impl UpsertModelInfo for GraphQlIntrospection {
|
||||
fn table_name() -> impl IntoTableRef {
|
||||
GraphQlIntrospectionIden::Table
|
||||
}
|
||||
|
||||
fn id_column() -> impl IntoIden + Eq + Clone {
|
||||
GraphQlIntrospectionIden::Id
|
||||
}
|
||||
|
||||
fn generate_id() -> String {
|
||||
generate_prefixed_id("gi")
|
||||
}
|
||||
|
||||
fn order_by() -> (impl IntoColumnRef, Order) {
|
||||
(GraphQlIntrospectionIden::CreatedAt, Desc)
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
fn insert_values(
|
||||
self,
|
||||
source: &UpdateSource,
|
||||
) -> Result<Vec<(impl IntoIden + Eq, impl Into<SimpleExpr>)>> {
|
||||
use GraphQlIntrospectionIden::*;
|
||||
Ok(vec![
|
||||
(CreatedAt, upsert_date(source, self.created_at)),
|
||||
(UpdatedAt, upsert_date(source, self.updated_at)),
|
||||
(WorkspaceId, self.workspace_id.into()),
|
||||
(RequestId, self.request_id.into()),
|
||||
(Content, self.content.into()),
|
||||
])
|
||||
}
|
||||
|
||||
fn update_columns() -> Vec<impl IntoIden> {
|
||||
vec![
|
||||
GraphQlIntrospectionIden::UpdatedAt,
|
||||
GraphQlIntrospectionIden::Content,
|
||||
]
|
||||
}
|
||||
|
||||
fn from_row(r: &Row) -> rusqlite::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(Self {
|
||||
id: r.get("id")?,
|
||||
model: r.get("model")?,
|
||||
created_at: r.get("created_at")?,
|
||||
updated_at: r.get("updated_at")?,
|
||||
workspace_id: r.get("workspace_id")?,
|
||||
request_id: r.get("request_id")?,
|
||||
content: r.get("content")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_models.ts")]
|
||||
@@ -2002,6 +2075,7 @@ define_any_model! {
|
||||
CookieJar,
|
||||
Environment,
|
||||
Folder,
|
||||
GraphQlIntrospection,
|
||||
GrpcConnection,
|
||||
GrpcEvent,
|
||||
GrpcRequest,
|
||||
@@ -2031,6 +2105,9 @@ impl<'de> Deserialize<'de> for AnyModel {
|
||||
Some(m) if m == "cookie_jar" => AnyModel::CookieJar(fv(value).unwrap()),
|
||||
Some(m) if m == "environment" => AnyModel::Environment(fv(value).unwrap()),
|
||||
Some(m) if m == "folder" => AnyModel::Folder(fv(value).unwrap()),
|
||||
Some(m) if m == "graphql_introspection" => {
|
||||
AnyModel::GraphQlIntrospection(fv(value).unwrap())
|
||||
}
|
||||
Some(m) if m == "grpc_connection" => AnyModel::GrpcConnection(fv(value).unwrap()),
|
||||
Some(m) if m == "grpc_event" => AnyModel::GrpcEvent(fv(value).unwrap()),
|
||||
Some(m) if m == "grpc_request" => AnyModel::GrpcRequest(fv(value).unwrap()),
|
||||
|
||||
55
src-tauri/yaak-models/src/queries/graphql_introspections.rs
Normal file
55
src-tauri/yaak-models/src/queries/graphql_introspections.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use crate::db_context::DbContext;
|
||||
use crate::error::Result;
|
||||
use crate::models::{GraphQlIntrospection, GraphQlIntrospectionIden};
|
||||
use crate::util::UpdateSource;
|
||||
use chrono::{Duration, Utc};
|
||||
use sea_query::{Expr, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
impl<'a> DbContext<'a> {
|
||||
pub fn get_graphql_introspection(&self, request_id: &str) -> Option<GraphQlIntrospection> {
|
||||
self.find_optional(GraphQlIntrospectionIden::RequestId, request_id)
|
||||
}
|
||||
|
||||
pub fn upsert_graphql_introspection(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
request_id: &str,
|
||||
content: Option<String>,
|
||||
source: &UpdateSource,
|
||||
) -> Result<GraphQlIntrospection> {
|
||||
// Clean up old ones every time a new one is upserted
|
||||
self.delete_expired_graphql_introspections()?;
|
||||
|
||||
match self.get_graphql_introspection(request_id) {
|
||||
None => self.upsert(
|
||||
&GraphQlIntrospection {
|
||||
content,
|
||||
request_id: request_id.to_string(),
|
||||
workspace_id: workspace_id.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
source,
|
||||
),
|
||||
Some(introspection) => self.upsert(
|
||||
&GraphQlIntrospection {
|
||||
content,
|
||||
..introspection
|
||||
},
|
||||
source,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_expired_graphql_introspections(&self) -> Result<()> {
|
||||
let cutoff = Utc::now().naive_utc() - Duration::days(7);
|
||||
let (sql, params) = Query::delete()
|
||||
.from_table(GraphQlIntrospectionIden::Table)
|
||||
.cond_where(Expr::col(GraphQlIntrospectionIden::UpdatedAt).lt(cutoff))
|
||||
.build_rusqlite(SqliteQueryBuilder);
|
||||
|
||||
let mut stmt = self.conn.resolve().prepare(sql.as_str())?;
|
||||
stmt.execute(&*params.as_params())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ mod batch;
|
||||
mod cookie_jars;
|
||||
mod environments;
|
||||
mod folders;
|
||||
mod graphql_introspections;
|
||||
mod grpc_connections;
|
||||
mod grpc_events;
|
||||
mod grpc_requests;
|
||||
|
||||
Reference in New Issue
Block a user