Skip to content

Instantly share code, notes, and snippets.

@Shipu
Last active July 29, 2024 07:43
Show Gist options
  • Save Shipu/f049956b6ca1a36a638ddb395376f28e to your computer and use it in GitHub Desktop.
Save Shipu/f049956b6ca1a36a638ddb395376f28e to your computer and use it in GitHub Desktop.
RCT
(c1 result >= 35 AND ( c3 result <= 30 AND c2 progress > 50))
AND
(c3 result > 10 AND purchase_date < 2025-01-10 )
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/shipu/artifact"
"net/http"
"strconv"
"time"
)
type Expression struct {
Content string `json:"content,omitempty"`
Variable string `json:"variable,omitempty"`
Comparison string `json:"comparison,omitempty"`
Value string `json:"value,omitempty"`
From string `json:"from,omitempty"`
Operator string `json:"operator,omitempty"`
Conditions []Expression `json:"conditions,omitempty"`
}
type VisibilityLogic struct {
Type string `json:"type"`
Until []Expression `json:"until"`
}
var context = map[string]interface{}{
"c1_result": 40,
"c2_progress": 80,
"c3_result": 20,
"purchase_date": "2024-07-01",
}
// compareDate compares two dates based on the operator.
func compareDate(from, to, operator string) (bool, error) {
fromDate, err := time.Parse("2006-01-02", from)
if err != nil {
return false, err
}
toDate, err := time.Parse("2006-01-02", to)
if err != nil {
return false, err
}
switch operator {
case "=":
return fromDate.Equal(toDate), nil
case "!=":
return !fromDate.Equal(toDate), nil
case ">":
return fromDate.After(toDate), nil
case "<":
return fromDate.Before(toDate), nil
case ">=":
return fromDate.After(toDate) || fromDate.Equal(toDate), nil
case "<=":
return fromDate.Before(toDate) || fromDate.Equal(toDate), nil
}
return false, nil
}
// evaluateExpression evaluates a single expression condition.
func evaluateExpression(cond Expression) bool {
// Handle date and time related comparisons
if cond.Variable == "date" || cond.Variable == "time" {
from := cond.From
if from == "" {
from = time.Now().Format("2006-01-02")
} else {
from = context[from].(string)
}
result, err := compareDate(from, cond.Value, cond.Comparison)
if err != nil {
fmt.Println("Error comparing dates:", err)
return false
}
return result
}
left, ok := context[cond.Content+"_"+cond.Variable]
if !ok {
fmt.Println("Context value not found for:", cond.Content+"_"+cond.Variable)
return false
}
var rightParsed interface{}
var err error
switch left.(type) {
case int:
rightParsed, err = strconv.Atoi(cond.Value)
if err != nil {
fmt.Println("Error parsing integer value:", err)
return false
}
case float64:
rightParsed, err = strconv.ParseFloat(cond.Value, 64)
if err != nil {
fmt.Println("Error parsing float value:", err)
return false
}
default:
rightParsed = cond.Value
}
switch cond.Comparison {
case "=":
return left == rightParsed
case "!=":
return left != rightParsed
case ">":
return left.(int) > rightParsed.(int)
case "<":
return left.(int) < rightParsed.(int)
case ">=":
return left.(int) >= rightParsed.(int)
case "<=":
return left.(int) <= rightParsed.(int)
}
return false
}
func evaluateExpressions(conditions []Expression) bool {
for _, condition := range conditions {
if condition.Operator == "" {
if !evaluateExpression(condition) {
return false
}
} else {
switch condition.Operator {
case "AND":
if !evaluateExpressions(condition.Conditions) {
return false
}
case "OR":
if evaluateExpressions(condition.Conditions) {
return true
}
}
}
}
return true
}
func Evaluate() gin.HandlerFunc {
return func(c *gin.Context) {
var visibilityLogic VisibilityLogic
if err := c.ShouldBind(&visibilityLogic); err != nil {
artifact.Res.Code(http.StatusBadRequest).Message("Bad Request").Data(err.Error()).AbortWithStatusJSON(c)
return
}
result := evaluateExpressions(visibilityLogic.Until)
artifact.Res.Code(200).Data(map[string]interface{}{
"result": result,
}).Message("success").Json(c)
}
}
{
"type": "lock",
"until": [
{
"operator": "AND",
"conditions": [
{
"operator": "AND",
"conditions": [
{
"content": "c1",
"variable": "result",
"comparison": ">=",
"value": "35"
},
{
"operator": "AND",
"conditions": [
{
"content": "c3",
"variable": "result",
"comparison": "<=",
"value": "30"
},
{
"content": "c2",
"variable": "progress",
"comparison": ">",
"value": "50"
}
]
}
]
},
{
"operator": "AND",
"conditions": [
{
"content": "c3",
"variable": "result",
"comparison": ">",
"value": "10"
},
{
"variable": "date",
"comparison": "<",
"value": "2025-01-10",
"from": "purchase_date"
}
]
}
]
}
]
}
userApi := Router.Group("api/v1")
userApi.POST("evaluate", c.Evaluate())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment