func (d *Driver) Insert(m driver.Model, data interface{}) (driver.Result, error) { _, fields, values, err := d.saveParameters(m, data) if err != nil { return nil, err } buf := getBuffer() buf.WriteString("INSERT INTO ") buf.WriteByte('"') buf.WriteString(m.Table()) buf.WriteByte('"') count := len(fields) if count > 0 { buf.WriteString(" (") for _, v := range fields { buf.WriteByte('"') buf.WriteString(v) buf.WriteByte('"') buf.WriteByte(',') } buf.Truncate(buf.Len() - 1) buf.WriteString(") VALUES (") buf.WriteString(d.backend.Placeholders(count)) buf.WriteByte(')') } else { buf.WriteByte(' ') buf.WriteString(d.backend.DefaultValues()) } res, err := d.backend.Insert(d.db, m, buftos(buf), values...) putBuffer(buf) return res, err }
func (d *Driver) Update(m driver.Model, q query.Q, data interface{}) (driver.Result, error) { _, fields, values, err := d.saveParameters(m, data) if err != nil { return nil, err } buf := getBuffer() buf.WriteString("UPDATE ") buf.WriteByte('"') buf.WriteString(m.Table()) buf.WriteByte('"') buf.WriteString(" SET ") for ii, v := range fields { buf.WriteByte('"') buf.WriteString(v) buf.WriteByte('"') buf.WriteByte('=') buf.WriteString(d.backend.Placeholder(ii)) buf.WriteByte(',') } // remove last , buf.Truncate(buf.Len() - 1) qParams, err := d.where(buf, m, q, len(values)) if err != nil { return nil, err } params := append(values, qParams...) res, err := d.db.Exec(buftos(buf), params...) putBuffer(buf) return res, err }
func (t *Table) SQL(db *DB, b Backend, m driver.Model, name string) (string, error) { var lines []string var constraints []string for _, v := range t.Fields { def, cons, err := v.SQL(db, m, t) if err != nil { return "", err } lines = append(lines, def) constraints = append(constraints, cons...) } pk, err := t.definePks(db, m) if err != nil { return "", err } if pk != "" { lines = append(lines, pk) } lines = append(lines, constraints...) if name == "" { name = m.Table() } // Use IF NOT EXISTS, since the DB user might not have // the privileges to inspect the database but still // be allowed to read and write from the tables (e.g. // Postgres only allows superusers and the owner to // inspect the database). sql := fmt.Sprintf("\nCREATE TABLE IF NOT EXISTS %s (\n\t%s\n)", db.QuoteIdentifier(name), strings.Join(lines, ",\n\t")) return sql, nil }
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) makeQuery(m driver.Model, q query.Q, opts *driver.QueryOptions) (*datastore.Query, error) { if m.Join() != nil { return nil, errJoinNotSupported } dq := datastore.NewQuery(m.Table()).Ancestor(d.parentKey(m)) var err error if dq, err = d.applyQuery(m, dq, q); err != nil { return nil, err } if opts != nil { if opts.Distinct { dq = dq.Distinct() } for _, v := range opts.Sort { field := v.Field() if v.Direction() == driver.DESC { field = "-" + field } dq = dq.Order(field) } if opts.Limit >= 0 { dq = dq.Limit(opts.Limit) } if opts.Offset > 0 { dq = dq.Offset(opts.Offset) } } return dq, nil }
func fieldHasDefault(m driver.Model, f *Field) bool { if f.Default != "" { return true } fields := m.Fields() idx := fields.MNameMap[f.Name] return fields.HasDefault(idx) }
func (d *Driver) createTable(m driver.Model, table *Table) error { sql, err := table.SQL(d.db, d.backend, m, m.Table()) if err != nil { return err } _, err = d.db.Exec(sql) return err }
func (b *Backend) HasIndex(db *sql.DB, m driver.Model, idx *index.Index, name string) (bool, error) { rows, err := db.Query("SHOW INDEX FROM ? WHERE Key_name = ?", m.Table(), name) if err != nil { return false, err } has := rows.Next() rows.Close() return has, nil }
func (b *Backend) Inspect(db *sql.DB, m driver.Model) (*sql.Table, error) { name := db.QuoteString(m.Table()) rows, err := db.Query(fmt.Sprintf("PRAGMA table_info(%s)", name)) if err != nil { return nil, err } defer rows.Close() fieldsByName := make(map[string]*sql.Field) var fields []*sql.Field for rows.Next() { var cid int var f sql.Field var notnull int var def *string var pk int if err := rows.Scan(&cid, &f.Name, &f.Type, ¬null, &def, &pk); err != nil { return nil, err } f.Type = strings.ToUpper(f.Type) if notnull != 0 { f.AddConstraint(sql.ConstraintNotNull) } if def != nil { f.Default = *def } if pk != 0 { f.AddConstraint(sql.ConstraintPrimaryKey) } fields = append(fields, &f) fieldsByName[f.Name] = &f } if err := rows.Err(); err != nil { return nil, err } rows, err = db.Query(fmt.Sprintf("PRAGMA foreign_key_list(%s)", name)) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var id, seq int var table, from, to, onUpdate, onDelete, match string if err := rows.Scan(&id, &seq, &table, &from, &to, &onUpdate, &onDelete, &match); err != nil { return nil, err } field := fieldsByName[from] field.Constraints = append(field.Constraints, &sql.Constraint{Type: sql.ConstraintForeignKey, References: sql.MakeReference(table, to)}) } if err := rows.Err(); err != nil { return nil, err } if len(fields) > 0 { return &sql.Table{Fields: fields}, nil } return nil, nil }
func (s sortModels) less(mi, mj driver.Model) bool { for _, v := range mi.Fields().References { if v.Model == mj { return false } if v.Model != mi && !s.less(v.Model, mj) { return false } } return true }
func (d *Driver) createIndexes(m driver.Model) error { for _, idx := range m.Indexes() { name, err := d.indexName(m, idx) if err != nil { return err } if err := d.createIndex(m, idx, name); err != nil { return err } } return nil }
func (d *Driver) Delete(m driver.Model, q query.Q) (driver.Result, error) { buf := getBuffer() buf.WriteString("DELETE FROM ") buf.WriteByte('"') buf.WriteString(m.Table()) buf.WriteByte('"') params, err := d.where(buf, m, q, 0) if err != nil { return nil, err } res, err := d.db.Exec(buftos(buf), params...) putBuffer(buf) return res, err }
func (b *Backend) Insert(db *sql.DB, m driver.Model, query string, args ...interface{}) (driver.Result, error) { fields := m.Fields() if fields.AutoincrementPk { q := query + " RETURNING " + fields.MNames[fields.PrimaryKey] var id int64 err := db.QueryRow(q, args...).Scan(&id) // We need to perform a "real" insert to find the real error, so // just let the code fall to the Exec at the end of the function // if there's an error. if err == nil { return insertResult(id), nil } } return db.Exec(query, args...) }
func (b *SqlBackend) AddFields(db *DB, m driver.Model, prevTable *Table, newTable *Table, fields []*Field) error { modelFields := m.Fields() tableName := db.QuoteIdentifier(m.Table()) for _, v := range fields { idx := modelFields.MNameMap[v.Name] field := v hasDefault := modelFields.HasDefault(idx) if hasDefault && v.HasConstraint(ConstraintNotNull) { // ORM level default // Must be added as nullable first, then the default value // must be set and finally the field has to be altered to be // nullable. field = field.Copy() var constraints []*Constraint for _, v := range field.Constraints { if v.Type != ConstraintNotNull { constraints = append(constraints, v) } } field.Constraints = constraints } sql, cons, err := field.SQL(db, m, newTable) if err != nil { return err } if _, err = db.Exec(fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s", tableName, sql)); err != nil { return err } if hasDefault { value := modelFields.DefaultValue(idx) fieldName := db.QuoteIdentifier(v.Name) if _, err := db.Exec(fmt.Sprintf("UPDATE %s SET %s = ?", tableName, fieldName), value); err != nil { return err } if v.HasConstraint(ConstraintNotNull) { if err := db.Backend().AlterField(db, m, newTable, field, v); err != nil { return err } } } for _, c := range cons { if _, err = db.Exec(fmt.Sprintf("ALTER TABLE %s ADD CONSTRAINT %s", tableName, c)); err != nil { return err } } } return nil }
func (b *Backend) AlterField(db *sql.DB, m driver.Model, table *sql.Table, oldField *sql.Field, newField *sql.Field) error { fsql, cons, err := newField.SQL(db, m, table) if err != nil { return err } tableName := db.QuoteIdentifier(m.Table()) if _, err = db.Exec(fmt.Sprintf("ALTER TABLE %s CHANGE COLUMN %s %s", tableName, db.QuoteIdentifier(oldField.Name), fsql)); err != nil { return err } for _, c := range cons { if _, err = db.Exec(fmt.Sprintf("ALTER TABLE %s ADD CONSTRAINT %s", tableName, c)); err != nil { return err } } return err }
func (b *Backend) DefineField(db *sql.DB, m driver.Model, table *sql.Table, field *sql.Field) (string, []string, error) { def, cons, err := b.SqlBackend.DefineField(db, m, table, field) if err != nil { return "", nil, err } if ref := field.Constraint(sql.ConstraintForeignKey); ref != nil { if pos := strings.Index(def, " REFERENCES"); pos >= 0 { def = def[:pos] } refTable := ref.References.Table() refField := ref.References.Field() fkName := db.QuoteIdentifier(fmt.Sprintf("%s_%s_%s_%s", m.Table(), field.Name, refTable, refField)) cons = append(cons, fmt.Sprintf("FOREIGN KEY %s(%s) REFERENCES %s(%s)", fkName, db.QuoteIdentifier(field.Name), db.QuoteIdentifier(refTable), db.QuoteIdentifier(refField))) } return strings.Replace(def, "AUTOINCREMENT", "AUTO_INCREMENT", -1), cons, nil }
func (d *Driver) outValues(m driver.Model, out interface{}) (reflect.Value, *driver.Fields, []interface{}, []*scanner, error) { val := reflect.ValueOf(out) if !val.IsValid() { // Untyped nil pointer return reflect.Value{}, nil, nil, nil, nil } vt := val.Type() if vt.Kind() != reflect.Ptr { return reflect.Value{}, nil, nil, nil, fmt.Errorf("can't set object of type %T. Please, pass a %v rather than a %v", out, reflect.PtrTo(vt), vt) } if vt.Elem().Kind() == reflect.Ptr && vt.Elem().Elem().Kind() == reflect.Struct { // Received a pointer to pointer. Always create a new object, // to avoid overwriting the previous result. val = val.Elem() el := reflect.New(val.Type().Elem()) val.Set(el) } for val.Kind() == reflect.Ptr { el := val.Elem() if !el.IsValid() { if !val.CanSet() { // Typed nil pointer return reflect.Value{}, nil, nil, nil, nil } el = reflect.New(val.Type().Elem()) val.Set(el) } val = el } fields := m.Fields() if fields == nil { // Skipped model return reflect.Value{}, nil, nil, nil, nil } values := make([]interface{}, len(fields.Indexes)) scanners := make([]*scanner, len(fields.Indexes)) for ii, v := range fields.Indexes { field := d.fieldByIndex(val, v, true) tag := fields.Tags[ii] s := newScanner(&field, tag, d.backend) scanners[ii] = s values[ii] = s } return val, fields, values, scanners, nil }
func (b *Backend) AddFields(db *sql.DB, m driver.Model, prevTable *sql.Table, newTable *sql.Table, fields []*sql.Field) error { rewrite := false for _, v := range fields { if !b.canAddField(v) { rewrite = true break } } if rewrite { name := db.QuoteIdentifier(m.Table()) tmpName := fmt.Sprintf("%s_%s", m.Table(), stringutil.Random(8)) quotedTmpName := db.QuoteIdentifier(tmpName) createSql, err := newTable.SQL(db, b, m, tmpName) if err != nil { return err } if _, err := db.Exec(createSql); err != nil { return err } fieldNames := generic.Map(prevTable.Fields, func(f *sql.Field) string { return f.Name }).([]string) // The previous table might have fields that we're not part // of the new table. fieldSet := make(map[string]bool) for _, v := range newTable.Fields { fieldSet[v.Name] = true } fieldNames = generic.Filter(fieldNames, func(n string) bool { return fieldSet[n] }).([]string) sqlFields := strings.Join(generic.Map(fieldNames, db.QuoteIdentifier).([]string), ", ") copySql := fmt.Sprintf("INSERT INTO %s (%s) SELECT %s FROM %s", quotedTmpName, sqlFields, sqlFields, name) if _, err := db.Exec(copySql); err != nil { return err } if _, err := db.Exec(fmt.Sprintf("DROP TABLE %s", name)); err != nil { return err } if _, err := db.Exec(fmt.Sprintf("ALTER TABLE %s RENAME TO %s", quotedTmpName, name)); err != nil { return err } return nil } return b.SqlBackend.AddFields(db, m, prevTable, newTable, fields) }
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) createIndex(m driver.Model, idx *index.Index, name string) error { has, err := d.backend.HasIndex(d.db, m, idx, name) if err != nil { return err } if has { return nil } buf := getBuffer() buf.WriteString("CREATE ") if idx.Unique { buf.WriteString("UNIQUE ") } buf.WriteString("INDEX ") buf.WriteString(name) buf.WriteString(" ON \"") buf.WriteString(m.Table()) buf.WriteString("\" (") fields := m.Fields() for _, v := range idx.Fields { name, _, err := fields.Map(v) if err != nil { return err } buf.WriteByte('"') buf.WriteString(name) buf.WriteByte('"') if DescField(idx, v) { buf.WriteString(" DESC") } buf.WriteByte(',') } buf.Truncate(buf.Len() - 1) buf.WriteString(")") _, err = d.db.Exec(buftos(buf)) putBuffer(buf) return err }
func (d *Driver) Insert(m driver.Model, data interface{}) (driver.Result, error) { var id int64 fields := m.Fields() var pkVal *reflect.Value // TODO: If the PK is supplied by the user rather than auto-assigned, it // might conflict with PKs generated by datastore.AllocateIDs(). if fields.PrimaryKey >= 0 { p := d.primaryKey(fields, data) if p.IsValid() && types.Kind(p.Kind()) == types.Int { id = p.Int() if id == 0 { // Must assign PK field value after calling AllocateIDs pkVal = &p } } } name := m.Table() // Make all objects of a given kind ancestors of the same key. While // this hurts scalability, it makes all reads strongly consistent. parent := d.parentKey(m) var err error if id == 0 { id, _, err = datastore.AllocateIDs(d.c, name, parent, 1) if err != nil { return nil, err } } if fields.AutoincrementPk && pkVal != nil { pkVal.SetInt(int64(id)) } key := datastore.NewKey(d.c, name, "", id, parent) log.Debugf("DATASTORE: put %s %v", key, data) _, err = datastore.Put(d.c, key, data) if err != nil { return nil, err } return &result{key: key, count: 1}, 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) mergeTable(m driver.Model, prevTable *Table, newTable *Table) error { existing := make(map[string]*Field) for _, v := range prevTable.Fields { existing[v.Name] = v } var missing []*Field for _, v := range newTable.Fields { prev := existing[v.Name] if prev == nil { // Check if we can add the field if v.HasConstraint(ConstraintNotNull) && !fieldHasDefault(m, v) { return fmt.Errorf("can't add NOT NULL field %q to table %q without a default value", v.Name, m.Table()) } if v.HasConstraint(ConstraintPrimaryKey) { return fmt.Errorf("can't add PRIMARY KEY field %q to table %q", v.Name, m.Table()) } missing = append(missing, v) } else { if prev.Type != v.Type { // Check the Kind k1, len1 := TypeKind(prev.Type) k2, len2 := TypeKind(v.Type) if k1 == k2 { // Check lengths if len1 != len2 { } continue } // Check if we can transform the kind fields := m.Fields() idx := fields.MNameMap[v.Name] modelName := fields.QNames[idx] modelType := fields.Types[idx] return fmt.Errorf("field %q on table %q is of type %s which is not compatible with the model field %q of type %s (%s)", v.Name, m.Table(), prev.Type, modelName, v.Type, modelType) } } } if len(missing) > 0 { if err := d.backend.AddFields(d.db, m, prevTable, newTable, missing); err != nil { return err } } return nil }
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) saveParameters(m driver.Model, data interface{}) (reflect.Value, []string, []interface{}, error) { // data is guaranteed to be of m.Type() val := driver.Direct(reflect.ValueOf(data)) fields := m.Fields() max := len(fields.MNames) names := make([]string, 0, max) values := make([]interface{}, 0, max) var err error if d.transforms != nil { for ii, v := range fields.Indexes { f := d.fieldByIndex(val, v, false) if !f.IsValid() { continue } if fields.OmitEmpty[ii] && driver.IsZero(f) { continue } ft := f.Type() var fval interface{} if _, ok := d.transforms[ft]; ok { fval, err = d.backend.TransformOutValue(f) if err != nil { return val, nil, nil, err } if fields.NullEmpty[ii] && driver.IsZero(reflect.ValueOf(fval)) { fval = nil } } else if !fields.NullEmpty[ii] || !driver.IsZero(f) { if c := codec.FromTag(fields.Tags[ii]); c != nil { fval, err = c.Encode(f.Interface()) if err != nil { return val, nil, nil, err } if p := pipe.FromTag(fields.Tags[ii]); p != nil { data, err := p.Encode(fval.([]byte)) if err != nil { return val, nil, nil, err } fval = data } } else { // Most sql drivers won't accept aliases for string type if ft.Kind() == reflect.String && ft != stringType { f = f.Convert(stringType) } fval = f.Interface() } } names = append(names, fields.MNames[ii]) values = append(values, fval) } } else { for ii, v := range fields.Indexes { f := d.fieldByIndex(val, v, false) if !f.IsValid() { continue } if fields.OmitEmpty[ii] && driver.IsZero(f) { continue } var fval interface{} if !fields.NullEmpty[ii] || !driver.IsZero(f) { if c := codec.FromTag(fields.Tags[ii]); c != nil { fval, err = c.Encode(&f) if err != nil { return val, nil, nil, err } } else { ft := f.Type() // Most sql drivers won't accept aliases for string type if ft.Kind() == reflect.String && ft != stringType { f = f.Convert(stringType) } fval = f.Interface() } } names = append(names, fields.MNames[ii]) values = append(values, fval) } } return val, names, values, nil }
func (d *Driver) selectStmt(buf *bytes.Buffer, params *[]interface{}, fields []string, quote bool, m driver.Model, opts driver.QueryOptions) error { buf.WriteString("SELECT ") if opts.Distinct { buf.WriteString("DISTINCT ") } if fields != nil { if quote { for _, v := range fields { buf.WriteByte('"') buf.WriteString(v) buf.WriteByte('"') buf.WriteByte(',') } } else { for _, v := range fields { buf.WriteString(v) buf.WriteByte(',') } } } else { // Select all fields for the given model (which might be joined) cur := m for { if !cur.Skip() { for _, v := range cur.Fields().QuotedNames { buf.WriteString(v) buf.WriteByte(',') } } join := cur.Join() if join == nil { break } cur = join.Model() } } buf.Truncate(buf.Len() - 1) buf.WriteString(" FROM ") buf.WriteByte('"') buf.WriteString(m.Table()) buf.WriteByte('"') for join := m.Join(); join != nil; { jm := join.Model() switch join.Type() { case driver.OuterJoin: buf.WriteString(" FULL OUTER") case driver.LeftJoin: buf.WriteString(" LEFT OUTER") case driver.RightJoin: buf.WriteString(" RIGHT OUTER") } buf.WriteString(" JOIN ") buf.WriteByte('"') buf.WriteString(jm.Table()) buf.WriteByte('"') buf.WriteString(" ON ") if err := d.condition(buf, params, m, join.Query(), len(*params)); err != nil { return err } join = jm.Join() } return 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 }
func (b *SqlBackend) Inspect(db *DB, m driver.Model, schema string) (*Table, error) { var val int name := db.QuoteString(m.Table()) s := db.QuoteString(schema) eq := fmt.Sprintf("SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE "+ "TABLE_NAME = %s AND TABLE_SCHEMA = %s", name, s) err := db.QueryRow(eq).Scan(&val) if err != nil { if err == ErrNoRows { return nil, nil } return nil, err } // Select fields with their types iq := fmt.Sprintf("SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, "+ "CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS "+ "WHERE TABLE_NAME = %s AND TABLE_SCHEMA = %s", name, s) rows, err := db.Query(iq) if err != nil { return nil, err } defer rows.Close() var fields []*Field fieldsByName := make(map[string]*Field) for rows.Next() { var f Field var nullable string var maxLength *int if err := rows.Scan(&f.Name, &nullable, &f.Type, &maxLength); err != nil { return nil, err } if maxLength != nil { f.Type = fmt.Sprintf("%s (%d)", f.Type, *maxLength) } f.Type = strings.ToUpper(f.Type) if nullable != "YES" { f.AddConstraint(ConstraintNotNull) } fields = append(fields, &f) fieldsByName[f.Name] = &f } // Field constraints cq := fmt.Sprintf("SELECT C.CONSTRAINT_NAME, CONSTRAINT_TYPE, COLUMN_NAME "+ "FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS C JOIN "+ "INFORMATION_SCHEMA.KEY_COLUMN_USAGE K ON C.CONSTRAINT_NAME = "+ "K.CONSTRAINT_NAME WHERE C.TABLE_NAME = %s AND K.TABLE_NAME = %s "+ "AND C.TABLE_SCHEMA = %s", name, name, s) rows, err = db.Query(cq) if err != nil { return nil, err } foreignKeys := make(map[string]string) defer rows.Close() for rows.Next() { var constraintName string var constraintType string var name string if err := rows.Scan(&constraintName, &constraintType, &name); err != nil { return nil, err } field := fieldsByName[name] if field == nil { return nil, fmt.Errorf("table %s has constraint on non-existing field %s", m.Table(), name) } switch strings.ToLower(constraintType) { case "primary key": field.AddConstraint(ConstraintPrimaryKey) case "foreign key": foreignKeys[constraintName] = name case "unique": field.AddConstraint(ConstraintUnique) default: return nil, fmt.Errorf("unknown constraint type %s on field %s in table %s", constraintType, name, m.Table()) } } if len(foreignKeys) > 0 { // Resolve FKs fks := strings.Join(generic.Map(generic.Keys(foreignKeys).([]string), db.QuoteString).([]string), ", ") fq := fmt.Sprintf("SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE CONSTRAINT_NAME IN (%s)", fks) rows, err := db.Query(fq) if err != nil { return nil, err } defer rows.Close() for rows.Next() { var constraintName string var tableName string var columnName string if err := rows.Scan(&constraintName, &tableName, &columnName); err != nil { return nil, err } fieldName := foreignKeys[constraintName] // Field was validated previously, won't be nil field := fieldsByName[fieldName] field.Constraints = append(field.Constraints, &Constraint{Type: ConstraintForeignKey, References: MakeReference(tableName, columnName)}) } } return &Table{Fields: fields}, nil }
func (d *Driver) makeTable(m driver.Model) (*Table, error) { fields := m.Fields() names := fields.MNames qnames := fields.QNames ftypes := fields.Types tags := fields.Tags dbFields := make([]*Field, len(names)) for ii, v := range names { typ := ftypes[ii] tag := tags[ii] ft, err := d.backend.FieldType(typ, tag) if err != nil { return nil, err } def := tag.Value("default") if fields.HasDefault(ii) { // Handled by the ORM def = "" } if def != "" { if driver.IsFunc(def) { fname, _ := driver.SplitFuncArgs(def) fn, err := d.backend.Func(fname, ftypes[ii]) if err != nil { if err == ErrFuncNotSupported { err = fmt.Errorf("backend %s does not support function %s", d.backend.Name(), tag.Value("default")) } return nil, err } def = fn } else { def = driver.UnescapeDefault(def) if typ.Kind() == reflect.String { def = d.db.QuoteString(def) } } } field := &Field{ Name: v, Type: ft, Default: def, } if tag.Has("notnull") { field.AddConstraint(ConstraintNotNull) } if d.isPrimaryKey(fields, ii, tag) { field.AddConstraint(ConstraintPrimaryKey) } else if tag.Has("unique") { field.AddConstraint(ConstraintUnique) } if tag.Has("auto_increment") { field.AddOption(OptionAutoIncrement) } if ref := fields.References[qnames[ii]]; ref != nil { fk, _, err := ref.Model.Fields().Map(ref.Field) if err != nil { return nil, err } field.Constraints = append(field.Constraints, &Constraint{ Type: ConstraintForeignKey, References: MakeReference(ref.Model.Table(), fk), }) } dbFields[ii] = field } return &Table{Fields: dbFields}, nil }
func (d *Driver) applyQuery(m driver.Model, dq *datastore.Query, q query.Q) (*datastore.Query, error) { var field *query.Field var op string switch x := q.(type) { case *query.Eq: field = &x.Field op = " =" case *query.Lt: field = &x.Field op = " <" case *query.Lte: field = &x.Field op = " <=" case *query.Gt: field = &x.Field op = " >" case *query.Gte: field = &x.Field op = " >=" case *query.And: var err error for _, v := range x.Conditions { dq, err = d.applyQuery(m, dq, v) if err != nil { return nil, err } } case nil: default: return nil, fmt.Errorf("datastore does not support %T queries", q) } if field != nil { if _, ok := field.Value.(query.F); ok { return nil, fmt.Errorf("datastore queries can't reference other properties (%v)", field.Value) } name := field.Field fields := m.Fields() idx, ok := fields.QNameMap[name] if !ok { return nil, fmt.Errorf("can't map field %q to a datastore name", name) } if strings.IndexByte(name, '.') >= 0 { // GAE flattens embedded fields, so we must remove // the parts of the field which refer to a flattened // field. indexes := fields.Indexes[idx] parts := strings.Split(name, ".") if len(indexes) == len(parts) { var final []string typ := fields.Type for ii, v := range indexes { f := typ.Field(v) if !f.Anonymous { final = append(final, parts[ii]) } typ = f.Type } name = strings.Join(final, ".") } } log.Debugf("DATASTORE: filter %s %s %v", m, name+op, field.Value) dq = dq.Filter(name+op, field.Value) } return dq, nil }