This commit is contained in:
slene 2013-07-31 22:11:22 +08:00
parent c83d03c298
commit 2c5e062c2b
9 changed files with 228 additions and 237 deletions

231
orm/db.go
View File

@ -406,7 +406,7 @@ func (d *dbTables) getLimitSql(offset int64, limit int) (limits string) {
if limit < 0 {
// no limit
if offset > 0 {
limits = fmt.Sprintf("OFFSET %d", offset)
limits = fmt.Sprintf("LIMIT 18446744073709551615 OFFSET %d", offset)
}
} else if offset <= 0 {
limits = fmt.Sprintf("LIMIT %d", limit)
@ -732,7 +732,7 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con
refs := make([]interface{}, colsNum)
for i, _ := range refs {
var ref string
var ref interface{}
refs[i] = &ref
}
@ -842,7 +842,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
refs := make([]interface{}, colsNum)
for i, _ := range refs {
var ref string
var ref interface{}
refs[i] = &ref
}
@ -882,18 +882,20 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
lastm := mmi
mmi := fi.relModelInfo
field := reflect.Indirect(last.Field(fi.fieldIndex))
d.setColsValues(mmi, &field, mmi.fields.dbcols, trefs[:len(mmi.fields.dbcols)])
for _, fi := range mmi.fields.fieldsReverse {
if fi.reverseFieldInfo.mi == lastm {
if fi.reverseFieldInfo != nil {
field.Field(fi.fieldIndex).Set(last.Addr())
if field.IsValid() {
d.setColsValues(mmi, &field, mmi.fields.dbcols, trefs[:len(mmi.fields.dbcols)])
for _, fi := range mmi.fields.fieldsReverse {
if fi.reverseFieldInfo.mi == lastm {
if fi.reverseFieldInfo != nil {
field.Field(fi.fieldIndex).Set(last.Addr())
}
}
}
cacheV[names] = &field
cacheM[names] = mmi
last = field
}
trefs = trefs[len(mmi.fields.dbcols):]
cacheV[names] = &field
cacheM[names] = mmi
last = field
}
}
}
@ -961,10 +963,15 @@ func (d *dbBase) GetOperatorSql(mi *modelInfo, operator string, args []interface
sql = operatorsSQL[operator]
arg := params[0]
switch operator {
case "exact":
if arg == nil {
params[0] = "IS NULL"
}
case "iexact", "contains", "icontains", "startswith", "endswith", "istartswith", "iendswith":
param := strings.Replace(ToStr(arg), `%`, `\%`, -1)
switch operator {
case "iexact", "contains", "icontains":
case "iexact":
case "contains", "icontains":
param = fmt.Sprintf("%%%s%%", param)
case "startswith", "istartswith":
param = fmt.Sprintf("%s%%", param)
@ -1143,205 +1150,61 @@ setValue:
switch {
case fieldType == TypeBooleanField:
if isNative {
if value == nil {
value = false
}
field.SetBool(value.(bool))
}
case fieldType == TypeCharField || fieldType == TypeTextField:
if isNative {
if value == nil {
value = ""
}
field.SetString(value.(string))
}
case fieldType == TypeDateField || fieldType == TypeDateTimeField:
if isNative {
if value == nil {
value = time.Time{}
}
field.Set(reflect.ValueOf(value))
}
case fieldType&IsIntegerField > 0:
if fieldType&IsPostiveIntegerField > 0 {
if isNative {
if value == nil {
value = uint64(0)
}
field.SetUint(value.(uint64))
}
} else {
if isNative {
if value == nil {
value = int64(0)
}
field.SetInt(value.(int64))
}
}
case fieldType == TypeFloatField || fieldType == TypeDecimalField:
if isNative {
if value == nil {
value = float64(0)
}
field.SetFloat(value.(float64))
}
case fieldType&IsRelField > 0:
fieldType = fi.relModelInfo.fields.pk[0].fieldType
mf := reflect.New(fi.relModelInfo.addrField.Elem().Type())
md := mf.Interface().(Modeler)
md.Init(md)
field.Set(mf)
f := mf.Elem().Field(fi.relModelInfo.fields.pk[0].fieldIndex)
field = &f
goto setValue
}
if isNative == false {
fd := field.Addr().Interface().(Fielder)
err := fd.SetRaw(value)
if err != nil {
return nil, err
if value != nil {
fieldType = fi.relModelInfo.fields.pk[0].fieldType
mf := reflect.New(fi.relModelInfo.addrField.Elem().Type())
md := mf.Interface().(Modeler)
md.Init(md)
field.Set(mf)
f := mf.Elem().Field(fi.relModelInfo.fields.pk[0].fieldIndex)
field = &f
goto setValue
}
}
return value, nil
}
func (d *dbBase) xsetValue(fi *fieldInfo, val interface{}, field *reflect.Value) (interface{}, error) {
if val == nil {
return nil, nil
}
var value interface{}
var str *StrTo
switch v := val.(type) {
case []byte:
s := StrTo(string(v))
str = &s
case string:
s := StrTo(v)
str = &s
}
fieldType := fi.fieldType
isNative := fi.isFielder == false
setValue:
switch {
case fieldType == TypeBooleanField:
if str == nil {
switch v := val.(type) {
case int64:
b := v == 1
if isNative {
field.SetBool(b)
}
value = b
default:
s := StrTo(ToStr(v))
str = &s
}
}
if str != nil {
b, err := str.Bool()
if err != nil {
return nil, err
}
if isNative {
field.SetBool(b)
}
value = b
}
case fieldType == TypeCharField || fieldType == TypeTextField:
s := str.String()
if str == nil {
s = ToStr(val)
}
if isNative {
field.SetString(s)
}
value = s
case fieldType == TypeDateField || fieldType == TypeDateTimeField:
if str == nil {
switch v := val.(type) {
case time.Time:
if isNative {
field.Set(reflect.ValueOf(v))
}
value = v
default:
s := StrTo(ToStr(v))
str = &s
}
}
if str != nil {
format := format_DateTime
if fi.fieldType == TypeDateField {
format = format_Date
}
t, err := timeParse(str.String(), format)
if err != nil {
return nil, err
}
if isNative {
field.Set(reflect.ValueOf(t))
}
value = t
}
case fieldType&IsIntegerField > 0:
if str == nil {
s := StrTo(ToStr(val))
str = &s
}
if str != nil {
var err error
switch fieldType {
case TypeSmallIntegerField:
value, err = str.Int16()
case TypeIntegerField:
value, err = str.Int32()
case TypeBigIntegerField:
value, err = str.Int64()
case TypePositiveSmallIntegerField:
value, err = str.Uint16()
case TypePositiveIntegerField:
value, err = str.Uint32()
case TypePositiveBigIntegerField:
value, err = str.Uint64()
}
if err != nil {
return nil, err
}
if fieldType&IsPostiveIntegerField > 0 {
v, _ := str.Uint64()
if isNative {
field.SetUint(v)
}
} else {
v, _ := str.Int64()
if isNative {
field.SetInt(v)
}
}
}
case fieldType == TypeFloatField || fieldType == TypeDecimalField:
if str == nil {
switch v := val.(type) {
case float64:
if isNative {
field.SetFloat(v)
}
value = v
default:
s := StrTo(ToStr(v))
str = &s
}
}
if str != nil {
v, err := str.Float64()
if err != nil {
return nil, err
}
if isNative {
field.SetFloat(v)
}
value = v
}
case fieldType&IsRelField > 0:
fieldType = fi.relModelInfo.fields.pk[0].fieldType
mf := reflect.New(fi.relModelInfo.addrField.Elem().Type())
md := mf.Interface().(Modeler)
md.Init(md)
field.Set(mf)
f := mf.Elem().Field(fi.relModelInfo.fields.pk[0].fieldIndex)
field = &f
goto setValue
}
if isNative == false {
fd := field.Addr().Interface().(Fielder)
err := fd.SetRaw(value)
@ -1420,7 +1283,7 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
refs := make([]interface{}, len(cols))
for i, _ := range refs {
var ref string
var ref interface{}
refs[i] = &ref
}

View File

@ -113,15 +113,18 @@ end:
}
func RegisterDriver(name string, typ driverType) {
if _, ok := drivers[name]; ok == false {
if t, ok := drivers[name]; ok == false {
drivers[name] = typ
} else {
fmt.Println("name `%s` db driver already registered")
os.Exit(2)
if t != typ {
fmt.Println("name `%s` db driver already registered and is other type")
os.Exit(2)
}
}
}
func init() {
// RegisterDriver("mysql", DR_MySQL)
RegisterDriver("mymysql", DR_MySQL)
RegisterDriver("mysql", DR_MySQL)
RegisterDriver("postgres", DR_Postgres)
RegisterDriver("sqlite3", DR_Sqlite)
}

View File

@ -26,7 +26,7 @@ var (
"auto": 1,
"auto_now": 1,
"auto_now_add": 1,
"max_length": 2,
"size": 2,
"choices": 2,
"column": 2,
"default": 2,
@ -37,6 +37,7 @@ var (
"digits": 2,
"decimals": 2,
"on_delete": 2,
"type": 2,
}
)

View File

@ -93,10 +93,16 @@ func (e *BooleanField) RawValue() interface{} {
return e.Value()
}
func (e *BooleanField) Clean() error {
return nil
}
var _ Fielder = new(BooleanField)
// A string field
// required values tag: max_length
// The max_length is enforced at the database level and in modelss validation.
// eg: `max_length:"120"`
// required values tag: size
// The size is enforced at the database level and in modelss validation.
// eg: `orm:"size(120)"`
type CharField string
func (e CharField) Value() string {
@ -129,6 +135,12 @@ func (e *CharField) RawValue() interface{} {
return e.Value()
}
func (e *CharField) Clean() error {
return nil
}
var _ Fielder = new(CharField)
// A date, represented in go by a time.Time instance.
// only date values like 2006-01-02
// Has a few extra, optional attr tag:
@ -141,7 +153,7 @@ func (e *CharField) RawValue() interface{} {
// Automatically set the field to now when the object is first created. Useful for creation of timestamps.
// Note that the current date is always used; its not just a default value that you can override.
//
// eg: `attr:"auto_now"` or `attr:"auto_now_add"`
// eg: `orm:"auto_now"` or `orm:"auto_now_add"`
type DateField time.Time
func (e DateField) Value() time.Time {
@ -180,6 +192,12 @@ func (e *DateField) RawValue() interface{} {
return e.Value()
}
func (e *DateField) Clean() error {
return nil
}
var _ Fielder = new(DateField)
// A date, represented in go by a time.Time instance.
// datetime values like 2006-01-02 15:04:05
// Takes the same extra arguments as DateField.
@ -221,6 +239,12 @@ func (e *DateTimeField) RawValue() interface{} {
return e.Value()
}
func (e *DateTimeField) Clean() error {
return nil
}
var _ Fielder = new(DateTimeField)
// A floating-point number represented in go by a float32 value.
type FloatField float64
@ -261,6 +285,12 @@ func (e *FloatField) RawValue() interface{} {
return e.Value()
}
func (e *FloatField) Clean() error {
return nil
}
var _ Fielder = new(FloatField)
// -32768 to 32767
type SmallIntegerField int16
@ -299,6 +329,12 @@ func (e *SmallIntegerField) RawValue() interface{} {
return e.Value()
}
func (e *SmallIntegerField) Clean() error {
return nil
}
var _ Fielder = new(SmallIntegerField)
// -2147483648 to 2147483647
type IntegerField int32
@ -337,6 +373,12 @@ func (e *IntegerField) RawValue() interface{} {
return e.Value()
}
func (e *IntegerField) Clean() error {
return nil
}
var _ Fielder = new(IntegerField)
// -9223372036854775808 to 9223372036854775807.
type BigIntegerField int64
@ -375,6 +417,12 @@ func (e *BigIntegerField) RawValue() interface{} {
return e.Value()
}
func (e *BigIntegerField) Clean() error {
return nil
}
var _ Fielder = new(BigIntegerField)
// 0 to 65535
type PositiveSmallIntegerField uint16
@ -413,6 +461,12 @@ func (e *PositiveSmallIntegerField) RawValue() interface{} {
return e.Value()
}
func (e *PositiveSmallIntegerField) Clean() error {
return nil
}
var _ Fielder = new(PositiveSmallIntegerField)
// 0 to 4294967295
type PositiveIntegerField uint32
@ -451,6 +505,12 @@ func (e *PositiveIntegerField) RawValue() interface{} {
return e.Value()
}
func (e *PositiveIntegerField) Clean() error {
return nil
}
var _ Fielder = new(PositiveIntegerField)
// 0 to 18446744073709551615
type PositiveBigIntegerField uint64
@ -489,6 +549,12 @@ func (e *PositiveBigIntegerField) RawValue() interface{} {
return e.Value()
}
func (e *PositiveBigIntegerField) Clean() error {
return nil
}
var _ Fielder = new(PositiveBigIntegerField)
// A large text field.
type TextField string
@ -521,3 +587,9 @@ func (e *TextField) SetRaw(value interface{}) error {
func (e *TextField) RawValue() interface{} {
return e.Value()
}
func (e *TextField) Clean() error {
return nil
}
var _ Fielder = new(TextField)

View File

@ -145,7 +145,7 @@ type fieldInfo struct {
unique bool
initial StrTo
choices fieldChoices
maxLength int
size int
auto_now bool
auto_now_add bool
rel bool
@ -188,7 +188,7 @@ func newFieldInfo(mi *modelInfo, field reflect.Value, sf reflect.StructField) (f
digits := tags["digits"]
decimals := tags["decimals"]
maxLength := tags["max_length"]
size := tags["size"]
onDelete := tags["on_delete"]
checkType:
@ -248,13 +248,13 @@ checkType:
if err != nil {
goto end
}
if fieldType == TypeTextField && maxLength != "" {
if fieldType == TypeTextField && size != "" {
fieldType = TypeCharField
}
if fieldType == TypeFloatField && (digits != "" || decimals != "") {
fieldType = TypeDecimalField
}
if fieldType == TypeDateTimeField && attrs["date"] {
if fieldType == TypeDateTimeField && tags["type"] == "date" {
fieldType = TypeDateField
}
}
@ -354,15 +354,15 @@ checkType:
switch fieldType {
case TypeBooleanField:
case TypeCharField:
if maxLength != "" {
v, e := StrTo(maxLength).Int32()
if size != "" {
v, e := StrTo(size).Int32()
if e != nil {
err = fmt.Errorf("wrong maxLength value `%s`", maxLength)
err = fmt.Errorf("wrong size value `%s`", size)
} else {
fi.maxLength = int(v)
fi.size = int(v)
}
} else {
err = fmt.Errorf("maxLength must be specify")
err = fmt.Errorf("size must be specify")
}
case TypeTextField:
fi.index = false
@ -417,7 +417,6 @@ checkType:
}
if fi.unique {
fi.null = false
fi.blank = false
fi.index = false
}
@ -484,7 +483,6 @@ checkType:
fi.choices = choices
fi.initial = initial
end:
if err != nil {
return nil, err

View File

@ -2,15 +2,43 @@ package orm
import ()
// non cleaned field errors
type FieldErrors map[string]error
func (fe FieldErrors) Get(name string) error {
return fe[name]
type fieldError struct {
name string
err error
}
func (fe FieldErrors) Set(name string, value error) {
fe[name] = value
func (f *fieldError) Name() string {
return f.name
}
func (f *fieldError) Error() error {
return f.err
}
func NewFieldError(name string, err error) IFieldError {
return &fieldError{name, err}
}
// non cleaned field errors
type fieldErrors struct {
errors map[string]IFieldError
errorList []IFieldError
}
func (fe *fieldErrors) Get(name string) IFieldError {
return fe.errors[name]
}
func (fe *fieldErrors) Set(name string, value IFieldError) {
fe.errors[name] = value
}
func (fe *fieldErrors) List() []IFieldError {
return fe.errorList
}
func NewFieldErrors() IFieldErrors {
return &fieldErrors{errors: make(map[string]IFieldError)}
}
type Manager struct {
@ -43,11 +71,11 @@ func (m *Manager) IsInited() bool {
return m.inited
}
func (m *Manager) Clean() FieldErrors {
func (m *Manager) Clean() IFieldErrors {
return nil
}
func (m *Manager) CleanFields(name string) FieldErrors {
func (m *Manager) CleanFields(name string) IFieldErrors {
return nil
}

View File

@ -75,11 +75,20 @@ func (o *object) Update() (int64, error) {
if err != nil {
return num, err
}
return 0, nil
return num, nil
}
func (o *object) Delete() (int64, error) {
return o.orm.alias.DbBaser.Delete(o.orm.db, o.mi, o.ind)
num, err := o.orm.alias.DbBaser.Delete(o.orm.db, o.mi, o.ind)
if err != nil {
return num, err
}
if num > 0 {
if o.mi.fields.auto != nil {
o.ind.Field(o.mi.fields.auto.fieldIndex).SetInt(0)
}
}
return num, nil
}
func newObject(orm *orm, mi *modelInfo, md Modeler) ObjectSeter {

View File

@ -16,40 +16,46 @@ type querySet struct {
}
func (o *querySet) Filter(expr string, args ...interface{}) QuerySeter {
o = o.clone()
if o.cond == nil {
o.cond = NewCondition()
}
o.cond.And(expr, args...)
return o.Clone()
return o
}
func (o *querySet) Exclude(expr string, args ...interface{}) QuerySeter {
o = o.clone()
if o.cond == nil {
o.cond = NewCondition()
}
o.cond.AndNot(expr, args...)
return o.Clone()
return o
}
func (o *querySet) Limit(limit int, args ...int64) QuerySeter {
o = o.clone()
o.limit = limit
if len(args) > 0 {
o.offset = args[0]
}
return o.Clone()
return o
}
func (o *querySet) Offset(offset int64) QuerySeter {
o = o.clone()
o.offset = offset
return o.Clone()
return o
}
func (o *querySet) OrderBy(orders ...string) QuerySeter {
o.orders = orders
return o.Clone()
func (o *querySet) OrderBy(exprs ...string) QuerySeter {
o = o.clone()
o.orders = exprs
return o
}
func (o *querySet) RelatedSel(params ...interface{}) QuerySeter {
o = o.clone()
var related []string
if len(params) == 0 {
o.relDepth = DefaultRelsDepth
@ -66,19 +72,19 @@ func (o *querySet) RelatedSel(params ...interface{}) QuerySeter {
}
}
o.related = related
return o.Clone()
return o
}
func (o querySet) Clone() QuerySeter {
func (o querySet) clone() *querySet {
if o.cond != nil {
o.cond = o.cond.Clone()
}
return &o
}
func (o *querySet) SetCond(cond *Condition) error {
func (o querySet) SetCond(cond *Condition) QuerySeter {
o.cond = cond
return nil
return &o
}
func (o *querySet) Count() (int64, error) {
@ -112,16 +118,16 @@ func (o *querySet) One(container Modeler) error {
return nil
}
func (o *querySet) Values(results *[]Params, args ...string) (int64, error) {
return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, args, results)
func (o *querySet) Values(results *[]Params, exprs ...string) (int64, error) {
return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, exprs, results)
}
func (o *querySet) ValuesList(results *[]ParamsList, args ...string) (int64, error) {
return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, args, results)
func (o *querySet) ValuesList(results *[]ParamsList, exprs ...string) (int64, error) {
return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, exprs, results)
}
func (o *querySet) ValuesFlat(result *ParamsList, arg string) (int64, error) {
return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, []string{arg}, result)
func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) {
return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, []string{expr}, result)
}
func newQuerySet(orm *orm, mi *modelInfo) QuerySeter {

View File

@ -10,13 +10,14 @@ type Fielder interface {
FieldType() int
SetRaw(interface{}) error
RawValue() interface{}
Clean() error
}
type Modeler interface {
Init(Modeler) Modeler
IsInited() bool
Clean() FieldErrors
CleanFields(string) FieldErrors
Clean() IFieldErrors
CleanFields(string) IFieldErrors
GetTableName() string
}
@ -48,8 +49,7 @@ type QuerySeter interface {
Offset(int64) QuerySeter
OrderBy(...string) QuerySeter
RelatedSel(...interface{}) QuerySeter
Clone() QuerySeter
SetCond(*Condition) error
SetCond(*Condition) QuerySeter
Count() (int64, error)
Update(Params) (int64, error)
Delete() (int64, error)
@ -75,6 +75,17 @@ type RawSeter interface {
Prepare() (RawPreparer, error)
}
type IFieldError interface {
Name() string
Error() error
}
type IFieldErrors interface {
Get(string) IFieldError
Set(string, IFieldError)
List() []IFieldError
}
type dbQuerier interface {
Prepare(query string) (*sql.Stmt, error)
Exec(query string, args ...interface{}) (sql.Result, error)