rule page in the validation client
This commit is contained in:
2
client
2
client
Submodule client updated: 25a901ff5e...83fedad94e
@@ -68,6 +68,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
".komp_ac.table_validation.ValidationRuleDefinition",
|
".komp_ac.table_validation.ValidationRuleDefinition",
|
||||||
"#[derive(serde::Serialize, serde::Deserialize)]",
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
)
|
)
|
||||||
|
.type_attribute(
|
||||||
|
".komp_ac.table_validation.ValidationSetRuleItem",
|
||||||
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
|
.type_attribute(
|
||||||
|
".komp_ac.table_validation.ValidationSetRuleItem.Source",
|
||||||
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
)
|
||||||
.type_attribute(
|
.type_attribute(
|
||||||
".komp_ac.table_validation.ValidationSetDefinition",
|
".komp_ac.table_validation.ValidationSetDefinition",
|
||||||
"#[derive(serde::Serialize, serde::Deserialize)]",
|
"#[derive(serde::Serialize, serde::Deserialize)]",
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ message ReplaceTableValidationResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ValidationRuleDefinition {
|
message ValidationRuleDefinition {
|
||||||
|
optional int64 id = 4;
|
||||||
string name = 1;
|
string name = 1;
|
||||||
optional string description = 2;
|
optional string description = 2;
|
||||||
|
|
||||||
@@ -226,12 +227,28 @@ message ValidationRuleDefinition {
|
|||||||
FieldValidation validation = 3;
|
FieldValidation validation = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ValidationSetRuleItem {
|
||||||
|
int32 position = 1;
|
||||||
|
optional string name = 2;
|
||||||
|
optional string description = 3;
|
||||||
|
|
||||||
|
oneof source {
|
||||||
|
string global_rule_name = 10;
|
||||||
|
FieldValidation inline_validation = 11;
|
||||||
|
int64 global_rule_id = 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message ValidationSetDefinition {
|
message ValidationSetDefinition {
|
||||||
|
reserved 3;
|
||||||
|
|
||||||
string name = 1;
|
string name = 1;
|
||||||
optional string description = 2;
|
optional string description = 2;
|
||||||
repeated string ruleNames = 3;
|
|
||||||
|
|
||||||
// Server-resolved snapshot of all rules in ruleNames order.
|
// Ordered set items.
|
||||||
|
repeated ValidationSetRuleItem ruleItems = 5;
|
||||||
|
|
||||||
|
// Server-resolved snapshot of all set items in order.
|
||||||
FieldValidation resolvedValidation = 4;
|
FieldValidation resolvedValidation = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -209,6 +209,8 @@ pub struct ReplaceTableValidationResponse {
|
|||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ValidationRuleDefinition {
|
pub struct ValidationRuleDefinition {
|
||||||
|
#[prost(int64, optional, tag = "4")]
|
||||||
|
pub id: ::core::option::Option<i64>,
|
||||||
#[prost(string, tag = "1")]
|
#[prost(string, tag = "1")]
|
||||||
pub name: ::prost::alloc::string::String,
|
pub name: ::prost::alloc::string::String,
|
||||||
#[prost(string, optional, tag = "2")]
|
#[prost(string, optional, tag = "2")]
|
||||||
@@ -219,14 +221,40 @@ pub struct ValidationRuleDefinition {
|
|||||||
}
|
}
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ValidationSetRuleItem {
|
||||||
|
#[prost(int32, tag = "1")]
|
||||||
|
pub position: i32,
|
||||||
|
#[prost(string, optional, tag = "2")]
|
||||||
|
pub name: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
|
#[prost(string, optional, tag = "3")]
|
||||||
|
pub description: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
|
#[prost(oneof = "validation_set_rule_item::Source", tags = "10, 11, 12")]
|
||||||
|
pub source: ::core::option::Option<validation_set_rule_item::Source>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `ValidationSetRuleItem`.
|
||||||
|
pub mod validation_set_rule_item {
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||||
|
pub enum Source {
|
||||||
|
#[prost(string, tag = "10")]
|
||||||
|
GlobalRuleName(::prost::alloc::string::String),
|
||||||
|
#[prost(message, tag = "11")]
|
||||||
|
InlineValidation(super::FieldValidation),
|
||||||
|
#[prost(int64, tag = "12")]
|
||||||
|
GlobalRuleId(i64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ValidationSetDefinition {
|
pub struct ValidationSetDefinition {
|
||||||
#[prost(string, tag = "1")]
|
#[prost(string, tag = "1")]
|
||||||
pub name: ::prost::alloc::string::String,
|
pub name: ::prost::alloc::string::String,
|
||||||
#[prost(string, optional, tag = "2")]
|
#[prost(string, optional, tag = "2")]
|
||||||
pub description: ::core::option::Option<::prost::alloc::string::String>,
|
pub description: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
#[prost(string, repeated, tag = "3")]
|
/// Ordered set items.
|
||||||
pub rule_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
#[prost(message, repeated, tag = "5")]
|
||||||
/// Server-resolved snapshot of all rules in ruleNames order.
|
pub rule_items: ::prost::alloc::vec::Vec<ValidationSetRuleItem>,
|
||||||
|
/// Server-resolved snapshot of all set items in order.
|
||||||
#[prost(message, optional, tag = "4")]
|
#[prost(message, optional, tag = "4")]
|
||||||
pub resolved_validation: ::core::option::Option<FieldValidation>,
|
pub resolved_validation: ::core::option::Option<FieldValidation>,
|
||||||
}
|
}
|
||||||
|
|||||||
2
server
2
server
Submodule server updated: b178fce273...0f74f9ee27
@@ -136,15 +136,15 @@ profileName: string
|
|||||||
set:
|
set:
|
||||||
name: string
|
name: string
|
||||||
description: optional string
|
description: optional string
|
||||||
ruleNames: repeated string
|
ruleItems: repeated ValidationSetRuleItem
|
||||||
```
|
```
|
||||||
|
|
||||||
Frontend rules:
|
Frontend rules:
|
||||||
|
|
||||||
- `set.name` is required and unique inside a profile.
|
- `set.name` is required and unique inside a profile.
|
||||||
- `ruleNames` must contain at least one rule.
|
- `ruleItems` must contain at least one item.
|
||||||
- `ruleNames` are ordered.
|
- `ruleItems` are ordered.
|
||||||
- Every rule name must already exist.
|
- Every global rule reference must already exist.
|
||||||
- Duplicate rule names in the same set are rejected.
|
- Duplicate rule names in the same set are rejected.
|
||||||
- Conflicting singleton fragments are rejected.
|
- Conflicting singleton fragments are rejected.
|
||||||
|
|
||||||
@@ -362,7 +362,7 @@ Recommended UI:
|
|||||||
```text
|
```text
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
ordered rule picker
|
ordered global/inline rule item picker
|
||||||
resolved preview
|
resolved preview
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -430,11 +430,11 @@ validation:
|
|||||||
Create set `phone`:
|
Create set `phone`:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
ruleNames:
|
ruleItems:
|
||||||
- required
|
- globalRuleName: required
|
||||||
- phone-length
|
- globalRuleName: phone-length
|
||||||
- digits-only
|
- globalRuleName: digits-only
|
||||||
- phone-mask
|
- globalRuleName: phone-mask
|
||||||
```
|
```
|
||||||
|
|
||||||
Apply set:
|
Apply set:
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ pub use rules::{
|
|||||||
count_text, CharacterFilter, CharacterLimits, CountMode, DisplayMask, LimitCheckResult,
|
count_text, CharacterFilter, CharacterLimits, CountMode, DisplayMask, LimitCheckResult,
|
||||||
MaskDisplayMode, PatternFilters, PositionFilter, PositionRange,
|
MaskDisplayMode, PatternFilters, PositionFilter, PositionRange,
|
||||||
};
|
};
|
||||||
pub use set::{AppliedValidation, ValidationRule, ValidationSet};
|
pub use set::{
|
||||||
|
AppliedValidation, ValidationRule, ValidationSet, ValidationSetItem, ValidationSetResolveError,
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{ValidationConfig, ValidationMergeError, ValidationSettings};
|
use crate::{ValidationConfig, ValidationMergeError, ValidationSettings};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ValidationRule {
|
pub struct ValidationRule {
|
||||||
@@ -18,19 +19,52 @@ impl ValidationRule {
|
|||||||
pub struct ValidationSet {
|
pub struct ValidationSet {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub rules: Vec<ValidationRule>,
|
pub items: Vec<ValidationSetItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum ValidationSetItem {
|
||||||
|
GlobalRuleRef(String),
|
||||||
|
InlineRule {
|
||||||
|
name: Option<String>,
|
||||||
|
validation: ValidationSettings,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidationSet {
|
impl ValidationSet {
|
||||||
pub fn resolve_settings(&self) -> Result<ValidationSettings, ValidationMergeError> {
|
pub fn resolve_settings_with_rules<'a>(
|
||||||
ValidationSettings::merge_rules(self.rules.iter().map(|rule| &rule.settings))
|
&'a self,
|
||||||
|
rules: impl Fn(&str) -> Option<&'a ValidationRule>,
|
||||||
|
) -> Result<ValidationSettings, ValidationSetResolveError> {
|
||||||
|
let settings = self.items.iter().map(|item| match item {
|
||||||
|
ValidationSetItem::GlobalRuleRef(name) => {
|
||||||
|
rules(name).map(|rule| &rule.settings).ok_or_else(|| {
|
||||||
|
ValidationSetResolveError::MissingGlobalRule { name: name.clone() }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ValidationSetItem::InlineRule { validation, .. } => Ok(validation),
|
||||||
|
});
|
||||||
|
|
||||||
|
let settings = settings.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
Ok(ValidationSettings::merge_rules(settings)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(&self) -> Result<ValidationConfig, ValidationMergeError> {
|
pub fn resolve_with_rules<'a>(
|
||||||
Ok(self.resolve_settings()?.resolve())
|
&'a self,
|
||||||
|
rules: impl Fn(&str) -> Option<&'a ValidationRule>,
|
||||||
|
) -> Result<ValidationConfig, ValidationSetResolveError> {
|
||||||
|
Ok(self.resolve_settings_with_rules(rules)?.resolve())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||||
|
pub enum ValidationSetResolveError {
|
||||||
|
#[error("validation set references missing global rule '{name}'")]
|
||||||
|
MissingGlobalRule { name: String },
|
||||||
|
#[error(transparent)]
|
||||||
|
Merge(#[from] ValidationMergeError),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct AppliedValidation {
|
pub struct AppliedValidation {
|
||||||
pub set_name: Option<String>,
|
pub set_name: Option<String>,
|
||||||
@@ -56,19 +90,17 @@ mod tests {
|
|||||||
let set = ValidationSet {
|
let set = ValidationSet {
|
||||||
name: "phone".to_string(),
|
name: "phone".to_string(),
|
||||||
description: None,
|
description: None,
|
||||||
rules: vec![
|
items: vec![
|
||||||
ValidationRule {
|
ValidationSetItem::InlineRule {
|
||||||
name: "phone-length".to_string(),
|
name: Some("phone-length".to_string()),
|
||||||
description: None,
|
validation: ValidationSettings {
|
||||||
settings: ValidationSettings {
|
|
||||||
character_limits: Some(CharacterLimits::new_range(10, 15)),
|
character_limits: Some(CharacterLimits::new_range(10, 15)),
|
||||||
..ValidationSettings::default()
|
..ValidationSettings::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ValidationRule {
|
ValidationSetItem::InlineRule {
|
||||||
name: "digits-only".to_string(),
|
name: Some("digits-only".to_string()),
|
||||||
description: None,
|
validation: ValidationSettings {
|
||||||
settings: ValidationSettings {
|
|
||||||
pattern: Some(PatternSettings {
|
pattern: Some(PatternSettings {
|
||||||
filters: vec![PositionFilterSettings {
|
filters: vec![PositionFilterSettings {
|
||||||
positions: PositionRange::From(0),
|
positions: PositionRange::From(0),
|
||||||
@@ -82,7 +114,9 @@ mod tests {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
let settings = set.resolve_settings().expect("set should resolve");
|
let settings = set
|
||||||
|
.resolve_settings_with_rules(|_| None)
|
||||||
|
.expect("set should resolve");
|
||||||
|
|
||||||
assert!(settings.character_limits.is_some());
|
assert!(settings.character_limits.is_some());
|
||||||
assert_eq!(settings.pattern.expect("pattern").filters.len(), 1);
|
assert_eq!(settings.pattern.expect("pattern").filters.len(), 1);
|
||||||
@@ -93,19 +127,17 @@ mod tests {
|
|||||||
let set = ValidationSet {
|
let set = ValidationSet {
|
||||||
name: "conflict".to_string(),
|
name: "conflict".to_string(),
|
||||||
description: None,
|
description: None,
|
||||||
rules: vec![
|
items: vec![
|
||||||
ValidationRule {
|
ValidationSetItem::InlineRule {
|
||||||
name: "short".to_string(),
|
name: Some("short".to_string()),
|
||||||
description: None,
|
validation: ValidationSettings {
|
||||||
settings: ValidationSettings {
|
|
||||||
character_limits: Some(CharacterLimits::new(10)),
|
character_limits: Some(CharacterLimits::new(10)),
|
||||||
..ValidationSettings::default()
|
..ValidationSettings::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ValidationRule {
|
ValidationSetItem::InlineRule {
|
||||||
name: "long".to_string(),
|
name: Some("long".to_string()),
|
||||||
description: None,
|
validation: ValidationSettings {
|
||||||
settings: ValidationSettings {
|
|
||||||
character_limits: Some(CharacterLimits::new(20)),
|
character_limits: Some(CharacterLimits::new(20)),
|
||||||
..ValidationSettings::default()
|
..ValidationSettings::default()
|
||||||
},
|
},
|
||||||
@@ -113,6 +145,6 @@ mod tests {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(set.resolve_settings().is_err());
|
assert!(set.resolve_settings_with_rules(|_| None).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user