func (d *Driver) clause(buf *bytes.Buffer, params *[]interface{}, m driver.Model, format string, f *query.Field, begin int) error { dbName, _, err := m.Map(f.Field) if err != nil { return err } if f.Value != nil { if field, ok := f.Value.(query.F); ok { fName, _, err := m.Map(string(field)) if err != nil { return err } fmt.Fprintf(buf, format, dbName, fName) return nil } if sq, ok := f.Value.(query.Subquery); ok { fmt.Fprintf(buf, format, dbName, "("+string(sq)+")") return nil } fmt.Fprintf(buf, format, dbName, d.backend.Placeholder(len(*params)+begin)) val, err := d.transformOutValue(f.Value) if err != nil { return err } *params = append(*params, val) return nil } fmt.Fprintf(buf, format, dbName) return nil }
func (d *Driver) Operate(m driver.Model, q query.Q, ops []*operation.Operation) (driver.Result, error) { buf := getBuffer() buf.WriteString("UPDATE ") buf.WriteByte('"') buf.WriteString(m.Table()) buf.WriteByte('"') buf.WriteString(" SET ") var params []interface{} for ii, op := range ops { if ii > 0 { buf.WriteByte(',') } dbName, _, err := m.Map(op.Field) if err != nil { return nil, err } dbName = unquote(dbName) buf.WriteByte('"') buf.WriteString(dbName) buf.WriteByte('"') buf.WriteByte('=') switch op.Operator { case operation.OpAdd, operation.OpSub: buf.WriteString(dbName) if op.Operator == operation.OpAdd { buf.WriteByte('+') } else { buf.WriteByte('-') } buf.WriteString(d.backend.Placeholder(len(params))) params = append(params, op.Value) case operation.OpSet: if f, ok := op.Value.(operation.Field); ok { fieldName, _, err := m.Map(string(f)) if err != nil { return nil, err } buf.WriteString(unquote(fieldName)) } else { buf.WriteString(d.backend.Placeholder(len(params))) val, err := d.transformOutValue(op.Value) if err != nil { return nil, err } params = append(params, val) } default: return nil, fmt.Errorf("operator %d is not supported", op.Operator) } } qParams, err := d.where(buf, m, q, len(params)) if err != nil { return nil, err } params = append(params, qParams...) res, err := d.db.Exec(buftos(buf), params...) putBuffer(buf) return res, err }
func (d *Driver) indexName(m driver.Model, idx *index.Index) (string, error) { if len(idx.Fields) == 0 { return "", fmt.Errorf("index on %v has no fields", m.Type()) } buf := getBuffer() buf.WriteString(m.Table()) for _, v := range idx.Fields { dbName, _, err := m.Map(v) if err != nil { return "", err } buf.WriteByte('_') // dbName is quoted and includes the table name // extract the unquoted field name. buf.WriteString(unquote(dbName)) if DescField(idx, v) { buf.WriteString("_desc") } } s := buf.String() putBuffer(buf) return s, nil }
func (d *Driver) Select(fields []string, quote bool, m driver.Model, q query.Q, opts driver.QueryOptions) (*bytes.Buffer, []interface{}, error) { buf := getBuffer() var params []interface{} if err := d.selectStmt(buf, ¶ms, fields, quote, m, opts); err != nil { return nil, nil, err } qParams, err := d.where(buf, m, q, 0) if err != nil { return nil, nil, err } params = append(params, qParams...) if len(opts.Sort) > 0 { buf.WriteString(" ORDER BY ") for _, v := range opts.Sort { dbName, _, err := m.Map(v.Field()) if err != nil { return nil, nil, err } buf.WriteString(dbName) if v.Direction() == driver.DESC { buf.WriteString(" DESC") } buf.WriteByte(',') } buf.Truncate(buf.Len() - 1) } if opts.Limit >= 0 { buf.WriteString(" LIMIT ") buf.WriteString(strconv.Itoa(opts.Limit)) } if opts.Offset >= 0 { buf.WriteString(" OFFSET ") buf.WriteString(strconv.Itoa(opts.Offset)) } return buf, params, nil }
func (d *Driver) condition(buf *bytes.Buffer, params *[]interface{}, m driver.Model, q query.Q, begin int) error { var err error switch x := q.(type) { case *query.Eq: if isNil(x.Value) { x.Value = nil err = d.clause(buf, params, m, "%s IS NULL", &x.Field, begin) } else { err = d.clause(buf, params, m, "%s = %s", &x.Field, begin) } case *query.Neq: if isNil(x.Value) { x.Value = nil err = d.clause(buf, params, m, "%s IS NOT NULL", &x.Field, begin) } else { err = d.clause(buf, params, m, "%s != %s", &x.Field, begin) } case *query.Contains: err = d.clause(buf, params, m, "%s LIKE '%%' || %s || '%%'", &x.Field, begin) case *query.Lt: err = d.clause(buf, params, m, "%s < %s", &x.Field, begin) case *query.Lte: err = d.clause(buf, params, m, "%s <= %s", &x.Field, begin) case *query.Gt: err = d.clause(buf, params, m, "%s > %s", &x.Field, begin) case *query.Gte: err = d.clause(buf, params, m, "%s >= %s", &x.Field, begin) case *query.Operator: err = d.clause(buf, params, m, "%s "+x.Operator+" %s", &x.Field, begin) case *query.In: dbName, _, err := m.Map(x.Field.Field) if err != nil { return err } buf.WriteString(dbName) buf.WriteString(" IN (") value := reflect.ValueOf(x.Value) switch { case value.Type() == subqueryType: buf.WriteString(value.String()) case value.Type().Kind() == reflect.Slice || value.Type().Kind() == reflect.Array: vLen := value.Len() if vLen == 0 { return fmt.Errorf("empty IN (field %s)", x.Field.Field) } jj := len(*params) + begin for ii := 0; ii < vLen; ii++ { *params = append(*params, value.Index(ii).Interface()) buf.WriteString(d.backend.Placeholder(jj)) buf.WriteByte(',') jj++ } buf.Truncate(buf.Len() - 1) default: return fmt.Errorf("argument for IN must be slice or array or query.Subquery (field %s)", x.Field.Field) } buf.WriteByte(')') case *query.And: err = d.conditions(buf, params, m, x.Conditions, " AND ", begin) case *query.Or: err = d.conditions(buf, params, m, x.Conditions, " OR ", begin) default: err = fmt.Errorf("unhandled operand %T (%v)", x, x) } return err }