func (q *Query) Cursor(in toolkit.M) (dbox.ICursor, error) { var e error dbname := q.Connection().Info().Database cursor := dbox.NewCursor(new(Cursor)) session := q.Session() cursor.(*Cursor).session = session // driverName := q.GetDriverDB() driverName := q.Connection().(*Connection).GetDriver() // driverName = "oracle" var QueryString string /* parts will return E - map{interface{}}interface{} where each interface{} returned is slice of interfaces --> []interface{} */ quyerParts := q.Parts() c := crowd.From(&quyerParts) groupParts := c.Group(func(x interface{}) interface{} { return x.(*dbox.QueryPart).PartType }, nil).Exec() parts := map[interface{}]interface{}{} if len(groupParts.Result.Data().([]crowd.KV)) > 0 { for _, kv := range groupParts.Result.Data().([]crowd.KV) { parts[kv.Key] = kv.Value } } fromParts, hasFrom := parts[dbox.QueryPartFrom] procedureParts, hasProcedure := parts["procedure"] freeQueryParts, hasFreeQuery := parts["freequery"] if hasFrom { tablename := "" tablename = fromParts.([]*dbox.QueryPart)[0].Value.(string) selectParts, hasSelect := parts[dbox.QueryPartSelect] var attribute string incAtt := 0 if hasSelect { for _, sl := range selectParts.([]*dbox.QueryPart) { for _, fid := range sl.Value.([]string) { if incAtt == 0 { attribute = fid } else { attribute = attribute + ", " + fid } incAtt++ } } } else { _, hasUpdate := parts[dbox.QueryPartUpdate] _, hasInsert := parts[dbox.QueryPartInsert] _, hasDelete := parts[dbox.QueryPartDelete] _, hasSave := parts[dbox.QueryPartSave] if hasUpdate || hasInsert || hasDelete || hasSave { return nil, errorlib.Error(packageName, modQuery, "Cursor", "Valid operation for a cursor is select only") } } aggrParts, hasAggr := parts[dbox.QueryPartAggr] var aggrExpression string if hasAggr { incAtt := 0 // for _, aggr := range aggrParts.([]interface{}) { for _, aggr := range aggrParts.([]*dbox.QueryPart) { // qp := aggr.(*dbox.QueryPart) /* isi qp : &{AGGR {$sum 1 Total Item}}*/ aggrInfo := aggr.Value.(dbox.AggrInfo) /* isi Aggr Info : {$sum 1 Total Item}*/ if incAtt == 0 { aggrExpression = strings.Replace(aggrInfo.Op, "$", "", 1) + "(" + cast.ToString(aggrInfo.Field) + ")" + " as \"" + aggrInfo.Alias + "\"" } else { aggrExpression += ", " + strings.Replace(aggrInfo.Op, "$", "", 1) + "(" + cast.ToString(aggrInfo.Field) + ")" + " as \"" + aggrInfo.Alias + "\"" } incAtt++ } /* isi Aggr Expression : sum(1) as 'Total Item', max(amount) as 'Max Amount', avg(amount) as 'Average Amount'*/ } var where interface{} whereParts, hasWhere := parts[dbox.QueryPartWhere] if hasWhere { fb := q.Connection().Fb() for _, p := range whereParts.([]*dbox.QueryPart) { fs := p.Value.([]*dbox.Filter) for _, f := range fs { if in != nil { f = rdbms.ReadVariable(f, in) } fb.AddFilter(f) } } where, e = fb.Build() if e != nil { return nil, errorlib.Error(packageName, modQuery, "Cursor", e.Error()) } } var orderExpression string orderParts, hasOrder := parts[dbox.QueryPartOrder] if hasOrder { qp := orderParts.([]*dbox.QueryPart)[0] for i, fid := range qp.Value.([]string) { if i == 0 { if string(fid[0]) == "-" { orderExpression = strings.Replace(fid, "-", "", 1) + " DESC" } else { orderExpression = fid + " ASC" } } else { if string(fid[0]) == "-" { orderExpression += ", " + strings.Replace(fid, "-", "", 1) + " DESC" } else { orderExpression += ", " + fid + " ASC" } } } // for _, oval := range orderParts.([]interface{}) { // qp := oval.(*dbox.QueryPart) // for i, fid := range qp.Value.([]string) { // if i == 0 { // if string(fid[0]) == "-" { // orderExpression = strings.Replace(fid, "-", "", 1) + " DESC" // } else { // orderExpression = fid + " ASC" // } // } else { // if string(fid[0]) == "-" { // orderExpression += ", " + strings.Replace(fid, "-", "", 1) + " DESC" // } else { // orderExpression += ", " + fid + " ASC" // } // } // } // } } skip := 0 skipParts, hasSkip := parts[dbox.QueryPartSkip] if hasSkip { skip = skipParts.([]*dbox.QueryPart)[0].Value.(int) } take := 0 takeParts, hasTake := parts[dbox.QueryPartTake] if hasTake { take = takeParts.([]*dbox.QueryPart)[0].Value.(int) } partGroup, hasGroup := parts[dbox.QueryPartGroup] var groupExpression string if hasGroup { for _, aggr := range partGroup.([]*dbox.QueryPart) { // qp := aggr.(*dbox.QueryPart) groupValue := aggr.Value.([]string) for i, val := range groupValue { if i == 0 { groupExpression += val } else { groupExpression += ", " + val } } } /* isi group expression : GROUP BY nama*/ } if dbname != "" && tablename != "" && e != nil && skip == 0 && take == 0 && where == nil { } if hasAggr { if hasSelect && attribute != "" { QueryString = "SELECT " + attribute + ", " + aggrExpression + " FROM " + tablename } else { QueryString = "SELECT " + aggrExpression + " FROM " + tablename } } else { if attribute == "" { QueryString = "SELECT * FROM " + tablename } else { QueryString = "SELECT " + attribute + " FROM " + tablename } } if hasWhere { QueryString += " WHERE " + cast.ToString(where) } if hasGroup { QueryString += " GROUP BY " + groupExpression } if hasOrder { QueryString += " ORDER BY " + orderExpression } if driverName == "mysql" { if hasSkip && hasTake { QueryString += " LIMIT " + cast.ToString(take) + " OFFSET " + cast.ToString(skip) } else if hasSkip && !hasTake { QueryString += " LIMIT " + cast.ToString(9999999) + " OFFSET " + cast.ToString(skip) } else if hasTake && !hasSkip { QueryString += " LIMIT " + cast.ToString(take) } } else if driverName == "mssql" { if hasSkip && hasTake { QueryString += " OFFSET " + cast.ToString(skip) + " ROWS FETCH NEXT " + cast.ToString(take) + " ROWS ONLY " } else if hasSkip && !hasTake { QueryString += " OFFSET " + cast.ToString(skip) + " ROWS" } else if hasTake && !hasSkip { top := "SELECT TOP " + cast.ToString(take) + " " QueryString = strings.Replace(QueryString, "SELECT", top, 1) } fmt.Println(" :: ", QueryString) } else if driverName == "oracle" { if hasSkip && hasTake { QueryString = "SELECT " + attribute + ", rownum as rnum FROM (" + QueryString + ") where rownum <= " + cast.ToString(take+skip) + ")" QueryString = "SELECT " + attribute + " FROM (" + QueryString + " WHERE rnum > " + cast.ToString(skip) } else if hasSkip && !hasTake { QueryString = "SELECT " + attribute + ", rownum as rnum FROM (" + QueryString + "))" QueryString = "SELECT " + attribute + " FROM (" + QueryString + " WHERE rnum > " + cast.ToString(skip) } else if hasTake && !hasSkip { QueryString = "SELECT " + attribute + ", rownum as rnum FROM (" + QueryString + ") where rownum <= " + cast.ToString(take) + ")" QueryString = "SELECT " + attribute + " FROM (" + QueryString } } else if driverName == "postgres" { if hasSkip && hasTake { QueryString += " LIMIT " + cast.ToString(take) + " OFFSET " + cast.ToString(skip) } else if hasSkip && !hasTake { QueryString += " LIMIT ALL" + " OFFSET " + cast.ToString(skip) } else if hasTake && !hasSkip { QueryString += " LIMIT " + cast.ToString(take) } } // toolkit.Println("driverName : ", driverName, " == >", QueryString) var querystmt string if where != nil { querystmt = "select count(*) from " + tablename + " where " + cast.ToString(where) } else { querystmt = "select count(*) from " + tablename } /*populate fetch.count*/ var rowCount int rows, _ := cursor.(*Cursor).session.Query(querystmt) for rows.Next() { rows.Scan(&rowCount) } if rowCount <= skip { rowCount = 0 } else { rowCount -= skip } if rowCount >= take && take > 0 { rowCount = take } cursor.(*Cursor).count = rowCount /*assign cursor.QueryString*/ cursor.(*Cursor).QueryString = QueryString } else if hasProcedure { procCommand := procedureParts.([]*dbox.QueryPart)[0].Value.(interface{}) spName := procCommand.(toolkit.M)["name"].(string) + " " params, hasParam := procCommand.(toolkit.M)["parms"] orderparam, hasOrder := procCommand.(toolkit.M)["orderparam"] ProcStatement := "" if driverName == "mysql" { paramstring := "" if hasParam && hasOrder { paramToolkit := params.(toolkit.M) orderString := orderparam.([]string) for i := 0; i < len(paramToolkit); i++ { if i == 0 { if strings.Contains(orderString[i], "@@") { paramstring = "(" + strings.Replace(orderString[i], "@@", "@", 1) } else if rdbms.StringValue(paramToolkit[orderString[i]], driverName) != "''" { paramstring = "(" + rdbms.StringValue(paramToolkit[orderString[i]], driverName) } else { paramstring = "(" } } else { if strings.Contains(orderString[i], "@@") { paramstring += ", " + strings.Replace(orderString[i], "@@", "@", 1) } else { paramstring += ", " + rdbms.StringValue(paramToolkit[orderString[i]], driverName) } } } } else if hasParam && !hasOrder { return nil, errorlib.Error(packageName, modQuery, "procedure", "please provide order parameter") } else { paramstring = "(" } paramstring += ");" ProcStatement = "CALL " + spName + paramstring } else if driverName == "mssql" { paramstring := "" incParam := 0 if hasParam { for key, val := range params.(toolkit.M) { if key != "" { if incParam == 0 { paramstring = key + " = " + rdbms.StringValue(val, driverName) + "" } else { paramstring += ", " + key + " = " + rdbms.StringValue(val, driverName) + "" } incParam += 1 } } paramstring += ";" } ProcStatement = "EXECUTE " + spName + paramstring } else if driverName == "oracle" { var paramstring string var variable string var isEmpty bool if hasParam && hasOrder { paramToolkit := params.(toolkit.M) orderString := orderparam.([]string) for i := 0; i < len(paramToolkit); i++ { if i == 0 { if strings.Contains(orderString[i], "@@") { variable = "var " + strings.Replace(orderString[i], "@@", "", 1) + " " + cast.ToString(paramToolkit[orderString[i]]) + ";" paramstring = "(" + strings.Replace(orderString[i], "@@", ":", 1) isEmpty = false } else if rdbms.StringValue(paramToolkit[orderString[i]], driverName) != "''" { paramstring = "(" + rdbms.StringValue(paramToolkit[orderString[i]], driverName) isEmpty = false } } else { if strings.Contains(orderString[i], "@@") { variable += "var " + strings.Replace(orderString[i], "@@", "", 1) + " " + cast.ToString(paramToolkit[orderString[i]]) + ";" paramstring += ", " + strings.Replace(orderString[i], "@@", ":", 1) } else { paramstring += ", " + rdbms.StringValue(paramToolkit[orderString[i]], driverName) } } } if !isEmpty { paramstring += ");" } } else if hasParam && !hasOrder { return nil, errorlib.Error(packageName, modQuery, "procedure", "please provide order parameter") } ProcStatement = variable + "EXECUTE " + spName + paramstring } else if driverName == "postgres" { paramstring := "" if hasParam && hasOrder { paramToolkit := params.(toolkit.M) orderString := orderparam.([]string) for i := 0; i < len(paramToolkit); i++ { if i == 0 { if strings.Contains(orderString[i], "@@") { paramstring = "(" + strings.Replace(orderString[i], "@@", "@", 1) } else if rdbms.StringValue(paramToolkit[orderString[i]], driverName) != "''" { paramstring = "(" + rdbms.StringValue(paramToolkit[orderString[i]], driverName) } else { paramstring = "(" } } else { if strings.Contains(orderString[i], "@@") { paramstring += ", " + strings.Replace(orderString[i], "@@", "@", 1) } else { paramstring += ", " + rdbms.StringValue(paramToolkit[orderString[i]], driverName) } } // fmt.Println("Print value order", paramstring) } } else if hasParam && !hasOrder { return nil, errorlib.Error(packageName, modQuery, "procedure", "please provide order parameter") } else { paramstring = "(" } paramstring += ")" ProcStatement = "SELECT " + spName + paramstring } cursor.(*Cursor).QueryString = ProcStatement // fmt.Println("Proc Statement : ", ProcStatement) } else if hasFreeQuery { querySyntax := freeQueryParts.([]*dbox.QueryPart)[0].Value.(interface{}) syntax := querySyntax.(toolkit.M)["syntax"].(string) cursor.(*Cursor).QueryString = syntax } return cursor, nil }
func (q *Query) prepare(in toolkit.M) (output toolkit.M, e error) { output = toolkit.M{} quyerParts := q.Parts() c := crowd.From(&quyerParts) groupParts := c.Group(func(x interface{}) interface{} { return x.(*dbox.QueryPart).PartType }, nil).Exec() parts := map[interface{}]interface{}{} if len(groupParts.Result.Data().([]crowd.KV)) > 0 { for _, kv := range groupParts.Result.Data().([]crowd.KV) { parts[kv.Key] = kv.Value } } //return nil, errorlib.Error(packageName, modQuery, "prepare", "asdaa") //fmt.Printf("Query parts: %s\n", toolkit.JsonString(q.Parts())) fromParts, hasFrom := parts[dbox.QueryPartFrom] if hasFrom == false { return nil, err.Error(packageName, "Query", "prepare", "Invalid table name") } tablename := fromParts.([]*dbox.QueryPart)[0].Value.(string) output.Set("tablename", tablename) q.jsonPath = filepath.Join(q.Connection().(*Connection).folder, tablename+".json") skip := 0 if skipParts, hasSkip := parts[dbox.QueryPartSkip]; hasSkip { skip = skipParts.([]*dbox.QueryPart)[0]. Value.(int) } output.Set("skip", skip) take := 0 if takeParts, has := parts[dbox.QueryPartTake]; has { take = takeParts.([]*dbox.QueryPart)[0]. Value.(int) } output.Set("take", take) var aggregate bool aggrParts, hasAggr := parts[dbox.QueryPartAggr] aggrExpression := toolkit.M{} if hasAggr { aggregate = true aggrElements := func() []*dbox.QueryPart { var qps []*dbox.QueryPart for _, v := range aggrParts.([]*dbox.QueryPart) { qps = append(qps, v) } return qps }() for _, el := range aggrElements { aggr := el.Value.(dbox.AggrInfo) aggrExpression.Set(aggr.Alias, toolkit.M{}.Set(aggr.Op, aggr.Field)) } } partGroup, hasGroup := parts[dbox.QueryPartGroup] if hasGroup { aggregate = true groups := func() toolkit.M { s := toolkit.M{} for _, v := range partGroup.([]*dbox.QueryPart) { gs := v.Value.([]string) for _, g := range gs { if strings.TrimSpace(g) != "" { s.Set(g, "$"+g) } } } return s }() if len(groups) == 0 { aggrExpression.Set("_id", "") } else { aggrExpression.Set("_id", groups) } } output.Set("aggregate", aggregate) output.Set("aggrExpression", aggrExpression) var fields []string selectParts, hasSelect := parts[dbox.QueryPartSelect] if hasSelect { for _, sl := range selectParts.([]*dbox.QueryPart) { // qp := sl.(*dbox.QueryPart) for _, fid := range sl.Value.([]string) { fields = append(fields, fid) } } output.Set("commandtype", dbox.QueryPartSelect) } else { _, hasUpdate := parts[dbox.QueryPartUpdate] _, hasInsert := parts[dbox.QueryPartInsert] _, hasDelete := parts[dbox.QueryPartDelete] _, hasSave := parts[dbox.QueryPartSave] if hasInsert { output.Set("commandtype", dbox.QueryPartInsert) } else if hasUpdate { output.Set("commandtype", dbox.QueryPartUpdate) } else if hasDelete { output.Set("commandtype", dbox.QueryPartDelete) } else if hasSave { output.Set("commandtype", dbox.QueryPartSave) } else { output.Set("commandtype", dbox.QueryPartSelect) } } output.Set("fields", fields) var sort []string sortParts, hasSort := parts[dbox.QueryPartOrder] if hasSort { sort = []string{} for _, sl := range sortParts.([]*dbox.QueryPart) { // qp := sl.(*dbox.QueryPart) for _, fid := range sl.Value.([]string) { sort = append(sort, fid) } } } output.Set("sort", sort) var filters []*dbox.Filter whereParts, hasWhere := parts[dbox.QueryPartWhere] if hasWhere { for _, p := range whereParts.([]*dbox.QueryPart) { fs := p.Value.([]*dbox.Filter) for _, f := range fs { if in != nil { f = rdbms.ReadVariable(f, in) } filters = append(filters, f) } } } output.Set("where", filters) return }
func (q *Query) prepare(in toolkit.M) (out toolkit.M, e error) { out = toolkit.M{} quyerParts := q.Parts() c := crowd.From(&quyerParts) groupParts := c.Group(func(x interface{}) interface{} { return x.(*dbox.QueryPart).PartType }, nil).Exec() parts := map[interface{}]interface{}{} if len(groupParts.Result.Data().([]crowd.KV)) > 0 { for _, kv := range groupParts.Result.Data().([]crowd.KV) { parts[kv.Key] = kv.Value } } _, hasUpdate := parts[dbox.QueryPartUpdate] _, hasInsert := parts[dbox.QueryPartInsert] _, hasDelete := parts[dbox.QueryPartDelete] _, hasSave := parts[dbox.QueryPartSave] _, hasFrom := parts[dbox.QueryPartFrom] procedureParts, hasProcedure := parts["procedure"] var tableName string if hasFrom { fromParts, _ := parts[dbox.QueryPartFrom] tableName = fromParts.([]*dbox.QueryPart)[0].Value.(string) } else { return nil, err.Error(packageName, "Query", "prepare", "Invalid table name") } out.Set("tableName", tableName) if freeQueryParts, hasFreeQuery := parts["freequery"]; hasFreeQuery { var syntax string qsyntax := freeQueryParts.([]*dbox.QueryPart)[0].Value.(interface{}) syntax = qsyntax.(toolkit.M)["syntax"].(string) out.Set("freequery", syntax) out.Set("cmdType", dbox.QueryPartSelect) } else if hasInsert || hasUpdate || hasDelete || hasSave { if hasUpdate { out.Set("cmdType", dbox.QueryPartUpdate) } else if hasInsert { out.Set("cmdType", dbox.QueryPartInsert) } else if hasDelete { out.Set("cmdType", dbox.QueryPartDelete) } else if hasSave { out.Set("cmdType", dbox.QueryPartSave) } var where interface{} whereParts, hasWhere := parts[dbox.QueryPartWhere] if hasWhere { fb := q.Connection().Fb() for _, p := range whereParts.([]*dbox.QueryPart) { fs := p.Value.([]*dbox.Filter) for _, f := range fs { fb.AddFilter(f) } } where, e = fb.Build() if e != nil { } out.Set("where", where) } var dataM toolkit.M var dataMs []toolkit.M hasData := in.Has("data") var dataIsSlice bool if hasData { data := in.Get("data") if toolkit.IsSlice(data) { dataIsSlice = true e = toolkit.Unjson(toolkit.Jsonify(data), dataMs) if e != nil { return nil, err.Error(packageName, modQuery, "Exec: ", "Data encoding error: "+e.Error()) } } else { dataM, e = toolkit.ToM(data) dataMs = append(dataMs, dataM) if e != nil { return nil, err.Error(packageName, modQuery, "Exec: ", "Data encoding error: "+e.Error()) } } var id string var idVal interface{} if where == nil { id, idVal = toolkit.IdInfo(data) if id != "" { where = id + " = " + StringValue(idVal, "non") } out.Set("where", where) } if !dataIsSlice { var fields string var values string var setUpdate string var inc int for field, val := range dataM { stringval := StringValue(val, "non") if inc == 0 { fields = "(" + field values = "(" + stringval setUpdate = field + " = " + stringval } else { fields += ", " + field values += ", " + stringval setUpdate += ", " + field + " = " + stringval } inc++ } fields += ")" values += ")" if hasInsert || hasSave { out.Set("fields", fields) out.Set("values", values) } if hasUpdate || hasSave { out.Set("setUpdate", setUpdate) } } } } else if hasProcedure { cmd := procedureParts.([]*dbox.QueryPart)[0].Value.(interface{}) spName := cmd.(toolkit.M)["name"].(string) + " " params, hasParams := cmd.(toolkit.M)["params"] orderparam, hasOrder := cmd.(toolkit.M)["orderparam"] ProcStatement := "" toolkit.Println(spName, params, hasParams, orderparam, hasOrder, ProcStatement) } else { var selectField string incAtt := 0 if selectParts, hasSelect := parts[dbox.QueryPartSelect]; hasSelect { for _, sl := range selectParts.([]*dbox.QueryPart) { for _, fid := range sl.Value.([]string) { if incAtt == 0 { selectField = fid } else { selectField = selectField + ", " + fid } incAtt++ } } } out.Set("cmdType", dbox.QueryPartSelect) out.Set("selectField", selectField) /// /// not yet iimplement var aggrExp string if aggrParts, hasAggr := parts[dbox.QueryPartAggr]; hasAggr { incAtt := 0 for _, aggr := range aggrParts.([]*dbox.QueryPart) { /* isi qp : &{AGGR {$sum 1 Total Item}}*/ aggrInfo := aggr.Value.(dbox.AggrInfo) /* isi Aggr Info : {$sum 1 Total Item}*/ if incAtt == 0 { aggrExp = strings.Replace(aggrInfo.Op, "$", "", 1) + "(" + toolkit.ToString(aggrInfo.Field) + ")" + " as \"" + aggrInfo.Alias + "\"" } else { aggrExp += ", " + strings.Replace(aggrInfo.Op, "$", "", 1) + "(" + toolkit.ToString(aggrInfo.Field) + ")" + " as \"" + aggrInfo.Alias + "\"" } incAtt++ } } out.Set("aggr", aggrExp) /// /// Where Condition var where interface{} if whereParts, hasWhere := parts[dbox.QueryPartWhere]; hasWhere { fb := q.Connection().Fb() for _, p := range whereParts.([]*dbox.QueryPart) { for _, f := range p.Value.([]*dbox.Filter) { if in != nil { f = rdbms.ReadVariable(f, in) } fb.AddFilter(f) } } where, e = fb.Build() if e != nil { return nil, err.Error(packageName, modQuery, "prepare", e.Error()) } } out.Set("where", where) /// /// Sort Condition var sort []string if sortParts, hasSort := parts[dbox.QueryPartOrder]; hasSort { sort = []string{} for _, sr := range sortParts.([]*dbox.QueryPart) { for _, s := range sr.Value.([]string) { sort = append(sort, s) } } } out.Set("sort", sort) /// /// Take Condition take := 0 isTake := false if takeParts, hasTake := parts[dbox.QueryPartTake]; hasTake { isTake = true take = takeParts.([]*dbox.QueryPart)[0].Value.(int) } out.Set("isTake", isTake) out.Set("take", take) /// /// Skip Condition skip := 0 isSkip := false if skipParts, hasSkip := parts[dbox.QueryPartSkip]; hasSkip { isSkip = true skip = skipParts.([]*dbox.QueryPart)[0].Value.(int) } out.Set("isSkip", isSkip) out.Set("skip", skip) /// /// Group By Condition var groupExp string hasAggr := false if groupParts, hasGroup := parts[dbox.QueryPartGroup]; hasGroup { hasAggr = true for _, pg := range groupParts.([]*dbox.QueryPart) { for i, grValue := range pg.Value.([]string) { if i == 0 { groupExp += grValue } else { groupExp += ", " + grValue } } } } out.Set("group", groupExp) out.Set("hasAggr", hasAggr) /// /// Order By Condition var orderExp string if orderParts, hasOrder := parts[dbox.QueryPartOrder]; hasOrder { for _, ordrs := range orderParts.([]*dbox.QueryPart) { for i, oVal := range ordrs.Value.([]string) { if i == 0 { if string(oVal[0]) == "-" { orderExp = strings.Replace(oVal, "-", "", 1) + " DESC" } else { orderExp = oVal + " ASC" } } else { if string(oVal[0]) == "-" { orderExp += ", " + strings.Replace(oVal, "-", "", 1) + " DESC" } else { orderExp += ", " + oVal + " ASC" } } } } } out.Set("order", orderExp) } return }