chore: initial git load of code space
This commit is contained in:
@@ -0,0 +1,459 @@
|
||||
# Strata.SqlTools.Rules Class Diagram
|
||||
|
||||
This diagram shows the class hierarchy for the expression system.
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// (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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
- `AND` or `\land` or `\wedge` - Logical AND
|
||||
- `OR` or `\lor` or `\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
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
```csharp
|
||||
// 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
|
||||
|
||||
1. **Documentation and Code Alignment**: Keep rule documentation and implementation in sync
|
||||
2. **Human-Readable Rules**: Write business rules in a format that non-developers can understand
|
||||
3. **LaTeX Support**: Use standard mathematical notation for complex logical expressions
|
||||
4. **Easy Testing**: Write test cases using readable markdown expressions
|
||||
5. **Version Control Friendly**: Track rule changes in readable text format
|
||||
Reference in New Issue
Block a user