// ToColumnsValuesAndArguments maps the given columnNames and columnValues into // expr's Columns and Values, it also extracts and returns query arguments. func (tu *templateWithUtils) ToColumnsValuesAndArguments(columnNames []string, columnValues []interface{}) (*exql.Columns, *exql.Values, []interface{}, error) { var arguments []interface{} columns := new(exql.Columns) columns.Columns = make([]exql.Fragment, 0, len(columnNames)) for i := range columnNames { columns.Columns = append(columns.Columns, exql.ColumnWithName(columnNames[i])) } values := new(exql.Values) arguments = make([]interface{}, 0, len(columnValues)) values.Values = make([]exql.Fragment, 0, len(columnValues)) for i := range columnValues { switch v := columnValues[i].(type) { case *exql.Value: // Adding value. values.Values = append(values.Values, v) case exql.Value: // Adding value. values.Values = append(values.Values, &v) default: // Adding both value and placeholder. values.Values = append(values.Values, sqlPlaceholder) arguments = append(arguments, v) } } return columns, values, arguments, nil }
func (qu *updater) Set(columns ...interface{}) Updater { if len(columns) == 1 { ff, vv, err := Map(columns[0], nil) if err == nil { cvs := make([]exql.Fragment, 0, len(ff)) args := make([]interface{}, 0, len(vv)) for i := range ff { cv := &exql.ColumnValue{ Column: exql.ColumnWithName(ff[i]), Operator: qu.builder.t.AssignmentOperator, } var localArgs []interface{} cv.Value, localArgs = qu.builder.t.PlaceholderValue(vv[i]) args = append(args, localArgs...) cvs = append(cvs, cv) } qu.columnValues.Insert(cvs...) qu.columnValuesArgs = append(qu.columnValuesArgs, args...) return qu } } cv, arguments := qu.builder.t.ToColumnValues(columns) qu.columnValues.Insert(cv.ColumnValues...) qu.columnValuesArgs = append(qu.columnValuesArgs, arguments...) return qu }
func (qi *inserter) columnsToFragments(dst *[]exql.Fragment, columns []string) error { l := len(columns) f := make([]exql.Fragment, l) for i := 0; i < l; i++ { f[i] = exql.ColumnWithName(columns[i]) } *dst = append(*dst, f...) return nil }
func (qs *selector) As(alias string) Selector { if qs.table == nil { qs.setErr(errors.New("Cannot use As() without a preceding From() expression")) return qs } last := len(qs.table.Columns) - 1 if raw, ok := qs.table.Columns[last].(*exql.Raw); ok { qs.table.Columns[last] = exql.RawValue("(" + raw.Value + ") AS " + exql.ColumnWithName(alias).Compile(qs.stringer.t)) } return qs }
func columnFragments(template *templateWithUtils, columns []interface{}) ([]exql.Fragment, []interface{}, error) { l := len(columns) f := make([]exql.Fragment, l) args := []interface{}{} for i := 0; i < l; i++ { switch v := columns[i].(type) { case *selector: expanded, rawArgs := Preprocess(v.statement().Compile(v.stringer.t), v.Arguments()) f[i] = exql.RawValue(expanded) args = append(args, rawArgs...) case db.Function: fnName, fnArgs := v.Name(), v.Arguments() if len(fnArgs) == 0 { fnName = fnName + "()" } else { fnName = fnName + "(?" + strings.Repeat("?, ", len(fnArgs)-1) + ")" } expanded, fnArgs := Preprocess(fnName, fnArgs) f[i] = exql.RawValue(expanded) args = append(args, fnArgs...) case db.RawValue: expanded, rawArgs := Preprocess(v.Raw(), v.Arguments()) f[i] = exql.RawValue(expanded) args = append(args, rawArgs...) case exql.Fragment: f[i] = v case string: f[i] = exql.ColumnWithName(v) case interface{}: f[i] = exql.ColumnWithName(fmt.Sprintf("%v", v)) default: return nil, nil, fmt.Errorf("Unexpected argument type %T for Select() argument.", v) } } return f, args, nil }
func (qs *selector) OrderBy(columns ...interface{}) Selector { var sortColumns exql.SortColumns for i := range columns { var sort *exql.SortColumn switch value := columns[i].(type) { case db.RawValue: col, args := Preprocess(value.Raw(), value.Arguments()) sort = &exql.SortColumn{ Column: exql.RawValue(col), } qs.mu.Lock() qs.orderByArgs = append(qs.orderByArgs, args...) qs.mu.Unlock() case db.Function: fnName, fnArgs := value.Name(), value.Arguments() if len(fnArgs) == 0 { fnName = fnName + "()" } else { fnName = fnName + "(?" + strings.Repeat("?, ", len(fnArgs)-1) + ")" } expanded, fnArgs := Preprocess(fnName, fnArgs) sort = &exql.SortColumn{ Column: exql.RawValue(expanded), } qs.mu.Lock() qs.orderByArgs = append(qs.orderByArgs, fnArgs...) qs.mu.Unlock() case string: if strings.HasPrefix(value, "-") { sort = &exql.SortColumn{ Column: exql.ColumnWithName(value[1:]), Order: exql.Descendent, } } else { chunks := strings.SplitN(value, " ", 2) order := exql.Ascendent if len(chunks) > 1 && strings.ToUpper(chunks[1]) == "DESC" { order = exql.Descendent } sort = &exql.SortColumn{ Column: exql.ColumnWithName(chunks[0]), Order: order, } } default: qs.setErr(fmt.Errorf("Can't sort by type %T", value)) return qs } sortColumns.Columns = append(sortColumns.Columns, sort) } qs.mu.Lock() qs.orderBy = &exql.OrderBy{ SortColumns: &sortColumns, } qs.mu.Unlock() return qs }
// ToColumnValues converts the given conditions into a exql.ColumnValues struct. func (tu *templateWithUtils) ToColumnValues(term interface{}) (cv exql.ColumnValues, args []interface{}) { args = []interface{}{} switch t := term.(type) { case []interface{}: l := len(t) for i := 0; i < l; i++ { column, ok := t[i].(string) if !ok { p, q := tu.ToColumnValues(t[i]) cv.ColumnValues = append(cv.ColumnValues, p.ColumnValues...) args = append(args, q...) continue } if !strings.ContainsAny(column, "=") { column = fmt.Sprintf("%s = ?", column) } chunks := strings.SplitN(column, "=", 2) column = chunks[0] format := strings.TrimSpace(chunks[1]) columnValue := exql.ColumnValue{ Column: exql.ColumnWithName(column), Operator: "=", Value: exql.RawValue(format), } ps := strings.Count(format, "?") if i+ps < l { for j := 0; j < ps; j++ { args = append(args, t[i+j+1]) } i = i + ps } else { panic(fmt.Sprintf("Format string %q has more placeholders than given arguments.", format)) } cv.ColumnValues = append(cv.ColumnValues, &columnValue) } return cv, args case db.Constraint: columnValue := exql.ColumnValue{} // Guessing operator from input, or using a default one. if column, ok := t.Key().(string); ok { chunks := strings.SplitN(strings.TrimSpace(column), ` `, 2) columnValue.Column = exql.ColumnWithName(chunks[0]) if len(chunks) > 1 { columnValue.Operator = chunks[1] } } else { if rawValue, ok := t.Key().(db.RawValue); ok { columnValue.Column = exql.RawValue(rawValue.Raw()) args = append(args, rawValue.Arguments()...) } else { columnValue.Column = exql.RawValue(fmt.Sprintf("%v", t.Key())) } } switch value := t.Value().(type) { case db.Function: fnName, fnArgs := value.Name(), value.Arguments() if len(fnArgs) == 0 { // A function with no arguments. fnName = fnName + "()" } else { // A function with one or more arguments. fnName = fnName + "(?" + strings.Repeat("?, ", len(fnArgs)-1) + ")" } expanded, fnArgs := Preprocess(fnName, fnArgs) columnValue.Value = exql.RawValue(expanded) args = append(args, fnArgs...) case db.RawValue: expanded, rawArgs := Preprocess(value.Raw(), value.Arguments()) columnValue.Value = exql.RawValue(expanded) args = append(args, rawArgs...) default: v, isSlice := toInterfaceArguments(value) if isSlice { if columnValue.Operator == "" { columnValue.Operator = sqlInOperator } if len(v) > 0 { // Array value given. columnValue.Value = exql.RawValue(fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1))) } else { // Single value given. columnValue.Value = exql.RawValue(`(NULL)`) } args = append(args, v...) } else { if v == nil { // Nil value given. columnValue.Value = sqlNull if columnValue.Operator == "" { columnValue.Operator = sqlIsOperator } } else { columnValue.Value = sqlPlaceholder args = append(args, v...) } } } // Using guessed operator if no operator was given. if columnValue.Operator == "" { if tu.DefaultOperator != "" { columnValue.Operator = tu.DefaultOperator } else { columnValue.Operator = sqlDefaultOperator } } cv.ColumnValues = append(cv.ColumnValues, &columnValue) return cv, args case db.RawValue: columnValue := exql.ColumnValue{} p, q := Preprocess(t.Raw(), t.Arguments()) columnValue.Column = exql.RawValue(p) args = append(args, q...) cv.ColumnValues = append(cv.ColumnValues, &columnValue) return cv, args case db.Constraints: for _, c := range t.Constraints() { p, q := tu.ToColumnValues(c) cv.ColumnValues = append(cv.ColumnValues, p.ColumnValues...) args = append(args, q...) } return cv, args } panic(fmt.Sprintf("Unknown term type %T.", term)) }