From dc80b557e3db6aafd44a697535d9f10c71a50961 Mon Sep 17 00:00:00 2001 From: Huangzj Date: Wed, 16 Dec 2020 14:23:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(Go-Tool)=EF=BC=9A=20=20=20=202020/12/16:?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0YAML=E5=92=8C=E7=BB=93=E6=9E=84=E4=BD=93?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 14 +- go.sum | 48 +-- readme.md | 2 + util/yaml/YamlTool.go | 57 +++ util/yaml/YamlTool_test.go | 79 ++++ util/yaml/config.yaml | 17 + util/yaml/readme.md | 5 + vendor/github.com/ahmetb/go-linq/.travis.yml | 3 +- vendor/github.com/ahmetb/go-linq/LICENSE | 207 ++++++++++- vendor/github.com/ahmetb/go-linq/README.md | 101 +++++- vendor/github.com/ahmetb/go-linq/aggregate.go | 143 +++++++- vendor/github.com/ahmetb/go-linq/compare.go | 22 +- vendor/github.com/ahmetb/go-linq/concat.go | 12 +- vendor/github.com/ahmetb/go-linq/distinct.go | 33 +- vendor/github.com/ahmetb/go-linq/doc.go | 7 +- vendor/github.com/ahmetb/go-linq/except.go | 38 +- vendor/github.com/ahmetb/go-linq/from.go | 34 +- vendor/github.com/ahmetb/go-linq/groupby.go | 49 ++- vendor/github.com/ahmetb/go-linq/groupjoin.go | 81 ++++- vendor/github.com/ahmetb/go-linq/intersect.go | 36 +- vendor/github.com/ahmetb/go-linq/join.go | 69 +++- vendor/github.com/ahmetb/go-linq/orderby.go | 141 ++++++-- vendor/github.com/ahmetb/go-linq/result.go | 336 ++++++++++++++++-- vendor/github.com/ahmetb/go-linq/reverse.go | 6 +- vendor/github.com/ahmetb/go-linq/select.go | 92 +++-- .../github.com/ahmetb/go-linq/selectmany.go | 154 ++++++-- vendor/github.com/ahmetb/go-linq/skip.go | 73 +++- vendor/github.com/ahmetb/go-linq/take.go | 59 ++- vendor/github.com/ahmetb/go-linq/union.go | 7 +- vendor/github.com/ahmetb/go-linq/where.go | 51 ++- vendor/github.com/ahmetb/go-linq/zip.go | 44 ++- vendor/modules.txt | 4 +- 32 files changed, 1700 insertions(+), 324 deletions(-) create mode 100644 util/yaml/YamlTool.go create mode 100644 util/yaml/YamlTool_test.go create mode 100644 util/yaml/config.yaml create mode 100644 util/yaml/readme.md diff --git a/go.mod b/go.mod index eed629d..a9a2347 100644 --- a/go.mod +++ b/go.mod @@ -3,19 +3,11 @@ module Go-Tool go 1.13 require ( - github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75 // indirect - github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible // indirect - github.com/ahmetb/go-linq v2.0.0-rc0+incompatible - github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 // indirect + github.com/ahmetb/go-linq v3.0.0+incompatible github.com/go-ini/ini v1.57.0 - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/json-iterator/go v1.1.10 - github.com/kardianos/govendor v1.0.9 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/smartystreets/goconvey v1.6.4 // indirect github.com/stretchr/testify v1.5.1 // indirect - golang.org/x/sys v0.0.0-20200428200454-593003d681fa // indirect - golang.org/x/tools v0.0.0-20200429213335-127c98bd7927 // indirect - gopkg.in/go-playground/validator.v8 v8.18.2 // indirect gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect + gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 1beaffa..ac95bd2 100644 --- a/go.sum +++ b/go.sum @@ -1,65 +1,45 @@ -github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75 h1:xGHheKK44eC6K0u5X+DZW/fRaR1LnDdqPHMZMWx5fv8= -github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75/go.mod h1:4/6eNcqZ09BZ9wLK3tZOjBA1nDj+B0728nlX5YRlSmQ= -github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible h1:8q+6K5jJ2RCTD7v7VxMfuUdHyU22GZi+qMY0hpLTnVc= -github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible/go.mod h1:IBvGwXyZVvXuN8KIbGCK53k+fzCKOmAdYhobMdJXOck= -github.com/ahmetb/go-linq v2.0.0-rc0+incompatible h1:H8yA1M8T+1/pyPRUwSOyc30MFrtiP9vgJ2s+lgdaQlM= -github.com/ahmetb/go-linq v2.0.0-rc0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY= +github.com/ahmetb/go-linq v3.0.0+incompatible h1:qQkjjOXKrKOTy83X8OpRmnKflXKQIL/mC/gMVVDMhOA= +github.com/ahmetb/go-linq v3.0.0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 h1:3T8ZyTDp5QxTx3NU48JVb2u+75xc040fofcBaN+6jPA= -github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185/go.mod h1:cFRxtTwTOJkz2x3rQUNCYKWC93yP1VKjR8NUhqFxZNU= github.com/go-ini/ini v1.57.0 h1:Qwzj3wZQW+Plax5Ntj+GYe07DfGj1OH+aL1nMTMaNow= github.com/go-ini/ini v1.57.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/kardianos/govendor v1.0.9 h1:WOH3FcVI9eOgnIZYg96iwUwrL4eOVx+aQ66oyX2R8Yc= -github.com/kardianos/govendor v1.0.9/go.mod h1:yvmR6q9ZZ7nSF5Wvh40v0wfP+3TwwL8zYQp+itoZSVM= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200429213335-127c98bd7927 h1:qunaQbmBN1l/xZt8mr6MLr8G/IOFiMbXvxYbGVqKlyw= -golang.org/x/tools v0.0.0-20200429213335-127c98bd7927/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/readme.md b/readme.md index 64b0c5e..088e7bd 100644 --- a/readme.md +++ b/readme.md @@ -70,6 +70,8 @@ 2020/12/15:添加前缀树工具,实现前缀搜索和字符串搜索功能 +2020/12/16: 添加YAML和结构体转换工具 + # mod vendor模式加载包 通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到 diff --git a/util/yaml/YamlTool.go b/util/yaml/YamlTool.go new file mode 100644 index 0000000..1162cc1 --- /dev/null +++ b/util/yaml/YamlTool.go @@ -0,0 +1,57 @@ +/* + * @Author : huangzj + * @Time : 2020/12/16 11:56 + * @Description: + */ + +package yaml + +import ( + "gopkg.in/yaml.v2" + "io/ioutil" +) + +//把文件中的yaml结构转换成结构体 +func GetYamlToStructByFile(fileName string, object interface{}) error { + yamlFile, err := ioutil.ReadFile(fileName) + if err != nil { + return err + } + + err = yaml.Unmarshal(yamlFile, object) + if err != nil { + return err + } + + return nil +} + +//通过字符串的Yaml转换成结构体 +func GetYamlToStructByString(content string, object interface{}) error { + err := yaml.Unmarshal([]byte(content), object) + if err != nil { + return err + } + + return nil +} + +//通过字符串的Yaml转换成map +func GetYamlToMap(content string) (error, map[interface{}]interface{}) { + m := make(map[interface{}]interface{}, 0) + err := yaml.Unmarshal([]byte(content), m) + if err != nil { + return err, m + } + + return nil, m +} + +//把结构体转换成yaml的字符串 +func GetStructToYaml(object interface{}) (error, string) { + result, err := yaml.Marshal(object) + if err != nil { + return err, "" + } + return nil, string(result) +} diff --git a/util/yaml/YamlTool_test.go b/util/yaml/YamlTool_test.go new file mode 100644 index 0000000..927227c --- /dev/null +++ b/util/yaml/YamlTool_test.go @@ -0,0 +1,79 @@ +/* + * @Author : huangzj + * @Time : 2020/12/16 11:56 + * @Description: + */ + +package yaml + +import ( + "fmt" + "io/ioutil" + "testing" +) + +type MySQLConfig struct { + User string `yaml:"user"` + Password string `yaml:"password"` + Host string `yaml:"host"` + Port int `yaml:"port"` + DbName string `yaml:"dbname"` +} +type RedisConfig struct { + Host string `yaml:"host"` + Port int `yaml:"port"` + Auth string `yaml:"-"` //标签表示不显示 +} +type NginxProxyConfig struct { + Counter int `yaml:"counter"` + NginxList []string `yaml:"nginx_list"` +} + +type ServiceYaml struct { + MySQL MySQLConfig `yaml:"mysql"` + Redis RedisConfig `yaml:"redis"` + NginxProxy NginxProxyConfig `yaml:"nginx_proxy"` +} + +func TestYamlToStructByFile(t *testing.T) { + config := new(ServiceYaml) + _ = GetYamlToStructByFile("config.yaml", &config) + + fmt.Printf("MySQL host : %s, port : %d, user : %s, password : %s, db_name : %s \n", + config.MySQL.Host, config.MySQL.Port, config.MySQL.User, config.MySQL.Password, config.MySQL.DbName) + + fmt.Printf("Redis host : %s, port %d, auth : %s\n", + config.Redis.Host, config.Redis.Port, config.Redis.Auth) + + fmt.Printf("Vip Counter: %d, Vip List : %v\n", config.NginxProxy.Counter, config.NginxProxy.NginxList) +} + +func TestYamlToStructByString(t *testing.T) { + config := new(ServiceYaml) + fileByte, _ := ioutil.ReadFile("config.yaml") + _ = GetYamlToStructByString(string(fileByte), &config) + + fmt.Printf("MySQL host : %s, port : %d, user : %s, password : %s, db_name : %s \n", + config.MySQL.Host, config.MySQL.Port, config.MySQL.User, config.MySQL.Password, config.MySQL.DbName) + + fmt.Printf("Redis host : %s, port %d, auth : %s\n", + config.Redis.Host, config.Redis.Port, config.Redis.Auth) + + fmt.Printf("Vip Counter: %d, Vip List : %v\n", config.NginxProxy.Counter, config.NginxProxy.NginxList) +} + +func TestYamlToMap(t *testing.T) { + fileByte, _ := ioutil.ReadFile("config.yaml") + _, m := GetYamlToMap(string(fileByte)) + for key, value := range m { + fmt.Println(fmt.Sprintf("key:%v ,value: %v", key, value)) + } +} + +func TestStructToYaml(t *testing.T) { + config := new(ServiceYaml) + fileByte, _ := ioutil.ReadFile("config.yaml") + _ = GetYamlToStructByString(string(fileByte), &config) + _, result := GetStructToYaml(config) + fmt.Println(result) +} diff --git a/util/yaml/config.yaml b/util/yaml/config.yaml new file mode 100644 index 0000000..af003df --- /dev/null +++ b/util/yaml/config.yaml @@ -0,0 +1,17 @@ +mysql: + user: root + password: 123456 + host: 192.198.1.1 + port: 3306 + dbname: mdb +redis: + host: 192.168.1.1 + port: 1234 + auth: 123456 +nginx_proxy: + counter: 3 + nginx_list: [ + 192.168.1.1, + 192.168.1.2, + 192.168.1.3 + ] \ No newline at end of file diff --git a/util/yaml/readme.md b/util/yaml/readme.md new file mode 100644 index 0000000..991fc90 --- /dev/null +++ b/util/yaml/readme.md @@ -0,0 +1,5 @@ +获取包命令: https://gopkg.in/yaml.v2 + +文档地址: https://gopkg.in/yaml.v2 + +参考地址:http://www.topgoer.com/%E5%85%B6%E4%BB%96/Yaml%E7%BC%96%E7%A0%81%E5%92%8C%E8%A7%A3%E7%A0%81.html \ No newline at end of file diff --git a/vendor/github.com/ahmetb/go-linq/.travis.yml b/vendor/github.com/ahmetb/go-linq/.travis.yml index 6587753..157e59f 100644 --- a/vendor/github.com/ahmetb/go-linq/.travis.yml +++ b/vendor/github.com/ahmetb/go-linq/.travis.yml @@ -2,14 +2,13 @@ sudo: false language: go go: - - 1.5 - 1.7 before_install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover - go get -u github.com/golang/lint/golint - + script: - go vet -x ./... - golint ./... diff --git a/vendor/github.com/ahmetb/go-linq/LICENSE b/vendor/github.com/ahmetb/go-linq/LICENSE index 71dd824..c1ab55f 100644 --- a/vendor/github.com/ahmetb/go-linq/LICENSE +++ b/vendor/github.com/ahmetb/go-linq/LICENSE @@ -1,14 +1,201 @@ -Copyright 2016 Ahmet Alp Balkan + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - http://www.apache.org/licenses/LICENSE-2.0 + 1. Definitions. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 Ahmet Alp Balkan + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/ahmetb/go-linq/README.md b/vendor/github.com/ahmetb/go-linq/README.md index 475464c..4e9f12b 100644 --- a/vendor/github.com/ahmetb/go-linq/README.md +++ b/vendor/github.com/ahmetb/go-linq/README.md @@ -1,16 +1,21 @@ # go-linq [![GoDoc](https://godoc.org/github.com/ahmetalpbalkan/go-linq?status.svg)](https://godoc.org/github.com/ahmetalpbalkan/go-linq) [![Build Status](https://travis-ci.org/ahmetalpbalkan/go-linq.svg?branch=master)](https://travis-ci.org/ahmetalpbalkan/go-linq) [![Coverage Status](https://coveralls.io/repos/github/ahmetalpbalkan/go-linq/badge.svg?branch=master)](https://coveralls.io/github/ahmetalpbalkan/go-linq?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/ahmetalpbalkan/go-linq)](https://goreportcard.com/report/github.com/ahmetalpbalkan/go-linq) A powerful language integrated query (LINQ) library for Go. -* Written in vanilla Go! -* Safe for concurrent use +* Written in vanilla Go, no dependencies! * Complete lazy evaluation with iterator pattern +* Safe for concurrent use +* Supports generic functions to make your code cleaner and free of type assertions * Supports arrays, slices, maps, strings, channels and custom collections -(collection needs to implement `Iterable` interface and element - `Comparable` -interface) ## Installation $ go get github.com/ahmetalpbalkan/go-linq +We recommend using a dependency manager (e.g. [govendor][govendor] or +[godep][godep]) to maintain a local copy of this package in your project. + +[govendor]: https://github.com/kardianos/govendor +[godep]: https://github.com/tools/godep/ + > :warning: :warning: `go-linq` has recently introduced _breaking API changes_ > with v2.0.0. See [release notes](#release-notes) for details. v2.0.0 comes with > a refined interface, dramatically increased performance and memory efficiency, @@ -26,16 +31,20 @@ Usage is as easy as chaining methods like: `From(slice)` `.Where(predicate)` `.Select(selector)` `.Union(data)` -**Example: Find all owners of cars manufactured from 2015** +**Example 1: Find all owners of cars manufactured after 2015** + ```go import . "github.com/ahmetalpbalkan/go-linq" type Car struct { - id, year int + year int owner, model string } -owners := []string{} +... + + +var owners []string From(cars).Where(func(c interface{}) bool { return c.(Car).year >= 2015 @@ -44,7 +53,21 @@ From(cars).Where(func(c interface{}) bool { }).ToSlice(&owners) ``` -**Example: Find the author who has written the most books** +Or, you can use generic functions, like `WhereT` and `SelectT` to simplify your code +(at a performance penalty): + +```go +var owners []string + +From(cars).WhereT(func(c Car) bool { + return c.year >= 2015 +}).SelectT(func(c Car) string { + return c.owner +}).ToSlice(&owners) +``` + +**Example 2: Find the author who has written the most books** + ```go import . "github.com/ahmetalpbalkan/go-linq" @@ -71,7 +94,8 @@ author := From(books).SelectMany( // make a flat array of authors }).First() // take the first author ``` -**Example: Implement a custom method that leaves only values greater than the specified threshold** +**Example 3: Implement a custom method that leaves only values greater than the specified threshold** + ```go type MyQuery Query @@ -96,10 +120,67 @@ func (q MyQuery) GreaterThan(threshold int) Query { result := MyQuery(Range(1,10)).GreaterThan(5).Results() ``` -**More examples** can be found in [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq). +## Generic Functions + +Although Go doesn't implement generics, with some reflection tricks, you can use go-linq without +typing `interface{}`s and type assertions. This will introduce a performance penalty (5x-10x slower) +but will yield in a cleaner and more readable code. + +Methods with `T` suffix (such as `WhereT`) accept functions with generic types. So instead of + + .Select(func(v interface{}) interface{} {...}) + +you can type: + + .SelectT(func(v YourType) YourOtherType {...}) + +This will make your code free of `interface{}` and type assertions. + +**Example 4: "MapReduce" in a slice of string sentences to list the top 5 most used words using generic functions** + +```go +var results []string + +From(sentences). + // split sentences to words + SelectManyT(func(sentence string) Query { + return From(strings.Split(sentence, " ")) + }). + // group the words + GroupByT( + func(word string) string { return word }, + func(word string) string { return word }, + ). + // order by count + OrderByDescendingT(func(wordGroup Group) int { + return len(wordGroup.Group) + }). + // order by the word + ThenByT(func(wordGroup Group) string { + return wordGroup.Key.(string) + }). + Take(5). // take the top 5 + // project the words using the index as rank + SelectIndexedT(func(index int, wordGroup Group) string { + return fmt.Sprintf("Rank: #%d, Word: %s, Counts: %d", index+1, wordGroup.Key, len(wordGroup.Group)) + }). + ToSlice(&results) +``` + +**More examples** can be found in the [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq). ## Release Notes + ~~~ +v3.0.0 (2017-01-10) +* Breaking change: ToSlice() now overwrites existing slice starting + from index 0 and grows/reslices it as needed. +* Generic methods support (thanks @cleitonmarx!) + - Accepting parametrized functions was originally proposed in #26 + - You can now avoid type assertions and interface{}s + - Functions with generic methods are named as "MethodNameT" and + signature for the existing LINQ methods are unchanged. +* Added ForEach(), ForEachIndexed() and AggregateWithSeedBy(). v2.0.0 (2016-09-02) * IMPORTANT: This release is a BREAKING CHANGE. The old version diff --git a/vendor/github.com/ahmetb/go-linq/aggregate.go b/vendor/github.com/ahmetb/go-linq/aggregate.go index a8658c5..bb1975d 100644 --- a/vendor/github.com/ahmetb/go-linq/aggregate.go +++ b/vendor/github.com/ahmetb/go-linq/aggregate.go @@ -2,16 +2,15 @@ package linq // Aggregate applies an accumulator function over a sequence. // -// Aggregate method makes it simple to perform a calculation over a sequence of values. -// This method works by calling f() one time for each element in source -// except the first one. Each time f() is called, Aggregate passes both -// the element from the sequence and an aggregated value (as the first argument to f()). -// The first element of source is used as the initial aggregate value. -// The result of f() replaces the previous aggregated value. +// Aggregate method makes it simple to perform a calculation over a sequence of +// values. This method works by calling f() one time for each element in source +// except the first one. Each time f() is called, Aggregate passes both the +// element from the sequence and an aggregated value (as the first argument to +// f()). The first element of source is used as the initial aggregate value. The +// result of f() replaces the previous aggregated value. // // Aggregate returns the final result of f(). -func (q Query) Aggregate( - f func(interface{}, interface{}) interface{}) interface{} { +func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface{} { next := q.Iterate() result, any := next() @@ -26,21 +25,40 @@ func (q Query) Aggregate( return result } -// AggregateWithSeed applies an accumulator function over a sequence. -// The specified seed value is used as the initial accumulator value. +// AggregateT is the typed version of Aggregate. // -// Aggregate method makes it simple to perform a calculation over a sequence of values. -// This method works by calling f() one time for each element in source -// except the first one. Each time f() is called, Aggregate passes both -// the element from the sequence and an aggregated value (as the first argument to f()). -// The value of the seed parameter is used as the initial aggregate value. +// - f is of type: func(TSource, TSource) TSource +// +// NOTE: Aggregate has better performance than AggregateT. +func (q Query) AggregateT(f interface{}) interface{} { + fGenericFunc, err := newGenericFunc( + "AggregateT", "f", f, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + fFunc := func(result interface{}, current interface{}) interface{} { + return fGenericFunc.Call(result, current) + } + + return q.Aggregate(fFunc) +} + +// AggregateWithSeed applies an accumulator function over a sequence. The +// specified seed value is used as the initial accumulator value. +// +// Aggregate method makes it simple to perform a calculation over a sequence of +// values. This method works by calling f() one time for each element in source +// except the first one. Each time f() is called, Aggregate passes both the +// element from the sequence and an aggregated value (as the first argument to +// f()). The value of the seed parameter is used as the initial aggregate value. // The result of f() replaces the previous aggregated value. // // Aggregate returns the final result of f(). -func (q Query) AggregateWithSeed( - seed interface{}, - f func(interface{}, interface{}) interface{}, -) interface{} { +func (q Query) AggregateWithSeed(seed interface{}, + f func(interface{}, interface{}) interface{}) interface{} { next := q.Iterate() result := seed @@ -51,3 +69,90 @@ func (q Query) AggregateWithSeed( return result } + +// AggregateWithSeedT is the typed version of AggregateWithSeed. +// +// - f is of type "func(TAccumulate, TSource) TAccumulate" +// +// NOTE: AggregateWithSeed has better performance than +// AggregateWithSeedT. +func (q Query) AggregateWithSeedT(seed interface{}, + f interface{}) interface{} { + fGenericFunc, err := newGenericFunc( + "AggregateWithSeed", "f", f, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + fFunc := func(result interface{}, current interface{}) interface{} { + return fGenericFunc.Call(result, current) + } + + return q.AggregateWithSeed(seed, fFunc) +} + +// AggregateWithSeedBy applies an accumulator function over a sequence. The +// specified seed value is used as the initial accumulator value, and the +// specified function is used to select the result value. +// +// Aggregate method makes it simple to perform a calculation over a sequence of +// values. This method works by calling f() one time for each element in source. +// Each time func is called, Aggregate passes both the element from the sequence +// and an aggregated value (as the first argument to func). The value of the +// seed parameter is used as the initial aggregate value. The result of func +// replaces the previous aggregated value. +// +// The final result of func is passed to resultSelector to obtain the final +// result of Aggregate. +func (q Query) AggregateWithSeedBy(seed interface{}, + f func(interface{}, interface{}) interface{}, + resultSelector func(interface{}) interface{}) interface{} { + + next := q.Iterate() + result := seed + + for current, ok := next(); ok; current, ok = next() { + result = f(result, current) + } + + return resultSelector(result) +} + +// AggregateWithSeedByT is the typed version of AggregateWithSeedBy. +// +// - f is of type "func(TAccumulate, TSource) TAccumulate" +// - resultSelectorFn is of type "func(TAccumulate) TResult" +// +// NOTE: AggregateWithSeedBy has better performance than +// AggregateWithSeedByT. +func (q Query) AggregateWithSeedByT(seed interface{}, + f interface{}, + resultSelectorFn interface{}) interface{} { + fGenericFunc, err := newGenericFunc( + "AggregateWithSeedByT", "f", f, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + fFunc := func(result interface{}, current interface{}) interface{} { + return fGenericFunc.Call(result, current) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "AggregateWithSeedByT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(result interface{}) interface{} { + return resultSelectorGenericFunc.Call(result) + } + + return q.AggregateWithSeedBy(seed, fFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/compare.go b/vendor/github.com/ahmetb/go-linq/compare.go index c78e4aa..3e0ffbf 100644 --- a/vendor/github.com/ahmetb/go-linq/compare.go +++ b/vendor/github.com/ahmetb/go-linq/compare.go @@ -2,21 +2,21 @@ package linq type comparer func(interface{}, interface{}) int -// Comparable is an interface that has to be implemented by a -// custom collection elememts in order to work with linq. +// Comparable is an interface that has to be implemented by a custom collection +// elememts in order to work with linq. // // Example: -// func (f foo) CompareTo(c Comparable) int { -// a, b := f.f1, c.(foo).f1 +// func (f foo) CompareTo(c Comparable) int { +// a, b := f.f1, c.(foo).f1 // -// if a < b { -// return -1 -// } else if a > b { -// return 1 -// } +// if a < b { +// return -1 +// } else if a > b { +// return 1 +// } // -// return 0 -// } +// return 0 +// } type Comparable interface { CompareTo(Comparable) int } diff --git a/vendor/github.com/ahmetb/go-linq/concat.go b/vendor/github.com/ahmetb/go-linq/concat.go index 6210126..3101c56 100644 --- a/vendor/github.com/ahmetb/go-linq/concat.go +++ b/vendor/github.com/ahmetb/go-linq/concat.go @@ -1,7 +1,7 @@ package linq -// Append inserts an item to the end of a collection, -// so it becomes the last item. +// Append inserts an item to the end of a collection, so it becomes the last +// item. func (q Query) Append(item interface{}) Query { return Query{ Iterate: func() Iterator { @@ -28,8 +28,8 @@ func (q Query) Append(item interface{}) Query { // Concat concatenates two collections. // // The Concat method differs from the Union method because the Concat method -// returns all the original elements in the input sequences. -// The Union method returns only unique elements. +// returns all the original elements in the input sequences. The Union method +// returns only unique elements. func (q Query) Concat(q2 Query) Query { return Query{ Iterate: func() Iterator { @@ -53,8 +53,8 @@ func (q Query) Concat(q2 Query) Query { } } -// Prepend inserts an item to the beginning of a collection, -// so it becomes the first item. +// Prepend inserts an item to the beginning of a collection, so it becomes the +// first item. func (q Query) Prepend(item interface{}) Query { return Query{ Iterate: func() Iterator { diff --git a/vendor/github.com/ahmetb/go-linq/distinct.go b/vendor/github.com/ahmetb/go-linq/distinct.go index 7a32c31..aaef37a 100644 --- a/vendor/github.com/ahmetb/go-linq/distinct.go +++ b/vendor/github.com/ahmetb/go-linq/distinct.go @@ -1,7 +1,7 @@ package linq -// Distinct method returns distinct elements from a collection. -// The result is an unordered collection that contains no duplicate values. +// Distinct method returns distinct elements from a collection. The result is an +// unordered collection that contains no duplicate values. func (q Query) Distinct() Query { return Query{ Iterate: func() Iterator { @@ -22,11 +22,11 @@ func (q Query) Distinct() Query { } } -// Distinct method returns distinct elements from a collection. -// The result is an ordered collection that contains no duplicate values. +// Distinct method returns distinct elements from a collection. The result is an +// ordered collection that contains no duplicate values. // // NOTE: Distinct method on OrderedQuery type has better performance than -// Distinct method on Query type +// Distinct method on Query type. func (oq OrderedQuery) Distinct() OrderedQuery { return OrderedQuery{ orders: oq.orders, @@ -73,3 +73,26 @@ func (q Query) DistinctBy(selector func(interface{}) interface{}) Query { }, } } + +// DistinctByT is the typed version of DistinctBy. +// +// - selectorFn is of type "func(TSource) TSource". +// +// NOTE: DistinctBy has better performance than DistinctByT. +func (q Query) DistinctByT(selectorFn interface{}) Query { + selectorFunc, ok := selectorFn.(func(interface{}) interface{}) + if !ok { + selectorGenericFunc, err := newGenericFunc( + "DistinctByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc = func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + } + return q.DistinctBy(selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/doc.go b/vendor/github.com/ahmetb/go-linq/doc.go index 8231f70..c89c4fe 100644 --- a/vendor/github.com/ahmetb/go-linq/doc.go +++ b/vendor/github.com/ahmetb/go-linq/doc.go @@ -1,5 +1,6 @@ -// Package linq provides methods for querying and manipulating -// slices, arrays, maps, strings, channels and collections. +// Package linq provides methods for querying and manipulating slices, arrays, +// maps, strings, channels and collections. // -// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan +// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan, Cleiton Marques +// Souza. package linq diff --git a/vendor/github.com/ahmetb/go-linq/except.go b/vendor/github.com/ahmetb/go-linq/except.go index c34a6b4..d146992 100644 --- a/vendor/github.com/ahmetb/go-linq/except.go +++ b/vendor/github.com/ahmetb/go-linq/except.go @@ -1,8 +1,7 @@ package linq -// Except produces the set difference of two sequences. -// The set difference is the members of the first sequence -// that don't appear in the second sequence. +// Except produces the set difference of two sequences. The set difference is +// the members of the first sequence that don't appear in the second sequence. func (q Query) Except(q2 Query) Query { return Query{ Iterate: func() Iterator { @@ -27,12 +26,11 @@ func (q Query) Except(q2 Query) Query { } } -// ExceptBy invokes a transform function on each element of a collection -// and produces the set difference of two sequences. -// The set difference is the members of the first sequence -// that don't appear in the second sequence. -func (q Query) ExceptBy( - q2 Query, selector func(interface{}) interface{}) Query { +// ExceptBy invokes a transform function on each element of a collection and +// produces the set difference of two sequences. The set difference is the +// members of the first sequence that don't appear in the second sequence. +func (q Query) ExceptBy(q2 Query, + selector func(interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { next := q.Iterate() @@ -57,3 +55,25 @@ func (q Query) ExceptBy( }, } } + +// ExceptByT is the typed version of ExceptBy. +// +// - selectorFn is of type "func(TSource) TSource" +// +// NOTE: ExceptBy has better performance than ExceptByT. +func (q Query) ExceptByT(q2 Query, + selectorFn interface{}) Query { + selectorGenericFunc, err := newGenericFunc( + "ExceptByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.ExceptBy(q2, selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/from.go b/vendor/github.com/ahmetb/go-linq/from.go index 56ab451..21ee9f4 100644 --- a/vendor/github.com/ahmetb/go-linq/from.go +++ b/vendor/github.com/ahmetb/go-linq/from.go @@ -5,30 +5,30 @@ import "reflect" // Iterator is an alias for function to iterate over data. type Iterator func() (item interface{}, ok bool) -// Query is the type returned from query functions. -// It can be iterated manually as shown in the example. +// Query is the type returned from query functions. It can be iterated manually +// as shown in the example. type Query struct { Iterate func() Iterator } -// KeyValue is a type that is used to iterate over a map -// (if query is created from a map). This type is also used by -// ToMap() method to output result of a query into a map. +// KeyValue is a type that is used to iterate over a map (if query is created +// from a map). This type is also used by ToMap() method to output result of a +// query into a map. type KeyValue struct { Key interface{} Value interface{} } -// Iterable is an interface that has to be implemented by a -// custom collection in order to work with linq. +// Iterable is an interface that has to be implemented by a custom collection in +// order to work with linq. type Iterable interface { Iterate() Iterator } -// From initializes a linq query with passed slice, array or map -// as the source. String, channel or struct implementing Iterable -// interface can be used as an input. In this case From delegates it -// to FromString, FromChannel and FromIterable internally. +// From initializes a linq query with passed slice, array or map as the source. +// String, channel or struct implementing Iterable interface can be used as an +// input. In this case From delegates it to FromString, FromChannel and +// FromIterable internally. func From(source interface{}) Query { src := reflect.ValueOf(source) @@ -84,8 +84,8 @@ func From(source interface{}) Query { } } -// FromChannel initializes a linq query with passed channel, -// linq iterates over channel until it is closed. +// FromChannel initializes a linq query with passed channel, linq iterates over +// channel until it is closed. func FromChannel(source <-chan interface{}) Query { return Query{ Iterate: func() Iterator { @@ -97,8 +97,8 @@ func FromChannel(source <-chan interface{}) Query { } } -// FromString initializes a linq query with passed string, -// linq iterates over runes of string. +// FromString initializes a linq query with passed string, linq iterates over +// runes of string. func FromString(source string) Query { runes := []rune(source) len := len(runes) @@ -120,8 +120,8 @@ func FromString(source string) Query { } } -// FromIterable initializes a linq query with custom collection passed. -// This collection has to implement Iterable interface, linq iterates over items, +// FromIterable initializes a linq query with custom collection passed. This +// collection has to implement Iterable interface, linq iterates over items, // that has to implement Comparable interface or be basic types. func FromIterable(source Iterable) Query { return Query{ diff --git a/vendor/github.com/ahmetb/go-linq/groupby.go b/vendor/github.com/ahmetb/go-linq/groupby.go index 2affbf8..face510 100644 --- a/vendor/github.com/ahmetb/go-linq/groupby.go +++ b/vendor/github.com/ahmetb/go-linq/groupby.go @@ -6,14 +6,11 @@ type Group struct { Group []interface{} } -// GroupBy method groups the elements of a collection according -// to a specified key selector function and projects the elements for each group -// by using a specified function. -func (q Query) GroupBy( - keySelector func(interface{}) interface{}, - elementSelector func(interface{}) interface{}, -) Query { - +// GroupBy method groups the elements of a collection according to a specified +// key selector function and projects the elements for each group by using a +// specified function. +func (q Query) GroupBy(keySelector func(interface{}) interface{}, + elementSelector func(interface{}) interface{}) Query { return Query{ func() Iterator { next := q.Iterate() @@ -46,3 +43,39 @@ func (q Query) GroupBy( }, } } + +// GroupByT is the typed version of GroupBy. +// +// - keySelectorFn is of type "func(TSource) TKey" +// - elementSelectorFn is of type "func(TSource) TElement" +// +// NOTE: GroupBy has better performance than GroupByT. +func (q Query) GroupByT(keySelectorFn interface{}, + elementSelectorFn interface{}) Query { + keySelectorGenericFunc, err := newGenericFunc( + "GroupByT", "keySelectorFn", keySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + keySelectorFunc := func(item interface{}) interface{} { + return keySelectorGenericFunc.Call(item) + } + + elementSelectorGenericFunc, err := newGenericFunc( + "GroupByT", "elementSelectorFn", elementSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + elementSelectorFunc := func(item interface{}) interface{} { + return elementSelectorGenericFunc.Call(item) + + } + + return q.GroupBy(keySelectorFunc, elementSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/groupjoin.go b/vendor/github.com/ahmetb/go-linq/groupjoin.go index 7a3b56b..f9f8144 100644 --- a/vendor/github.com/ahmetb/go-linq/groupjoin.go +++ b/vendor/github.com/ahmetb/go-linq/groupjoin.go @@ -1,25 +1,27 @@ package linq +import "reflect" + // GroupJoin correlates the elements of two collections based on key equality, // and groups the results. // -// This method produces hierarchical results, which means that elements from outer query -// are paired with collections of matching elements from inner. GroupJoin enables you -// to base your results on a whole set of matches for each element of outer query. +// This method produces hierarchical results, which means that elements from +// outer query are paired with collections of matching elements from inner. +// GroupJoin enables you to base your results on a whole set of matches for each +// element of outer query. // // The resultSelector function is called only one time for each outer element -// together with a collection of all the inner elements that match the outer element. -// This differs from the Join method, in which the result selector function is invoked -// on pairs that contain one element from outer and one element from inner. +// together with a collection of all the inner elements that match the outer +// element. This differs from the Join method, in which the result selector +// function is invoked on pairs that contain one element from outer and one +// element from inner. // -// GroupJoin preserves the order of the elements of outer, and for each element of outer, -// the order of the matching elements from inner. -func (q Query) GroupJoin( - inner Query, +// GroupJoin preserves the order of the elements of outer, and for each element +// of outer, the order of the matching elements from inner. +func (q Query) GroupJoin(inner Query, outerKeySelector func(interface{}) interface{}, innerKeySelector func(interface{}) interface{}, - resultSelector func(outer interface{}, inners []interface{}) interface{}, -) Query { + resultSelector func(outer interface{}, inners []interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { @@ -48,3 +50,58 @@ func (q Query) GroupJoin( }, } } + +// GroupJoinT is the typed version of GroupJoin. +// +// - inner: The query to join to the outer query. +// - outerKeySelectorFn is of type "func(TOuter) TKey" +// - innerKeySelectorFn is of type "func(TInner) TKey" +// - resultSelectorFn: is of type "func(TOuter, inners []TInner) TResult" +// +// NOTE: GroupJoin has better performance than GroupJoinT. +func (q Query) GroupJoinT(inner Query, + outerKeySelectorFn interface{}, + innerKeySelectorFn interface{}, + resultSelectorFn interface{}) Query { + outerKeySelectorGenericFunc, err := newGenericFunc( + "GroupJoinT", "outerKeySelectorFn", outerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + outerKeySelectorFunc := func(item interface{}) interface{} { + return outerKeySelectorGenericFunc.Call(item) + } + + innerKeySelectorFuncGenericFunc, err := newGenericFunc( + "GroupJoinT", "innerKeySelectorFn", innerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + innerKeySelectorFunc := func(item interface{}) interface{} { + return innerKeySelectorFuncGenericFunc.Call(item) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "GroupJoinT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, inners []interface{}) interface{} { + innerSliceType := reflect.MakeSlice(resultSelectorGenericFunc.Cache.TypesIn[1], 0, 0) + innersSlicePointer := reflect.New(innerSliceType.Type()) + From(inners).ToSlice(innersSlicePointer.Interface()) + innersTyped := reflect.Indirect(innersSlicePointer).Interface() + return resultSelectorGenericFunc.Call(outer, innersTyped) + } + + return q.GroupJoin(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/intersect.go b/vendor/github.com/ahmetb/go-linq/intersect.go index 6499bb8..511ed3b 100644 --- a/vendor/github.com/ahmetb/go-linq/intersect.go +++ b/vendor/github.com/ahmetb/go-linq/intersect.go @@ -2,8 +2,8 @@ package linq // Intersect produces the set intersection of the source collection and the // provided input collection. The intersection of two sets A and B is defined as -// the set that contains all the elements of A that also appear in B, -// but no other elements. +// the set that contains all the elements of A that also appear in B, but no +// other elements. func (q Query) Intersect(q2 Query) Query { return Query{ Iterate: func() Iterator { @@ -31,14 +31,12 @@ func (q Query) Intersect(q2 Query) Query { // IntersectBy produces the set intersection of the source collection and the // provided input collection. The intersection of two sets A and B is defined as -// the set that contains all the elements of A that also appear in B, -// but no other elements. +// the set that contains all the elements of A that also appear in B, but no +// other elements. // // IntersectBy invokes a transform function on each element of both collections. -func (q Query) IntersectBy( - q2 Query, - selector func(interface{}) interface{}, -) Query { +func (q Query) IntersectBy(q2 Query, + selector func(interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { @@ -65,3 +63,25 @@ func (q Query) IntersectBy( }, } } + +// IntersectByT is the typed version of IntersectBy. +// +// - selectorFn is of type "func(TSource) TSource" +// +// NOTE: IntersectBy has better performance than IntersectByT. +func (q Query) IntersectByT(q2 Query, + selectorFn interface{}) Query { + selectorGenericFunc, err := newGenericFunc( + "IntersectByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.IntersectBy(q2, selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/join.go b/vendor/github.com/ahmetb/go-linq/join.go index 95cb835..68211a2 100644 --- a/vendor/github.com/ahmetb/go-linq/join.go +++ b/vendor/github.com/ahmetb/go-linq/join.go @@ -2,20 +2,18 @@ package linq // Join correlates the elements of two collection based on matching keys. // -// A join refers to the operation of correlating the elements of two sources -// of information based on a common key. Join brings the two information sources -// and the keys by which they are matched together in one method call. -// This differs from the use of SelectMany, which requires more than one method call +// A join refers to the operation of correlating the elements of two sources of +// information based on a common key. Join brings the two information sources +// and the keys by which they are matched together in one method call. This +// differs from the use of SelectMany, which requires more than one method call // to perform the same operation. // -// Join preserves the order of the elements of outer collection, -// and for each of these elements, the order of the matching elements of inner. -func (q Query) Join( - inner Query, +// Join preserves the order of the elements of outer collection, and for each of +// these elements, the order of the matching elements of inner. +func (q Query) Join(inner Query, outerKeySelector func(interface{}) interface{}, innerKeySelector func(interface{}) interface{}, - resultSelector func(outer interface{}, inner interface{}) interface{}, -) Query { + resultSelector func(outer interface{}, inner interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { @@ -54,3 +52,54 @@ func (q Query) Join( }, } } + +// JoinT is the typed version of Join. +// +// - outerKeySelectorFn is of type "func(TOuter) TKey" +// - innerKeySelectorFn is of type "func(TInner) TKey" +// - resultSelectorFn is of type "func(TOuter,TInner) TResult" +// +// NOTE: Join has better performance than JoinT. +func (q Query) JoinT(inner Query, + outerKeySelectorFn interface{}, + innerKeySelectorFn interface{}, + resultSelectorFn interface{}) Query { + outerKeySelectorGenericFunc, err := newGenericFunc( + "JoinT", "outerKeySelectorFn", outerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + outerKeySelectorFunc := func(item interface{}) interface{} { + return outerKeySelectorGenericFunc.Call(item) + } + + innerKeySelectorFuncGenericFunc, err := newGenericFunc( + "JoinT", "innerKeySelectorFn", + innerKeySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + innerKeySelectorFunc := func(item interface{}) interface{} { + return innerKeySelectorFuncGenericFunc.Call(item) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "JoinT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, inner interface{}) interface{} { + return resultSelectorGenericFunc.Call(outer, inner) + } + + return q.Join(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/orderby.go b/vendor/github.com/ahmetb/go-linq/orderby.go index ff7f5ce..110559d 100644 --- a/vendor/github.com/ahmetb/go-linq/orderby.go +++ b/vendor/github.com/ahmetb/go-linq/orderby.go @@ -8,18 +8,17 @@ type order struct { desc bool } -// OrderedQuery is the type returned from OrderBy, OrderByDescending -// ThenBy and ThenByDescending functions. +// OrderedQuery is the type returned from OrderBy, OrderByDescending ThenBy and +// ThenByDescending functions. type OrderedQuery struct { Query original Query orders []order } -// OrderBy sorts the elements of a collection in ascending order. -// Elements are sorted according to a key. -func (q Query) OrderBy( - selector func(interface{}) interface{}) OrderedQuery { +// OrderBy sorts the elements of a collection in ascending order. Elements are +// sorted according to a key. +func (q Query) OrderBy(selector func(interface{}) interface{}) OrderedQuery { return OrderedQuery{ orders: []order{{selector: selector}}, original: q, @@ -43,10 +42,30 @@ func (q Query) OrderBy( } } +// OrderByT is the typed version of OrderBy. +// +// - selectorFn is of type "func(TSource) TKey" +// +// NOTE: OrderBy has better performance than OrderByT. +func (q Query) OrderByT(selectorFn interface{}) OrderedQuery { + selectorGenericFunc, err := newGenericFunc( + "OrderByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.OrderBy(selectorFunc) +} + // OrderByDescending sorts the elements of a collection in descending order. // Elements are sorted according to a key. -func (q Query) OrderByDescending( - selector func(interface{}) interface{}) OrderedQuery { +func (q Query) OrderByDescending(selector func(interface{}) interface{}) OrderedQuery { return OrderedQuery{ orders: []order{{selector: selector, desc: true}}, original: q, @@ -70,9 +89,28 @@ func (q Query) OrderByDescending( } } -// ThenBy performs a subsequent ordering of the elements in a collection -// in ascending order. This method enables you to specify multiple sort criteria -// by applying any number of ThenBy or ThenByDescending methods. +// OrderByDescendingT is the typed version of OrderByDescending. +// - selectorFn is of type "func(TSource) TKey" +// NOTE: OrderByDescending has better performance than OrderByDescendingT. +func (q Query) OrderByDescendingT(selectorFn interface{}) OrderedQuery { + selectorGenericFunc, err := newGenericFunc( + "OrderByDescendingT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return q.OrderByDescending(selectorFunc) +} + +// ThenBy performs a subsequent ordering of the elements in a collection in +// ascending order. This method enables you to specify multiple sort criteria by +// applying any number of ThenBy or ThenByDescending methods. func (oq OrderedQuery) ThenBy( selector func(interface{}) interface{}) OrderedQuery { return OrderedQuery{ @@ -98,11 +136,29 @@ func (oq OrderedQuery) ThenBy( } } -// ThenByDescending performs a subsequent ordering of the elements in a collection -// in descending order. This method enables you to specify multiple sort criteria -// by applying any number of ThenBy or ThenByDescending methods. -func (oq OrderedQuery) ThenByDescending( - selector func(interface{}) interface{}) OrderedQuery { +// ThenByT is the typed version of ThenBy. +// - selectorFn is of type "func(TSource) TKey" +// NOTE: ThenBy has better performance than ThenByT. +func (oq OrderedQuery) ThenByT(selectorFn interface{}) OrderedQuery { + selectorGenericFunc, err := newGenericFunc( + "ThenByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + + return oq.ThenBy(selectorFunc) +} + +// ThenByDescending performs a subsequent ordering of the elements in a +// collection in descending order. This method enables you to specify multiple +// sort criteria by applying any number of ThenBy or ThenByDescending methods. +func (oq OrderedQuery) ThenByDescending(selector func(interface{}) interface{}) OrderedQuery { return OrderedQuery{ orders: append(oq.orders, order{selector: selector, desc: true}), original: oq.original, @@ -126,10 +182,32 @@ func (oq OrderedQuery) ThenByDescending( } } -// Sort returns a new query by sorting elements with provided less function -// in ascending order. The comparer function should return true if the parameter i -// is less than j. While this method is uglier than chaining OrderBy, OrderByDescending, -// ThenBy and ThenByDescending methods, it's performance is much better. +// ThenByDescendingT is the typed version of ThenByDescending. +// - selectorFn is of type "func(TSource) TKey" +// NOTE: ThenByDescending has better performance than ThenByDescendingT. +func (oq OrderedQuery) ThenByDescendingT(selectorFn interface{}) OrderedQuery { + selectorFunc, ok := selectorFn.(func(interface{}) interface{}) + if !ok { + selectorGenericFunc, err := newGenericFunc( + "ThenByDescending", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc = func(item interface{}) interface{} { + return selectorGenericFunc.Call(item) + } + } + return oq.ThenByDescending(selectorFunc) +} + +// Sort returns a new query by sorting elements with provided less function in +// ascending order. The comparer function should return true if the parameter i +// is less than j. While this method is uglier than chaining OrderBy, +// OrderByDescending, ThenBy and ThenByDescending methods, it's performance is +// much better. func (q Query) Sort(less func(i, j interface{}) bool) Query { return Query{ Iterate: func() Iterator { @@ -150,6 +228,25 @@ func (q Query) Sort(less func(i, j interface{}) bool) Query { } } +// SortT is the typed version of Sort. +// - lessFn is of type "func(TSource,TSource) bool" +// NOTE: Sort has better performance than SortT. +func (q Query) SortT(lessFn interface{}) Query { + lessGenericFunc, err := newGenericFunc( + "SortT", "lessFn", lessFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + lessFunc := func(i, j interface{}) bool { + return lessGenericFunc.Call(i, j).(bool) + } + + return q.Sort(lessFunc) +} + type sorter struct { items []interface{} less func(i, j interface{}) bool @@ -173,6 +270,10 @@ func (q Query) sort(orders []order) (r []interface{}) { r = append(r, item) } + if len(r) == 0 { + return + } + for i, j := range orders { orders[i].compare = getComparer(j.selector(r[0])) } diff --git a/vendor/github.com/ahmetb/go-linq/result.go b/vendor/github.com/ahmetb/go-linq/result.go index 979be93..34e47ab 100644 --- a/vendor/github.com/ahmetb/go-linq/result.go +++ b/vendor/github.com/ahmetb/go-linq/result.go @@ -18,6 +18,27 @@ func (q Query) All(predicate func(interface{}) bool) bool { return true } +// AllT is the typed version of All. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: All has better performance than AllT. +func (q Query) AllT(predicateFn interface{}) bool { + + predicateGenericFunc, err := newGenericFunc( + "AllT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.All(predicateFunc) +} + // Any determines whether any element of a collection exists. func (q Query) Any() bool { _, ok := q.Iterate()() @@ -37,6 +58,28 @@ func (q Query) AnyWith(predicate func(interface{}) bool) bool { return false } +// AnyWithT is the typed version of AnyWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: AnyWith has better performance than AnyWithT. +func (q Query) AnyWithT(predicateFn interface{}) bool { + + predicateGenericFunc, err := newGenericFunc( + "AnyWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.AnyWith(predicateFunc) +} + // Average computes the average of a collection of numeric values. func (q Query) Average() (r float64) { next := q.Iterate() @@ -104,8 +147,8 @@ func (q Query) Count() (r int) { return } -// CountWith returns a number that represents how many elements -// in the specified collection satisfy a condition. +// CountWith returns a number that represents how many elements in the specified +// collection satisfy a condition. func (q Query) CountWith(predicate func(interface{}) bool) (r int) { next := q.Iterate() @@ -118,14 +161,36 @@ func (q Query) CountWith(predicate func(interface{}) bool) (r int) { return } +// CountWithT is the typed version of CountWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: CountWith has better performance than CountWithT. +func (q Query) CountWithT(predicateFn interface{}) int { + + predicateGenericFunc, err := newGenericFunc( + "CountWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.CountWith(predicateFunc) +} + // First returns the first element of a collection. func (q Query) First() interface{} { item, _ := q.Iterate()() return item } -// FirstWith returns the first element of a collection that satisfies -// a specified condition. +// FirstWith returns the first element of a collection that satisfies a +// specified condition. func (q Query) FirstWith(predicate func(interface{}) bool) interface{} { next := q.Iterate() @@ -138,6 +203,99 @@ func (q Query) FirstWith(predicate func(interface{}) bool) interface{} { return nil } +// FirstWithT is the typed version of FirstWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: FirstWith has better performance than FirstWithT. +func (q Query) FirstWithT(predicateFn interface{}) interface{} { + + predicateGenericFunc, err := newGenericFunc( + "FirstWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.FirstWith(predicateFunc) +} + +// ForEach performs the specified action on each element of a collection. +func (q Query) ForEach(action func(interface{})) { + next := q.Iterate() + + for item, ok := next(); ok; item, ok = next() { + action(item) + } +} + +// ForEachT is the typed version of ForEach. +// +// - actionFn is of type "func(TSource)" +// +// NOTE: ForEach has better performance than ForEachT. +func (q Query) ForEachT(actionFn interface{}) { + actionGenericFunc, err := newGenericFunc( + "ForEachT", "actionFn", actionFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), nil), + ) + + if err != nil { + panic(err) + } + + actionFunc := func(item interface{}) { + actionGenericFunc.Call(item) + } + + q.ForEach(actionFunc) +} + +// ForEachIndexed performs the specified action on each element of a collection. +// +// The first argument to action represents the zero-based index of that +// element in the source collection. This can be useful if the elements are in a +// known order and you want to do something with an element at a particular +// index, for example. It can also be useful if you want to retrieve the index +// of one or more elements. The second argument to action represents the +// element to process. +func (q Query) ForEachIndexed(action func(int, interface{})) { + next := q.Iterate() + index := 0 + + for item, ok := next(); ok; item, ok = next() { + action(index, item) + index++ + } +} + +// ForEachIndexedT is the typed version of ForEachIndexed. +// +// - actionFn is of type "func(int, TSource)" +// +// NOTE: ForEachIndexed has better performance than ForEachIndexedT. +func (q Query) ForEachIndexedT(actionFn interface{}) { + actionGenericFunc, err := newGenericFunc( + "ForEachIndexedT", "actionFn", actionFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil), + ) + + if err != nil { + panic(err) + } + + actionFunc := func(index int, item interface{}) { + actionGenericFunc.Call(index, item) + } + + q.ForEachIndexed(actionFunc) +} + // Last returns the last element of a collection. func (q Query) Last() (r interface{}) { next := q.Iterate() @@ -149,8 +307,8 @@ func (q Query) Last() (r interface{}) { return } -// LastWith returns the last element of a collection that satisfies -// a specified condition. +// LastWith returns the last element of a collection that satisfies a specified +// condition. func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) { next := q.Iterate() @@ -163,6 +321,28 @@ func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) { return } +// LastWithT is the typed version of LastWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: LastWith has better performance than LastWithT. +func (q Query) LastWithT(predicateFn interface{}) interface{} { + + predicateGenericFunc, err := newGenericFunc( + "LastWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.LastWith(predicateFunc) +} + // Max returns the maximum value in a collection of values. func (q Query) Max() (r interface{}) { next := q.Iterate() @@ -230,8 +410,8 @@ func (q Query) SequenceEqual(q2 Query) bool { return !ok2 } -// Single returns the only element of a collection, and nil -// if there is not exactly one element in the collection. +// Single returns the only element of a collection, and nil if there is not +// exactly one element in the collection. func (q Query) Single() interface{} { next := q.Iterate() item, ok := next() @@ -247,8 +427,8 @@ func (q Query) Single() interface{} { return item } -// SingleWith returns the only element of a collection that satisfies -// a specified condition, and nil if more than one such element exists. +// SingleWith returns the only element of a collection that satisfies a +// specified condition, and nil if more than one such element exists. func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) { next := q.Iterate() found := false @@ -267,10 +447,31 @@ func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) { return } +// SingleWithT is the typed version of SingleWith. +// +// - predicateFn is of type "func(TSource) bool" +// +// NOTE: SingleWith has better performance than SingleWithT. +func (q Query) SingleWithT(predicateFn interface{}) interface{} { + predicateGenericFunc, err := newGenericFunc( + "SingleWithT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.SingleWith(predicateFunc) +} + // SumInts computes the sum of a collection of numeric values. // -// Values can be of any integer type: int, int8, int16, int32, int64. -// The result is int64. Method returns zero if collection contains no elements. +// Values can be of any integer type: int, int8, int16, int32, int64. The result +// is int64. Method returns zero if collection contains no elements. func (q Query) SumInts() (r int64) { next := q.Iterate() item, ok := next() @@ -290,8 +491,9 @@ func (q Query) SumInts() (r int64) { // SumUInts computes the sum of a collection of numeric values. // -// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64. -// The result is uint64. Method returns zero if collection contains no elements. +// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, +// uint64. The result is uint64. Method returns zero if collection contains no +// elements. func (q Query) SumUInts() (r uint64) { next := q.Iterate() item, ok := next() @@ -330,8 +532,8 @@ func (q Query) SumFloats() (r float64) { return } -// ToChannel iterates over a collection and outputs each element -// to a channel, then closes it. +// ToChannel iterates over a collection and outputs each element to a channel, +// then closes it. func (q Query) ToChannel(result chan<- interface{}) { next := q.Iterate() @@ -343,8 +545,9 @@ func (q Query) ToChannel(result chan<- interface{}) { } // ToMap iterates over a collection and populates result map with elements. -// Collection elements have to be of KeyValue type to use this method. -// To populate a map with elements of different type use ToMapBy method. +// Collection elements have to be of KeyValue type to use this method. To +// populate a map with elements of different type use ToMapBy method. ToMap +// doesn't empty the result map before populating it. func (q Query) ToMap(result interface{}) { q.ToMapBy( result, @@ -356,15 +559,14 @@ func (q Query) ToMap(result interface{}) { }) } -// ToMapBy iterates over a collection and populates result map with elements. -// Functions keySelector and valueSelector are executed for each element of the collection -// to generate key and value for the map. Generated key and value types must be assignable -// to the map's key and value types. -func (q Query) ToMapBy( - result interface{}, +// ToMapBy iterates over a collection and populates the result map with +// elements. Functions keySelector and valueSelector are executed for each +// element of the collection to generate key and value for the map. Generated +// key and value types must be assignable to the map's key and value types. +// ToMapBy doesn't empty the result map before populating it. +func (q Query) ToMapBy(result interface{}, keySelector func(interface{}) interface{}, - valueSelector func(interface{}) interface{}, -) { + valueSelector func(interface{}) interface{}) { res := reflect.ValueOf(result) m := reflect.Indirect(res) next := q.Iterate() @@ -379,16 +581,78 @@ func (q Query) ToMapBy( res.Elem().Set(m) } -// ToSlice iterates over a collection and populates result slice with elements. -// Collection elements must be assignable to the slice's element type. -func (q Query) ToSlice(result interface{}) { - res := reflect.ValueOf(result) - slice := reflect.Indirect(res) - next := q.Iterate() - - for item, ok := next(); ok; item, ok = next() { - slice = reflect.Append(slice, reflect.ValueOf(item)) +// ToMapByT is the typed version of ToMapBy. +// +// - keySelectorFn is of type "func(TSource)TKey" +// - valueSelectorFn is of type "func(TSource)TValue" +// +// NOTE: ToMapBy has better performance than ToMapByT. +func (q Query) ToMapByT(result interface{}, + keySelectorFn interface{}, valueSelectorFn interface{}) { + keySelectorGenericFunc, err := newGenericFunc( + "ToMapByT", "keySelectorFn", keySelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) } - res.Elem().Set(slice) + keySelectorFunc := func(item interface{}) interface{} { + return keySelectorGenericFunc.Call(item) + } + + valueSelectorGenericFunc, err := newGenericFunc( + "ToMapByT", "valueSelectorFn", valueSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + valueSelectorFunc := func(item interface{}) interface{} { + return valueSelectorGenericFunc.Call(item) + } + + q.ToMapBy(result, keySelectorFunc, valueSelectorFunc) +} + +// ToSlice iterates over a collection and saves the results in the slice pointed +// by v. It overwrites the existing slice, starting from index 0. +// +// If the slice pointed by v has sufficient capacity, v will be pointed to a +// resliced slice. If it does not, a new underlying array will be allocated and +// v will point to it. +func (q Query) ToSlice(v interface{}) { + res := reflect.ValueOf(v) + slice := reflect.Indirect(res) + + cap := slice.Cap() + res.Elem().Set(slice.Slice(0, cap)) // make len(slice)==cap(slice) from now on + + next := q.Iterate() + index := 0 + for item, ok := next(); ok; item, ok = next() { + if index >= cap { + slice, cap = grow(slice) + } + slice.Index(index).Set(reflect.ValueOf(item)) + index++ + } + + // reslice the len(res)==cap(res) actual res size + res.Elem().Set(slice.Slice(0, index)) +} + +// grow grows the slice s by doubling its capacity, then it returns the new +// slice (resliced to its full capacity) and the new capacity. +func grow(s reflect.Value) (v reflect.Value, newCap int) { + cap := s.Cap() + if cap == 0 { + cap = 1 + } else { + cap *= 2 + } + newSlice := reflect.MakeSlice(s.Type(), cap, cap) + reflect.Copy(newSlice, s) + return newSlice, cap } diff --git a/vendor/github.com/ahmetb/go-linq/reverse.go b/vendor/github.com/ahmetb/go-linq/reverse.go index eaacb9f..8716c22 100644 --- a/vendor/github.com/ahmetb/go-linq/reverse.go +++ b/vendor/github.com/ahmetb/go-linq/reverse.go @@ -2,9 +2,9 @@ package linq // Reverse inverts the order of the elements in a collection. // -// Unlike OrderBy, this sorting method does not consider the actual values themselves -// in determining the order. Rather, it just returns the elements in the reverse order -// from which they are produced by the underlying source. +// Unlike OrderBy, this sorting method does not consider the actual values +// themselves in determining the order. Rather, it just returns the elements in +// the reverse order from which they are produced by the underlying source. func (q Query) Reverse() Query { return Query{ Iterate: func() Iterator { diff --git a/vendor/github.com/ahmetb/go-linq/select.go b/vendor/github.com/ahmetb/go-linq/select.go index e607229..5dc8cc7 100644 --- a/vendor/github.com/ahmetb/go-linq/select.go +++ b/vendor/github.com/ahmetb/go-linq/select.go @@ -1,17 +1,16 @@ package linq -// Select projects each element of a collection into a new form. -// Returns a query with the result of invoking the transform function -// on each element of original source. +// Select projects each element of a collection into a new form. Returns a query +// with the result of invoking the transform function on each element of +// original source. // -// This projection method requires the transform function, selector, -// to produce one value for each value in the source collection. -// If selector returns a value that is itself a collection, -// it is up to the consumer to traverse the subcollections manually. -// In such a situation, it might be better for your query to return a single -// coalesced collection of values. To achieve this, use the SelectMany method -// instead of Select. Although SelectMany works similarly to Select, -// it differs in that the transform function returns a collection +// This projection method requires the transform function, selector, to produce +// one value for each value in the source collection. If selector returns a +// value that is itself a collection, it is up to the consumer to traverse the +// subcollections manually. In such a situation, it might be better for your +// query to return a single coalesced collection of values. To achieve this, use +// the SelectMany method instead of Select. Although SelectMany works similarly +// to Select, it differs in that the transform function returns a collection // that is then expanded by SelectMany before it is returned. func (q Query) Select(selector func(interface{}) interface{}) Query { return Query{ @@ -31,24 +30,44 @@ func (q Query) Select(selector func(interface{}) interface{}) Query { } } -// SelectIndexed projects each element of a collection into a new form -// by incorporating the element's index. Returns a query with the result -// of invoking the transform function on each element of original source. +// SelectT is the typed version of Select. +// - selectorFn is of type "func(TSource)TResult" +// NOTE: Select has better performance than SelectT. +func (q Query) SelectT(selectorFn interface{}) Query { + + selectGenericFunc, err := newGenericFunc( + "SelectT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(item interface{}) interface{} { + return selectGenericFunc.Call(item) + } + + return q.Select(selectorFunc) +} + +// SelectIndexed projects each element of a collection into a new form by +// incorporating the element's index. Returns a query with the result of +// invoking the transform function on each element of original source. // -// The first argument to selector represents the zero-based index of that element -// in the source collection. This can be useful if the elements are in a known order -// and you want to do something with an element at a particular index, -// for example. It can also be useful if you want to retrieve the index of one -// or more elements. The second argument to selector represents the element to process. +// The first argument to selector represents the zero-based index of that +// element in the source collection. This can be useful if the elements are in a +// known order and you want to do something with an element at a particular +// index, for example. It can also be useful if you want to retrieve the index +// of one or more elements. The second argument to selector represents the +// element to process. // -// This projection method requires the transform function, selector, -// to produce one value for each value in the source collection. -// If selector returns a value that is itself a collection, -// it is up to the consumer to traverse the subcollections manually. -// In such a situation, it might be better for your query to return a single -// coalesced collection of values. To achieve this, use the SelectMany method -// instead of Select. Although SelectMany works similarly to Select, -// it differs in that the transform function returns a collection +// This projection method requires the transform function, selector, to produce +// one value for each value in the source collection. If selector returns a +// value that is itself a collection, it is up to the consumer to traverse the +// subcollections manually. In such a situation, it might be better for your +// query to return a single coalesced collection of values. To achieve this, use +// the SelectMany method instead of Select. Although SelectMany works similarly +// to Select, it differs in that the transform function returns a collection // that is then expanded by SelectMany before it is returned. func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query { return Query{ @@ -69,3 +88,22 @@ func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query }, } } + +// SelectIndexedT is the typed version of SelectIndexed. +// - selectorFn is of type "func(int,TSource)TResult" +// NOTE: SelectIndexed has better performance than SelectIndexedT. +func (q Query) SelectIndexedT(selectorFn interface{}) Query { + selectGenericFunc, err := newGenericFunc( + "SelectIndexedT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(index int, item interface{}) interface{} { + return selectGenericFunc.Call(index, item) + } + + return q.SelectIndexed(selectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/selectmany.go b/vendor/github.com/ahmetb/go-linq/selectmany.go index 25ea8c3..74fa671 100644 --- a/vendor/github.com/ahmetb/go-linq/selectmany.go +++ b/vendor/github.com/ahmetb/go-linq/selectmany.go @@ -32,14 +32,37 @@ func (q Query) SelectMany(selector func(interface{}) Query) Query { } } -// SelectManyIndexed projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection. +// SelectManyT is the typed version of SelectMany. // -// The first argument to selector represents the zero-based index of that element -// in the source collection. This can be useful if the elements are in a known order -// and you want to do something with an element at a particular index, for example. -// It can also be useful if you want to retrieve the index of one or more elements. -// The second argument to selector represents the element to process. +// - selectorFn is of type "func(TSource)Query" +// +// NOTE: SelectMany has better performance than SelectManyT. +func (q Query) SelectManyT(selectorFn interface{}) Query { + + selectManyGenericFunc, err := newGenericFunc( + "SelectManyT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(inner interface{}) Query { + return selectManyGenericFunc.Call(inner).(Query) + } + return q.SelectMany(selectorFunc) + +} + +// SelectManyIndexed projects each element of a collection to a Query, iterates +// and flattens the resulting collection into one collection. +// +// The first argument to selector represents the zero-based index of that +// element in the source collection. This can be useful if the elements are in a +// known order and you want to do something with an element at a particular +// index, for example. It can also be useful if you want to retrieve the index +// of one or more elements. The second argument to selector represents the +// element to process. func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query { return Query{ Iterate: func() Iterator { @@ -72,13 +95,33 @@ func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query { } } +// SelectManyIndexedT is the typed version of SelectManyIndexed. +// +// - selectorFn is of type "func(int,TSource)Query" +// +// NOTE: SelectManyIndexed has better performance than SelectManyIndexedT. +func (q Query) SelectManyIndexedT(selectorFn interface{}) Query { + + selectManyIndexedGenericFunc, err := newGenericFunc( + "SelectManyIndexedT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(index int, inner interface{}) Query { + return selectManyIndexedGenericFunc.Call(index, inner).(Query) + } + + return q.SelectManyIndexed(selectorFunc) +} + // SelectManyBy projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection, and invokes -// a result selector function on each element therein. -func (q Query) SelectManyBy( - selector func(interface{}) Query, - resultSelector func(interface{}, interface{}) interface{}, -) Query { +// flattens the resulting collection into one collection, and invokes a result +// selector function on each element therein. +func (q Query) SelectManyBy(selector func(interface{}) Query, + resultSelector func(interface{}, interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { @@ -103,18 +146,53 @@ func (q Query) SelectManyBy( } } - item = resultSelector(outer, item) + item = resultSelector(item, outer) return } }, } } -// SelectManyByIndexed projects each element of a collection to a Query, iterates and -// flattens the resulting collection into one collection, and invokes -// a result selector function on each element therein. -// The index of each source element is used in the intermediate projected form -// of that element. +// SelectManyByT is the typed version of SelectManyBy. +// +// - selectorFn is of type "func(TSource)Query" +// - resultSelectorFn is of type "func(TSource,TCollection)TResult" +// +// NOTE: SelectManyBy has better performance than SelectManyByT. +func (q Query) SelectManyByT(selectorFn interface{}, + resultSelectorFn interface{}) Query { + + selectorGenericFunc, err := newGenericFunc( + "SelectManyByT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(outer interface{}) Query { + return selectorGenericFunc.Call(outer).(Query) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "SelectManyByT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, item interface{}) interface{} { + return resultSelectorGenericFunc.Call(outer, item) + } + + return q.SelectManyBy(selectorFunc, resultSelectorFunc) +} + +// SelectManyByIndexed projects each element of a collection to a Query, +// iterates and flattens the resulting collection into one collection, and +// invokes a result selector function on each element therein. The index of each +// source element is used in the intermediate projected form of that element. func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query, resultSelector func(interface{}, interface{}) interface{}) Query { @@ -143,9 +221,45 @@ func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query, } } - item = resultSelector(outer, item) + item = resultSelector(item, outer) return } }, } } + +// SelectManyByIndexedT is the typed version of SelectManyByIndexed. +// +// - selectorFn is of type "func(int,TSource)Query" +// - resultSelectorFn is of type "func(TSource,TCollection)TResult" +// +// NOTE: SelectManyByIndexed has better performance than +// SelectManyByIndexedT. +func (q Query) SelectManyByIndexedT(selectorFn interface{}, + resultSelectorFn interface{}) Query { + selectorGenericFunc, err := newGenericFunc( + "SelectManyByIndexedT", "selectorFn", selectorFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))), + ) + if err != nil { + panic(err) + } + + selectorFunc := func(index int, outer interface{}) Query { + return selectorGenericFunc.Call(index, outer).(Query) + } + + resultSelectorGenericFunc, err := newGenericFunc( + "SelectManyByIndexedT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(outer interface{}, item interface{}) interface{} { + return resultSelectorGenericFunc.Call(outer, item) + } + + return q.SelectManyByIndexed(selectorFunc, resultSelectorFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/skip.go b/vendor/github.com/ahmetb/go-linq/skip.go index 1110ae5..0fb05d3 100644 --- a/vendor/github.com/ahmetb/go-linq/skip.go +++ b/vendor/github.com/ahmetb/go-linq/skip.go @@ -1,7 +1,7 @@ package linq -// Skip bypasses a specified number of elements in a collection -// and then returns the remaining elements. +// Skip bypasses a specified number of elements in a collection and then returns +// the remaining elements. func (q Query) Skip(count int) Query { return Query{ Iterate: func() Iterator { @@ -22,13 +22,13 @@ func (q Query) Skip(count int) Query { } } -// SkipWhile bypasses elements in a collection as long as a specified condition is true -// and then returns the remaining elements. +// SkipWhile bypasses elements in a collection as long as a specified condition +// is true and then returns the remaining elements. // -// This method tests each element by using predicate and skips the element -// if the result is true. After the predicate function returns false for an element, -// that element and the remaining elements in source are returned -// and there are no more invocations of predicate. +// This method tests each element by using predicate and skips the element if +// the result is true. After the predicate function returns false for an +// element, that element and the remaining elements in source are returned and +// there are no more invocations of predicate. func (q Query) SkipWhile(predicate func(interface{}) bool) Query { return Query{ Iterate: func() Iterator { @@ -54,14 +54,36 @@ func (q Query) SkipWhile(predicate func(interface{}) bool) Query { } } -// SkipWhileIndexed bypasses elements in a collection as long as a specified condition -// is true and then returns the remaining elements. The element's index is used -// in the logic of the predicate function. +// SkipWhileT is the typed version of SkipWhile. // -// This method tests each element by using predicate and skips the element -// if the result is true. After the predicate function returns false for an element, -// that element and the remaining elements in source are returned -// and there are no more invocations of predicate. +// - predicateFn is of type "func(TSource)bool" +// +// NOTE: SkipWhile has better performance than SkipWhileT. +func (q Query) SkipWhileT(predicateFn interface{}) Query { + + predicateGenericFunc, err := newGenericFunc( + "SkipWhileT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.SkipWhile(predicateFunc) +} + +// SkipWhileIndexed bypasses elements in a collection as long as a specified +// condition is true and then returns the remaining elements. The element's +// index is used in the logic of the predicate function. +// +// This method tests each element by using predicate and skips the element if +// the result is true. After the predicate function returns false for an +// element, that element and the remaining elements in source are returned and +// there are no more invocations of predicate. func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query { return Query{ Iterate: func() Iterator { @@ -89,3 +111,24 @@ func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query { }, } } + +// SkipWhileIndexedT is the typed version of SkipWhileIndexed. +// +// - predicateFn is of type "func(int,TSource)bool" +// +// NOTE: SkipWhileIndexed has better performance than SkipWhileIndexedT. +func (q Query) SkipWhileIndexedT(predicateFn interface{}) Query { + predicateGenericFunc, err := newGenericFunc( + "SkipWhileIndexedT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(index int, item interface{}) bool { + return predicateGenericFunc.Call(index, item).(bool) + } + + return q.SkipWhileIndexed(predicateFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/take.go b/vendor/github.com/ahmetb/go-linq/take.go index d21fc96..c2707e5 100644 --- a/vendor/github.com/ahmetb/go-linq/take.go +++ b/vendor/github.com/ahmetb/go-linq/take.go @@ -1,6 +1,7 @@ package linq -// Take returns a specified number of contiguous elements from the start of a collection. +// Take returns a specified number of contiguous elements from the start of a +// collection. func (q Query) Take(count int) Query { return Query{ Iterate: func() Iterator { @@ -19,8 +20,8 @@ func (q Query) Take(count int) Query { } } -// TakeWhile returns elements from a collection as long as a specified condition is true, -// and then skips the remaining elements. +// TakeWhile returns elements from a collection as long as a specified condition +// is true, and then skips the remaining elements. func (q Query) TakeWhile(predicate func(interface{}) bool) Query { return Query{ Iterate: func() Iterator { @@ -49,10 +50,33 @@ func (q Query) TakeWhile(predicate func(interface{}) bool) Query { } } -// TakeWhileIndexed returns elements from a collection as long as a specified condition -// is true. The element's index is used in the logic of the predicate function. -// The first argument of predicate represents the zero-based index of the element -// within collection. The second argument represents the element to test. +// TakeWhileT is the typed version of TakeWhile. +// +// - predicateFn is of type "func(TSource)bool" +// +// NOTE: TakeWhile has better performance than TakeWhileT. +func (q Query) TakeWhileT(predicateFn interface{}) Query { + + predicateGenericFunc, err := newGenericFunc( + "TakeWhileT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.TakeWhile(predicateFunc) +} + +// TakeWhileIndexed returns elements from a collection as long as a specified +// condition is true. The element's index is used in the logic of the predicate +// function. The first argument of predicate represents the zero-based index of +// the element within collection. The second argument represents the element to +// test. func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query { return Query{ Iterate: func() Iterator { @@ -82,3 +106,24 @@ func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query { }, } } + +// TakeWhileIndexedT is the typed version of TakeWhileIndexed. +// +// - predicateFn is of type "func(int,TSource)bool" +// +// NOTE: TakeWhileIndexed has better performance than TakeWhileIndexedT. +func (q Query) TakeWhileIndexedT(predicateFn interface{}) Query { + whereFunc, err := newGenericFunc( + "TakeWhileIndexedT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(index int, item interface{}) bool { + return whereFunc.Call(index, item).(bool) + } + + return q.TakeWhileIndexed(predicateFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/union.go b/vendor/github.com/ahmetb/go-linq/union.go index 9ca4b65..717b83b 100644 --- a/vendor/github.com/ahmetb/go-linq/union.go +++ b/vendor/github.com/ahmetb/go-linq/union.go @@ -2,10 +2,9 @@ package linq // Union produces the set union of two collections. // -// This method excludes duplicates from the return set. -// This is different behavior to the Concat method, -// which returns all the elements in the input collection -// including duplicates. +// This method excludes duplicates from the return set. This is different +// behavior to the Concat method, which returns all the elements in the input +// collection including duplicates. func (q Query) Union(q2 Query) Query { return Query{ Iterate: func() Iterator { diff --git a/vendor/github.com/ahmetb/go-linq/where.go b/vendor/github.com/ahmetb/go-linq/where.go index 26d0bda..6fd4302 100644 --- a/vendor/github.com/ahmetb/go-linq/where.go +++ b/vendor/github.com/ahmetb/go-linq/where.go @@ -19,11 +19,33 @@ func (q Query) Where(predicate func(interface{}) bool) Query { } } -// WhereIndexed filters a collection of values based on a predicate. -// Each element's index is used in the logic of the predicate function. +// WhereT is the typed version of Where. // -// The first argument represents the zero-based index of the element within collection. -// The second argument of predicate represents the element to test. +// - predicateFn is of type "func(TSource)bool" +// +// NOTE: Where has better performance than WhereT. +func (q Query) WhereT(predicateFn interface{}) Query { + + predicateGenericFunc, err := newGenericFunc( + "WhereT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(item interface{}) bool { + return predicateGenericFunc.Call(item).(bool) + } + + return q.Where(predicateFunc) +} + +// WhereIndexed filters a collection of values based on a predicate. Each +// element's index is used in the logic of the predicate function. +// +// The first argument represents the zero-based index of the element within +// collection. The second argument of predicate represents the element to test. func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query { return Query{ Iterate: func() Iterator { @@ -44,3 +66,24 @@ func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query { }, } } + +// WhereIndexedT is the typed version of WhereIndexed. +// +// - predicateFn is of type "func(int,TSource)bool" +// +// NOTE: WhereIndexed has better performance than WhereIndexedT. +func (q Query) WhereIndexedT(predicateFn interface{}) Query { + predicateGenericFunc, err := newGenericFunc( + "WhereIndexedT", "predicateFn", predicateFn, + simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))), + ) + if err != nil { + panic(err) + } + + predicateFunc := func(index int, item interface{}) bool { + return predicateGenericFunc.Call(index, item).(bool) + } + + return q.WhereIndexed(predicateFunc) +} diff --git a/vendor/github.com/ahmetb/go-linq/zip.go b/vendor/github.com/ahmetb/go-linq/zip.go index 1314b9a..da3dcd3 100644 --- a/vendor/github.com/ahmetb/go-linq/zip.go +++ b/vendor/github.com/ahmetb/go-linq/zip.go @@ -1,19 +1,17 @@ package linq -// Zip applies a specified function to the corresponding elements -// of two collections, producing a collection of the results. +// Zip applies a specified function to the corresponding elements of two +// collections, producing a collection of the results. // // The method steps through the two input collections, applying function -// resultSelector to corresponding elements of the two collections. -// The method returns a collection of the values that are returned by resultSelector. -// If the input collections do not have the same number of elements, -// the method combines elements until it reaches the end of one of the collections. -// For example, if one collection has three elements and the other one has four, -// the result collection has only three elements. -func (q Query) Zip( - q2 Query, - resultSelector func(interface{}, interface{}) interface{}, -) Query { +// resultSelector to corresponding elements of the two collections. The method +// returns a collection of the values that are returned by resultSelector. If +// the input collections do not have the same number of elements, the method +// combines elements until it reaches the end of one of the collections. For +// example, if one collection has three elements and the other one has four, the +// result collection has only three elements. +func (q Query) Zip(q2 Query, + resultSelector func(interface{}, interface{}) interface{}) Query { return Query{ Iterate: func() Iterator { @@ -33,3 +31,25 @@ func (q Query) Zip( }, } } + +// ZipT is the typed version of Zip. +// +// - resultSelectorFn is of type "func(TFirst,TSecond)TResult" +// +// NOTE: Zip has better performance than ZipT. +func (q Query) ZipT(q2 Query, + resultSelectorFn interface{}) Query { + resultSelectorGenericFunc, err := newGenericFunc( + "ZipT", "resultSelectorFn", resultSelectorFn, + simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))), + ) + if err != nil { + panic(err) + } + + resultSelectorFunc := func(item1 interface{}, item2 interface{}) interface{} { + return resultSelectorGenericFunc.Call(item1, item2) + } + + return q.Zip(q2, resultSelectorFunc) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 103f816..b03cabb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/ahmetb/go-linq v2.0.0-rc0+incompatible +# github.com/ahmetb/go-linq v3.0.0+incompatible github.com/ahmetb/go-linq # github.com/go-ini/ini v1.57.0 github.com/go-ini/ini @@ -8,3 +8,5 @@ github.com/json-iterator/go github.com/modern-go/concurrent # github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 github.com/modern-go/reflect2 +# gopkg.in/yaml.v2 v2.4.0 +gopkg.in/yaml.v2