diff --git a/container/garray/garray_z_example_str_test.go b/container/garray/garray_z_example_str_test.go index 8091e8955..f07bded82 100644 --- a/container/garray/garray_z_example_str_test.go +++ b/container/garray/garray_z_example_str_test.go @@ -10,6 +10,9 @@ import ( "fmt" "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/internal/json" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" ) func ExampleStrArray_Walk() { @@ -26,3 +29,621 @@ func ExampleStrArray_Walk() { // Output: // [gf_user gf_user_detail] } + +func ExampleStrArray_NewStrArray() { + s := garray.NewStrArray() + s.Append("We") + s.Append("are") + s.Append("GF") + s.Append("fans") + fmt.Println(s.Slice()) + + // Output: + // [We are GF fans] +} + +func ExampleStrArray_NewStrArraySize() { + s := garray.NewStrArraySize(3, 5) + s.Set(0, "We") + s.Set(1, "are") + s.Set(2, "GF") + s.Set(3, "fans") + fmt.Println(s.Slice(), s.Len(), cap(s.Slice())) + + // Output: + // [We are GF] 3 5 +} + +func ExampleStrArray_NewStrArrayFrom() { + s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"}) + fmt.Println(s.Slice(), s.Len(), cap(s.Slice())) + + // Output: + // [We are GF fans !] 5 5 +} + +func ExampleStrArray_NewStrArrayFromCopy() { + s := garray.NewStrArrayFromCopy(g.SliceStr{"We", "are", "GF", "fans", "!"}) + fmt.Println(s.Slice(), s.Len(), cap(s.Slice())) + + // Output: + // [We are GF fans !] 5 5 +} + +func ExampleStrArray_At() { + s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"}) + sAt := s.At(2) + fmt.Println(sAt) + + // Output: + // GF +} + +func ExampleStrArray_Get() { + s := garray.NewStrArrayFrom(g.SliceStr{"We", "are", "GF", "fans", "!"}) + sGet, sBool := s.Get(3) + fmt.Println(sGet, sBool) + + // Output: + // fans true +} + +func ExampleStrArray_Set() { + s := garray.NewStrArraySize(3, 5) + s.Set(0, "We") + s.Set(1, "are") + s.Set(2, "GF") + s.Set(3, "fans") + fmt.Println(s.Slice()) + + // Output: + // [We are GF] +} + +func ExampleStrArray_SetArray() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"We", "are", "GF", "fans", "!"}) + fmt.Println(s.Slice()) + + // Output: + // [We are GF fans !] +} + +func ExampleStrArray_Replace() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"We", "are", "GF", "fans", "!"}) + fmt.Println(s.Slice()) + s.Replace(g.SliceStr{"Happy", "coding"}) + fmt.Println(s.Slice()) + + // Output: + // [We are GF fans !] + // [Happy coding GF fans !] +} + +func ExampleStrArray_Sum() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"3", "5", "10"}) + a := s.Sum() + fmt.Println(a) + + // Output: + // 18 +} + +func ExampleStrArray_Sort() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"b", "d", "a", "c"}) + a := s.Sort() + fmt.Println(a) + + // Output: + // ["a","b","c","d"] +} + +func ExampleStrArray_SortFunc() { + s := garray.NewStrArrayFrom(g.SliceStr{"b", "c", "a"}) + fmt.Println(s) + s.SortFunc(func(v1, v2 string) bool { + return gstr.Compare(v1, v2) > 0 + }) + fmt.Println(s) + s.SortFunc(func(v1, v2 string) bool { + return gstr.Compare(v1, v2) < 0 + }) + fmt.Println(s) + + // Output: + // ["b","c","a"] + // ["c","b","a"] + // ["a","b","c"] +} + +func ExampleStrArray_InsertBefore() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.InsertBefore(1, "here") + fmt.Println(s.Slice()) + + // Output: + // [a here b c d] +} + +func ExampleStrArray_InsertAfter() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.InsertAfter(1, "here") + fmt.Println(s.Slice()) + + // Output: + // [a b here c d] +} + +func ExampleStrArray_Remove() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.Remove(1) + fmt.Println(s.Slice()) + + // Output: + // [a c d] +} + +func ExampleStrArray_RemoveValue() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.RemoveValue("b") + fmt.Println(s.Slice()) + + // Output: + // [a c d] +} + +func ExampleStrArray_PushLeft() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.PushLeft("We", "are", "GF", "fans") + fmt.Println(s.Slice()) + + // Output: + // [We are GF fans a b c d] +} + +func ExampleStrArray_PushRight() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.PushRight("We", "are", "GF", "fans") + fmt.Println(s.Slice()) + + // Output: + // [a b c d We are GF fans] +} + +func ExampleStrArray_PopLeft() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.PopLeft() + fmt.Println(s.Slice()) + + // Output: + // [b c d] +} + +func ExampleStrArray_PopRight() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d"}) + s.PopRight() + fmt.Println(s.Slice()) + + // Output: + // [a b c] +} + +func ExampleStrArray_PopRand() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r, _ := s.PopRand() + fmt.Println(r) + + // May Output: + // e +} + +func ExampleStrArray_PopRands() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.PopRands(2) + fmt.Println(r) + + // May Output: + // [e c] +} + +func ExampleStrArray_PopLefts() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.PopLefts(2) + fmt.Println(r) + fmt.Println(s) + + // Output: + // [a b] + // ["c","d","e","f","g","h"] +} + +func ExampleStrArray_PopRights() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.PopRights(2) + fmt.Println(r) + fmt.Println(s) + + // Output: + // [g h] + // ["a","b","c","d","e","f"] +} + +func ExampleStrArray_Range() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.Range(2, 5) + fmt.Println(r) + + // Output: + // [c d e] +} + +func ExampleStrArray_SubSlice() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.SubSlice(3, 4) + fmt.Println(r) + + // Output: + // [d e f g] +} + +func ExampleStrArray_Append() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"We", "are", "GF", "fans"}) + s.Append("a", "b", "c") + fmt.Println(s) + + // Output: + // ["We","are","GF","fans","a","b","c"] +} + +func ExampleStrArray_Len() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Len()) + + // Output: + // 8 +} + +func ExampleStrArray_Slice() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Slice()) + + // Output: + // [a b c d e f g h] +} + +func ExampleStrArray_Interfaces() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.Interfaces() + fmt.Println(r) + + // Output: + // [a b c d e f g h] +} + +func ExampleStrArray_Clone() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.Clone() + fmt.Println(r) + fmt.Println(s) + + // Output: + // ["a","b","c","d","e","f","g","h"] + // ["a","b","c","d","e","f","g","h"] +} + +func ExampleStrArray_Clear() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s) + fmt.Println(s.Clear()) + fmt.Println(s) + + // Output: + // ["a","b","c","d","e","f","g","h"] + // [] + // [] +} + +func ExampleStrArray_Contains() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Contains("e")) + fmt.Println(s.Contains("z")) + + // Output: + // true + // false +} + +func ExampleStrArray_ContainsI() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.ContainsI("E")) + fmt.Println(s.ContainsI("z")) + + // Output: + // true + // false +} + +func ExampleStrArray_Search() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Search("e")) + fmt.Println(s.Search("z")) + + // Output: + // 4 + // -1 +} + +func ExampleStrArray_Unique() { + s := garray.NewStrArray() + s.SetArray(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"}) + fmt.Println(s.Unique()) + + // Output: + // ["a","b","c","d"] +} + +func ExampleStrArray_LockFunc() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + s.LockFunc(func(array []string) { + array[len(array)-1] = "GF fans" + }) + fmt.Println(s) + + // Output: + // ["a","b","GF fans"] +} + +func ExampleStrArray_RLockFunc() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e"}) + s.RLockFunc(func(array []string) { + for i := 0; i < len(array); i++ { + fmt.Println(array[i]) + } + }) + + // Output: + // a + // b + // c + // d + // e +} + +func ExampleStrArray_Merge() { + s1 := garray.NewStrArray() + s2 := garray.NewStrArray() + s1.SetArray(g.SliceStr{"a", "b", "c"}) + s2.SetArray(g.SliceStr{"d", "e", "f"}) + s1.Merge(s2) + fmt.Println(s1) + + // Output: + // ["a","b","c","d","e","f"] +} + +func ExampleStrArray_Fill() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + s.Fill(2, 3, "here") + fmt.Println(s) + + // Output: + // ["a","b","here","here","here","f","g","h"] +} + +func ExampleStrArray_Chunk() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + r := s.Chunk(3) + fmt.Println(r) + + // Output: + // [[a b c] [d e f] [g h]] +} + +func ExampleStrArray_Pad() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + s.Pad(7, "here") + fmt.Println(s) + s.Pad(-10, "there") + fmt.Println(s) + + // Output: + // ["a","b","c","here","here","here","here"] + // ["there","there","there","a","b","c","here","here","here","here"] +} + +func ExampleStrArray_Rand() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Rand()) + + // May Output: + // c true +} + +func ExampleStrArray_Rands() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Rands(3)) + + // May Output: + // [e h e] +} + +func ExampleStrArray_Shuffle() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Shuffle()) + + // May Output: + // ["a","c","e","d","b","g","f","h"] +} + +func ExampleStrArray_Reverse() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "d", "e", "f", "g", "h"}) + fmt.Println(s.Reverse()) + + // Output: + // ["h","g","f","e","d","c","b","a"] +} + +func ExampleStrArray_Join() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + fmt.Println(s.Join(",")) + + // Output: + // a,b,c +} + +func ExampleStrArray_CountValues() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c", "c", "c", "d", "d"}) + fmt.Println(s.CountValues()) + + // Output: + // map[a:1 b:1 c:3 d:2] +} + +func ExampleStrArray_Iterator() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + s.Iterator(func(k int, v string) bool { + fmt.Println(k, v) + return true + }) + + // Output: + // 0 a + // 1 b + // 2 c +} + +func ExampleStrArray_IteratorAsc() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + s.IteratorAsc(func(k int, v string) bool { + fmt.Println(k, v) + return true + }) + + // Output: + // 0 a + // 1 b + // 2 c +} + +func ExampleStrArray_IteratorDesc() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + s.IteratorDesc(func(k int, v string) bool { + fmt.Println(k, v) + return true + }) + + // Output: + // 2 c + // 1 b + // 0 a +} + +func ExampleStrArray_String() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "c"}) + fmt.Println(s.String()) + + // Output: + // ["a","b","c"] +} + +func ExampleStrArray_MarshalJSON() { + type Student struct { + Id int + Name string + Lessons []string + } + s := Student{ + Id: 1, + Name: "john", + Lessons: []string{"Math", "English", "Music"}, + } + b, _ := json.Marshal(s) + fmt.Println(string(b)) + + // Output: + // {"Id":1,"Name":"john","Lessons":["Math","English","Music"]} +} + +func ExampleStrArray_UnmarshalJSON() { + b := []byte(`{"Id":1,"Name":"john","Lessons":["Math","English","Sport"]}`) + type Student struct { + Id int + Name string + Lessons *garray.StrArray + } + s := Student{} + json.Unmarshal(b, &s) + fmt.Println(s) + + // Output: + // {1 john ["Math","English","Sport"]} +} + +func ExampleStrArray_UnmarshalValue() { + type Student struct { + Name string + Lessons *garray.StrArray + } + var s *Student + gconv.Struct(g.Map{ + "name": "john", + "lessons": []byte(`["Math","English","Sport"]`), + }, &s) + fmt.Println(s) + + var s1 *Student + gconv.Struct(g.Map{ + "name": "john", + "lessons": g.SliceStr{"Math", "English", "Sport"}, + }, &s1) + fmt.Println(s1) + + // Output: + // &{john ["Math","English","Sport"]} + // &{john ["Math","English","Sport"]} +} + +func ExampleStrArray_FilterEmpty() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"}) + fmt.Println(s.FilterEmpty()) + + // Output: + // ["a","b","c","d"] +} + +func ExampleStrArray_IsEmpty() { + s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"}) + fmt.Println(s.IsEmpty()) + s1 := garray.NewStrArray() + fmt.Println(s1.IsEmpty()) + + // Output: + // false + // true +} diff --git a/container/glist/glist.go b/container/glist/glist.go index ee6baa3d7..03bfa261b 100644 --- a/container/glist/glist.go +++ b/container/glist/glist.go @@ -416,7 +416,7 @@ func (l *List) RemoveAll() { l.mu.Unlock() } -// See RemoveAll(). +// Clear is alias of RemoveAll. func (l *List) Clear() { l.RemoveAll() } diff --git a/container/glist/glist_example_test.go b/container/glist/glist_example_test.go deleted file mode 100644 index 3cd2880d3..000000000 --- a/container/glist/glist_example_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package glist_test - -import ( - "container/list" - "fmt" - "github.com/gogf/gf/v2/container/garray" - "github.com/gogf/gf/v2/frame/g" - - "github.com/gogf/gf/v2/container/glist" -) - -func ExampleNew() { - n := 10 - l := glist.New() - for i := 0; i < n; i++ { - l.PushBack(i) - } - fmt.Println(l.Len()) - fmt.Println(l.FrontAll()) - fmt.Println(l.BackAll()) - for i := 0; i < n; i++ { - fmt.Print(l.PopFront()) - } - l.Clear() - fmt.Println() - fmt.Println(l.Len()) - - // Output: - // 10 - // [0 1 2 3 4 5 6 7 8 9] - // [9 8 7 6 5 4 3 2 1 0] - // 0123456789 - // 0 -} - -func ExampleList_RLockFunc() { - // concurrent-safe list. - l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) - // iterate reading from head. - l.RLockFunc(func(list *list.List) { - length := list.Len() - if length > 0 { - for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() { - fmt.Print(e.Value) - } - } - }) - fmt.Println() - // iterate reading from tail. - l.RLockFunc(func(list *list.List) { - length := list.Len() - if length > 0 { - for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() { - fmt.Print(e.Value) - } - } - }) - - fmt.Println() - // Output: - // 12345678910 - // 10987654321 -} - -func ExampleList_IteratorAsc() { - // concurrent-safe list. - l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) - // iterate reading from head using IteratorAsc. - l.IteratorAsc(func(e *glist.Element) bool { - fmt.Print(e.Value) - return true - }) - - // Output: - // 12345678910 -} - -func ExampleList_IteratorDesc() { - // concurrent-safe list. - l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) - // iterate reading from tail using IteratorDesc. - l.IteratorDesc(func(e *glist.Element) bool { - fmt.Print(e.Value) - return true - }) - // Output: - // 10987654321 -} - -func ExampleList_LockFunc() { - // concurrent-safe list. - l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) - // iterate writing from head. - l.LockFunc(func(list *list.List) { - length := list.Len() - if length > 0 { - for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() { - if e.Value == 6 { - e.Value = "M" - break - } - } - } - }) - fmt.Println(l) - - // Output: - // [1,2,3,4,5,M,7,8,9,10] -} - -func ExampleList_PopBack() { - l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9}) - - fmt.Println(l.PopBack()) - - // Output: - // 9 -} -func ExampleList_PopBacks() { - l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9}) - - fmt.Println(l.PopBacks(2)) - - // Output: - // [9 8] -} - -func ExampleList_PopFront() { - l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9}) - - fmt.Println(l.PopFront()) - - // Output: - // 1 -} - -func ExampleList_PopFronts() { - l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7, 8, 9}) - - fmt.Println(l.PopFronts(2)) - - // Output: - // [1 2] -} - -func ExampleList_Join() { - var l glist.List - l.PushBacks(g.Slice{"a", "b", "c", "d"}) - - fmt.Println(l.Join(",")) - - // Output: - // a,b,c,d -} diff --git a/container/glist/glist_z_example_test.go b/container/glist/glist_z_example_test.go new file mode 100644 index 000000000..54126b760 --- /dev/null +++ b/container/glist/glist_z_example_test.go @@ -0,0 +1,689 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package glist_test + +import ( + "container/list" + "fmt" + "github.com/gogf/gf/v2/container/garray" + "github.com/gogf/gf/v2/frame/g" + + "github.com/gogf/gf/v2/container/glist" +) + +func ExampleNew() { + n := 10 + l := glist.New() + for i := 0; i < n; i++ { + l.PushBack(i) + } + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.FrontAll()) + fmt.Println(l.BackAll()) + + for i := 0; i < n; i++ { + fmt.Print(l.PopFront()) + } + + fmt.Println() + fmt.Println(l.Len()) + + // Output: + // 10 + // [0,1,2,3,4,5,6,7,8,9] + // [0 1 2 3 4 5 6 7 8 9] + // [9 8 7 6 5 4 3 2 1 0] + // 0123456789 + // 0 +} + +func ExampleNewFrom() { + n := 10 + l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.FrontAll()) + fmt.Println(l.BackAll()) + + for i := 0; i < n; i++ { + fmt.Print(l.PopFront()) + } + + fmt.Println() + fmt.Println(l.Len()) + + // Output: + // 10 + // [1,2,3,4,5,6,7,8,9,10] + // [1 2 3 4 5 6 7 8 9 10] + // [10 9 8 7 6 5 4 3 2 1] + // 12345678910 + // 0 +} + +func ExampleList_PushFront() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.PushFront(0) + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 6 + // [0,1,2,3,4,5] +} + +func ExampleList_PushBack() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.PushBack(6) + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 6 + // [1,2,3,4,5,6] +} + +func ExampleList_PushFronts() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.PushFronts(g.Slice{0, -1, -2, -3, -4}) + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 10 + // [-4,-3,-2,-1,0,1,2,3,4,5] +} + +func ExampleList_PushBacks() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.PushBacks(g.Slice{6, 7, 8, 9, 10}) + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 10 + // [1,2,3,4,5,6,7,8,9,10] +} + +func ExampleList_PopBack() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.PopBack()) + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 5 + // 4 + // [1,2,3,4] +} + +func ExampleList_PopFront() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.PopFront()) + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 1 + // 4 + // [2,3,4,5] +} + +func ExampleList_PopBacks() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.PopBacks(2)) + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // [5 4] + // 3 + // [1,2,3] +} + +func ExampleList_PopFronts() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.PopFronts(2)) + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // [1 2] + // 3 + // [3,4,5] +} + +func ExampleList_PopBackAll() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.PopBackAll()) + fmt.Println(l.Len()) + + // Output: + // 5 + // [1,2,3,4,5] + // [5 4 3 2 1] + // 0 +} + +func ExampleList_PopFrontAll() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + fmt.Println(l.PopFrontAll()) + fmt.Println(l.Len()) + + // Output: + // 5 + // [1,2,3,4,5] + // [1 2 3 4 5] + // 0 +} + +func ExampleList_FrontAll() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l) + fmt.Println(l.FrontAll()) + + // Output: + // [1,2,3,4,5] + // [1 2 3 4 5] +} + +func ExampleList_BackAll() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l) + fmt.Println(l.BackAll()) + + // Output: + // [1,2,3,4,5] + // [5 4 3 2 1] +} + +func ExampleList_FrontValue() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l) + fmt.Println(l.FrontValue()) + + // Output: + // [1,2,3,4,5] + // 1 +} + +func ExampleList_BackValue() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l) + fmt.Println(l.BackValue()) + + // Output: + // [1,2,3,4,5] + // 5 +} + +func ExampleList_Front() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Front().Value) + fmt.Println(l) + + e := l.Front() + l.InsertBefore(e, 0) + l.InsertAfter(e, "a") + + fmt.Println(l) + + // Output: + // 1 + // [1,2,3,4,5] + // [0,1,a,2,3,4,5] +} + +func ExampleList_Back() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Back().Value) + fmt.Println(l) + + e := l.Back() + l.InsertBefore(e, "a") + l.InsertAfter(e, 6) + + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // [1,2,3,4,a,5,6] +} + +func ExampleList_Len() { + l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5}) + + fmt.Println(l.Len()) + + // Output: + // 5 +} + +func ExampleList_Size() { + l := glist.NewFrom(g.Slice{1, 2, 3, 4, 5}) + + fmt.Println(l.Size()) + + // Output: + // 5 +} + +func ExampleList_MoveBefore() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // element of `l` + e := l.PushBack(6) + fmt.Println(l.Size()) + fmt.Println(l) + + l.MoveBefore(e, l.Front()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // not element of `l` + e = &glist.Element{Value: 7} + l.MoveBefore(e, l.Front()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 6 + // [1,2,3,4,5,6] + // 6 + // [6,1,2,3,4,5] + // 6 + // [6,1,2,3,4,5] +} + +func ExampleList_MoveAfter() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // element of `l` + e := l.PushFront(0) + fmt.Println(l.Size()) + fmt.Println(l) + + l.MoveAfter(e, l.Back()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // not element of `l` + e = &glist.Element{Value: -1} + l.MoveAfter(e, l.Back()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 6 + // [0,1,2,3,4,5] + // 6 + // [1,2,3,4,5,0] + // 6 + // [1,2,3,4,5,0] +} + +func ExampleList_MoveToFront() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // element of `l` + l.MoveToFront(l.Back()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // not element of `l` + e := &glist.Element{Value: 6} + l.MoveToFront(e) + + fmt.Println(l.Size()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 5 + // [5,1,2,3,4] + // 5 + // [5,1,2,3,4] +} + +func ExampleList_MoveToBack() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // element of `l` + l.MoveToBack(l.Front()) + + fmt.Println(l.Size()) + fmt.Println(l) + + // not element of `l` + e := &glist.Element{Value: 0} + l.MoveToBack(e) + + fmt.Println(l.Size()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 5 + // [2,3,4,5,1] + // 5 + // [2,3,4,5,1] +} + +func ExampleList_PushBackList() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Size()) + fmt.Println(l) + + other := glist.NewFrom(g.Slice{6, 7, 8, 9, 10}) + + fmt.Println(other.Size()) + fmt.Println(other) + + l.PushBackList(other) + + fmt.Println(l.Size()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 5 + // [6,7,8,9,10] + // 10 + // [1,2,3,4,5,6,7,8,9,10] +} + +func ExampleList_PushFrontList() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Size()) + fmt.Println(l) + + other := glist.NewFrom(g.Slice{-4, -3, -2, -1, 0}) + + fmt.Println(other.Size()) + fmt.Println(other) + + l.PushFrontList(other) + + fmt.Println(l.Size()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 5 + // [-4,-3,-2,-1,0] + // 10 + // [-4,-3,-2,-1,0,1,2,3,4,5] +} + +func ExampleList_InsertAfter() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.InsertAfter(l.Front(), "a") + l.InsertAfter(l.Back(), "b") + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 7 + // [1,a,2,3,4,5,b] +} + +func ExampleList_InsertBefore() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.InsertBefore(l.Front(), "a") + l.InsertBefore(l.Back(), "b") + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 7 + // [a,1,2,3,4,b,5] +} + +func ExampleList_Remove() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + fmt.Println(l.Remove(l.Front())) + fmt.Println(l.Remove(l.Back())) + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 1 + // 5 + // 3 + // [2,3,4] +} + +func ExampleList_Removes() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.Removes([]*glist.Element{l.Front(), l.Back()}) + + fmt.Println(l.Len()) + fmt.Println(l) + + // Output: + // 5 + // [1,2,3,4,5] + // 3 + // [2,3,4] +} + +func ExampleList_RemoveAll() { + l := glist.NewFrom(garray.NewArrayRange(1, 5, 1).Slice()) + + fmt.Println(l.Len()) + fmt.Println(l) + + l.RemoveAll() + + fmt.Println(l.Len()) + + // Output: + // 5 + // [1,2,3,4,5] + // 0 +} + +func ExampleList_RLockFunc() { + // concurrent-safe list. + l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) + // iterate reading from head. + l.RLockFunc(func(list *list.List) { + length := list.Len() + if length > 0 { + for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() { + fmt.Print(e.Value) + } + } + }) + fmt.Println() + // iterate reading from tail. + l.RLockFunc(func(list *list.List) { + length := list.Len() + if length > 0 { + for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() { + fmt.Print(e.Value) + } + } + }) + + fmt.Println() + // Output: + // 12345678910 + // 10987654321 +} + +func ExampleList_IteratorAsc() { + // concurrent-safe list. + l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) + // iterate reading from head using IteratorAsc. + l.IteratorAsc(func(e *glist.Element) bool { + fmt.Print(e.Value) + return true + }) + + // Output: + // 12345678910 +} + +func ExampleList_IteratorDesc() { + // concurrent-safe list. + l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) + // iterate reading from tail using IteratorDesc. + l.IteratorDesc(func(e *glist.Element) bool { + fmt.Print(e.Value) + return true + }) + // Output: + // 10987654321 +} + +func ExampleList_LockFunc() { + // concurrent-safe list. + l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true) + // iterate writing from head. + l.LockFunc(func(list *list.List) { + length := list.Len() + if length > 0 { + for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() { + if e.Value == 6 { + e.Value = "M" + break + } + } + } + }) + fmt.Println(l) + + // Output: + // [1,2,3,4,5,M,7,8,9,10] +} + +func ExampleList_Join() { + var l glist.List + l.PushBacks(g.Slice{"a", "b", "c", "d"}) + + fmt.Println(l.Join(",")) + + // Output: + // a,b,c,d +} diff --git a/container/gset/gset_z_example_str_test.go b/container/gset/gset_z_example_str_test.go index cfa0d22e1..586e55615 100644 --- a/container/gset/gset_z_example_str_test.go +++ b/container/gset/gset_z_example_str_test.go @@ -7,24 +7,400 @@ 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 `safe` is used to specify whether using set in concurrent-safety, +// which is false in default. +func ExampleNewStrSet() { + strSet := gset.NewStrSet(true) + strSet.Add([]string{"str1", "str2", "str3"}...) + fmt.Println(strSet.Slice()) + + // May Output: + // [str3 str1 str2] +} + +// NewStrSetFrom returns a new set from `items`. +func ExampleNewStrSetFrom() { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + fmt.Println(strSet.Slice()) + + // May Output: + // [str1 str2 str3] +} + +// Add adds one or multiple items to the set. +func ExampleStrSet_Add() { + 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 +} + +// 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() { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + strSet.Add("str") + fmt.Println(strSet.Slice()) + fmt.Println(strSet.AddIfNotExistFunc("str5", func() bool { + return true + })) + + // 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 `f` returns true, +// or else it does nothing and returns false. +// Note that, the function `f` is executed without writing lock. +func ExampleStrSet_AddIfNotExistFuncLock() { + strSet := gset.NewStrSetFrom([]string{"str1", "str2", "str3"}, true) + strSet.Add("str") + fmt.Println(strSet.Slice()) + fmt.Println(strSet.AddIfNotExistFuncLock("str4", func() bool { + return true + })) + + // May Output: + // [str1 str2 str3 str] + // true +} + +// 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 `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) + fmt.Println(s.Complement(strSet).Slice()) + + // May Output: + // [str4 str5] +} + +// Contains checks whether the set contains `item`. 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 +} + +// 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") + fmt.Println(set.ContainsI("a")) + fmt.Println(set.ContainsI("A")) + + // Output: + // true // true } +// 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. +func ExampleStrSet_Equal() { + 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 `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 `other` +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 +} + +// 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"}...) + s1.Iterator(func(v string) bool { + fmt.Println("Iterator", v) + return true + }) + + // May Output: + // Iterator a + // Iterator b + // Iterator c + // Iterator d +} + +// Join joins items with a string `glue`. +func ExampleStrSet_Join() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + fmt.Println(s1.Join(",")) + + // May Output: + // b,c,d,a +} + +// LockFunc locks writing with callback function `f`. +func ExampleStrSet_LockFunc() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"1", "2"}...) + s1.LockFunc(func(m map[string]struct{}) { + m["3"] = struct{}{} + }) + fmt.Println(s1.Slice()) + + // May Output + // [2 3 1] + +} + +// 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 `others` sets into `set`. +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 `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"}...) + for _, v := range s1.Pops(2) { + fmt.Println(v) + } + + // May Output: + // a + // b +} + +// RLockFunc locks reading with callback function `f`. +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 `item` from set. +func ExampleStrSet_Remove() { + s1 := gset.NewStrSet(true) + s1.Add([]string{"a", "b", "c", "d"}...) + s1.Remove("a") + fmt.Println(s1.Slice()) + + // May 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()) + + // May 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{"1", "2", "3", "4"}...) + fmt.Println(s1.Sum()) + + // Output: + // 10 +} + +// 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"}...) + 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() { + 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"} +} + +// Walk applies a user supplied function `f` to every item of set. func ExampleStrSet_Walk() { var ( set gset.StrSet diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 9c5a487e4..88b8d55a1 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -642,7 +642,7 @@ func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) { } } s := fmt.Sprintf( - "[%3d ms] [%s] [%s:%d] %s%s", + "[%3d ms] [%s] [%s:%-3d] %s%s", sql.End-sql.Start, sql.Group, sqlTypeKey, sql.RowsAffected, transactionIdStr, sql.Format, ) if sql.Error != nil { diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index 4c98ff773..d2360309b 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -829,6 +829,10 @@ func FormatSqlWithArgs(sql string, args []interface{}) string { if args[index] == nil { return "null" } + // Parameters of type Raw do not require special treatment + if v, ok := args[index].(Raw); ok { + return gconv.String(v) + } var ( reflectInfo = utils.OriginValueAndKind(args[index]) ) 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/encoding/gini/gini.go b/encoding/gini/gini.go index 878b6216b..55b5325cf 100644 --- a/encoding/gini/gini.go +++ b/encoding/gini/gini.go @@ -65,7 +65,7 @@ func Decode(data []byte) (res map[string]interface{}, err error) { if strings.Contains(lineStr, "=") && haveSection { values := strings.Split(lineStr, "=") - fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], "")) + fieldMap[strings.TrimSpace(values[0])] = strings.TrimSpace(strings.Join(values[1:], "=")) res[section] = fieldMap } } diff --git a/encoding/gini/gini_test.go b/encoding/gini/gini_test.go index 1295a0d8a..e080d8900 100644 --- a/encoding/gini/gini_test.go +++ b/encoding/gini/gini_test.go @@ -22,6 +22,7 @@ aa=bb ip = 127.0.0.1 port=9001 enable=true +command=/bin/echo "gf=GoFrame" [DBINFO] type=mysql @@ -40,6 +41,7 @@ func TestDecode(t *testing.T) { } t.Assert(res["addr"].(map[string]interface{})["ip"], "127.0.0.1") t.Assert(res["addr"].(map[string]interface{})["port"], "9001") + t.Assert(res["addr"].(map[string]interface{})["command"], `/bin/echo "gf=GoFrame"`) t.Assert(res["DBINFO"].(map[string]interface{})["user"], "root") t.Assert(res["DBINFO"].(map[string]interface{})["type"], "mysql") t.Assert(res["键"].(map[string]interface{})["呵呵"], "值") diff --git a/os/glog/glog_logger.go b/os/glog/glog_logger.go index 79be582b7..bdd873976 100644 --- a/os/glog/glog_logger.go +++ b/os/glog/glog_logger.go @@ -202,7 +202,7 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { if len(input.Content) > 0 { if input.Content[len(input.Content)-1] == '\n' { // Remove one blank line(\n\n). - if tempStr[0] == '\n' { + if len(tempStr) > 0 && tempStr[0] == '\n' { input.Content += tempStr[1:] } else { input.Content += tempStr 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. diff --git a/util/gutil/gutil_dump.go b/util/gutil/gutil_dump.go index 140209236..06ed56fd5 100644 --- a/util/gutil/gutil_dump.go +++ b/util/gutil/gutil_dump.go @@ -12,6 +12,7 @@ import ( "github.com/gogf/gf/v2/internal/structs" "github.com/gogf/gf/v2/text/gstr" "reflect" + "strings" ) // ExportOption specifies the behavior of function Export. @@ -56,12 +57,17 @@ type doExportOption struct { } func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doExportOption) { + if value == nil { + buffer.WriteString(``) + return + } var ( reflectValue = reflect.ValueOf(value) reflectKind = reflectValue.Kind() - reflectTypeName = reflectValue.Type().String() + reflectTypeName = reflect.TypeOf(value).String() newIndent = indent + dumpIndent ) + reflectTypeName = strings.ReplaceAll(reflectTypeName, `[]uint8`, `[]byte`) if option.WithoutType { reflectTypeName = "" } @@ -73,10 +79,10 @@ func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doE case reflect.Slice, reflect.Array: if _, ok := value.([]byte); ok { if option.WithoutType { - buffer.WriteString(fmt.Sprintf("\"%v\"\n", value)) + buffer.WriteString(fmt.Sprintf(`"%s"`, value)) } else { buffer.WriteString(fmt.Sprintf( - "%s(%d) \"%v\"\n", + `%s(%d) "%s"`, reflectTypeName, len(reflectValue.String()), value, diff --git a/util/gutil/gutil_z_unit_test.go b/util/gutil/gutil_z_unit_test.go index 962f85f91..253b89373 100755 --- a/util/gutil/gutil_z_unit_test.go +++ b/util/gutil/gutil_z_unit_test.go @@ -73,7 +73,7 @@ func Test_Dump(t *testing.T) { }) } -func Test_DumpBrief(t *testing.T) { +func TestDumpWithType(t *testing.T) { type CommonReq struct { AppId int64 `json:"appId" v:"required" in:"path" des:"应用Id" sum:"应用Id Summary"` ResourceId string `json:"resourceId" in:"query" des:"资源Id" sum:"资源Id Summary"` @@ -127,6 +127,7 @@ func Test_DumpBrief(t *testing.T) { 100: 100, }) gutil.DumpWithType(req) + gutil.DumpWithType([][]byte{[]byte("hello")}) }) } diff --git a/util/gvalid/gvalid_validator_check_struct.go b/util/gvalid/gvalid_validator_check_struct.go index 15bddf090..878e8a728 100644 --- a/util/gvalid/gvalid_validator_check_struct.go +++ b/util/gvalid/gvalid_validator_check_struct.go @@ -44,7 +44,7 @@ func (v *Validator) doCheckStruct(ctx context.Context, object interface{}) Error if _, ok := field.TagLookup(noValidationTagName); ok { continue } - if err := v.doCheckStruct(ctx, field.Value); err != nil { + if err = v.doCheckStruct(ctx, field.Value); err != nil { // It merges the errors into single error map. for k, m := range err.(*validationError).errors { errorMaps[k] = m diff --git a/util/gvalid/gvalid_z_example_test.go b/util/gvalid/gvalid_z_example_test.go index bc0c4f0dc..f163b1b56 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,1023 @@ 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_Date() { + type BizReq struct { + Date1 string `v:"date"` + Date2 string `v:"date"` + Date3 string `v:"date"` + Date4 string `v:"date"` + Date5 string `v:"date"` + } + + var ( + ctx = context.Background() + req = BizReq{ + Date1: "2021-10-31", + 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 { + fmt.Print(err) + } + + // Output: + // 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() { + 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 +} + +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 +} + +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 +}