Merge pull request #10 from gogf/master

pr from master
This commit is contained in:
HaiLaz
2021-11-05 15:02:25 +08:00
committed by GitHub
18 changed files with 3174 additions and 269 deletions

View File

@ -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
}

View File

@ -416,7 +416,7 @@ func (l *List) RemoveAll() {
l.mu.Unlock()
}
// See RemoveAll().
// Clear is alias of RemoveAll.
func (l *List) Clear() {
l.RemoveAll()
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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 {

View File

@ -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])
)

View File

@ -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.

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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
}
}

View File

@ -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{})["呵呵"], "值")

View File

@ -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

View File

@ -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.

View File

@ -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(`<nil>`)
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,

View File

@ -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")})
})
}

View File

@ -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

File diff suppressed because it is too large Load Diff