diff --git a/Cargo.lock b/Cargo.lock index 49d95f5..9dc42e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -599,9 +599,12 @@ dependencies = [ "prost 0.13.5", "prost-types 0.13.5", "ratatui", + "regex", "rstest", "serde", "serde_json", + "steel-core", + "steel-decimal", "strum 0.27.2", "strum_macros 0.27.2", "time", diff --git a/common/proto/table_script.proto b/common/proto/table_script.proto index b3ea63e..587ac53 100644 --- a/common/proto/table_script.proto +++ b/common/proto/table_script.proto @@ -33,6 +33,15 @@ service TableScript { // - UPSERTS into table_scripts on (table_definitions_id, target_column) // and saves a normalized dependency list into script_dependencies rpc PostTableScript(PostTableScriptRequest) returns (TableScriptResponse); + + // Fetch all stored scripts for a specific table. + // + // Behavior: + // - Resolves the table from (profile_name, table_name) + // - Returns the stored, transformed script from table_scripts + // - Includes normalized dependency metadata from script_dependencies + // - Returns an empty scripts list when the table has no scripts + rpc GetTableScripts(GetTableScriptsRequest) returns (GetTableScriptsResponse); } // Request to create or update a script bound to a specific table and column. @@ -99,3 +108,32 @@ message TableScriptResponse { // - Warning if many dependencies may affect performance string warnings = 2; } + +message GetTableScriptsRequest { + // Required. Profile (schema) name. + string profile_name = 1; + + // Required. Table name within the profile. + string table_name = 2; +} + +message GetTableScriptsResponse { + repeated StoredTableScript scripts = 1; +} + +message StoredTableScript { + int64 id = 1; + string target_column = 2; + string target_column_type = 3; + string script = 4; + string description = 5; + repeated ScriptDependency dependencies = 6; +} + +message ScriptDependency { + string target_table = 1; + string dependency_type = 2; + string column = 3; + int64 index = 4; + string query_fragment = 5; +} diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index a212cd5..4afc012 100644 Binary files a/common/src/proto/descriptor.bin and b/common/src/proto/descriptor.bin differ diff --git a/common/src/proto/komp_ac.table_script.rs b/common/src/proto/komp_ac.table_script.rs index 672b26e..1ab41e3 100644 --- a/common/src/proto/komp_ac.table_script.rs +++ b/common/src/proto/komp_ac.table_script.rs @@ -68,6 +68,48 @@ pub struct TableScriptResponse { #[prost(string, tag = "2")] pub warnings: ::prost::alloc::string::String, } +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetTableScriptsRequest { + /// Required. Profile (schema) name. + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, + /// Required. Table name within the profile. + #[prost(string, tag = "2")] + pub table_name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetTableScriptsResponse { + #[prost(message, repeated, tag = "1")] + pub scripts: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StoredTableScript { + #[prost(int64, tag = "1")] + pub id: i64, + #[prost(string, tag = "2")] + pub target_column: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub target_column_type: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub script: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub description: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "6")] + pub dependencies: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ScriptDependency { + #[prost(string, tag = "1")] + pub target_table: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub dependency_type: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub column: ::prost::alloc::string::String, + #[prost(int64, tag = "4")] + pub index: i64, + #[prost(string, tag = "5")] + pub query_fragment: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod table_script_client { #![allow( @@ -217,6 +259,42 @@ pub mod table_script_client { ); self.inner.unary(req, path, codec).await } + /// Fetch all stored scripts for a specific table. + /// + /// Behavior: + /// - Resolves the table from (profile_name, table_name) + /// - Returns the stored, transformed script from table_scripts + /// - Includes normalized dependency metadata from script_dependencies + /// - Returns an empty scripts list when the table has no scripts + pub async fn get_table_scripts( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.table_script.TableScript/GetTableScripts", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.table_script.TableScript", + "GetTableScripts", + ), + ); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -256,6 +334,20 @@ pub mod table_script_server { tonic::Response, tonic::Status, >; + /// Fetch all stored scripts for a specific table. + /// + /// Behavior: + /// - Resolves the table from (profile_name, table_name) + /// - Returns the stored, transformed script from table_scripts + /// - Includes normalized dependency metadata from script_dependencies + /// - Returns an empty scripts list when the table has no scripts + async fn get_table_scripts( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } /// Manages column-computation scripts for user-defined tables. /// Each script belongs to a single table (table_definition_id) and populates @@ -390,6 +482,51 @@ pub mod table_script_server { }; Box::pin(fut) } + "/komp_ac.table_script.TableScript/GetTableScripts" => { + #[allow(non_camel_case_types)] + struct GetTableScriptsSvc(pub Arc); + impl< + T: TableScript, + > tonic::server::UnaryService + for GetTableScriptsSvc { + type Response = super::GetTableScriptsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_table_scripts(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTableScriptsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { let mut response = http::Response::new(