diff --git a/context/output.go b/context/output.go index c15f9fe7..564ef96d 100644 --- a/context/output.go +++ b/context/output.go @@ -105,7 +105,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface switch { case maxAge > 0: fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge) - case maxAge <= 0: + case maxAge < 0: fmt.Fprintf(&b, "; Max-Age=0") } } diff --git a/orm/db.go b/orm/db.go index 2a05797a..12f0f54d 100644 --- a/orm/db.go +++ b/orm/db.go @@ -833,7 +833,11 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con if err := rs.Scan(&ref); err != nil { return 0, err } - args = append(args, reflect.ValueOf(ref).Interface()) + pkValue, err := d.convertValueFromDB(mi.fields.pk, reflect.ValueOf(ref).Interface(), tz) + if err != nil { + return 0, err + } + args = append(args, pkValue) cnt++ } diff --git a/orm/models_boot.go b/orm/models_boot.go index 85d0917f..5327f754 100644 --- a/orm/models_boot.go +++ b/orm/models_boot.go @@ -75,7 +75,7 @@ func registerModel(PrefixOrSuffix string, model interface{}, isPrefix bool) { } if mi.fields.pk == nil { - fmt.Printf(" `%s` need a primary key field, default use 'id' if not set\n", name) + fmt.Printf(" `%s` needs a primary key field, default is to use 'id' if not set\n", name) os.Exit(2) } diff --git a/orm/orm.go b/orm/orm.go index 5db79386..fcf82590 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -107,7 +107,7 @@ func (o *orm) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect if mi, ok := modelCache.getByFullName(name); ok { return mi, ind } - panic(fmt.Errorf(" table: `%s` not found, maybe not RegisterModel", name)) + panic(fmt.Errorf(" table: `%s` not found, make sure it was registered with `RegisterModel()`", name)) } // get field info from model info by given field name diff --git a/orm/orm_raw.go b/orm/orm_raw.go index 1e86212a..c8e741ea 100644 --- a/orm/orm_raw.go +++ b/orm/orm_raw.go @@ -493,19 +493,33 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { } } } else { - for i := 0; i < ind.NumField(); i++ { - f := ind.Field(i) - fe := ind.Type().Field(i) - _, tags := parseStructTag(fe.Tag.Get(defaultStructTagName)) - var col string - if col = tags["column"]; col == "" { - col = snakeString(fe.Name) - } - if v, ok := columnsMp[col]; ok { - value := reflect.ValueOf(v).Elem().Interface() - o.setFieldValue(f, value) + // define recursive function + var recursiveSetField func(rv reflect.Value) + recursiveSetField = func(rv reflect.Value) { + for i := 0; i < rv.NumField(); i++ { + f := rv.Field(i) + fe := rv.Type().Field(i) + + // check if the field is a Struct + // recursive the Struct type + if fe.Type.Kind() == reflect.Struct { + recursiveSetField(f) + } + + _, tags := parseStructTag(fe.Tag.Get(defaultStructTagName)) + var col string + if col = tags["column"]; col == "" { + col = snakeString(fe.Name) + } + if v, ok := columnsMp[col]; ok { + value := reflect.ValueOf(v).Elem().Interface() + o.setFieldValue(f, value) + } } } + + // init call the recursive function + recursiveSetField(ind) } if eTyps[0].Kind() == reflect.Ptr { diff --git a/orm/orm_test.go b/orm/orm_test.go index c5bfa8b9..f1f2d85e 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -1661,6 +1661,13 @@ func TestRawQueryRow(t *testing.T) { throwFail(t, AssertIs(pid, nil)) } +// user_profile table +type userProfile struct { + User + Age int + Money float64 +} + func TestQueryRows(t *testing.T) { Q := dDbBaser.TableQuote() @@ -1731,6 +1738,19 @@ func TestQueryRows(t *testing.T) { throwFailNow(t, AssertIs(usernames[1], "astaxie")) throwFailNow(t, AssertIs(ids[2], 4)) throwFailNow(t, AssertIs(usernames[2], "nobody")) + + //test query rows by nested struct + var l []userProfile + query = fmt.Sprintf("SELECT * FROM %suser_profile%s LEFT JOIN %suser%s ON %suser_profile%s.%sid%s = %suser%s.%sid%s", Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q) + num, err = dORM.Raw(query).QueryRows(&l) + throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 2)) + throwFailNow(t, AssertIs(len(l), 2)) + throwFailNow(t, AssertIs(l[0].UserName, "slene")) + throwFailNow(t, AssertIs(l[0].Age, 28)) + throwFailNow(t, AssertIs(l[1].UserName, "astaxie")) + throwFailNow(t, AssertIs(l[1].Age, 30)) + } func TestRawValues(t *testing.T) { diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 20dbe030..d0424515 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -179,7 +179,7 @@ func (rp *Provider) SessionRead(sid string) (session.Store, error) { var kv map[interface{}]interface{} kvs, err := redis.String(c.Do("GET", sid)) - if err != redis.ErrNil { + if err != nil && err != redis.ErrNil { return nil, err } if len(kvs) == 0 { diff --git a/swagger/swagger.go b/swagger/swagger.go index c687fb8e..035d5a49 100644 --- a/swagger/swagger.go +++ b/swagger/swagger.go @@ -22,19 +22,19 @@ package swagger // Swagger list the resource type Swagger struct { - SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"` - Infos Information `json:"info" yaml:"info"` - Host string `json:"host,omitempty" yaml:"host,omitempty"` - BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` - Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` - Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` - Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` - Paths map[string]*Item `json:"paths" yaml:"paths"` - Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"` - SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` - Security map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` - Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"` - ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"` + Infos Information `json:"info" yaml:"info"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` + Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` + Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` + Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` + Paths map[string]*Item `json:"paths" yaml:"paths"` + Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"` + SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` + Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` + Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"` + ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` } // Information Provides metadata about the API. The metadata can be used by the clients if needed. @@ -75,16 +75,17 @@ type Item struct { // Operation Describes a single API operation on a path. type Operation struct { - Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` - Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"` - Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` - Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` - Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` - Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` - Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` - Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"` + Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` + Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` + Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` + Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` + Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` + Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` } // Parameter Describes a single operation parameter. diff --git a/templatefunc.go b/templatefunc.go index a6f9c961..2591c88e 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -53,21 +53,21 @@ func Substr(s string, start, length int) string { // HTML2str returns escaping text convert from html. func HTML2str(html string) string { - re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") + re, _ := regexp.Compile(`\<[\S\s]+?\>`) html = re.ReplaceAllStringFunc(html, strings.ToLower) //remove STYLE - re, _ = regexp.Compile("\\") + re, _ = regexp.Compile(`\`) html = re.ReplaceAllString(html, "") //remove SCRIPT - re, _ = regexp.Compile("\\") + re, _ = regexp.Compile(`\`) html = re.ReplaceAllString(html, "") - re, _ = regexp.Compile("\\<[\\S\\s]+?\\>") + re, _ = regexp.Compile(`\<[\S\s]+?\>`) html = re.ReplaceAllString(html, "\n") - re, _ = regexp.Compile("\\s{2,}") + re, _ = regexp.Compile(`\s{2,}`) html = re.ReplaceAllString(html, "\n") return strings.TrimSpace(html) diff --git a/validation/validation_test.go b/validation/validation_test.go index 83e881bf..cb7a297e 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -175,10 +175,10 @@ func TestAlphaNumeric(t *testing.T) { func TestMatch(t *testing.T) { valid := Validation{} - if valid.Match("suchuangji@gmail", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok { + if valid.Match("suchuangji@gmail", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok { t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be false") } - if !valid.Match("suchuangji@gmail.com", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok { + if !valid.Match("suchuangji@gmail.com", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok { t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be true") } } @@ -186,10 +186,10 @@ func TestMatch(t *testing.T) { func TestNoMatch(t *testing.T) { valid := Validation{} - if valid.NoMatch("123@gmail", regexp.MustCompile("[^\\w\\d]"), "nomatch").Ok { + if valid.NoMatch("123@gmail", regexp.MustCompile(`[^\w\d]`), "nomatch").Ok { t.Error("\"123@gmail\" not match \"[^\\w\\d]\" should be false") } - if !valid.NoMatch("123gmail", regexp.MustCompile("[^\\w\\d]"), "match").Ok { + if !valid.NoMatch("123gmail", regexp.MustCompile(`[^\w\d]`), "match").Ok { t.Error("\"123@gmail\" not match \"[^\\w\\d@]\" should be true") } } diff --git a/validation/validators.go b/validation/validators.go index 01aed443..2b5ae38b 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -145,7 +145,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default error message func (r Required) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Required"]) + return MessageTmpls["Required"] } // GetKey return the r.Key @@ -364,7 +364,7 @@ func (a Alpha) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Length error message func (a Alpha) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Alpha"]) + return MessageTmpls["Alpha"] } // GetKey return the m.Key @@ -397,7 +397,7 @@ func (n Numeric) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Length error message func (n Numeric) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Numeric"]) + return MessageTmpls["Numeric"] } // GetKey return the n.Key @@ -430,7 +430,7 @@ func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Length error message func (a AlphaNumeric) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["AlphaNumeric"]) + return MessageTmpls["AlphaNumeric"] } // GetKey return the a.Key @@ -495,7 +495,7 @@ func (n NoMatch) GetLimitValue() interface{} { return n.Regexp.String() } -var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]") +var alphaDashPattern = regexp.MustCompile(`[^\d\w-_]`) // AlphaDash check not Alpha type AlphaDash struct { @@ -505,7 +505,7 @@ type AlphaDash struct { // DefaultMessage return the default AlphaDash error message func (a AlphaDash) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["AlphaDash"]) + return MessageTmpls["AlphaDash"] } // GetKey return the n.Key @@ -518,7 +518,7 @@ func (a AlphaDash) GetLimitValue() interface{} { return nil } -var emailPattern = regexp.MustCompile("^[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?$") +var emailPattern = regexp.MustCompile(`^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`) // Email check struct type Email struct { @@ -528,7 +528,7 @@ type Email struct { // DefaultMessage return the default Email error message func (e Email) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Email"]) + return MessageTmpls["Email"] } // GetKey return the n.Key @@ -541,7 +541,7 @@ func (e Email) GetLimitValue() interface{} { return nil } -var ipPattern = regexp.MustCompile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$") +var ipPattern = regexp.MustCompile(`^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$`) // IP check struct type IP struct { @@ -551,7 +551,7 @@ type IP struct { // DefaultMessage return the default IP error message func (i IP) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["IP"]) + return MessageTmpls["IP"] } // GetKey return the i.Key @@ -564,7 +564,7 @@ func (i IP) GetLimitValue() interface{} { return nil } -var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$") +var base64Pattern = regexp.MustCompile(`^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$`) // Base64 check struct type Base64 struct { @@ -574,7 +574,7 @@ type Base64 struct { // DefaultMessage return the default Base64 error message func (b Base64) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Base64"]) + return MessageTmpls["Base64"] } // GetKey return the b.Key @@ -588,7 +588,7 @@ func (b Base64) GetLimitValue() interface{} { } // just for chinese mobile phone number -var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\\d{8}$") +var mobilePattern = regexp.MustCompile(`^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\d{8}$`) // Mobile check struct type Mobile struct { @@ -598,7 +598,7 @@ type Mobile struct { // DefaultMessage return the default Mobile error message func (m Mobile) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Mobile"]) + return MessageTmpls["Mobile"] } // GetKey return the m.Key @@ -612,7 +612,7 @@ func (m Mobile) GetLimitValue() interface{} { } // just for chinese telephone number -var telPattern = regexp.MustCompile("^(0\\d{2,3}(\\-)?)?\\d{7,8}$") +var telPattern = regexp.MustCompile(`^(0\d{2,3}(\-)?)?\d{7,8}$`) // Tel check telephone struct type Tel struct { @@ -622,7 +622,7 @@ type Tel struct { // DefaultMessage return the default Tel error message func (t Tel) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Tel"]) + return MessageTmpls["Tel"] } // GetKey return the t.Key @@ -649,7 +649,7 @@ func (p Phone) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Phone error message func (p Phone) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Phone"]) + return MessageTmpls["Phone"] } // GetKey return the p.Key @@ -663,7 +663,7 @@ func (p Phone) GetLimitValue() interface{} { } // just for chinese zipcode -var zipCodePattern = regexp.MustCompile("^[1-9]\\d{5}$") +var zipCodePattern = regexp.MustCompile(`^[1-9]\d{5}$`) // ZipCode check the zip struct type ZipCode struct { @@ -673,7 +673,7 @@ type ZipCode struct { // DefaultMessage return the default Zip error message func (z ZipCode) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["ZipCode"]) + return MessageTmpls["ZipCode"] } // GetKey return the z.Key