text:
package mcir

import (
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"

	//"strings"

	"github.com/cloud-barista/cb-spider/interface/api"
	"github.com/cloud-barista/cb-tumblebug/src/core/common"
	"github.com/go-resty/resty/v2"

	//"github.com/cloud-barista/cb-tumblebug/src/core/mcis"

	_ "github.com/go-sql-driver/mysql"
	"github.com/xwb1989/sqlparser"
)

type SpiderSpecInfo struct { // Spider
	// https://github.com/cloud-barista/cb-spider/blob/master/cloud-control-manager/cloud-driver/interfaces/resources/VMSpecHandler.go

	Region string
	Name   string
	VCpu   SpiderVCpuInfo
	Mem    string
	Gpu    []SpiderGpuInfo

	KeyValueList []common.KeyValue
}

type SpiderVCpuInfo struct { // Spider
	Count string
	Clock string // GHz
}

type SpiderGpuInfo struct { // Spider
	Count string
	Mfr   string
	Model string
	Mem   string
}

type TbSpecReq struct { // Tumblebug
	Name           string `json:"name"`
	ConnectionName string `json:"connectionName"`
	CspSpecName    string `json:"cspSpecName"`
	Description    string `json:"description"`
}

type TbSpecInfo struct { // Tumblebug
	Id                    string   `json:"id"`
	Name                  string   `json:"name"`
	ConnectionName        string   `json:"connectionName"`
	CspSpecName           string   `json:"cspSpecName"`
	Os_type               string   `json:"os_type"`
	Num_vCPU              uint16   `json:"num_vCPU"`
	Num_core              uint16   `json:"num_core"`
	Mem_GiB               uint16   `json:"mem_GiB"`
	Storage_GiB           uint32   `json:"storage_GiB"`
	Description           string   `json:"description"`
	Cost_per_hour         float32  `json:"cost_per_hour"`
	Num_storage           uint8    `json:"num_storage"`
	Max_num_storage       uint8    `json:"max_num_storage"`
	Max_total_storage_TiB uint16   `json:"max_total_storage_TiB"`
	Net_bw_Gbps           uint16   `json:"net_bw_Gbps"`
	Ebs_bw_Mbps           uint32   `json:"ebs_bw_Mbps"`
	Gpu_model             string   `json:"gpu_model"`
	Num_gpu               uint8    `json:"num_gpu"`
	Gpumem_GiB            uint16   `json:"gpumem_GiB"`
	Gpu_p2p               string   `json:"gpu_p2p"`
	OrderInFilteredResult uint16   `json:"orderInFilteredResult"`
	EvaluationStatus      string   `json:"evaluationStatus"`
	EvaluationScore_01    float32  `json:"evaluationScore_01"`
	EvaluationScore_02    float32  `json:"evaluationScore_02"`
	EvaluationScore_03    float32  `json:"evaluationScore_03"`
	EvaluationScore_04    float32  `json:"evaluationScore_04"`
	EvaluationScore_05    float32  `json:"evaluationScore_05"`
	EvaluationScore_06    float32  `json:"evaluationScore_06"`
	EvaluationScore_07    float32  `json:"evaluationScore_07"`
	EvaluationScore_08    float32  `json:"evaluationScore_08"`
	EvaluationScore_09    float32  `json:"evaluationScore_09"`
	EvaluationScore_10    float32  `json:"evaluationScore_10"`
	AssociatedObjectList  []string `json:"associatedObjectList"`
	IsAutoGenerated       bool     `json:"isAutoGenerated"`
}

// ConvertSpiderSpecToTumblebugSpec accepts an Spider spec object, converts to and returns an TB spec object
func ConvertSpiderSpecToTumblebugSpec(spiderSpec SpiderSpecInfo) (TbSpecInfo, error) {
	if spiderSpec.Name == "" {
		err := fmt.Errorf("ConvertSpiderSpecToTumblebugSpec failed; spiderSpec.Name == \"\" ")
		emptyTumblebugSpec := TbSpecInfo{}
		return emptyTumblebugSpec, err
	}

	tumblebugSpec := TbSpecInfo{}

	tumblebugSpec.Name = spiderSpec.Name
	tumblebugSpec.CspSpecName = spiderSpec.Name
	tempUint64, _ := strconv.ParseUint(spiderSpec.VCpu.Count, 10, 16)
	tumblebugSpec.Num_vCPU = uint16(tempUint64)
	tempFloat64, _ := strconv.ParseFloat(spiderSpec.Mem, 32)
	tumblebugSpec.Mem_GiB = uint16(tempFloat64 / 1024) //fmt.Sprintf("%.0f", tempFloat64/1024)

	return tumblebugSpec, nil
}

type SpiderSpecList struct {
	Vmspec []SpiderSpecInfo `json:"vmspec"`
}

// LookupSpecList accepts Spider conn config,
// lookups and returns the list of all specs in the region of conn config
// in the form of the list of Spider spec objects
func LookupSpecList(connConfig string) (SpiderSpecList, error) {

	if connConfig == "" {
		content := SpiderSpecList{}
		err := fmt.Errorf("LookupSpec() called with empty connConfig.")
		common.CBLog.Error(err)
		return content, err
	}

	if os.Getenv("SPIDER_CALL_METHOD") == "REST" {

		url := common.SPIDER_REST_URL + "/vmspec"

		// Create Req body
		tempReq := common.SpiderConnectionName{}
		tempReq.ConnectionName = connConfig

		client := resty.New()
		client.SetAllowGetMethodPayload(true)

		resp, err := client.R().
			SetHeader("Content-Type", "application/json").
			SetBody(tempReq).
			SetResult(&SpiderSpecList{}). // or SetResult(AuthSuccess{}).
			//SetError(&AuthError{}).       // or SetError(AuthError{}).
			Get(url)

		if err != nil {
			common.CBLog.Error(err)
			content := SpiderSpecList{}
			err := fmt.Errorf("an error occurred while requesting to CB-Spider")
			return content, err
		}

		fmt.Println(string(resp.Body()))

		fmt.Println("HTTP Status code: " + strconv.Itoa(resp.StatusCode()))
		switch {
		case resp.StatusCode() >= 400 || resp.StatusCode() < 200:
			err := fmt.Errorf(string(resp.Body()))
			common.CBLog.Error(err)
			content := SpiderSpecList{}
			return content, err
		}

		temp := resp.Result().(*SpiderSpecList)
		return *temp, nil

	} else {

		// CCM API 설정
		ccm := api.NewCloudResourceHandler()
		err := ccm.SetConfigPath(os.Getenv("CBTUMBLEBUG_ROOT") + "/conf/grpc_conf.yaml")
		if err != nil {
			common.CBLog.Error("ccm failed to set config : ", err)
			return SpiderSpecList{}, err
		}
		err = ccm.Open()
		if err != nil {
			common.CBLog.Error("ccm api open failed : ", err)
			return SpiderSpecList{}, err
		}
		defer ccm.Close()

		result, err := ccm.ListVMSpecByParam(connConfig)
		if err != nil {
			common.CBLog.Error(err)
			return SpiderSpecList{}, err
		}

		temp := SpiderSpecList{}
		err = json.Unmarshal([]byte(result), &temp)
		if err != nil {
			common.CBLog.Error(err)
			return SpiderSpecList{}, err
		}
		return temp, nil

	}
}

// LookupSpec accepts Spider conn config and CSP spec name, lookups and returns the Spider spec object
func LookupSpec(connConfig string, specName string) (SpiderSpecInfo, error) {

	if connConfig == "" {
		content := SpiderSpecInfo{}
		err := fmt.Errorf("LookupSpec() called with empty connConfig.")
		common.CBLog.Error(err)
		return content, err
	} else if specName == "" {
		content := SpiderSpecInfo{}
		err := fmt.Errorf("LookupSpec() called with empty specName.")
		common.CBLog.Error(err)
		return content, err
	}

	if os.Getenv("SPIDER_CALL_METHOD") == "REST" {

		//url := common.SPIDER_REST_URL + "/vmspec/" + u.CspSpecName
		url := common.SPIDER_REST_URL + "/vmspec/" + specName

		// Create Req body
		tempReq := common.SpiderConnectionName{}
		tempReq.ConnectionName = connConfig

		client := resty.New()
		client.SetAllowGetMethodPayload(true)

		resp, err := client.R().
			SetHeader("Content-Type", "application/json").
			SetBody(tempReq).
			SetResult(&SpiderSpecInfo{}). // or SetResult(AuthSuccess{}).
			//SetError(&AuthError{}).       // or SetError(AuthError{}).
			Get(url)

		if err != nil {
			common.CBLog.Error(err)
			content := SpiderSpecInfo{}
			err := fmt.Errorf("an error occurred while requesting to CB-Spider")
			return content, err
		}

		fmt.Println(string(resp.Body()))

		fmt.Println("HTTP Status code: " + strconv.Itoa(resp.StatusCode()))
		switch {
		case resp.StatusCode() >= 400 || resp.StatusCode() < 200:
			err := fmt.Errorf(string(resp.Body()))
			common.CBLog.Error(err)
			content := SpiderSpecInfo{}
			return content, err
		}

		temp := resp.Result().(*SpiderSpecInfo)
		return *temp, nil

	} else {

		// CCM API 설정
		ccm := api.NewCloudResourceHandler()
		err := ccm.SetConfigPath(os.Getenv("CBTUMBLEBUG_ROOT") + "/conf/grpc_conf.yaml")
		if err != nil {
			common.CBLog.Error("ccm failed to set config : ", err)
			return SpiderSpecInfo{}, err
		}
		err = ccm.Open()
		if err != nil {
			common.CBLog.Error("ccm api open failed : ", err)
			return SpiderSpecInfo{}, err
		}
		defer ccm.Close()

		result, err := ccm.GetVMSpecByParam(connConfig, specName)
		if err != nil {
			common.CBLog.Error(err)
			return SpiderSpecInfo{}, err
		}

		temp := SpiderSpecInfo{}
		err2 := json.Unmarshal([]byte(result), &temp)
		if err2 != nil {
			fmt.Errorf("an error occurred while unmarshaling: " + err2.Error())
		}
		return temp, nil

	}
}

func RefineSpecName(specName string) string {
	out := strings.ToLower(specName)
	out = strings.ReplaceAll(out, ".", "-")
	out = strings.ReplaceAll(out, "_", "-")

	return out
}

// FetchSpecsForConnConfig lookups all specs for region of conn config, and saves into TB spec objects
func FetchSpecsForConnConfig(connConfig string, nsId string) (specCount uint, err error) {
	fmt.Println("FetchSpecsForConnConfig(" + connConfig + ")")

	spiderSpecList, err := LookupSpecList(connConfig)
	if err != nil {
		common.CBLog.Error(err)
		return 0, err
	}

	for _, spiderSpec := range spiderSpecList.Vmspec {
		tumblebugSpec, err := ConvertSpiderSpecToTumblebugSpec(spiderSpec)
		if err != nil {
			common.CBLog.Error(err)
			return 0, err
		}

		tumblebugSpecId := connConfig + "-" + RefineSpecName(tumblebugSpec.Name)
		//fmt.Println("tumblebugSpecId: " + tumblebugSpecId) // for debug

		check, err := CheckResource(nsId, common.StrSpec, tumblebugSpecId)
		if check {
			common.CBLog.Infoln("The spec " + tumblebugSpecId + " already exists in TB; continue")
			continue
		} else if err != nil {
			common.CBLog.Infoln("Cannot check the existence of " + tumblebugSpecId + " in TB; continue")
			continue
		} else {
			tumblebugSpec.Name = tumblebugSpecId
			tumblebugSpec.ConnectionName = connConfig

			_, err := RegisterSpecWithInfo(nsId, &tumblebugSpec)
			if err != nil {
				common.CBLog.Error(err)
				return 0, err
			}
			specCount++
		}
	}
	return specCount, nil
}

// FetchSpecsForAllConnConfigs gets all conn configs from Spider, lookups all specs for each region of conn config, and saves into TB spec objects
func FetchSpecsForAllConnConfigs(nsId string) (connConfigCount uint, specCount uint, err error) {

	err = common.CheckString(nsId)
	if err != nil {
		common.CBLog.Error(err)
		return 0, 0, err
	}

	connConfigs, err := common.GetConnConfigList()
	if err != nil {
		common.CBLog.Error(err)
		return 0, 0, err
	}

	for _, connConfig := range connConfigs.Connectionconfig {
		temp, _ := FetchSpecsForConnConfig(connConfig.ConfigName, nsId)
		specCount += temp
		connConfigCount++
	}
	return connConfigCount, specCount, nil
}

// RegisterSpecWithCspSpecName accepts spec creation request, creates and returns an TB spec object
func RegisterSpecWithCspSpecName(nsId string, u *TbSpecReq) (TbSpecInfo, error) {

	resourceType := common.StrSpec

	err := common.CheckString(nsId)
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	err = common.CheckString(u.Name)
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	check, _ := CheckResource(nsId, resourceType, u.Name)

	if check {
		temp := TbSpecInfo{}
		err := fmt.Errorf("The spec " + u.Name + " already exists.")
		return temp, err
	}

	res, err := LookupSpec(u.ConnectionName, u.CspSpecName)
	if err != nil {
		common.CBLog.Error(err)
		err := fmt.Errorf("an error occurred while lookup spec via CB-Spider")
		emptySpecInfoObj := TbSpecInfo{}
		return emptySpecInfoObj, err
	}

	content := TbSpecInfo{}
	//content.Id = common.GenUuid()
	content.Id = u.Name
	content.Name = u.Name
	content.CspSpecName = res.Name
	content.ConnectionName = u.ConnectionName
	content.AssociatedObjectList = []string{}

	tempUint64, _ := strconv.ParseUint(res.VCpu.Count, 10, 16)
	content.Num_vCPU = uint16(tempUint64)

	//content.Num_core = res.Num_core

	tempFloat64, _ := strconv.ParseFloat(res.Mem, 32)
	content.Mem_GiB = uint16(tempFloat64 / 1024)

	//content.Storage_GiB = res.Storage_GiB
	//content.Description = res.Description

	sql := "INSERT INTO `spec`(" +
		"`namespace`, " +
		"`id`, " +
		"`connectionName`, " +
		"`cspSpecName`, " +
		"`name`, " +
		"`os_type`, " +
		"`num_vCPU`, " +
		"`num_core`, " +
		"`mem_GiB`, " +
		"`storage_GiB`, " +
		"`description`, " +
		"`cost_per_hour`, " +
		"`num_storage`, " +
		"`max_num_storage`, " +
		"`max_total_storage_TiB`, " +
		"`net_bw_Gbps`, " +
		"`ebs_bw_Mbps`, " +
		"`gpu_model`, " +
		"`num_gpu`, " +
		"`gpumem_GiB`, " +
		"`gpu_p2p`, " +
		"`orderInFilteredResult`, " +
		"`evaluationStatus`, " +
		"`evaluationScore_01`, " +
		"`evaluationScore_02`, " +
		"`evaluationScore_03`, " +
		"`evaluationScore_04`, " +
		"`evaluationScore_05`, " +
		"`evaluationScore_06`, " +
		"`evaluationScore_07`, " +
		"`evaluationScore_08`, " +
		"`evaluationScore_09`, " +
		"`evaluationScore_10`) " +
		"VALUES ('" +
		nsId + "', '" +
		content.Id + "', '" +
		content.ConnectionName + "', '" +
		content.CspSpecName + "', '" +
		content.Name + "', '" +
		content.Os_type + "', '" +
		strconv.Itoa(int(content.Num_vCPU)) + "', '" +
		strconv.Itoa(int(content.Num_core)) + "', '" +
		strconv.Itoa(int(content.Mem_GiB)) + "', '" +
		strconv.Itoa(int(content.Storage_GiB)) + "', '" +
		content.Description + "', '" +
		fmt.Sprintf("%.6f", content.Cost_per_hour) + "', '" +
		strconv.Itoa(int(content.Num_storage)) + "', '" +
		strconv.Itoa(int(content.Max_num_storage)) + "', '" +
		strconv.Itoa(int(content.Max_total_storage_TiB)) + "', '" +
		strconv.Itoa(int(content.Net_bw_Gbps)) + "', '" +
		strconv.Itoa(int(content.Ebs_bw_Mbps)) + "', '" +
		content.Gpu_model + "', '" +
		strconv.Itoa(int(content.Num_gpu)) + "', '" +
		strconv.Itoa(int(content.Gpumem_GiB)) + "', '" +
		content.Gpu_p2p + "', '" +
		strconv.Itoa(int(content.OrderInFilteredResult)) + "', '" +
		content.EvaluationStatus + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_01) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_02) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_03) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_04) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_05) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_06) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_07) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_08) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_09) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_10) + "');"

	fmt.Println("sql: " + sql)
	// https://stackoverflow.com/questions/42486032/golang-sql-query-syntax-validator
	_, err = sqlparser.Parse(sql)
	if err != nil {
		return content, err
	}

	// cb-store
	fmt.Println("=========================== PUT registerSpec")
	Key := common.GenResourceKey(nsId, resourceType, content.Id)
	Val, _ := json.Marshal(content)
	err = common.CBStore.Put(string(Key), string(Val))
	if err != nil {
		common.CBLog.Error(err)
		return content, err
	}
	keyValue, _ := common.CBStore.Get(string(Key))
	fmt.Println("<" + keyValue.Key + "> \n" + keyValue.Value)
	fmt.Println("===========================")

	// register information related with MCIS recommendation
	err = RegisterRecommendList(nsId, content.ConnectionName, content.Num_vCPU, content.Mem_GiB, content.Storage_GiB, content.Id, content.Cost_per_hour)
	if err != nil {
		common.CBLog.Error(err)
		return content, err
	}

	stmt, err := common.MYDB.Prepare(sql)
	if err != nil {
		fmt.Println(err.Error())
	}
	_, err = stmt.Exec()
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Data inserted successfully..")
	}

	return content, nil
}

// RegisterSpecWithInfo accepts spec creation request, creates and returns an TB spec object
func RegisterSpecWithInfo(nsId string, content *TbSpecInfo) (TbSpecInfo, error) {

	resourceType := common.StrSpec

	err := common.CheckString(nsId)
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	err = common.CheckString(content.Name)
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	check, _ := CheckResource(nsId, resourceType, content.Name)

	if check {
		temp := TbSpecInfo{}
		err := fmt.Errorf("The spec " + content.Name + " already exists.")
		return temp, err
	}

	content.Id = content.Name
	content.AssociatedObjectList = []string{}

	sql := "INSERT INTO `spec`(" +
		"`namespace`, " +
		"`id`, " +
		"`connectionName`, " +
		"`cspSpecName`, " +
		"`name`, " +
		"`os_type`, " +
		"`num_vCPU`, " +
		"`num_core`, " +
		"`mem_GiB`, " +
		"`storage_GiB`, " +
		"`description`, " +
		"`cost_per_hour`, " +
		"`num_storage`, " +
		"`max_num_storage`, " +
		"`max_total_storage_TiB`, " +
		"`net_bw_Gbps`, " +
		"`ebs_bw_Mbps`, " +
		"`gpu_model`, " +
		"`num_gpu`, " +
		"`gpumem_GiB`, " +
		"`gpu_p2p`, " +
		"`orderInFilteredResult`, " +
		"`evaluationStatus`, " +
		"`evaluationScore_01`, " +
		"`evaluationScore_02`, " +
		"`evaluationScore_03`, " +
		"`evaluationScore_04`, " +
		"`evaluationScore_05`, " +
		"`evaluationScore_06`, " +
		"`evaluationScore_07`, " +
		"`evaluationScore_08`, " +
		"`evaluationScore_09`, " +
		"`evaluationScore_10`) " +
		"VALUES ('" +
		nsId + "', '" +
		content.Id + "', '" +
		content.ConnectionName + "', '" +
		content.CspSpecName + "', '" +
		content.Name + "', '" +
		content.Os_type + "', '" +
		strconv.Itoa(int(content.Num_vCPU)) + "', '" +
		strconv.Itoa(int(content.Num_core)) + "', '" +
		strconv.Itoa(int(content.Mem_GiB)) + "', '" +
		strconv.Itoa(int(content.Storage_GiB)) + "', '" +
		content.Description + "', '" +
		fmt.Sprintf("%.6f", content.Cost_per_hour) + "', '" +
		strconv.Itoa(int(content.Num_storage)) + "', '" +
		strconv.Itoa(int(content.Max_num_storage)) + "', '" +
		strconv.Itoa(int(content.Max_total_storage_TiB)) + "', '" +
		strconv.Itoa(int(content.Net_bw_Gbps)) + "', '" +
		strconv.Itoa(int(content.Ebs_bw_Mbps)) + "', '" +
		content.Gpu_model + "', '" +
		strconv.Itoa(int(content.Num_gpu)) + "', '" +
		strconv.Itoa(int(content.Gpumem_GiB)) + "', '" +
		content.Gpu_p2p + "', '" +
		strconv.Itoa(int(content.OrderInFilteredResult)) + "', '" +
		content.EvaluationStatus + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_01) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_02) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_03) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_04) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_05) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_06) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_07) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_08) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_09) + "', '" +
		fmt.Sprintf("%.6f", content.EvaluationScore_10) + "');"

	fmt.Println("sql: " + sql)
	// https://stackoverflow.com/questions/42486032/golang-sql-query-syntax-validator
	_, err = sqlparser.Parse(sql)
	if err != nil {
		return *content, err
	}

	// cb-store
	fmt.Println("=========================== PUT registerSpec")
	Key := common.GenResourceKey(nsId, resourceType, content.Id)
	Val, _ := json.Marshal(content)
	err = common.CBStore.Put(string(Key), string(Val))
	if err != nil {
		common.CBLog.Error(err)
		return *content, err
	}
	keyValue, _ := common.CBStore.Get(string(Key))
	fmt.Println("<" + keyValue.Key + "> \n" + keyValue.Value)
	fmt.Println("===========================")

	// register information related with MCIS recommendation
	err = RegisterRecommendList(nsId, content.ConnectionName, content.Num_vCPU, content.Mem_GiB, content.Storage_GiB, content.Id, content.Cost_per_hour)
	if err != nil {
		common.CBLog.Error(err)
		return *content, err
	}

	stmt, err := common.MYDB.Prepare(sql)
	if err != nil {
		fmt.Println(err.Error())
	}
	_, err = stmt.Exec()
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Data inserted successfully..")
	}

	return *content, nil
}

// RegisterRecommendList creates the spec recommendation info
func RegisterRecommendList(nsId string, connectionName string, cpuSize uint16, memSize uint16, diskSize uint32, specId string, price float32) error {

	err := common.CheckString(nsId)
	if err != nil {
		common.CBLog.Error(err)
		return err
	}

	//fmt.Println("[Get MCISs")
	key := common.GenMcisKey(nsId, "", "") + "/cpuSize/" + strconv.Itoa(int(cpuSize)) + "/memSize/" + strconv.Itoa(int(memSize)) + "/diskSize/" + strconv.Itoa(int(diskSize)) + "/specId/" + specId
	fmt.Println(key)

	mapA := map[string]string{"id": specId, "price": fmt.Sprintf("%.6f", price), "connectionName": connectionName}
	Val, _ := json.Marshal(mapA)

	err = common.CBStore.Put(string(key), string(Val))
	if err != nil {
		common.CBLog.Error(err)
		return err
	}

	fmt.Println("===============================================")
	return nil

}

// DelRecommendSpec deletes the spec recommendation info
func DelRecommendSpec(nsId string, specId string, cpuSize uint16, memSize uint16, diskSize uint32) error {

	err := common.CheckString(nsId)
	if err != nil {
		common.CBLog.Error(err)
		return err
	}

	fmt.Println("DelRecommendSpec()")

	key := common.GenMcisKey(nsId, "", "") + "/cpuSize/" + strconv.Itoa(int(cpuSize)) + "/memSize/" + strconv.Itoa(int(memSize)) + "/diskSize/" + strconv.Itoa(int(diskSize)) + "/specId/" + specId

	err = common.CBStore.Delete(key)
	if err != nil {
		common.CBLog.Error(err)
		return err
	}

	return nil

}

// FilterSpecs accepts criteria for filtering, and returns the list of filtered TB spec objects
func FilterSpecs(nsId string, filter TbSpecInfo) ([]TbSpecInfo, error) {

	err := common.CheckString(nsId)
	if err != nil {
		common.CBLog.Error(err)
		return nil, err
	}

	tempList := []TbSpecInfo{}

	sqlQuery := "SELECT * FROM `spec` WHERE `namespace`='" + nsId + "'"

	if filter.Id != "" {
		sqlQuery += " AND `id` LIKE '%" + filter.Id + "%'"
	}
	if filter.Name != "" {
		sqlQuery += " AND `name` LIKE '%" + filter.Name + "%'"
	}
	if filter.ConnectionName != "" {
		sqlQuery += " AND `connectionName` LIKE '%" + filter.ConnectionName + "%'"
	}
	if filter.CspSpecName != "" {
		sqlQuery += " AND `cspSpecName` LIKE '%" + filter.CspSpecName + "%'"
	}
	if filter.Os_type != "" {
		sqlQuery += " AND `os_type` LIKE '%" + filter.Os_type + "%'"
	}

	if filter.Num_vCPU > 0 {
		sqlQuery += " AND `num_vCPU`=" + strconv.Itoa(int(filter.Num_vCPU))
	}
	if filter.Num_core > 0 {
		sqlQuery += " AND `num_core`=" + strconv.Itoa(int(filter.Num_core))
	}
	if filter.Mem_GiB > 0 {
		sqlQuery += " AND `mem_GiB`=" + strconv.Itoa(int(filter.Mem_GiB))
	}
	if filter.Storage_GiB > 0 {
		sqlQuery += " AND `storage_GiB`=" + strconv.Itoa(int(filter.Storage_GiB))
	}
	if filter.Description != "" {
		sqlQuery += " AND `description` LIKE '%" + filter.Description + "%'"
	}
	if filter.Cost_per_hour > 0 {
		sqlQuery += " AND `cost_per_hour`=" + fmt.Sprintf("%.6f", filter.Cost_per_hour)
	}
	if filter.Num_storage > 0 {
		sqlQuery += " AND `num_storage`=" + strconv.Itoa(int(filter.Num_storage))
	}
	if filter.Max_num_storage > 0 {
		sqlQuery += " AND `max_num_storage`=" + strconv.Itoa(int(filter.Max_num_storage))
	}
	if filter.Max_total_storage_TiB > 0 {
		sqlQuery += " AND `max_total_storage_TiB`=" + strconv.Itoa(int(filter.Max_total_storage_TiB))
	}
	if filter.Net_bw_Gbps > 0 {
		sqlQuery += " AND `net_bw_Gbps`=" + strconv.Itoa(int(filter.Net_bw_Gbps))
	}
	if filter.Ebs_bw_Mbps > 0 {
		sqlQuery += " AND `ebs_bw_Mbps`=" + strconv.Itoa(int(filter.Ebs_bw_Mbps))
	}
	if filter.Gpu_model != "" {
		sqlQuery += " AND `gpu_model` LIKE '%" + filter.Gpu_model + "%'"
	}
	if filter.Num_gpu > 0 {
		sqlQuery += " AND `num_gpu`=" + strconv.Itoa(int(filter.Num_gpu))
	}
	if filter.Gpumem_GiB > 0 {
		sqlQuery += " AND `gpumem_GiB`=" + strconv.Itoa(int(filter.Gpumem_GiB))
	}
	if filter.Gpu_p2p != "" {
		sqlQuery += " AND `gpu_p2p` LIKE '%" + filter.Gpu_p2p + "%'"
	}
	if filter.EvaluationStatus != "" {
		sqlQuery += " AND `evaluationStatus` LIKE '%" + filter.EvaluationStatus + "%'"
	}
	if filter.EvaluationScore_01 > 0 {
		sqlQuery += " AND `evaluationScore_01`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_01)
	}
	if filter.EvaluationScore_02 > 0 {
		sqlQuery += " AND `evaluationScore_02`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_02)
	}
	if filter.EvaluationScore_03 > 0 {
		sqlQuery += " AND `evaluationScore_03`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_03)
	}
	if filter.EvaluationScore_04 > 0 {
		sqlQuery += " AND `evaluationScore_04`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_04)
	}
	if filter.EvaluationScore_05 > 0 {
		sqlQuery += " AND `evaluationScore_05`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_05)
	}
	if filter.EvaluationScore_06 > 0 {
		sqlQuery += " AND `evaluationScore_06`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_06)
	}
	if filter.EvaluationScore_07 > 0 {
		sqlQuery += " AND `evaluationScore_07`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_07)
	}
	if filter.EvaluationScore_08 > 0 {
		sqlQuery += " AND `evaluationScore_08`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_08)
	}
	if filter.EvaluationScore_09 > 0 {
		sqlQuery += " AND `evaluationScore_09`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_09)
	}
	if filter.EvaluationScore_10 > 0 {
		sqlQuery += " AND `evaluationScore_10`=" + fmt.Sprintf("%.6f", filter.EvaluationScore_10)
	}
	sqlQuery += ";"
	_, err = sqlparser.Parse(sqlQuery)
	if err != nil {
		return tempList, err
	}

	/*
		stmt, err := common.MYDB.Prepare(sqlQuery)
		if err != nil {
			fmt.Println(err.Error())
		}
		result, err := stmt.Exec()
		if err != nil {
			fmt.Println(err.Error())
		} else {
			fmt.Println("SELECTed successfully..")
		}

		result.RowsAffected

		temp := []TbSpecInfo{}
		return temp, nil
	*/

	rows, err := common.MYDB.Query(sqlQuery)
	if err != nil {
		common.CBLog.Error(err)
		return tempList, err
	}

	cols, err := rows.Columns()
	if err != nil {
		common.CBLog.Error(err)
		return tempList, err
	}

	for rows.Next() {
		columns := make([]interface{}, len(cols))
		columnPointers := make([]interface{}, len(cols))
		for i := range columns {
			columnPointers[i] = &columns[i]
		}

		if err := rows.Scan(columnPointers...); err != nil {
			return tempList, err
		}
		m := make(map[string]interface{})
		for i, colName := range cols {
			val := columnPointers[i].(*interface{})
			m[colName] = *val
		}
		js, _ := json.Marshal(m)
		tempSpec := TbSpecInfo{}
		err = json.Unmarshal(js, &tempSpec)
		if err != nil {
			common.CBLog.Error(err)
			return nil, err
		}
		tempList = append(tempList, tempSpec)
	}
	return tempList, nil
}

type Range struct {
	Min float32 `json:"min"`
	Max float32 `json:"max"`
}

type FilterSpecsByRangeRequest struct {
	Id                    string `json:"id"`
	Name                  string `json:"name"`
	ConnectionName        string `json:"connectionName"`
	CspSpecName           string `json:"cspSpecName"`
	Os_type               string `json:"os_type"`
	Num_vCPU              Range  `json:"num_vCPU"`
	Num_core              Range  `json:"num_core"`
	Mem_GiB               Range  `json:"mem_GiB"`
	Storage_GiB           Range  `json:"storage_GiB"`
	Description           string `json:"description"`
	Cost_per_hour         Range  `json:"cost_per_hour"`
	Num_storage           Range  `json:"num_storage"`
	Max_num_storage       Range  `json:"max_num_storage"`
	Max_total_storage_TiB Range  `json:"max_total_storage_TiB"`
	Net_bw_Gbps           Range  `json:"net_bw_Gbps"`
	Ebs_bw_Mbps           Range  `json:"ebs_bw_Mbps"`
	Gpu_model             string `json:"gpu_model"`
	Num_gpu               Range  `json:"num_gpu"`
	Gpumem_GiB            Range  `json:"gpumem_GiB"`
	Gpu_p2p               string `json:"gpu_p2p"`
	EvaluationStatus      string `json:"evaluationStatus"`
	EvaluationScore_01    Range  `json:"evaluationScore_01"`
	EvaluationScore_02    Range  `json:"evaluationScore_02"`
	EvaluationScore_03    Range  `json:"evaluationScore_03"`
	EvaluationScore_04    Range  `json:"evaluationScore_04"`
	EvaluationScore_05    Range  `json:"evaluationScore_05"`
	EvaluationScore_06    Range  `json:"evaluationScore_06"`
	EvaluationScore_07    Range  `json:"evaluationScore_07"`
	EvaluationScore_08    Range  `json:"evaluationScore_08"`
	EvaluationScore_09    Range  `json:"evaluationScore_09"`
	EvaluationScore_10    Range  `json:"evaluationScore_10"`
}

// FilterSpecsByRange accepts criteria ranges for filtering, and returns the list of filtered TB spec objects
func FilterSpecsByRange(nsId string, filter FilterSpecsByRangeRequest) ([]TbSpecInfo, error) {

	err := common.CheckString(nsId)
	if err != nil {
		common.CBLog.Error(err)
		return nil, err
	}

	tempList := []TbSpecInfo{}

	sqlQuery := "SELECT * FROM `spec` WHERE `namespace`='" + nsId + "'"

	if filter.Id != "" {
		sqlQuery += " AND `id` LIKE '%" + filter.Id + "%'"
	}
	if filter.Name != "" {
		sqlQuery += " AND `name` LIKE '%" + filter.Name + "%'"
	}
	if filter.ConnectionName != "" {
		sqlQuery += " AND `connectionName` LIKE '%" + filter.ConnectionName + "%'"
	}
	if filter.CspSpecName != "" {
		sqlQuery += " AND `cspSpecName` LIKE '%" + filter.CspSpecName + "%'"
	}
	if filter.Os_type != "" {
		sqlQuery += " AND `os_type` LIKE '%" + filter.Os_type + "%'"
	}

	if filter.Num_vCPU.Min > 0 {
		sqlQuery += " AND `num_vCPU`>=" + fmt.Sprintf("%.6f", filter.Num_vCPU.Min)
	}
	if filter.Num_vCPU.Max > 0 {
		sqlQuery += " AND `num_vCPU`<=" + fmt.Sprintf("%.6f", filter.Num_vCPU.Max)
	}

	if filter.Num_core.Min > 0 {
		sqlQuery += " AND `num_core`>=" + fmt.Sprintf("%.6f", filter.Num_core.Min)
	}
	if filter.Num_core.Max > 0 {
		sqlQuery += " AND `num_core`<=" + fmt.Sprintf("%.6f", filter.Num_core.Max)
	}

	if filter.Mem_GiB.Min > 0 {
		sqlQuery += " AND `mem_GiB`>=" + fmt.Sprintf("%.6f", filter.Mem_GiB.Min)
	}
	if filter.Mem_GiB.Max > 0 {
		sqlQuery += " AND `mem_GiB`<=" + fmt.Sprintf("%.6f", filter.Mem_GiB.Max)
	}

	if filter.Storage_GiB.Min > 0 {
		sqlQuery += " AND `storage_GiB`>=" + fmt.Sprintf("%.6f", filter.Storage_GiB.Min)
	}
	if filter.Storage_GiB.Max > 0 {
		sqlQuery += " AND `storage_GiB`<=" + fmt.Sprintf("%.6f", filter.Storage_GiB.Max)
	}

	if filter.Description != "" {
		sqlQuery += " AND `description` LIKE '%" + filter.Description + "%'"
	}

	if filter.Cost_per_hour.Min > 0 {
		sqlQuery += " AND `cost_per_hour`>=" + fmt.Sprintf("%.6f", filter.Cost_per_hour.Min)
	}
	if filter.Cost_per_hour.Max > 0 {
		sqlQuery += " AND `cost_per_hour`<=" + fmt.Sprintf("%.6f", filter.Cost_per_hour.Max)
	}

	if filter.Num_storage.Min > 0 {
		sqlQuery += " AND `num_storage`>=" + fmt.Sprintf("%.6f", filter.Num_storage.Min)
	}
	if filter.Num_storage.Max > 0 {
		sqlQuery += " AND `num_storage`<=" + fmt.Sprintf("%.6f", filter.Num_storage.Max)
	}

	if filter.Max_num_storage.Min > 0 {
		sqlQuery += " AND `max_num_storage`>=" + fmt.Sprintf("%.6f", filter.Max_num_storage.Min)
	}
	if filter.Max_num_storage.Max > 0 {
		sqlQuery += " AND `max_num_storage`<=" + fmt.Sprintf("%.6f", filter.Max_num_storage.Max)
	}

	if filter.Max_total_storage_TiB.Min > 0 {
		sqlQuery += " AND `max_total_storage_TiB`>=" + fmt.Sprintf("%.6f", filter.Max_total_storage_TiB.Min)
	}
	if filter.Max_total_storage_TiB.Max > 0 {
		sqlQuery += " AND `max_total_storage_TiB`<=" + fmt.Sprintf("%.6f", filter.Max_total_storage_TiB.Max)
	}

	if filter.Net_bw_Gbps.Min > 0 {
		sqlQuery += " AND `net_bw_Gbps`>=" + fmt.Sprintf("%.6f", filter.Net_bw_Gbps.Min)
	}
	if filter.Net_bw_Gbps.Max > 0 {
		sqlQuery += " AND `net_bw_Gbps`<=" + fmt.Sprintf("%.6f", filter.Net_bw_Gbps.Max)
	}

	if filter.Ebs_bw_Mbps.Min > 0 {
		sqlQuery += " AND `ebs_bw_Mbps`>=" + fmt.Sprintf("%.6f", filter.Ebs_bw_Mbps.Min)
	}
	if filter.Ebs_bw_Mbps.Max > 0 {
		sqlQuery += " AND `ebs_bw_Mbps`<=" + fmt.Sprintf("%.6f", filter.Ebs_bw_Mbps.Max)
	}

	if filter.Gpu_model != "" {
		sqlQuery += " AND `gpu_model` LIKE '%" + filter.Gpu_model + "%'"
	}

	if filter.Num_gpu.Min > 0 {
		sqlQuery += " AND `num_gpu`>=" + fmt.Sprintf("%.6f", filter.Num_gpu.Min)
	}
	if filter.Num_gpu.Max > 0 {
		sqlQuery += " AND `num_gpu`<=" + fmt.Sprintf("%.6f", filter.Num_gpu.Max)
	}

	if filter.Gpumem_GiB.Min > 0 {
		sqlQuery += " AND `gpumem_GiB`>=" + fmt.Sprintf("%.6f", filter.Gpumem_GiB.Min)
	}
	if filter.Gpumem_GiB.Max > 0 {
		sqlQuery += " AND `gpumem_GiB`<=" + fmt.Sprintf("%.6f", filter.Gpumem_GiB.Max)
	}

	if filter.Gpu_p2p != "" {
		sqlQuery += " AND `gpu_p2p` LIKE '%" + filter.Gpu_p2p + "%'"
	}
	if filter.EvaluationStatus != "" {
		sqlQuery += " AND `evaluationStatus` LIKE '%" + filter.EvaluationStatus + "%'"
	}

	if filter.EvaluationScore_01.Min > 0 {
		sqlQuery += " AND `evaluationScore_01`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_01.Min)
	}
	if filter.EvaluationScore_01.Max > 0 {
		sqlQuery += " AND `evaluationScore_01`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_01.Max)
	}

	if filter.EvaluationScore_02.Min > 0 {
		sqlQuery += " AND `evaluationScore_02`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_02.Min)
	}
	if filter.EvaluationScore_02.Max > 0 {
		sqlQuery += " AND `evaluationScore_02`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_02.Max)
	}

	if filter.EvaluationScore_03.Min > 0 {
		sqlQuery += " AND `evaluationScore_03`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_03.Min)
	}
	if filter.EvaluationScore_03.Max > 0 {
		sqlQuery += " AND `evaluationScore_03`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_03.Max)
	}

	if filter.EvaluationScore_04.Min > 0 {
		sqlQuery += " AND `evaluationScore_04`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_04.Min)
	}
	if filter.EvaluationScore_04.Max > 0 {
		sqlQuery += " AND `evaluationScore_04`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_04.Max)
	}

	if filter.EvaluationScore_05.Min > 0 {
		sqlQuery += " AND `evaluationScore_05`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_05.Min)
	}
	if filter.EvaluationScore_05.Max > 0 {
		sqlQuery += " AND `evaluationScore_05`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_05.Max)
	}

	if filter.EvaluationScore_06.Min > 0 {
		sqlQuery += " AND `evaluationScore_06`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_06.Min)
	}
	if filter.EvaluationScore_06.Max > 0 {
		sqlQuery += " AND `evaluationScore_06`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_06.Max)
	}

	if filter.EvaluationScore_07.Min > 0 {
		sqlQuery += " AND `evaluationScore_07`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_07.Min)
	}
	if filter.EvaluationScore_07.Max > 0 {
		sqlQuery += " AND `evaluationScore_07`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_07.Max)
	}

	if filter.EvaluationScore_08.Min > 0 {
		sqlQuery += " AND `evaluationScore_08`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_08.Min)
	}
	if filter.EvaluationScore_08.Max > 0 {
		sqlQuery += " AND `evaluationScore_08`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_08.Max)
	}

	if filter.EvaluationScore_09.Min > 0 {
		sqlQuery += " AND `evaluationScore_09`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_09.Min)
	}
	if filter.EvaluationScore_09.Max > 0 {
		sqlQuery += " AND `evaluationScore_09`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_09.Max)
	}

	if filter.EvaluationScore_10.Min > 0 {
		sqlQuery += " AND `evaluationScore_10`>=" + fmt.Sprintf("%.6f", filter.EvaluationScore_10.Min)
	}
	if filter.EvaluationScore_10.Max > 0 {
		sqlQuery += " AND `evaluationScore_10`<=" + fmt.Sprintf("%.6f", filter.EvaluationScore_10.Max)
	}

	sqlQuery += ";"
	_, err = sqlparser.Parse(sqlQuery)
	if err != nil {
		return tempList, err
	}

	rows, err := common.MYDB.Query(sqlQuery)
	if err != nil {
		common.CBLog.Error(err)
		return tempList, err
	}

	cols, err := rows.Columns()
	if err != nil {
		common.CBLog.Error(err)
		return tempList, err
	}

	for rows.Next() {
		columns := make([]interface{}, len(cols))
		columnPointers := make([]interface{}, len(cols))
		for i := range columns {
			columnPointers[i] = &columns[i]
		}

		if err := rows.Scan(columnPointers...); err != nil {
			return tempList, err
		}
		m := make(map[string]interface{})
		for i, colName := range cols {
			val := columnPointers[i].(*interface{})
			m[colName] = *val
		}
		js, _ := json.Marshal(m)
		tempSpec := TbSpecInfo{}
		err = json.Unmarshal(js, &tempSpec)
		if err != nil {
			common.CBLog.Error(err)
			return nil, err
		}
		tempList = append(tempList, tempSpec)
	}
	return tempList, nil
}

// SortSpecs accepts the list of TB spec objects, criteria and sorting direction,
// sorts and returns the sorted list of TB spec objects
func SortSpecs(specList []TbSpecInfo, orderBy string, direction string) ([]TbSpecInfo, error) {
	var err error = nil

	sort.Slice(specList, func(i, j int) bool {
		if orderBy == "num_vCPU" {
			if direction == "descending" {
				return specList[i].Num_vCPU > specList[j].Num_vCPU
			} else if direction == "ascending" {
				return specList[i].Num_vCPU < specList[j].Num_vCPU
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "mem_GiB" {
			if direction == "descending" {
				return specList[i].Mem_GiB > specList[j].Mem_GiB
			} else if direction == "ascending" {
				return specList[i].Mem_GiB < specList[j].Mem_GiB
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "storage_GiB" {
			if direction == "descending" {
				return specList[i].Storage_GiB > specList[j].Storage_GiB
			} else if direction == "ascending" {
				return specList[i].Storage_GiB < specList[j].Storage_GiB
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_01" {
			if direction == "descending" {
				return specList[i].EvaluationScore_01 > specList[j].EvaluationScore_01
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_01 < specList[j].EvaluationScore_01
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_02" {
			if direction == "descending" {
				return specList[i].EvaluationScore_02 > specList[j].EvaluationScore_02
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_02 < specList[j].EvaluationScore_02
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_03" {
			if direction == "descending" {
				return specList[i].EvaluationScore_03 > specList[j].EvaluationScore_03
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_03 < specList[j].EvaluationScore_03
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_04" {
			if direction == "descending" {
				return specList[i].EvaluationScore_04 > specList[j].EvaluationScore_04
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_04 < specList[j].EvaluationScore_04
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_05" {
			if direction == "descending" {
				return specList[i].EvaluationScore_05 > specList[j].EvaluationScore_05
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_05 < specList[j].EvaluationScore_05
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_06" {
			if direction == "descending" {
				return specList[i].EvaluationScore_06 > specList[j].EvaluationScore_06
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_06 < specList[j].EvaluationScore_06
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_07" {
			if direction == "descending" {
				return specList[i].EvaluationScore_07 > specList[j].EvaluationScore_07
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_07 < specList[j].EvaluationScore_07
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_08" {
			if direction == "descending" {
				return specList[i].EvaluationScore_08 > specList[j].EvaluationScore_08
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_08 < specList[j].EvaluationScore_08
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_09" {
			if direction == "descending" {
				return specList[i].EvaluationScore_09 > specList[j].EvaluationScore_09
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_09 < specList[j].EvaluationScore_09
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else if orderBy == "evaluationScore_10" {
			if direction == "descending" {
				return specList[i].EvaluationScore_10 > specList[j].EvaluationScore_10
			} else if direction == "ascending" {
				return specList[i].EvaluationScore_10 < specList[j].EvaluationScore_10
			} else {
				err = fmt.Errorf("'direction' should one of these: ascending, descending")
				return true
			}
		} else {
			err = fmt.Errorf("'orderBy' should one of these: num_vCPU, mem_GiB, storage_GiB")
			return true
		}
	})

	for i := range specList {
		specList[i].OrderInFilteredResult = uint16(i + 1)
	}

	return specList, err
}

// UpdateSpec accepts to-be TB spec objects,
// updates and returns the updated TB spec objects
func UpdateSpec(nsId string, newSpec TbSpecInfo) (TbSpecInfo, error) {
	resourceType := common.StrSpec

	err := common.CheckString(nsId)
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	err = common.CheckString(newSpec.Id)
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	check, _ := CheckResource(nsId, resourceType, newSpec.Id)

	if !check {
		temp := TbSpecInfo{}
		err := fmt.Errorf("The spec " + newSpec.Id + " does not exist.")
		return temp, err
	}

	tempInterface, err := GetResource(nsId, resourceType, newSpec.Id)
	if err != nil {
		temp := TbSpecInfo{}
		err := fmt.Errorf("Failed to get the spec " + newSpec.Id + ".")
		return temp, err
	}
	tempSpec := TbSpecInfo{}
	err = common.CopySrcToDest(&tempInterface, &tempSpec)
	if err != nil {
		temp := TbSpecInfo{}
		err := fmt.Errorf("Failed to CopySrcToDest() " + newSpec.Id + ".")
		return temp, err
	}

	sqlQuery := "UPDATE `spec` SET `id`='" + newSpec.Id + "'"

	if newSpec.Name != "" {
		tempSpec.Name = newSpec.Name
		sqlQuery += ", `name`='" + newSpec.Name + "'"
	}
	if newSpec.Os_type != "" {
		tempSpec.Os_type = newSpec.Os_type
		sqlQuery += ", `os_type`='" + newSpec.Os_type + "'"
	}
	if newSpec.Num_vCPU > 0 {
		tempSpec.Num_vCPU = newSpec.Num_vCPU
		sqlQuery += ", `num_vCPU`='" + strconv.Itoa(int(newSpec.Num_vCPU)) + "'"
	}
	if newSpec.Num_core > 0 {
		tempSpec.Num_core = newSpec.Num_core
		sqlQuery += ", `num_core`='" + strconv.Itoa(int(newSpec.Num_core)) + "'"
	}
	if newSpec.Mem_GiB > 0 {
		tempSpec.Mem_GiB = newSpec.Mem_GiB
		sqlQuery += ", `mem_GiB`='" + strconv.Itoa(int(newSpec.Mem_GiB)) + "'"
	}
	if newSpec.Storage_GiB > 0 {
		tempSpec.Storage_GiB = newSpec.Storage_GiB
		sqlQuery += ", `storage_GiB`='" + strconv.Itoa(int(newSpec.Storage_GiB)) + "'"
	}
	if newSpec.Description != "" {
		tempSpec.Description = newSpec.Description
		sqlQuery += ", `description`='" + newSpec.Description + "'"
	}
	if newSpec.Cost_per_hour > 0 {
		tempSpec.Cost_per_hour = newSpec.Cost_per_hour
		sqlQuery += ", `cost_per_hour`='" + fmt.Sprintf("%.6f", newSpec.Cost_per_hour) + "'"
	}
	if newSpec.Num_storage > 0 {
		tempSpec.Num_storage = newSpec.Num_storage
		sqlQuery += ", `num_storage`='" + strconv.Itoa(int(newSpec.Num_storage)) + "'"
	}
	if newSpec.Max_num_storage > 0 {
		tempSpec.Max_num_storage = newSpec.Max_num_storage
		sqlQuery += ", `max_num_storage`='" + strconv.Itoa(int(newSpec.Max_num_storage)) + "'"
	}
	if newSpec.Max_total_storage_TiB > 0 {
		tempSpec.Max_total_storage_TiB = newSpec.Max_total_storage_TiB
		sqlQuery += ", `max_total_storage_TiB`='" + strconv.Itoa(int(newSpec.Max_total_storage_TiB)) + "'"
	}
	if newSpec.Net_bw_Gbps > 0 {
		tempSpec.Net_bw_Gbps = newSpec.Net_bw_Gbps
		sqlQuery += ", `net_bw_Gbps`='" + strconv.Itoa(int(newSpec.Net_bw_Gbps)) + "'"
	}
	if newSpec.Ebs_bw_Mbps > 0 {
		tempSpec.Ebs_bw_Mbps = newSpec.Ebs_bw_Mbps
		sqlQuery += ", `ebs_bw_Mbps`='" + strconv.Itoa(int(newSpec.Ebs_bw_Mbps)) + "'"
	}
	if newSpec.Gpu_model != "" {
		tempSpec.Gpu_model = newSpec.Gpu_model
		sqlQuery += ", `gpu_model`='" + newSpec.Gpu_model + "'"
	}
	if newSpec.Num_gpu > 0 {
		tempSpec.Num_gpu = newSpec.Num_gpu
		sqlQuery += ", `num_gpu`='" + strconv.Itoa(int(newSpec.Num_gpu)) + "'"
	}
	if newSpec.Gpumem_GiB > 0 {
		tempSpec.Gpumem_GiB = newSpec.Gpumem_GiB
		sqlQuery += ", `gpumem_GiB`='" + strconv.Itoa(int(newSpec.Gpumem_GiB)) + "'"
	}
	if newSpec.Gpu_p2p != "" {
		tempSpec.Gpu_p2p = newSpec.Gpu_p2p
		sqlQuery += ", `gpu_p2p`='" + newSpec.Gpu_p2p + "'"
	}
	if newSpec.OrderInFilteredResult > 0 {
		tempSpec.OrderInFilteredResult = newSpec.OrderInFilteredResult
		sqlQuery += ", `orderInFilteredResult`='" + strconv.Itoa(int(newSpec.OrderInFilteredResult)) + "'"
	}
	if newSpec.EvaluationStatus != "" {
		tempSpec.EvaluationStatus = newSpec.EvaluationStatus
		sqlQuery += ", `evaluationStatus`='" + newSpec.EvaluationStatus + "'"
	}
	if newSpec.EvaluationScore_01 > 0 {
		tempSpec.EvaluationScore_01 = newSpec.EvaluationScore_01
		sqlQuery += ", `evaluationScore_01`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_01) + "'"
	}
	if newSpec.EvaluationScore_02 > 0 {
		tempSpec.EvaluationScore_02 = newSpec.EvaluationScore_02
		sqlQuery += ", `evaluationScore_02`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_02) + "'"
	}
	if newSpec.EvaluationScore_03 > 0 {
		tempSpec.EvaluationScore_03 = newSpec.EvaluationScore_03
		sqlQuery += ", `evaluationScore_03`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_03) + "'"
	}
	if newSpec.EvaluationScore_04 > 0 {
		tempSpec.EvaluationScore_04 = newSpec.EvaluationScore_04
		sqlQuery += ", `evaluationScore_04`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_04) + "'"
	}
	if newSpec.EvaluationScore_05 > 0 {
		tempSpec.EvaluationScore_05 = newSpec.EvaluationScore_05
		sqlQuery += ", `evaluationScore_05`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_05) + "'"
	}
	if newSpec.EvaluationScore_06 > 0 {
		tempSpec.EvaluationScore_06 = newSpec.EvaluationScore_06
		sqlQuery += ", `evaluationScore_06`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_06) + "'"
	}
	if newSpec.EvaluationScore_07 > 0 {
		tempSpec.EvaluationScore_07 = newSpec.EvaluationScore_07
		sqlQuery += ", `evaluationScore_07`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_07) + "'"
	}
	if newSpec.EvaluationScore_08 > 0 {
		tempSpec.EvaluationScore_08 = newSpec.EvaluationScore_08
		sqlQuery += ", `evaluationScore_08`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_08) + "'"
	}
	if newSpec.EvaluationScore_09 > 0 {
		tempSpec.EvaluationScore_09 = newSpec.EvaluationScore_09
		sqlQuery += ", `evaluationScore_09`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_09) + "'"
	}
	if newSpec.EvaluationScore_10 > 0 {
		tempSpec.EvaluationScore_10 = newSpec.EvaluationScore_10
		sqlQuery += ", `evaluationScore_10`='" + fmt.Sprintf("%.6f", newSpec.EvaluationScore_10) + "'"
	}

	sqlQuery += "WHERE `namespace`='" + nsId + "' AND `id`='" + newSpec.Id + "';"

	fmt.Println("sqlQuery: " + sqlQuery)
	// https://stackoverflow.com/questions/42486032/golang-sql-query-syntax-validator
	_, err = sqlparser.Parse(sqlQuery)
	if err != nil {
		temp := TbSpecInfo{}
		return temp, err
	}

	// cb-store
	fmt.Println("=========================== PUT registerSpec")
	Key := common.GenResourceKey(nsId, resourceType, tempSpec.Id)
	Val, _ := json.Marshal(tempSpec)
	err = common.CBStore.Put(string(Key), string(Val))
	if err != nil {
		temp := TbSpecInfo{}
		common.CBLog.Error(err)
		return temp, err
	}
	keyValue, _ := common.CBStore.Get(string(Key))
	fmt.Println("<" + keyValue.Key + "> \n" + keyValue.Value)
	fmt.Println("===========================")

	// register information related with MCIS recommendation
	err = RegisterRecommendList(nsId, tempSpec.ConnectionName, tempSpec.Num_vCPU, tempSpec.Mem_GiB, tempSpec.Storage_GiB, tempSpec.Id, tempSpec.Cost_per_hour)
	if err != nil {
		common.CBLog.Error(err)
		return tempSpec, err
	}

	stmt, err := common.MYDB.Prepare(sqlQuery)
	if err != nil {
		fmt.Println(err.Error())
	}
	_, err = stmt.Exec()
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Data inserted successfully..")
	}

	return tempSpec, nil
}

repository: innodreamer/cb-tumblebug

repo_name: innodreamer/cb-tumblebug

branch_name: refs/heads/main


text:
// Code generated by SQLBoiler 4.2.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.

package models

import (
	"context"
	"database/sql"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/friendsofgo/errors"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/volatiletech/sqlboiler/v4/queries/qmhelper"
	"github.com/volatiletech/strmangle"
)

// ServiceEndpoint is an object representing the database table.
type ServiceEndpoint struct {
	ID        int64  `boil:"id" json:"id" toml:"id" yaml:"id"`
	ServiceID int64  `boil:"service_id" json:"service_id" toml:"service_id" yaml:"service_id"`
	Code      string `boil:"code" json:"code" toml:"code" yaml:"code"`
	Name      string `boil:"name" json:"name" toml:"name" yaml:"name"`

	R *serviceEndpointR `boil:"-" json:"-" toml:"-" yaml:"-"`
	L serviceEndpointL  `boil:"-" json:"-" toml:"-" yaml:"-"`
}

var ServiceEndpointColumns = struct {
	ID        string
	ServiceID string
	Code      string
	Name      string
}{
	ID:        "id",
	ServiceID: "service_id",
	Code:      "code",
	Name:      "name",
}

// Generated where

var ServiceEndpointWhere = struct {
	ID        whereHelperint64
	ServiceID whereHelperint64
	Code      whereHelperstring
	Name      whereHelperstring
}{
	ID:        whereHelperint64{field: "\"service_endpoint\".\"id\""},
	ServiceID: whereHelperint64{field: "\"service_endpoint\".\"service_id\""},
	Code:      whereHelperstring{field: "\"service_endpoint\".\"code\""},
	Name:      whereHelperstring{field: "\"service_endpoint\".\"name\""},
}

// ServiceEndpointRels is where relationship names are stored.
var ServiceEndpointRels = struct {
	Service                                              string
	DependencyServiceEndpointServiceEndpointDependencies string
	ServiceEndpointDependencies                          string
}{
	Service: "Service",
	DependencyServiceEndpointServiceEndpointDependencies: "DependencyServiceEndpointServiceEndpointDependencies",
	ServiceEndpointDependencies:                          "ServiceEndpointDependencies",
}

// serviceEndpointR is where relationships are stored.
type serviceEndpointR struct {
	Service                                              *Service                       `boil:"Service" json:"Service" toml:"Service" yaml:"Service"`
	DependencyServiceEndpointServiceEndpointDependencies ServiceEndpointDependencySlice `boil:"DependencyServiceEndpointServiceEndpointDependencies" json:"DependencyServiceEndpointServiceEndpointDependencies" toml:"DependencyServiceEndpointServiceEndpointDependencies" yaml:"DependencyServiceEndpointServiceEndpointDependencies"`
	ServiceEndpointDependencies                          ServiceEndpointDependencySlice `boil:"ServiceEndpointDependencies" json:"ServiceEndpointDependencies" toml:"ServiceEndpointDependencies" yaml:"ServiceEndpointDependencies"`
}

// NewStruct creates a new relationship struct
func (*serviceEndpointR) NewStruct() *serviceEndpointR {
	return &serviceEndpointR{}
}

// serviceEndpointL is where Load methods for each relationship are stored.
type serviceEndpointL struct{}

var (
	serviceEndpointAllColumns            = []string{"id", "service_id", "code", "name"}
	serviceEndpointColumnsWithoutDefault = []string{"service_id", "code", "name"}
	serviceEndpointColumnsWithDefault    = []string{"id"}
	serviceEndpointPrimaryKeyColumns     = []string{"id"}
)

type (
	// ServiceEndpointSlice is an alias for a slice of pointers to ServiceEndpoint.
	// This should generally be used opposed to []ServiceEndpoint.
	ServiceEndpointSlice []*ServiceEndpoint
	// ServiceEndpointHook is the signature for custom ServiceEndpoint hook methods
	ServiceEndpointHook func(context.Context, boil.ContextExecutor, *ServiceEndpoint) error

	serviceEndpointQuery struct {
		*queries.Query
	}
)

// Cache for insert, update and upsert
var (
	serviceEndpointType                 = reflect.TypeOf(&ServiceEndpoint{})
	serviceEndpointMapping              = queries.MakeStructMapping(serviceEndpointType)
	serviceEndpointPrimaryKeyMapping, _ = queries.BindMapping(serviceEndpointType, serviceEndpointMapping, serviceEndpointPrimaryKeyColumns)
	serviceEndpointInsertCacheMut       sync.RWMutex
	serviceEndpointInsertCache          = make(map[string]insertCache)
	serviceEndpointUpdateCacheMut       sync.RWMutex
	serviceEndpointUpdateCache          = make(map[string]updateCache)
	serviceEndpointUpsertCacheMut       sync.RWMutex
	serviceEndpointUpsertCache          = make(map[string]insertCache)
)

var (
	// Force time package dependency for automated UpdatedAt/CreatedAt.
	_ = time.Second
	// Force qmhelper dependency for where clause generation (which doesn't
	// always happen)
	_ = qmhelper.Where
)

var serviceEndpointBeforeInsertHooks []ServiceEndpointHook
var serviceEndpointBeforeUpdateHooks []ServiceEndpointHook
var serviceEndpointBeforeDeleteHooks []ServiceEndpointHook
var serviceEndpointBeforeUpsertHooks []ServiceEndpointHook

var serviceEndpointAfterInsertHooks []ServiceEndpointHook
var serviceEndpointAfterSelectHooks []ServiceEndpointHook
var serviceEndpointAfterUpdateHooks []ServiceEndpointHook
var serviceEndpointAfterDeleteHooks []ServiceEndpointHook
var serviceEndpointAfterUpsertHooks []ServiceEndpointHook

// doBeforeInsertHooks executes all "before insert" hooks.
func (o *ServiceEndpoint) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointBeforeInsertHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doBeforeUpdateHooks executes all "before Update" hooks.
func (o *ServiceEndpoint) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointBeforeUpdateHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doBeforeDeleteHooks executes all "before Delete" hooks.
func (o *ServiceEndpoint) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointBeforeDeleteHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doBeforeUpsertHooks executes all "before Upsert" hooks.
func (o *ServiceEndpoint) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointBeforeUpsertHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doAfterInsertHooks executes all "after Insert" hooks.
func (o *ServiceEndpoint) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointAfterInsertHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doAfterSelectHooks executes all "after Select" hooks.
func (o *ServiceEndpoint) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointAfterSelectHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doAfterUpdateHooks executes all "after Update" hooks.
func (o *ServiceEndpoint) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointAfterUpdateHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doAfterDeleteHooks executes all "after Delete" hooks.
func (o *ServiceEndpoint) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointAfterDeleteHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// doAfterUpsertHooks executes all "after Upsert" hooks.
func (o *ServiceEndpoint) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
	if boil.HooksAreSkipped(ctx) {
		return nil
	}

	for _, hook := range serviceEndpointAfterUpsertHooks {
		if err := hook(ctx, exec, o); err != nil {
			return err
		}
	}

	return nil
}

// AddServiceEndpointHook registers your hook function for all future operations.
func AddServiceEndpointHook(hookPoint boil.HookPoint, serviceEndpointHook ServiceEndpointHook) {
	switch hookPoint {
	case boil.BeforeInsertHook:
		serviceEndpointBeforeInsertHooks = append(serviceEndpointBeforeInsertHooks, serviceEndpointHook)
	case boil.BeforeUpdateHook:
		serviceEndpointBeforeUpdateHooks = append(serviceEndpointBeforeUpdateHooks, serviceEndpointHook)
	case boil.BeforeDeleteHook:
		serviceEndpointBeforeDeleteHooks = append(serviceEndpointBeforeDeleteHooks, serviceEndpointHook)
	case boil.BeforeUpsertHook:
		serviceEndpointBeforeUpsertHooks = append(serviceEndpointBeforeUpsertHooks, serviceEndpointHook)
	case boil.AfterInsertHook:
		serviceEndpointAfterInsertHooks = append(serviceEndpointAfterInsertHooks, serviceEndpointHook)
	case boil.AfterSelectHook:
		serviceEndpointAfterSelectHooks = append(serviceEndpointAfterSelectHooks, serviceEndpointHook)
	case boil.AfterUpdateHook:
		serviceEndpointAfterUpdateHooks = append(serviceEndpointAfterUpdateHooks, serviceEndpointHook)
	case boil.AfterDeleteHook:
		serviceEndpointAfterDeleteHooks = append(serviceEndpointAfterDeleteHooks, serviceEndpointHook)
	case boil.AfterUpsertHook:
		serviceEndpointAfterUpsertHooks = append(serviceEndpointAfterUpsertHooks, serviceEndpointHook)
	}
}

// One returns a single serviceEndpoint record from the query.
func (q serviceEndpointQuery) One(ctx context.Context, exec boil.ContextExecutor) (*ServiceEndpoint, error) {
	o := &ServiceEndpoint{}

	queries.SetLimit(q.Query, 1)

	err := q.Bind(ctx, exec, o)
	if err != nil {
		if errors.Cause(err) == sql.ErrNoRows {
			return nil, sql.ErrNoRows
		}
		return nil, errors.Wrap(err, "models: failed to execute a one query for service_endpoint")
	}

	if err := o.doAfterSelectHooks(ctx, exec); err != nil {
		return o, err
	}

	return o, nil
}

// All returns all ServiceEndpoint records from the query.
func (q serviceEndpointQuery) All(ctx context.Context, exec boil.ContextExecutor) (ServiceEndpointSlice, error) {
	var o []*ServiceEndpoint

	err := q.Bind(ctx, exec, &o)
	if err != nil {
		return nil, errors.Wrap(err, "models: failed to assign all query results to ServiceEndpoint slice")
	}

	if len(serviceEndpointAfterSelectHooks) != 0 {
		for _, obj := range o {
			if err := obj.doAfterSelectHooks(ctx, exec); err != nil {
				return o, err
			}
		}
	}

	return o, nil
}

// Count returns the count of all ServiceEndpoint records in the query.
func (q serviceEndpointQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
	var count int64

	queries.SetSelect(q.Query, nil)
	queries.SetCount(q.Query)

	err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
	if err != nil {
		return 0, errors.Wrap(err, "models: failed to count service_endpoint rows")
	}

	return count, nil
}

// Exists checks if the row exists in the table.
func (q serviceEndpointQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) {
	var count int64

	queries.SetSelect(q.Query, nil)
	queries.SetCount(q.Query)
	queries.SetLimit(q.Query, 1)

	err := q.Query.QueryRowContext(ctx, exec).Scan(&count)
	if err != nil {
		return false, errors.Wrap(err, "models: failed to check if service_endpoint exists")
	}

	return count > 0, nil
}

// Service pointed to by the foreign key.
func (o *ServiceEndpoint) Service(mods ...qm.QueryMod) serviceQuery {
	queryMods := []qm.QueryMod{
		qm.Where("\"id\" = ?", o.ServiceID),
	}

	queryMods = append(queryMods, mods...)

	query := Services(queryMods...)
	queries.SetFrom(query.Query, "\"service\"")

	return query
}

// DependencyServiceEndpointServiceEndpointDependencies retrieves all the service_endpoint_dependency's ServiceEndpointDependencies with an executor via dependency_service_endpoint_id column.
func (o *ServiceEndpoint) DependencyServiceEndpointServiceEndpointDependencies(mods ...qm.QueryMod) serviceEndpointDependencyQuery {
	var queryMods []qm.QueryMod
	if len(mods) != 0 {
		queryMods = append(queryMods, mods...)
	}

	queryMods = append(queryMods,
		qm.Where("\"service_endpoint_dependency\".\"dependency_service_endpoint_id\"=?", o.ID),
	)

	query := ServiceEndpointDependencies(queryMods...)
	queries.SetFrom(query.Query, "\"service_endpoint_dependency\"")

	if len(queries.GetSelect(query.Query)) == 0 {
		queries.SetSelect(query.Query, []string{"\"service_endpoint_dependency\".*"})
	}

	return query
}

// ServiceEndpointDependencies retrieves all the service_endpoint_dependency's ServiceEndpointDependencies with an executor.
func (o *ServiceEndpoint) ServiceEndpointDependencies(mods ...qm.QueryMod) serviceEndpointDependencyQuery {
	var queryMods []qm.QueryMod
	if len(mods) != 0 {
		queryMods = append(queryMods, mods...)
	}

	queryMods = append(queryMods,
		qm.Where("\"service_endpoint_dependency\".\"service_endpoint_id\"=?", o.ID),
	)

	query := ServiceEndpointDependencies(queryMods...)
	queries.SetFrom(query.Query, "\"service_endpoint_dependency\"")

	if len(queries.GetSelect(query.Query)) == 0 {
		queries.SetSelect(query.Query, []string{"\"service_endpoint_dependency\".*"})
	}

	return query
}

// LoadService allows an eager lookup of values, cached into the
// loaded structs of the objects. This is for an N-1 relationship.
func (serviceEndpointL) LoadService(ctx context.Context, e boil.ContextExecutor, singular bool, maybeServiceEndpoint interface{}, mods queries.Applicator) error {
	var slice []*ServiceEndpoint
	var object *ServiceEndpoint

	if singular {
		object = maybeServiceEndpoint.(*ServiceEndpoint)
	} else {
		slice = *maybeServiceEndpoint.(*[]*ServiceEndpoint)
	}

	args := make([]interface{}, 0, 1)
	if singular {
		if object.R == nil {
			object.R = &serviceEndpointR{}
		}
		args = append(args, object.ServiceID)

	} else {
	Outer:
		for _, obj := range slice {
			if obj.R == nil {
				obj.R = &serviceEndpointR{}
			}

			for _, a := range args {
				if a == obj.ServiceID {
					continue Outer
				}
			}

			args = append(args, obj.ServiceID)

		}
	}

	if len(args) == 0 {
		return nil
	}

	query := NewQuery(
		qm.From(`service`),
		qm.WhereIn(`service.id in ?`, args...),
	)
	if mods != nil {
		mods.Apply(query)
	}

	results, err := query.QueryContext(ctx, e)
	if err != nil {
		return errors.Wrap(err, "failed to eager load Service")
	}

	var resultSlice []*Service
	if err = queries.Bind(results, &resultSlice); err != nil {
		return errors.Wrap(err, "failed to bind eager loaded slice Service")
	}

	if err = results.Close(); err != nil {
		return errors.Wrap(err, "failed to close results of eager load for service")
	}
	if err = results.Err(); err != nil {
		return errors.Wrap(err, "error occurred during iteration of eager loaded relations for service")
	}

	if len(serviceEndpointAfterSelectHooks) != 0 {
		for _, obj := range resultSlice {
			if err := obj.doAfterSelectHooks(ctx, e); err != nil {
				return err
			}
		}
	}

	if len(resultSlice) == 0 {
		return nil
	}

	if singular {
		foreign := resultSlice[0]
		object.R.Service = foreign
		if foreign.R == nil {
			foreign.R = &serviceR{}
		}
		foreign.R.ServiceEndpoints = append(foreign.R.ServiceEndpoints, object)
		return nil
	}

	for _, local := range slice {
		for _, foreign := range resultSlice {
			if local.ServiceID == foreign.ID {
				local.R.Service = foreign
				if foreign.R == nil {
					foreign.R = &serviceR{}
				}
				foreign.R.ServiceEndpoints = append(foreign.R.ServiceEndpoints, local)
				break
			}
		}
	}

	return nil
}

// LoadDependencyServiceEndpointServiceEndpointDependencies allows an eager lookup of values, cached into the
// loaded structs of the objects. This is for a 1-M or N-M relationship.
func (serviceEndpointL) LoadDependencyServiceEndpointServiceEndpointDependencies(ctx context.Context, e boil.ContextExecutor, singular bool, maybeServiceEndpoint interface{}, mods queries.Applicator) error {
	var slice []*ServiceEndpoint
	var object *ServiceEndpoint

	if singular {
		object = maybeServiceEndpoint.(*ServiceEndpoint)
	} else {
		slice = *maybeServiceEndpoint.(*[]*ServiceEndpoint)
	}

	args := make([]interface{}, 0, 1)
	if singular {
		if object.R == nil {
			object.R = &serviceEndpointR{}
		}
		args = append(args, object.ID)
	} else {
	Outer:
		for _, obj := range slice {
			if obj.R == nil {
				obj.R = &serviceEndpointR{}
			}

			for _, a := range args {
				if a == obj.ID {
					continue Outer
				}
			}

			args = append(args, obj.ID)
		}
	}

	if len(args) == 0 {
		return nil
	}

	query := NewQuery(
		qm.From(`service_endpoint_dependency`),
		qm.WhereIn(`service_endpoint_dependency.dependency_service_endpoint_id in ?`, args...),
	)
	if mods != nil {
		mods.Apply(query)
	}

	results, err := query.QueryContext(ctx, e)
	if err != nil {
		return errors.Wrap(err, "failed to eager load service_endpoint_dependency")
	}

	var resultSlice []*ServiceEndpointDependency
	if err = queries.Bind(results, &resultSlice); err != nil {
		return errors.Wrap(err, "failed to bind eager loaded slice service_endpoint_dependency")
	}

	if err = results.Close(); err != nil {
		return errors.Wrap(err, "failed to close results in eager load on service_endpoint_dependency")
	}
	if err = results.Err(); err != nil {
		return errors.Wrap(err, "error occurred during iteration of eager loaded relations for service_endpoint_dependency")
	}

	if len(serviceEndpointDependencyAfterSelectHooks) != 0 {
		for _, obj := range resultSlice {
			if err := obj.doAfterSelectHooks(ctx, e); err != nil {
				return err
			}
		}
	}
	if singular {
		object.R.DependencyServiceEndpointServiceEndpointDependencies = resultSlice
		for _, foreign := range resultSlice {
			if foreign.R == nil {
				foreign.R = &serviceEndpointDependencyR{}
			}
			foreign.R.DependencyServiceEndpoint = object
		}
		return nil
	}

	for _, foreign := range resultSlice {
		for _, local := range slice {
			if local.ID == foreign.DependencyServiceEndpointID {
				local.R.DependencyServiceEndpointServiceEndpointDependencies = append(local.R.DependencyServiceEndpointServiceEndpointDependencies, foreign)
				if foreign.R == nil {
					foreign.R = &serviceEndpointDependencyR{}
				}
				foreign.R.DependencyServiceEndpoint = local
				break
			}
		}
	}

	return nil
}

// LoadServiceEndpointDependencies allows an eager lookup of values, cached into the
// loaded structs of the objects. This is for a 1-M or N-M relationship.
func (serviceEndpointL) LoadServiceEndpointDependencies(ctx context.Context, e boil.ContextExecutor, singular bool, maybeServiceEndpoint interface{}, mods queries.Applicator) error {
	var slice []*ServiceEndpoint
	var object *ServiceEndpoint

	if singular {
		object = maybeServiceEndpoint.(*ServiceEndpoint)
	} else {
		slice = *maybeServiceEndpoint.(*[]*ServiceEndpoint)
	}

	args := make([]interface{}, 0, 1)
	if singular {
		if object.R == nil {
			object.R = &serviceEndpointR{}
		}
		args = append(args, object.ID)
	} else {
	Outer:
		for _, obj := range slice {
			if obj.R == nil {
				obj.R = &serviceEndpointR{}
			}

			for _, a := range args {
				if a == obj.ID {
					continue Outer
				}
			}

			args = append(args, obj.ID)
		}
	}

	if len(args) == 0 {
		return nil
	}

	query := NewQuery(
		qm.From(`service_endpoint_dependency`),
		qm.WhereIn(`service_endpoint_dependency.service_endpoint_id in ?`, args...),
	)
	if mods != nil {
		mods.Apply(query)
	}

	results, err := query.QueryContext(ctx, e)
	if err != nil {
		return errors.Wrap(err, "failed to eager load service_endpoint_dependency")
	}

	var resultSlice []*ServiceEndpointDependency
	if err = queries.Bind(results, &resultSlice); err != nil {
		return errors.Wrap(err, "failed to bind eager loaded slice service_endpoint_dependency")
	}

	if err = results.Close(); err != nil {
		return errors.Wrap(err, "failed to close results in eager load on service_endpoint_dependency")
	}
	if err = results.Err(); err != nil {
		return errors.Wrap(err, "error occurred during iteration of eager loaded relations for service_endpoint_dependency")
	}

	if len(serviceEndpointDependencyAfterSelectHooks) != 0 {
		for _, obj := range resultSlice {
			if err := obj.doAfterSelectHooks(ctx, e); err != nil {
				return err
			}
		}
	}
	if singular {
		object.R.ServiceEndpointDependencies = resultSlice
		for _, foreign := range resultSlice {
			if foreign.R == nil {
				foreign.R = &serviceEndpointDependencyR{}
			}
			foreign.R.ServiceEndpoint = object
		}
		return nil
	}

	for _, foreign := range resultSlice {
		for _, local := range slice {
			if local.ID == foreign.ServiceEndpointID {
				local.R.ServiceEndpointDependencies = append(local.R.ServiceEndpointDependencies, foreign)
				if foreign.R == nil {
					foreign.R = &serviceEndpointDependencyR{}
				}
				foreign.R.ServiceEndpoint = local
				break
			}
		}
	}

	return nil
}

// SetService of the serviceEndpoint to the related item.
// Sets o.R.Service to related.
// Adds o to related.R.ServiceEndpoints.
func (o *ServiceEndpoint) SetService(ctx context.Context, exec boil.ContextExecutor, insert bool, related *Service) error {
	var err error
	if insert {
		if err = related.Insert(ctx, exec, boil.Infer()); err != nil {
			return errors.Wrap(err, "failed to insert into foreign table")
		}
	}

	updateQuery := fmt.Sprintf(
		"UPDATE \"service_endpoint\" SET %s WHERE %s",
		strmangle.SetParamNames("\"", "\"", 1, []string{"service_id"}),
		strmangle.WhereClause("\"", "\"", 2, serviceEndpointPrimaryKeyColumns),
	)
	values := []interface{}{related.ID, o.ID}

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, updateQuery)
		fmt.Fprintln(writer, values)
	}
	if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil {
		return errors.Wrap(err, "failed to update local table")
	}

	o.ServiceID = related.ID
	if o.R == nil {
		o.R = &serviceEndpointR{
			Service: related,
		}
	} else {
		o.R.Service = related
	}

	if related.R == nil {
		related.R = &serviceR{
			ServiceEndpoints: ServiceEndpointSlice{o},
		}
	} else {
		related.R.ServiceEndpoints = append(related.R.ServiceEndpoints, o)
	}

	return nil
}

// AddDependencyServiceEndpointServiceEndpointDependencies adds the given related objects to the existing relationships
// of the service_endpoint, optionally inserting them as new records.
// Appends related to o.R.DependencyServiceEndpointServiceEndpointDependencies.
// Sets related.R.DependencyServiceEndpoint appropriately.
func (o *ServiceEndpoint) AddDependencyServiceEndpointServiceEndpointDependencies(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*ServiceEndpointDependency) error {
	var err error
	for _, rel := range related {
		if insert {
			rel.DependencyServiceEndpointID = o.ID
			if err = rel.Insert(ctx, exec, boil.Infer()); err != nil {
				return errors.Wrap(err, "failed to insert into foreign table")
			}
		} else {
			updateQuery := fmt.Sprintf(
				"UPDATE \"service_endpoint_dependency\" SET %s WHERE %s",
				strmangle.SetParamNames("\"", "\"", 1, []string{"dependency_service_endpoint_id"}),
				strmangle.WhereClause("\"", "\"", 2, serviceEndpointDependencyPrimaryKeyColumns),
			)
			values := []interface{}{o.ID, rel.ID}

			if boil.IsDebug(ctx) {
				writer := boil.DebugWriterFrom(ctx)
				fmt.Fprintln(writer, updateQuery)
				fmt.Fprintln(writer, values)
			}
			if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil {
				return errors.Wrap(err, "failed to update foreign table")
			}

			rel.DependencyServiceEndpointID = o.ID
		}
	}

	if o.R == nil {
		o.R = &serviceEndpointR{
			DependencyServiceEndpointServiceEndpointDependencies: related,
		}
	} else {
		o.R.DependencyServiceEndpointServiceEndpointDependencies = append(o.R.DependencyServiceEndpointServiceEndpointDependencies, related...)
	}

	for _, rel := range related {
		if rel.R == nil {
			rel.R = &serviceEndpointDependencyR{
				DependencyServiceEndpoint: o,
			}
		} else {
			rel.R.DependencyServiceEndpoint = o
		}
	}
	return nil
}

// AddServiceEndpointDependencies adds the given related objects to the existing relationships
// of the service_endpoint, optionally inserting them as new records.
// Appends related to o.R.ServiceEndpointDependencies.
// Sets related.R.ServiceEndpoint appropriately.
func (o *ServiceEndpoint) AddServiceEndpointDependencies(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*ServiceEndpointDependency) error {
	var err error
	for _, rel := range related {
		if insert {
			rel.ServiceEndpointID = o.ID
			if err = rel.Insert(ctx, exec, boil.Infer()); err != nil {
				return errors.Wrap(err, "failed to insert into foreign table")
			}
		} else {
			updateQuery := fmt.Sprintf(
				"UPDATE \"service_endpoint_dependency\" SET %s WHERE %s",
				strmangle.SetParamNames("\"", "\"", 1, []string{"service_endpoint_id"}),
				strmangle.WhereClause("\"", "\"", 2, serviceEndpointDependencyPrimaryKeyColumns),
			)
			values := []interface{}{o.ID, rel.ID}

			if boil.IsDebug(ctx) {
				writer := boil.DebugWriterFrom(ctx)
				fmt.Fprintln(writer, updateQuery)
				fmt.Fprintln(writer, values)
			}
			if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil {
				return errors.Wrap(err, "failed to update foreign table")
			}

			rel.ServiceEndpointID = o.ID
		}
	}

	if o.R == nil {
		o.R = &serviceEndpointR{
			ServiceEndpointDependencies: related,
		}
	} else {
		o.R.ServiceEndpointDependencies = append(o.R.ServiceEndpointDependencies, related...)
	}

	for _, rel := range related {
		if rel.R == nil {
			rel.R = &serviceEndpointDependencyR{
				ServiceEndpoint: o,
			}
		} else {
			rel.R.ServiceEndpoint = o
		}
	}
	return nil
}

// ServiceEndpoints retrieves all the records using an executor.
func ServiceEndpoints(mods ...qm.QueryMod) serviceEndpointQuery {
	mods = append(mods, qm.From("\"service_endpoint\""))
	return serviceEndpointQuery{NewQuery(mods...)}
}

// FindServiceEndpoint retrieves a single record by ID with an executor.
// If selectCols is empty Find will return all columns.
func FindServiceEndpoint(ctx context.Context, exec boil.ContextExecutor, iD int64, selectCols ...string) (*ServiceEndpoint, error) {
	serviceEndpointObj := &ServiceEndpoint{}

	sel := "*"
	if len(selectCols) > 0 {
		sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",")
	}
	query := fmt.Sprintf(
		"select %s from \"service_endpoint\" where \"id\"=$1", sel,
	)

	q := queries.Raw(query, iD)

	err := q.Bind(ctx, exec, serviceEndpointObj)
	if err != nil {
		if errors.Cause(err) == sql.ErrNoRows {
			return nil, sql.ErrNoRows
		}
		return nil, errors.Wrap(err, "models: unable to select from service_endpoint")
	}

	return serviceEndpointObj, nil
}

// Insert a single record using an executor.
// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts.
func (o *ServiceEndpoint) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error {
	if o == nil {
		return errors.New("models: no service_endpoint provided for insertion")
	}

	var err error

	if err := o.doBeforeInsertHooks(ctx, exec); err != nil {
		return err
	}

	nzDefaults := queries.NonZeroDefaultSet(serviceEndpointColumnsWithDefault, o)

	key := makeCacheKey(columns, nzDefaults)
	serviceEndpointInsertCacheMut.RLock()
	cache, cached := serviceEndpointInsertCache[key]
	serviceEndpointInsertCacheMut.RUnlock()

	if !cached {
		wl, returnColumns := columns.InsertColumnSet(
			serviceEndpointAllColumns,
			serviceEndpointColumnsWithDefault,
			serviceEndpointColumnsWithoutDefault,
			nzDefaults,
		)

		cache.valueMapping, err = queries.BindMapping(serviceEndpointType, serviceEndpointMapping, wl)
		if err != nil {
			return err
		}
		cache.retMapping, err = queries.BindMapping(serviceEndpointType, serviceEndpointMapping, returnColumns)
		if err != nil {
			return err
		}
		if len(wl) != 0 {
			cache.query = fmt.Sprintf("INSERT INTO \"service_endpoint\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1))
		} else {
			cache.query = "INSERT INTO \"service_endpoint\" %sDEFAULT VALUES%s"
		}

		var queryOutput, queryReturning string

		if len(cache.retMapping) != 0 {
			queryReturning = fmt.Sprintf(" RETURNING \"%s\"", strings.Join(returnColumns, "\",\""))
		}

		cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
	}

	value := reflect.Indirect(reflect.ValueOf(o))
	vals := queries.ValuesFromMapping(value, cache.valueMapping)

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, cache.query)
		fmt.Fprintln(writer, vals)
	}

	if len(cache.retMapping) != 0 {
		err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
	} else {
		_, err = exec.ExecContext(ctx, cache.query, vals...)
	}

	if err != nil {
		return errors.Wrap(err, "models: unable to insert into service_endpoint")
	}

	if !cached {
		serviceEndpointInsertCacheMut.Lock()
		serviceEndpointInsertCache[key] = cache
		serviceEndpointInsertCacheMut.Unlock()
	}

	return o.doAfterInsertHooks(ctx, exec)
}

// Update uses an executor to update the ServiceEndpoint.
// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates.
// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records.
func (o *ServiceEndpoint) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) {
	var err error
	if err = o.doBeforeUpdateHooks(ctx, exec); err != nil {
		return 0, err
	}
	key := makeCacheKey(columns, nil)
	serviceEndpointUpdateCacheMut.RLock()
	cache, cached := serviceEndpointUpdateCache[key]
	serviceEndpointUpdateCacheMut.RUnlock()

	if !cached {
		wl := columns.UpdateColumnSet(
			serviceEndpointAllColumns,
			serviceEndpointPrimaryKeyColumns,
		)

		if !columns.IsWhitelist() {
			wl = strmangle.SetComplement(wl, []string{"created_at"})
		}
		if len(wl) == 0 {
			return 0, errors.New("models: unable to update service_endpoint, could not build whitelist")
		}

		cache.query = fmt.Sprintf("UPDATE \"service_endpoint\" SET %s WHERE %s",
			strmangle.SetParamNames("\"", "\"", 1, wl),
			strmangle.WhereClause("\"", "\"", len(wl)+1, serviceEndpointPrimaryKeyColumns),
		)
		cache.valueMapping, err = queries.BindMapping(serviceEndpointType, serviceEndpointMapping, append(wl, serviceEndpointPrimaryKeyColumns...))
		if err != nil {
			return 0, err
		}
	}

	values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, cache.query)
		fmt.Fprintln(writer, values)
	}
	var result sql.Result
	result, err = exec.ExecContext(ctx, cache.query, values...)
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to update service_endpoint row")
	}

	rowsAff, err := result.RowsAffected()
	if err != nil {
		return 0, errors.Wrap(err, "models: failed to get rows affected by update for service_endpoint")
	}

	if !cached {
		serviceEndpointUpdateCacheMut.Lock()
		serviceEndpointUpdateCache[key] = cache
		serviceEndpointUpdateCacheMut.Unlock()
	}

	return rowsAff, o.doAfterUpdateHooks(ctx, exec)
}

// UpdateAll updates all rows with the specified column values.
func (q serviceEndpointQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
	queries.SetUpdate(q.Query, cols)

	result, err := q.Query.ExecContext(ctx, exec)
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to update all for service_endpoint")
	}

	rowsAff, err := result.RowsAffected()
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to retrieve rows affected for service_endpoint")
	}

	return rowsAff, nil
}

// UpdateAll updates all rows with the specified column values, using an executor.
func (o ServiceEndpointSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) {
	ln := int64(len(o))
	if ln == 0 {
		return 0, nil
	}

	if len(cols) == 0 {
		return 0, errors.New("models: update all requires at least one column argument")
	}

	colNames := make([]string, len(cols))
	args := make([]interface{}, len(cols))

	i := 0
	for name, value := range cols {
		colNames[i] = name
		args[i] = value
		i++
	}

	// Append all of the primary key values for each column
	for _, obj := range o {
		pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), serviceEndpointPrimaryKeyMapping)
		args = append(args, pkeyArgs...)
	}

	sql := fmt.Sprintf("UPDATE \"service_endpoint\" SET %s WHERE %s",
		strmangle.SetParamNames("\"", "\"", 1, colNames),
		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), len(colNames)+1, serviceEndpointPrimaryKeyColumns, len(o)))

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, sql)
		fmt.Fprintln(writer, args...)
	}
	result, err := exec.ExecContext(ctx, sql, args...)
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to update all in serviceEndpoint slice")
	}

	rowsAff, err := result.RowsAffected()
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all serviceEndpoint")
	}
	return rowsAff, nil
}

// Upsert attempts an insert using an executor, and does an update or ignore on conflict.
// See boil.Columns documentation for how to properly use updateColumns and insertColumns.
func (o *ServiceEndpoint) Upsert(ctx context.Context, exec boil.ContextExecutor, updateOnConflict bool, conflictColumns []string, updateColumns, insertColumns boil.Columns) error {
	if o == nil {
		return errors.New("models: no service_endpoint provided for upsert")
	}

	if err := o.doBeforeUpsertHooks(ctx, exec); err != nil {
		return err
	}

	nzDefaults := queries.NonZeroDefaultSet(serviceEndpointColumnsWithDefault, o)

	// Build cache key in-line uglily - mysql vs psql problems
	buf := strmangle.GetBuffer()
	if updateOnConflict {
		buf.WriteByte('t')
	} else {
		buf.WriteByte('f')
	}
	buf.WriteByte('.')
	for _, c := range conflictColumns {
		buf.WriteString(c)
	}
	buf.WriteByte('.')
	buf.WriteString(strconv.Itoa(updateColumns.Kind))
	for _, c := range updateColumns.Cols {
		buf.WriteString(c)
	}
	buf.WriteByte('.')
	buf.WriteString(strconv.Itoa(insertColumns.Kind))
	for _, c := range insertColumns.Cols {
		buf.WriteString(c)
	}
	buf.WriteByte('.')
	for _, c := range nzDefaults {
		buf.WriteString(c)
	}
	key := buf.String()
	strmangle.PutBuffer(buf)

	serviceEndpointUpsertCacheMut.RLock()
	cache, cached := serviceEndpointUpsertCache[key]
	serviceEndpointUpsertCacheMut.RUnlock()

	var err error

	if !cached {
		insert, ret := insertColumns.InsertColumnSet(
			serviceEndpointAllColumns,
			serviceEndpointColumnsWithDefault,
			serviceEndpointColumnsWithoutDefault,
			nzDefaults,
		)
		update := updateColumns.UpdateColumnSet(
			serviceEndpointAllColumns,
			serviceEndpointPrimaryKeyColumns,
		)

		if updateOnConflict && len(update) == 0 {
			return errors.New("models: unable to upsert service_endpoint, could not build update column list")
		}

		conflict := conflictColumns
		if len(conflict) == 0 {
			conflict = make([]string, len(serviceEndpointPrimaryKeyColumns))
			copy(conflict, serviceEndpointPrimaryKeyColumns)
		}
		cache.query = buildUpsertQueryPostgres(dialect, "\"service_endpoint\"", updateOnConflict, ret, update, conflict, insert)

		cache.valueMapping, err = queries.BindMapping(serviceEndpointType, serviceEndpointMapping, insert)
		if err != nil {
			return err
		}
		if len(ret) != 0 {
			cache.retMapping, err = queries.BindMapping(serviceEndpointType, serviceEndpointMapping, ret)
			if err != nil {
				return err
			}
		}
	}

	value := reflect.Indirect(reflect.ValueOf(o))
	vals := queries.ValuesFromMapping(value, cache.valueMapping)
	var returns []interface{}
	if len(cache.retMapping) != 0 {
		returns = queries.PtrsFromMapping(value, cache.retMapping)
	}

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, cache.query)
		fmt.Fprintln(writer, vals)
	}
	if len(cache.retMapping) != 0 {
		err = exec.QueryRowContext(ctx, cache.query, vals...).Scan(returns...)
		if err == sql.ErrNoRows {
			err = nil // Postgres doesn't return anything when there's no update
		}
	} else {
		_, err = exec.ExecContext(ctx, cache.query, vals...)
	}
	if err != nil {
		return errors.Wrap(err, "models: unable to upsert service_endpoint")
	}

	if !cached {
		serviceEndpointUpsertCacheMut.Lock()
		serviceEndpointUpsertCache[key] = cache
		serviceEndpointUpsertCacheMut.Unlock()
	}

	return o.doAfterUpsertHooks(ctx, exec)
}

// Delete deletes a single ServiceEndpoint record with an executor.
// Delete will match against the primary key column to find the record to delete.
func (o *ServiceEndpoint) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
	if o == nil {
		return 0, errors.New("models: no ServiceEndpoint provided for delete")
	}

	if err := o.doBeforeDeleteHooks(ctx, exec); err != nil {
		return 0, err
	}

	args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), serviceEndpointPrimaryKeyMapping)
	sql := "DELETE FROM \"service_endpoint\" WHERE \"id\"=$1"

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, sql)
		fmt.Fprintln(writer, args...)
	}
	result, err := exec.ExecContext(ctx, sql, args...)
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to delete from service_endpoint")
	}

	rowsAff, err := result.RowsAffected()
	if err != nil {
		return 0, errors.Wrap(err, "models: failed to get rows affected by delete for service_endpoint")
	}

	if err := o.doAfterDeleteHooks(ctx, exec); err != nil {
		return 0, err
	}

	return rowsAff, nil
}

// DeleteAll deletes all matching rows.
func (q serviceEndpointQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
	if q.Query == nil {
		return 0, errors.New("models: no serviceEndpointQuery provided for delete all")
	}

	queries.SetDelete(q.Query)

	result, err := q.Query.ExecContext(ctx, exec)
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to delete all from service_endpoint")
	}

	rowsAff, err := result.RowsAffected()
	if err != nil {
		return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for service_endpoint")
	}

	return rowsAff, nil
}

// DeleteAll deletes all rows in the slice, using an executor.
func (o ServiceEndpointSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) {
	if len(o) == 0 {
		return 0, nil
	}

	if len(serviceEndpointBeforeDeleteHooks) != 0 {
		for _, obj := range o {
			if err := obj.doBeforeDeleteHooks(ctx, exec); err != nil {
				return 0, err
			}
		}
	}

	var args []interface{}
	for _, obj := range o {
		pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), serviceEndpointPrimaryKeyMapping)
		args = append(args, pkeyArgs...)
	}

	sql := "DELETE FROM \"service_endpoint\" WHERE " +
		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, serviceEndpointPrimaryKeyColumns, len(o))

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, sql)
		fmt.Fprintln(writer, args)
	}
	result, err := exec.ExecContext(ctx, sql, args...)
	if err != nil {
		return 0, errors.Wrap(err, "models: unable to delete all from serviceEndpoint slice")
	}

	rowsAff, err := result.RowsAffected()
	if err != nil {
		return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for service_endpoint")
	}

	if len(serviceEndpointAfterDeleteHooks) != 0 {
		for _, obj := range o {
			if err := obj.doAfterDeleteHooks(ctx, exec); err != nil {
				return 0, err
			}
		}
	}

	return rowsAff, nil
}

// Reload refetches the object from the database
// using the primary keys with an executor.
func (o *ServiceEndpoint) Reload(ctx context.Context, exec boil.ContextExecutor) error {
	ret, err := FindServiceEndpoint(ctx, exec, o.ID)
	if err != nil {
		return err
	}

	*o = *ret
	return nil
}

// ReloadAll refetches every row with matching primary key column values
// and overwrites the original object slice with the newly updated slice.
func (o *ServiceEndpointSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error {
	if o == nil || len(*o) == 0 {
		return nil
	}

	slice := ServiceEndpointSlice{}
	var args []interface{}
	for _, obj := range *o {
		pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), serviceEndpointPrimaryKeyMapping)
		args = append(args, pkeyArgs...)
	}

	sql := "SELECT \"service_endpoint\".* FROM \"service_endpoint\" WHERE " +
		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 1, serviceEndpointPrimaryKeyColumns, len(*o))

	q := queries.Raw(sql, args...)

	err := q.Bind(ctx, exec, &slice)
	if err != nil {
		return errors.Wrap(err, "models: unable to reload all in ServiceEndpointSlice")
	}

	*o = slice

	return nil
}

// ServiceEndpointExists checks if the ServiceEndpoint row exists.
func ServiceEndpointExists(ctx context.Context, exec boil.ContextExecutor, iD int64) (bool, error) {
	var exists bool
	sql := "select exists(select 1 from \"service_endpoint\" where \"id\"=$1 limit 1)"

	if boil.IsDebug(ctx) {
		writer := boil.DebugWriterFrom(ctx)
		fmt.Fprintln(writer, sql)
		fmt.Fprintln(writer, iD)
	}
	row := exec.QueryRowContext(ctx, sql, iD)

	err := row.Scan(&exists)
	if err != nil {
		return false, errors.Wrap(err, "models: unable to check if service_endpoint exists")
	}

	return exists, nil
}

license: MIT

repository: yashap/crius

license_type: permissive

repo_name: yashap/crius

branch_name: refs/heads/master

gha_license_id: MIT

gha_language: Go

extension: go


text:
package gateway

import (
	"sync"
	"fmt"
	"go.uber.org/zap"
	"database/sql"
	"simpleGatewayExample/global/gdata"
	"context"
	"simpleGatewayExample/global/gconst"
	"github.com/coreos/etcd/clientv3"
	"strings"
	"strconv"
	"bytes"
	"sort"
)

type Api struct {
	// domain.group.service.version
	// 只能由字母、数字、点组成
	FullName string
	//GET POST
	Method string
	// 1.Raw: 将请求的Path直接append在upstream_value(url)后
	// 2.Indirect: 直接访问upstream_value(url)
	ProxyMode string

	// 1.直接寻址： url = upstream_value
	// 2.间接寻址: 在etcd中取出key为Api.Name的值，返回的数据结构存储在UpstreamValue
	UpstreamMode    string
	UpstreamServers []*UpstreamServer
}
//IP跟权重
type UpstreamServer struct {
	Load 	float64
	IP		string
}

type Apis struct {
	*sync.Map
}

var apis *Apis

func (a *Apis) LoadAll() {
	query := fmt.Sprintf("select * from api")
	rows,err := db.Query(query)
	if err != nil {
		Logger.Fatal("query simpleGatewayExample.api error ",zap.Error(err))
	}

	for rows.Next() {
		load(rows)
	}
}

func load(rows *sql.Rows) {
	rowApi := &gdata.API{}
	err := rows.Scan(&rowApi.ID,&rowApi.FullName,&rowApi.Company,&rowApi.Product,&rowApi.System,&rowApi.Interface, &rowApi.Version,
		&rowApi.Method, &rowApi.ProxyMode, &rowApi.UpstreamMode, &rowApi.UpstreamValue)

	if err != nil {
		Logger.Fatal("scan simpleGatewayExample.api error ",zap.Error(err))
	}

	//添加到服务组里

	api := &Api{}
	api.FullName = rowApi.FullName
	api.Method = rowApi.Method
	api.ProxyMode = rowApi.ProxyMode
	api.UpstreamMode = rowApi.UpstreamMode

	if api.UpstreamMode == "1" {
		//直接寻址 放入servers
		api.UpstreamServers = []*UpstreamServer{
			&UpstreamServer{
				Load:1,
				IP:rowApi.UpstreamValue,
			},
		}
	}else {
		//在etcd中取出key 前缀为gconst.APIsRootPath+api.FullName 的服务
		resp,err:=etcdCli.Get(context.Background(),gconst.APIsRootPath+api.FullName,clientv3.WithPrefix())
		if err != nil {
			Logger.Fatal("etcd get err",zap.Error(err))
		}
		//从etcd 读出服务报春到apis里
		servers := make([]*UpstreamServer,len(resp.Kvs))

		for _, v := range resp.Kvs {
			//从etcd 的k v 中解析出
			ip,load,_ := ipAndLoad(v.Key,v.Value)
			servers = append(servers,&UpstreamServer{
				IP:ip,
				Load:load,
			})
		}
		//负载排序
		sort.Slice(servers, func(i, j int) bool {
			return servers[i].Load < servers[j].Load
		})
		api.UpstreamServers = servers
		for _,s := range api.UpstreamServers {
			fmt.Printf("api load: %s 的最新服务器列表: %v\n", api.FullName, *s)
		}
	}

	fmt.Println(*api)
	//将服务组放入 apis里
	apis.Store(api.FullName,api)

}

func ipAndLoad(key []byte, val []byte) (string, float64, int) {
	// 解析load
	loadPath := strings.Split(string(val), "--")

	load, _ := strconv.ParseFloat(loadPath[0], 64)
	path := loadPath[1]

	// 解析出ip
	ipIndex := bytes.LastIndex(key, []byte{'/'})
	ip := "http://" + string(key[ipIndex+1:]) + path

	return ip, load, ipIndex
}

repository: cometstone/simpleGatewayExample

repo_name: cometstone/simpleGatewayExample


text:
/*
Copyright © 2019 The Nature of Software Nordic AB <lars@thenatureofsoftware.se>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

// Package misc miscellaneous functionality
package misc

import (
	"bufio"
	"crypto/sha256"
	"fmt"
	"github.com/TheNatureOfSoftware/k3pi/pkg/model"
	"github.com/dustin/go-humanize"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

// WriteCounter counts bytes written
type WriteCounter struct {
	Total uint64
}

func (wc *WriteCounter) Write(p []byte) (int, error) {
	n := len(p)
	wc.Total += uint64(n)
	wc.PrintProgress()
	return n, nil
}

// PrintProgress prints progress of bytes written
func (wc WriteCounter) PrintProgress() {
	fmt.Printf("\r%s", strings.Repeat(" ", 35))
	fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total))
}

// DownloadFile downloads a file to a resource directory
func DownloadFile(resourceDir string, filename string, url string) error {

	absPath := resourceDir + string(os.PathSeparator) + filename
	out, err := os.Create(absPath + ".tmp")
	if err != nil {
		return err
	}
	defer out.Close()
	defer os.RemoveAll(absPath + ".tmp")

	// Get the data
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return fmt.Errorf("%s - %s", url, resp.Status)
	}
	defer resp.Body.Close()

	counter := &WriteCounter{}
	_, err = io.Copy(out, io.TeeReader(resp.Body, counter))
	if err != nil {
		return err
	}

	fmt.Print("\n")

	err = os.Rename(absPath+".tmp", absPath)
	if err != nil {
		return err
	}

	return nil
}

// DownloadAndVerify downloads a file and verifies the check sum
func DownloadAndVerify(resourceDir string, download *model.RemoteAsset) error {

	err := DownloadFile(resourceDir, download.Filename, download.FileURL)
	if err != nil {
		return err
	}

	err = DownloadFile(resourceDir, download.CheckSumFilename, download.CheckSumURL)
	if err != nil {
		return err
	}

	checksum, err := ioutil.ReadFile(resourceDir + string(os.PathSeparator) + download.CheckSumFilename)
	if err != nil {
		return err
	}
	allValidCheckSums := string(checksum)

	calcSHA256, err := CalculateSHA256(resourceDir, download.Filename)
	if err != nil {
		return fmt.Errorf("failed to calculate check sum: %v", err)
	}

	if !strings.Contains(allValidCheckSums, calcSHA256) {
		return fmt.Errorf("%s check sum is not valid for %s", calcSHA256, download.Filename)
	}

	return nil
}

// CalculateSHA256 calculates SHA256 check sum for a file
func CalculateSHA256(resourceDir string, filename string) (string, error) {
	f, err := os.Open(resourceDir + string(os.PathSeparator) + filename)
	if err != nil {
		return "", err
	}
	defer f.Close()

	input := bufio.NewReader(f)

	hash := sha256.New()
	if _, err := io.Copy(hash, input); err != nil {
		log.Fatal(err)
	}
	sum := hash.Sum(nil)

	return fmt.Sprintf("%x", sum), nil
}


text:
@incollection{Salari2017a,
 address = {Cham},
 author = {Ebrahimi Salari, Mahdi and Coleman, Joseph and Toal, Daniel},
 booktitle = {3rd International Congress on Energy Efficiency and Energy Related Materials (ENEFM2015)},
 date = {2016-10-18},
 editor = {Oral, Ahmet Yavuz and Bahsi Oral, Zehra Banu},
 pages = {81--92},
 publisher = {Springer International Publishing},
 series = {Springer Proceedings in Energy},
 title = {Airborne Wind Energy---A Review},
 year = {2017}
}

extension: bib