1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| func difference(a []string, b []string) (diff []string) { mapB := make(map[string]bool) for _, v := range b { mapB[v] = true } for _, v := range a { if _, ok := mapB[v]; !ok { diff = append(diff, v) } } return }
func (engine *Engine) Migrate(value interface{}) error { _, err := engine.Transaction(func(s *session.Session) (result interface{}, err error) { if !s.Model(value).HasTable() { log.Infof("table %s doesn't exist", s.RefTable().Name) return nil, s.CreateTable() } table := s.RefTable() rows, _ := s.Raw(fmt.Sprintf("SELECT * FROM %s LIMIT 1", table.Name)).QueryRows() columns, _ := rows.Columns() addCols := difference(table.FieldNames, columns) delCols := difference(columns, table.FieldNames) log.Infof("added cols %v, deleted cols %v", addCols, delCols)
for _, col := range addCols { f := table.GetField(col) sqlStr := fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s %s;", table.Name, f.Name, f.Type) if _, err = s.Raw(sqlStr).Exec(); err != nil { return } }
if len(delCols) == 0 { return } tmp := "tmp_" + table.Name fieldStr := strings.Join(table.FieldNames, ", ") s.Raw(fmt.Sprintf("CREATE TABLE %s AS SELECT %s from %s;", tmp, fieldStr, table.Name)) s.Raw(fmt.Sprintf("DROP TABLE %s;", table.Name)) s.Raw(fmt.Sprintf("ALTER TABLE %s RENAME TO %s;", tmp, table.Name)) _, err = s.Exec() return }) return err }
|
GeeORM 的整体实现比较粗糙,比如数据库的迁移仅仅考虑了最简单的场景。实现的特性也比较少,比如结构体嵌套的场景,外键的场景,复合主键的场景都没有覆盖。ORM 框架的代码规模一般都比较大,如果想尽可能地逼近数据库,就需要大量的代码来实现相关的特性;二是数据库之间的差异也是比较大的,实现的功能越多,数据库之间的差异就会越突出,有时候为了达到较好的性能,就不得不为每个数据做特殊处理;还有些 ORM 框架同时支持关系型数据库和非关系型数据库,这就要求框架本身有更高层次的抽象,不能局限在 SQL 这一层。
GeeORM 仅 800 左右的代码是不可能做到这一点的。不过,GeeORM 的目的并不是实现一个可以在生产使用的 ORM 框架,而是希望尽可能多地介绍 ORM 框架大致的实现原理,例如