Add metadata and squash migrations

This commit is contained in:
Gregory Schier
2024-02-18 08:35:31 -08:00
parent 4c6bd63b8b
commit 5409678855
11 changed files with 108 additions and 44 deletions

View File

@@ -1,6 +1,6 @@
{ {
"db_name": "SQLite", "db_name": "SQLite",
"query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message, authentication_type,\n authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\"\n FROM grpc_requests\n WHERE workspace_id = ?\n ", "query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message, authentication_type,\n authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\",\n metadata AS \"metadata!: sqlx::types::Json<Vec<GrpcMetadataEntry>>\"\n FROM grpc_requests\n WHERE workspace_id = ?\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@@ -77,6 +77,11 @@
"name": "proto_files!: sqlx::types::Json<Vec<String>>", "name": "proto_files!: sqlx::types::Json<Vec<String>>",
"ordinal": 14, "ordinal": 14,
"type_info": "Text" "type_info": "Text"
},
{
"name": "metadata!: sqlx::types::Json<Vec<GrpcMetadataEntry>>",
"ordinal": 15,
"type_info": "Text"
} }
], ],
"parameters": { "parameters": {
@@ -97,8 +102,9 @@
false, false,
true, true,
false, false,
false,
false false
] ]
}, },
"hash": "545d21ff21bd02468be86746325dc9f1b50f3fe53d7735194d91927b5d14a436" "hash": "24a721700844cb0ea9c2585c4df796ec10188b559063a9093e432ae993154f31"
} }

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO grpc_requests (\n id, name, workspace_id, folder_id, sort_priority, url, service, method, message,\n proto_files, authentication_type, authentication, metadata\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority,\n url = excluded.url,\n service = excluded.service,\n method = excluded.method,\n message = excluded.message,\n proto_files = excluded.proto_files,\n authentication_type = excluded.authentication_type,\n authentication = excluded.authentication,\n metadata = excluded.metadata\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 13
},
"nullable": []
},
"hash": "38e8fd3b0959623322bf49cf6682a4ddeac667cf6e71b97bc7e122848ad1565f"
}

View File

@@ -1,6 +1,6 @@
{ {
"db_name": "SQLite", "db_name": "SQLite",
"query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message, authentication_type,\n authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\"\n FROM grpc_requests\n WHERE id = ?\n ", "query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message, authentication_type,\n authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\",\n metadata AS \"metadata!: sqlx::types::Json<Vec<GrpcMetadataEntry>>\"\n FROM grpc_requests\n WHERE id = ?\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@@ -77,6 +77,11 @@
"name": "proto_files!: sqlx::types::Json<Vec<String>>", "name": "proto_files!: sqlx::types::Json<Vec<String>>",
"ordinal": 14, "ordinal": 14,
"type_info": "Text" "type_info": "Text"
},
{
"name": "metadata!: sqlx::types::Json<Vec<GrpcMetadataEntry>>",
"ordinal": 15,
"type_info": "Text"
} }
], ],
"parameters": { "parameters": {
@@ -97,8 +102,9 @@
false, false,
true, true,
false, false,
false,
false false
] ]
}, },
"hash": "0d9e685f878fc2a0e1803c6aaae3828deebd684fc9f78e9f8595a550f90749fe" "hash": "697afa2c3072b7b01676be53d5857066724fc23c94cd279d074253d5581b6f2c"
} }

View File

@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO grpc_requests (\n id, name, workspace_id, folder_id, sort_priority, url, service, method, message,\n proto_files, authentication_type, authentication\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority,\n url = excluded.url,\n service = excluded.service,\n method = excluded.method,\n message = excluded.message,\n proto_files = excluded.proto_files,\n authentication_type = excluded.authentication_type,\n authentication = excluded.authentication\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "c554305252cb21e34aa1e3c1f204c6060c3d2a209689a879824dea4d26e5497e"
}

View File

@@ -1,22 +1,26 @@
CREATE TABLE grpc_requests CREATE TABLE grpc_requests
( (
id TEXT NOT NULL id TEXT NOT NULL
PRIMARY KEY, PRIMARY KEY,
model TEXT DEFAULT 'grpc_request' NOT NULL, model TEXT DEFAULT 'grpc_request' NOT NULL,
workspace_id TEXT NOT NULL workspace_id TEXT NOT NULL
REFERENCES workspaces REFERENCES workspaces
ON DELETE CASCADE, ON DELETE CASCADE,
folder_id TEXT NULL folder_id TEXT NULL
REFERENCES folders REFERENCES folders
ON DELETE CASCADE, ON DELETE CASCADE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
name TEXT NOT NULL, name TEXT NOT NULL,
sort_priority REAL NOT NULL, sort_priority REAL NOT NULL,
url TEXT NOT NULL, url TEXT NOT NULL,
service TEXT NULL, service TEXT NULL,
method TEXT NULL, method TEXT NULL,
message TEXT NOT NULL message TEXT NOT NULL,
proto_files TEXT DEFAULT '[]' NOT NULL,
authentication TEXT DEFAULT '{}' NOT NULL,
authentication_type TEXT NULL,
metadata TEXT DEFAULT '[]' NOT NULL
); );
CREATE TABLE grpc_connections CREATE TABLE grpc_connections

View File

@@ -1 +0,0 @@
ALTER TABLE grpc_requests ADD COLUMN proto_files TEXT DEFAULT '[]' NOT NULL;

View File

@@ -1,2 +0,0 @@
ALTER TABLE grpc_requests ADD COLUMN authentication TEXT NOT NULL DEFAULT '{}';
ALTER TABLE grpc_requests ADD COLUMN authentication_type TEXT;

View File

@@ -16,7 +16,7 @@ use std::process::exit;
use std::str::FromStr; use std::str::FromStr;
use ::http::uri::InvalidUri; use ::http::uri::InvalidUri;
use ::http::Uri; use ::http::{HeaderValue, Uri};
use base64::Engine; use base64::Engine;
use fern::colors::ColoredLevelConfig; use fern::colors::ColoredLevelConfig;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
@@ -275,6 +275,23 @@ async fn cmd_grpc_go(
}; };
let event_handler = w.listen_global(format!("grpc_client_msg_{}", conn.id).as_str(), cb); let event_handler = w.listen_global(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
let mut metadata = HashMap::new(); let mut metadata = HashMap::new();
// Add rest of metadata
for h in req.clone().metadata.0 {
if h.name.is_empty() && h.value.is_empty() {
continue;
}
if !h.enabled {
continue;
}
let name = render::render(&h.name, &workspace, environment.as_ref());
let value = render::render(&h.value, &workspace, environment.as_ref());
metadata.insert(name, value);
}
if let Some(b) = &req.authentication_type { if let Some(b) = &req.authentication_type {
let req = req.clone(); let req = req.clone();
let environment_ref = environment.as_ref(); let environment_ref = environment.as_ref();
@@ -304,6 +321,7 @@ async fn cmd_grpc_go(
metadata.insert("Authorization".to_string(), format!("Bearer {token}")); metadata.insert("Authorization".to_string(), format!("Bearer {token}"));
} }
} }
println!("METADATA: {:?}", metadata); println!("METADATA: {:?}", metadata);
let grpc_listen = { let grpc_listen = {

View File

@@ -189,6 +189,15 @@ impl HttpResponse {
} }
} }
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default, rename_all = "camelCase")]
pub struct GrpcMetadataEntry {
#[serde(default = "default_true")]
pub enabled: bool,
pub name: String,
pub value: String,
}
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)] #[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default, rename_all = "camelCase")] #[serde(default, rename_all = "camelCase")]
pub struct GrpcRequest { pub struct GrpcRequest {
@@ -207,6 +216,7 @@ pub struct GrpcRequest {
pub proto_files: Json<Vec<String>>, pub proto_files: Json<Vec<String>>,
pub authentication_type: Option<String>, pub authentication_type: Option<String>,
pub authentication: Json<HashMap<String, JsonValue>>, pub authentication: Json<HashMap<String, JsonValue>>,
pub metadata: Json<Vec<GrpcMetadataEntry>>,
} }
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)] #[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)]
@@ -504,9 +514,9 @@ pub async fn upsert_grpc_request(
r#" r#"
INSERT INTO grpc_requests ( INSERT INTO grpc_requests (
id, name, workspace_id, folder_id, sort_priority, url, service, method, message, id, name, workspace_id, folder_id, sort_priority, url, service, method, message,
proto_files, authentication_type, authentication proto_files, authentication_type, authentication, metadata
) )
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET ON CONFLICT (id) DO UPDATE SET
updated_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP,
name = excluded.name, name = excluded.name,
@@ -518,7 +528,8 @@ pub async fn upsert_grpc_request(
message = excluded.message, message = excluded.message,
proto_files = excluded.proto_files, proto_files = excluded.proto_files,
authentication_type = excluded.authentication_type, authentication_type = excluded.authentication_type,
authentication = excluded.authentication authentication = excluded.authentication,
metadata = excluded.metadata
"#, "#,
id, id,
trimmed_name, trimmed_name,
@@ -532,6 +543,7 @@ pub async fn upsert_grpc_request(
request.proto_files, request.proto_files,
request.authentication_type, request.authentication_type,
request.authentication, request.authentication,
request.metadata,
) )
.execute(&db) .execute(&db)
.await?; .await?;
@@ -554,7 +566,8 @@ pub async fn get_grpc_request(
id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority, id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,
url, service, method, message, authentication_type, url, service, method, message, authentication_type,
authentication AS "authentication!: Json<HashMap<String, JsonValue>>", authentication AS "authentication!: Json<HashMap<String, JsonValue>>",
proto_files AS "proto_files!: sqlx::types::Json<Vec<String>>" proto_files AS "proto_files!: sqlx::types::Json<Vec<String>>",
metadata AS "metadata!: sqlx::types::Json<Vec<GrpcMetadataEntry>>"
FROM grpc_requests FROM grpc_requests
WHERE id = ? WHERE id = ?
"#, "#,
@@ -576,7 +589,8 @@ pub async fn list_grpc_requests(
id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority, id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,
url, service, method, message, authentication_type, url, service, method, message, authentication_type,
authentication AS "authentication!: Json<HashMap<String, JsonValue>>", authentication AS "authentication!: Json<HashMap<String, JsonValue>>",
proto_files AS "proto_files!: sqlx::types::Json<Vec<String>>" proto_files AS "proto_files!: sqlx::types::Json<Vec<String>>",
metadata AS "metadata!: sqlx::types::Json<Vec<GrpcMetadataEntry>>"
FROM grpc_requests FROM grpc_requests
WHERE workspace_id = ? WHERE workspace_id = ?
"#, "#,
@@ -1032,8 +1046,6 @@ pub async fn upsert_http_request(
"" => generate_id(Some("rq")), "" => generate_id(Some("rq")),
_ => r.id.to_string(), _ => r.id.to_string(),
}; };
let headers_json = Json(r.headers);
let auth_json = Json(r.authentication);
let trimmed_name = r.name.trim(); let trimmed_name = r.name.trim();
let db = get_db(mgr).await; let db = get_db(mgr).await;
@@ -1068,9 +1080,9 @@ pub async fn upsert_http_request(
r.method, r.method,
r.body, r.body,
r.body_type, r.body_type,
auth_json, r.authentication,
r.authentication_type, r.authentication_type,
headers_json, r.headers,
r.sort_priority, r.sort_priority,
) )
.execute(&db) .execute(&db)
@@ -1291,7 +1303,6 @@ pub async fn update_response(
mgr: &impl Manager<Wry>, mgr: &impl Manager<Wry>,
response: &HttpResponse, response: &HttpResponse,
) -> Result<HttpResponse, sqlx::Error> { ) -> Result<HttpResponse, sqlx::Error> {
let headers_json = Json(&response.headers);
let db = get_db(mgr).await; let db = get_db(mgr).await;
sqlx::query!( sqlx::query!(
r#" r#"
@@ -1308,7 +1319,7 @@ pub async fn update_response(
response.content_length, response.content_length,
response.body_path, response.body_path,
response.error, response.error,
headers_json, response.headers,
response.version, response.version,
response.remote_addr, response.remote_addr,
response.id, response.id,

View File

@@ -7,13 +7,14 @@ import type { ReflectResponseService } from '../hooks/useGrpc';
import { useGrpcConnections } from '../hooks/useGrpcConnections'; import { useGrpcConnections } from '../hooks/useGrpcConnections';
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey'; import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
import { useUpdateGrpcRequest } from '../hooks/useUpdateGrpcRequest'; import { useUpdateGrpcRequest } from '../hooks/useUpdateGrpcRequest';
import type { GrpcRequest } from '../lib/models'; import type { GrpcMetadataEntry, GrpcRequest } from '../lib/models';
import { AUTH_TYPE_BASIC, AUTH_TYPE_BEARER, AUTH_TYPE_NONE } from '../lib/models'; import { AUTH_TYPE_BASIC, AUTH_TYPE_BEARER, AUTH_TYPE_NONE } from '../lib/models';
import { BasicAuth } from './BasicAuth'; import { BasicAuth } from './BasicAuth';
import { BearerAuth } from './BearerAuth'; import { BearerAuth } from './BearerAuth';
import { Button } from './core/Button'; import { Button } from './core/Button';
import { Icon } from './core/Icon'; import { Icon } from './core/Icon';
import { IconButton } from './core/IconButton'; import { IconButton } from './core/IconButton';
import { PairEditor } from './core/PairEditor';
import { RadioDropdown } from './core/RadioDropdown'; import { RadioDropdown } from './core/RadioDropdown';
import { HStack, VStack } from './core/Stacks'; import { HStack, VStack } from './core/Stacks';
import type { TabItem } from './core/Tabs/Tabs'; import type { TabItem } from './core/Tabs/Tabs';
@@ -155,6 +156,11 @@ export function GrpcConnectionSetupPane({
[activeRequest.authentication, activeRequest.authenticationType, updateRequest], [activeRequest.authentication, activeRequest.authenticationType, updateRequest],
); );
const handleMetadataChange = useCallback(
(metadata: GrpcMetadataEntry[]) => updateRequest.mutate({ metadata }),
[updateRequest],
);
return ( return (
<VStack style={style}> <VStack style={style}>
<div <div
@@ -281,6 +287,15 @@ export function GrpcConnectionSetupPane({
<EmptyStateText>No Authentication {activeRequest.authenticationType}</EmptyStateText> <EmptyStateText>No Authentication {activeRequest.authenticationType}</EmptyStateText>
)} )}
</TabContent> </TabContent>
<TabContent value="metadata">
<PairEditor
valueAutocompleteVariables
nameAutocompleteVariables
pairs={activeRequest.metadata}
onChange={handleMetadataChange}
forceUpdateKey={forceUpdateKey}
/>
</TabContent>
</Tabs> </Tabs>
</VStack> </VStack>
); );

View File

@@ -104,6 +104,12 @@ export interface HttpUrlParameter {
enabled?: boolean; enabled?: boolean;
} }
export interface GrpcMetadataEntry {
name: string;
value: string;
enabled?: boolean;
}
export interface GrpcRequest extends BaseModel { export interface GrpcRequest extends BaseModel {
readonly workspaceId: string; readonly workspaceId: string;
readonly model: 'grpc_request'; readonly model: 'grpc_request';
@@ -117,6 +123,7 @@ export interface GrpcRequest extends BaseModel {
protoFiles: string[]; protoFiles: string[];
authentication: Record<string, string | number | boolean | null | undefined>; authentication: Record<string, string | number | boolean | null | undefined>;
authenticationType: string | null; authenticationType: string | null;
metadata: GrpcMetadataEntry[];
} }
export interface GrpcMessage extends BaseModel { export interface GrpcMessage extends BaseModel {