Slide 1

Slide 1 text

reform путь к лучшему ORM Алексей Палажченко mc² software

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Цели database/sql src/database/sql/doc.txt • generic database API for SQL/SQL-like, feel like Go • common cases, portable, no quirks • consistent but flexible type conversions • concurrency, thread safety, built-in pool • push complexity to drivers via optional interfaces

Slide 4

Slide 4 text

Интерфейс database/sql • DB: Open, Close, Begin, Prepare, Driver • DB, Stmt, Tx: Query, QueryRow, Exec • Rows: Next, Scan, Err, Close • Result: LastInsertId, RowsAffected • NullBool, NullInt64, NullFloat64, NullString • Scanner: Scan(src interface{}) error

Slide 5

Slide 5 text

INSERT result, err := db.Exec( "INSERT INTO users (name) "+ "VALUES ($1)", "gopher" )

Slide 6

Slide 6 text

SELECT defer rows.Close() for rows.Next() { var name string if e := rows.Scan(&name); e != nil { log.Fatal(e) } fmt.Println(name) } if e := rows.Err(); e != nil { log.Fatal(e) }

Slide 7

Slide 7 text

Интерфейс database/sql/driver • Value: пустой интерфейс • ValueConverter: ConvertValue(v interface{}) (Value, error) • Valuer: Value() (Value, error)

Slide 8

Slide 8 text

database/sql/driver.Value • nil • int64 • float64 • bool • []byte (non-nil) • string everywhere except from Rows.Next. #6497 • time.Time (боль с часовыми зонами)

Slide 9

Slide 9 text

Свои типы func (j JSONText) Value() (driver.Value, error) { if j == nil { return nil, nil } var m json.RawMessage err := json.Unmarshal(j, &m) if err != nil { return []byte{}, err } return []byte(j), nil }

Slide 10

Slide 10 text

Свои типы func (j *JSONText) Scan(value interface{}) error { if value == nil { *j = nil return nil } v, ok := value.([]byte) if !ok { return fmt.Errorf("error") } *j = JSONText(append((*j)[0:0], v...)) return nil }

Slide 11

Slide 11 text

Драйвера • github.com/golang/go/wiki/SQLDrivers • github.com/bradfitz/go-sql-test

Slide 12

Slide 12 text

Зачем ORM?

Slide 13

Slide 13 text

INSERT result, err := db.Exec( "INSERT INTO users (name) "+ "VALUES ($1)", "gopher" )

Slide 14

Slide 14 text

SELECT defer rows.Close() for rows.Next() { var name string if e := rows.Scan(&name); e != nil { log.Fatal(e) } fmt.Println(name) } if e := rows.Err(); e != nil { log.Fatal(e) }

Slide 15

Slide 15 text

ORM • Не-ORM / малые ORM (например, отображение Scan строк в структуры) • Большие ORM

Slide 16

Slide 16 text

ORM func Save(m interface{}) error

Slide 17

Slide 17 text

ORM Save(User{Name: "gopher"}) Save(&User{Name: "gopher"}) Save(nil) Save(42) Save("Batman!!")

Slide 18

Slide 18 text

Идея: struct для данных type Person struct { ID int64 `sql:"id,omitempty"` Name string `sql:"name,omitempty"` }

Slide 19

Slide 19 text

Идея: непустые интерфейсы type Record interface { Values() []interface{} Pointers() []interface{} PrimaryKeyPointer() interface{} SetPrimaryKey(id interface{}) Table() Table } funс Save(record Record) error

Slide 20

Slide 20 text

Идея: генерация кода • struct и код из XML • XML из information_schema • struct пишется, код генерируется из него

Slide 21

Slide 21 text

Проблемы: Go vs SQL • SQL: значения по-умолчанию • SQL: отсутствие в запросе • Go: zero value

Slide 22

Slide 22 text

person := &Person{ Name: "gopher", } if err := DB.Save(person); err != nil { log.Fatal(err) }

Slide 23

Slide 23 text

Что почитать • Документацию database/sql/… • Код database/sql/… • github.com/mc2soft/pq-types • github.com/AlekSi/reform

Slide 24

Slide 24 text

• https://groups.google.com/forum/#!forum/golang-ru • http://www.meetup.com/Golang-Moscow/ • http://4gophers.ru • http://4gophers.ru/slack • https://golangshow.com