serde of jsonb in grpc
This commit is contained in:
@@ -10,10 +10,10 @@ search = { path = "../search" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
tantivy = { workspace = true }
|
||||
prost = "0.13.5"
|
||||
prost-types = { workspace = true }
|
||||
chrono = { version = "0.4.40", features = ["serde"] }
|
||||
dotenvy = "0.15.7"
|
||||
prost = "0.13.5"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
sqlx = { version = "0.8.5", features = ["chrono", "postgres", "runtime-tokio", "runtime-tokio-native-tls", "rust_decimal", "time", "uuid"] }
|
||||
@@ -40,6 +40,9 @@ regex = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
steel-decimal = "1.0.0"
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = "0.14.1"
|
||||
|
||||
[lib]
|
||||
name = "server"
|
||||
path = "src/lib.rs"
|
||||
|
||||
@@ -23,7 +23,7 @@ use common::proto::komp_ac::{
|
||||
search2::search2_server::Search2Server,
|
||||
};
|
||||
use search::{SearcherService, SearcherServer};
|
||||
use crate::table_validation::post::service::TableValidationSvc;
|
||||
use crate::table_validation::get::service::TableValidationSvc;
|
||||
|
||||
pub async fn run_server(db_pool: sqlx::PgPool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Initialize JWT for authentication
|
||||
|
||||
@@ -2,28 +2,14 @@
|
||||
|
||||
use tonic::{Request, Response, Status};
|
||||
use sqlx::PgPool;
|
||||
use serde::Deserialize;
|
||||
use common::proto::komp_ac::table_validation::{
|
||||
table_validation_service_server::TableValidationService,
|
||||
GetTableValidationRequest, TableValidationResponse,
|
||||
FieldValidation, CharacterLimits, CountMode as PbCountMode,
|
||||
UpdateFieldValidationRequest, UpdateFieldValidationResponse,
|
||||
FieldValidation,
|
||||
};
|
||||
use crate::table_validation::post::repo; // repo still lives in post
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct FieldConfig {
|
||||
#[serde(default)]
|
||||
character_limits: Option<CharacterLimitsCfg>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CharacterLimitsCfg {
|
||||
#[serde(default)] min: Option<u32>,
|
||||
#[serde(default)] max: Option<u32>,
|
||||
#[serde(default)] warn_at: Option<u32>,
|
||||
#[serde(default)] count_mode: Option<String>, // "CHARS"/"BYTES"/"DISPLAY_WIDTH"
|
||||
}
|
||||
|
||||
pub struct TableValidationSvc {
|
||||
pub db: PgPool,
|
||||
}
|
||||
@@ -46,46 +32,71 @@ impl TableValidationService for TableValidationSvc {
|
||||
.await
|
||||
.map_err(|e| Status::internal(format!("Failed to fetch rules: {}", e)))?;
|
||||
|
||||
// 3. Map JSON -> proto
|
||||
// 3. Parse JSON directly into proto types
|
||||
let mut fields_out = Vec::new();
|
||||
for r in rules {
|
||||
let cfg: FieldConfig = match serde_json::from_value(r.config) {
|
||||
Ok(c) => c,
|
||||
match serde_json::from_value::<FieldValidation>(r.config) {
|
||||
Ok(mut fv) => {
|
||||
// Set the data_key from the database row
|
||||
fv.data_key = r.data_key;
|
||||
|
||||
// Skip if limits are all zero
|
||||
if let Some(lims) = &fv.limits {
|
||||
if lims.min == 0 && lims.max == 0 && lims.warn_at.is_none() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fields_out.push(fv);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("Invalid config for {}: {}", r.data_key, e);
|
||||
tracing::warn!("Invalid JSON for {}: {}", r.data_key, e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(cl) = cfg.character_limits {
|
||||
let min = cl.min.unwrap_or(0);
|
||||
let max = cl.max.unwrap_or(0);
|
||||
|
||||
// Skip "empty" validations (min=0,max=0,warn_at=None)
|
||||
if min == 0 && max == 0 && cl.warn_at.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pb_mode = match cl.count_mode.as_deref() {
|
||||
Some("BYTES") => PbCountMode::Bytes as i32,
|
||||
Some("DISPLAY_WIDTH") => PbCountMode::DisplayWidth as i32,
|
||||
_ => PbCountMode::Chars as i32,
|
||||
};
|
||||
|
||||
let limits = CharacterLimits {
|
||||
min,
|
||||
max,
|
||||
warn_at: cl.warn_at,
|
||||
count_mode: pb_mode,
|
||||
};
|
||||
|
||||
fields_out.push(FieldValidation {
|
||||
data_key: r.data_key,
|
||||
limits: Some(limits),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Response::new(TableValidationResponse { fields: fields_out }))
|
||||
}
|
||||
|
||||
async fn update_field_validation(
|
||||
&self,
|
||||
req: Request<UpdateFieldValidationRequest>,
|
||||
) -> Result<Response<UpdateFieldValidationResponse>, Status> {
|
||||
let req = req.into_inner();
|
||||
|
||||
let table_def_id = repo::get_table_def_id(
|
||||
&self.db, &req.profile_name, &req.table_name,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Status::not_found("Table definition not found"))?;
|
||||
|
||||
// Check if validation is provided
|
||||
if let Some(validation) = req.validation {
|
||||
// Convert proto FieldValidation directly to JSON
|
||||
let json_value = serde_json::to_value(&validation)
|
||||
.map_err(|e| Status::internal(format!("serialize error: {e}")))?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"UPDATE table_validation_rules
|
||||
SET config = $1, updated_at = now()
|
||||
WHERE table_def_id = $2 AND data_key = $3"#,
|
||||
json_value,
|
||||
table_def_id,
|
||||
req.data_key
|
||||
)
|
||||
.execute(&self.db)
|
||||
.await
|
||||
.map_err(|e| Status::internal(format!("DB error: {e}")))?;
|
||||
|
||||
Ok(Response::new(UpdateFieldValidationResponse {
|
||||
success: true,
|
||||
message: format!(
|
||||
"Validation rules updated for {}.{} column {}",
|
||||
req.profile_name, req.table_name, req.data_key
|
||||
),
|
||||
}))
|
||||
} else {
|
||||
Err(Status::invalid_argument("No validation provided"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
server/src/table_validation/post/service.rs
Normal file
18
server/src/table_validation/post/service.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
// src/table_validation/post/service.rs
|
||||
|
||||
use tonic::{Request, Response, Status};
|
||||
use sqlx::PgPool;
|
||||
use common::proto::komp_ac::table_validation::{
|
||||
UpdateFieldValidationRequest, UpdateFieldValidationResponse,
|
||||
};
|
||||
use crate::table_validation::post::repo;
|
||||
|
||||
pub struct TableValidationUpdateSvc {
|
||||
pub db: PgPool,
|
||||
}
|
||||
|
||||
impl TableValidationUpdateSvc {
|
||||
pub fn new(db: PgPool) -> Self {
|
||||
Self { db }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user