func init() { testApp = app.New() testApp.Config().Secret = stringutil.Random(32) testApp.Handle("^/hello$", func(ctx *app.Context) { ctx.Header().Add("X-Hello", "World") ctx.Header().Add("X-Number", "42") ctx.WriteString("hello world") }) testApp.Handle("^/empty$", func(ctx *app.Context) {}) testApp.Handle("^/echo$", func(ctx *app.Context) { if ctx.R.Method == "POST" { data, err := ioutil.ReadAll(ctx.R.Body) if err != nil { panic(err) } ctx.Write(data) } }) testApp.Handle("^/echo-form$", func(ctx *app.Context) { if err := ctx.R.ParseForm(); err != nil { panic(err) } var values url.Values if ctx.R.Method == "POST" || ctx.R.Method == "PUT" { values = ctx.R.PostForm } else { values = ctx.R.Form } keys := generic.Keys(values).([]string) sort.Strings(keys) for _, k := range keys { fmt.Fprintf(ctx, "%s=%s\n", k, values.Get(k)) } }) testApp.Handle("^/invalid-write-header$", func(ctx *app.Context) { ctx.WriteHeader(0) }) testApp.Handle("^/multiple-write-header$", func(ctx *app.Context) { ctx.WriteHeader(200) ctx.WriteHeader(300) }) }
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 }