orm support auto create db
Showing
16 changed files
with
444 additions
and
57 deletions
orm/cmd.go
0 → 100644
| 1 | package orm | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "flag" | ||
| 5 | "fmt" | ||
| 6 | "os" | ||
| 7 | "strings" | ||
| 8 | ) | ||
| 9 | |||
| 10 | type commander interface { | ||
| 11 | Parse([]string) | ||
| 12 | Run() | ||
| 13 | } | ||
| 14 | |||
| 15 | var ( | ||
| 16 | commands = make(map[string]commander) | ||
| 17 | ) | ||
| 18 | |||
| 19 | func printHelp(errs ...string) { | ||
| 20 | content := `orm command usage: | ||
| 21 | |||
| 22 | syncdb - auto create tables | ||
| 23 | sqlall - print sql of create tables | ||
| 24 | help - print this help | ||
| 25 | ` | ||
| 26 | |||
| 27 | if len(errs) > 0 { | ||
| 28 | fmt.Println(errs[0]) | ||
| 29 | } | ||
| 30 | fmt.Println(content) | ||
| 31 | os.Exit(2) | ||
| 32 | } | ||
| 33 | |||
| 34 | func RunCommand() { | ||
| 35 | if len(os.Args) < 2 || os.Args[1] != "orm" { | ||
| 36 | return | ||
| 37 | } | ||
| 38 | |||
| 39 | BootStrap() | ||
| 40 | |||
| 41 | args := argString(os.Args[2:]) | ||
| 42 | name := args.Get(0) | ||
| 43 | |||
| 44 | if name == "help" { | ||
| 45 | printHelp() | ||
| 46 | } | ||
| 47 | |||
| 48 | if cmd, ok := commands[name]; ok { | ||
| 49 | cmd.Parse(os.Args[3:]) | ||
| 50 | cmd.Run() | ||
| 51 | os.Exit(0) | ||
| 52 | } else { | ||
| 53 | if name == "" { | ||
| 54 | printHelp() | ||
| 55 | } else { | ||
| 56 | printHelp(fmt.Sprintf("unknown command %s", name)) | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | type commandSyncDb struct { | ||
| 62 | al *alias | ||
| 63 | force bool | ||
| 64 | verbose bool | ||
| 65 | } | ||
| 66 | |||
| 67 | func (d *commandSyncDb) Parse(args []string) { | ||
| 68 | var name string | ||
| 69 | |||
| 70 | flagSet := flag.NewFlagSet("orm command: syncdb", flag.ExitOnError) | ||
| 71 | flagSet.StringVar(&name, "db", "default", "DataBase alias name") | ||
| 72 | flagSet.BoolVar(&d.force, "force", false, "drop tables before create") | ||
| 73 | flagSet.BoolVar(&d.verbose, "v", false, "verbose info") | ||
| 74 | flagSet.Parse(args) | ||
| 75 | |||
| 76 | d.al = getDbAlias(name) | ||
| 77 | } | ||
| 78 | |||
| 79 | func (d *commandSyncDb) Run() { | ||
| 80 | var drops []string | ||
| 81 | if d.force { | ||
| 82 | drops = getDbDropSql(d.al) | ||
| 83 | } | ||
| 84 | |||
| 85 | db := d.al.DB | ||
| 86 | |||
| 87 | if d.force { | ||
| 88 | for i, mi := range modelCache.allOrdered() { | ||
| 89 | query := drops[i] | ||
| 90 | _, err := db.Exec(query) | ||
| 91 | result := "" | ||
| 92 | if err != nil { | ||
| 93 | result = err.Error() | ||
| 94 | } | ||
| 95 | fmt.Printf("drop table `%s` %s\n", mi.table, result) | ||
| 96 | if d.verbose { | ||
| 97 | fmt.Printf(" %s\n\n", query) | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | tables := getDbCreateSql(d.al) | ||
| 103 | |||
| 104 | for i, mi := range modelCache.allOrdered() { | ||
| 105 | query := tables[i] | ||
| 106 | _, err := db.Exec(query) | ||
| 107 | fmt.Printf("create table `%s` \n", mi.table) | ||
| 108 | if d.verbose { | ||
| 109 | query = " " + strings.Join(strings.Split(query, "\n"), "\n ") | ||
| 110 | fmt.Println(query) | ||
| 111 | } | ||
| 112 | if err != nil { | ||
| 113 | fmt.Printf(" %s\n", err.Error()) | ||
| 114 | } | ||
| 115 | if d.verbose { | ||
| 116 | fmt.Println("") | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | type commandSqlAll struct { | ||
| 122 | al *alias | ||
| 123 | } | ||
| 124 | |||
| 125 | func (d *commandSqlAll) Parse(args []string) { | ||
| 126 | var name string | ||
| 127 | |||
| 128 | flagSet := flag.NewFlagSet("orm command: sqlall", flag.ExitOnError) | ||
| 129 | flagSet.StringVar(&name, "db", "default", "DataBase alias name") | ||
| 130 | flagSet.Parse(args) | ||
| 131 | |||
| 132 | d.al = getDbAlias(name) | ||
| 133 | } | ||
| 134 | |||
| 135 | func (d *commandSqlAll) Run() { | ||
| 136 | sqls := getDbCreateSql(d.al) | ||
| 137 | sql := strings.Join(sqls, "\n\n") | ||
| 138 | fmt.Println(sql) | ||
| 139 | } | ||
| 140 | |||
| 141 | func init() { | ||
| 142 | commands["syncdb"] = new(commandSyncDb) | ||
| 143 | commands["sqlall"] = new(commandSqlAll) | ||
| 144 | } |
orm/cmd_utils.go
0 → 100644
| 1 | package orm | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "fmt" | ||
| 5 | "os" | ||
| 6 | "strings" | ||
| 7 | ) | ||
| 8 | |||
| 9 | func getDbAlias(name string) *alias { | ||
| 10 | if al, ok := dataBaseCache.get(name); ok { | ||
| 11 | return al | ||
| 12 | } else { | ||
| 13 | fmt.Println(fmt.Sprintf("unknown DataBase alias name %s", name)) | ||
| 14 | os.Exit(2) | ||
| 15 | } | ||
| 16 | |||
| 17 | return nil | ||
| 18 | } | ||
| 19 | |||
| 20 | func getDbDropSql(al *alias) (sqls []string) { | ||
| 21 | if len(modelCache.cache) == 0 { | ||
| 22 | fmt.Println("no Model found, need register your model") | ||
| 23 | os.Exit(2) | ||
| 24 | } | ||
| 25 | |||
| 26 | Q := al.DbBaser.TableQuote() | ||
| 27 | |||
| 28 | for _, mi := range modelCache.allOrdered() { | ||
| 29 | sqls = append(sqls, fmt.Sprintf(`DROP TABLE IF EXISTS %s%s%s`, Q, mi.table, Q)) | ||
| 30 | } | ||
| 31 | return sqls | ||
| 32 | } | ||
| 33 | |||
| 34 | func getDbCreateSql(al *alias) (sqls []string) { | ||
| 35 | if len(modelCache.cache) == 0 { | ||
| 36 | fmt.Println("no Model found, need register your model") | ||
| 37 | os.Exit(2) | ||
| 38 | } | ||
| 39 | |||
| 40 | Q := al.DbBaser.TableQuote() | ||
| 41 | T := al.DbBaser.DbTypes() | ||
| 42 | |||
| 43 | for _, mi := range modelCache.allOrdered() { | ||
| 44 | sql := fmt.Sprintf("-- %s\n", strings.Repeat("-", 50)) | ||
| 45 | sql += fmt.Sprintf("-- Table Structure for `%s`\n", mi.fullName) | ||
| 46 | sql += fmt.Sprintf("-- %s\n", strings.Repeat("-", 50)) | ||
| 47 | |||
| 48 | sql += fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s%s%s (\n", Q, mi.table, Q) | ||
| 49 | |||
| 50 | columns := make([]string, 0, len(mi.fields.fieldsDB)) | ||
| 51 | |||
| 52 | for _, fi := range mi.fields.fieldsDB { | ||
| 53 | |||
| 54 | fieldType := fi.fieldType | ||
| 55 | column := fmt.Sprintf(" %s%s%s ", Q, fi.column, Q) | ||
| 56 | col := "" | ||
| 57 | |||
| 58 | checkColumn: | ||
| 59 | switch fieldType { | ||
| 60 | case TypeBooleanField: | ||
| 61 | col = T["bool"] | ||
| 62 | case TypeCharField: | ||
| 63 | col = fmt.Sprintf(T["string"], fi.size) | ||
| 64 | case TypeTextField: | ||
| 65 | col = T["string-text"] | ||
| 66 | case TypeDateField: | ||
| 67 | col = T["time.Time-date"] | ||
| 68 | case TypeDateTimeField: | ||
| 69 | col = T["time.Time"] | ||
| 70 | case TypeBitField: | ||
| 71 | col = T["int8"] | ||
| 72 | case TypeSmallIntegerField: | ||
| 73 | col = T["int16"] | ||
| 74 | case TypeIntegerField: | ||
| 75 | col = T["int32"] | ||
| 76 | case TypeBigIntegerField: | ||
| 77 | if al.Driver == DR_Sqlite { | ||
| 78 | fieldType = TypeIntegerField | ||
| 79 | goto checkColumn | ||
| 80 | } | ||
| 81 | col = T["int64"] | ||
| 82 | case TypePositiveBitField: | ||
| 83 | col = T["uint8"] | ||
| 84 | case TypePositiveSmallIntegerField: | ||
| 85 | col = T["uint16"] | ||
| 86 | case TypePositiveIntegerField: | ||
| 87 | col = T["uint32"] | ||
| 88 | case TypePositiveBigIntegerField: | ||
| 89 | col = T["uint64"] | ||
| 90 | case TypeFloatField: | ||
| 91 | col = T["float64"] | ||
| 92 | case TypeDecimalField: | ||
| 93 | s := T["float64-decimal"] | ||
| 94 | if strings.Index(s, "%d") == -1 { | ||
| 95 | col = s | ||
| 96 | } else { | ||
| 97 | col = fmt.Sprintf(s, fi.digits, fi.decimals) | ||
| 98 | } | ||
| 99 | case RelForeignKey, RelOneToOne: | ||
| 100 | fieldType = fi.relModelInfo.fields.pk.fieldType | ||
| 101 | goto checkColumn | ||
| 102 | } | ||
| 103 | |||
| 104 | if fi.auto { | ||
| 105 | if al.Driver == DR_Postgres { | ||
| 106 | column += T["auto"] | ||
| 107 | } else { | ||
| 108 | column += col + " " + T["auto"] | ||
| 109 | } | ||
| 110 | } else if fi.pk { | ||
| 111 | column += col + " " + T["pk"] | ||
| 112 | } else { | ||
| 113 | column += col | ||
| 114 | |||
| 115 | if fi.null == false { | ||
| 116 | column += " " + "NOT NULL" | ||
| 117 | } | ||
| 118 | |||
| 119 | if fi.unique { | ||
| 120 | column += " " + "UNIQUE" | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | if strings.Index(column, "%COL%") != -1 { | ||
| 125 | column = strings.Replace(column, "%COL%", fi.column, -1) | ||
| 126 | } | ||
| 127 | |||
| 128 | columns = append(columns, column) | ||
| 129 | } | ||
| 130 | |||
| 131 | sql += strings.Join(columns, ",\n") | ||
| 132 | sql += "\n)" | ||
| 133 | |||
| 134 | if al.Driver == DR_MySQL { | ||
| 135 | sql += " ENGINE=INNODB" | ||
| 136 | } | ||
| 137 | |||
| 138 | sqls = append(sqls, sql) | ||
| 139 | } | ||
| 140 | |||
| 141 | return sqls | ||
| 142 | } |
orm/command.go
deleted
100644 → 0
| 1 | package orm | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "flag" | ||
| 5 | "fmt" | ||
| 6 | "os" | ||
| 7 | ) | ||
| 8 | |||
| 9 | func printHelp() { | ||
| 10 | |||
| 11 | } | ||
| 12 | |||
| 13 | func getSqlAll() (sql string) { | ||
| 14 | for _, mi := range modelCache.allOrdered() { | ||
| 15 | _ = mi | ||
| 16 | } | ||
| 17 | return | ||
| 18 | } | ||
| 19 | |||
| 20 | func runCommand() { | ||
| 21 | if len(os.Args) < 2 || os.Args[1] != "orm" { | ||
| 22 | return | ||
| 23 | } | ||
| 24 | |||
| 25 | _ = flag.NewFlagSet("orm command", flag.ExitOnError) | ||
| 26 | |||
| 27 | args := argString(os.Args[2:]) | ||
| 28 | cmd := args.Get(0) | ||
| 29 | |||
| 30 | switch cmd { | ||
| 31 | case "syncdb": | ||
| 32 | case "sqlall": | ||
| 33 | sql := getSqlAll() | ||
| 34 | fmt.Println(sql) | ||
| 35 | default: | ||
| 36 | if cmd != "" { | ||
| 37 | fmt.Printf("unknown command %s", cmd) | ||
| 38 | } else { | ||
| 39 | printHelp() | ||
| 40 | } | ||
| 41 | |||
| 42 | os.Exit(2) | ||
| 43 | } | ||
| 44 | } |
| ... | @@ -805,7 +805,7 @@ setValue: | ... | @@ -805,7 +805,7 @@ setValue: |
| 805 | _, err = str.Int32() | 805 | _, err = str.Int32() |
| 806 | case TypeBigIntegerField: | 806 | case TypeBigIntegerField: |
| 807 | _, err = str.Int64() | 807 | _, err = str.Int64() |
| 808 | case TypePostiveBitField: | 808 | case TypePositiveBitField: |
| 809 | _, err = str.Uint8() | 809 | _, err = str.Uint8() |
| 810 | case TypePositiveSmallIntegerField: | 810 | case TypePositiveSmallIntegerField: |
| 811 | _, err = str.Uint16() | 811 | _, err = str.Uint16() |
| ... | @@ -1112,3 +1112,7 @@ func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) { | ... | @@ -1112,3 +1112,7 @@ func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) { |
| 1112 | func (d *dbBase) TimeToDB(t *time.Time, tz *time.Location) { | 1112 | func (d *dbBase) TimeToDB(t *time.Time, tz *time.Location) { |
| 1113 | *t = t.In(tz) | 1113 | *t = t.In(tz) |
| 1114 | } | 1114 | } |
| 1115 | |||
| 1116 | func (d *dbBase) DbTypes() map[string]string { | ||
| 1117 | return nil | ||
| 1118 | } | ... | ... |
| ... | @@ -17,6 +17,26 @@ var mysqlOperators = map[string]string{ | ... | @@ -17,6 +17,26 @@ var mysqlOperators = map[string]string{ |
| 17 | "iendswith": "LIKE ?", | 17 | "iendswith": "LIKE ?", |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | var mysqlTypes = map[string]string{ | ||
| 21 | "auto": "AUTO_INCREMENT NOT NULL PRIMARY KEY", | ||
| 22 | "pk": "NOT NULL PRIMARY KEY", | ||
| 23 | "bool": "bool", | ||
| 24 | "string": "varchar(%d)", | ||
| 25 | "string-text": "longtext", | ||
| 26 | "time.Time-date": "date", | ||
| 27 | "time.Time": "datetime", | ||
| 28 | "int8": "tinyint", | ||
| 29 | "int16": "smallint", | ||
| 30 | "int32": "integer", | ||
| 31 | "int64": "bigint", | ||
| 32 | "uint8": "tinyint unsigned", | ||
| 33 | "uint16": "smallint unsigned", | ||
| 34 | "uint32": "integer unsigned", | ||
| 35 | "uint64": "bigint unsigned", | ||
| 36 | "float64": "double precision", | ||
| 37 | "float64-decimal": "numeric(%d, %d)", | ||
| 38 | } | ||
| 39 | |||
| 20 | type dbBaseMysql struct { | 40 | type dbBaseMysql struct { |
| 21 | dbBase | 41 | dbBase |
| 22 | } | 42 | } |
| ... | @@ -27,6 +47,10 @@ func (d *dbBaseMysql) OperatorSql(operator string) string { | ... | @@ -27,6 +47,10 @@ func (d *dbBaseMysql) OperatorSql(operator string) string { |
| 27 | return mysqlOperators[operator] | 47 | return mysqlOperators[operator] |
| 28 | } | 48 | } |
| 29 | 49 | ||
| 50 | func (d *dbBaseMysql) DbTypes() map[string]string { | ||
| 51 | return mysqlTypes | ||
| 52 | } | ||
| 53 | |||
| 30 | func newdbBaseMysql() dbBaser { | 54 | func newdbBaseMysql() dbBaser { |
| 31 | b := new(dbBaseMysql) | 55 | b := new(dbBaseMysql) |
| 32 | b.ins = b | 56 | b.ins = b | ... | ... |
| ... | @@ -20,6 +20,26 @@ var postgresOperators = map[string]string{ | ... | @@ -20,6 +20,26 @@ var postgresOperators = map[string]string{ |
| 20 | "iendswith": "LIKE UPPER(?)", | 20 | "iendswith": "LIKE UPPER(?)", |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | var postgresTypes = map[string]string{ | ||
| 24 | "auto": "serial NOT NULL PRIMARY KEY", | ||
| 25 | "pk": "NOT NULL PRIMARY KEY", | ||
| 26 | "bool": "bool", | ||
| 27 | "string": "varchar(%d)", | ||
| 28 | "string-text": "text", | ||
| 29 | "time.Time-date": "date", | ||
| 30 | "time.Time": "timestamp with time zone", | ||
| 31 | "int8": `smallint CHECK("%COL%" >= -127 AND "%COL%" <= 128)`, | ||
| 32 | "int16": "smallint", | ||
| 33 | "int32": "integer", | ||
| 34 | "int64": "bigint", | ||
| 35 | "uint8": `smallint CHECK("%COL%" >= 0 AND "%COL%" <= 255)`, | ||
| 36 | "uint16": `integer CHECK("%COL%" >= 0)`, | ||
| 37 | "uint32": `bigint CHECK("%COL%" >= 0)`, | ||
| 38 | "uint64": `bigint CHECK("%COL%" >= 0)`, | ||
| 39 | "float64": "double precision", | ||
| 40 | "float64-decimal": "numeric(%d, %d)", | ||
| 41 | } | ||
| 42 | |||
| 23 | type dbBasePostgres struct { | 43 | type dbBasePostgres struct { |
| 24 | dbBase | 44 | dbBase |
| 25 | } | 45 | } |
| ... | @@ -87,6 +107,10 @@ func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool) | ... | @@ -87,6 +107,10 @@ func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool) |
| 87 | return | 107 | return |
| 88 | } | 108 | } |
| 89 | 109 | ||
| 110 | func (d *dbBasePostgres) DbTypes() map[string]string { | ||
| 111 | return postgresTypes | ||
| 112 | } | ||
| 113 | |||
| 90 | func newdbBasePostgres() dbBaser { | 114 | func newdbBasePostgres() dbBaser { |
| 91 | b := new(dbBasePostgres) | 115 | b := new(dbBasePostgres) |
| 92 | b.ins = b | 116 | b.ins = b | ... | ... |
| ... | @@ -19,6 +19,26 @@ var sqliteOperators = map[string]string{ | ... | @@ -19,6 +19,26 @@ var sqliteOperators = map[string]string{ |
| 19 | "iendswith": "LIKE ? ESCAPE '\\'", | 19 | "iendswith": "LIKE ? ESCAPE '\\'", |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | var sqliteTypes = map[string]string{ | ||
| 23 | "auto": "NOT NULL PRIMARY KEY AUTOINCREMENT", | ||
| 24 | "pk": "NOT NULL PRIMARY KEY", | ||
| 25 | "bool": "bool", | ||
| 26 | "string": "varchar(%d)", | ||
| 27 | "string-text": "text", | ||
| 28 | "time.Time-date": "date", | ||
| 29 | "time.Time": "datetime", | ||
| 30 | "int8": "tinyint", | ||
| 31 | "int16": "smallint", | ||
| 32 | "int32": "integer", | ||
| 33 | "int64": "bigint", | ||
| 34 | "uint8": "tinyint unsigned", | ||
| 35 | "uint16": "smallint unsigned", | ||
| 36 | "uint32": "integer unsigned", | ||
| 37 | "uint64": "bigint unsigned", | ||
| 38 | "float64": "real", | ||
| 39 | "float64-decimal": "decimal", | ||
| 40 | } | ||
| 41 | |||
| 22 | type dbBaseSqlite struct { | 42 | type dbBaseSqlite struct { |
| 23 | dbBase | 43 | dbBase |
| 24 | } | 44 | } |
| ... | @@ -43,6 +63,10 @@ func (d *dbBaseSqlite) MaxLimit() uint64 { | ... | @@ -43,6 +63,10 @@ func (d *dbBaseSqlite) MaxLimit() uint64 { |
| 43 | return 9223372036854775807 | 63 | return 9223372036854775807 |
| 44 | } | 64 | } |
| 45 | 65 | ||
| 66 | func (d *dbBaseSqlite) DbTypes() map[string]string { | ||
| 67 | return sqliteTypes | ||
| 68 | } | ||
| 69 | |||
| 46 | func newdbBaseSqlite() dbBaser { | 70 | func newdbBaseSqlite() dbBaser { |
| 47 | b := new(dbBaseSqlite) | 71 | b := new(dbBaseSqlite) |
| 48 | b.ins = b | 72 | b.ins = b | ... | ... |
| ... | @@ -84,3 +84,10 @@ func (mc *_modelCache) set(table string, mi *modelInfo) *modelInfo { | ... | @@ -84,3 +84,10 @@ func (mc *_modelCache) set(table string, mi *modelInfo) *modelInfo { |
| 84 | } | 84 | } |
| 85 | return mii | 85 | return mii |
| 86 | } | 86 | } |
| 87 | |||
| 88 | func (mc *_modelCache) clean() { | ||
| 89 | mc.orders = make([]string, 0) | ||
| 90 | mc.cache = make(map[string]*modelInfo) | ||
| 91 | mc.cacheByFN = make(map[string]*modelInfo) | ||
| 92 | mc.done = false | ||
| 93 | } | ... | ... |
| ... | @@ -8,7 +8,7 @@ import ( | ... | @@ -8,7 +8,7 @@ import ( |
| 8 | "strings" | 8 | "strings" |
| 9 | ) | 9 | ) |
| 10 | 10 | ||
| 11 | func registerModel(model interface{}) { | 11 | func registerModel(model interface{}, prefix string) { |
| 12 | val := reflect.ValueOf(model) | 12 | val := reflect.ValueOf(model) |
| 13 | ind := reflect.Indirect(val) | 13 | ind := reflect.Indirect(val) |
| 14 | typ := ind.Type() | 14 | typ := ind.Type() |
| ... | @@ -17,20 +17,25 @@ func registerModel(model interface{}) { | ... | @@ -17,20 +17,25 @@ func registerModel(model interface{}) { |
| 17 | panic(fmt.Sprintf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ))) | 17 | panic(fmt.Sprintf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ))) |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | info := newModelInfo(val) | 20 | table := getTableName(val) |
| 21 | |||
| 22 | if prefix != "" { | ||
| 23 | table = prefix + table | ||
| 24 | } | ||
| 21 | 25 | ||
| 22 | name := getFullName(typ) | 26 | name := getFullName(typ) |
| 23 | if _, ok := modelCache.getByFN(name); ok { | 27 | if _, ok := modelCache.getByFN(name); ok { |
| 24 | fmt.Printf("<orm.RegisterModel> model `%s` redeclared, must be unique\n", name) | 28 | fmt.Printf("<orm.RegisterModel> model `%s` repeat register, must be unique\n", name) |
| 25 | os.Exit(2) | 29 | os.Exit(2) |
| 26 | } | 30 | } |
| 27 | 31 | ||
| 28 | table := getTableName(val) | ||
| 29 | if _, ok := modelCache.get(table); ok { | 32 | if _, ok := modelCache.get(table); ok { |
| 30 | fmt.Printf("<orm.RegisterModel> table name `%s` redeclared, must be unique\n", table) | 33 | fmt.Printf("<orm.RegisterModel> table name `%s` repeat register, must be unique\n", table) |
| 31 | os.Exit(2) | 34 | os.Exit(2) |
| 32 | } | 35 | } |
| 33 | 36 | ||
| 37 | info := newModelInfo(val) | ||
| 38 | |||
| 34 | if info.fields.pk == nil { | 39 | if info.fields.pk == nil { |
| 35 | outFor: | 40 | outFor: |
| 36 | for _, fi := range info.fields.fieldsDB { | 41 | for _, fi := range info.fields.fieldsDB { |
| ... | @@ -58,6 +63,7 @@ func registerModel(model interface{}) { | ... | @@ -58,6 +63,7 @@ func registerModel(model interface{}) { |
| 58 | info.pkg = typ.PkgPath() | 63 | info.pkg = typ.PkgPath() |
| 59 | info.model = model | 64 | info.model = model |
| 60 | info.manual = true | 65 | info.manual = true |
| 66 | |||
| 61 | modelCache.set(table, info) | 67 | modelCache.set(table, info) |
| 62 | } | 68 | } |
| 63 | 69 | ||
| ... | @@ -72,7 +78,7 @@ func bootStrap() { | ... | @@ -72,7 +78,7 @@ func bootStrap() { |
| 72 | ) | 78 | ) |
| 73 | 79 | ||
| 74 | if dataBaseCache.getDefault() == nil { | 80 | if dataBaseCache.getDefault() == nil { |
| 75 | err = fmt.Errorf("must have one register alias named `default`") | 81 | err = fmt.Errorf("must have one register DataBase alias named `default`") |
| 76 | goto end | 82 | goto end |
| 77 | } | 83 | } |
| 78 | 84 | ||
| ... | @@ -97,7 +103,7 @@ func bootStrap() { | ... | @@ -97,7 +103,7 @@ func bootStrap() { |
| 97 | switch fi.fieldType { | 103 | switch fi.fieldType { |
| 98 | case RelManyToMany: | 104 | case RelManyToMany: |
| 99 | if fi.relThrough != "" { | 105 | if fi.relThrough != "" { |
| 100 | msg := fmt.Sprintf("filed `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough) | 106 | msg := fmt.Sprintf("field `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough) |
| 101 | if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) { | 107 | if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) { |
| 102 | pn := fi.relThrough[:i] | 108 | pn := fi.relThrough[:i] |
| 103 | mn := fi.relThrough[i+1:] | 109 | mn := fi.relThrough[i+1:] |
| ... | @@ -238,11 +244,22 @@ end: | ... | @@ -238,11 +244,22 @@ end: |
| 238 | 244 | ||
| 239 | func RegisterModel(models ...interface{}) { | 245 | func RegisterModel(models ...interface{}) { |
| 240 | if modelCache.done { | 246 | if modelCache.done { |
| 241 | panic(fmt.Errorf("RegisterModel must be run begore BootStrap")) | 247 | panic(fmt.Errorf("RegisterModel must be run before BootStrap")) |
| 248 | } | ||
| 249 | |||
| 250 | for _, model := range models { | ||
| 251 | registerModel(model, "") | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | // register model with a prefix | ||
| 256 | func RegisterModelWithPrefix(prefix string, models ...interface{}) { | ||
| 257 | if modelCache.done { | ||
| 258 | panic(fmt.Errorf("RegisterModel must be run before BootStrap")) | ||
| 242 | } | 259 | } |
| 243 | 260 | ||
| 244 | for _, model := range models { | 261 | for _, model := range models { |
| 245 | registerModel(model) | 262 | registerModel(model, prefix) |
| 246 | } | 263 | } |
| 247 | } | 264 | } |
| 248 | 265 | ... | ... |
| ... | @@ -31,7 +31,7 @@ const ( | ... | @@ -31,7 +31,7 @@ const ( |
| 31 | // int64 | 31 | // int64 |
| 32 | TypeBigIntegerField | 32 | TypeBigIntegerField |
| 33 | // uint8 | 33 | // uint8 |
| 34 | TypePostiveBitField | 34 | TypePositiveBitField |
| 35 | // uint16 | 35 | // uint16 |
| 36 | TypePositiveSmallIntegerField | 36 | TypePositiveSmallIntegerField |
| 37 | // uint32 | 37 | // uint32 | ... | ... |
| ... | @@ -399,7 +399,7 @@ checkType: | ... | @@ -399,7 +399,7 @@ checkType: |
| 399 | _, err = v.Int32() | 399 | _, err = v.Int32() |
| 400 | case TypeBigIntegerField: | 400 | case TypeBigIntegerField: |
| 401 | _, err = v.Int64() | 401 | _, err = v.Int64() |
| 402 | case TypePostiveBitField: | 402 | case TypePositiveBitField: |
| 403 | _, err = v.Uint8() | 403 | _, err = v.Uint8() |
| 404 | case TypePositiveSmallIntegerField: | 404 | case TypePositiveSmallIntegerField: |
| 405 | _, err = v.Uint16() | 405 | _, err = v.Uint16() | ... | ... |
| ... | @@ -90,6 +90,9 @@ func newM2MModelInfo(m1, m2 *modelInfo) (info *modelInfo) { | ... | @@ -90,6 +90,9 @@ func newM2MModelInfo(m1, m2 *modelInfo) (info *modelInfo) { |
| 90 | fa.auto = true | 90 | fa.auto = true |
| 91 | fa.pk = true | 91 | fa.pk = true |
| 92 | fa.dbcol = true | 92 | fa.dbcol = true |
| 93 | fa.name = "Id" | ||
| 94 | fa.column = "id" | ||
| 95 | fa.fullName = info.fullName + "." + fa.name | ||
| 93 | 96 | ||
| 94 | f1.dbcol = true | 97 | f1.dbcol = true |
| 95 | f2.dbcol = true | 98 | f2.dbcol = true | ... | ... |
This diff is collapsed.
Click to expand it.
| ... | @@ -52,7 +52,7 @@ func getFieldType(val reflect.Value) (ft int, err error) { | ... | @@ -52,7 +52,7 @@ func getFieldType(val reflect.Value) (ft int, err error) { |
| 52 | case reflect.Int64: | 52 | case reflect.Int64: |
| 53 | ft = TypeBigIntegerField | 53 | ft = TypeBigIntegerField |
| 54 | case reflect.Uint8: | 54 | case reflect.Uint8: |
| 55 | ft = TypePostiveBitField | 55 | ft = TypePositiveBitField |
| 56 | case reflect.Uint16: | 56 | case reflect.Uint16: |
| 57 | ft = TypePositiveSmallIntegerField | 57 | ft = TypePositiveSmallIntegerField |
| 58 | case reflect.Uint32, reflect.Uint: | 58 | case reflect.Uint32, reflect.Uint: | ... | ... |
| ... | @@ -189,6 +189,47 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { | ... | @@ -189,6 +189,47 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { |
| 189 | } | 189 | } |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | func TestSyncDb(t *testing.T) { | ||
| 193 | RegisterModel(new(Data), new(DataNull)) | ||
| 194 | RegisterModel(new(User)) | ||
| 195 | RegisterModel(new(Profile)) | ||
| 196 | RegisterModel(new(Post)) | ||
| 197 | RegisterModel(new(Tag)) | ||
| 198 | RegisterModel(new(Comment)) | ||
| 199 | |||
| 200 | BootStrap() | ||
| 201 | |||
| 202 | al := dataBaseCache.getDefault() | ||
| 203 | db := al.DB | ||
| 204 | |||
| 205 | drops := getDbDropSql(al) | ||
| 206 | for _, query := range drops { | ||
| 207 | _, err := db.Exec(query) | ||
| 208 | throwFailNow(t, err, query) | ||
| 209 | } | ||
| 210 | |||
| 211 | tables := getDbCreateSql(al) | ||
| 212 | for _, query := range tables { | ||
| 213 | _, err := db.Exec(query) | ||
| 214 | throwFailNow(t, err, query) | ||
| 215 | } | ||
| 216 | |||
| 217 | modelCache.clean() | ||
| 218 | } | ||
| 219 | |||
| 220 | func TestRegisterModels(t *testing.T) { | ||
| 221 | RegisterModel(new(Data), new(DataNull)) | ||
| 222 | RegisterModel(new(User)) | ||
| 223 | RegisterModel(new(Profile)) | ||
| 224 | RegisterModel(new(Post)) | ||
| 225 | RegisterModel(new(Tag)) | ||
| 226 | RegisterModel(new(Comment)) | ||
| 227 | |||
| 228 | BootStrap() | ||
| 229 | |||
| 230 | dORM = NewOrm() | ||
| 231 | } | ||
| 232 | |||
| 192 | func TestModelSyntax(t *testing.T) { | 233 | func TestModelSyntax(t *testing.T) { |
| 193 | user := &User{} | 234 | user := &User{} |
| 194 | ind := reflect.ValueOf(user).Elem() | 235 | ind := reflect.ValueOf(user).Elem() | ... | ... |
| ... | @@ -132,4 +132,5 @@ type dbBaser interface { | ... | @@ -132,4 +132,5 @@ type dbBaser interface { |
| 132 | HasReturningID(*modelInfo, *string) bool | 132 | HasReturningID(*modelInfo, *string) bool |
| 133 | TimeFromDB(*time.Time, *time.Location) | 133 | TimeFromDB(*time.Time, *time.Location) |
| 134 | TimeToDB(*time.Time, *time.Location) | 134 | TimeToDB(*time.Time, *time.Location) |
| 135 | DbTypes() map[string]string | ||
| 135 | } | 136 | } | ... | ... |
-
Please register or sign in to post a comment