Compare commits

...

5 Commits
v0.6.4 ... main

Author SHA1 Message Date
Priec
3b0133640f more advancements 2026-05-03 23:34:03 +02:00
Priec
0600d3deaa table validation for the client from the server 2026-05-03 10:34:59 +02:00
Priec
90f8aedc3b better new functionality of column aliases 2026-05-02 13:56:45 +02:00
Priec
2a811b1f8c rename the column aliases 2026-05-02 00:38:54 +02:00
Priec
1f9c29411e multiple requests to the structure of a tables at once(batching) 2026-04-30 11:48:03 +02:00
14 changed files with 808 additions and 116 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ steel_decimal/tests/property_tests.proptest-regressions
.direnv/ .direnv/
canvas/*.toml canvas/*.toml
.aider* .aider*
.codex

11
Cargo.lock generated
View File

@@ -493,7 +493,7 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]] [[package]]
name = "canvas" name = "canvas"
version = "0.6.3" version = "0.6.7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -585,7 +585,7 @@ dependencies = [
[[package]] [[package]]
name = "client" name = "client"
version = "0.6.3" version = "0.6.7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -641,7 +641,7 @@ dependencies = [
[[package]] [[package]]
name = "common" name = "common"
version = "0.6.3" version = "0.6.7"
dependencies = [ dependencies = [
"prost 0.13.5", "prost 0.13.5",
"prost-build 0.14.1", "prost-build 0.14.1",
@@ -3116,7 +3116,7 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]] [[package]]
name = "search" name = "search"
version = "0.6.3" version = "0.6.7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"common", "common",
@@ -3215,7 +3215,7 @@ dependencies = [
[[package]] [[package]]
name = "server" name = "server"
version = "0.6.3" version = "0.6.7"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bcrypt", "bcrypt",
@@ -3252,6 +3252,7 @@ dependencies = [
"tonic-reflection", "tonic-reflection",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"unicode-width 0.2.0",
"uuid", "uuid",
"validator", "validator",
] ]

View File

@@ -5,7 +5,7 @@ resolver = "2"
[workspace.package] [workspace.package]
# TODO: idk how to do the name, fix later # TODO: idk how to do the name, fix later
# name = "komp_ac" # name = "komp_ac"
version = "0.6.3" version = "0.6.7"
edition = "2021" edition = "2021"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
authors = ["Filip Priečinský <filippriec@gmail.com>"] authors = ["Filip Priečinský <filippriec@gmail.com>"]

2
canvas

Submodule canvas updated: abbda5b7a9...d6e8ff58d5

2
client

Submodule client updated: 6a32d8cb3a...14a8b4ffbe

View File

@@ -24,6 +24,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
".komp_ac.table_validation.PatternRule", ".komp_ac.table_validation.PatternRule",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",
) )
.type_attribute(
".komp_ac.table_validation.PatternPosition",
"#[derive(serde::Serialize, serde::Deserialize)]",
)
.type_attribute(
".komp_ac.table_validation.CharacterConstraint",
"#[derive(serde::Serialize, serde::Deserialize)]",
)
.type_attribute( .type_attribute(
".komp_ac.table_validation.PatternRules", ".komp_ac.table_validation.PatternRules",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",
@@ -32,6 +40,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
".komp_ac.table_validation.CustomFormatter", ".komp_ac.table_validation.CustomFormatter",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",
) )
.type_attribute(
".komp_ac.table_validation.FormatterOption",
"#[derive(serde::Serialize, serde::Deserialize)]",
)
.type_attribute(
".komp_ac.table_validation.AllowedValues",
"#[derive(serde::Serialize, serde::Deserialize)]",
)
.type_attribute( .type_attribute(
".komp_ac.table_validation.UpdateFieldValidationRequest", ".komp_ac.table_validation.UpdateFieldValidationRequest",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",
@@ -40,11 +56,27 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
".komp_ac.table_validation.UpdateFieldValidationResponse", ".komp_ac.table_validation.UpdateFieldValidationResponse",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",
) )
.type_attribute(
".komp_ac.table_validation.ReplaceTableValidationRequest",
"#[derive(serde::Serialize, serde::Deserialize)]",
)
.type_attribute(
".komp_ac.table_validation.ReplaceTableValidationResponse",
"#[derive(serde::Serialize, serde::Deserialize)]",
)
// Enum -> readable strings in JSON ("BYTES", "DISPLAY_WIDTH") // Enum -> readable strings in JSON ("BYTES", "DISPLAY_WIDTH")
.type_attribute( .type_attribute(
".komp_ac.table_validation.CountMode", ".komp_ac.table_validation.CountMode",
"#[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]", "#[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]",
) )
.type_attribute(
".komp_ac.table_validation.PatternPositionKind",
"#[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]",
)
.type_attribute(
".komp_ac.table_validation.CharacterConstraintKind",
"#[derive(serde::Serialize, serde::Deserialize)] #[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]",
)
.type_attribute( .type_attribute(
".komp_ac.table_definition.ColumnDefinition", ".komp_ac.table_definition.ColumnDefinition",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",
@@ -61,6 +93,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
".komp_ac.table_definition.TableDefinitionResponse", ".komp_ac.table_definition.TableDefinitionResponse",
"#[derive(serde::Serialize, serde::Deserialize)]" "#[derive(serde::Serialize, serde::Deserialize)]"
) )
.type_attribute(
".komp_ac.table_definition.GetColumnAliasRenameHistoryRequest",
"#[derive(serde::Serialize, serde::Deserialize)]"
)
.type_attribute(
".komp_ac.table_definition.ColumnAliasRenameHistoryEntry",
"#[derive(serde::Serialize, serde::Deserialize)]"
)
.type_attribute(
".komp_ac.table_definition.GetColumnAliasRenameHistoryResponse",
"#[derive(serde::Serialize, serde::Deserialize)]"
)
.type_attribute(
".komp_ac.table_definition.RenameColumnAliasRequest",
"#[derive(serde::Serialize, serde::Deserialize)]"
)
.type_attribute(
".komp_ac.table_definition.RenameColumnAliasResponse",
"#[derive(serde::Serialize, serde::Deserialize)]"
)
.type_attribute( .type_attribute(
".komp_ac.table_script.PostTableScriptRequest", ".komp_ac.table_script.PostTableScriptRequest",
"#[derive(serde::Serialize, serde::Deserialize)]", "#[derive(serde::Serialize, serde::Deserialize)]",

View File

@@ -22,6 +22,12 @@ service TableDefinition {
// Pure data retrieval - no business logic. // Pure data retrieval - no business logic.
rpc GetProfileDetails(GetProfileDetailsRequest) returns (GetProfileDetailsResponse); rpc GetProfileDetails(GetProfileDetailsRequest) returns (GetProfileDetailsResponse);
// Returns the stored rename history for column aliases in one profile.
rpc GetColumnAliasRenameHistory(GetColumnAliasRenameHistoryRequest) returns (GetColumnAliasRenameHistoryResponse);
// Renames a user-visible column alias while keeping the physical column unchanged.
rpc RenameColumnAlias(RenameColumnAliasRequest) returns (RenameColumnAliasResponse);
// Drops a table and its metadata, then deletes the profile if it becomes empty. // Drops a table and its metadata, then deletes the profile if it becomes empty.
rpc DeleteTable(DeleteTableRequest) returns (DeleteTableResponse); rpc DeleteTable(DeleteTableRequest) returns (DeleteTableResponse);
} }
@@ -135,6 +141,31 @@ message GetProfileDetailsResponse {
repeated TableDetail tables = 2; repeated TableDetail tables = 2;
} }
// Request to fetch recorded column alias rename history for one profile.
message GetColumnAliasRenameHistoryRequest {
string profile_name = 1;
// Optional filter. When omitted, returns all tables in the profile.
optional int64 table_definition_id = 2;
}
// One recorded column alias rename.
message ColumnAliasRenameHistoryEntry {
int64 id = 1;
string profile_name = 2;
int64 table_definition_id = 3;
string table_name = 4;
string old_column_name = 5;
string new_column_name = 6;
string created_at = 7;
}
// Response with stored column alias rename history rows.
message GetColumnAliasRenameHistoryResponse {
string profile_name = 1;
repeated ColumnAliasRenameHistoryEntry entries = 2;
}
// Describes a table with its columns and associated scripts. // Describes a table with its columns and associated scripts.
message TableDetail { message TableDetail {
string name = 1; string name = 1;
@@ -152,6 +183,20 @@ message ScriptInfo {
string description = 5; string description = 5;
} }
// Request to rename one user-visible column alias in a table.
message RenameColumnAliasRequest {
string profile_name = 1;
string table_name = 2;
string old_column_name = 3;
string new_column_name = 4;
}
// Response after renaming one column alias.
message RenameColumnAliasResponse {
bool success = 1;
string message = 2;
}
// Request to delete one table definition entirely. // Request to delete one table definition entirely.
message DeleteTableRequest { message DeleteTableRequest {
// Profile (schema) name owning the table (must exist). // Profile (schema) name owning the table (must exist).

View File

@@ -4,40 +4,45 @@ package komp_ac.table_structure;
import "common.proto"; import "common.proto";
// Introspects the physical PostgreSQL table for a given logical table // Introspects the physical PostgreSQL tables for one or more logical tables
// (defined in table_definitions) and returns its column structure. // (defined in table_definitions) and returns their column structures.
// The server validates that: // The server validates that:
// - The profile (schema) exists in `schemas` // - The profile (schema) exists in `schemas`
// - The table is defined for that profile in `table_definitions` // - Every table is defined for that profile in `table_definitions`
// It then queries information_schema for the physical table and returns // It then queries information_schema for the physical tables and returns
// normalized column metadata. If the physical table is missing despite // normalized column metadata.
// a definition, the response may contain an empty `columns` list.
service TableStructureService { service TableStructureService {
// Return the physical column list (name, normalized data_type, // Return the physical column list (name, normalized data_type,
// nullability, primary key flag) for a table in a profile. // nullability, primary key flag) for one or more tables in a profile.
// //
// Behavior: // Behavior:
// - NOT_FOUND if profile doesn't exist in `schemas` // - NOT_FOUND if profile doesn't exist in `schemas`
// - NOT_FOUND if table not defined for that profile in `table_definitions` // - NOT_FOUND if any table is not defined for that profile in `table_definitions`
// - Queries information_schema.columns ordered by ordinal position // - Queries information_schema.columns ordered by ordinal position
// - Normalizes data_type text (details under TableColumn.data_type) // - Normalizes data_type text (details under TableColumn.data_type)
// - Returns an empty list if the table is validated but has no visible // - Returns an error if any validated table has no visible columns in
// columns in information_schema (e.g., physical table missing) // information_schema (e.g., physical table missing)
rpc GetTableStructure(GetTableStructureRequest) returns (TableStructureResponse); rpc GetTableStructure(GetTableStructureRequest) returns (GetTableStructureResponse);
} }
// Request identifying the profile (schema) and table to inspect. // Request identifying the profile (schema) and tables to inspect.
message GetTableStructureRequest { message GetTableStructureRequest {
// Required. Profile (PostgreSQL schema) name. Must exist in `schemas`. // Required. Profile (PostgreSQL schema) name. Must exist in `schemas`.
string profile_name = 1; string profile_name = 1;
// Required. Table name within the profile. Must exist in `table_definitions` // Required. Table names within the profile. Each must exist in
// for the given profile. The physical table is then introspected via // `table_definitions` for the given profile. The physical tables are then
// information_schema. // introspected via information_schema.
string table_name = 2; repeated string table_names = 2;
} }
// Response with the ordered list of columns (by ordinal position). // Batched response keyed by table name.
message GetTableStructureResponse {
// Per-table physical column lists keyed by requested table name.
map<string, TableStructureResponse> table_structures = 1;
}
// Response with the ordered list of columns (by ordinal position) for one table.
message TableStructureResponse { message TableStructureResponse {
// Columns of the physical table, including system columns (id, deleted, // Columns of the physical table, including system columns (id, deleted,
// created_at), user-defined columns, and any foreign-key columns such as // created_at), user-defined columns, and any foreign-key columns such as

View File

@@ -2,31 +2,55 @@
syntax = "proto3"; syntax = "proto3";
package komp_ac.table_validation; package komp_ac.table_validation;
// This proto is the canonical server-side storage and distribution contract for
// client validation configuration.
//
// Design goals:
// - The server stores the entire field validation definition in one structured payload.
// - Clients fetch the validation rules for a table in one batch and map them to
// their local validation/runtime system (for example canvas).
// - Common validation must be represented as typed data, not as string mini-languages.
//
// Important split:
// - limits / pattern / allowed_values / required are validation rules.
// - mask / formatter are presentation and input-shaping metadata for clients.
// Request validation rules for a table // Request validation rules for a table
message GetTableValidationRequest { message GetTableValidationRequest {
string profileName = 1; string profileName = 1;
string tableName = 2; string tableName = 2;
} }
// Response with field-level validations; if a field is omitted, // Response with field-level validations for the whole table.
// no validation is applied (default unspecified). // If a field is omitted, no validation configuration exists for that field.
message TableValidationResponse { message TableValidationResponse {
repeated FieldValidation fields = 1; repeated FieldValidation fields = 1;
} }
// Field-level validation (extensible for future kinds) // Field-level validation definition stored on the server and distributed to clients.
message FieldValidation { message FieldValidation {
// MUST match your frontend FormState.dataKey for the column // MUST match your frontend FormState.dataKey for the column
string dataKey = 1; string dataKey = 1;
// Current: only CharacterLimits. More rules can be added later. // Validation 1: length and counting rules.
CharacterLimits limits = 10; CharacterLimits limits = 10;
// Future expansion:
PatternRules pattern = 11; // Validation 2 // Validation 2: position-based character constraints.
optional CustomFormatter formatter = 14; // Validation 4 custom formatting logic PatternRules pattern = 11;
// Exact-value whitelist.
AllowedValues allowed_values = 12;
// Client-side hint that this field participates in external/asynchronous validation UI.
bool external_validation_enabled = 13;
// Client-side formatter metadata. This is intentionally data-only, not executable code.
optional CustomFormatter formatter = 14;
// Client-side display mask metadata. The server stores raw data without mask literals.
DisplayMask mask = 3; DisplayMask mask = 3;
// ExternalValidation external = 13;
// CustomFormatter formatter = 14; // Field must be provided / treated as required by clients and server enforcement layers.
bool required = 4; bool required = 4;
} }
@@ -38,7 +62,8 @@ enum CountMode {
DISPLAY_WIDTH = 3; DISPLAY_WIDTH = 3;
} }
// Character limit validation (Validation 1) // Character limit validation (Validation 1).
// These rules map directly to canvas CharacterLimits.
message CharacterLimits { message CharacterLimits {
// When zero, the field is considered "not set". If both min/max are zero, // When zero, the field is considered "not set". If both min/max are zero,
// the server should avoid sending this FieldValidation (no validation). // the server should avoid sending this FieldValidation (no validation).
@@ -51,39 +76,91 @@ message CharacterLimits {
CountMode countMode = 4; // defaults to CHARS if unspecified CountMode countMode = 4; // defaults to CHARS if unspecified
} }
// Mask for pretty display // Mask for pretty display only.
//
// This is not a validation rule by itself. It exists so clients can render and
// navigate masked input while still storing raw values server-side.
message DisplayMask { message DisplayMask {
string pattern = 1; // e.g., "(###) ###-####" or "####-##-##" string pattern = 1; // e.g., "(###) ###-####" or "####-##-##"
string input_char = 2; // e.g., "#" string input_char = 2; // e.g., "#"
optional string template_char = 3; // e.g., "_" optional string template_char = 3; // e.g., "_"
} }
// One positionbased validation rule, similar to CharacterFilter + PositionRange // Which positions a pattern rule applies to.
message PatternRule { // This exists instead of a string syntax like "0-3" so the server can validate
// Range descriptor: how far the rule applies // the structure directly and clients do not need to parse a DSL.
// Examples: message PatternPosition {
// - "0" → Single position 0 PatternPositionKind kind = 1;
// - "0-3" → Range 0..3 inclusive uint32 single = 2;
// - "from:5" → From position 5 onward uint32 start = 3;
// - "0,2,5" → Multiple discrete positions uint32 end = 4;
string range = 1; repeated uint32 positions = 5;
// Character filter type, caseinsensitive keywords:
// "ALPHABETIC", "NUMERIC", "ALPHANUMERIC",
// "ONEOF(<chars>)", "EXACT(:)", "CUSTOM(<name>)"
string filter = 2;
} }
enum PatternPositionKind {
PATTERN_POSITION_KIND_UNSPECIFIED = 0;
PATTERN_POSITION_SINGLE = 1;
PATTERN_POSITION_RANGE = 2;
PATTERN_POSITION_FROM = 3;
PATTERN_POSITION_MULTIPLE = 4;
}
// What type of character constraint a pattern rule applies.
// This mirrors the typed character filters used by canvas.
message CharacterConstraint {
CharacterConstraintKind kind = 1;
// Used when kind == CHARACTER_CONSTRAINT_EXACT.
optional string exact = 2;
// Used when kind == CHARACTER_CONSTRAINT_ONE_OF.
repeated string one_of = 3;
// Used when kind == CHARACTER_CONSTRAINT_REGEX.
optional string regex = 4;
}
enum CharacterConstraintKind {
CHARACTER_CONSTRAINT_KIND_UNSPECIFIED = 0;
CHARACTER_CONSTRAINT_ALPHABETIC = 1;
CHARACTER_CONSTRAINT_NUMERIC = 2;
CHARACTER_CONSTRAINT_ALPHANUMERIC = 3;
CHARACTER_CONSTRAINT_EXACT = 4;
CHARACTER_CONSTRAINT_ONE_OF = 5;
CHARACTER_CONSTRAINT_REGEX = 6;
}
// One position-based validation rule, similar to canvas PositionFilter.
message PatternRule {
PatternPosition position = 1;
CharacterConstraint constraint = 2;
}
// Client-side formatter metadata.
// The formatter "type" is intended to be resolved by a client-side formatter registry.
message CustomFormatter { message CustomFormatter {
// Formatter type identifier; handled clientside. // Formatter type identifier; handled clientside.
// Examples: "PSCFormatter", "PhoneFormatter", "CreditCardFormatter", "DateFormatter" // Examples: "PSCFormatter", "PhoneFormatter", "CreditCardFormatter", "DateFormatter"
string type = 1; string type = 1;
// Optional freetext note or parameters (e.g. locale, pattern) repeated FormatterOption options = 2;
optional string description = 2; optional string description = 3;
} }
// Collection of pattern rules for one field message FormatterOption {
string key = 1;
string value = 2;
}
// Exact-value whitelist configuration.
// This maps to canvas AllowedValues semantics.
message AllowedValues {
repeated string values = 1;
bool allow_empty = 2;
bool case_insensitive = 3;
}
// Collection of pattern rules for one field.
message PatternRules { message PatternRules {
// All rules that make up the validation logic // All rules that make up the validation logic
repeated PatternRule rules = 1; repeated PatternRule rules = 1;
@@ -92,11 +169,15 @@ message PatternRules {
optional string description = 2; optional string description = 2;
} }
// Service to fetch validations for a table // Service for storing and fetching field-validation definitions.
service TableValidationService { service TableValidationService {
rpc GetTableValidation(GetTableValidationRequest) returns (TableValidationResponse); rpc GetTableValidation(GetTableValidationRequest) returns (TableValidationResponse);
// Upsert a single field validation definition.
rpc UpdateFieldValidation(UpdateFieldValidationRequest) returns (UpdateFieldValidationResponse); rpc UpdateFieldValidation(UpdateFieldValidationRequest) returns (UpdateFieldValidationResponse);
// Replace the full validation definition set for a table in one transaction.
rpc ReplaceTableValidation(ReplaceTableValidationRequest) returns (ReplaceTableValidationResponse);
} }
message UpdateFieldValidationRequest { message UpdateFieldValidationRequest {
@@ -110,3 +191,16 @@ message UpdateFieldValidationResponse {
bool success = 1; bool success = 1;
string message = 2; string message = 2;
} }
message ReplaceTableValidationRequest {
string profileName = 1;
string tableName = 2;
// Full replacement set. Fields omitted here are removed from the stored config.
repeated FieldValidation fields = 3;
}
message ReplaceTableValidationResponse {
bool success = 1;
string message = 2;
}

Binary file not shown.

View File

@@ -125,6 +125,44 @@ pub struct GetProfileDetailsResponse {
#[prost(message, repeated, tag = "2")] #[prost(message, repeated, tag = "2")]
pub tables: ::prost::alloc::vec::Vec<TableDetail>, pub tables: ::prost::alloc::vec::Vec<TableDetail>,
} }
/// Request to fetch recorded column alias rename history for one profile.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetColumnAliasRenameHistoryRequest {
#[prost(string, tag = "1")]
pub profile_name: ::prost::alloc::string::String,
/// Optional filter. When omitted, returns all tables in the profile.
#[prost(int64, optional, tag = "2")]
pub table_definition_id: ::core::option::Option<i64>,
}
/// One recorded column alias rename.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ColumnAliasRenameHistoryEntry {
#[prost(int64, tag = "1")]
pub id: i64,
#[prost(string, tag = "2")]
pub profile_name: ::prost::alloc::string::String,
#[prost(int64, tag = "3")]
pub table_definition_id: i64,
#[prost(string, tag = "4")]
pub table_name: ::prost::alloc::string::String,
#[prost(string, tag = "5")]
pub old_column_name: ::prost::alloc::string::String,
#[prost(string, tag = "6")]
pub new_column_name: ::prost::alloc::string::String,
#[prost(string, tag = "7")]
pub created_at: ::prost::alloc::string::String,
}
/// Response with stored column alias rename history rows.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetColumnAliasRenameHistoryResponse {
#[prost(string, tag = "1")]
pub profile_name: ::prost::alloc::string::String,
#[prost(message, repeated, tag = "2")]
pub entries: ::prost::alloc::vec::Vec<ColumnAliasRenameHistoryEntry>,
}
/// Describes a table with its columns and associated scripts. /// Describes a table with its columns and associated scripts.
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct TableDetail { pub struct TableDetail {
@@ -151,6 +189,28 @@ pub struct ScriptInfo {
#[prost(string, tag = "5")] #[prost(string, tag = "5")]
pub description: ::prost::alloc::string::String, pub description: ::prost::alloc::string::String,
} }
/// Request to rename one user-visible column alias in a table.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RenameColumnAliasRequest {
#[prost(string, tag = "1")]
pub profile_name: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub table_name: ::prost::alloc::string::String,
#[prost(string, tag = "3")]
pub old_column_name: ::prost::alloc::string::String,
#[prost(string, tag = "4")]
pub new_column_name: ::prost::alloc::string::String,
}
/// Response after renaming one column alias.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RenameColumnAliasResponse {
#[prost(bool, tag = "1")]
pub success: bool,
#[prost(string, tag = "2")]
pub message: ::prost::alloc::string::String,
}
/// Request to delete one table definition entirely. /// Request to delete one table definition entirely.
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct DeleteTableRequest { pub struct DeleteTableRequest {
@@ -361,6 +421,66 @@ pub mod table_definition_client {
); );
self.inner.unary(req, path, codec).await self.inner.unary(req, path, codec).await
} }
/// Returns the stored rename history for column aliases in one profile.
pub async fn get_column_alias_rename_history(
&mut self,
request: impl tonic::IntoRequest<super::GetColumnAliasRenameHistoryRequest>,
) -> std::result::Result<
tonic::Response<super::GetColumnAliasRenameHistoryResponse>,
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_definition.TableDefinition/GetColumnAliasRenameHistory",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"komp_ac.table_definition.TableDefinition",
"GetColumnAliasRenameHistory",
),
);
self.inner.unary(req, path, codec).await
}
/// Renames a user-visible column alias while keeping the physical column unchanged.
pub async fn rename_column_alias(
&mut self,
request: impl tonic::IntoRequest<super::RenameColumnAliasRequest>,
) -> std::result::Result<
tonic::Response<super::RenameColumnAliasResponse>,
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_definition.TableDefinition/RenameColumnAlias",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"komp_ac.table_definition.TableDefinition",
"RenameColumnAlias",
),
);
self.inner.unary(req, path, codec).await
}
/// Drops a table and its metadata, then deletes the profile if it becomes empty. /// Drops a table and its metadata, then deletes the profile if it becomes empty.
pub async fn delete_table( pub async fn delete_table(
&mut self, &mut self,
@@ -434,6 +554,22 @@ pub mod table_definition_server {
tonic::Response<super::GetProfileDetailsResponse>, tonic::Response<super::GetProfileDetailsResponse>,
tonic::Status, tonic::Status,
>; >;
/// Returns the stored rename history for column aliases in one profile.
async fn get_column_alias_rename_history(
&self,
request: tonic::Request<super::GetColumnAliasRenameHistoryRequest>,
) -> std::result::Result<
tonic::Response<super::GetColumnAliasRenameHistoryResponse>,
tonic::Status,
>;
/// Renames a user-visible column alias while keeping the physical column unchanged.
async fn rename_column_alias(
&self,
request: tonic::Request<super::RenameColumnAliasRequest>,
) -> std::result::Result<
tonic::Response<super::RenameColumnAliasResponse>,
tonic::Status,
>;
/// Drops a table and its metadata, then deletes the profile if it becomes empty. /// Drops a table and its metadata, then deletes the profile if it becomes empty.
async fn delete_table( async fn delete_table(
&self, &self,
@@ -664,6 +800,106 @@ pub mod table_definition_server {
}; };
Box::pin(fut) Box::pin(fut)
} }
"/komp_ac.table_definition.TableDefinition/GetColumnAliasRenameHistory" => {
#[allow(non_camel_case_types)]
struct GetColumnAliasRenameHistorySvc<T: TableDefinition>(
pub Arc<T>,
);
impl<
T: TableDefinition,
> tonic::server::UnaryService<
super::GetColumnAliasRenameHistoryRequest,
> for GetColumnAliasRenameHistorySvc<T> {
type Response = super::GetColumnAliasRenameHistoryResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<
super::GetColumnAliasRenameHistoryRequest,
>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as TableDefinition>::get_column_alias_rename_history(
&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 = GetColumnAliasRenameHistorySvc(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)
}
"/komp_ac.table_definition.TableDefinition/RenameColumnAlias" => {
#[allow(non_camel_case_types)]
struct RenameColumnAliasSvc<T: TableDefinition>(pub Arc<T>);
impl<
T: TableDefinition,
> tonic::server::UnaryService<super::RenameColumnAliasRequest>
for RenameColumnAliasSvc<T> {
type Response = super::RenameColumnAliasResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::RenameColumnAliasRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as TableDefinition>::rename_column_alias(&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 = RenameColumnAliasSvc(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)
}
"/komp_ac.table_definition.TableDefinition/DeleteTable" => { "/komp_ac.table_definition.TableDefinition/DeleteTable" => {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
struct DeleteTableSvc<T: TableDefinition>(pub Arc<T>); struct DeleteTableSvc<T: TableDefinition>(pub Arc<T>);

View File

@@ -1,17 +1,27 @@
// This file is @generated by prost-build. // This file is @generated by prost-build.
/// Request identifying the profile (schema) and table to inspect. /// Request identifying the profile (schema) and tables to inspect.
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetTableStructureRequest { pub struct GetTableStructureRequest {
/// Required. Profile (PostgreSQL schema) name. Must exist in `schemas`. /// Required. Profile (PostgreSQL schema) name. Must exist in `schemas`.
#[prost(string, tag = "1")] #[prost(string, tag = "1")]
pub profile_name: ::prost::alloc::string::String, pub profile_name: ::prost::alloc::string::String,
/// Required. Table name within the profile. Must exist in `table_definitions` /// Required. Table names within the profile. Each must exist in
/// for the given profile. The physical table is then introspected via /// `table_definitions` for the given profile. The physical tables are then
/// information_schema. /// introspected via information_schema.
#[prost(string, tag = "2")] #[prost(string, repeated, tag = "2")]
pub table_name: ::prost::alloc::string::String, pub table_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
} }
/// Response with the ordered list of columns (by ordinal position). /// Batched response keyed by table name.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetTableStructureResponse {
/// Per-table physical column lists keyed by requested table name.
#[prost(map = "string, message", tag = "1")]
pub table_structures: ::std::collections::HashMap<
::prost::alloc::string::String,
TableStructureResponse,
>,
}
/// Response with the ordered list of columns (by ordinal position) for one table.
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct TableStructureResponse { pub struct TableStructureResponse {
/// Columns of the physical table, including system columns (id, deleted, /// Columns of the physical table, including system columns (id, deleted,
@@ -55,14 +65,13 @@ pub mod table_structure_service_client {
)] )]
use tonic::codegen::*; use tonic::codegen::*;
use tonic::codegen::http::Uri; use tonic::codegen::http::Uri;
/// Introspects the physical PostgreSQL table for a given logical table /// Introspects the physical PostgreSQL tables for one or more logical tables
/// (defined in table_definitions) and returns its column structure. /// (defined in table_definitions) and returns their column structures.
/// The server validates that: /// The server validates that:
/// - The profile (schema) exists in `schemas` /// - The profile (schema) exists in `schemas`
/// - The table is defined for that profile in `table_definitions` /// - Every table is defined for that profile in `table_definitions`
/// It then queries information_schema for the physical table and returns /// It then queries information_schema for the physical tables and returns
/// normalized column metadata. If the physical table is missing despite /// normalized column metadata.
/// a definition, the response may contain an empty `columns` list.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TableStructureServiceClient<T> { pub struct TableStructureServiceClient<T> {
inner: tonic::client::Grpc<T>, inner: tonic::client::Grpc<T>,
@@ -144,20 +153,20 @@ pub mod table_structure_service_client {
self self
} }
/// Return the physical column list (name, normalized data_type, /// Return the physical column list (name, normalized data_type,
/// nullability, primary key flag) for a table in a profile. /// nullability, primary key flag) for one or more tables in a profile.
/// ///
/// Behavior: /// Behavior:
/// - NOT_FOUND if profile doesn't exist in `schemas` /// - NOT_FOUND if profile doesn't exist in `schemas`
/// - NOT_FOUND if table not defined for that profile in `table_definitions` /// - NOT_FOUND if any table is not defined for that profile in `table_definitions`
/// - Queries information_schema.columns ordered by ordinal position /// - Queries information_schema.columns ordered by ordinal position
/// - Normalizes data_type text (details under TableColumn.data_type) /// - Normalizes data_type text (details under TableColumn.data_type)
/// - Returns an empty list if the table is validated but has no visible /// - Returns an error if any validated table has no visible columns in
/// columns in information_schema (e.g., physical table missing) /// information_schema (e.g., physical table missing)
pub async fn get_table_structure( pub async fn get_table_structure(
&mut self, &mut self,
request: impl tonic::IntoRequest<super::GetTableStructureRequest>, request: impl tonic::IntoRequest<super::GetTableStructureRequest>,
) -> std::result::Result< ) -> std::result::Result<
tonic::Response<super::TableStructureResponse>, tonic::Response<super::GetTableStructureResponse>,
tonic::Status, tonic::Status,
> { > {
self.inner self.inner
@@ -198,31 +207,30 @@ pub mod table_structure_service_server {
#[async_trait] #[async_trait]
pub trait TableStructureService: std::marker::Send + std::marker::Sync + 'static { pub trait TableStructureService: std::marker::Send + std::marker::Sync + 'static {
/// Return the physical column list (name, normalized data_type, /// Return the physical column list (name, normalized data_type,
/// nullability, primary key flag) for a table in a profile. /// nullability, primary key flag) for one or more tables in a profile.
/// ///
/// Behavior: /// Behavior:
/// - NOT_FOUND if profile doesn't exist in `schemas` /// - NOT_FOUND if profile doesn't exist in `schemas`
/// - NOT_FOUND if table not defined for that profile in `table_definitions` /// - NOT_FOUND if any table is not defined for that profile in `table_definitions`
/// - Queries information_schema.columns ordered by ordinal position /// - Queries information_schema.columns ordered by ordinal position
/// - Normalizes data_type text (details under TableColumn.data_type) /// - Normalizes data_type text (details under TableColumn.data_type)
/// - Returns an empty list if the table is validated but has no visible /// - Returns an error if any validated table has no visible columns in
/// columns in information_schema (e.g., physical table missing) /// information_schema (e.g., physical table missing)
async fn get_table_structure( async fn get_table_structure(
&self, &self,
request: tonic::Request<super::GetTableStructureRequest>, request: tonic::Request<super::GetTableStructureRequest>,
) -> std::result::Result< ) -> std::result::Result<
tonic::Response<super::TableStructureResponse>, tonic::Response<super::GetTableStructureResponse>,
tonic::Status, tonic::Status,
>; >;
} }
/// Introspects the physical PostgreSQL table for a given logical table /// Introspects the physical PostgreSQL tables for one or more logical tables
/// (defined in table_definitions) and returns its column structure. /// (defined in table_definitions) and returns their column structures.
/// The server validates that: /// The server validates that:
/// - The profile (schema) exists in `schemas` /// - The profile (schema) exists in `schemas`
/// - The table is defined for that profile in `table_definitions` /// - Every table is defined for that profile in `table_definitions`
/// It then queries information_schema for the physical table and returns /// It then queries information_schema for the physical tables and returns
/// normalized column metadata. If the physical table is missing despite /// normalized column metadata.
/// a definition, the response may contain an empty `columns` list.
#[derive(Debug)] #[derive(Debug)]
pub struct TableStructureServiceServer<T> { pub struct TableStructureServiceServer<T> {
inner: Arc<T>, inner: Arc<T>,
@@ -307,7 +315,7 @@ pub mod table_structure_service_server {
T: TableStructureService, T: TableStructureService,
> tonic::server::UnaryService<super::GetTableStructureRequest> > tonic::server::UnaryService<super::GetTableStructureRequest>
for GetTableStructureSvc<T> { for GetTableStructureSvc<T> {
type Response = super::TableStructureResponse; type Response = super::GetTableStructureResponse;
type Future = BoxFuture< type Future = BoxFuture<
tonic::Response<Self::Response>, tonic::Response<Self::Response>,
tonic::Status, tonic::Status,

View File

@@ -7,40 +7,45 @@ pub struct GetTableValidationRequest {
#[prost(string, tag = "2")] #[prost(string, tag = "2")]
pub table_name: ::prost::alloc::string::String, pub table_name: ::prost::alloc::string::String,
} }
/// Response with field-level validations; if a field is omitted, /// Response with field-level validations for the whole table.
/// no validation is applied (default unspecified). /// If a field is omitted, no validation configuration exists for that field.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct TableValidationResponse { pub struct TableValidationResponse {
#[prost(message, repeated, tag = "1")] #[prost(message, repeated, tag = "1")]
pub fields: ::prost::alloc::vec::Vec<FieldValidation>, pub fields: ::prost::alloc::vec::Vec<FieldValidation>,
} }
/// Field-level validation (extensible for future kinds) /// Field-level validation definition stored on the server and distributed to clients.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct FieldValidation { pub struct FieldValidation {
/// MUST match your frontend FormState.dataKey for the column /// MUST match your frontend FormState.dataKey for the column
#[prost(string, tag = "1")] #[prost(string, tag = "1")]
pub data_key: ::prost::alloc::string::String, pub data_key: ::prost::alloc::string::String,
/// Current: only CharacterLimits. More rules can be added later. /// Validation 1: length and counting rules.
#[prost(message, optional, tag = "10")] #[prost(message, optional, tag = "10")]
pub limits: ::core::option::Option<CharacterLimits>, pub limits: ::core::option::Option<CharacterLimits>,
/// Future expansion: /// Validation 2: position-based character constraints.
///
/// Validation 2
#[prost(message, optional, tag = "11")] #[prost(message, optional, tag = "11")]
pub pattern: ::core::option::Option<PatternRules>, pub pattern: ::core::option::Option<PatternRules>,
/// Validation 4 custom formatting logic /// Exact-value whitelist.
#[prost(message, optional, tag = "12")]
pub allowed_values: ::core::option::Option<AllowedValues>,
/// Client-side hint that this field participates in external/asynchronous validation UI.
#[prost(bool, tag = "13")]
pub external_validation_enabled: bool,
/// Client-side formatter metadata. This is intentionally data-only, not executable code.
#[prost(message, optional, tag = "14")] #[prost(message, optional, tag = "14")]
pub formatter: ::core::option::Option<CustomFormatter>, pub formatter: ::core::option::Option<CustomFormatter>,
/// Client-side display mask metadata. The server stores raw data without mask literals.
#[prost(message, optional, tag = "3")] #[prost(message, optional, tag = "3")]
pub mask: ::core::option::Option<DisplayMask>, pub mask: ::core::option::Option<DisplayMask>,
/// ExternalValidation external = 13; /// Field must be provided / treated as required by clients and server enforcement layers.
/// CustomFormatter formatter = 14;
#[prost(bool, tag = "4")] #[prost(bool, tag = "4")]
pub required: bool, pub required: bool,
} }
/// Character limit validation (Validation 1) /// Character limit validation (Validation 1).
/// These rules map directly to canvas CharacterLimits.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, Copy, PartialEq, ::prost::Message)] #[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct CharacterLimits { pub struct CharacterLimits {
@@ -57,7 +62,10 @@ pub struct CharacterLimits {
#[prost(enumeration = "CountMode", tag = "4")] #[prost(enumeration = "CountMode", tag = "4")]
pub count_mode: i32, pub count_mode: i32,
} }
/// Mask for pretty display /// Mask for pretty display only.
///
/// This is not a validation rule by itself. It exists so clients can render and
/// navigate masked input while still storing raw values server-side.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct DisplayMask { pub struct DisplayMask {
@@ -71,24 +79,51 @@ pub struct DisplayMask {
#[prost(string, optional, tag = "3")] #[prost(string, optional, tag = "3")]
pub template_char: ::core::option::Option<::prost::alloc::string::String>, pub template_char: ::core::option::Option<::prost::alloc::string::String>,
} }
/// One positionbased validation rule, similar to CharacterFilter + PositionRange /// Which positions a pattern rule applies to.
/// This exists instead of a string syntax like "0-3" so the server can validate
/// the structure directly and clients do not need to parse a DSL.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PatternPosition {
#[prost(enumeration = "PatternPositionKind", tag = "1")]
pub kind: i32,
#[prost(uint32, tag = "2")]
pub single: u32,
#[prost(uint32, tag = "3")]
pub start: u32,
#[prost(uint32, tag = "4")]
pub end: u32,
#[prost(uint32, repeated, tag = "5")]
pub positions: ::prost::alloc::vec::Vec<u32>,
}
/// What type of character constraint a pattern rule applies.
/// This mirrors the typed character filters used by canvas.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CharacterConstraint {
#[prost(enumeration = "CharacterConstraintKind", tag = "1")]
pub kind: i32,
/// Used when kind == CHARACTER_CONSTRAINT_EXACT.
#[prost(string, optional, tag = "2")]
pub exact: ::core::option::Option<::prost::alloc::string::String>,
/// Used when kind == CHARACTER_CONSTRAINT_ONE_OF.
#[prost(string, repeated, tag = "3")]
pub one_of: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
/// Used when kind == CHARACTER_CONSTRAINT_REGEX.
#[prost(string, optional, tag = "4")]
pub regex: ::core::option::Option<::prost::alloc::string::String>,
}
/// One position-based validation rule, similar to canvas PositionFilter.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct PatternRule { pub struct PatternRule {
/// Range descriptor: how far the rule applies #[prost(message, optional, tag = "1")]
/// Examples: pub position: ::core::option::Option<PatternPosition>,
/// - "0" → Single position 0 #[prost(message, optional, tag = "2")]
/// - "0-3" → Range 0..3 inclusive pub constraint: ::core::option::Option<CharacterConstraint>,
/// - "from:5" → From position 5 onward
/// - "0,2,5" → Multiple discrete positions
#[prost(string, tag = "1")]
pub range: ::prost::alloc::string::String,
/// Character filter type, caseinsensitive keywords:
/// "ALPHABETIC", "NUMERIC", "ALPHANUMERIC",
/// "ONEOF(<chars>)", "EXACT(:)", "CUSTOM(<name>)"
#[prost(string, tag = "2")]
pub filter: ::prost::alloc::string::String,
} }
/// Client-side formatter metadata.
/// The formatter "type" is intended to be resolved by a client-side formatter registry.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct CustomFormatter { pub struct CustomFormatter {
@@ -96,11 +131,32 @@ pub struct CustomFormatter {
/// Examples: "PSCFormatter", "PhoneFormatter", "CreditCardFormatter", "DateFormatter" /// Examples: "PSCFormatter", "PhoneFormatter", "CreditCardFormatter", "DateFormatter"
#[prost(string, tag = "1")] #[prost(string, tag = "1")]
pub r#type: ::prost::alloc::string::String, pub r#type: ::prost::alloc::string::String,
/// Optional freetext note or parameters (e.g. locale, pattern) #[prost(message, repeated, tag = "2")]
#[prost(string, optional, tag = "2")] pub options: ::prost::alloc::vec::Vec<FormatterOption>,
#[prost(string, optional, tag = "3")]
pub description: ::core::option::Option<::prost::alloc::string::String>, pub description: ::core::option::Option<::prost::alloc::string::String>,
} }
/// Collection of pattern rules for one field #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct FormatterOption {
#[prost(string, tag = "1")]
pub key: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub value: ::prost::alloc::string::String,
}
/// Exact-value whitelist configuration.
/// This maps to canvas AllowedValues semantics.
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AllowedValues {
#[prost(string, repeated, tag = "1")]
pub values: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
#[prost(bool, tag = "2")]
pub allow_empty: bool,
#[prost(bool, tag = "3")]
pub case_insensitive: bool,
}
/// Collection of pattern rules for one field.
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct PatternRules { pub struct PatternRules {
@@ -131,6 +187,25 @@ pub struct UpdateFieldValidationResponse {
#[prost(string, tag = "2")] #[prost(string, tag = "2")]
pub message: ::prost::alloc::string::String, pub message: ::prost::alloc::string::String,
} }
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ReplaceTableValidationRequest {
#[prost(string, tag = "1")]
pub profile_name: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub table_name: ::prost::alloc::string::String,
/// Full replacement set. Fields omitted here are removed from the stored config.
#[prost(message, repeated, tag = "3")]
pub fields: ::prost::alloc::vec::Vec<FieldValidation>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ReplaceTableValidationResponse {
#[prost(bool, tag = "1")]
pub success: bool,
#[prost(string, tag = "2")]
pub message: ::prost::alloc::string::String,
}
/// Character length counting mode /// Character length counting mode
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
@@ -167,6 +242,90 @@ impl CountMode {
} }
} }
} }
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum PatternPositionKind {
Unspecified = 0,
PatternPositionSingle = 1,
PatternPositionRange = 2,
PatternPositionFrom = 3,
PatternPositionMultiple = 4,
}
impl PatternPositionKind {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "PATTERN_POSITION_KIND_UNSPECIFIED",
Self::PatternPositionSingle => "PATTERN_POSITION_SINGLE",
Self::PatternPositionRange => "PATTERN_POSITION_RANGE",
Self::PatternPositionFrom => "PATTERN_POSITION_FROM",
Self::PatternPositionMultiple => "PATTERN_POSITION_MULTIPLE",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"PATTERN_POSITION_KIND_UNSPECIFIED" => Some(Self::Unspecified),
"PATTERN_POSITION_SINGLE" => Some(Self::PatternPositionSingle),
"PATTERN_POSITION_RANGE" => Some(Self::PatternPositionRange),
"PATTERN_POSITION_FROM" => Some(Self::PatternPositionFrom),
"PATTERN_POSITION_MULTIPLE" => Some(Self::PatternPositionMultiple),
_ => None,
}
}
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum CharacterConstraintKind {
Unspecified = 0,
CharacterConstraintAlphabetic = 1,
CharacterConstraintNumeric = 2,
CharacterConstraintAlphanumeric = 3,
CharacterConstraintExact = 4,
CharacterConstraintOneOf = 5,
CharacterConstraintRegex = 6,
}
impl CharacterConstraintKind {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Unspecified => "CHARACTER_CONSTRAINT_KIND_UNSPECIFIED",
Self::CharacterConstraintAlphabetic => "CHARACTER_CONSTRAINT_ALPHABETIC",
Self::CharacterConstraintNumeric => "CHARACTER_CONSTRAINT_NUMERIC",
Self::CharacterConstraintAlphanumeric => "CHARACTER_CONSTRAINT_ALPHANUMERIC",
Self::CharacterConstraintExact => "CHARACTER_CONSTRAINT_EXACT",
Self::CharacterConstraintOneOf => "CHARACTER_CONSTRAINT_ONE_OF",
Self::CharacterConstraintRegex => "CHARACTER_CONSTRAINT_REGEX",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"CHARACTER_CONSTRAINT_KIND_UNSPECIFIED" => Some(Self::Unspecified),
"CHARACTER_CONSTRAINT_ALPHABETIC" => {
Some(Self::CharacterConstraintAlphabetic)
}
"CHARACTER_CONSTRAINT_NUMERIC" => Some(Self::CharacterConstraintNumeric),
"CHARACTER_CONSTRAINT_ALPHANUMERIC" => {
Some(Self::CharacterConstraintAlphanumeric)
}
"CHARACTER_CONSTRAINT_EXACT" => Some(Self::CharacterConstraintExact),
"CHARACTER_CONSTRAINT_ONE_OF" => Some(Self::CharacterConstraintOneOf),
"CHARACTER_CONSTRAINT_REGEX" => Some(Self::CharacterConstraintRegex),
_ => None,
}
}
}
/// Generated client implementations. /// Generated client implementations.
pub mod table_validation_service_client { pub mod table_validation_service_client {
#![allow( #![allow(
@@ -178,7 +337,7 @@ pub mod table_validation_service_client {
)] )]
use tonic::codegen::*; use tonic::codegen::*;
use tonic::codegen::http::Uri; use tonic::codegen::http::Uri;
/// Service to fetch validations for a table /// Service for storing and fetching field-validation definitions.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TableValidationServiceClient<T> { pub struct TableValidationServiceClient<T> {
inner: tonic::client::Grpc<T>, inner: tonic::client::Grpc<T>,
@@ -290,6 +449,7 @@ pub mod table_validation_service_client {
); );
self.inner.unary(req, path, codec).await self.inner.unary(req, path, codec).await
} }
/// Upsert a single field validation definition.
pub async fn update_field_validation( pub async fn update_field_validation(
&mut self, &mut self,
request: impl tonic::IntoRequest<super::UpdateFieldValidationRequest>, request: impl tonic::IntoRequest<super::UpdateFieldValidationRequest>,
@@ -319,6 +479,36 @@ pub mod table_validation_service_client {
); );
self.inner.unary(req, path, codec).await self.inner.unary(req, path, codec).await
} }
/// Replace the full validation definition set for a table in one transaction.
pub async fn replace_table_validation(
&mut self,
request: impl tonic::IntoRequest<super::ReplaceTableValidationRequest>,
) -> std::result::Result<
tonic::Response<super::ReplaceTableValidationResponse>,
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_validation.TableValidationService/ReplaceTableValidation",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"komp_ac.table_validation.TableValidationService",
"ReplaceTableValidation",
),
);
self.inner.unary(req, path, codec).await
}
} }
} }
/// Generated server implementations. /// Generated server implementations.
@@ -341,6 +531,7 @@ pub mod table_validation_service_server {
tonic::Response<super::TableValidationResponse>, tonic::Response<super::TableValidationResponse>,
tonic::Status, tonic::Status,
>; >;
/// Upsert a single field validation definition.
async fn update_field_validation( async fn update_field_validation(
&self, &self,
request: tonic::Request<super::UpdateFieldValidationRequest>, request: tonic::Request<super::UpdateFieldValidationRequest>,
@@ -348,8 +539,16 @@ pub mod table_validation_service_server {
tonic::Response<super::UpdateFieldValidationResponse>, tonic::Response<super::UpdateFieldValidationResponse>,
tonic::Status, tonic::Status,
>; >;
/// Replace the full validation definition set for a table in one transaction.
async fn replace_table_validation(
&self,
request: tonic::Request<super::ReplaceTableValidationRequest>,
) -> std::result::Result<
tonic::Response<super::ReplaceTableValidationResponse>,
tonic::Status,
>;
} }
/// Service to fetch validations for a table /// Service for storing and fetching field-validation definitions.
#[derive(Debug)] #[derive(Debug)]
pub struct TableValidationServiceServer<T> { pub struct TableValidationServiceServer<T> {
inner: Arc<T>, inner: Arc<T>,
@@ -527,6 +726,57 @@ pub mod table_validation_service_server {
}; };
Box::pin(fut) Box::pin(fut)
} }
"/komp_ac.table_validation.TableValidationService/ReplaceTableValidation" => {
#[allow(non_camel_case_types)]
struct ReplaceTableValidationSvc<T: TableValidationService>(
pub Arc<T>,
);
impl<
T: TableValidationService,
> tonic::server::UnaryService<super::ReplaceTableValidationRequest>
for ReplaceTableValidationSvc<T> {
type Response = super::ReplaceTableValidationResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::ReplaceTableValidationRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as TableValidationService>::replace_table_validation(
&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 = ReplaceTableValidationSvc(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 { Box::pin(async move {
let mut response = http::Response::new( let mut response = http::Response::new(

2
server

Submodule server updated: 82df1dea82...f828b7688a