From d1c09cb21d3d2483b1491e1e7938710be8ac4817 Mon Sep 17 00:00:00 2001 From: huangqian Date: Fri, 29 Oct 2021 22:37:38 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BB=A5=E4=B8=8B?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E8=A7=84=E5=88=99=E7=A4=BA=E4=BE=8B=E6=96=B9?= =?UTF-8?q?=E6=B3=95=201.=20required=202.required-if=203.required-unless?= =?UTF-8?q?=204.required-with=205.required-with-all=206.required-without?= =?UTF-8?q?=207.required-without-all=208.same=209.different=2010.in=2011.n?= =?UTF-8?q?ot-in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/gvalid/gvalid_z_example_test.go | 259 ++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 4 deletions(-) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index bc0c4f0dc..aab2c8644 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -10,14 +10,13 @@ import ( "context" "errors" "fmt" - "github.com/gogf/gf/v2/os/gctx" - "math" - "reflect" - "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gvalid" + "math" + "reflect" ) func ExampleCheckMap() { @@ -276,3 +275,255 @@ func ExampleValidator_CheckStruct() { // Output: // [map[Type:map[required:请选择用户类型]]] } + +func ExampleValidator_Required() { + type BizReq struct { + Id uint `v:"required"` + Name string `v:"required"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Name field is required +} + +func ExampleValidator_RequiredIf() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string `v:"required-if:gender,1"` + HusbandName string `v:"required-if:gender,2"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The WifeName field is required +} + +func ExampleValidator_RequiredUnless() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string `v:"required-unless:gender,0,gender,2"` + HusbandName string `v:"required-unless:id,0,gender,2"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The WifeName field is required; The HusbandName field is required +} + +func ExampleValidator_RequiredWith() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-with:WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + WifeName: "Ann", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_RequiredWithAll() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-with-all:Id,Name,Gender,WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + WifeName: "Ann", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_RequiredWithout() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-without:Id,WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_RequiredWithoutAll() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-without-all:Id,WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_Same() { + type BizReq struct { + Name string `v:"required"` + Password string `v:"required|same:Password2"` + Password2 string `v:"required"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "gf", + Password: "goframe.org", + Password2: "goframe.net", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Password value must be the same as field Password2 +} + +func ExampleValidator_Different() { + type BizReq struct { + Name string `v:"required"` + MailAddr string `v:"required"` + OtherMailAddr string `v:"required|different:MailAddr"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "gf", + MailAddr: "gf@goframe.org", + OtherMailAddr: "gf@goframe.org", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The OtherMailAddr value must be different from field MailAddr +} + +func ExampleValidator_In() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 3, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Gender value is not in acceptable range +} + +func ExampleValidator_NotIn() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + InvalidIndex uint `v:"not-in:-1,0,1"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + InvalidIndex: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The InvalidIndex value is not in acceptable range +} From 4b3eb09492cc61435cede6dc9e247ac96f900b31 Mon Sep 17 00:00:00 2001 From: huangqian Date: Fri, 29 Oct 2021 22:37:38 +0800 Subject: [PATCH 02/17] Complete the following verification rule example method 1. required 2.required-if 3.required-unless 4.required-with 5.required-with-all 6.required-without 7.required-without-all 8.same 9.different 10.in 11.not-in --- util/gvalid/gvalid_z_example_test.go | 259 ++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 4 deletions(-) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index bc0c4f0dc..aab2c8644 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -10,14 +10,13 @@ import ( "context" "errors" "fmt" - "github.com/gogf/gf/v2/os/gctx" - "math" - "reflect" - "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gvalid" + "math" + "reflect" ) func ExampleCheckMap() { @@ -276,3 +275,255 @@ func ExampleValidator_CheckStruct() { // Output: // [map[Type:map[required:请选择用户类型]]] } + +func ExampleValidator_Required() { + type BizReq struct { + Id uint `v:"required"` + Name string `v:"required"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Name field is required +} + +func ExampleValidator_RequiredIf() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string `v:"required-if:gender,1"` + HusbandName string `v:"required-if:gender,2"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The WifeName field is required +} + +func ExampleValidator_RequiredUnless() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string `v:"required-unless:gender,0,gender,2"` + HusbandName string `v:"required-unless:id,0,gender,2"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The WifeName field is required; The HusbandName field is required +} + +func ExampleValidator_RequiredWith() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-with:WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + WifeName: "Ann", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_RequiredWithAll() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-with-all:Id,Name,Gender,WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + WifeName: "Ann", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_RequiredWithout() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-without:Id,WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_RequiredWithoutAll() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + WifeName string + HusbandName string `v:"required-without-all:Id,WifeName"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "test", + Gender: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The HusbandName field is required +} + +func ExampleValidator_Same() { + type BizReq struct { + Name string `v:"required"` + Password string `v:"required|same:Password2"` + Password2 string `v:"required"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "gf", + Password: "goframe.org", + Password2: "goframe.net", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Password value must be the same as field Password2 +} + +func ExampleValidator_Different() { + type BizReq struct { + Name string `v:"required"` + MailAddr string `v:"required"` + OtherMailAddr string `v:"required|different:MailAddr"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "gf", + MailAddr: "gf@goframe.org", + OtherMailAddr: "gf@goframe.org", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The OtherMailAddr value must be different from field MailAddr +} + +func ExampleValidator_In() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 3, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Gender value is not in acceptable range +} + +func ExampleValidator_NotIn() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + InvalidIndex uint `v:"not-in:-1,0,1"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + InvalidIndex: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The InvalidIndex value is not in acceptable range +} From 191ad2043606481d5291db6a1ac2eddbe0e3a451 Mon Sep 17 00:00:00 2001 From: huangqian Date: Sun, 31 Oct 2021 23:16:54 +0800 Subject: [PATCH 03/17] Complete the following verification rule example method 1. date --- util/gvalid/gvalid_z_example_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index aab2c8644..95dee5403 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -527,3 +527,28 @@ func ExampleValidator_NotIn() { // Output: // The InvalidIndex value is not in acceptable range } + +func ExampleValidator_Date() { + type BizReq struct { + Date1 string `v:"date"` + Date2 string `v:"date"` + Date3 string `v:"date"` + Date4 string `v:"date"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Date1: "2021-10-31", + Date2: "2021.10.31", + Date3: "2021 10 31", + Date4: "31/10/2021", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Date3 value is not a valid date; The Date4 value is not a valid date +} From 94768530cc9e41d74bd1bff389d9fa74e7f4f181 Mon Sep 17 00:00:00 2001 From: huangqian Date: Tue, 2 Nov 2021 00:03:44 +0800 Subject: [PATCH 04/17] Complete the following verification rule example method 1. datetime 2.date-format 3.email 4.phone 5.phone-loose 6.telephone --- util/gvalid/gvalid_z_example_test.go | 154 ++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index 95dee5403..52fce3097 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -541,8 +541,8 @@ func ExampleValidator_Date() { req = BizReq{ Date1: "2021-10-31", Date2: "2021.10.31", - Date3: "2021 10 31", - Date4: "31/10/2021", + Date3: "2021-Oct-31", + Date4: "2021 Octa 31", } ) if err := g.Validator().CheckStruct(ctx, req); err != nil { @@ -552,3 +552,153 @@ func ExampleValidator_Date() { // Output: // The Date3 value is not a valid date; The Date4 value is not a valid date } + +func ExampleValidator_Datetime() { + type BizReq struct { + Date1 string `v:"datetime"` + Date2 string `v:"datetime"` + Date3 string `v:"datetime"` + Date4 string `v:"datetime"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Date1: "2021-11-01 23:00:00", + Date2: "2021-11-01 23:00", // error + Date3: "2021/11/01 23:00:00", // error + Date4: "2021/Dec/01 23:00:00", // error + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Date2 value is not a valid datetime; The Date3 value is not a valid datetime; The Date4 value is not a valid datetime +} + +func ExampleValidator_DateFormat() { + type BizReq struct { + Date1 string `v:"date-format:Y-m-d"` + Date2 string `v:"date-format:Y-m-d"` + Date3 string `v:"date-format:Y-m-d H:i:s"` + Date4 string `v:"date-format:Y-m-d H:i:s"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Date1: "2021-11-01", + Date2: "2021-11-01 23:00", // error + Date3: "2021-11-01 23:00:00", + Date4: "2021-11-01 23:00", // error + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Date2 value does not match the format Y-m-d; The Date4 value does not match the format Y-m-d H:i:s +} + +func ExampleValidator_Email() { + type BizReq struct { + MailAddr1 string `v:"email"` + MailAddr2 string `v:"email"` + MailAddr3 string `v:"email"` + MailAddr4 string `v:"email"` + } + + var ( + ctx = context.Background() + req = BizReq{ + MailAddr1: "gf@goframe.org", + MailAddr2: "gf@goframe", // error + MailAddr3: "gf@goframe.org.cn", + MailAddr4: "gf#goframe.org", // error + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The MailAddr2 value must be a valid email address; The MailAddr4 value must be a valid email address +} + +func ExampleValidator_Phone() { + type BizReq struct { + PhoneNumber1 string `v:"phone"` + PhoneNumber2 string `v:"phone"` + PhoneNumber3 string `v:"phone"` + PhoneNumber4 string `v:"phone"` + } + + var ( + ctx = context.Background() + req = BizReq{ + PhoneNumber1: "13578912345", + PhoneNumber2: "11578912345", // error 11x not exist + PhoneNumber3: "17178912345", // error 171 not exit + PhoneNumber4: "1357891234", // error len must be 11 + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The PhoneNumber2 value must be a valid phone number; The PhoneNumber3 value must be a valid phone number; The PhoneNumber4 value must be a valid phone number +} + +func ExampleValidator_PhoneLoose() { + type BizReq struct { + PhoneNumber1 string `v:"phone-loose"` + PhoneNumber2 string `v:"phone-loose"` + PhoneNumber3 string `v:"phone-loose"` + PhoneNumber4 string `v:"phone-loose"` + } + + var ( + ctx = context.Background() + req = BizReq{ + PhoneNumber1: "13578912345", + PhoneNumber2: "11578912345", // error 11x not exist + PhoneNumber3: "17178912345", + PhoneNumber4: "1357891234", // error len must be 11 + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The PhoneNumber2 value must be a valid phone number; The PhoneNumber4 value must be a valid phone number +} + +func ExampleValidator_Telephone() { + type BizReq struct { + Telephone1 string `v:"telephone"` + Telephone2 string `v:"telephone"` + Telephone3 string `v:"telephone"` + Telephone4 string `v:"telephone"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Telephone1: "010-77542145", + Telephone2: "0571-77542145", + Telephone3: "20-77542145", // error + Telephone4: "775421451", // error len must be 7 or 8 + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Telephone3 value must be a valid telephone number; The Telephone4 value must be a valid telephone number +} From a3eff53c69f148da6a338f79b004fca8f376a538 Mon Sep 17 00:00:00 2001 From: huangqian Date: Tue, 2 Nov 2021 11:22:34 +0800 Subject: [PATCH 05/17] Modify "date" rule Example --- util/gvalid/gvalid_z_example_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index 52fce3097..51f197793 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -534,6 +534,7 @@ func ExampleValidator_Date() { Date2 string `v:"date"` Date3 string `v:"date"` Date4 string `v:"date"` + Date5 string `v:"date"` } var ( @@ -543,6 +544,7 @@ func ExampleValidator_Date() { Date2: "2021.10.31", Date3: "2021-Oct-31", Date4: "2021 Octa 31", + Date5: "2021/Oct/31", } ) if err := g.Validator().CheckStruct(ctx, req); err != nil { @@ -550,7 +552,7 @@ func ExampleValidator_Date() { } // Output: - // The Date3 value is not a valid date; The Date4 value is not a valid date + // The Date3 value is not a valid date; The Date4 value is not a valid date; The Date5 value is not a valid date } func ExampleValidator_Datetime() { From c1f856fa8eff8e9276291e1f5169271ad3423a3d Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Tue, 2 Nov 2021 13:27:54 +0800 Subject: [PATCH 06/17] update --- container/gset/gset_z_example_str_test.go | 157 +++++++++++++++++++++- 1 file changed, 156 insertions(+), 1 deletion(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index cfa0d22e1..faa8d252e 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -12,17 +12,172 @@ import ( "github.com/gogf/gf/v2/frame/g" ) +func ExampleStrSet_NewStrSet() { + strSet := gset.NewStrSet(true) + strSet.Add([]string{"str1", "str2", "str3"}...) + + // Mya Output: + //Iterator str1 + //Iterator str2 + //Iterator str3 +} + +func ExampleStrSet_Add() { + var strSet gset.StrSet + strSet.Add([]string{"str1", "str2", "str3"}...) + + // Mya Output: + //Iterator str1 + //Iterator str2 + //Iterator str3 +} + +func ExampleStrSet_AddIfNotExist() { + var strSet gset.StrSet + fmt.Println(strSet.AddIfNotExist("str")) + + // Output: + // true +} + +func ExampleStrSet_AddIfNotExistFunc() { + var strSet gset.StrSet + fmt.Println(strSet.AddIfNotExistFunc("str", func() bool { + return true + })) + + // Output: + // true +} + +func ExampleStrSet_AddIfNotExistFuncLock() { + var strSet gset.StrSet + fmt.Println(strSet.AddIfNotExistFuncLock("str", func() bool { + return true + })) + + // Output: + // true +} + +func ExampleStrSet_Clear() { + var strSet gset.StrSet + strSet.Add([]string{"str1", "str2", "str3"}...) + + strSet.Clear() + + fmt.Println(strSet.Size()) + + // Output: + // 0 +} + +func ExampleStrSet_Complement() { + strSet := gset.NewStrSet(true) + strSet.Add([]string{"str1", "str2", "str3", "str4", "str5"}...) + + var s gset.StrSet + s.Add([]string{"str1", "str2", "str3"}...) + + fmt.Println(s.Complement(strSet).Slice()) + + // May Output: + // [str4 str5] +} + func ExampleStrSet_Contains() { var set gset.StrSet set.Add("a") fmt.Println(set.Contains("a")) fmt.Println(set.Contains("A")) - fmt.Println(set.ContainsI("A")) // Output: // true // false +} + +func ExampleStrSet_ContainsI() { + var set gset.StrSet + set.Add("a") + fmt.Println(set.ContainsI("a")) + fmt.Println(set.ContainsI("A")) + + // Output: // true + // true +} + +func ExampleStrSet_Diff() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c"}...) + var s2 gset.StrSet + s2.Add([]string{"a", "b", "c", "d"}...) + // 差集 + fmt.Println(s2.Diff(s1).Slice()) + + // Output: + // [d] +} + +func ExampleStrSet_Equal() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c"}...) + var s2 gset.StrSet + s2.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s2.Equal(s1)) + + // Output: + // false +} + +func ExampleStrSet_Intersect() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c"}...) + var s2 gset.StrSet + s2.Add([]string{"a", "b", "c", "d"}...) + // 交集 + fmt.Println(s2.Intersect(s1).Slice()) + + // May Output: + // [c a b] +} + +func ExampleStrSet_IsSubsetOf() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + var s2 gset.StrSet + s2.Add([]string{"a", "b", "d"}...) + fmt.Println(s2.IsSubsetOf(s1)) + + // Output: + // true +} + +func ExampleStrSet_Iterator() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + s1.Iterator(func(v string) bool { + fmt.Println("Iterator", v) + return true + }) + // May Output: + // Iterator a + // Iterator b + // Iterator c + // Iterator d +} + +func ExampleStrSet_Join() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s1.Join(",")) + + // May Output: + // b,c,d,a +} + +func ExampleStrSet_LockFunc() { + } func ExampleStrSet_Walk() { From 797719d8d5e38d7ed7d71e80c6abd9a098aa2feb Mon Sep 17 00:00:00 2001 From: huangqian Date: Tue, 2 Nov 2021 23:47:25 +0800 Subject: [PATCH 07/17] Complete the following verification rule example method 1. passport 2.password 3.password2 4.password3 5.postcode 6.resident-id 7.bank-card 8.qq 9.ip 10.ipv4 11.ipv6 --- util/gvalid/gvalid_z_example_test.go | 245 +++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index 51f197793..3550f1dca 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -704,3 +704,248 @@ func ExampleValidator_Telephone() { // Output: // The Telephone3 value must be a valid telephone number; The Telephone4 value must be a valid telephone number } + +func ExampleValidator_Passport() { + type BizReq struct { + Passport1 string `v:"passport"` + Passport2 string `v:"passport"` + Passport3 string `v:"passport"` + Passport4 string `v:"passport"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Passport1: "goframe", + Passport2: "1356666", // error starting with letter + Passport3: "goframe#", // error containing only numbers or underscores + Passport4: "gf", // error length between 6 and 18 + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Passport2 value is not a valid passport format; The Passport3 value is not a valid passport format; The Passport4 value is not a valid passport format +} + +func ExampleValidator_Password() { + type BizReq struct { + Password1 string `v:"password"` + Password2 string `v:"password"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Password1: "goframe", + Password2: "gofra", // error length between 6 and 18 + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Password2 value is not a valid passport format +} + +func ExampleValidator_Password2() { + type BizReq struct { + Password1 string `v:"password2"` + Password2 string `v:"password2"` + Password3 string `v:"password2"` + Password4 string `v:"password2"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Password1: "Goframe123", + Password2: "gofra", // error length between 6 and 18 + Password3: "Goframe", // error must contain lower and upper letters and numbers. + Password4: "goframe123", // error must contain lower and upper letters and numbers. + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Password2 value is not a valid passport format; The Password3 value is not a valid passport format; The Password4 value is not a valid passport format +} + +func ExampleValidator_Password3() { + type BizReq struct { + Password1 string `v:"password3"` + Password2 string `v:"password3"` + Password3 string `v:"password3"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Password1: "Goframe123#", + Password2: "gofra", // error length between 6 and 18 + Password3: "Goframe123", // error must contain lower and upper letters, numbers and special chars. + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Password2 value is not a valid passport format; The Password3 value is not a valid passport format +} + +func ExampleValidator_Postcode() { + type BizReq struct { + Postcode1 string `v:"postcode"` + Postcode2 string `v:"postcode"` + Postcode3 string `v:"postcode"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Postcode1: "100000", + Postcode2: "10000", // error length must be 6 + Postcode3: "1000000", // error length must be 6 + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Postcode2 value is not a valid passport format; The Postcode3 value is not a valid passport format +} + +func ExampleValidator_ResidentId() { + type BizReq struct { + ResidentId1 string `v:"resident-id"` + } + + var ( + ctx = context.Background() + req = BizReq{ + ResidentId1: "320107199506285482", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The ResidentId1 value is not a valid resident id number +} + +func ExampleValidator_BankCard() { + type BizReq struct { + BankCard1 string `v:"bank-card"` + } + + var ( + ctx = context.Background() + req = BizReq{ + BankCard1: "6225760079930218", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The BankCard1 value must be a valid bank card number +} + +func ExampleValidator_QQ() { + type BizReq struct { + QQ1 string `v:"qq"` + QQ2 string `v:"qq"` + QQ3 string `v:"qq"` + } + + var ( + ctx = context.Background() + req = BizReq{ + QQ1: "389961817", + QQ2: "9999", // error >= 10000 + QQ3: "514258412a", // error all number + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The QQ2 value must be a valid QQ number; The QQ3 value must be a valid QQ number +} + +func ExampleValidator_IP() { + type BizReq struct { + IP1 string `v:"ip"` + IP2 string `v:"ip"` + IP3 string `v:"ip"` + IP4 string `v:"ip"` + } + + var ( + ctx = context.Background() + req = BizReq{ + IP1: "127.0.0.1", + IP2: "fe80::812b:1158:1f43:f0d1", + IP3: "520.255.255.255", // error >= 10000 + IP4: "ze80::812b:1158:1f43:f0d1", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The IP3 value must be a valid IP address; The IP4 value must be a valid IP address +} + +func ExampleValidator_IPV4() { + type BizReq struct { + IP1 string `v:"ipv4"` + IP2 string `v:"ipv4"` + } + + var ( + ctx = context.Background() + req = BizReq{ + IP1: "127.0.0.1", + IP2: "520.255.255.255", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The IP2 value must be a valid IPv4 address +} + +func ExampleValidator_IPV6() { + type BizReq struct { + IP1 string `v:"ipv6"` + IP2 string `v:"ipv6"` + } + + var ( + ctx = context.Background() + req = BizReq{ + IP1: "fe80::812b:1158:1f43:f0d1", + IP2: "ze80::812b:1158:1f43:f0d1", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The IP2 value must be a valid IPv6 address +} From 5e34aee2d7fab23c3b160275c468a17b0ca26c4e Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Wed, 3 Nov 2021 00:49:06 +0800 Subject: [PATCH 08/17] example over --- container/gset/gset_z_example_str_test.go | 229 ++++++++++++++++++++-- 1 file changed, 214 insertions(+), 15 deletions(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index faa8d252e..671547499 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -7,21 +7,36 @@ package gset_test import ( + "encoding/json" "fmt" "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/frame/g" ) +//NewStrSet create and returns a new set, which contains un-repeated items. +//The parameter is used to specify whether using set in concurrent-safety, +//which is false in default. func ExampleStrSet_NewStrSet() { strSet := gset.NewStrSet(true) strSet.Add([]string{"str1", "str2", "str3"}...) + fmt.Println(strSet.Slice()) - // Mya Output: + // May Output: //Iterator str1 //Iterator str2 //Iterator str3 } +//NewStrSetFrom returns a new set from . +func ExampleStrSet_NewStrSetFrom() { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + fmt.Println(strSet.Slice()) + + // Output: + // [str1 str2 str3] +} + +//Add adds one or multiple items to the set. func ExampleStrSet_Add() { var strSet gset.StrSet strSet.Add([]string{"str1", "str2", "str3"}...) @@ -32,6 +47,9 @@ func ExampleStrSet_Add() { //Iterator str3 } +//AddIfNotExist checks whether item exists in the set, +//it adds the item to set and returns true if it does not exists in the set, +//or else it does nothing and returns false. func ExampleStrSet_AddIfNotExist() { var strSet gset.StrSet fmt.Println(strSet.AddIfNotExist("str")) @@ -40,6 +58,10 @@ func ExampleStrSet_AddIfNotExist() { // true } +//AddIfNotExistFunc checks whether item exists in the set, +//it adds the item to set and returns true if it does not exists in the set and function returns true, +//or else it does nothing and returns false. +//Note that, the function is executed without writing lock. func ExampleStrSet_AddIfNotExistFunc() { var strSet gset.StrSet fmt.Println(strSet.AddIfNotExistFunc("str", func() bool { @@ -50,6 +72,10 @@ func ExampleStrSet_AddIfNotExistFunc() { // true } +//AddIfNotExistFunc checks whether item exists in the set, +//it adds the item to set and returns true if it does not exists in the set and function returns true, +//or else it does nothing and returns false. +//Note that, the function is executed without writing lock. func ExampleStrSet_AddIfNotExistFuncLock() { var strSet gset.StrSet fmt.Println(strSet.AddIfNotExistFuncLock("str", func() bool { @@ -60,10 +86,9 @@ func ExampleStrSet_AddIfNotExistFuncLock() { // true } +//Clear deletes all items of the set. func ExampleStrSet_Clear() { - var strSet gset.StrSet - strSet.Add([]string{"str1", "str2", "str3"}...) - + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) strSet.Clear() fmt.Println(strSet.Size()) @@ -72,19 +97,19 @@ func ExampleStrSet_Clear() { // 0 } +//Complement returns a new set which is the complement from to . +//Which means, all the items in are in and not in . +//It returns the difference between and if the given set is not the full set of . func ExampleStrSet_Complement() { - strSet := gset.NewStrSet(true) - strSet.Add([]string{"str1", "str2", "str3", "str4", "str5"}...) - - var s gset.StrSet - s.Add([]string{"str1", "str2", "str3"}...) - + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3", "str4", "str5"}, true) + s := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) fmt.Println(s.Complement(strSet).Slice()) // May Output: // [str4 str5] } +//Contains checks whether the set contains . func ExampleStrSet_Contains() { var set gset.StrSet set.Add("a") @@ -96,6 +121,8 @@ func ExampleStrSet_Contains() { // false } +//ContainsI checks whether a value exists in the set with case-insensitively. +//Note that it internally iterates the whole set to do the comparison with case-insensitively. func ExampleStrSet_ContainsI() { var set gset.StrSet set.Add("a") @@ -107,11 +134,11 @@ func ExampleStrSet_ContainsI() { // true } +//Diff returns a new set which is the difference set from to . +//Which means, all the items in are in but not in . func ExampleStrSet_Diff() { - s1 := gset.NewStrSet(true) - s1.Add([]string{"a", "b", "c"}...) - var s2 gset.StrSet - s2.Add([]string{"a", "b", "c", "d"}...) + s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true) + s2 := gset.NewStrSetFrom([]string{"a", "b", "c", "d"}, true) // 差集 fmt.Println(s2.Diff(s1).Slice()) @@ -119,6 +146,7 @@ func ExampleStrSet_Diff() { // [d] } +//Equal checks whether the two sets equal. func ExampleStrSet_Equal() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c"}...) @@ -130,6 +158,8 @@ func ExampleStrSet_Equal() { // false } +//Intersect returns a new set which is the intersection from to . +//Which means, all the items in are in and also in . func ExampleStrSet_Intersect() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c"}...) @@ -142,6 +172,7 @@ func ExampleStrSet_Intersect() { // [c a b] } +//IsSubsetOf checks whether the current set is a sub-set of . func ExampleStrSet_IsSubsetOf() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -153,6 +184,8 @@ func ExampleStrSet_IsSubsetOf() { // true } +//Iterator iterates the set readonly with given callback function , +//if returns true then continue iterating; or false to stop. func ExampleStrSet_Iterator() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -167,6 +200,7 @@ func ExampleStrSet_Iterator() { // Iterator d } +//Join joins items with a string . func ExampleStrSet_Join() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -176,10 +210,175 @@ func ExampleStrSet_Join() { // b,c,d,a } +//LockFunc locks writing with callback function . func ExampleStrSet_LockFunc() { - + s := gset.NewStrSet(true) + s.Add([]string{"a", "b", "c", "d"}...) + s.LockFunc(func(m map[string]struct{}) { + m["a"] = struct{}{} + }) } +//MarshalJSON implements the interface MarshalJSON for json.Marshal. +func ExampleStrSet_MarshalJSON() { + type Student struct { + Id int + Name string + Scores *gset.StrSet + } + s := Student{ + Id: 1, + Name: "john", + Scores: gset.NewStrSetFrom([]string{"100", "99", "98"}, true), + } + b, _ := json.Marshal(s) + fmt.Println(string(b)) + + // May Output: + // {"Id":1,"Name":"john","Scores":["100","99","98"]} +} + +//Merge adds items from sets into . +func ExampleStrSet_Merge() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + + s2 := gset.NewStrSet(true) + fmt.Println(s1.Merge(s2).Slice()) + + // May Output: + // [d a b c] +} + +//Pops randomly pops an item from set. +func ExampleStrSet_Pop() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + + fmt.Println(s1.Pop()) + + // May Output: + // a +} + +//Pops randomly pops items from set. +//It returns all items if size == -1. +func ExampleStrSet_Pops() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + for _, v := range s1.Pops(2) { + fmt.Println(v) + } + + // May Output: + // a + // b +} + +//RLockFunc locks reading with callback function . +func ExampleStrSet_RLockFunc() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + s1.RLockFunc(func(m map[string]struct{}) { + fmt.Println(m) + }) + + // Output: + // map[a:{} b:{} c:{} d:{}] +} + +//Remove deletes from set. +func ExampleStrSet_Remove() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + s1.Remove("a") + fmt.Println(s1.Slice()) + + // Output: + // [b c d] +} + +//Size returns the size of the set. +func ExampleStrSet_Size() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s1.Size()) + + // Output: + // 4 +} + +//Slice returns the a of items of the set as slice. +func ExampleStrSet_Slice() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s1.Slice()) + + // May Output: + // [a,b,c,d] +} + +//String returns items as a string, which implements like json.Marshal does. +func ExampleStrSet_String() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s1.String()) + + // Output: + // "a","b","c","d" +} + +//Sum sums items. Note: The items should be converted to int type, +//or you'd get a result that you unexpected. +func ExampleStrSet_Sum() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s1.Sum()) + + // Output: + // 0 +} + +//Union returns a new set which is the union of and . +//Which means, all the items in are in or in . +func ExampleStrSet_Union() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + s2 := gset.NewStrSet(true) + s2.Add([]string{"a", "b", "d"}...) + fmt.Println(s1.Union(s2).Slice()) + + // May Output: + // [a b c d] +} + +//UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func ExampleStrSet_UnmarshalJSON() { + b := []byte(`{"Id":1,"Name":"john","Scores":["100","99","98"]}`) + type Student struct { + Id int + Name string + Scores *gset.StrSet + } + s := Student{} + json.Unmarshal(b, &s) + fmt.Println(s) + + // May Output: + // {1 john "99","98","100"} +} + +//UnmarshalValue is an interface implement which sets any type of value for set. +func ExampleStrSet_UnmarshalValue() { + s := gset.NewStrSetFrom([]string{"a"}, true) + s.UnmarshalValue([]string{"b", "c"}) + fmt.Println(s.Slice()) + + // Output: + // [a b c] +} + +//Walk applies a user supplied function to every item of set. func ExampleStrSet_Walk() { var ( set gset.StrSet From 274052511c732dd82b61b9568e4dc05e44bc7111 Mon Sep 17 00:00:00 2001 From: huangqian Date: Wed, 3 Nov 2021 22:20:05 +0800 Subject: [PATCH 09/17] Complete the following verification rule example method 1.mac 2.url 3.domain 4.size 5.length 6.min-length 7.max-length 8.between 9.min 10.max 11.json 12.integer 13.float 14.boolean 15.regex --- util/gvalid/gvalid_z_example_test.go | 522 ++++++++++++++++++++++----- 1 file changed, 434 insertions(+), 88 deletions(-) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index 3550f1dca..99d891ffe 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -440,94 +440,6 @@ func ExampleValidator_RequiredWithoutAll() { // The HusbandName field is required } -func ExampleValidator_Same() { - type BizReq struct { - Name string `v:"required"` - Password string `v:"required|same:Password2"` - Password2 string `v:"required"` - } - var ( - ctx = context.Background() - req = BizReq{ - Name: "gf", - Password: "goframe.org", - Password2: "goframe.net", - } - ) - if err := g.Validator().CheckStruct(ctx, req); err != nil { - fmt.Println(err) - } - - // Output: - // The Password value must be the same as field Password2 -} - -func ExampleValidator_Different() { - type BizReq struct { - Name string `v:"required"` - MailAddr string `v:"required"` - OtherMailAddr string `v:"required|different:MailAddr"` - } - var ( - ctx = context.Background() - req = BizReq{ - Name: "gf", - MailAddr: "gf@goframe.org", - OtherMailAddr: "gf@goframe.org", - } - ) - if err := g.Validator().CheckStruct(ctx, req); err != nil { - fmt.Println(err) - } - - // Output: - // The OtherMailAddr value must be different from field MailAddr -} - -func ExampleValidator_In() { - type BizReq struct { - Id uint `v:"required" dc:"Your Id"` - Name string `v:"required" dc:"Your name"` - Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` - } - var ( - ctx = context.Background() - req = BizReq{ - Id: 1, - Name: "test", - Gender: 3, - } - ) - if err := g.Validator().CheckStruct(ctx, req); err != nil { - fmt.Println(err) - } - - // Output: - // The Gender value is not in acceptable range -} - -func ExampleValidator_NotIn() { - type BizReq struct { - Id uint `v:"required" dc:"Your Id"` - Name string `v:"required" dc:"Your name"` - InvalidIndex uint `v:"not-in:-1,0,1"` - } - var ( - ctx = context.Background() - req = BizReq{ - Id: 1, - Name: "test", - InvalidIndex: 1, - } - ) - if err := g.Validator().CheckStruct(ctx, req); err != nil { - fmt.Println(err) - } - - // Output: - // The InvalidIndex value is not in acceptable range -} - func ExampleValidator_Date() { type BizReq struct { Date1 string `v:"date"` @@ -949,3 +861,437 @@ func ExampleValidator_IPV6() { // Output: // The IP2 value must be a valid IPv6 address } + +func ExampleValidator_Mac() { + type BizReq struct { + Mac1 string `v:"mac"` + Mac2 string `v:"mac"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Mac1: "4C-CC-6A-D6-B1-1A", + Mac2: "Z0-CC-6A-D6-B1-1A", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Mac2 value must be a valid MAC address +} + +func ExampleValidator_Url() { + type BizReq struct { + Url1 string `v:"url"` + Url2 string `v:"url"` + Url3 string `v:"url"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Url1: "http://goframe.org", + Url2: "ftp://goframe.org", + Url3: "ws://goframe.org", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Url3 value must be a valid URL address +} + +func ExampleValidator_Domain() { + type BizReq struct { + Domain1 string `v:"domain"` + Domain2 string `v:"domain"` + Domain3 string `v:"domain"` + Domain4 string `v:"domain"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Domain1: "goframe.org", + Domain2: "a.b", + Domain3: "goframe#org", + Domain4: "1a.2b", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Domain3 value must be a valid domain format; The Domain4 value must be a valid domain format +} + +func ExampleValidator_Size() { + type BizReq struct { + Size1 string `v:"size:10"` + Size2 string `v:"size:5"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Size1: "goframe欢迎你", + Size2: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Size2 value length must be 5 +} + +func ExampleValidator_Length() { + type BizReq struct { + Length1 string `v:"length:5,10"` + Length2 string `v:"length:10,15"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Length1: "goframe欢迎你", + Length2: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Length2 value length must be between 10 and 15 +} + +func ExampleValidator_MinLength() { + type BizReq struct { + MinLength1 string `v:"min-length:10"` + MinLength2 string `v:"min-length:8"` + } + + var ( + ctx = context.Background() + req = BizReq{ + MinLength1: "goframe欢迎你", + MinLength2: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The MinLength2 value length must be equal or greater than 8 +} + +func ExampleValidator_MaxLength() { + type BizReq struct { + MaxLength1 string `v:"max-length:10"` + MaxLength2 string `v:"max-length:5"` + } + + var ( + ctx = context.Background() + req = BizReq{ + MaxLength1: "goframe欢迎你", + MaxLength2: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The MaxLength2 value length must be equal or lesser than 5 +} + +func ExampleValidator_Between() { + type BizReq struct { + Age1 int `v:"between:1,100"` + Age2 int `v:"between:1,100"` + Score1 float32 `v:"between:0.0,10.0"` + Score2 float32 `v:"between:0.0,10.0"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Age1: 50, + Age2: 101, + Score1: 9.8, + Score2: -0.5, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Age2 value must be between 1 and 100; The Score2 value must be between 0 and 10 +} + +func ExampleValidator_Min() { + type BizReq struct { + Age1 int `v:"min:100"` + Age2 int `v:"min:100"` + Score1 float32 `v:"min:10.0"` + Score2 float32 `v:"min:10.0"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Age1: 50, + Age2: 101, + Score1: 9.8, + Score2: 10.1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Age1 value must be equal or greater than 100; The Score1 value must be equal or greater than 10 +} + +func ExampleValidator_Max() { + type BizReq struct { + Age1 int `v:"max:100"` + Age2 int `v:"max:100"` + Score1 float32 `v:"max:10.0"` + Score2 float32 `v:"max:10.0"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Age1: 99, + Age2: 101, + Score1: 9.9, + Score2: 10.1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Age2 value must be equal or lesser than 100; The Score2 value must be equal or lesser than 10 +} + +func ExampleValidator_Json() { + type BizReq struct { + Json1 string `v:"json"` + Json2 string `v:"json"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Json1: "{\"name\":\"goframe\",\"author\":\"郭强\"}", + Json2: "{\"name\":\"goframe\",\"author\":\"郭强\",\"test\"}", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Json2 value must be a valid JSON string +} + +func ExampleValidator_Integer() { + type BizReq struct { + Integer string `v:"integer"` + Float string `v:"integer"` + Str string `v:"integer"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Integer: "100", + Float: "10.0", + Str: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Float value must be an integer; The Str value must be an integer +} + +func ExampleValidator_Float() { + type BizReq struct { + Integer string `v:"float"` + Float string `v:"float"` + Str string `v:"float"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Integer: "100", + Float: "10.0", + Str: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Str value must be a float +} + +func ExampleValidator_Boolean() { + type BizReq struct { + Boolean bool `v:"boolean"` + Integer int `v:"boolean"` + Float float32 `v:"boolean"` + Str1 string `v:"boolean"` + Str2 string `v:"boolean"` + Str3 string `v:"boolean"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Boolean: true, + Integer: 1, + Float: 10.0, + Str1: "on", + Str2: "", + Str3: "goframe", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Print(err) + } + + // Output: + // The Float value field must be true or false; The Str3 value field must be true or false +} + +func ExampleValidator_Same() { + type BizReq struct { + Name string `v:"required"` + Password string `v:"required|same:Password2"` + Password2 string `v:"required"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "gf", + Password: "goframe.org", + Password2: "goframe.net", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Password value must be the same as field Password2 +} + +func ExampleValidator_Different() { + type BizReq struct { + Name string `v:"required"` + MailAddr string `v:"required"` + OtherMailAddr string `v:"required|different:MailAddr"` + } + var ( + ctx = context.Background() + req = BizReq{ + Name: "gf", + MailAddr: "gf@goframe.org", + OtherMailAddr: "gf@goframe.org", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The OtherMailAddr value must be different from field MailAddr +} + +func ExampleValidator_In() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + Gender: 3, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Gender value is not in acceptable range +} + +func ExampleValidator_NotIn() { + type BizReq struct { + Id uint `v:"required" dc:"Your Id"` + Name string `v:"required" dc:"Your name"` + InvalidIndex uint `v:"not-in:-1,0,1"` + } + var ( + ctx = context.Background() + req = BizReq{ + Id: 1, + Name: "test", + InvalidIndex: 1, + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The InvalidIndex value is not in acceptable range +} + +func ExampleValidator_Regex() { + type BizReq struct { + Regex1 string `v:"regex:[1-9][0-9]{4,14}"` + Regex2 string `v:"regex:[1-9][0-9]{4,14}"` + Regex3 string `v:"regex:[1-9][0-9]{4,14}"` + } + var ( + ctx = context.Background() + req = BizReq{ + Regex1: "1234", + Regex2: "01234", + Regex3: "10000", + } + ) + if err := g.Validator().CheckStruct(ctx, req); err != nil { + fmt.Println(err) + } + + // Output: + // The Regex1 value is invalid; The Regex2 value is invalid +} From 4e057956428d6e4f3ee9adcb5497f7c1a6db831a Mon Sep 17 00:00:00 2001 From: huangqian Date: Wed, 3 Nov 2021 22:38:31 +0800 Subject: [PATCH 10/17] Modify variable name --- util/gvalid/gvalid_z_example_test.go | 64 ++++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index 99d891ffe..f163b1b56 100644 --- a/util/gvalid/gvalid_z_example_test.go +++ b/util/gvalid/gvalid_z_example_test.go @@ -278,13 +278,13 @@ func ExampleValidator_CheckStruct() { func ExampleValidator_Required() { type BizReq struct { - Id uint `v:"required"` + ID uint `v:"required"` Name string `v:"required"` } var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, } ) if err := g.Validator().CheckStruct(ctx, req); err != nil { @@ -297,7 +297,7 @@ func ExampleValidator_Required() { func ExampleValidator_RequiredIf() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your ID"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` WifeName string `v:"required-if:gender,1"` @@ -306,7 +306,7 @@ func ExampleValidator_RequiredIf() { var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", Gender: 1, } @@ -321,7 +321,7 @@ func ExampleValidator_RequiredIf() { func ExampleValidator_RequiredUnless() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your ID"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` WifeName string `v:"required-unless:gender,0,gender,2"` @@ -330,7 +330,7 @@ func ExampleValidator_RequiredUnless() { var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", Gender: 1, } @@ -345,7 +345,7 @@ func ExampleValidator_RequiredUnless() { func ExampleValidator_RequiredWith() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your ID"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` WifeName string @@ -354,7 +354,7 @@ func ExampleValidator_RequiredWith() { var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", Gender: 1, WifeName: "Ann", @@ -370,7 +370,7 @@ func ExampleValidator_RequiredWith() { func ExampleValidator_RequiredWithAll() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your ID"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` WifeName string @@ -379,7 +379,7 @@ func ExampleValidator_RequiredWithAll() { var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", Gender: 1, WifeName: "Ann", @@ -395,7 +395,7 @@ func ExampleValidator_RequiredWithAll() { func ExampleValidator_RequiredWithout() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your ID"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` WifeName string @@ -404,7 +404,7 @@ func ExampleValidator_RequiredWithout() { var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", Gender: 1, } @@ -419,7 +419,7 @@ func ExampleValidator_RequiredWithout() { func ExampleValidator_RequiredWithoutAll() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your ID"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` WifeName string @@ -736,13 +736,13 @@ func ExampleValidator_Postcode() { func ExampleValidator_ResidentId() { type BizReq struct { - ResidentId1 string `v:"resident-id"` + ResidentID1 string `v:"resident-id"` } var ( ctx = context.Background() req = BizReq{ - ResidentId1: "320107199506285482", + ResidentID1: "320107199506285482", } ) if err := g.Validator().CheckStruct(ctx, req); err != nil { @@ -750,7 +750,7 @@ func ExampleValidator_ResidentId() { } // Output: - // The ResidentId1 value is not a valid resident id number + // The ResidentID1 value is not a valid resident id number } func ExampleValidator_BankCard() { @@ -885,17 +885,17 @@ func ExampleValidator_Mac() { func ExampleValidator_Url() { type BizReq struct { - Url1 string `v:"url"` - Url2 string `v:"url"` - Url3 string `v:"url"` + URL1 string `v:"url"` + URL2 string `v:"url"` + URL3 string `v:"url"` } var ( ctx = context.Background() req = BizReq{ - Url1: "http://goframe.org", - Url2: "ftp://goframe.org", - Url3: "ws://goframe.org", + URL1: "http://goframe.org", + URL2: "ftp://goframe.org", + URL3: "ws://goframe.org", } ) if err := g.Validator().CheckStruct(ctx, req); err != nil { @@ -903,7 +903,7 @@ func ExampleValidator_Url() { } // Output: - // The Url3 value must be a valid URL address + // The URL3 value must be a valid URL address } func ExampleValidator_Domain() { @@ -1092,15 +1092,15 @@ func ExampleValidator_Max() { func ExampleValidator_Json() { type BizReq struct { - Json1 string `v:"json"` - Json2 string `v:"json"` + JSON1 string `v:"json"` + JSON2 string `v:"json"` } var ( ctx = context.Background() req = BizReq{ - Json1: "{\"name\":\"goframe\",\"author\":\"郭强\"}", - Json2: "{\"name\":\"goframe\",\"author\":\"郭强\",\"test\"}", + JSON1: "{\"name\":\"goframe\",\"author\":\"郭强\"}", + JSON2: "{\"name\":\"goframe\",\"author\":\"郭强\",\"test\"}", } ) if err := g.Validator().CheckStruct(ctx, req); err != nil { @@ -1108,7 +1108,7 @@ func ExampleValidator_Json() { } // Output: - // The Json2 value must be a valid JSON string + // The JSON2 value must be a valid JSON string } func ExampleValidator_Integer() { @@ -1232,14 +1232,14 @@ func ExampleValidator_Different() { func ExampleValidator_In() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your Id"` Name string `v:"required" dc:"Your name"` Gender uint `v:"in:0,1,2" dc:"0:Secret;1:Male;2:Female"` } var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", Gender: 3, } @@ -1254,14 +1254,14 @@ func ExampleValidator_In() { func ExampleValidator_NotIn() { type BizReq struct { - Id uint `v:"required" dc:"Your Id"` + ID uint `v:"required" dc:"Your Id"` Name string `v:"required" dc:"Your name"` InvalidIndex uint `v:"not-in:-1,0,1"` } var ( ctx = context.Background() req = BizReq{ - Id: 1, + ID: 1, Name: "test", InvalidIndex: 1, } From f2bb9d65c3e3d248bf77aae83e8520a65b3d9692 Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Wed, 3 Nov 2021 22:49:30 +0800 Subject: [PATCH 11/17] edit review --- container/gset/gset_z_example_str_test.go | 213 +++++++++++++--------- 1 file changed, 127 insertions(+), 86 deletions(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index 671547499..1adb15f3b 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -11,11 +11,12 @@ import ( "fmt" "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/frame/g" + "time" ) -//NewStrSet create and returns a new set, which contains un-repeated items. -//The parameter is used to specify whether using set in concurrent-safety, -//which is false in default. +// NewStrSet create and returns a new set, which contains un-repeated items. +// The parameter `safe` is used to specify whether using set in concurrent-safety, +// which is false in default. func ExampleStrSet_NewStrSet() { strSet := gset.NewStrSet(true) strSet.Add([]string{"str1", "str2", "str3"}...) @@ -27,7 +28,7 @@ func ExampleStrSet_NewStrSet() { //Iterator str3 } -//NewStrSetFrom returns a new set from . +// NewStrSetFrom returns a new set from `items`. func ExampleStrSet_NewStrSetFrom() { strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) fmt.Println(strSet.Slice()) @@ -36,70 +37,81 @@ func ExampleStrSet_NewStrSetFrom() { // [str1 str2 str3] } -//Add adds one or multiple items to the set. +// Add adds one or multiple items to the set. func ExampleStrSet_Add() { - var strSet gset.StrSet - strSet.Add([]string{"str1", "str2", "str3"}...) - - // Mya Output: - //Iterator str1 - //Iterator str2 - //Iterator str3 -} - -//AddIfNotExist checks whether item exists in the set, -//it adds the item to set and returns true if it does not exists in the set, -//or else it does nothing and returns false. -func ExampleStrSet_AddIfNotExist() { - var strSet gset.StrSet + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + strSet.Add("str") + fmt.Println(strSet.Slice()) fmt.Println(strSet.AddIfNotExist("str")) - // Output: - // true + // Mya Output: + // [str str1 str2 str3] + // false } -//AddIfNotExistFunc checks whether item exists in the set, -//it adds the item to set and returns true if it does not exists in the set and function returns true, -//or else it does nothing and returns false. -//Note that, the function is executed without writing lock. +// AddIfNotExist checks whether item exists in the set, +// it adds the item to set and returns true if it does not exists in the set, +// or else it does nothing and returns false. +func ExampleStrSet_AddIfNotExist() { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + strSet.Add("str") + fmt.Println(strSet.Slice()) + fmt.Println(strSet.AddIfNotExist("str")) + + // Mya Output: + // [str str1 str2 str3] + // false +} + +// AddIfNotExistFunc checks whether item exists in the set, +// it adds the item to set and returns true if it does not exists in the set and function `f` returns true, +// or else it does nothing and returns false. +// Note that, the function `f` is executed without writing lock. func ExampleStrSet_AddIfNotExistFunc() { - var strSet gset.StrSet - fmt.Println(strSet.AddIfNotExistFunc("str", func() bool { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + strSet.Add("str") + fmt.Println(strSet.Slice()) + fmt.Println(strSet.AddIfNotExistFunc("str5", func() bool { return true })) - // Output: + // May Output: + // [str1 str2 str3 str] // true } -//AddIfNotExistFunc checks whether item exists in the set, -//it adds the item to set and returns true if it does not exists in the set and function returns true, -//or else it does nothing and returns false. -//Note that, the function is executed without writing lock. +// AddIfNotExistFunc checks whether item exists in the set, +// it adds the item to set and returns true if it does not exists in the set and function `f` returns true, +// or else it does nothing and returns false. +// Note that, the function `f` is executed without writing lock. func ExampleStrSet_AddIfNotExistFuncLock() { - var strSet gset.StrSet - fmt.Println(strSet.AddIfNotExistFuncLock("str", func() bool { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + strSet.Add("str") + fmt.Println(strSet.Slice()) + fmt.Println(strSet.AddIfNotExistFuncLock("str4", func() bool { return true })) - // Output: + // May Output: + // [str1 str2 str3 str] // true } -//Clear deletes all items of the set. +// Clear deletes all items of the set. func ExampleStrSet_Clear() { strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + fmt.Println(strSet.Size()) strSet.Clear() - fmt.Println(strSet.Size()) // Output: + // 3 // 0 } -//Complement returns a new set which is the complement from to . -//Which means, all the items in are in and not in . -//It returns the difference between and if the given set is not the full set of . +// Complement returns a new set which is the complement from `set` to `full`. +// Which means, all the items in `newSet` are in `full` and not in `set`. +// It returns the difference between `full` and `set` if the given set `full` is not the full set of `set`. func ExampleStrSet_Complement() { strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3", "str4", "str5"}, true) s := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) @@ -109,7 +121,7 @@ func ExampleStrSet_Complement() { // [str4 str5] } -//Contains checks whether the set contains . +// Contains checks whether the set contains `item`. func ExampleStrSet_Contains() { var set gset.StrSet set.Add("a") @@ -121,8 +133,8 @@ func ExampleStrSet_Contains() { // false } -//ContainsI checks whether a value exists in the set with case-insensitively. -//Note that it internally iterates the whole set to do the comparison with case-insensitively. +// ContainsI checks whether a value exists in the set with case-insensitively. +// Note that it internally iterates the whole set to do the comparison with case-insensitively. func ExampleStrSet_ContainsI() { var set gset.StrSet set.Add("a") @@ -134,45 +146,46 @@ func ExampleStrSet_ContainsI() { // true } -//Diff returns a new set which is the difference set from to . -//Which means, all the items in are in but not in . +// Diff returns a new set which is the difference set from `set` to `other`. +// Which means, all the items in `newSet` are in `set` but not in `other`. func ExampleStrSet_Diff() { s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true) s2 := gset.NewStrSetFrom([]string{"a", "b", "c", "d"}, true) - // 差集 fmt.Println(s2.Diff(s1).Slice()) // Output: // [d] } -//Equal checks whether the two sets equal. +// Equal checks whether the two sets equal. func ExampleStrSet_Equal() { - s1 := gset.NewStrSet(true) - s1.Add([]string{"a", "b", "c"}...) - var s2 gset.StrSet - s2.Add([]string{"a", "b", "c", "d"}...) + s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true) + s2 := gset.NewStrSetFrom([]string{"a", "b", "c", "d"}, true) fmt.Println(s2.Equal(s1)) + s3 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true) + s4 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true) + fmt.Println(s3.Equal(s4)) + // Output: // false + // true } -//Intersect returns a new set which is the intersection from to . -//Which means, all the items in are in and also in . +// Intersect returns a new set which is the intersection from `set` to `other`. +// Which means, all the items in `newSet` are in `set` and also in `other`. func ExampleStrSet_Intersect() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c"}...) var s2 gset.StrSet s2.Add([]string{"a", "b", "c", "d"}...) - // 交集 fmt.Println(s2.Intersect(s1).Slice()) // May Output: // [c a b] } -//IsSubsetOf checks whether the current set is a sub-set of . +// IsSubsetOf checks whether the current set is a sub-set of `other` func ExampleStrSet_IsSubsetOf() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -184,8 +197,8 @@ func ExampleStrSet_IsSubsetOf() { // true } -//Iterator iterates the set readonly with given callback function , -//if returns true then continue iterating; or false to stop. +// Iterator iterates the set readonly with given callback function `f`, +// if `f` returns true then continue iterating; or false to stop. func ExampleStrSet_Iterator() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -200,7 +213,7 @@ func ExampleStrSet_Iterator() { // Iterator d } -//Join joins items with a string . +// Join joins items with a string `glue`. func ExampleStrSet_Join() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -210,16 +223,38 @@ func ExampleStrSet_Join() { // b,c,d,a } -//LockFunc locks writing with callback function . +// LockFunc locks writing with callback function `f`. func ExampleStrSet_LockFunc() { - s := gset.NewStrSet(true) - s.Add([]string{"a", "b", "c", "d"}...) - s.LockFunc(func(m map[string]struct{}) { - m["a"] = struct{}{} - }) + s1 := gset.NewStrSet(true) + s1.Add([]string{"1", "2"}...) + go func() { + s1.LockFunc(func(m map[string]struct{}) { + m["3"] = struct{}{} + }) + fmt.Println("one:", s1.Slice()) + }() + time.Sleep(time.Duration(2) * time.Second) + go func() { + s1.LockFunc(func(m map[string]struct{}) { + m["4"] = struct{}{} + }) + fmt.Println("two:", s1.Slice()) + }() + time.Sleep(time.Duration(2) * time.Second) + go func() { + s1.LockFunc(func(m map[string]struct{}) { + m["5"] = struct{}{} + }) + fmt.Println("three:", s1.Slice()) + }() + time.Sleep(time.Duration(2) * time.Second) + // May Output + // [2 3 1] + // [1 2 3 4] + // [1 2 3 4 5] } -//MarshalJSON implements the interface MarshalJSON for json.Marshal. +// MarshalJSON implements the interface MarshalJSON for json.Marshal. func ExampleStrSet_MarshalJSON() { type Student struct { Id int @@ -238,7 +273,7 @@ func ExampleStrSet_MarshalJSON() { // {"Id":1,"Name":"john","Scores":["100","99","98"]} } -//Merge adds items from sets into . +// Merge adds items from `others` sets into `set`. func ExampleStrSet_Merge() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -250,7 +285,7 @@ func ExampleStrSet_Merge() { // [d a b c] } -//Pops randomly pops an item from set. +// Pops randomly pops an item from set. func ExampleStrSet_Pop() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -261,8 +296,8 @@ func ExampleStrSet_Pop() { // a } -//Pops randomly pops items from set. -//It returns all items if size == -1. +// Pops randomly pops `size` items from set. +// It returns all items if size == -1. func ExampleStrSet_Pops() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -275,7 +310,7 @@ func ExampleStrSet_Pops() { // b } -//RLockFunc locks reading with callback function . +// RLockFunc locks reading with callback function `f`. func ExampleStrSet_RLockFunc() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -287,7 +322,7 @@ func ExampleStrSet_RLockFunc() { // map[a:{} b:{} c:{} d:{}] } -//Remove deletes from set. +// Remove deletes `item` from set. func ExampleStrSet_Remove() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -298,7 +333,7 @@ func ExampleStrSet_Remove() { // [b c d] } -//Size returns the size of the set. +// Size returns the size of the set. func ExampleStrSet_Size() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -308,7 +343,7 @@ func ExampleStrSet_Size() { // 4 } -//Slice returns the a of items of the set as slice. +// Slice returns the a of items of the set as slice. func ExampleStrSet_Slice() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -318,7 +353,7 @@ func ExampleStrSet_Slice() { // [a,b,c,d] } -//String returns items as a string, which implements like json.Marshal does. +// String returns items as a string, which implements like json.Marshal does. func ExampleStrSet_String() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -328,8 +363,8 @@ func ExampleStrSet_String() { // "a","b","c","d" } -//Sum sums items. Note: The items should be converted to int type, -//or you'd get a result that you unexpected. +// Sum sums items. Note: The items should be converted to int type, +// or you'd get a result that you unexpected. func ExampleStrSet_Sum() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -339,8 +374,8 @@ func ExampleStrSet_Sum() { // 0 } -//Union returns a new set which is the union of and . -//Which means, all the items in are in or in . +// Union returns a new set which is the union of `set` and `other`. +// Which means, all the items in `newSet` are in `set` or in `other`. func ExampleStrSet_Union() { s1 := gset.NewStrSet(true) s1.Add([]string{"a", "b", "c", "d"}...) @@ -352,7 +387,7 @@ func ExampleStrSet_Union() { // [a b c d] } -//UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func ExampleStrSet_UnmarshalJSON() { b := []byte(`{"Id":1,"Name":"john","Scores":["100","99","98"]}`) type Student struct { @@ -368,17 +403,23 @@ func ExampleStrSet_UnmarshalJSON() { // {1 john "99","98","100"} } -//UnmarshalValue is an interface implement which sets any type of value for set. +// UnmarshalValue is an interface implement which sets any type of value for set. func ExampleStrSet_UnmarshalValue() { - s := gset.NewStrSetFrom([]string{"a"}, true) - s.UnmarshalValue([]string{"b", "c"}) - fmt.Println(s.Slice()) + b := []byte(`{"Id":1,"Name":"john","Scores":["100","99","98"]}`) + type Student struct { + Id int + Name string + Scores *gset.StrSet + } + s := Student{} + json.Unmarshal(b, &s) + fmt.Println(s) - // Output: - // [a b c] + // May Output: + // {1 john "99","98","100"} } -//Walk applies a user supplied function to every item of set. +// Walk applies a user supplied function `f` to every item of set. func ExampleStrSet_Walk() { var ( set gset.StrSet From c850c420fd2f579fb958d7f0314347703dd1c97c Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Wed, 3 Nov 2021 23:06:24 +0800 Subject: [PATCH 12/17] fixCi --- container/gset/gset_z_example_str_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index 1adb15f3b..5bc15b152 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -33,7 +33,7 @@ func ExampleStrSet_NewStrSetFrom() { strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) fmt.Println(strSet.Slice()) - // Output: + // May Output: // [str1 str2 str3] } From 9ea2db5c817bb3278aef7dea46a967d37d8e1cfc Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Wed, 3 Nov 2021 23:17:04 +0800 Subject: [PATCH 13/17] fix --- container/gset/gset_z_example_str_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index 5bc15b152..c81568f2a 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -359,7 +359,7 @@ func ExampleStrSet_String() { s1.Add([]string{"a", "b", "c", "d"}...) fmt.Println(s1.String()) - // Output: + // May Output: // "a","b","c","d" } From 430102c995bbbe4e164932b61a31244c581b04c1 Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Thu, 4 Nov 2021 22:11:09 +0800 Subject: [PATCH 14/17] update --- container/gset/gset_z_example_str_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index c81568f2a..e3cb6cf4c 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -23,9 +23,7 @@ func ExampleStrSet_NewStrSet() { fmt.Println(strSet.Slice()) // May Output: - //Iterator str1 - //Iterator str2 - //Iterator str3 + // [str3 str1 str2] } // NewStrSetFrom returns a new set from `items`. From 3091f61a2656cf1bec8ffb02b518f81f39dc62b1 Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Thu, 4 Nov 2021 22:26:17 +0800 Subject: [PATCH 15/17] update ExampleStrSet_Remove --- container/gset/gset_z_example_str_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index e3cb6cf4c..3a08aaf50 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -327,7 +327,7 @@ func ExampleStrSet_Remove() { s1.Remove("a") fmt.Println(s1.Slice()) - // Output: + // May Output: // [b c d] } From ef7f7e35f8ae2e14782e2d39ef00ac0a188a92dc Mon Sep 17 00:00:00 2001 From: "timmy.hu" Date: Fri, 5 Nov 2021 00:04:24 +0800 Subject: [PATCH 16/17] update review --- container/gset/gset_z_example_str_test.go | 39 +++++++---------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index 3a08aaf50..586e55615 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -11,13 +11,12 @@ import ( "fmt" "github.com/gogf/gf/v2/container/gset" "github.com/gogf/gf/v2/frame/g" - "time" ) // NewStrSet create and returns a new set, which contains un-repeated items. // The parameter `safe` is used to specify whether using set in concurrent-safety, // which is false in default. -func ExampleStrSet_NewStrSet() { +func ExampleNewStrSet() { strSet := gset.NewStrSet(true) strSet.Add([]string{"str1", "str2", "str3"}...) fmt.Println(strSet.Slice()) @@ -27,7 +26,7 @@ func ExampleStrSet_NewStrSet() { } // NewStrSetFrom returns a new set from `items`. -func ExampleStrSet_NewStrSetFrom() { +func ExampleNewStrSetFrom() { strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) fmt.Println(strSet.Slice()) @@ -204,6 +203,7 @@ func ExampleStrSet_Iterator() { fmt.Println("Iterator", v) return true }) + // May Output: // Iterator a // Iterator b @@ -225,31 +225,14 @@ func ExampleStrSet_Join() { func ExampleStrSet_LockFunc() { s1 := gset.NewStrSet(true) s1.Add([]string{"1", "2"}...) - go func() { - s1.LockFunc(func(m map[string]struct{}) { - m["3"] = struct{}{} - }) - fmt.Println("one:", s1.Slice()) - }() - time.Sleep(time.Duration(2) * time.Second) - go func() { - s1.LockFunc(func(m map[string]struct{}) { - m["4"] = struct{}{} - }) - fmt.Println("two:", s1.Slice()) - }() - time.Sleep(time.Duration(2) * time.Second) - go func() { - s1.LockFunc(func(m map[string]struct{}) { - m["5"] = struct{}{} - }) - fmt.Println("three:", s1.Slice()) - }() - time.Sleep(time.Duration(2) * time.Second) + s1.LockFunc(func(m map[string]struct{}) { + m["3"] = struct{}{} + }) + fmt.Println(s1.Slice()) + // May Output // [2 3 1] - // [1 2 3 4] - // [1 2 3 4 5] + } // MarshalJSON implements the interface MarshalJSON for json.Marshal. @@ -365,11 +348,11 @@ func ExampleStrSet_String() { // or you'd get a result that you unexpected. func ExampleStrSet_Sum() { s1 := gset.NewStrSet(true) - s1.Add([]string{"a", "b", "c", "d"}...) + s1.Add([]string{"1", "2", "3", "4"}...) fmt.Println(s1.Sum()) // Output: - // 0 + // 10 } // Union returns a new set which is the union of `set` and `other`. From 485706a676c8383a0911e1e9104e82ee0d1ed86f Mon Sep 17 00:00:00 2001 From: John Guo Date: Fri, 5 Nov 2021 01:07:06 +0800 Subject: [PATCH 17/17] improve ScanList feature for package gdb --- database/gdb/gdb_model_select.go | 35 +- database/gdb/gdb_type_result_scanlist.go | 191 +++++++---- .../gdb_z_mysql_association_scanlist_test.go | 309 +++++++++++++++++- util/gconv/gconv_struct.go | 2 +- 4 files changed, 442 insertions(+), 95 deletions(-) diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go index 6c1445794..70f449d44 100644 --- a/database/gdb/gdb_model_select.go +++ b/database/gdb/gdb_model_select.go @@ -319,32 +319,25 @@ func (m *Model) Scan(pointer interface{}, where ...interface{}) error { // ScanList converts `r` to struct slice which contains other complex struct attributes. // Note that the parameter `listPointer` should be type of *[]struct/*[]*struct. -// Usage example: // -// type Entity struct { -// User *EntityUser -// UserDetail *EntityUserDetail -// UserScores []*EntityUserScores -// } -// var users []*Entity -// or -// var users []Entity -// -// ScanList(&users, "User") -// ScanList(&users, "UserDetail", "User", "uid:Uid") -// ScanList(&users, "UserScores", "User", "uid:Uid") -// The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct -// that current result will be bound to. -// The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational -// struct attribute name. It automatically calculates the HasOne/HasMany relationship with given `relation` -// parameter. -// See the example or unit testing cases for clear understanding for this function. -func (m *Model) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) { +// See Result.ScanList. +func (m *Model) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) { result, err := m.All() if err != nil { return err } - return doScanList(m, result, listPointer, attributeName, relation...) + var ( + relationAttrName string + relationFields string + ) + switch len(relationAttrNameAndFields) { + case 2: + relationAttrName = relationAttrNameAndFields[0] + relationFields = relationAttrNameAndFields[1] + case 1: + relationFields = relationAttrNameAndFields[0] + } + return doScanList(m, result, structSlicePointer, bindToAttrName, relationAttrName, relationFields) } // Count does "SELECT COUNT(x) FROM ..." statement for the model. diff --git a/database/gdb/gdb_type_result_scanlist.go b/database/gdb/gdb_type_result_scanlist.go index 6fb16baae..0e76b6c61 100644 --- a/database/gdb/gdb_type_result_scanlist.go +++ b/database/gdb/gdb_type_result_scanlist.go @@ -10,6 +10,7 @@ import ( "database/sql" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gutil" @@ -17,21 +18,61 @@ import ( ) // ScanList converts `r` to struct slice which contains other complex struct attributes. -// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct. -// Usage example: +// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct. // +// Usage example 1: Normal attribute struct relation: +// type EntityUser struct { +// Uid int +// Name string +// } +// type EntityUserDetail struct { +// Uid int +// Address string +// } +// type EntityUserScores struct { +// Id int +// Uid int +// Score int +// Course string +// } // type Entity struct { -// User *EntityUser +// User *EntityUser // UserDetail *EntityUserDetail -// UserScores []*EntityUserScores +// UserScores []*EntityUserScores // } // var users []*Entity -// or -// var users []Entity -// // ScanList(&users, "User") +// ScanList(&users, "User", "uid") // ScanList(&users, "UserDetail", "User", "uid:Uid") // ScanList(&users, "UserScores", "User", "uid:Uid") +// ScanList(&users, "UserScores", "User", "uid") +// +// +// Usage example 2: Embedded attribute struct relation: +// type EntityUser struct { +// Uid int +// Name string +// } +// type EntityUserDetail struct { +// Uid int +// Address string +// } +// type EntityUserScores struct { +// Id int +// Uid int +// Score int +// } +// type Entity struct { +// EntityUser +// UserDetail EntityUserDetail +// UserScores []EntityUserScores +// } +// +// var users []*Entity +// ScanList(&users) +// ScanList(&users, "UserDetail", "uid") +// ScanList(&users, "UserScores", "uid") +// // // The parameters "User/UserDetail/UserScores" in the example codes specify the target attribute struct // that current result will be bound to. @@ -42,15 +83,26 @@ import ( // given `relation` parameter. // // See the example or unit testing cases for clear understanding for this function. -func (r Result) ScanList(listPointer interface{}, bindToAttrName string, relationKV ...string) (err error) { - return doScanList(nil, r, listPointer, bindToAttrName, relationKV...) +func (r Result) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) { + var ( + relationAttrName string + relationFields string + ) + switch len(relationAttrNameAndFields) { + case 2: + relationAttrName = relationAttrNameAndFields[0] + relationFields = relationAttrNameAndFields[1] + case 1: + relationFields = relationAttrNameAndFields[0] + } + return doScanList(nil, r, structSlicePointer, bindToAttrName, relationAttrName, relationFields) } // doScanList converts `result` to struct slice which contains other complex struct attributes recursively. -// The parameter `model` is used for recursively scanning purpose, which means, it can scans the attribute struct/structs recursively but -// it needs the Model for database accessing. -// Note that the parameter `listPointer` should be type of *[]struct/*[]*struct. -func doScanList(model *Model, result Result, listPointer interface{}, bindToAttrName string, relationKV ...string) (err error) { +// The parameter `model` is used for recursively scanning purpose, which means, it can scan the attribute struct/structs recursively, +// but it needs the Model for database accessing. +// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct. +func doScanList(model *Model, result Result, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string) (err error) { if result.IsEmpty() { return nil } @@ -59,8 +111,12 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr return gerror.NewCode(gcode.CodeInvalidParameter, `bindToAttrName should not be empty`) } + if relationAttrName == "." { + relationAttrName = "" + } + var ( - reflectValue = reflect.ValueOf(listPointer) + reflectValue = reflect.ValueOf(structSlicePointer) reflectKind = reflectValue.Kind() ) if reflectKind == reflect.Interface { @@ -70,7 +126,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr if reflectKind != reflect.Ptr { return gerror.NewCodef( gcode.CodeInvalidParameter, - "listPointer should be type of *[]struct/*[]*struct, but got: %v", + "structSlicePointer should be type of *[]struct/*[]*struct, but got: %v", reflectKind, ) } @@ -79,7 +135,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr if reflectKind != reflect.Slice && reflectKind != reflect.Array { return gerror.NewCodef( gcode.CodeInvalidParameter, - "listPointer should be type of *[]struct/*[]*struct, but got: %v", + "structSlicePointer should be type of *[]struct/*[]*struct, but got: %v", reflectKind, ) } @@ -99,7 +155,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr var ( arrayValue reflect.Value // Like: []*Entity arrayItemType reflect.Type // Like: *Entity - reflectType = reflect.TypeOf(listPointer) + reflectType = reflect.TypeOf(structSlicePointer) ) if reflectValue.Len() > 0 { arrayValue = reflectValue @@ -112,46 +168,38 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr // Relation variables. var ( - relationKVStr string - relationDataMap map[string]Value - relationFromAttrName string // Eg: relationKV: User, uid:Uid -> User - relationResultFieldName string // Eg: relationKV: uid:Uid -> uid - relationBindToSubAttrName string // Eg: relationKV: uid:Uid -> Uid + relationDataMap map[string]Value + relationFromFieldName string // Eg: relationKV: id:uid -> id + relationBindToFieldName string // Eg: relationKV: id:uid -> uid ) - if len(relationKV) > 0 { - if len(relationKV) == 1 { - relationKVStr = relationKV[0] - } else { - relationFromAttrName = relationKV[0] - relationKVStr = relationKV[1] - } + if len(relationFields) > 0 { // The relation key string of table filed name and attribute name // can be joined with char '=' or ':'. - array := gstr.SplitAndTrim(relationKVStr, "=") + array := gstr.SplitAndTrim(relationFields, "=") if len(array) == 1 { // Compatible with old splitting char ':'. - array = gstr.SplitAndTrim(relationKVStr, ":") + array = gstr.SplitAndTrim(relationFields, ":") } if len(array) == 1 { // The relation names are the same. - array = []string{relationKVStr, relationKVStr} + array = []string{relationFields, relationFields} } if len(array) == 2 { // Defined table field to relation attribute name. // Like: // uid:Uid // uid:UserId - relationResultFieldName = array[0] - relationBindToSubAttrName = array[1] - if key, _ := gutil.MapPossibleItemByKey(result[0].Map(), relationResultFieldName); key == "" { + relationFromFieldName = array[0] + relationBindToFieldName = array[1] + if key, _ := gutil.MapPossibleItemByKey(result[0].Map(), relationFromFieldName); key == "" { return gerror.NewCodef( gcode.CodeInvalidParameter, - `cannot find possible related table field name "%s" from given relation key "%s"`, - relationResultFieldName, - relationKVStr, + `cannot find possible related table field name "%s" from given relation fields "%s"`, + relationFromFieldName, + relationFields, ) } else { - relationResultFieldName = key + relationFromFieldName = key } } else { return gerror.NewCode( @@ -159,15 +207,15 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr `parameter relationKV should be format of "ResultFieldName:BindToAttrName"`, ) } - if relationResultFieldName != "" { + if relationFromFieldName != "" { // Note that the value might be type of slice. - relationDataMap = result.MapKeyValue(relationResultFieldName) + relationDataMap = result.MapKeyValue(relationFromFieldName) } if len(relationDataMap) == 0 { return gerror.NewCodef( gcode.CodeInvalidParameter, - `cannot find the relation data map, maybe invalid relation given "%v"`, - relationKV, + `cannot find the relation data map, maybe invalid relation fields given "%v"`, + relationFields, ) } } @@ -201,9 +249,9 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr // Bind to relation conditions. var ( - relationFromAttrValue reflect.Value - relationFromAttrField reflect.Value - relationBindToSubAttrNameChecked bool + relationFromAttrValue reflect.Value + relationFromAttrField reflect.Value + relationBindToFieldNameChecked bool ) for i := 0; i < arrayValue.Len(); i++ { arrayElemValue := arrayValue.Index(i) @@ -224,9 +272,9 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr // Like: []Entity } bindToAttrValue = arrayElemValue.FieldByName(bindToAttrName) - if relationFromAttrName != "" { + if relationAttrName != "" { // Attribute value of current slice element. - relationFromAttrValue = arrayElemValue.FieldByName(relationFromAttrName) + relationFromAttrValue = arrayElemValue.FieldByName(relationAttrName) if relationFromAttrValue.Kind() == reflect.Ptr { relationFromAttrValue = relationFromAttrValue.Elem() } @@ -235,36 +283,35 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr relationFromAttrValue = arrayElemValue } if len(relationDataMap) > 0 && !relationFromAttrValue.IsValid() { - return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV) + return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields) } // Check and find possible bind to attribute name. - if relationKVStr != "" && !relationBindToSubAttrNameChecked { - relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName) + if relationFields != "" && !relationBindToFieldNameChecked { + relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if !relationFromAttrField.IsValid() { var ( - relationFromAttrType = relationFromAttrValue.Type() - filedMap = make(map[string]interface{}) + filedMap, _ = structs.FieldMap(structs.FieldMapInput{ + Pointer: relationFromAttrValue, + RecursiveOption: structs.RecursiveOptionEmbeddedNoTag, + }) ) - for i := 0; i < relationFromAttrType.NumField(); i++ { - filedMap[relationFromAttrType.Field(i).Name] = struct{}{} - } - if key, _ := gutil.MapPossibleItemByKey(filedMap, relationBindToSubAttrName); key == "" { + if key, _ := gutil.MapPossibleItemByKey(gconv.Map(filedMap), relationBindToFieldName); key == "" { return gerror.NewCodef( gcode.CodeInvalidParameter, - `cannot find possible related attribute name "%s" from given relation key "%s"`, - relationBindToSubAttrName, - relationKVStr, + `cannot find possible related attribute name "%s" from given relation fields "%s"`, + relationBindToFieldName, + relationFields, ) } else { - relationBindToSubAttrName = key + relationBindToFieldName = key } } - relationBindToSubAttrNameChecked = true + relationBindToFieldNameChecked = true } switch bindToAttrKind { case reflect.Array, reflect.Slice: if len(relationDataMap) > 0 { - relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName) + relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if relationFromAttrField.IsValid() { results := make(Result, 0) for _, v := range relationDataMap[gconv.String(relationFromAttrField.Interface())].Slice() { @@ -280,8 +327,8 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr } } } else { - // May be the attribute does not exist yet. - return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV) + // Maybe the attribute does not exist yet. + return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields) } } else { return gerror.NewCodef( @@ -299,7 +346,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr element = bindToAttrValue.Elem() } if len(relationDataMap) > 0 { - relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName) + relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if relationFromAttrField.IsValid() { v := relationDataMap[gconv.String(relationFromAttrField.Interface())] if v == nil { @@ -316,8 +363,8 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr } } } else { - // May be the attribute does not exist yet. - return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV) + // Maybe the attribute does not exist yet. + return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields) } } else { if i >= len(result) { @@ -343,7 +390,7 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr case reflect.Struct: if len(relationDataMap) > 0 { - relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToSubAttrName) + relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName) if relationFromAttrField.IsValid() { relationDataItem := relationDataMap[gconv.String(relationFromAttrField.Interface())] if relationDataItem == nil { @@ -360,8 +407,8 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr } } } else { - // May be the attribute does not exist yet. - return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation specified: "%v"`, relationKV) + // Maybe the attribute does not exist yet. + return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid relation fields specified: "%v"`, relationFields) } } else { if i >= len(result) { @@ -388,6 +435,6 @@ func doScanList(model *Model, result Result, listPointer interface{}, bindToAttr return gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported attribute type: %s`, bindToAttrKind.String()) } } - reflect.ValueOf(listPointer).Elem().Set(arrayValue) + reflect.ValueOf(structSlicePointer).Elem().Set(arrayValue) return nil } diff --git a/database/gdb/gdb_z_mysql_association_scanlist_test.go b/database/gdb/gdb_z_mysql_association_scanlist_test.go index b5a908807..dee305cfc 100644 --- a/database/gdb/gdb_z_mysql_association_scanlist_test.go +++ b/database/gdb/gdb_z_mysql_association_scanlist_test.go @@ -1553,7 +1553,7 @@ CREATE TABLE %s ( }) } -func Test_Table_Relation_EmbeddedStruct(t *testing.T) { +func Test_Table_Relation_EmbeddedStruct1(t *testing.T) { var ( tableUser = "user_" + gtime.TimestampMicroStr() tableUserDetail = "user_detail_" + gtime.TimestampMicroStr() @@ -1670,3 +1670,310 @@ CREATE TABLE %s ( t.Assert(scores[24].Address, "address_5") }) } + +func Test_Table_Relation_EmbeddedStruct2(t *testing.T) { + var ( + tableUser = "user_" + gtime.TimestampMicroStr() + tableUserDetail = "user_detail_" + gtime.TimestampMicroStr() + tableUserScores = "user_scores_" + gtime.TimestampMicroStr() + ) + if _, err := db.Exec(ctx, fmt.Sprintf(` +CREATE TABLE %s ( + uid int(10) unsigned NOT NULL AUTO_INCREMENT, + name varchar(45) NOT NULL, + PRIMARY KEY (uid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + `, tableUser)); err != nil { + gtest.Error(err) + } + defer dropTable(tableUser) + + if _, err := db.Exec(ctx, fmt.Sprintf(` +CREATE TABLE %s ( + uid int(10) unsigned NOT NULL AUTO_INCREMENT, + address varchar(45) NOT NULL, + PRIMARY KEY (uid) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + `, tableUserDetail)); err != nil { + gtest.Error(err) + } + defer dropTable(tableUserDetail) + + if _, err := db.Exec(ctx, fmt.Sprintf(` +CREATE TABLE %s ( + id int(10) unsigned NOT NULL AUTO_INCREMENT, + uid int(10) unsigned NOT NULL, + score int(10) unsigned NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + `, tableUserScores)); err != nil { + gtest.Error(err) + } + defer dropTable(tableUserScores) + + type EntityUser struct { + Uid int `json:"uid"` + Name string `json:"name"` + } + type EntityUserDetail struct { + Uid int `json:"uid"` + Address string `json:"address"` + } + type EntityUserScores struct { + Id int `json:"id"` + Uid int `json:"uid"` + Score int `json:"score"` + } + type Entity struct { + *EntityUser + UserDetail *EntityUserDetail + UserScores []*EntityUserScores + } + + // Initialize the data. + gtest.C(t, func(t *gtest.T) { + var err error + for i := 1; i <= 5; i++ { + // User. + _, err = db.Insert(ctx, tableUser, g.Map{ + "uid": i, + "name": fmt.Sprintf(`name_%d`, i), + }) + t.AssertNil(err) + // Detail. + _, err = db.Insert(ctx, tableUserDetail, g.Map{ + "uid": i, + "address": fmt.Sprintf(`address_%d`, i), + }) + t.AssertNil(err) + // Scores. + for j := 1; j <= 5; j++ { + _, err = db.Insert(ctx, tableUserScores, g.Map{ + "uid": i, + "score": j, + }) + t.AssertNil(err) + } + } + }) + + // MapKeyValue. + gtest.C(t, func(t *gtest.T) { + all, err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").All() + t.AssertNil(err) + t.Assert(all.Len(), 2) + t.Assert(len(all.MapKeyValue("uid")), 2) + t.Assert(all.MapKeyValue("uid")["3"].Map()["uid"], 3) + t.Assert(all.MapKeyValue("uid")["4"].Map()["uid"], 4) + all, err = db.Model(tableUserScores).Where("uid", g.Slice{3, 4}).Order("id asc").All() + t.AssertNil(err) + t.Assert(all.Len(), 10) + t.Assert(len(all.MapKeyValue("uid")), 2) + t.Assert(len(all.MapKeyValue("uid")["3"].Slice()), 5) + t.Assert(len(all.MapKeyValue("uid")["4"].Slice()), 5) + t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[0])["uid"], 3) + t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[0])["score"], 1) + t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[4])["uid"], 3) + t.Assert(gconv.Map(all.MapKeyValue("uid")["3"].Slice()[4])["score"], 5) + }) + db.SetDebug(true) + // Result ScanList with struct elements and pointer attributes. + gtest.C(t, func(t *gtest.T) { + var users []Entity + // User + err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"}) + t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"}) + // Detail + all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserDetail", "uid") + t.AssertNil(err) + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + // Scores + all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserScores", "uid") + t.AssertNil(err) + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) + + // Result ScanList with pointer elements and pointer attributes. + gtest.C(t, func(t *gtest.T) { + var users []*Entity + // User + err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"}) + t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"}) + // Detail + all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserDetail", "uid") + t.AssertNil(err) + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + // Scores + all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserScores", "uid") + t.AssertNil(err) + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) + + // Result ScanList with struct elements and struct attributes. + gtest.C(t, func(t *gtest.T) { + type EntityUser struct { + Uid int `json:"uid"` + Name string `json:"name"` + } + type EntityUserDetail struct { + Uid int `json:"uid"` + Address string `json:"address"` + } + type EntityUserScores struct { + Id int `json:"id"` + Uid int `json:"uid"` + Score int `json:"score"` + } + type Entity struct { + EntityUser + UserDetail EntityUserDetail + UserScores []EntityUserScores + } + var users []Entity + // User + err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"}) + t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"}) + // Detail + all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserDetail", "uid") + t.AssertNil(err) + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + // Scores + all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserScores", "uid") + t.AssertNil(err) + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) + + // Result ScanList with pointer elements and struct attributes. + gtest.C(t, func(t *gtest.T) { + type EntityUser struct { + Uid int `json:"uid"` + Name string `json:"name"` + } + type EntityUserDetail struct { + Uid int `json:"uid"` + Address string `json:"address"` + } + type EntityUserScores struct { + Id int `json:"id"` + Uid int `json:"uid"` + Score int `json:"score"` + } + type Entity struct { + EntityUser + UserDetail EntityUserDetail + UserScores []EntityUserScores + } + var users []*Entity + + // User + err := db.Model(tableUser).Where("uid", g.Slice{3, 4}).Order("uid asc").Scan(&users) + t.AssertNil(err) + t.Assert(len(users), 2) + t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"}) + t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"}) + // Detail + all, err := db.Model(tableUserDetail).Where("uid", gdb.ListItemValues(users, "Uid")).Order("uid asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserDetail", "uid") + t.AssertNil(err) + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + // Scores + all, err = db.Model(tableUserScores).Where("uid", gdb.ListItemValues(users, "Uid")).Order("id asc").All() + t.AssertNil(err) + err = all.ScanList(&users, "UserScores", "uid") + t.AssertNil(err) + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) + + // Model ScanList with pointer elements and pointer attributes. + gtest.C(t, func(t *gtest.T) { + var users []*Entity + // User + err := db.Model(tableUser). + Where("uid", g.Slice{3, 4}). + Order("uid asc"). + Scan(&users) + t.AssertNil(err) + // Detail + err = db.Model(tableUserDetail). + Where("uid", gdb.ListItemValues(users, "Uid")). + Order("uid asc"). + ScanList(&users, "UserDetail", "uid:Uid") + t.AssertNil(err) + // Scores + err = db.Model(tableUserScores). + Where("uid", gdb.ListItemValues(users, "Uid")). + Order("id asc"). + ScanList(&users, "UserScores", "uid:Uid") + t.AssertNil(err) + + t.Assert(len(users), 2) + t.Assert(users[0].EntityUser, &EntityUser{3, "name_3"}) + t.Assert(users[1].EntityUser, &EntityUser{4, "name_4"}) + + t.Assert(users[0].UserDetail, &EntityUserDetail{3, "address_3"}) + t.Assert(users[1].UserDetail, &EntityUserDetail{4, "address_4"}) + + t.Assert(len(users[0].UserScores), 5) + t.Assert(len(users[1].UserScores), 5) + t.Assert(users[0].UserScores[0].Uid, 3) + t.Assert(users[0].UserScores[0].Score, 1) + t.Assert(users[0].UserScores[4].Score, 5) + t.Assert(users[1].UserScores[0].Uid, 4) + t.Assert(users[1].UserScores[0].Score, 1) + t.Assert(users[1].UserScores[4].Score, 5) + }) +} diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 1ef90525d..1546efae4 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -20,7 +20,7 @@ import ( // Struct maps the params key-value pairs to the corresponding struct object's attributes. // The third parameter `mapping` is unnecessary, indicating the mapping rules between the -// custom key name and the attribute name(case sensitive). +// custom key name and the attribute name(case-sensitive). // // Note: // 1. The `params` can be any type of map/struct, usually a map.