github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/engine/function/funcs.go (about)

     1  package funcs
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"reflect"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"database/sql"
    13  
    14  	"github.com/mdaxf/iac/documents"
    15  	"github.com/mdaxf/iac/engine/types"
    16  	"github.com/mdaxf/iac/logger"
    17  	"github.com/mdaxf/iac-signalr/signalr"
    18  )
    19  
    20  type Funcs struct {
    21  	Fobj                 types.Function
    22  	DBTx                 *sql.Tx
    23  	Ctx                  context.Context
    24  	CtxCancel            context.CancelFunc
    25  	SystemSession        map[string]interface{} // {sessionanme: value}
    26  	UserSession          map[string]interface{} // {sessionanme: value}
    27  	Externalinputs       map[string]interface{} // {sessionanme: value}
    28  	Externaloutputs      map[string]interface{} // {sessionanme: value}
    29  	FuncCachedVariables  map[string]interface{}
    30  	iLog                 logger.Log
    31  	FunctionInputs       []map[string]interface{}
    32  	FunctionOutputs      []map[string]interface{}
    33  	ExecutionNumber      int
    34  	ExecutionCount       int
    35  	FunctionMappedInputs map[string]interface{}
    36  	DocDBCon             *documents.DocDB
    37  	SignalRClient        signalr.Client
    38  	ErrorMessage         string
    39  	TestwithSc           bool
    40  	TestResults          []map[string]interface{}
    41  }
    42  
    43  // NewFuncs creates a new instance of the Funcs struct.
    44  // It initializes the Funcs struct with the provided parameters and returns a pointer to the created instance.
    45  // The Funcs struct represents a collection of functions and their associated data for execution.
    46  // Parameters:
    47  // - DocDBCon: A pointer to the DocDB connection object.
    48  // - SignalRClient: The SignalR client object.
    49  // - dbTx: A pointer to the SQL transaction object.
    50  // - fobj: The function object.
    51  // - systemSession: A map containing system session data.
    52  // - userSession: A map containing user session data.
    53  // - externalinputs: A map containing external input data.
    54  // - externaloutputs: A map containing external output data.
    55  // - funcCachedVariables: A map containing cached variables for the function.
    56  // - ctx: The context object.
    57  // - ctxcancel: The cancel function for the context.
    58  // Returns:
    59  // - A pointer to the created Funcs instance.
    60  
    61  func NewFuncs(DocDBCon *documents.DocDB, SignalRClient signalr.Client, dbTx *sql.Tx, fobj types.Function, systemSession, userSession, externalinputs, externaloutputs, funcCachedVariables map[string]interface{}, ctx context.Context, ctxcancel context.CancelFunc) *Funcs {
    62  	log := logger.Log{}
    63  	log.ModuleName = logger.TranCode
    64  	log.ControllerName = "Function"
    65  	if systemSession["User"] != nil {
    66  		log.User = systemSession["User"].(string)
    67  	} else {
    68  		log.User = "System"
    69  	}
    70  	startTime := time.Now()
    71  	defer func() {
    72  		elapsed := time.Since(startTime)
    73  		log.PerformanceWithDuration("engine.funcs.NewFuncs", elapsed)
    74  	}()
    75  
    76  	var newdata []map[string]interface{}
    77  
    78  	systemSession["UTCTime"] = time.Now().UTC()
    79  	systemSession["LocalTime"] = time.Now()
    80  	if systemSession["UserNo"] == nil {
    81  		systemSession["UserNo"] = "System"
    82  	}
    83  	if systemSession["UserID"] == nil {
    84  		systemSession["UserID"] = 0
    85  	}
    86  
    87  	if systemSession["WorkSpace"] == nil {
    88  		systemSession["WorkSpace"] = ""
    89  	}
    90  
    91  	return &Funcs{
    92  		Fobj:                fobj,
    93  		DBTx:                dbTx,
    94  		Ctx:                 ctx,
    95  		CtxCancel:           ctxcancel,
    96  		SystemSession:       systemSession,
    97  		UserSession:         userSession,
    98  		Externalinputs:      externalinputs,
    99  		Externaloutputs:     externaloutputs,
   100  		FuncCachedVariables: funcCachedVariables,
   101  		iLog:                log,
   102  		FunctionInputs:      newdata,
   103  		FunctionOutputs:     newdata,
   104  		ExecutionNumber:     1,
   105  		ExecutionCount:      0,
   106  		DocDBCon:            DocDBCon,
   107  		SignalRClient:       SignalRClient,
   108  		ErrorMessage:        "",
   109  		TestwithSc:          false,
   110  		TestResults:         newdata,
   111  	}
   112  }
   113  
   114  // HandleInputs handles the inputs for the Funcs struct.
   115  // It retrieves the inputs from various sources such as system session, user session, pre-function, and external inputs.
   116  // The retrieved inputs are then converted to the appropriate data types and stored in the newinputs map.
   117  // Finally, it returns the list of input names, input values, and the newinputs map.
   118  // Returns:
   119  // - A list of input names.
   120  // - A list of input values.
   121  // - A map containing the new inputs.
   122  // - An error if there was an error in the process.
   123  
   124  func (f *Funcs) HandleInputs() ([]string, []string, map[string]interface{}, error) {
   125  	/*	startTime := time.Now()
   126  		defer func() {
   127  			elapsed := time.Since(startTime)
   128  			f.iLog.PerformanceWithDuration("engine.funcs.HandleInputs", elapsed)
   129  		}()
   130  	*/defer func() {
   131  		if err := recover(); err != nil {
   132  			f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.HandleInputs with error: %s", err))
   133  			f.CancelExecution(fmt.Sprintf("There is error to engine.funcs.HandleInputs with error: %s", err))
   134  			return
   135  		}
   136  	}()
   137  
   138  	f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.HandleInputs).Kind().String()))
   139  
   140  	f.iLog.Debug(fmt.Sprintf("function inputs: %s", logger.ConvertJson(f.Fobj.Inputs)))
   141  
   142  	newinputs := make(map[string]interface{})
   143  	namelist := make([]string, len(f.Fobj.Inputs))
   144  	valuelist := make([]string, len(f.Fobj.Inputs))
   145  
   146  	inputs := f.Fobj.Inputs
   147  	//	newinputs = f.FunctionMappedInputs
   148  
   149  	for i, _ := range inputs {
   150  		//	f.iLog.Debug(fmt.Sprintf("function input: %s, Source: %s", logger.ConvertJson(inputs[i]), inputs[i].Source))
   151  		switch inputs[i].Source {
   152  		case types.Fromsyssession:
   153  
   154  			if f.SystemSession[inputs[i].Aliasname] != nil {
   155  				inputs[i].Value = f.SystemSession[inputs[i].Aliasname].(string)
   156  			} else {
   157  
   158  				f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s SystemSession[%s]", "System Session not found", inputs[i].Aliasname))
   159  				//	f.DBTx.Rollback()
   160  			}
   161  		case types.Fromusersession:
   162  			if f.UserSession[inputs[i].Aliasname] != nil {
   163  				inputs[i].Value = f.UserSession[inputs[i].Aliasname].(string)
   164  			} else {
   165  				f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s UserSession[%s]", "User Session not found", inputs[i].Aliasname))
   166  				//	f.DBTx.Rollback()
   167  			}
   168  		case types.Prefunction:
   169  			arr := strings.Split(inputs[i].Aliasname, ".")
   170  			f.iLog.Debug(fmt.Sprintf("Prefunction: %s", logger.ConvertJson(arr)))
   171  			if len(arr) == 2 {
   172  				f.iLog.Debug(fmt.Sprintf("Prefunction variables: %s", logger.ConvertJson(f.FuncCachedVariables)))
   173  				if f.FuncCachedVariables[arr[0]] != nil {
   174  					value, _ := f.checkinputvalue(arr[1], f.FuncCachedVariables[arr[0]].(map[string]interface{}))
   175  					inputs[i].Value = value
   176  				} else {
   177  					f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s Prefunction[%s]", "Prefunction not found", inputs[i].Aliasname))
   178  					//	f.DBTx.Rollback()
   179  					if inputs[i].Datatype == types.DateTime {
   180  						if inputs[i].Defaultvalue == "" {
   181  							inputs[i].Value = time.Now().Format(types.DateTimeFormat)
   182  						} else {
   183  							inputs[i].Value = inputs[i].Defaultvalue
   184  						}
   185  
   186  					} else if inputs[i].Datatype == types.Integer {
   187  						if inputs[i].Defaultvalue == "" {
   188  							inputs[i].Value = "0"
   189  						} else {
   190  							inputs[i].Value = inputs[i].Defaultvalue
   191  						}
   192  					} else if inputs[i].Datatype == types.Float {
   193  						if inputs[i].Defaultvalue == "" {
   194  							inputs[i].Value = "0.0"
   195  						} else {
   196  							inputs[i].Value = inputs[i].Defaultvalue
   197  						}
   198  
   199  					} else if inputs[i].Datatype == types.Bool {
   200  						if inputs[i].Defaultvalue == "" {
   201  							inputs[i].Value = "false"
   202  						} else {
   203  							inputs[i].Value = inputs[i].Defaultvalue
   204  						}
   205  
   206  					} else {
   207  
   208  						inputs[i].Value = inputs[i].Defaultvalue
   209  					}
   210  				}
   211  			} else {
   212  				f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s Prefunction[%s]", "Prefunction not found", inputs[i].Aliasname))
   213  				//	f.DBTx.Rollback()
   214  				if inputs[i].Datatype == types.DateTime {
   215  					if inputs[i].Defaultvalue == "" {
   216  						inputs[i].Value = time.Now().Format(types.DateTimeFormat)
   217  					} else {
   218  						inputs[i].Value = inputs[i].Defaultvalue
   219  					}
   220  
   221  				} else if inputs[i].Datatype == types.Integer {
   222  					if inputs[i].Defaultvalue == "" {
   223  						inputs[i].Value = "0"
   224  					} else {
   225  						inputs[i].Value = inputs[i].Defaultvalue
   226  					}
   227  				} else if inputs[i].Datatype == types.Float {
   228  					if inputs[i].Defaultvalue == "" {
   229  						inputs[i].Value = "0.0"
   230  					} else {
   231  						inputs[i].Value = inputs[i].Defaultvalue
   232  					}
   233  
   234  				} else if inputs[i].Datatype == types.Bool {
   235  					if inputs[i].Defaultvalue == "" {
   236  						inputs[i].Value = "false"
   237  					} else {
   238  						inputs[i].Value = inputs[i].Defaultvalue
   239  					}
   240  
   241  				} else {
   242  
   243  					inputs[i].Value = inputs[i].Defaultvalue
   244  				}
   245  			}
   246  
   247  		case types.Fromexternal:
   248  			f.iLog.Debug(fmt.Sprintf("Externalinputs: %s", logger.ConvertJson(f.Externalinputs)))
   249  			value, _ := f.checkinputvalue(inputs[i].Aliasname, f.Externalinputs)
   250  			inputs[i].Value = value
   251  
   252  		}
   253  
   254  		f.iLog.Debug(fmt.Sprintf("function input: %s, Source: %v, value: %s type: %d", logger.ConvertJson(inputs[i]), inputs[i].Source, inputs[i].Value, inputs[i].Datatype))
   255  		switch inputs[i].Datatype {
   256  
   257  		case types.Integer:
   258  
   259  			if inputs[i].List == false {
   260  
   261  				temp := f.ConverttoInt(inputs[i].Value)
   262  				newinputs[inputs[i].Name] = temp
   263  
   264  			}
   265  			if inputs[i].List == true {
   266  
   267  				f.iLog.Debug(fmt.Sprintf("check value %s if it isArray: %s", inputs[i].Value, reflect.ValueOf(inputs[i].Value).Kind().String()))
   268  
   269  				var tempstr []string
   270  				err := json.Unmarshal([]byte(inputs[i].Value), &tempstr)
   271  				f.iLog.Debug(fmt.Sprintf("Unmarshal %s result: %s length:%d", inputs[i].Value, logger.ConvertJson(tempstr), len(tempstr)))
   272  
   273  				if err != nil {
   274  					//f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   275  
   276  					var tempint []int
   277  					err := json.Unmarshal([]byte(inputs[i].Value), &tempint)
   278  					if err != nil {
   279  						//f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   280  
   281  						var tempfloat []float64
   282  						err := json.Unmarshal([]byte(inputs[i].Value), &tempfloat)
   283  						if err != nil {
   284  							//f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   285  							//	f.DBTx.Rollback()
   286  
   287  							str := inputs[i].Value
   288  							str = strings.TrimPrefix(str, "[")
   289  							str = strings.TrimSuffix(str, "]")
   290  							strList := strings.Split(str, ",")
   291  
   292  							intList := make([]int, len(strList))
   293  							for index, str := range strList {
   294  								intList[index] = f.ConverttoInt(str)
   295  							}
   296  							newinputs[inputs[i].Name] = intList
   297  
   298  						} else {
   299  							temp := make([]int, 0)
   300  							for _, str := range tempfloat {
   301  								temp = append(temp, int(str))
   302  							}
   303  							newinputs[inputs[i].Name] = temp
   304  						}
   305  
   306  					} else {
   307  						newinputs[inputs[i].Name] = tempint
   308  					}
   309  				} else {
   310  					temp := make([]int, 0)
   311  					for _, str := range tempstr {
   312  						temp = append(temp, f.ConverttoInt(str))
   313  					}
   314  					newinputs[inputs[i].Name] = temp
   315  
   316  				}
   317  				/*
   318  					if isArray(inputs[i].Value) {
   319  
   320  
   321  
   322  					} else {
   323  						temp := make([]int, 0)
   324  						temp = append(temp, f.ConverttoInt(inputs[i].Value))
   325  						newinputs[inputs[i].Name] = temp
   326  					} */
   327  
   328  			}
   329  		case types.Float:
   330  			if inputs[i].List == false {
   331  
   332  				temp := f.ConverttoFloat(inputs[i].Value)
   333  				newinputs[inputs[i].Name] = temp
   334  
   335  			}
   336  			if inputs[i].List == true {
   337  
   338  				var temp []float64
   339  				err := json.Unmarshal([]byte(inputs[i].Value), &temp)
   340  				if err != nil {
   341  					f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   342  					//	f.DBTx.Rollback()
   343  				}
   344  				newinputs[inputs[i].Name] = temp
   345  
   346  			}
   347  		case types.Bool:
   348  			if inputs[i].List == false {
   349  				temp := f.ConverttoBool(inputs[i].Value)
   350  				newinputs[inputs[i].Name] = temp
   351  			}
   352  			if inputs[i].List == true {
   353  
   354  				var temp []bool
   355  				err := json.Unmarshal([]byte(inputs[i].Value), &temp)
   356  				if err != nil {
   357  					f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   358  					//	f.DBTx.Rollback()
   359  				}
   360  				newinputs[inputs[i].Name] = temp
   361  
   362  			}
   363  		case types.DateTime:
   364  			if inputs[i].List == false {
   365  
   366  				temp := f.ConverttoDateTime(inputs[i].Value)
   367  				newinputs[inputs[i].Name] = temp
   368  
   369  			}
   370  			if inputs[i].List == true {
   371  
   372  				var temp []time.Time
   373  				var datetimeStrings []string
   374  				err := json.Unmarshal([]byte(inputs[i].Value), &datetimeStrings)
   375  				if err != nil {
   376  					f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   377  					//	f.DBTx.Rollback()
   378  				}
   379  				for _, dtStr := range datetimeStrings {
   380  					dt, err := time.Parse("2006-01-02 15:04:05", dtStr)
   381  					if err != nil {
   382  						f.iLog.Error(fmt.Sprintf("Parse %s error: %s", dtStr, err.Error()))
   383  						//	f.DBTx.Rollback()
   384  					}
   385  					temp = append(temp, dt)
   386  				}
   387  
   388  				newinputs[inputs[i].Name] = temp
   389  
   390  			}
   391  		default:
   392  			if inputs[i].List == false {
   393  				newinputs[inputs[i].Name] = inputs[i].Value
   394  
   395  			}
   396  			if inputs[i].List == true {
   397  
   398  				var temp []string
   399  				err := json.Unmarshal([]byte(inputs[i].Value), &temp)
   400  				if err != nil {
   401  					f.iLog.Error(fmt.Sprintf("Unmarshal %s error: %s", inputs[i].Value, err.Error()))
   402  					//	f.DBTx.Rollback()
   403  				}
   404  
   405  				newinputs[inputs[i].Name] = temp
   406  
   407  			}
   408  		}
   409  		namelist[i] = inputs[i].Name
   410  		valuelist[i] = inputs[i].Value
   411  	}
   412  
   413  	f.FunctionMappedInputs = newinputs
   414  
   415  	return namelist, valuelist, newinputs, nil
   416  }
   417  
   418  // SetInputs sets the inputs for the Funcs object.
   419  // It handles the mapping of inputs and prepares them for execution.
   420  // It returns the list of input names, the list of input values, and a map of new inputs.
   421  
   422  func (f *Funcs) SetInputs() ([]string, []string, map[string]interface{}) {
   423  	/*	startTime := time.Now()
   424  		defer func() {
   425  			elapsed := time.Since(startTime)
   426  			f.iLog.PerformanceWithDuration("engine.funcs.SetInputs", elapsed)
   427  		}()
   428  	*/defer func() {
   429  		if err := recover(); err != nil {
   430  			f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetInputs with error: %s", err))
   431  			f.CancelExecution(fmt.Sprintf("There is error to engine.funcs.HandleInputs with error: %s", err))
   432  			return
   433  		}
   434  	}()
   435  
   436  	f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.SetInputs).Kind().String()))
   437  
   438  	namelist, valuelist, newinputs, err := f.HandleInputs()
   439  
   440  	if err != nil {
   441  		f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s", err.Error()))
   442  	}
   443  	inputs := f.Fobj.Inputs
   444  
   445  	if f.ExecutionNumber > 1 {
   446  		f.iLog.Debug(fmt.Sprintf("function inputs: %s execution count: %d/%d", logger.ConvertJson(inputs), f.ExecutionCount, f.ExecutionNumber))
   447  
   448  		f.iLog.Debug(fmt.Sprintf("function mapped inputs: %s", logger.ConvertJson(f.FunctionMappedInputs)))
   449  		for i := 0; i < len(inputs); i++ {
   450  
   451  			//	newinputs[inputs[i].Name] = inputs[i].Value
   452  			namelist[i] = inputs[i].Name
   453  			f.iLog.Debug(fmt.Sprintf("function input: %s, Source: %d", logger.ConvertJson(inputs[i]), inputs[i].Source))
   454  			if f.ExecutionNumber > 1 && inputs[i].Repeat && inputs[i].List {
   455  
   456  				//valuelist[i] = (f.FunctionMappedInputs[inputs[i].Name]).([]interface{})[f.ExecutionCount].(string)
   457  				if inputs[i].Datatype == types.DateTime {
   458  					temp := (f.FunctionMappedInputs[inputs[i].Name]).([]time.Time)[f.ExecutionCount]
   459  					newinputs[inputs[i].Name] = temp.Format("2006-01-02 15:04:05")
   460  					valuelist[i] = temp.Format("2006-01-02 15:04:05")
   461  				} else if inputs[i].Datatype == types.Integer {
   462  					temp := (f.FunctionMappedInputs[inputs[i].Name]).([]int)[f.ExecutionCount]
   463  					newinputs[inputs[i].Name] = strconv.Itoa(temp)
   464  					valuelist[i] = strconv.Itoa(temp)
   465  				} else if inputs[i].Datatype == types.Float {
   466  					temp := (f.FunctionMappedInputs[inputs[i].Name]).([]float64)[f.ExecutionCount]
   467  					newinputs[inputs[i].Name] = strconv.FormatFloat(temp, 'f', -1, 64)
   468  					valuelist[i] = strconv.FormatFloat(temp, 'f', -1, 64)
   469  				} else if inputs[i].Datatype == types.Bool {
   470  					temp := (f.FunctionMappedInputs[inputs[i].Name]).([]bool)[f.ExecutionCount]
   471  					newinputs[inputs[i].Name] = strconv.FormatBool(temp)
   472  					valuelist[i] = strconv.FormatBool(temp)
   473  				} else {
   474  					valuelist[i] = (f.FunctionMappedInputs[inputs[i].Name]).([]string)[f.ExecutionCount]
   475  					newinputs[inputs[i].Name] = (f.FunctionMappedInputs[inputs[i].Name]).([]string)[f.ExecutionCount]
   476  				}
   477  
   478  			} else {
   479  				newinputs[inputs[i].Name] = f.FunctionMappedInputs[inputs[i].Name]
   480  				valuelist[i] = inputs[i].Value
   481  			}
   482  
   483  			//inputs[i].Value
   484  		}
   485  
   486  		f.iLog.Debug(fmt.Sprintf("function mapped inputs: %s for execution: %d/%d", logger.ConvertJson(newinputs), f.ExecutionCount, f.ExecutionNumber))
   487  	}
   488  	//f.Fobj.Inputs = inputs
   489  
   490  	return namelist, valuelist, newinputs
   491  }
   492  
   493  // isArray checks if the given value is an array or a slice.
   494  // It uses reflection to determine the kind of the value.
   495  // Returns true if the value is an array or a slice, false otherwise.
   496  func isArray(value interface{}) bool {
   497  	// Use reflection to check if the value's kind is an array
   498  
   499  	val := reflect.ValueOf(value)
   500  	return val.Kind() == reflect.Array || val.Kind() == reflect.Slice
   501  }
   502  
   503  // checkifRepeatExecution checks if the function should be repeated execution based on the inputs.
   504  // It returns the count of repetitions and an error if any.
   505  // Returns:
   506  // - The count of repetitions.
   507  // - An error if there was an error in the process.
   508  
   509  func (f *Funcs) checkifRepeatExecution() (int, error) {
   510  	/*	startTime := time.Now()
   511  		defer func() {
   512  			elapsed := time.Since(startTime)
   513  			f.iLog.PerformanceWithDuration("engine.funcs.checkifRepeatExecution", elapsed)
   514  		}()
   515  		defer func() {
   516  			if err := recover(); err != nil {
   517  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.checkifRepeatExecution with error: %s", err))
   518  				return
   519  			}
   520  		}()
   521  	*/
   522  	inputs := f.Fobj.Inputs
   523  	lastcount := -2
   524  
   525  	_, _, newinputs, err := f.HandleInputs()
   526  
   527  	if err != nil {
   528  		f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s", err.Error()))
   529  	}
   530  
   531  	f.Fobj.Inputs = inputs
   532  	f.iLog.Debug(fmt.Sprintf("parse inputs result: %s", logger.ConvertJson(newinputs)))
   533  	for _, input := range inputs {
   534  
   535  		f.iLog.Debug(fmt.Sprintf("checkifRepeatExecution input: %s", logger.ConvertJson(input)))
   536  
   537  		count := -1
   538  		if input.Repeat && input.List {
   539  			inputvalue := newinputs[input.Name]
   540  			if isArray(inputvalue) {
   541  				if input.Datatype == types.DateTime {
   542  					count = len(inputvalue.([]time.Time))
   543  				} else if input.Datatype == types.Integer {
   544  					count = len(inputvalue.([]int))
   545  				} else if input.Datatype == types.Float {
   546  					count = len(inputvalue.([]float64))
   547  				} else if input.Datatype == types.Bool {
   548  					count = len(inputvalue.([]bool))
   549  				} else {
   550  					count = len(inputvalue.([]string))
   551  				}
   552  
   553  			} else {
   554  				count = 1
   555  			}
   556  			f.iLog.Debug(fmt.Sprintf("checkifRepeatExecution input.Value: %s, count: %d, lastcount %d", input.Value, count, lastcount))
   557  			if lastcount == -2 {
   558  				lastcount = count
   559  			} else if lastcount != count {
   560  				return -1, nil
   561  			}
   562  
   563  		}
   564  	}
   565  
   566  	if lastcount > 0 {
   567  		return lastcount, nil
   568  	} else {
   569  		return 1, nil
   570  	}
   571  }
   572  
   573  // checkinputvalue is a function that checks the input value for a given alias name and variables.
   574  // It returns the result as a string and an error if any.
   575  // Parameters:
   576  // - Aliasname: The alias name of the input.
   577  // - variables: A map containing the variables.
   578  // Returns:
   579  // - The result as a string.
   580  // - An error if there was an error in the process.
   581  func (f *Funcs) checkinputvalue(Aliasname string, variables map[string]interface{}) (string, error) {
   582  	/*	startTime := time.Now()
   583  		defer func() {
   584  			elapsed := time.Since(startTime)
   585  			f.iLog.PerformanceWithDuration("engine.funcs.checkinputvalue", elapsed)
   586  		}()
   587  		defer func() {
   588  			if err := recover(); err != nil {
   589  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.checkinputvalue with error: %s", err))
   590  				return
   591  			}
   592  		}()  */
   593  
   594  	var err error
   595  	err = nil
   596  	var Result string
   597  	if variables[Aliasname] != nil {
   598  		if resultMap, ok := variables[Aliasname].([]interface{}); ok {
   599  			Result = "["
   600  			for index, value := range resultMap {
   601  				_value, err := json.Marshal(value)
   602  				if err != nil {
   603  					f.iLog.Error(fmt.Sprintf("Marshal %s error: %s", Aliasname, err.Error()))
   604  					//	f.DBTx.Rollback()
   605  				}
   606  
   607  				if index == 0 {
   608  					Result += string(_value)
   609  				} else {
   610  					Result = Result + "," + string(_value)
   611  				}
   612  			}
   613  			Result += "]"
   614  		} else if resultMap, ok := variables[Aliasname].(map[string]interface{}); ok {
   615  			value, err := json.Marshal(resultMap)
   616  			if err != nil {
   617  				f.iLog.Error(fmt.Sprintf("Marshal %s error: %s", Aliasname, err.Error()))
   618  				//	f.DBTx.Rollback()
   619  			} else {
   620  				Result = string(value)
   621  			}
   622  
   623  			Result = string(value)
   624  		} else if resultMap, ok := variables[Aliasname].([]string); ok {
   625  			Result = ""
   626  			for index, value := range resultMap {
   627  				if index == 0 {
   628  					Result = value
   629  				} else {
   630  					Result = Result + "," + value
   631  				}
   632  			}
   633  		} else {
   634  
   635  			/*temp, err := json.Marshal(variables[Aliasname])
   636  			if err != nil {
   637  				f.iLog.Error(fmt.Sprintf("Marshal %s error: %s", Aliasname, err.Error()))
   638  			}
   639  			f.iLog.Debug(fmt.Sprintf("checkinputvalue %s temp: %s", variables[Aliasname], temp))  */
   640  			switch variables[Aliasname].(type) {
   641  			case int:
   642  				if variables[Aliasname] == "" {
   643  					Result = strconv.Itoa(0)
   644  				} else {
   645  					Result = strconv.Itoa(variables[Aliasname].(int))
   646  				}
   647  			case int64:
   648  				if variables[Aliasname] == "" {
   649  					Result = strconv.Itoa(0)
   650  				} else {
   651  					value := int(variables[Aliasname].(int64))
   652  					Result = strconv.Itoa(value)
   653  				}
   654  			case float64:
   655  				if variables[Aliasname] == "" {
   656  					Result = strconv.FormatFloat(0.0, 'f', -1, 64)
   657  				} else {
   658  					Result = strconv.FormatFloat(variables[Aliasname].(float64), 'f', -1, 64)
   659  				}
   660  			case bool:
   661  				if variables[Aliasname] == "" {
   662  					Result = strconv.FormatBool(false)
   663  				} else {
   664  					Result = strconv.FormatBool(variables[Aliasname].(bool))
   665  				}
   666  			case string:
   667  				Result = variables[Aliasname].(string)
   668  			case time.Time:
   669  				Result = variables[Aliasname].(time.Time).Format(types.DateTimeFormat)
   670  			case nil:
   671  				Result = ""
   672  			default:
   673  				Result = fmt.Sprint(variables[Aliasname])
   674  
   675  			}
   676  			Result = string(Result)
   677  		}
   678  	} else {
   679  		f.iLog.Error(fmt.Sprintf("Error in SetInputs: %s Externalinputs[%s]", "Externalinputs not found", Aliasname))
   680  		//	f.DBTx.Rollback()
   681  
   682  	}
   683  
   684  	f.iLog.Debug(fmt.Sprintf("checkinputvalue %s result: %s", variables[Aliasname], Result))
   685  	return Result, err
   686  }
   687  
   688  // customMarshal is a function that takes an interface{} as input and returns a string representation of the input object in JSON format.
   689  // The function uses reflection to iterate over the fields of the input object and constructs a JSON string by concatenating the field names and values.
   690  // The field names are obtained from the "json" tag of the struct fields.
   691  // If the input object is not a struct, the function returns an empty string.
   692  // Parameters:
   693  // - v: The input object.
   694  // Returns:
   695  // - A string representation of the input object in JSON format.
   696  
   697  func customMarshal(v interface{}) string {
   698  
   699  	var jsonStr string
   700  	switch reflect.TypeOf(v).Kind() {
   701  	case reflect.Struct:
   702  		t := reflect.TypeOf(v)
   703  		v := reflect.ValueOf(v)
   704  		jsonStr += "{"
   705  		for i := 0; i < t.NumField(); i++ {
   706  			fieldName := t.Field(i).Tag.Get("json")
   707  			fieldValue := fmt.Sprintf("%v", v.Field(i))
   708  			jsonStr += fmt.Sprintf(`%s:%s,`, fieldName, fieldValue)
   709  		}
   710  		jsonStr = jsonStr[:len(jsonStr)-1] // Remove trailing comma
   711  		jsonStr += "}"
   712  	}
   713  	return jsonStr
   714  }
   715  
   716  // ConverttoInt converts a string to an integer.
   717  // It measures the performance of the conversion and logs any errors that occur.
   718  // If an error occurs during the conversion, it returns 0.
   719  // Parameters:
   720  // - str: The string to be converted.
   721  // Returns:
   722  // - The converted integer value.
   723  
   724  func (f *Funcs) ConverttoInt(str string) int {
   725  	/*	startTime := time.Now()
   726  		defer func() {
   727  			elapsed := time.Since(startTime)
   728  			f.iLog.PerformanceWithDuration("engine.funcs.ConverttoInt", elapsed)
   729  		}()
   730  		defer func() {
   731  			if err := recover(); err != nil {
   732  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoInt with error: %s", err))
   733  				return
   734  			}
   735  		}()
   736  	*/
   737  	temp, err := strconv.Atoi(str)
   738  	if err != nil {
   739  		f.iLog.Error(fmt.Sprintf("Convert %s to int error: %s", str, err.Error()))
   740  	}
   741  
   742  	return temp
   743  }
   744  
   745  // ConverttoFloat converts a string to a float64 value.
   746  // It uses the strconv.ParseFloat function to perform the conversion.
   747  // If the conversion fails, an error is logged and the function returns 0.
   748  // The performance of this function is logged using the provided iLog instance.
   749  // Parameters:
   750  // - str: The string to be converted.
   751  // Returns:
   752  // - The converted float64 value.
   753  
   754  func (f *Funcs) ConverttoFloat(str string) float64 {
   755  	/*	startTime := time.Now()
   756  		defer func() {
   757  			elapsed := time.Since(startTime)
   758  			f.iLog.PerformanceWithDuration("engine.funcs.ConverttoFloat", elapsed)
   759  		}()
   760  		defer func() {
   761  			if err := recover(); err != nil {
   762  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoFloat with error: %s", err))
   763  				return
   764  			}
   765  		}()
   766  	*/
   767  	temp, err := strconv.ParseFloat(str, 64)
   768  	if err != nil {
   769  		f.iLog.Error(fmt.Sprintf("Convert %s to float error: %s", str, err.Error()))
   770  	}
   771  
   772  	return temp
   773  }
   774  
   775  // ConverttoBool converts a string to a boolean value.
   776  // It uses the strconv.ParseBool function to parse the string.
   777  // If the string cannot be parsed, an error is logged and false is returned.
   778  // The performance of this function is logged using the iLog.PerformanceWithDuration method.
   779  // If a panic occurs during the execution of this function, the panic is recovered and logged as an error.
   780  // Parameters:
   781  // - str: The string to be converted to a boolean value.
   782  // Returns:
   783  // - bool: The boolean value parsed from the string.
   784  
   785  func (f *Funcs) ConverttoBool(str string) bool {
   786  	/*	startTime := time.Now()
   787  		defer func() {
   788  			elapsed := time.Since(startTime)
   789  			f.iLog.PerformanceWithDuration("engine.funcs.ConverttoBool", elapsed)
   790  		}()
   791  		defer func() {
   792  			if err := recover(); err != nil {
   793  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoBool with error: %s", err))
   794  				return
   795  			}
   796  		}()
   797  	*/
   798  	temp, err := strconv.ParseBool(str)
   799  	if err != nil {
   800  		f.iLog.Error(fmt.Sprintf("Convert %s to bool error: %s", str, err.Error()))
   801  	}
   802  
   803  	return temp
   804  }
   805  
   806  // ConverttoDateTime converts a string to a time.Time value.
   807  // It uses the specified DateTimeFormat to parse the string.
   808  // If the string cannot be parsed, an error is logged and the zero time value is returned.
   809  // The function also logs the performance duration of the conversion.
   810  // If a panic occurs during the execution of this function, the panic is recovered and logged as an error.
   811  // Parameters:
   812  // - str: The string to be converted to a time.Time value.
   813  // Returns:
   814  // - time.Time: The time.Time value parsed from the string.
   815  
   816  func (f *Funcs) ConverttoDateTime(str string) time.Time {
   817  	/*	startTime := time.Now()
   818  		defer func() {
   819  			elapsed := time.Since(startTime)
   820  			f.iLog.PerformanceWithDuration("engine.funcs.ConverttoDatTime", elapsed)
   821  		}()
   822  		defer func() {
   823  			if err := recover(); err != nil {
   824  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConverttoDateTime with error: %s", err))
   825  				return
   826  			}
   827  		}()
   828  	*/
   829  	temp, err := time.Parse(types.DateTimeFormat, str)
   830  	if err != nil {
   831  		f.iLog.Error(fmt.Sprintf("Convert %s to time error: %s", str, err.Error()))
   832  	}
   833  
   834  	return temp
   835  }
   836  
   837  // SetOutputs sets the outputs of the function.
   838  // It takes a map of string keys and interface{} values representing the outputs.
   839  // The function logs the performance duration and any errors that occur during execution.
   840  // It also appends the outputs to the FunctionOutputs slice.
   841  // Parameters:
   842  // - outputs: A map of string keys and interface{} values representing the outputs.
   843  
   844  func (f *Funcs) SetOutputs(outputs map[string]interface{}) {
   845  	/*	startTime := time.Now()
   846  		defer func() {
   847  			elapsed := time.Since(startTime)
   848  			f.iLog.PerformanceWithDuration("engine.funcs.SetOutputs", elapsed)
   849  		}()
   850  		defer func() {
   851  			if err := recover(); err != nil {
   852  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetOutputs with error: %s", err))
   853  				return
   854  			}
   855  		}()
   856  	*/
   857  	f.iLog.Debug(fmt.Sprintf("function's ouputs: %s", logger.ConvertJson(outputs)))
   858  
   859  	f.FunctionOutputs = append(f.FunctionOutputs, outputs)
   860  
   861  }
   862  
   863  // SetfuncOutputs sets the function outputs for the Funcs struct.
   864  // It combines the outputs from multiple function executions into a single output map.
   865  // If the execution number is greater than 1, it iterates over the function outputs and combines them.
   866  // Otherwise, it sets the single function output.
   867  // The function also measures the performance duration and logs any errors that occur during execution.
   868  // If a panic occurs during the execution of this function, the panic is recovered and logged as an error.
   869  // Parameters:
   870  // - outputs: A map of string keys and interface{} values representing the outputs.
   871  
   872  func (f *Funcs) SetfuncOutputs() {
   873  	/*	startTime := time.Now()
   874  		defer func() {
   875  			elapsed := time.Since(startTime)
   876  			f.iLog.PerformanceWithDuration("engine.funcs.SetfuncOutputs", elapsed)
   877  		}()
   878  		defer func() {
   879  			if err := recover(); err != nil {
   880  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetfuncOutputs with error: %s", err))
   881  				return
   882  			}
   883  		}()
   884  	*/
   885  	newoutputs := make(map[string]interface{})
   886  	if f.ExecutionNumber > 1 {
   887  		for index, outputs := range f.FunctionOutputs {
   888  			for key, value := range outputs {
   889  				if newoutputs[key] == nil {
   890  					newoutputs[key] = make([]interface{}, f.ExecutionNumber)
   891  				}
   892  				newoutputs[key].([]interface{})[index] = value
   893  			}
   894  		}
   895  
   896  		f.SetfuncSingleOutputs(newoutputs)
   897  	} else {
   898  		f.SetfuncSingleOutputs(f.FunctionOutputs[0])
   899  	}
   900  
   901  }
   902  
   903  // SetfuncSingleOutputs sets the single outputs of the Funcs object based on the provided map of outputs.
   904  // It iterates through the outputs of the Funcs object and assigns the corresponding values from the map to the appropriate destinations.
   905  // The UserSession, Externaloutputs, and FuncCachedVariables are updated accordingly.
   906  // If an error occurs during the process, it is recovered and logged.
   907  // The performance duration of the function is also logged.
   908  // Parameters:
   909  // - outputs: A map of string keys and interface{} values representing the outputs.
   910  // Returns:
   911  // - An error if there was an error in the process.
   912  func (f *Funcs) SetfuncSingleOutputs(outputs map[string]interface{}) {
   913  	/*	startTime := time.Now()
   914  		defer func() {
   915  			elapsed := time.Since(startTime)
   916  			f.iLog.PerformanceWithDuration("engine.funcs.SetfuncSingleOutputs", elapsed)
   917  		}()
   918  		defer func() {
   919  			if err := recover(); err != nil {
   920  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.SetfuncSingleOutputs with error: %s", err))
   921  				return
   922  			}
   923  		}()
   924  	*/
   925  	for i := 0; i < len(f.Fobj.Outputs); i++ {
   926  		if outputs[f.Fobj.Outputs[i].Name] == nil {
   927  			continue
   928  		}
   929  
   930  		for j := 0; j < len(f.Fobj.Outputs[i].Outputdest); j++ {
   931  
   932  			switch f.Fobj.Outputs[i].Outputdest[j] {
   933  			case types.Tosession:
   934  				f.UserSession[f.Fobj.Outputs[i].Aliasname[j]] = outputs[f.Fobj.Outputs[i].Name]
   935  
   936  			case types.Toexternal:
   937  				f.Externaloutputs[f.Fobj.Outputs[i].Aliasname[j]] = outputs[f.Fobj.Outputs[i].Name]
   938  
   939  			}
   940  		}
   941  
   942  		f.FuncCachedVariables[f.Fobj.Name] = outputs
   943  	}
   944  	f.iLog.Debug(fmt.Sprintf("UserSession after function: %s", logger.ConvertJson(f.UserSession)))
   945  	f.iLog.Debug(fmt.Sprintf("Externaloutputs after function: %s", logger.ConvertJson(f.Externaloutputs)))
   946  	f.iLog.Debug(fmt.Sprintf("FuncCachedVariables after function: %s", logger.ConvertJson(f.FuncCachedVariables[f.Fobj.Name])))
   947  
   948  }
   949  
   950  // ConvertfromBytes converts a byte buffer into a map[string]interface{}.
   951  // It takes a byte buffer as input and returns a map containing the converted data.
   952  // The function also logs the performance duration and handles any panics that occur during execution.
   953  // If there is an error during the JSON unmarshaling process, it is logged as well.
   954  
   955  func (f *Funcs) ConvertfromBytes(bytesbuffer []byte) map[string]interface{} {
   956  	/*	startTime := time.Now()
   957  		defer func() {
   958  			elapsed := time.Since(startTime)
   959  			f.iLog.PerformanceWithDuration("engine.funcs.ConvertfromBytes", elapsed)
   960  		}()
   961  		defer func() {
   962  			if err := recover(); err != nil {
   963  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.ConvertfromBytes with error: %s", err))
   964  				return
   965  			}
   966  		}()
   967  	*/
   968  	f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.ConvertfromBytes).Kind().String()))
   969  
   970  	temobj := make(map[string]interface{})
   971  	for i := 0; i < len(f.Fobj.Outputs); i++ {
   972  		temobj[f.Fobj.Outputs[i].Name] = f.Fobj.Outputs[i].Defaultvalue
   973  	}
   974  
   975  	err := json.Unmarshal(bytesbuffer, &temobj)
   976  	if err != nil {
   977  		f.iLog.Error(fmt.Sprintf("error: %v", err.Error()))
   978  	}
   979  	return temobj
   980  }
   981  
   982  // Execute executes the function.
   983  // It measures the execution time, handles panics, and executes the appropriate function based on the function type.
   984  // It also sets the function outputs and updates the execution count.
   985  func (f *Funcs) Execute() {
   986  	startTime := time.Now()
   987  	defer func() {
   988  		elapsed := time.Since(startTime)
   989  		f.iLog.PerformanceWithDuration("engine.funcs.Execute", elapsed)
   990  	}()
   991  
   992  	defer func() {
   993  		if r := recover(); r != nil {
   994  			f.iLog.Error(fmt.Sprintf("Panic in Execute: %s", r))
   995  			f.CancelExecution(fmt.Sprintf("Panic in Execute: %s", r))
   996  			f.ErrorMessage = fmt.Sprintf("Panic in Execute: %s", r)
   997  			return
   998  		}
   999  	}()
  1000  
  1001  	f.iLog.Debug(fmt.Sprintf("Execute function: %s", f.Fobj.Name))
  1002  	//f.iLog.Debug(fmt.Sprintf("Start process %s", reflect.ValueOf(f.Execute).Kind().String()))
  1003  	number, err := f.checkifRepeatExecution()
  1004  
  1005  	if err != nil {
  1006  		f.iLog.Error(fmt.Sprintf("Error in Execute: %s", err.Error()))
  1007  	}
  1008  	if number < 1 {
  1009  		f.iLog.Debug(fmt.Sprintf("No repeat execution"))
  1010  		outputs := make(map[string]interface{})
  1011  		f.SetOutputs(outputs)
  1012  		return
  1013  	}
  1014  	f.iLog.Debug(fmt.Sprintf("Execute the function: %s, inputs: %s mapped inputs: %s", f.Fobj.Name, logger.ConvertJson(f.Fobj.Inputs), logger.ConvertJson(f.FunctionMappedInputs)))
  1015  	f.iLog.Debug(fmt.Sprintf("Repeat execution: %d", number))
  1016  
  1017  	f.ExecutionNumber = number
  1018  	f.ExecutionCount = 0
  1019  
  1020  	for i := 0; i < f.ExecutionNumber; i++ {
  1021  		f.ErrorMessage = ""
  1022  		f.iLog.Debug(fmt.Sprintf("Execute the function: %s, execution count: %d / %d", f.Fobj.Name, i+1, f.ExecutionNumber))
  1023  		switch f.Fobj.Functype {
  1024  		case types.InputMap:
  1025  			inputmapfuncs := InputMapFuncs{}
  1026  			inputmapfuncs.Execute(f)
  1027  
  1028  		case types.GoExpr:
  1029  			goexprfuncs := GoExprFuncs{}
  1030  			goexprfuncs.Execute(f)
  1031  		case types.Javascript:
  1032  			jsfuncs := JSFuncs{}
  1033  			jsfuncs.Execute(f)
  1034  
  1035  		case types.Query:
  1036  			qfuncs := QueryFuncs{}
  1037  			qfuncs.Execute(f)
  1038  
  1039  		case types.SubTranCode:
  1040  			stcfuncs := SubTranCodeFuncs{}
  1041  			//stcfuncs := NewSubTran()
  1042  			stcfuncs.Execute(f)
  1043  
  1044  		case types.StoreProcedure:
  1045  			spfuncs := StoreProcFuncs{}
  1046  			spfuncs.Execute(f)
  1047  
  1048  		case types.TableInsert:
  1049  			ti := TableInsertFuncs{}
  1050  			ti.Execute(f)
  1051  
  1052  		case types.TableUpdate:
  1053  			tu := TableUpdateFuncs{}
  1054  			tu.Execute(f)
  1055  
  1056  		case types.TableDelete:
  1057  			td := TableDeleteFuncs{}
  1058  			td.Execute(f)
  1059  
  1060  		case types.CollectionInsert:
  1061  			ci := CollectionInsertFuncs{}
  1062  			ci.Execute(f)
  1063  
  1064  		case types.CollectionUpdate:
  1065  			cu := CollectionUpdateFuncs{}
  1066  			cu.Execute(f)
  1067  
  1068  		case types.CollectionDelete:
  1069  			cd := CollectionDeleteFuncs{}
  1070  			cd.Execute(f)
  1071  
  1072  		case types.ThrowError:
  1073  			te := ThrowErrorFuncs{}
  1074  			te.Execute(f)
  1075  
  1076  		case types.SendMessage:
  1077  			sm := SendMessageFuncs{}
  1078  			sm.Execute(f)
  1079  
  1080  		case types.SendEmail:
  1081  			se := EmailFuncs{}
  1082  			se.Execute(f)
  1083  
  1084  		case types.ExplodeWorkFlow:
  1085  			wf := WorkFlowFunc{}
  1086  			wf.Execute_Explode(f)
  1087  
  1088  		case types.StartWorkFlowTask:
  1089  			wf := WorkFlowFunc{}
  1090  			wf.Execute_StartTask(f)
  1091  
  1092  		case types.CompleteWorkFlowTask:
  1093  			wf := WorkFlowFunc{}
  1094  			wf.Execute_CompleteTask(f)
  1095  
  1096  		case types.SendMessagebyKafka:
  1097  			sm := SendMessagebyKafka{}
  1098  			sm.Execute(f)
  1099  
  1100  		case types.WebServiceCall:
  1101  			ws := WebServiceCallFunc{}
  1102  			ws.Execute(f)
  1103  		}
  1104  
  1105  		f.iLog.Debug(fmt.Sprintf("executed function %s with outputs: %s", f.Fobj.Name, logger.ConvertJson(f.FunctionOutputs)))
  1106  
  1107  		f.ExecutionCount = i + 1
  1108  
  1109  		if f.TestwithSc == true {
  1110  			functioninputs := map[string]interface{}{}
  1111  
  1112  			for _, input := range f.Fobj.Inputs {
  1113  				functioninputs[input.Name] = input.Value
  1114  			}
  1115  
  1116  			TestResult := make(map[string]interface{})
  1117  			TestResult["Name"] = f.Fobj.Name
  1118  			TestResult["Type"] = "Function"
  1119  			TestResult["FunctionType"] = f.Fobj.Functype
  1120  			TestResult["Inputs"] = functioninputs
  1121  			TestResult["Outputs"] = f.FunctionOutputs
  1122  			TestResult["UserSession"] = f.UserSession
  1123  			TestResult["SystemSession"] = f.SystemSession
  1124  			TestResult["ExecutionCount"] = f.ExecutionCount
  1125  			TestResult["ExecutionNumber"] = f.ExecutionNumber
  1126  			TestResult["ExecutionTime"] = time.Since(startTime)
  1127  			TestResult["Error"] = f.ErrorMessage
  1128  			f.TestResults = append(f.TestResults, TestResult)
  1129  		}
  1130  
  1131  	}
  1132  	f.SetfuncOutputs()
  1133  }
  1134  
  1135  func (f *Funcs) Validate() (bool, error) {
  1136  	startTime := time.Now()
  1137  	defer func() {
  1138  		elapsed := time.Since(startTime)
  1139  		f.iLog.PerformanceWithDuration("engine.funcs.Validate", elapsed)
  1140  	}()
  1141  	/*	defer func() {
  1142  			if err := recover(); err != nil {
  1143  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.Validate with error: %s", err))
  1144  				return
  1145  			}
  1146  		}()
  1147  	*/
  1148  	return true, nil
  1149  }
  1150  
  1151  // CancelExecution cancels the execution of the function and rolls back any database transaction.
  1152  // It takes an error message as input and logs the error message along with the function name.
  1153  // It also cancels the context and returns.
  1154  func (f *Funcs) CancelExecution(errormessage string) {
  1155  	startTime := time.Now()
  1156  	defer func() {
  1157  		elapsed := time.Since(startTime)
  1158  		f.iLog.PerformanceWithDuration("engine.funcs.CancelExecution", elapsed)
  1159  	}()
  1160  	/*	defer func() {
  1161  			if err := recover(); err != nil {
  1162  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.CancelExecution with error: %s", err))
  1163  				return
  1164  			}
  1165  		}()
  1166  	*/
  1167  	f.iLog.Error(fmt.Sprintf("There is error during functoin %s execution: %s", f.Fobj.Name, errormessage))
  1168  	f.DBTx.Rollback()
  1169  	f.CtxCancel()
  1170  	f.Ctx.Done()
  1171  	return
  1172  }
  1173  
  1174  // convertMap converts a map[string][]interface{} to a map[string]interface{}.
  1175  // It iterates over the input map and assigns the first value of each key's slice
  1176  // to the corresponding key in the output map. If a key's slice has more than one
  1177  // value, the entire slice is assigned to the key in the output map.
  1178  // The function also logs the performance duration and debug information.
  1179  // It returns the converted map[string]interface{}.
  1180  
  1181  func (f *Funcs) convertMap(m map[string][]interface{}) map[string]interface{} {
  1182  	/*	startTime := time.Now()
  1183  		defer func() {
  1184  			elapsed := time.Since(startTime)
  1185  			f.iLog.PerformanceWithDuration("engine.funcs.convertMap", elapsed)
  1186  		}()
  1187  		defer func() {
  1188  			if err := recover(); err != nil {
  1189  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.convertMap with error: %s", err))
  1190  				return
  1191  			}
  1192  		}()
  1193  	*/
  1194  	f.iLog.Debug(fmt.Sprintf("Convert Map to Json Objects: %s", m))
  1195  
  1196  	result := make(map[string]interface{})
  1197  	for key, value := range m {
  1198  		var interfaceValue interface{}
  1199  		if len(value) == 1 {
  1200  			interfaceValue = value[0]
  1201  		} else {
  1202  			interfaceValue = value
  1203  		}
  1204  		result[key] = interfaceValue
  1205  	}
  1206  
  1207  	f.iLog.Debug(fmt.Sprintf("Convert Map to Json Objects result: %s", result))
  1208  	return result
  1209  }
  1210  
  1211  // revertMap reverts a map[string]interface{} to a map[string][]interface{}.
  1212  // It converts each value in the input map to an array, preserving the original key-value pairs.
  1213  // If the value is already an array, it is preserved as is. Otherwise, it is converted to a single-element array.
  1214  // The reverted map is returned as the result.
  1215  func (f *Funcs) revertMap(m map[string]interface{}) map[string][]interface{} {
  1216  	/*	startTime := time.Now()
  1217  		defer func() {
  1218  			elapsed := time.Since(startTime)
  1219  			f.iLog.PerformanceWithDuration("engine.funcs.revertMap", elapsed)
  1220  		}()
  1221  		defer func() {
  1222  			if err := recover(); err != nil {
  1223  				f.iLog.Error(fmt.Sprintf("There is error to engine.funcs.revertMap with error: %s", err))
  1224  				return
  1225  			}
  1226  		}()
  1227  	*/
  1228  	f.iLog.Debug(fmt.Sprintf("Revert Json Objects to array: %s", m))
  1229  	reverted := make(map[string][]interface{})
  1230  
  1231  	for k, v := range m {
  1232  		switch t := v.(type) {
  1233  		case []interface{}:
  1234  			reverted[k] = t
  1235  		default:
  1236  			reverted[k] = []interface{}{v}
  1237  		}
  1238  	}
  1239  	f.iLog.Debug(fmt.Sprintf("Revert Json Objects to array result: %s", reverted))
  1240  
  1241  	return reverted
  1242  }