servicebuildermdl.go 5.43 KiB
Newer Older
package servicebuildermdl

import (
Ajit Jagtap's avatar
Ajit Jagtap committed
	"strings"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"

Ajit Jagtap's avatar
Ajit Jagtap committed
	"github.com/oleksandr/conditions"
	"github.com/tidwall/gjson"
Ajit Jagtap's avatar
Ajit Jagtap committed
var ruleCache map[string]conditions.Expr

func init() {
	ruleCache = make(map[string]conditions.Expr, 0)
}

// LoadData is a method sign for loader methods
type LoadData = func(ab *AbstractBusinessLogicHolder)

// FinalStepProcessOutput is a method sign for loader methods
type FinalStepProcessOutput = func(ab *AbstractBusinessLogicHolder) *interface{}

// AbstractBusinessLogicHolder use this type to inheritance
type AbstractBusinessLogicHolder struct {
	ServiceData map[string]interface{}
}

// GetDataString will give you string
func (ab *AbstractBusinessLogicHolder) GetDataString(key string) (string, bool) {
	//check in map
	temp, found := ab.ServiceData[key]
	if errormdl.CheckBool(!found) {
		return "", false
	}
	// cast it
	value, ok := temp.(string)
	if errormdl.CheckBool1(!ok) {
		return "", false
	}
	return value, true
}

// GetDataInt will give you int
func (ab *AbstractBusinessLogicHolder) GetDataInt(key string) (int, bool) {
	//check in map
	temp, found := ab.ServiceData[key]
	if errormdl.CheckBool(!found) {
		return 0, false
	}
	// cast it
	value, ok := temp.(int)
	if errormdl.CheckBool1(!ok) {
		return 0, false
	}
	return value, true
}

Ajit Jagtap's avatar
Ajit Jagtap committed
// GetResultset will give you int
func (ab *AbstractBusinessLogicHolder) GetResultset(key string) (*gjson.Result, bool) {
	//check in map
	temp, found := ab.ServiceData[key]
	if errormdl.CheckBool(!found) {
		loggermdl.LogWarn("Key not found -", key)
		return &gjson.Result{}, false
	}
	// cast it
	value, ok := temp.(*gjson.Result)

	if errormdl.CheckBool1(!ok) {
		return &gjson.Result{}, false
	}
	return value, true
}

// GetBool will give you int
func (ab *AbstractBusinessLogicHolder) GetBool(key string) (bool, bool) {
	//check in map
	temp, found := ab.ServiceData[key]
	if errormdl.CheckBool(!found) {
		return false, false
	}
	// cast it
	value, ok := temp.(bool)
	if errormdl.CheckBool1(!ok) {
		return false, false
	}
	return value, true
}

// GetInterface will give you string
func (ab *AbstractBusinessLogicHolder) GetInterface(key string) (interface{}, bool) {
	//check in map
	temp, found := ab.ServiceData[key]
	if errormdl.CheckBool(!found) {
		return 0, false
	}
	// cast it
	return temp, true
}

// Build will create memory for your data
func (ab *AbstractBusinessLogicHolder) Build() {
	ab.ServiceData = make(map[string]interface{})
}

Ajit Jagtap's avatar
Ajit Jagtap committed
// SetResultset will return map data with finaldata key
func (ab *AbstractBusinessLogicHolder) SetResultset(key string, obj *gjson.Result) {
	ab.ServiceData[key] = obj
}

// GetFinalData will return map data with finaldata key
func (ab *AbstractBusinessLogicHolder) GetFinalData() *interface{} {
	a := ab.ServiceData["finaldata"]
	return &a
}

Ajit Jagtap's avatar
Ajit Jagtap committed
// SetFinalData will return map data with finaldata key
func (ab *AbstractBusinessLogicHolder) SetFinalData(data interface{}) {
	ab.ServiceData["finaldata"] = data
}

// EchoBL sample EchoBL logic handler
func (ab *AbstractBusinessLogicHolder) EchoBL() map[string]interface{} {
Ajit Jagtap's avatar
Ajit Jagtap committed
	// loggermdl.LogWarn("EchoBL called")
	return map[string]interface{}{
		"ok": int64(1),
	}
}

// Step help to maintain steps
type Step struct {
	Stepname        string
	RawYQL          string
Ajit Jagtap's avatar
Ajit Jagtap committed
	expr            conditions.Expr
	processDataFunc LoadData
	RunFunc         func() map[string]interface{}
	ErrorFunc       func() map[string]interface{}
}

// ServiceBuilder will help you to run steps
type ServiceBuilder struct {
	ServiceName         string
	steps               []Step
	businessLogicHolder *AbstractBusinessLogicHolder
}

// GetSB Gives you service builder from where you can run steps
func GetSB(name string, ab *AbstractBusinessLogicHolder) *ServiceBuilder {
	newsb := ServiceBuilder{}
	newsb.ServiceName = name
	newsb.businessLogicHolder = ab
	return &newsb
}

// AddStep will add func step with rule
// Stepname : Give Name to step. It will appear in log.
// Rule : Give Ybl rule
// blfunc : Give Business Logic function pointer
// errorfunc : Give Error  function pointer
func (sb *ServiceBuilder) AddStep(stepname, rule string, ld LoadData, blfunc, errorfunc func() map[string]interface{}) *ServiceBuilder {
	step := Step{}
	step.RawYQL = rule
Ajit Jagtap's avatar
Ajit Jagtap committed

	//Check rule in cache
	cachedRule, found := ruleCache[rule]
	if !found {
		step.expr = cachedRule
	} else {

		// Parse the condition language and get expression
		p := conditions.NewParser(strings.NewReader(rule))
		expr, err := p.Parse()
		if err != nil {
			step.expr = expr
		} else {
			loggermdl.LogError("Error in step expr", err)
		}
		ruleCache[rule] = expr
	}

	step.RunFunc = blfunc
	step.ErrorFunc = errorfunc
	step.Stepname = stepname
	step.processDataFunc = ld
	sb.steps = append(sb.steps, step)
	return sb
}

// Run all Steps one by one
func (sb *ServiceBuilder) Run() *ServiceBuilder {

	for _, step := range sb.steps {
		//Load Data
		if step.processDataFunc != nil {
			step.processDataFunc(sb.businessLogicHolder)
		}

		//Run step func
		tmp := step.RunFunc()
Ajit Jagtap's avatar
Ajit Jagtap committed
		// result, _ := yql.Match(step.RawYQL, tmp)
		result, _ := conditions.Evaluate(step.expr, tmp)
		if !result {
Ajit Jagtap's avatar
Ajit Jagtap committed
			// loggermdl.LogWarn(step.Stepname, "Failed", result)
			step.ErrorFunc()
			break
		}
	}
	return sb
}

// FinalOutput Step
func (sb *ServiceBuilder) FinalOutput(fn FinalStepProcessOutput) *interface{} {
	if fn == nil {
		return sb.businessLogicHolder.GetFinalData()
	}
	return fn(sb.businessLogicHolder)
}