use crate::errors::*;
use dsntk_common::{DsntkError, HRef, Result, Uri, gen_id};
use dsntk_feel::{FeelType, Name};
use std::fmt;
use std::fmt::Display;
use std::slice::Iter;
pub enum DmnVersion {
V13,
V14,
V15,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DmnId {
Provided(String),
Generated(String),
}
pub trait DmnElement {
fn namespace(&self) -> &str;
fn model_name(&self) -> &str;
fn id(&self) -> &String;
fn opt_id(&self) -> Option<&String>;
fn description(&self) -> &Option<String>;
fn label(&self) -> &Option<String>;
fn extension_elements(&self) -> &Vec<ExtensionElement>;
fn extension_attributes(&self) -> &Vec<ExtensionAttribute>;
}
pub trait NamedElement: DmnElement {
fn name(&self) -> &str;
fn feel_name(&self) -> &Name;
}
pub trait Expression {
fn type_ref(&self) -> &Option<String>;
}
pub trait FeelTypedElement {
fn feel_type(&self) -> &Option<FeelType>;
fn set_feel_type(&mut self, feel_type: FeelType);
}
pub trait RequiredTypeRef {
fn type_ref(&self) -> &str;
}
pub trait RequiredVariable {
fn variable(&self) -> &InformationItem;
}
pub trait Invocable: DmnElement + NamedElement + RequiredVariable {}
pub trait BusinessContextElement: NamedElement {
fn uri(&self) -> &Option<String>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtensionElement;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtensionAttribute;
#[derive(Debug, Clone)]
pub enum BusinessContextElementInstance {
PerformanceIndicator(PerformanceIndicator),
OrganizationUnit(OrganizationUnit),
}
#[named_element]
#[dmn_element]
#[business_context_element]
#[derive(Debug, Clone)]
pub struct PerformanceIndicator {
pub(crate) impacting_decisions: Vec<HRef>,
}
impl PerformanceIndicator {
pub fn impacting_decisions(&self) -> &Vec<HRef> {
&self.impacting_decisions
}
}
#[named_element]
#[dmn_element]
#[business_context_element]
#[derive(Debug, Clone)]
pub struct OrganizationUnit {
pub(crate) decisions_made: Vec<HRef>,
pub(crate) decisions_owned: Vec<HRef>,
}
impl OrganizationUnit {
pub fn decisions_made(&self) -> &Vec<HRef> {
&self.decisions_made
}
pub fn decisions_owned(&self) -> &Vec<HRef> {
&self.decisions_owned
}
}
#[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum DrgElement {
Decision(Decision),
InputData(InputData),
BusinessKnowledgeModel(BusinessKnowledgeModel),
DecisionService(DecisionService),
KnowledgeSource(KnowledgeSource),
}
pub enum Requirement {
Information(InformationRequirement),
Knowledge(KnowledgeRequirement),
Authority(AuthorityRequirement),
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone)]
pub struct Definitions {
pub(crate) expression_language: Option<Uri>,
pub(crate) type_language: Option<Uri>,
pub(crate) exporter: Option<String>,
pub(crate) exporter_version: Option<String>,
pub(crate) item_definitions: Vec<ItemDefinition>,
pub(crate) drg_elements: Vec<DrgElement>,
pub(crate) business_context_elements: Vec<BusinessContextElementInstance>,
pub(crate) imports: Vec<Import>,
pub(crate) dmndi: Option<Dmndi>,
}
impl Definitions {
pub fn expression_language(&self) -> &Option<String> {
&self.expression_language
}
pub fn type_language(&self) -> &Option<String> {
&self.type_language
}
pub fn exporter(&self) -> &Option<String> {
&self.exporter
}
pub fn exporter_version(&self) -> &Option<String> {
&self.exporter_version
}
pub fn item_definitions(&self) -> &Vec<ItemDefinition> {
&self.item_definitions
}
pub fn imports(&self) -> &Vec<Import> {
&self.imports
}
pub fn dmndi(&self) -> &Option<Dmndi> {
&self.dmndi
}
pub fn drg_elements(&self) -> Iter<'_, DrgElement> {
self.drg_elements.iter()
}
pub fn decisions(&self) -> Vec<Decision> {
self
.drg_elements
.iter()
.filter_map(|drg_element| {
if let DrgElement::Decision(decision) = drg_element {
Some(decision.clone())
} else {
None
}
})
.collect()
}
pub fn business_knowledge_models(&self) -> Vec<BusinessKnowledgeModel> {
self
.drg_elements
.iter()
.filter_map(|drg_element| {
if let DrgElement::BusinessKnowledgeModel(bkm) = drg_element {
Some(bkm.clone())
} else {
None
}
})
.collect()
}
pub fn decision_services(&self) -> Vec<DecisionService> {
self
.drg_elements
.iter()
.filter_map(|drg_element| {
if let DrgElement::DecisionService(decision_service) = drg_element {
Some(decision_service.clone())
} else {
None
}
})
.collect()
}
pub fn knowledge_sources(&self) -> Vec<&KnowledgeSource> {
self
.drg_elements
.iter()
.filter_map(|drg_element| {
if let DrgElement::KnowledgeSource(knowledge_source) = drg_element {
Some(knowledge_source)
} else {
None
}
})
.collect()
}
pub fn input_data(&self) -> Vec<InputData> {
self
.drg_elements
.iter()
.filter_map(|drg_element| {
if let DrgElement::InputData(input_data) = drg_element {
Some(input_data.clone())
} else {
None
}
})
.collect()
}
pub fn performance_indicators(&self) -> Vec<&PerformanceIndicator> {
self
.business_context_elements
.iter()
.filter_map(|item| match item {
BusinessContextElementInstance::PerformanceIndicator(performance_indicator) => Some(performance_indicator),
_ => None,
})
.collect()
}
pub fn organisation_units(&self) -> Vec<&OrganizationUnit> {
self
.business_context_elements
.iter()
.filter_map(|item| match item {
BusinessContextElementInstance::OrganizationUnit(organisation_unit) => Some(organisation_unit),
_ => None,
})
.collect()
}
pub fn get_decision(&self, id: &str) -> Option<&Decision> {
for drg_element in &self.drg_elements {
if let DrgElement::Decision(decision) = drg_element
&& decision.id() == id
{
return Some(decision);
}
}
None
}
pub fn get_input_data(&self, id: &str) -> Option<&InputData> {
for drg_element in &self.drg_elements {
if let DrgElement::InputData(input_data) = drg_element
&& input_data.id() == id
{
return Some(input_data);
}
}
None
}
pub fn get_business_knowledge_model(&self, id: &str) -> Option<&BusinessKnowledgeModel> {
for drg_element in &self.drg_elements {
if let DrgElement::BusinessKnowledgeModel(business_knowledge_model) = drg_element
&& business_knowledge_model.id() == id
{
return Some(business_knowledge_model);
}
}
None
}
pub fn get_knowledge_source(&self, id: &str) -> Option<&KnowledgeSource> {
for drg_element in &self.drg_elements {
if let DrgElement::KnowledgeSource(knowledge_source) = drg_element
&& knowledge_source.id() == id
{
return Some(knowledge_source);
}
}
None
}
pub fn get_requirement(&self, id: &str) -> Option<Requirement> {
for drg_element in &self.drg_elements {
match drg_element {
DrgElement::Decision(decision) => {
for knowledge_requirement in &decision.knowledge_requirements {
if knowledge_requirement.id() == id {
return Some(Requirement::Knowledge(knowledge_requirement.clone()));
}
}
for information_requirement in &decision.information_requirements {
if information_requirement.id() == id {
return Some(Requirement::Information(information_requirement.clone()));
}
}
for authority_requirement in &decision.authority_requirements {
if authority_requirement.id() == id {
return Some(Requirement::Authority(authority_requirement.clone()));
}
}
}
DrgElement::BusinessKnowledgeModel(business_knowledge_model) => {
for knowledge_requirement in &business_knowledge_model.knowledge_requirements {
if knowledge_requirement.id() == id {
return Some(Requirement::Knowledge(knowledge_requirement.clone()));
}
}
for authority_requirement in &business_knowledge_model.authority_requirements {
if authority_requirement.id() == id {
return Some(Requirement::Authority(authority_requirement.clone()));
}
}
}
DrgElement::KnowledgeSource(knowledge_source) => {
for authority_requirement in &knowledge_source.authority_requirements {
if authority_requirement.id() == id {
return Some(Requirement::Authority(authority_requirement.clone()));
}
}
}
_ => {}
}
}
None
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone, PartialEq)]
pub struct InformationItem {
pub(crate) type_ref: String,
pub(crate) feel_type: Option<FeelType>,
}
impl InformationItem {
pub fn type_ref(&self) -> &String {
&self.type_ref
}
}
impl FeelTypedElement for InformationItem {
fn feel_type(&self) -> &Option<FeelType> {
&self.feel_type
}
fn set_feel_type(&mut self, feel_type: FeelType) {
self.feel_type = Some(feel_type);
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone)]
pub struct InputData {
pub(crate) variable: InformationItem,
}
impl RequiredVariable for InputData {
fn variable(&self) -> &InformationItem {
&self.variable
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Import {
pub(crate) import_type: String,
pub(crate) location_uri: Option<String>,
}
impl Import {
pub fn import_type(&self) -> &str {
&self.import_type
}
pub fn location_uri(&self) -> &Option<String> {
&self.location_uri
}
pub fn namespace(&self) -> &str {
&self.namespace
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExpressionInstance {
Conditional(Box<Conditional>),
Context(Box<Context>),
DecisionTable(Box<DecisionTable>),
Every(Box<Every>),
Filter(Box<Filter>),
For(Box<For>),
FunctionDefinition(Box<FunctionDefinition>),
Invocation(Box<Invocation>),
List(Box<List>),
LiteralExpression(Box<LiteralExpression>),
Relation(Box<Relation>),
Some(Box<Some>),
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Context {
pub(crate) context_entries: Vec<ContextEntry>,
}
impl Context {
pub fn context_entries(&self) -> &Vec<ContextEntry> {
&self.context_entries
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ContextEntry {
pub variable: Option<InformationItem>,
pub value: ExpressionInstance,
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LiteralExpression {
pub(crate) text: Option<String>,
pub(crate) expression_language: Option<String>,
pub(crate) imported_values: Option<Import>,
}
impl LiteralExpression {
pub fn text(&self) -> &Option<String> {
&self.text
}
pub fn expression_language(&self) -> Option<String> {
self.expression_language.clone()
}
pub fn imported_values(&self) -> Option<Import> {
self.imported_values.clone()
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Invocation {
pub(crate) called_function: ExpressionInstance,
pub(crate) bindings: Vec<Binding>,
}
impl Invocation {
pub fn called_function(&self) -> &ExpressionInstance {
&self.called_function
}
pub fn bindings(&self) -> &Vec<Binding> {
&self.bindings
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Binding {
pub(crate) parameter: InformationItem,
pub(crate) binding_formula: Option<ExpressionInstance>,
}
impl Binding {
pub fn parameter(&self) -> &InformationItem {
&self.parameter
}
pub fn binding_formula(&self) -> &Option<ExpressionInstance> {
&self.binding_formula
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone)]
pub struct Decision {
pub(crate) question: Option<String>,
pub(crate) allowed_answers: Option<String>,
pub(crate) variable: InformationItem,
pub(crate) decision_logic: Option<ExpressionInstance>,
pub(crate) information_requirements: Vec<InformationRequirement>,
pub(crate) knowledge_requirements: Vec<KnowledgeRequirement>,
pub(crate) authority_requirements: Vec<AuthorityRequirement>,
}
impl Decision {
pub fn question(&self) -> &Option<String> {
&self.question
}
pub fn allowed_answers(&self) -> &Option<String> {
&self.allowed_answers
}
pub fn variable(&self) -> &InformationItem {
&self.variable
}
pub fn decision_logic(&self) -> &Option<ExpressionInstance> {
&self.decision_logic
}
pub fn information_requirements(&self) -> &Vec<InformationRequirement> {
&self.information_requirements
}
pub fn knowledge_requirements(&self) -> &Vec<KnowledgeRequirement> {
&self.knowledge_requirements
}
pub fn authority_requirements(&self) -> &Vec<AuthorityRequirement> {
&self.authority_requirements
}
}
#[dmn_element]
#[derive(Debug, Clone)]
pub struct InformationRequirement {
pub(crate) required_decision: Option<HRef>,
pub(crate) required_input: Option<HRef>,
}
impl InformationRequirement {
pub fn required_decision(&self) -> &Option<HRef> {
&self.required_decision
}
pub fn required_input(&self) -> &Option<HRef> {
&self.required_input
}
}
#[dmn_element]
#[derive(Debug, Clone)]
pub struct KnowledgeRequirement {
pub(crate) required_knowledge: HRef,
}
impl KnowledgeRequirement {
pub fn required_knowledge(&self) -> &HRef {
&self.required_knowledge
}
}
#[dmn_element]
#[derive(Debug, Clone)]
pub struct AuthorityRequirement {
pub(crate) required_authority: Option<HRef>,
pub(crate) required_decision: Option<HRef>,
pub(crate) required_input: Option<HRef>,
}
impl AuthorityRequirement {
pub fn required_authority(&self) -> &Option<HRef> {
&self.required_authority
}
pub fn required_decision(&self) -> &Option<HRef> {
&self.required_decision
}
pub fn required_input(&self) -> &Option<HRef> {
&self.required_input
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone)]
pub struct KnowledgeSource {
pub(crate) authority_requirements: Vec<AuthorityRequirement>,
}
impl KnowledgeSource {
pub fn authority_requirements(&self) -> &Vec<AuthorityRequirement> {
&self.authority_requirements
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone)]
pub struct BusinessKnowledgeModel {
pub(crate) variable: InformationItem,
pub(crate) encapsulated_logic: Option<FunctionDefinition>,
pub(crate) knowledge_requirements: Vec<KnowledgeRequirement>,
pub(crate) authority_requirements: Vec<AuthorityRequirement>,
}
impl BusinessKnowledgeModel {
pub fn encapsulated_logic(&self) -> &Option<FunctionDefinition> {
&self.encapsulated_logic
}
pub fn knowledge_requirements(&self) -> &Vec<KnowledgeRequirement> {
&self.knowledge_requirements
}
pub fn authority_requirements(&self) -> &Vec<AuthorityRequirement> {
&self.authority_requirements
}
}
impl RequiredVariable for BusinessKnowledgeModel {
fn variable(&self) -> &InformationItem {
&self.variable
}
}
#[named_element]
#[dmn_element]
#[derive(Debug, Clone)]
pub struct DecisionService {
pub(crate) variable: InformationItem,
pub(crate) output_decisions: Vec<HRef>,
pub(crate) encapsulated_decisions: Vec<HRef>,
pub(crate) input_decisions: Vec<HRef>,
pub(crate) input_data: Vec<HRef>,
}
impl DecisionService {
pub fn input_decisions(&self) -> &Vec<HRef> {
&self.input_decisions
}
pub fn encapsulated_decisions(&self) -> &Vec<HRef> {
&self.encapsulated_decisions
}
pub fn output_decisions(&self) -> &Vec<HRef> {
&self.output_decisions
}
pub fn input_data(&self) -> &Vec<HRef> {
&self.input_data
}
}
impl RequiredVariable for DecisionService {
fn variable(&self) -> &InformationItem {
&self.variable
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ItemDefinitionType {
SimpleType(FeelType),
ReferencedType(String, String),
ComponentType,
CollectionOfSimpleType(FeelType),
CollectionOfReferencedType(String, String),
CollectionOfComponentType,
FunctionType,
}
#[named_element]
#[dmn_element]
#[expression]
#[derive(Debug, Clone)]
pub struct ItemDefinition {
pub(crate) type_language: Option<String>,
pub(crate) feel_type: Option<FeelType>,
pub(crate) allowed_values: Option<UnaryTests>,
pub(crate) item_components: Vec<ItemDefinition>,
pub(crate) is_collection: bool,
pub(crate) function_item: Option<FunctionItem>,
}
impl ItemDefinition {
pub fn type_language(&self) -> &Option<String> {
&self.type_language
}
pub fn allowed_values(&self) -> &Option<UnaryTests> {
&self.allowed_values
}
pub fn item_components(&self) -> &Vec<ItemDefinition> {
&self.item_components
}
pub fn item_components_mut(&mut self) -> &mut Vec<ItemDefinition> {
&mut self.item_components
}
pub fn is_collection(&self) -> bool {
self.is_collection
}
pub fn feel_type(&self) -> &Option<FeelType> {
&self.feel_type
}
pub fn set_feel_type(&mut self, feel_type: FeelType) {
self.feel_type = Some(feel_type);
}
pub fn function_item(&self) -> &Option<FunctionItem> {
&self.function_item
}
}
#[derive(Debug, Clone)]
pub struct UnaryTests {
pub(crate) text: Option<String>,
pub(crate) expression_language: Option<String>,
}
impl UnaryTests {
pub fn text(&self) -> &Option<String> {
&self.text
}
pub fn expression_language(&self) -> &Option<String> {
&self.expression_language
}
}
#[derive(Debug, Clone)]
pub struct FunctionItem {
pub(crate) output_type_ref: Option<String>,
pub(crate) parameters: Vec<InformationItem>,
}
impl FunctionItem {
pub fn output_type_ref(&self) -> &Option<String> {
&self.output_type_ref
}
pub fn parameters(&self) -> &Vec<InformationItem> {
&self.parameters
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FunctionKind {
Feel,
Java,
Pmml,
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionDefinition {
pub(crate) formal_parameters: Vec<InformationItem>,
pub(crate) body: Option<ExpressionInstance>,
pub(crate) kind: FunctionKind,
}
impl FunctionDefinition {
pub fn formal_parameters(&self) -> &Vec<InformationItem> {
&self.formal_parameters
}
pub fn body(&self) -> &Option<ExpressionInstance> {
&self.body
}
pub fn kind(&self) -> &FunctionKind {
&self.kind
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Relation {
pub(crate) rows: Vec<List>,
pub(crate) columns: Vec<InformationItem>,
}
impl Relation {
pub fn rows(&self) -> &Vec<List> {
&self.rows
}
pub fn columns(&self) -> &Vec<InformationItem> {
&self.columns
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct List {
pub(crate) elements: Vec<ExpressionInstance>,
}
impl List {
pub fn elements(&self) -> &Vec<ExpressionInstance> {
&self.elements
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Conditional {
pub(crate) if_expression: ChildExpression,
pub(crate) then_expression: ChildExpression,
pub(crate) else_expression: ChildExpression,
}
impl Conditional {
pub fn if_expression(&self) -> &ChildExpression {
&self.if_expression
}
pub fn then_expression(&self) -> &ChildExpression {
&self.then_expression
}
pub fn else_expression(&self) -> &ChildExpression {
&self.else_expression
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Filter {
pub(crate) in_expression: ChildExpression,
pub(crate) match_expression: ChildExpression,
}
impl Filter {
pub fn in_expression(&self) -> &ChildExpression {
&self.in_expression
}
pub fn match_expression(&self) -> &ChildExpression {
&self.match_expression
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct For {
pub(crate) iterator_variable: String,
pub(crate) in_expression: TypedChildExpression,
pub(crate) return_expression: ChildExpression,
}
impl For {
pub fn iterator_variable(&self) -> &String {
&self.iterator_variable
}
pub fn in_expression(&self) -> &TypedChildExpression {
&self.in_expression
}
pub fn return_expression(&self) -> &ChildExpression {
&self.return_expression
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Every {
pub(crate) iterator_variable: String,
pub(crate) in_expression: TypedChildExpression,
pub(crate) satisfies_expression: ChildExpression,
}
impl Every {
pub fn iterator_variable(&self) -> &String {
&self.iterator_variable
}
pub fn in_expression(&self) -> &TypedChildExpression {
&self.in_expression
}
pub fn satisfies_expression(&self) -> &ChildExpression {
&self.satisfies_expression
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct Some {
pub(crate) iterator_variable: String,
pub(crate) in_expression: TypedChildExpression,
pub(crate) satisfies_expression: ChildExpression,
}
impl Some {
pub fn iterator_variable(&self) -> &String {
&self.iterator_variable
}
pub fn in_expression(&self) -> &TypedChildExpression {
&self.in_expression
}
pub fn satisfies_expression(&self) -> &ChildExpression {
&self.satisfies_expression
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ChildExpression {
pub(crate) id: DmnId,
pub(crate) value: ExpressionInstance,
}
impl ChildExpression {
pub fn id(&self) -> &DmnId {
&self.id
}
pub fn value(&self) -> &ExpressionInstance {
&self.value
}
}
#[expression]
#[derive(Debug, Clone, PartialEq)]
pub struct TypedChildExpression {
pub(crate) id: DmnId,
pub(crate) value: ExpressionInstance,
}
impl TypedChildExpression {
pub fn id(&self) -> &DmnId {
&self.id
}
pub fn value(&self) -> &ExpressionInstance {
&self.value
}
}
#[dmn_element]
#[expression]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecisionTable {
pub(crate) information_item_name: Option<String>,
pub(crate) input_clauses: Vec<InputClause>,
pub(crate) output_clauses: Vec<OutputClause>,
pub(crate) annotations: Vec<RuleAnnotationClause>,
pub(crate) rules: Vec<DecisionRule>,
pub(crate) hit_policy: HitPolicy,
pub(crate) aggregation: Option<BuiltinAggregator>,
pub(crate) preferred_orientation: DecisionTableOrientation,
pub(crate) output_label: Option<String>,
}
impl Display for DecisionTable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut buffer = String::new();
buffer.push_str("Decision table:\n");
buffer.push_str(format!(">> preferred orientation: {}\n", self.preferred_orientation).as_str());
buffer.push_str(">> information item name: ");
if let Some(text) = &self.information_item_name {
buffer.push_str(format!("\n'{text}'\n").as_str());
} else {
buffer.push_str("none\n");
}
buffer.push_str(format!(">> hit policy: {}\n", self.hit_policy).as_str());
buffer.push_str(">> aggregation: ");
if let Some(aggregation) = &self.aggregation {
buffer.push_str(format!("{aggregation}\n").as_str());
} else {
buffer.push_str("none\n");
}
buffer.push_str(">> output label: ");
if let Some(text) = &self.output_label {
buffer.push_str(format!("\n'{text}'\n").as_str());
} else {
buffer.push_str("none\n");
}
write!(f, "{buffer}")
}
}
impl DecisionTable {
#[allow(clippy::too_many_arguments)]
pub fn new(
information_item_name: Option<String>,
input_clauses: Vec<InputClause>,
output_clauses: Vec<OutputClause>,
annotations: Vec<RuleAnnotationClause>,
rules: Vec<DecisionRule>,
hit_policy: HitPolicy,
aggregation: Option<BuiltinAggregator>,
preferred_orientation: DecisionTableOrientation,
output_label: Option<String>,
) -> Self {
Self {
namespace: "".to_string(),
model_name: "".to_string(),
id: DmnId::Generated(gen_id()),
description: None,
label: None,
extension_elements: vec![],
extension_attributes: vec![],
type_ref: None,
information_item_name,
input_clauses,
output_clauses,
annotations,
rules,
hit_policy,
aggregation,
preferred_orientation,
output_label,
}
}
pub fn information_item_name(&self) -> &Option<String> {
&self.information_item_name
}
pub fn input_clauses(&self) -> Iter<'_, InputClause> {
self.input_clauses.iter()
}
pub fn output_clauses(&self) -> Iter<'_, OutputClause> {
self.output_clauses.iter()
}
pub fn annotations(&self) -> Iter<'_, RuleAnnotationClause> {
self.annotations.iter()
}
pub fn rules(&self) -> Iter<'_, DecisionRule> {
self.rules.iter()
}
pub fn hit_policy(&self) -> HitPolicy {
self.hit_policy
}
pub fn aggregation(&self) -> &Option<BuiltinAggregator> {
&self.aggregation
}
pub fn preferred_orientation(&self) -> &DecisionTableOrientation {
&self.preferred_orientation
}
pub fn output_label(&self) -> &Option<String> {
&self.output_label
}
pub fn allowed_values_present(&self) -> bool {
for input_clause in &self.input_clauses {
if input_clause.allowed_input_values.is_some() {
return true;
}
}
for output_clause in &self.output_clauses {
if output_clause.allowed_output_values.is_some() {
return true;
}
}
false
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecisionTableOrientation {
RuleAsRow,
RuleAsColumn,
CrossTable,
}
impl Display for DecisionTableOrientation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DecisionTableOrientation::RuleAsRow => write!(f, "Rule-as-Row"),
DecisionTableOrientation::RuleAsColumn => write!(f, "Rule-as-Column"),
DecisionTableOrientation::CrossTable => write!(f, "CrossTable"),
}
}
}
impl TryFrom<&str> for DecisionTableOrientation {
type Error = DsntkError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value.trim() {
"Rule-as-Row" => Ok(DecisionTableOrientation::RuleAsRow),
"Rule-as-Column" => Ok(DecisionTableOrientation::RuleAsColumn),
"CrossTable" => Ok(DecisionTableOrientation::CrossTable),
other => Err(err_invalid_decision_table_orientation(other)),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum HitPolicy {
Unique,
Any,
Priority,
First,
Collect(BuiltinAggregator),
OutputOrder,
RuleOrder,
}
impl Display for HitPolicy {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HitPolicy::Unique => write!(f, "U"),
HitPolicy::Any => write!(f, "A"),
HitPolicy::Priority => write!(f, "P"),
HitPolicy::First => write!(f, "F"),
HitPolicy::Collect(aggregator) => write!(f, "{aggregator}"),
HitPolicy::OutputOrder => write!(f, "O"),
HitPolicy::RuleOrder => write!(f, "R"),
}
}
}
impl TryFrom<&str> for HitPolicy {
type Error = DsntkError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value.trim() {
"U" => Ok(HitPolicy::Unique),
"A" => Ok(HitPolicy::Any),
"P" => Ok(HitPolicy::Priority),
"F" => Ok(HitPolicy::First),
"R" => Ok(HitPolicy::RuleOrder),
"O" => Ok(HitPolicy::OutputOrder),
"C" => Ok(HitPolicy::Collect(BuiltinAggregator::List)),
"C+" => Ok(HitPolicy::Collect(BuiltinAggregator::Sum)),
"C#" => Ok(HitPolicy::Collect(BuiltinAggregator::Count)),
"C<" => Ok(HitPolicy::Collect(BuiltinAggregator::Min)),
"C>" => Ok(HitPolicy::Collect(BuiltinAggregator::Max)),
other => Err(err_invalid_decision_table_hit_policy(other)),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum BuiltinAggregator {
List,
Count,
Sum,
Min,
Max,
}
impl Display for BuiltinAggregator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
BuiltinAggregator::List => "C",
BuiltinAggregator::Count => "C#",
BuiltinAggregator::Sum => "C+",
BuiltinAggregator::Min => "C<",
BuiltinAggregator::Max => "C>",
}
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InputClause {
pub input_expression: String,
pub allowed_input_values: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutputClause {
pub type_ref: Option<String>,
pub name: Option<String>,
pub allowed_output_values: Option<String>,
pub default_output_entry: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuleAnnotationClause {
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecisionRule {
pub input_entries: Vec<InputEntry>,
pub output_entries: Vec<OutputEntry>,
pub annotation_entries: Vec<AnnotationEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InputEntry {
pub text: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutputEntry {
pub text: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AnnotationEntry {
pub text: String,
}
#[derive(Debug, Clone)]
pub struct Dmndi {
pub styles: Vec<DmnStyle>,
pub diagrams: Vec<DmnDiagram>,
}
#[derive(Debug, Clone)]
pub enum DmnDiagramElement {
DmnShape(DmnShape),
DmnEdge(DmnEdge),
}
#[derive(Debug, Clone, Default)]
pub struct DmnDiagram {
pub id: Option<String>,
pub name: Option<String>,
pub documentation: String,
pub resolution: f64,
pub diagram_elements: Vec<DmnDiagramElement>,
pub shared_style: Option<String>,
pub local_style: Option<DmnStyle>,
pub size: Option<DcDimension>,
}
#[derive(Debug, Clone)]
pub struct DmnShape {
pub id: Option<String>,
pub bounds: DcBounds,
pub dmn_element_ref: Option<String>,
pub is_listed_input_data: bool,
pub decision_service_divider_line: Option<DmnDecisionServiceDividerLine>,
pub is_collapsed: bool,
pub shared_style: Option<String>,
pub local_style: Option<DmnStyle>,
pub label: Option<DmnLabel>,
}
#[derive(Debug, Clone)]
pub struct DmnDecisionServiceDividerLine {
pub id: Option<String>,
pub way_points: Vec<DcPoint>,
pub shared_style: Option<String>,
pub local_style: Option<DmnStyle>,
}
#[derive(Debug, Clone)]
pub struct DmnEdge {
pub id: Option<String>,
pub way_points: Vec<DcPoint>,
pub dmn_element_ref: Option<String>,
pub source_element: Option<String>,
pub target_element: Option<String>,
pub shared_style: Option<String>,
pub local_style: Option<DmnStyle>,
pub label: Option<DmnLabel>,
}
#[derive(Debug, Clone)]
pub struct Association {}
#[derive(Debug, Clone)]
pub struct TextAnnotation {}
#[derive(Debug, Clone)]
pub struct DmnStyle {
pub id: String,
pub fill_color: Option<DcColor>,
pub stroke_color: Option<DcColor>,
pub font_color: Option<DcColor>,
pub font_family: Option<String>,
pub font_size: Option<f64>,
pub font_italic: Option<bool>,
pub font_bold: Option<bool>,
pub font_underline: Option<bool>,
pub font_strike_through: Option<bool>,
pub label_horizontal_alignment: Option<DcAlignmentKind>,
pub label_vertical_alignment: Option<DcAlignmentKind>,
}
#[derive(Debug, Clone)]
pub struct DmnLabel {
pub bounds: Option<DcBounds>,
pub text: Option<String>,
pub shared_style: Option<String>,
}
#[derive(Debug, Copy, Clone)]
pub struct DcColor {
pub red: u8,
pub green: u8,
pub blue: u8,
}
impl DcColor {
pub fn white() -> Self {
Self {
red: 0xFF,
green: 0xFF,
blue: 0xFF,
}
}
pub fn black() -> Self {
Self { red: 0x0, green: 0x0, blue: 0x0 }
}
}
#[derive(Debug, Copy, Clone)]
pub struct DcPoint {
pub x: f64,
pub y: f64,
}
#[derive(Debug, Copy, Clone)]
pub struct DcBounds {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
#[derive(Debug, Copy, Clone)]
pub struct DcDimension {
pub width: f64,
pub height: f64,
}
#[derive(Debug, Copy, Clone)]
pub enum DcAlignmentKind {
Start,
End,
Center,
}
#[derive(Debug, Copy, Clone)]
pub enum DcKnownColor {
Aqua = 0x00FFFF,
Black = 0x000000,
Blue = 0x0000FF,
Fuchsia = 0xFF00FF,
Gray = 0x808080,
Green = 0x008000,
Lime = 0x00FF00,
Maroon = 0x800000,
Navy = 0x000080,
Olive = 0x808000,
Orange = 0xFFA500,
Purple = 0x800080,
Red = 0xFF0000,
Silver = 0xC0C0C0,
Teal = 0x008080,
White = 0xFFFFFF,
Yellow = 0xFFFF00,
}