12 KiB
12 KiB
Strata.SqlTools.Rules Class Diagram
This diagram shows the class hierarchy for the expression system.
classDiagram
class IVisitable {
<<interface>>
+Accept~T~(IVisitor~T~) T
}
note for IVisitable "Visitor Pattern Interface<br/>var visitor = new MyRuleVisitor()#59;<br/>var result = expr.Accept(visitor)#59;"
class Expression {
<<abstract>>
+Accept~T~(IVisitor~T~) T
}
class BoolExpr {
<<abstract>>
}
class Literal {
+Value object
}
class LiteralGeneric~TValue~ {
+Value TValue
}
note for LiteralGeneric "Generic Literal<br/>var literal = new Literal<int><br/>{ Value = 100 }#59;"
class Property {
+Expression Expression
+PropertyName string
}
note for Property "Property Access<br/>var prop = new Property<br/>{ PropertyName = #quot;Age#quot; }#59;"
class Logical {
<<abstract>>
+Left BoolExpr
+Right BoolExpr
}
class Comparison {
<<abstract>>
+Left Expression
+Right Expression
+ExpressionType ExpressionType
}
class And
note for And "AND Logic<br/>var and = new And<br/>{<br/> Left = expr1,<br/> Right = expr2<br/>}#59;"
class Or
note for Or "OR Logic<br/>var or = new Or<br/>{<br/> Left = expr1,<br/> Right = expr2<br/>}#59;"
class With
note for With "WITH Sequential<br/>var with = new With<br/>{<br/> Left = expr1,<br/> Right = expr2<br/>}#59;"
class Equal {
+ExpressionType ExpressionType
}
note for Equal "Equality#58; Age == 25<br/>var eq = new Equal<br/>{<br/> Left = new Property<br/> { PropertyName = #quot;Age#quot; },<br/> Right = new NumberLiteral<br/> { Value = 25m }<br/>}#59;"
class GreaterThan {
+ExpressionType ExpressionType
}
note for GreaterThan "Comparison#58; Score > 100<br/>var gt = new GreaterThan<br/>{<br/> Left = new Property<br/> { PropertyName = #quot;Score#quot; },<br/> Right = new NumberLiteral<br/> { Value = 100m }<br/>}#59;"
class NumberLiteral {
+Value decimal
}
note for NumberLiteral "Number Literal<br/>var num = new NumberLiteral<br/>{ Value = 42.5m }#59;"
class StringLiteral {
+Value string
}
note for StringLiteral "String Literal<br/>var str = new StringLiteral<br/>{ Value = #quot;Hello#quot; }#59;"
IVisitable <|.. Expression
Expression <|-- BoolExpr
Expression <|-- Literal
Expression <|-- Property
BoolExpr <|-- Logical
BoolExpr <|-- Comparison
Literal <|-- LiteralGeneric
LiteralGeneric <|-- NumberLiteral
LiteralGeneric <|-- StringLiteral
Logical <|-- And
Logical <|-- Or
Logical <|-- With
Comparison <|-- Equal
Comparison <|-- GreaterThan
Class Descriptions
Core Classes
- IVisitable: Interface for classes that can be visited using the visitor pattern
- Expression: Base abstract class for all expressions
- BoolExpr: Base class for expressions that evaluate to boolean values
Literal Expressions
- Literal: Represents a literal value
- Literal<TValue>: Generic typed literal expression
- NumberLiteral: Represents numeric literal values (decimal)
- StringLiteral: Represents string literal values
Property Expressions
- Property: Represents property access in expressions
Logical Expressions
- Logical: Base class for logical operations (AND, OR, WITH)
- And: Logical AND operation
- Or: Logical OR operation
- With: Sequential WITH operation
Comparison Expressions
- Comparison: Base class for comparison operations
- Equal: Equality comparison (==)
- GreaterThan: Greater than comparison (>)
C# Usage Examples
Creating Literal Expressions
// String literal
var stringLiteral = new StringLiteral
{
Value = "Hello World"
};
// Number literal
var numberLiteral = new NumberLiteral
{
Value = 42.5m
};
// Generic typed literal
var typedLiteral = new Literal<int>
{
Value = 100
};
Creating Property Expressions
// Simple property access
var propertyExpr = new Property
{
PropertyName = "Age"
};
// Property with nested expression
var nestedPropertyExpr = new Property
{
PropertyName = "Address",
Expression = new Property
{
PropertyName = "City"
}
};
Creating Comparison Expressions
// Equal comparison: Age == 25
var equalExpr = new Equal
{
Left = new Property { PropertyName = "Age" },
Right = new NumberLiteral { Value = 25m }
};
// Greater than comparison: Score > 100
var greaterThanExpr = new GreaterThan
{
Left = new Property { PropertyName = "Score" },
Right = new NumberLiteral { Value = 100m }
};
Creating Logical Expressions
// AND expression: Age > 18 AND Status == "Active"
var andExpr = new And
{
Left = new GreaterThan
{
Left = new Property { PropertyName = "Age" },
Right = new NumberLiteral { Value = 18m }
},
Right = new Equal
{
Left = new Property { PropertyName = "Status" },
Right = new StringLiteral { Value = "Active" }
}
};
// OR expression: Type == "Premium" OR Score > 500
var orExpr = new Or
{
Left = new Equal
{
Left = new Property { PropertyName = "Type" },
Right = new StringLiteral { Value = "Premium" }
},
Right = new GreaterThan
{
Left = new Property { PropertyName = "Score" },
Right = new NumberLiteral { Value = 500m }
}
};
Complex Expression Example
// (Age > 18 AND Status == "Active") OR (Type == "Premium" WITH Score > 500)
var complexExpr = new Or
{
Left = new And
{
Left = new GreaterThan
{
Left = new Property { PropertyName = "Age" },
Right = new NumberLiteral { Value = 18m }
},
Right = new Equal
{
Left = new Property { PropertyName = "Status" },
Right = new StringLiteral { Value = "Active" }
}
},
Right = new With
{
Left = new Equal
{
Left = new Property { PropertyName = "Type" },
Right = new StringLiteral { Value = "Premium" }
},
Right = new GreaterThan
{
Left = new Property { PropertyName = "Score" },
Right = new NumberLiteral { Value = 500m }
}
}
};
Using the Visitor Pattern
// Implement a custom visitor
public class MyRuleVisitor : IVisitor<string>
{
public string Visit(And expression)
{
return $"({expression.Left.Accept(this)} AND {expression.Right.Accept(this)})";
}
public string Visit(Equal expression)
{
return $"{expression.Left.Accept(this)} == {expression.Right.Accept(this)}";
}
public string Visit(StringLiteral expression)
{
return $"\"{expression.Value}\"";
}
// ... implement other Visit methods
}
// Use the visitor
var visitor = new MyRuleVisitor();
var result = complexExpr.Accept(visitor);
Console.WriteLine(result);
Markdown Parser
The Markdown class provides functionality to parse markdown/LaTeX mathematical expressions and convert them into Expression objects. This is useful for:
- Documenting rules in markdown format
- Creating expressions from user-friendly text representations
- Converting mathematical notation to executable rule expressions
Supported Markdown Delimiters
The parser automatically strips these common markdown delimiters:
- Inline math:
$...$ - Block math:
$$...$$ - Code fence:
```math...```
Supported Syntax
Logical Operators
ANDor\landor\wedge- Logical ANDORor\loror\vee- Logical OR
Comparison Operators
=- Equality!=or\neq- Not equal>or\gt- Greater than
Literals
- Numbers:
42,3.14 - Strings:
"text"or'text'or\text{text} - Booleans:
true,false
Properties
- Simple:
PropertyName - With parameter:
x.PropertyName - LaTeX format:
\text{x.PropertyName}
Parentheses
- Regular:
(...) - LaTeX:
\left(...\right)
Markdown Parser Usage Examples
Basic Parsing
using Strata.SqlTools.Rules.Rule.Expression;
// Parse a simple comparison
var expr1 = Markdown.Parse("x.Age > 18");
// Returns: GreaterThan { Left = Property("x", "Age"), Right = NumberLiteral(18) }
// Parse with inline math delimiters
var expr2 = Markdown.Parse("$x.Status = 'active'$");
// Returns: Equal { Left = Property("x", "Status"), Right = StringLiteral("active") }
// Parse with block math delimiters
var expr3 = Markdown.Parse(@"$$
user.IsVerified = true
$$");
// Returns: Equal { Left = Property("user", "IsVerified"), Right = Literal(true) }
Parsing Logical Operations
// Parse AND expression
var andExpr = Markdown.Parse("x.Age > 18 AND x.Active = true");
// Returns: And { Left = GreaterThan(...), Right = Equal(...) }
// Parse OR with LaTeX notation
var orExpr = Markdown.Parse(@"$
x.Type = 'premium' \lor x.Score > 500
$");
// Returns: Or { Left = Equal(...), Right = GreaterThan(...) }
// Parse with LaTeX wedge (AND) and vee (OR)
var complexExpr = Markdown.Parse(@"
(x.Valid = true \wedge x.Count > 0) \vee y.Override = true
");
// Returns: Or { Left = And(...), Right = Equal(...) }
Parsing Complex Expressions
// Complex business rule with nested conditions
var businessRule = Markdown.Parse(@"$$
(invoice.TotalCharges > 1000 \land invoice.Status = \text{pending})
\lor
(invoice.Priority = \text{urgent} \land invoice.ApprovedBy \neq \text{})
$$");
// Use with visitor pattern
var visitor = new MyRuleVisitor();
var result = businessRule.Accept(visitor);
Safe Parsing with TryParse
// Use TryParse for error handling
if (Markdown.TryParse("x.Age > 18", out var expression))
{
Console.WriteLine("Parsed successfully!");
// Use the expression
var result = expression.Accept(myVisitor);
}
else
{
Console.WriteLine("Failed to parse expression");
}
Real-World Example
// Define a rule in markdown documentation
var ruleMarkdown = @"
# User Eligibility Rule
The user must meet one of the following conditions:
\`\`\`math
(\text{user.Age} > 18 \land \text{user.AccountStatus} = \text{active})
\lor
(\text{user.Role} = \text{admin})
\`\`\`
";
// Extract and parse the math block
var mathContent = ExtractMathBlock(ruleMarkdown); // Your extraction logic
var eligibilityRule = Markdown.Parse(mathContent);
// Apply the rule
public class EligibilityChecker : IVisitor<bool>
{
private readonly User _user;
public EligibilityChecker(User user) => _user = user;
public bool VisitAnd(And expression) =>
expression.Left.Accept(this) && expression.Right.Accept(this);
public bool VisitOr(Or expression) =>
expression.Left.Accept(this) || expression.Right.Accept(this);
public bool VisitEqual(Equal expression)
{
var left = expression.Left.Accept(new PropertyEvaluator(_user));
var right = expression.Right.Accept(new LiteralEvaluator());
return Equals(left, right);
}
// ... other visitor methods
}
// Check eligibility
var checker = new EligibilityChecker(currentUser);
bool isEligible = eligibilityRule.Accept(checker);
Benefits of Using Markdown Parser
- Documentation and Code Alignment: Keep rule documentation and implementation in sync
- Human-Readable Rules: Write business rules in a format that non-developers can understand
- LaTeX Support: Use standard mathematical notation for complex logical expressions
- Easy Testing: Write test cases using readable markdown expressions
- Version Control Friendly: Track rule changes in readable text format