pax_global_header00006660000000000000000000000064137545222210014515gustar00rootroot0000000000000052 comment=dbce9c84f96d6f60f286f4ba59b9b311182bc421 golang-github-thedevsaddam-gojsonq-2.5.2/000077500000000000000000000000001375452222100203575ustar00rootroot00000000000000golang-github-thedevsaddam-gojsonq-2.5.2/.gitignore000066400000000000000000000000321375452222100223420ustar00rootroot00000000000000data.json .idea .DS_Store golang-github-thedevsaddam-gojsonq-2.5.2/.travis.yml000066400000000000000000000007561375452222100225000ustar00rootroot00000000000000language: go sudo: false matrix: include: - go: 1.6 - go: 1.7 - go: 1.8 - go: 1.9 - go: 1.10.x - go: 1.11.x - go: 1.12.x - go: 1.13.x - go: tip allow_failures: - go: tip before_install: - go get github.com/mattn/goveralls script: - $GOPATH/bin/goveralls -service=travis-ci - go get -t -v ./... - diff -u <(echo -n) <(gofmt -d .) - go vet $(go list ./... | grep -v /vendor/) - go test -v -race ./... - go test --bench . --benchmem=true golang-github-thedevsaddam-gojsonq-2.5.2/CONTRIBUTING.md000066400000000000000000000011631375452222100226110ustar00rootroot00000000000000# Contributing ## Must follow the guide for issues - Use the search tool before opening a new issue. - Please provide source code and stack trace if you found a bug. - Please review the existing issues and then provide feedback ## Pull Request Process - Before sending PR, create issue and discuss about the changes - You MUST send pull requests against `dev` branch - It should pass all tests in the available continuous integrations systems such as TravisCI. - You should add/modify tests to cover your proposed code changes. - If your pull request contains a new feature, please document it on the README. golang-github-thedevsaddam-gojsonq-2.5.2/LICENSE.md000066400000000000000000000021561375452222100217670ustar00rootroot00000000000000# The MIT License (MIT) Copyright (c) 2018 Saddam H > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal > in the Software without restriction, including without limitation the rights > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > copies of the Software, and to permit persons to whom the Software is > furnished to do so, subject to the following conditions: > > The above copyright notice and this permission notice shall be included in > all copies or substantial portions of the Software. > > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > THE SOFTWARE. golang-github-thedevsaddam-gojsonq-2.5.2/Makefile000066400000000000000000000025271375452222100220250ustar00rootroot00000000000000# Makefile includes some useful commands to build or format incentives # More commands could be added # Variables PROJECT = gojsonq REPO_ROOT = github.com/thedevsaddam ROOT = ${REPO_ROOT}/${PROJECT} fmt: goimports -w . gofmt -s -w . compile: fmt go install . check: fmt golangci-lint run --deadline 10m ./... staticcheck -checks="all,-S1*" ./... dep: go mod download go mod vendor go mod tidy # A user can invoke tests in different ways: # - make test runs all tests; # - make test TEST_TIMEOUT=10 runs all tests with a timeout of 10 seconds; # - make test TEST_PKG=./model/... only runs tests for the model package; # - make test TEST_ARGS="-v -short" runs tests with the specified arguments; # - make test-race runs tests with race detector enabled. TEST_TIMEOUT = 60 TEST_PKGS ?= ./... TEST_TARGETS := test-short test-verbose test-race test-cover .PHONY: $(TEST_TARGETS) test test-short: TEST_ARGS=-short test-verbose: TEST_ARGS=-v test-race: TEST_ARGS=-race test-cover: TEST_ARGS=-cover $(TEST_TARGETS): test test: compile go test -timeout $(TEST_TIMEOUT)s $(TEST_ARGS) $(TEST_PKGS) clean: @go clean .PHONY: help help: @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | \ awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | \ sort | \ egrep -v -e '^[^[:alnum:]]' -e '^$@$$'golang-github-thedevsaddam-gojsonq-2.5.2/README.md000066400000000000000000000114761375452222100216470ustar00rootroot00000000000000![gojsonq-logo](gojsonq.png) [![Build Status](https://travis-ci.org/thedevsaddam/gojsonq.svg?branch=master)](https://travis-ci.org/thedevsaddam/gojsonq) [![Project status](https://img.shields.io/badge/version-v2-green.svg)](https://github.com/thedevsaddam/gojsonq/releases) [![Go Report Card](https://goreportcard.com/badge/github.com/thedevsaddam/gojsonq)](https://goreportcard.com/report/github.com/thedevsaddam/gojsonq) [![Coverage Status](https://coveralls.io/repos/github/thedevsaddam/gojsonq/badge.svg?branch=master)](https://coveralls.io/github/thedevsaddam/gojsonq) [![GoDoc](https://godoc.org/github.com/thedevsaddam/gojsonq?status.svg)](https://pkg.go.dev/github.com/thedevsaddam/gojsonq/v2) [![License](https://img.shields.io/dub/l/vibe-d.svg)](LICENSE.md) A simple Go package to Query over JSON Data. It provides [simple](https://github.com/thedevsaddam/gojsonq/wiki/Queries#jsonstringjson), [elegant](https://github.com/thedevsaddam/gojsonq/wiki/Queries#selectproperties) and [fast](https://github.com/thedevsaddam/gojsonq/wiki/Benchmark) [ODM](https://github.com/thedevsaddam/gojsonq/wiki/Queries#frompath) like API to access, query JSON document ### Installation Install the package using ```go $ go get github.com/thedevsaddam/gojsonq/v2 ``` ### Usage To use the package import it in your `*.go` code ```go import "github.com/thedevsaddam/gojsonq/v2" ``` Let's see a quick example: [See in playground](https://play.golang.org/p/UiqyllP2vkn) ```go package main import gojsonq "github.com/thedevsaddam/gojsonq/v2" func main() { const json = `{"name":{"first":"Tom","last":"Hanks"},"age":61}` name := gojsonq.New().FromString(json).Find("name.first") println(name.(string)) // Tom } ``` Another example: [See in playground](https://play.golang.org/p/QLVxpi6nVbi) ```go package main import ( "fmt" gojsonq "github.com/thedevsaddam/gojsonq/v2" ) func main() { const json = `{"city":"dhaka","type":"weekly","temperatures":[30,39.9,35.4,33.5,31.6,33.2,30.7]}` avg := gojsonq.New().FromString(json).From("temperatures").Avg() fmt.Printf("Average temperature: %.2f", avg) // 33.471428571428575 } ``` You can query your document using the various query methods such as **[Find](https://github.com/thedevsaddam/gojsonq/wiki/Queries#findpath)**, **[First](https://github.com/thedevsaddam/gojsonq/wiki/Queries#first)**, **[Nth](https://github.com/thedevsaddam/gojsonq/wiki/Queries#nthindex)**, **[Pluck](https://github.com/thedevsaddam/gojsonq/wiki/Queries#pluckproperty)**, **[Where](https://github.com/thedevsaddam/gojsonq/wiki/Queries#wherekey-op-val)**, **[OrWhere](https://github.com/thedevsaddam/gojsonq/wiki/Queries#orwherekey-op-val)**, **[WhereIn](https://github.com/thedevsaddam/gojsonq/wiki/Queries#whereinkey-val)**, **[WhereStartsWith](https://github.com/thedevsaddam/gojsonq/wiki/Queries#wherestartswithkey-val)**, **[WhereEndsWith](https://github.com/thedevsaddam/gojsonq/wiki/Queries#whereendswithkey-val)**, **[WhereContains](https://github.com/thedevsaddam/gojsonq/wiki/Queries#wherecontainskey-val)**, **[Sort](https://github.com/thedevsaddam/gojsonq/wiki/Queries#sortorder)**, **[GroupBy](https://github.com/thedevsaddam/gojsonq/wiki/Queries#groupbyproperty)**, **[SortBy](https://github.com/thedevsaddam/gojsonq/wiki/Queries#sortbyproperty-order)** and so on. Also you can aggregate data after query using **[Avg](https://github.com/thedevsaddam/gojsonq/wiki/Queries#avgproperty)**, **[Count](https://github.com/thedevsaddam/gojsonq/wiki/Queries#count)**, **[Max](https://github.com/thedevsaddam/gojsonq/wiki/Queries#maxproperty)**, **[Min](https://github.com/thedevsaddam/gojsonq/wiki/Queries#minproperty)**, **[Sum](https://github.com/thedevsaddam/gojsonq/wiki/Queries#sumproperty)** etc. ## Find more query API in [Wiki page](https://github.com/thedevsaddam/gojsonq/wiki/Queries) ## Bugs and Issues If you encounter any bugs or issues, feel free to [open an issue at github](https://github.com/thedevsaddam/gojsonq/issues). Also, you can shoot me an email to for hugs or bugs. ## Credit Special thanks to [Nahid Bin Azhar](https://github.com/nahid) for the inspiration and guidance for the package. Thanks to [Ahmed Shamim Hasan Shaon](https://github.com/me-shaon) for his support from the very beginning. ## Contributors * [Lenin Hasda](https://github.com/leninhasda) * [Sadlil Rhythom](https://github.com/sadlil) * [See contributors list here](https://github.com/thedevsaddam/gojsonq/graphs/contributors) ## Contribution If you are interested to make the package better please send pull requests or create an issue so that others can fix. [Read the contribution guide here](CONTRIBUTING.md) ## Special Thanks ## License The **gojsonq** is an open-source software licensed under the [MIT License](LICENSE.md). golang-github-thedevsaddam-gojsonq-2.5.2/decoder.go000066400000000000000000000006161375452222100223160ustar00rootroot00000000000000package gojsonq import "encoding/json" // Decoder provide contract to decode JSON using custom decoder type Decoder interface { Decode(data []byte, v interface{}) error } // DefaultDecoder use json.Unmarshal to decode JSON type DefaultDecoder struct{} // Decode decodes using json.Unmarshal func (u *DefaultDecoder) Decode(data []byte, v interface{}) error { return json.Unmarshal(data, v) } golang-github-thedevsaddam-gojsonq-2.5.2/decoder_test.go000066400000000000000000000006671375452222100233630ustar00rootroot00000000000000package gojsonq import ( "testing" ) func Test_DefaultDecoder(t *testing.T) { dd := DefaultDecoder{} var user = struct { Name string `json:"name"` Age int `json:"age"` }{} if err := dd.Decode([]byte(`{"name": "tom", "age": 27}`), &user); err != nil { t.Errorf("failed to decode using default decoder: %v", err) } if user.Name != "tom" || user.Age != 27 { t.Error("failed to decode properly by default decoder") } } golang-github-thedevsaddam-gojsonq-2.5.2/doc.go000066400000000000000000000011271375452222100214540ustar00rootroot00000000000000// Package gojsonq provides a simple, elegant and fast ODM like API to access/query JSON document. // // JSON document can be read from file, string or io.Reader. // Accessing the value of json property or querying document is simple as the example below: // // package main // // import "github.com/thedevsaddam/gojsonq" // // const json = `{"name":{"first":"Tom","last":"Hanks"},"age":61}` // // func main() { // name := gojsonq.New().FromString(json).Find("name.first") // println(name.(string)) // Tom // } // // For more details, see the documentation and examples. // package gojsonq golang-github-thedevsaddam-gojsonq-2.5.2/go.mod000066400000000000000000000000631375452222100214640ustar00rootroot00000000000000module github.com/thedevsaddam/gojsonq/v2 go 1.13 golang-github-thedevsaddam-gojsonq-2.5.2/gojsonq.png000066400000000000000000000651121375452222100225520ustar00rootroot00000000000000PNG  IHDR8Vr IiCCPICC ProfileHWXS[RIhH RK E*I ĐD.*vuEWE] k^Z(bʛX{;|s30tjxRi. @@š"uQ#0Rv\\42tm\uQrs@(A! >^— @O@XYj\j\I@ 2Ǔe B~ѾD C8/ xT^ %v!+qf sxYX]Jȡb47l\P ;8h"Ydfط[93q$#&b}ߋ*{QHGMr`B*FAl q$7&Zs!+-p5 glF|ΔqLWiJ CoE)1j89bm( fS, m J"BشLYx^'[,sc4@7Y(a' 哢jCԵcBI^SZ}%͍TanRo0Acqx X@GRτ, .͐GjF ȇBTBP TN =[Kl1;c&Ža%GU4-^O#OSIkk'\H~Y2qņo~!+rwu@Q^3Uy/]q|ˠ2/C`Kg >+8W :\y!|9wA0A,H`g 怅`-@8 N3"hzsނAHa ƈb8#!H<#YQ srdRlF_C <ҁF =+#45C1FDt*h Dk]h#z^G;h?0-Yb.b4,a2ub3pWp$||w)*ÿS3%L"dfJ mi&%L=>llRqbO"IΤR,G* ֓vIZd ;9F+;GWO]-ŏKPfQSRZ()ݔ՞@MfSR+ ԻZZZVZZZ *jzOsqhSh 2vqmk:nG u \m|jF+/t(::li:::u.Rtt9 f###hqe;FFB2=F׍>ÌsW73ML&4hrڤwHe#5u27miYlI^syy= @ cX,6+U:4TXnlJZd5:zuu966Rl}lElھK=׾ؾ!!ߡ#1qc$rv:{978w"%U; ͅRR`4stEFc3&m1g|qtuzMm"WN|jktp/:8'sd^ ^=657} ||%=˯oߟ.9;'u\WU/`s@g +0= ^Pm``A'lGv6{Ek,`;g.x(ZVv?*<+>/3bvHBdTț\3.[=~SQNѲ VOc#iձ~H7zx9g v&M I\x'!IԚ<%.]JhʪIc&͝t1$UڜFJKNۖ?9lSYlO7 %{Ń3g/+]4kɬ'?ggαp΃칛!2η_2{AĂ suѪEoKĬdAIחjJoæb%K/R&(PZ^Qi)~qpY沶^7 2hUzWuq kMٚ7k=_1b::ź6WT%^RƴfIͻ W6old|ǟ?֮b qK[m&ʷ}.޹#~ǩ:ﺺ;ף]SvҰysO^W/uj25"DMͩjmo9_<\}ԣ%G?.={"DW;''vj⩶Qϝ ?s,s;υ^/y^:oۼ/{_nnmoqJЕWCƽvzI7nݜr۹_^w wޫoz_yAKw=$1q'uOݟ i6Ys?y^RrƯ?ۼُ) DTs˗/w<O@33xz*;@>QMU'> $- Q6a 1 ޕ[`zx 3=\4x!|mϲ dop<_}T  ~Rs~^ }~ pHYs%%IR$iTXtXML:com.adobe.xmp 1080 194 ] iDOTa(aa,i-[R,5IDATxi\יo(nDmyȻwy2l03 8x'? Ȃ x2 2ȫIe[7IDI}vVTfWw{9`rss̤ H@$  H@$`U$  H@$  H$@$  H@$  H8߅6@$  H@$ ǀ$  H@$  H@'.$  H@$  (p8$  H@$  H@h<w $  H@$  H@1  H@$  H@@ (p4 m$  H@$  H@  H@$  H@O@]h$  H@$  H@Pp H@$  H@$x B  H@$  H@c@$  H@$ Ph| H@$  H@8$  H@$  4GH@$  H@$$  H@$  H8߅6@$  H@$ ǀ$  H@$  H@'.$  H@$  (p8$  H@$  H@h<w $  H@$  H@1  H@$  H@@ (p4 m$  H@$  H@  H@$  H@O@]h$  H@$  H@Pp H@$  H@$x B  /ϟ)޾Sdjf]$  H@$n _[' ,s3t|obEq /,w)91S\S|hsX5U)9W'^,9ŵ_=8hn{y8<-,#CI?n!z.5 H`^"<<Qpb197 HtGgc)E|CVuM186gϟ;_>&|CDx*3|wuߔ1V6ekbe1ڲ? FLRS,\y^[00[A6/-y?=^bߝK ˿y:zﳵJc,[ɿuƦs'TE爘<є}WrL5m W>K˲^x qED؍yk !c1s.c7;x~nW^{e\3{:׼g$4 M1+ Eqdn )NűXrgxjm1 6 3E1Jk 7bhN9|*" Z(qc'Kᦔzb10G>ǰبc-_mX/vh?Xw0Jg_1r~to9?~k .8E^p(;i [r-ٹY<вx,"jM{:N>CBZj \_9\߇|ֻf3+H cͰOo.k^OS1xtwpmaY$  q " M:8Ax$@0` h63d +$  @c}NMq:x,\p]>r wDw [: G:6sߔߚ!o V5W;(4T*ۼyDzRx[GWW ErPXNڞK[<GN̄3LY)npCɍfg$0-7Ce,ģ)Zh}$jE}8v^|_TwO $iQc[K85S.XxWb Ǭ7'8U|gKW^Mo I+`)<@!v 3Έ;c}>(@~G'핀FI@ct=$0r&nYKWك6u}'At+vs#ܐVMLxTɥW׹)F5<sY^%@ x0nA4X"c#<,J@c$yIf>=Sqzgƛ6$r-/ϗ|8')n2ʿ{g}q0PN$z|sELk=:efDb'ۢ[o<@nY Ժ7N܊>=Wtz2_?9_qoL>Om1Щ۟!wįBX*eݼFA+#BhvD`'}4^g㕬#z) H`e dLR###>č?S7/f8B\%`I>B*A)ē6``e2 D@2 ;_~e3<-<{lǬ=6(Yc$ǁ$8܀LausCl(qO\7k$0x}|2@aʟÁdu!d1}DA˾*فwˮ;}-P>h荙؛VVA<4z;Nb__xkc70Xƈ =S޹XS_?_~cySeԝAPԓp) !Ųrbì.mk?Cᝳg3K@uPਓǒFB8l h luЧrz"[<9,$2.WCgf.X!l!K`To])n3WHWB๑1%@w"xGhW]1sӦX- H`8 % #2`tEn,5#<$ |G|aO_W#fwT*w,3yni7ΖU)nH$> S[$V`5kɒKOZѭ6Bh)<@ĸ5@oN6jRED,cd}OR߾}$. O[#x s#e{\Tr~H" H@db -.ٹ,E?c H=8ӗD"@ 6e3Q v8k!4Z}H@1"H@!ў%h]7Z! H@D7L3)cM@g%0vj5ِ%K[?Mׇq6AC-$  H`ۛʔP  ,M H`Ͳy,K@$0:L pnjDY9#@CIz$ FKSzdJ@$Rf,l*y% (p /K@!p*RX=u8 H@$${ʿ^c%sK. u8%%WW'Jg X$  H@JamG\}%PHz H`Nڸ+YSHK}gf -@(0S̒q.;gG 6:}h$  H@m%@zXgmc5y8&mYSNGȿ\;L3Exbr |X$  H@r,*^g\( (pǖ8o)ްSfKFbpDHXxgfdãO$  H@XNm:ŔNˉsI`d8FK`2 3Ŏ̆5S3xIc2$  15SE,Sm wU8F 8 n6_VD摢xtZc~# H@ؖ/*dkM@g%0v`Ie<3šƮVH$  ߹ʥ* 4G{K` M,A&Ȗgcg#xF-&@6mS{YD/xD*1vl@/3icɢKrjed2.>@} K^7V;;M*5A@cUJ(bF %X( F*B-C ŶUEqN)nl{K;MTFpl1$g,=LO$Ne vޘŃjbKyr"A?R5ăQ]bϚNr:C 2qYTYYߌ˧꺮bl?rRzGs31bokҺ os]ymB}`w(FA ymQ||+b`BNJQ['LWVR`ßwyl7%p" 4GsΚK`h/ŋfȟ̝== n->3 R4{:k~|( FWu? {0) pH]`@::,!oX$Eu`İf b/d቙{o[#8|fTG!s{+*x|=|/Mݥ\rXt}.#3׮GEh.5`3x<3 ӳ"7 G#1"wW<ޠc#$/q], [e?cRh/I)İM&H) ngķG|RJUxu+,Ψ?L7gIB ƪ(8Uq۔kɰd D##fq$7F@%&xl^/}dEC yFd|d 3̚#3Nc1ߎq"džx' l'5kn@G|CNg)e.k+&Fn8Ļ tuxyIV? 'H stRXT#|al`H4%:H9e^jKK%8>۝_)nWu)D)AgOgp=m+pC>n̜' r3Wo8gf>@ǀ 31c)<Co2m;V>yq.K\Ag}.uf|Rp=|,k-!V\'b  xY8ƻN2(xo" GI`0&1r989ȽqfLdcH`4< JY fcC`̺ Pb5+`,^sQ1l?ӏV1dsԃ'uBϹ 1.R<9zb\޵M8od ^hD^Ŏ1Id{n wSŽ7WvDoe\.v |ua^ۭ-p4w]=N{ALm:[" @@q  vij1P˒"r `!AFjA n13~}D꾽scn2o&(䆢vxx|?/3 wI!p:3<\ǸzqlYHĽjU>G@x[q1cr$/"Gic8 \݈ H=8ӗD+Fe̒LtR2I܍yy+5C3Yr¬8.뙃ʍcF0[71~1-%0\|U"S g)ҽ H xTe㞈nx2L<9a{вqr а.O`O\L <>%*Bb ̘Z\7<,/āA [ґc?'0."ա; % 3^76LKh*a pMDGc2zVN Ii)E`!% tg#fBǠkYwuсu !ò- χ8orOo*8gS n]6U灸18*_70hAꍐwq)u M= ;;: ۶rR(pLJON ,7fŁ,=ɒRv{p'0-1$]L#ޚڔ,}b)b1n ;3cX,S/x_<`|Y6I!w3.YRW!{a{a\#B̡Aʠ,HރL6o'@ (p4FDx鹑{<'r<29mTft_Nǃ{]F$ǐ=+kb3oR+p,g?ɲY`p0ҷF! o"~.P$M688ڙzic-%p4R"GH@!ў%ܯ;Nd-ʳgb7viV.'Ç&ug6y}|z-Z (<"m >OjA?86VxIp̗AdD;w-`i`+RTKaw&&ƮxY$ PhO_ , 'blY7.K^z! g*u|J8Xm9#w,?`VZڛˀF# tXg8a"d1 #*R߈@w*1}NG@25ԭk%5lQ {u%UϬ%b% G[!Shʌb/sdRzM6Ń/r 7&I{6"x.3=LR0W#ѣW<KY!h#Z"8agb]^RS&p֌17cƾnG0oXH&Mo 6u|m^qD@eo3KM1Hm$rmlm$P^KdČcqg[>rcᙞ1,ĂmqÛ.p\$6!;(xs=tcXd !I!v O&8 ,C/d@O:X]jXqaXxh]$ (p oK`*=.p?ϲ2_m2 !Atn4Yؖ.,~7/,BKciVO~7OJR2wtVe3DЇ^RO&.m8X:w9^v)ic8Vzzq#@bWqK@c_cLb:BK#fpS<˗sq3ʸy{L:dhAv6u_͒ zT , (˳z?LKlǎ;Ŗ9"p<<XFB[#uuQ*{R^UYJGP 㓱!7HQL#p|IcܶN  tn2CpK|v)aƞ)d9/[&@SɭS5}Ŀdʌx/,ac[7/[jpz:7&g2dCM kY҃3Wݣaw1u%J[fJ/:v~F^2X-T8"FY%*Ws4Wm$^MZ/c˹9YChqE<6704cC8@DY$~U'rs| ָnAL2v)ђŋƅ*"D,-!J4K,1񼘲3->I+XB;3 fUKm P/ObFK7Ǔͱ\׈6 K.aA*p,WBTM )vPhw: 0Ĩ륀%hlRXᦙY[$#DsT7ju̪sܹocF=7 YRAi`UpZr$jӉAl<;/R@? .p ,!0}u+d?\'EXOƒ U'I"GDkW'S_xl VaM*I!1)=m;% Z$P1gŠ1sqoE/v#pd2v^7Gx<ʖTrBEfK|2"5,@; f)/IDATY$y߫/8E.EmڲZɋF!H $/~[H ؁ CeKnBmD6!g8g2knMݷ޹azs~nw}tB$0 KE^,8wpk!pۦ螹 | kyk)~g3;rQ|5׺{NNV_=wurr{NvO?7ݹךd{X83SGũ,zo(v^W7oRuEK=rBtQ+K/u޳nmJ=v|껣߰(~c\'|8|xn[RjDZrrSi=p+Wݯ\_l>wo^юlj;ߞwxXC @G] nm%3q-^D^y.pྔo}80!MG>X7m;-t[>-~p[<^S_h}:K8;;{"WE;OEਗ਼GM%%?}\Ox"tLC& 4Gs֚I`AC:N?.vEU[E:' m]~H Uc>0(;L,7Gu]w73nDy 8m)Nǁ%K"t"ʩj U7{wt7o`VMh7vo!A5_JFrQAx!>8+6uQ^o>oC* *+ׇ /5!*W^y;hN0r0Qa#~!|H 0C0"vu{E ;yQ\o*~R6go{~1B;2EK@mo[JPB38S?8uB5 "0K^zx} I^(pQZ-GY.zTwgX-ӫ/x 3"9A Icm8rszx]֍h%D8=%=u| y%V dɵAC{&dzgdMRtV^Oƽs  0j82AT+HZOvYPr겭"m UBĊLrp/AP W[C߿~i [ɊJ8ܸVML2zg\ƨ>/GC(poaBB[' 9zWsÏ8!p̪BLfBY*pL?TޔY#A1܋'2*F I~DPD@^[' HJ@Ju  (^W4lfIN eZ3 (poW<&B "$C>6Uj}6 8ocLQsn WCQE@w$0sQ>&~>$Zs(poK<&bӻҫJ4G}Fžu[|ſE,p|ic$n%fG||ߕCHOƱ{Os w򉽙)& G{ښJ`̂@xVO72V9*7E? e:~L!^k|n5m#0$" -jl*CǧL({:ϚO`q*ey^Oƽsž Ws-ķ]wnzc0 8F+&;Q8mQC\= ͙5o%!] :" wy,~! ;NG.*98hQv@xCMe1zy~GvĄ:׏py* ~(lRc^7'#n;$. jok+|[靭5I$1H[6H\(ja<֓OUi VY.oי.` qgk&_F`(xW(."f(  w#WD3+ۚ f}a^e%86Jؙ&2~wشM*p&ޟ Y%sqYEЬZ[ H@{@ ?Ӓeл!pKt٘ :8̴QIzE4N$DT7]H=CzN^"8uP) #p,d$?ŁGG!|RFfe#Փ_2䧋 15e\'W?#\1H\w[.k/4mll 7I]!̿uh/5@B(hTQ<gF@:=ׄs?Y6䂠n@ਊ 8$]1l}a%bg 7af^ufC++dG xpB媞N 3Q0[/ )w#18=D\,"2LXAfaw&ôZ/e zr \gicTX-I>˴ǚ#5oŎs H 8ЊAY3nLD/%}8ͪ~KU"@;#n|4=U$?L6^0}4FB}Dx{CzyuGՃDV˧A~ {6# $xCDՈ' C3b{3)uq6jfhG$8prp1-чa;EED !2DiZ:Shw[@PcCZ3&8V o&=|$&& GK'j<EȺL{"ȳqVX\>s0 tpp&01̂FG~#$ hKp|z~^伣fx^8F >rac$Xع[fX2T{YmA]j0d*ZtQoI=6yDC1CwpƔ_Pqm-a]*9x#""8WBH;p1~& 4GsҚH`fN.K.5y?idg{՟g<DFԂ8zb$LP2a|$IszNIKQgI4S'pk$yp}ń_JGY0_;1nnDG._], "csԕNP5I#lIs./#ˈXup Rq`I2*e%:Qf)'])mR }2y\[ !vf(\MD lEqF 138ٚ$N lwk- 0hzQጰW0}.q{<åxi>2ziXO63t qlkO}Vr\9sJ @L qf]0dx6ux`*>30貿Cqǁq_^A$ 939d.gT ,x -X>qE3 yÖ"rUܴ$, kb uQs">(% 3cȍ7_yqqJ|1 >_qx/~Z.5@{ (pFxBY.x%ᤕ p.^ 좭Q^aPs Lڽϰ L{ 98YE5AoC'$Q;=bǨ!%0oK4H=g/Bƒ$ZaX@=9׋q)ÑF a>6M(ϰMDDMX `0, t(^|-ƫס;RR^ږhy;__+; Pp 8'Q6Gz&G]lO[&eymDya@C`&&X)崱Rq5x#!pDTzܖ-s!pҐK@mo%9x =sqpX M88Q C4ټt2%`ɓ4.=|g &#?1t$i ahuʈ{u!qa50M?2(f80wC#( vȔ\g6$12lRQV)E{R_l(o/+eݞBrʋC4CDKxsDD 3'8edb.ʛ%e^0A,!K>[)#ю jK8o"Dz|$3 k@{ (pX?C3KpҍJa4,Cp88-{#'d|_26qƗQ'ʈJRץ8KPa1qM ,sx^W7JqnRG=! m7$'(Gz.C9)/e5Ny9h fƸ?0]yB `r}㖗D̜7IJ `Dɻ#gY9W7mD D,7ZFo3Mh/5<8GB=ؠǗkhkQx1*a)w3\}pg_!8ǖ^|]NbD 0Iɾe&!`bBa&#1H'd$3S({wv`čXi7mlDI697&oʽ7!;Mh/5<hN͓<C[S^!߈` >֞0)"SByXi\),)cpC3k#J>m,b6I]'egXfɛ1ߟrM76L%b?([$^ m{k.p8&jQ C? T{`nks 8gU_׍\I?[ȣB3FGfZ:ÓcpkvL4e%C_pf)s)0 rϰf5z )BeymI})/b茈;!4J`PH a(`;C8";}Zެ1a5`X IG)/Ôen1:<ߥI_dk73ODs~63\{kL=l61/ĻL~cy>FCryo we@M$ vPhw[{ \Ay?y<P{=g=/_::y H7/:Su=V5".CUppj%k->2Dm)W|hP-WYtr ~WN&5&l{6D n%ܛ41C|`ˋ{Us0e{33kU#Z뇉X`#"gu%P@lfNJ}& H H<[MF9Rma& })o3$  r>a9i|_PMd5)Wh07UJ Dh9CJZV#`13[Tdd:n$$0<2,@K (p᭶CYH`GY9畀$ 0-Iʐ U_L4 CAiPw% ) 0K}RcJ. H``dgfsJ Dqn8ә.65 H@@IM2v\qczό*kk˸3CLnI{I3EaRD#8($ i(pLCc%X"4$SÌ.{xyO}(~*g /X{m%  ,/;7'c\/x_ȡҎQcgԌhSK* 4GZH`xD`:?^=~Nohʧv #8G"h$ *]_"8޽S_3I6iђ/=nH*:KWM0sɹO$-l1 ;ܖF At>W$  %$$HۡJ<|do0)N&̿Ѥ&.fF)o}wzәzTkG!7g6 TlMԳ*8qnDh+N23(mHX^cԞYx8^@ЁsS1\s 8y oa:dr9><_&'p=p!a_#jbwMPTՙ&b0޷S| |Yƺm7$-!geSX*aJ@-o%(:҈ <4nqY_׳~.nqnTJ5 H@)>OG` K!,v''ŗu/-v=~Hɴ;#\ȲG(pwDA4#Ss-MN@c`y831+bRؐh GS"$ i(pLCc% 0̄ j@HOWB&1τfBG$0m B0|~l]Bׄ߿S|(y:ưIď y]/ fh$pu (p\]^]%@~{3^2=_U(+MI̖D_aD Wp H@ {" DZJA(i%& H@o#K(F c=4֍W $)% 'xWLf!Fvf̴& H@&@4bEoA. qoxʰߔv&nZ!\q,yݒRI3/O$  HE^dI0T\ߘ7 4zƈߏfP$ HA8hN+! ?ymDȳ'jd2L b"|6lcZu H@!њh6GOThv+[; Hi`((,g{k"Vl` dI@P7% F֚J@kIEaؓH s-y G|19.D^PAxY %A(#4<$  H`b # H`5`6Dz52I@Xmƨ7["B @ Hb Gʿ˖ )-59% q& H@PgVmSXMa$ 5DDilOE?3l6y0"I@JQXѣJkZN;"T0 \]`?4d`Yn0M$(pHnqy# H@M!@}ȋNo#"IGvq)Y'^i$ FPhD3Z H;-  @3 @iQF^т f0,uds-B$  GZJNR>y8I@X 1[HBE4`qm_r68Zhi( H@+A@c%({ H`EO3UcT8V@ $QFWUks.OsY'Eyd+YE)`2bc̓QRr) H@xKX#u[Q5\D'ħ/’z9$8cʨ)i9Y"F ;DHղ.։],r4 H@fO@cL=$p 0]?~xE*Bs/SM{o9pXqqhq^y1(?9Ѓ={y.Pey]zcPr~B/j';o))C{p\Gy>j?;vާnìKċ ;$  H@ 8t/) ,?90YWYzr$HqA86Kv+{G1 Y)(띗g}^t9].p7ˉ8W*guzT#_fNc\-xV׹Ϣ\T" H@Dz`$L?2e6y+6D ~S{&be~Rì@[:GYNsKǘ]y9s{ֱ$  H@#Ѹ&BWdόăwsxQ9żr,VQn G(EX>|nu]CTgrإ ?M$  H@Ǫo" ( ,/ŏq|Qͼ~%;8$r`+jBQ:<.佗G}>x91E-gl5(u z);~TDk/98Gh$  H@@ (p4ZLtTI:J4XĀc?΅X2,njo${Yj@RЊm>B@(#-XV$  H@$f mn}. H@$  H@h4Ր$  H@$  G[ߺK@$  H@B@! i5$  H@$  H@m&ַ$  H@$ PhHCZ H@$  H@@ (p$  H@$  H!8ҐVC$  H@$f mn}. H@$  H@h4Ր$  H@$  G[ߺK@$  H@B@! i5$  H@$  H@m&ַ$  H@$ PhHCZ H@$  H@@ (p$  H@$  H!8ҐVC$  H@$f mn}. H@$  H@h4Ր$  H@$  G[ߺK@$  H@B@! i5$  H@$  H@m&ַ$  H@$ PhHCZ H@$  H@@ (p$  H@$  H!?d1=X`IENDB`golang-github-thedevsaddam-gojsonq-2.5.2/helper.go000066400000000000000000000124141375452222100221670ustar00rootroot00000000000000package gojsonq import ( "errors" "fmt" "reflect" "sort" "strconv" "strings" ) func abs(i int) int { if i < 0 { i = -1 * i } return i } func isIndex(in string) bool { return strings.HasPrefix(in, "[") && strings.HasSuffix(in, "]") } func getIndex(in string) (int, error) { if !isIndex(in) { return -1, fmt.Errorf("invalid index") } is := strings.TrimLeft(in, "[") is = strings.TrimRight(is, "]") oint, err := strconv.Atoi(is) if err != nil { return -1, err } return oint, nil } func toString(v interface{}) string { return fmt.Sprintf("%v", v) } // toFloat64 converts interface{} value to float64 if value is numeric else return false func toFloat64(v interface{}) (float64, bool) { var f float64 flag := true // as Go convert the json Numeric value to float64 switch u := v.(type) { case int: f = float64(u) case int8: f = float64(u) case int16: f = float64(u) case int32: f = float64(u) case int64: f = float64(u) case float32: f = float64(u) case float64: f = u default: flag = false } return f, flag } // sortList sorts a list of interfaces func sortList(list []interface{}, asc bool) []interface{} { var ss []string var ff []float64 var result []interface{} for _, v := range list { // sort elements for string if sv, ok := v.(string); ok { ss = append(ss, sv) } // sort elements for float64 if fv, ok := v.(float64); ok { ff = append(ff, fv) } } if len(ss) > 0 { if asc { sort.Strings(ss) } else { sort.Sort(sort.Reverse(sort.StringSlice(ss))) } for _, v := range ss { result = append(result, v) } } if len(ff) > 0 { if asc { sort.Float64s(ff) } else { sort.Sort(sort.Reverse(sort.Float64Slice(ff))) } for _, v := range ff { result = append(result, v) } } return result } type sortMap struct { data interface{} key string desc bool separator string errs []error } // Sort sorts the slice of maps func (s *sortMap) Sort(data interface{}) { s.data = data sort.Sort(s) } // Len satisfies the sort.Interface func (s *sortMap) Len() int { return reflect.ValueOf(s.data).Len() } // Swap satisfies the sort.Interface func (s *sortMap) Swap(i, j int) { if i > j { i, j = j, i } list := reflect.ValueOf(s.data) tmp := list.Index(i).Interface() list.Index(i).Set(list.Index(j)) list.Index(j).Set(reflect.ValueOf(tmp)) } // TODO: need improvement // Less satisfies the sort.Interface // This will work for string/float64 only func (s *sortMap) Less(i, j int) (res bool) { list := reflect.ValueOf(s.data) x := list.Index(i).Interface() y := list.Index(j).Interface() // compare nested values if strings.Contains(s.key, s.separator) { xv, errX := getNestedValue(x, s.key, s.separator) if errX != nil { s.errs = append(s.errs, errX) } yv, errY := getNestedValue(y, s.key, s.separator) if errY != nil { s.errs = append(s.errs, errY) } res = s.compare(xv, yv) } xv, okX := x.(map[string]interface{}) if !okX { return } yv := y.(map[string]interface{}) if mvx, ok := xv[s.key]; ok { mvy := yv[s.key] res = s.compare(mvx, mvy) } return } // compare compare two values func (s *sortMap) compare(x, y interface{}) (res bool) { if mfv, ok := x.(float64); ok { if mvy, oky := y.(float64); oky { if s.desc { return mfv > mvy } res = mfv < mvy } } if mfv, ok := x.(string); ok { if mvy, oky := y.(string); oky { if s.desc { return mfv > mvy } res = mfv < mvy } } return } // getNestedValue fetch nested value from node func getNestedValue(input interface{}, node, separator string) (interface{}, error) { pp := strings.Split(node, separator) for _, n := range pp { if isIndex(n) { // find slice/array if arr, ok := input.([]interface{}); ok { indx, err := getIndex(n) if err != nil { return input, err } arrLen := len(arr) if arrLen == 0 || indx > arrLen-1 { return empty, errors.New("empty array") } input = arr[indx] } } else { // find in map validNode := false if mp, ok := input.(map[string]interface{}); ok { input, ok = mp[n] validNode = ok } // find in group data if mp, ok := input.(map[string][]interface{}); ok { input, ok = mp[n] validNode = ok } if !validNode { return empty, fmt.Errorf("invalid node name %s", n) } } } return input, nil } // makeAlias provide syntactic suger. when provide Property name as "user.name as userName" // it return userName as output and pure node name like: "user.name". // If "user.name" does not use "as" clause then it'll return "user.name", "user.name" func makeAlias(in, separator string) (string, string) { const alias = " as " in = strings.Replace(in, " As ", alias, -1) in = strings.Replace(in, " AS ", alias, -1) if strings.Contains(in, alias) { ss := strings.Split(in, alias) return strings.TrimSpace(ss[0]), strings.TrimSpace(ss[1]) } if strings.Contains(in, separator) { ss := strings.Split(in, separator) return in, ss[len(ss)-1] } return in, in } // length return length of strings/array/map func length(v interface{}) (int, error) { switch val := v.(type) { case string: return len(val), nil case []interface{}: return len(val), nil case map[string]interface{}: return len(val), nil default: return -1, errors.New("invalid type for length") } } golang-github-thedevsaddam-gojsonq-2.5.2/helper_test.go000066400000000000000000000231251375452222100232270ustar00rootroot00000000000000package gojsonq import ( "bytes" "encoding/json" "testing" ) func Test_abs(t *testing.T) { testCases := []struct { data int expected int }{ { data: 15, expected: 15, }, { data: -25, expected: 25, }, { data: 0, expected: 0, }, } for _, tc := range testCases { if o := abs(tc.data); o != tc.expected { t.Errorf("expected: %v got: %v", tc.expected, o) } } } func Test_isIndex(t *testing.T) { testCases := []struct { node string expected bool }{ { node: "items", expected: false, }, { node: "[0]", expected: true, }, { node: "[101]", expected: true, }, { node: "101", expected: false, }, } for _, tc := range testCases { if o := isIndex(tc.node); o != tc.expected { t.Errorf("expected: %v got: %v", tc.expected, o) } } } func Test_getIndex(t *testing.T) { testCases := []struct { node string expected int }{ { node: "Invalid integer", expected: -1, }, { node: "item", expected: -1, }, { node: "[0]", expected: 0, }, { node: "101", expected: -1, }, { node: "[101]", expected: 101, }, } for _, tc := range testCases { if o, _ := getIndex(tc.node); o != tc.expected { t.Errorf("expected: %v got: %v", tc.expected, o) } } } func Test_toString(t *testing.T) { testCases := []struct { val interface{} expected string }{ { val: 10, expected: "10", }, { val: -10, expected: "-10", }, { val: 10.99, expected: "10.99", }, { val: -10.99, expected: "-10.99", }, { val: true, expected: "true", }, } for _, tc := range testCases { if o := toString(tc.val); o != tc.expected { t.Errorf("expected: %v got: %v", tc.expected, o) } } } func Test_toFloat64(t *testing.T) { testCases := []struct { val interface{} expected float64 }{ { val: 10, expected: 10, }, { val: int8(1), expected: 1, }, { val: int16(91), expected: 91, }, { val: int32(88), expected: 88, }, { val: int64(898), expected: 898, }, { val: float32(99.01), // The nearest IEEE754 float32 value of 99.01 is 99.01000213623047; which are not equal (while using ==). // Need suggestions for precision float value. // one way to solve the comparison using convertFloat(string with float precision)==float64 expected: 99.01000213623047, }, { val: float32(-99), expected: -99, }, { val: -99.91, expected: -99.91, }, { val: "", expected: 0, }, { val: []int{}, expected: 0, }, } for _, tc := range testCases { if o, _ := toFloat64(tc.val); o != tc.expected { t.Errorf("expected: %v got: %v", tc.expected, o) } } } func Test_sorter(t *testing.T) { testCases := []struct { tag string asc bool inArr []interface{} outArr []interface{} }{ { tag: "list of string, result should be in ascending order", asc: true, inArr: []interface{}{"x", "b", "a", "c", "z"}, outArr: []interface{}{"a", "b", "c", "x", "z"}, }, { tag: "list of string, result should be in descending order", asc: false, inArr: []interface{}{"x", "b", "a", "c", "z"}, outArr: []interface{}{"z", "x", "c", "b", "a"}, }, { tag: "list of float64, result should be in ascending order", asc: true, inArr: []interface{}{8.0, 7.0, 1.0, 3.0, 5.0, 8.0}, outArr: []interface{}{1.0, 3.0, 5.0, 7.0, 8.0, 8.0}, }, { tag: "list of float64, result should be in descending order", asc: false, inArr: []interface{}{8.0, 7.0, 1.0, 3.0, 5.0, 8.0}, outArr: []interface{}{8.0, 8.0, 7.0, 5.0, 3.0, 1.0}, }, } for _, tc := range testCases { obb, _ := json.Marshal(sortList(tc.inArr, tc.asc)) ebb, _ := json.Marshal(tc.outArr) if !bytes.Equal(obb, ebb) { t.Errorf("expected: %v got: %v", string(obb), string(ebb)) } } } func Test_sortMap(t *testing.T) { testCases := []struct { tag string inObjs interface{} outObjs interface{} key string asc bool }{ { tag: "should return in ascending order of string value name", key: "name", asc: true, inObjs: []map[string]interface{}{ {"name": "Z", "height": 5.8}, {"name": "A", "height": 5.5}, {"name": "D", "height": 4.9}, {"name": "X", "height": 5.9}, }, outObjs: []map[string]interface{}{ {"name": "A", "height": 5.5}, {"name": "D", "height": 4.9}, {"name": "X", "height": 5.9}, {"name": "Z", "height": 5.8}, }, }, { tag: "should return in descending order of string value name", key: "name", asc: false, inObjs: []map[string]interface{}{ {"name": "Z", "height": 5.8}, {"name": "A", "height": 5.5}, {"name": "D", "height": 4.9}, {"name": "X", "height": 5.9}, }, outObjs: []map[string]interface{}{ {"name": "Z", "height": 5.8}, {"name": "X", "height": 5.9}, {"name": "D", "height": 4.9}, {"name": "A", "height": 5.5}, }, }, { tag: "should return in ascending order of float value height", key: "height", asc: true, inObjs: []map[string]interface{}{ {"name": "Z", "height": 5.8}, {"name": "A", "height": 5.5}, {"name": "D", "height": 4.9}, {"name": "X", "height": 5.9}, }, outObjs: []map[string]interface{}{ {"name": "D", "height": 4.9}, {"name": "A", "height": 5.5}, {"name": "Z", "height": 5.8}, {"name": "X", "height": 5.9}, }, }, { tag: "should return in descending order of float value height", key: "height", asc: false, inObjs: []map[string]interface{}{ {"name": "Z", "height": 5.8}, {"name": "A", "height": 5.5}, {"name": "D", "height": 4.9}, {"name": "X", "height": 5.9}, }, outObjs: []map[string]interface{}{ {"name": "X", "height": 5.9}, {"name": "Z", "height": 5.8}, {"name": "A", "height": 5.5}, {"name": "D", "height": 4.9}, }, }, { key: "height", asc: false, inObjs: []string{"a", "z", "x"}, outObjs: []string{"a", "z", "x"}, }, { key: "invalid_key", asc: false, inObjs: []string{"x", "z", "a"}, outObjs: []string{"x", "z", "a"}, }, } for _, tc := range testCases { inObjs := tc.inObjs sm := &sortMap{} sm.key = tc.key sm.desc = !tc.asc sm.Sort(inObjs) assertInterface(t, inObjs, tc.outObjs, tc.tag) } } func Test_getNestedValue(t *testing.T) { var content interface{} if err := json.Unmarshal([]byte(jsonStr), &content); err != nil { t.Error("failed to decode json:", err) } testCases := []struct { tag string query string expected interface{} expectError bool }{ { tag: "accessing node", query: "vendor.name", expected: `Star Trek`, expectError: false, }, { tag: "should return nil", query: "vendor.xox", expected: nil, expectError: true, }, { tag: "should return a map", query: "vendor.items.[0]", expected: map[string]interface{}{"id": 1, "name": "MacBook Pro 13 inch retina", "price": 1350}, expectError: false, }, { tag: "accessing not existed index", query: "vendor.items.[10]", expected: nil, expectError: true, }, { tag: "accessing invalid index error", query: "vendor.items.[x]", expected: nil, expectError: true, }, { tag: "should receive valid float value", query: "vendor.items.[0].price", expected: 1350, expectError: false, }, } for _, tc := range testCases { out, err := getNestedValue(content, tc.query, defaultSeparator) if tc.expectError && err == nil { t.Error("failed to catch error") } if !tc.expectError { assertInterface(t, tc.expected, out, tc.tag) } } } func Test_makeAlias(t *testing.T) { testCases := []struct { tag string input string node string alias string separator string }{ { tag: "scenario 1", input: "user.name as uname", node: "user.name", alias: "uname", separator: ".", }, { tag: "scenario 2", input: "post.title", node: "post.title", alias: "title", separator: ".", }, { tag: "scenario 3", input: "name", node: "name", alias: "name", separator: ".", }, { tag: "scenario 4", input: "post->title", node: "post->title", alias: "title", separator: "->", }, } for _, tc := range testCases { n, a := makeAlias(tc.input, tc.separator) if tc.node != n || tc.alias != a { t.Errorf("Tag: %v\nExpected: %v %v \nGot: %v %v\n", tc.tag, tc.node, tc.alias, n, a) } } } func Test_length(t *testing.T) { testCases := []struct { tag string input interface{} output int errExpected bool }{ { tag: "scenario 1: should return 5 with no error", input: "Hello", output: 5, errExpected: false, }, { tag: "scenario 2: must return error with -1", input: 45, output: -1, errExpected: true, }, { tag: "scenario 3: must return length of array", input: []interface{}{"john", "31", false}, output: 3, errExpected: false, }, { tag: "scenario 4: must return length of map", input: map[string]interface{}{"name": "john", "age": 31, "is_designer": false}, output: 3, errExpected: false, }, } for _, tc := range testCases { out, outErr := length(tc.input) if out != tc.output { if tc.errExpected && outErr == nil { t.Errorf("tag: %s\nExpected: %v\nGot: %v", tc.tag, tc.output, out) } } } } golang-github-thedevsaddam-gojsonq-2.5.2/jetbrains-grayscale.png000066400000000000000000003155461375452222100250340ustar00rootroot00000000000000PNG  IHDRu%4 pHYs   IDATxii}ta_ f[H]U`ӳ3`K`b`Cp2sJHȹ`!F]Ouf@< !vlLii t9pEKwߵ|>ץӿ:Q*s:rȽ}#~qgD5"9oN)9"66DTι_G#█AUUcD|+"رcgϞ(e@80qg?89RJ[SJgϊFu^D|9{J~ѣGr~w~(tXc2559OvDP8]D|)s^H)un楙n0X+tXe[sοs{"gGSJͶZŔRtQxE>|/"~ٝ;wP:NNtUUFD#<[Gk<">199oAp24??3=T_q϶m~X:nG]禔s~jDSgH}'6/b@iӦ'真-3bnks״Zg@Eij"⮅sF]/h4>[:" N"/޳Ϟ=`|y9X:pĹ~Ҏ=DDķ"nvvƏ2;;;e˖GEĹ{UO)}\ctBιZ qNN-9+z[fFW"m [8%9I}ݻK0 vH)3"~t [tK0z {w?ggQfӥC-^&02rUyQD%",9m߾n`4 sssUU}8"Z[XW "j+p30fgg7m޼M)߉=sCyV! /:CnJ)폈J0)w|ͯY)10txy:}9F.p104rΩ<+"+`릔|+p009)k#⡥[*_zyM_U:nO9uґ0s.\C|.XDL^9˯~:D;"bsFrOiZ*10P>"[Y'LOO/` N󜉉xzPb]׿^::?)Xf! :Eu:w+@xIJ_: qСLMM}0"P"W̬:뮮D#[űc.۽{r0n=@ɥ[6nvv֟uQ#ʈw7;vݻwtˀ:x7l[$|]t}֏5S"q-p 499۷!:n~~^)gntѣGgϞ(3~dD\/d[n /n֖UqС-L)=t mٲ[n=Z:S`u:73.ws 0&K0ޑs~av#F\u]}Dt kKNNI~mJ-ltπIiwr/ ϓ5rV=~_Dl-CFF;4;;3|KeQAsl>?/3p.jD1Y9F:V:g@ "">??t {ӦMO޶mKpr cnvvvrͿRz}DL-[\u֣C8qt1틈VA^^^~JN` 8p`~eJMtsjtẁ0fΫj_D. n߾[}UGιt:/j!nrvZZZKn t1PqmD\X;v#w޽\:[`SyID,J 6|f~~Cu.FY^J?>zCItt^s~GD0r qiV:9|'''9_ZCק.n4,#?/ XiۿYU{sw/0rl6mDƍ N^9FK tMܻwotz1#<)W!gOXt`d]wu|De˖˷nztZ1#cnnUU}$"~t fffVJ:0:ejjO"٥[g=zٞ={n) P#⁥[EJݾ}K&:0"[6mm۶}tj1CnϤnsرcܽ{r`@❻#E9` 1==[NPhE9[)ԥwJ:0^(HAVkt0\guxSJsssƓ tऴ>+ZI)=h|t0^\'VUuCX[rǖƋ t-..޻^O,Xa)VC`@nW~rJq-c)+Jπܪ뮻[{݈xZ!h3?n?SE3GKˀ#Gرcn[я6}Cd@""n?&_9VuU``̵3SJ*'(j]Y:-tcv)"⁥[d^h4[tC_7q*"Y8)W4wFL]E5-RJi4o/ ?:;wݷGċ3#&Fp@]k#-VRJh4X^ta: 骪G/nARjzz)~``Hk#"bt c@!n)?"KM7̽{JɀCsk" t ?[^^~Lt0x 0$;KXVut0X9Wu]2"xwKKK .`-,,\\F'lr֭[ t@ǯ_xk1T: .`sRJFCK8H)}fee{칥t P t9Tox&|ƍ?x-@Y.`t:圯J¦Mm۶pua<Cm) Y\\|@۽:"^ jn./P@]v7Ѯ9rJ:v}G"1[ۗs^zڵۥ[a@uR"= Ǒ%F㛥Cg@5xnxB圗ŻwF`m` u7",//jZ_/:v}Ϫ>s~r`ujrr;vm`m`uw`tKπwߴi{sοYXS_jfzzkCe@UPc#q-7VNC>w真YXw{!0)9RJ(_.>:/~t;3-@y)oTUu;Jǀ'\s:"T(ߌK!3 X\\s{Guܹstpj p:ί术K;)7v6-0dM7{J(0P]{޻SJ(0gffC`(GFUq-.#7[ֱ-0 Cm|gJ鹥[F7mm۶t +:\s&"~t Ė-[u֣C`Xswz90|?_^^!0lNk~ڔY[EJ3+++߳g-[`XvNҋ @ ۾}K0h~k#bk16mz̶m۾W:U3;;3|KeQ "_< /nttVUU폈n\s~Dպt 2:eiiiѣGߜs~eDL6~t *:fD싈_,vڵۥC`8iv{7"&KpR.i4,ƀIt:s#b{NMy^{onAb@Nn޼wSJ=//jZ_/€ZXXEDt 'WرoK 0p80qg2X5qK.UsssUU/"vn`}鯕 sn_QUBŃ_sJ@I.'u]Fą[X9511q[D9u:DbVJ~sssn\ųz59燕n`05t 'c鼰1r9nRXO.P٪9_Z.^(:t:M)]o<ܣfX.{G"Q[:såC`-@N^0pjZUg`:t>SSSJ0n6_(k:t:WLMM-sTݞ)k:t:9_n`dݒRh|t&:t:UOh6.ŀ01+bHYfI=@w@o1j, 7t6l\h{NafO$th''INRt"3`xx43@c@6Y~&3{y=@ddDDb@6(rIG]4M_jfut?1,r,3콒D]۷o'܊t%eY>.wD]۷o#:`1^rw+ufz;xh3?`/?l^&i-@?;@HEfm1r]9111/:@TcIE}⫓'NEz:솢(^ffHZ3۩VZ3л`lݺVSF}~LwFz(ZxD;̾:11@oŖ-[600pc[/3;իW- px^$DG7cf+~=!~R!###ߍt$:fSQ渤x3fJu]?~7TU!Ƹ'lڴi\A4M`fu}- ~hߎt&t],˕."),bI$_t: :&Ir@a@еm6rrlI*i M3{IhÆ />_+ :^yW-€+UU:I|!_JIYͮ(4 IzȖ@3]ebbbY,i0 $Qc ˲Xۢ# tf||!fBI'DЁv&I᫣CfSQGċswgYgǀ`VE,3[@?i,t}[ 7wFw:r7'$@'rKdMNEQfvGD@w@o9t{($@VvŊ? [n}dټ̖G@3;'M3;{n馛433sG6 }A<:d.MLL<`jj IGG@s,{}t`%KQGLra6KҥK}tzY; ex `E>&-t23W|ɭhUU?*i |2MWGv :Uw=*NffgizVtG')(3D@4}!ǀ^mܸq… ϑ:\Nh4u}GF@l߾Tޝ::{T!.:ܴeYvUtH'~Wr-/dDƀ7l6? Oğܟfvl 9 ID@wwft 1eY>Uen ynIUUtzt ?;ŀ@6mZ8Izs]&Ft,Otp NZt]!P[|Ft#$E-૓'NE:Чm6rrlIoD +u]?+;[zEYfWZ3:_Ё>h4F^'I-t'''_>::ڌ5UU=ݯF@o18 ::G&&&MMMKқ}i-l6?'p ^t/C1}blll8Iu0.R4=/:{RUՇ%s; -0~r%wC0,S%}TҒvw_OY/ I-0Gn5C4 @*fIIGE#W\I|Q@! tÔe39ܹcddo"_[`<̾YUղ\b||!f"IG xҥwE`m޼ͻWD\0><*:ʲ|_t =ciytlڴi?#-0G~Q-!ЭЁ@EQ$'Y-,>V-0G&lmߊnĀ)IJzHt =if/M!G@7H^WZI730}9vײen5/FXhf׌݀ tM6nܸh},aff+WNF{5?wF̞5!Ё6PwTc[5fEnAo%~hIɲT ,߷j}_%2MͬAo)IWJz`t YS,[%UU_&iz۳,,כ[Z~J矋NÀM6-?$N?@;i^WUՃjImV٩i~:::ItFjN9S+i!meUU$:: 6lذ`ɒ%u3 Qh 3]i~+ݭJz[t KzueE@'`@v؊$I.z}MV%],i(8%6˲C :&&&MOO$i v˗8:(FJInvry~ntDb@vAQz?$Ir/C_766$I"ih'wc( }(b(Iw$ F<99ѩE]-iUt -Ew@t^ey3-:w0˲̬n˶mONN^.9-N<s-6l\d[,IC=:Gqw+=fh'3;;Mӳ;`.1?pu@KҟdYvqt'x],i^t ?MӷFw\a@$_~ Ox™gG$y IDAT!ިieInv1s4=3:֭[j2>sw?6!l%=!,^DQ=)VU w2,_{fs$~_eeys}(2IOn|jYbŏCvضmK$=?i<:ځ}ݭh/iȦcVZu{tneY[һ;.KefVGlc@Gh4RI-kjժ!\)I[Yʈ eYo9l߾s4M?cf')eY~v-0@GO۲eˣ/qã[7<Dj4u}[;vxh3f:zVUU/qHZ@y":7x~YS[Mry>{=GH@6izetI&&&MMM]"-&,XYK.+::zJUU/tKz`t }h !@*]`f_Yhщxtt )t͛7?tpp"3;.>fYvStʲ|K$͏n6V{]_JwlM?EQϰz7<ŀU~.0[c7y,:6eY>ݯ7ߋn6aG/]!;`OeyM0̾0{&˲u]$hMOOƍE]eӦM3o޼4F.|h3:v󦦦>%-gff֬\r2:v:FYHXâ[gf4M(if6KÿÀh4j5S[s!@~-0˪WZu{ttt,JGFtJe_zS$kIE,w>Vu?=ܧu}Ȗ(%f%IE,KIY]w$lnEQlx@ׁ07y)pKK,y8;{efi݋S\In4M_gfutVUc뺾̖F^%,˲ˢCt'th˖-Hұ-`ט;4}otޱyCCC_K.UY]}Nn21m+WƁu]_.iUt U_| ݓFQw]t jzzUV`p>G݊8b<ٺc`Y^+)?7/:}?l^&i-`v<Ktt#$Dnyppe˖`1[Y2I7*w33i:bddݓΑM} YRŋZb<W}jb<afuegiZ=!v{i˖-X1-m#-[v[tp/HZGɲ!v^(yIv'.]-ʲ<*=c@wy!-~),˾ueY^EHc!/{QfvR]ׇ٣{@[i}cccONzIn]C,6GM ݓΖV~p5Y}?:l򰁁k$D.#FFF1:b 5EQgfWH:,om6kW\+b3[`̎JCHKߜ9aʕ!VU%NIdY 蒤^J,XpҥKGYt;<Ͽ7mڴp޼y)-`nLJ_ofh(af_8vWC~ַzQٕEou֥VzIn]p,6:WIt@,6B􋦻'fff6-- I,C~wzYtF9qg]y.:cʕ?z+[` IZ_ųC~Wo^U-`!xnUU_қ[`i^7l0dɒO[A]kFFF,EQ.4efi_>>>o#[y!TUa%IK[~Ԓ^ee!@?($WD9s@gzIn^e'C^׳$̕/~8i6H:8k$ƀKZiu[hKk/jxEޝ8ժ`UE IJk!!alegxXPuϞ=zוAz:RzOCxК5k.!0jFu]:P~UU/*ֶ_R`RJNMM=lݺu?(bi) M?"]UKRi9翌JħWZеk^[:F m1+"~t 0rOz/Kms"9ۖn8߿7nS:Jw;9w՞CLnNsrqwɥCЛyADܯt0_K)֯_Ņ-7s>_|{R#ސR,"KsԃfffRFݻۻw[# [n.3"UJ(:رcΔJvR78i^/-pK)ݿ~t,p_b[0>655u?9ZUU/'F Sn9Kʟ*K؀4͓#q G{yu~PF]UUDķKOMM]ڶKR*;wcqq۔?04v{J)iGG#-7-֭jX K~}֭S 9ϩs8rUU}y߾}#S[n ۶!|@숨ܐRz|UUZ:M6۪U,p3圷ڵnC`ؖu]%qR倫v/.㤮뗤~tsyK׻t ˒@O)>0.W IDATs77NgwDL P};333W:u'DĖ-\?B%CH zJa<e'NsX>fffs~PDt Gsss,Gj'۶圯Ƶ99묳^8:MӼ0"^~'Fޔңߖ59?rmaa>sXުx\D-rlaCp tn9yM`趮Zk׮t0m+}؟s>M5=~9Lvb<v?;==!">_ "V߶cJ؀~ޠ W^Y)~`֭[NgSD|t @DL۶J-Ȁu֩+q-`"?z=O1733ݜCrU ~8i_-2wu_ ZP]w݃V]=1A?"RUJ s'"^8`7dz9?6"n&^'"i;}~~) "9ojG^}#["-u]VA@ B\JiSB^wE_x)􆺮U:~7DĦn!蘙JySD\\ ?۶uHpLzJ0>gϞzFOޞ={R-9״m?lgrWG{9[4#q  BJn;\G}=09=x(E[ɖs~E۶WuT,߱cǚ+VsDpp#iUUE`y;kjj9SKzQ&Q@?s%w:Gc1;;{eDl9.L6MG#t892`ƍ{sso.LǮY}u](x9]vىW׈X=E㫪@k9?#> ?z֮]{CajժGRJh<FU}myTD\WL)_޻w/,x8=+n⚜nSCṅ"✈Z`bgϞm۶mU[}W\qG_9?!+qf`b]o߾_ڴiCXn#xKef9ܜuY|o-LZꣻv:t׭)G/EaÆo87oW_xc`2ﻰwM[|{]'+&_lٲP:`xMƗƍ`y_b;CxCR~x4ȈA`"㎻h~~!,/8yB`SJv/,0 n9s"-9/ꪫN)qGo۶mz͚5ߊ& Ī]vt 0yr;aÆon`mnsa<aؓs~֭U6>Z<)ӗm{-C ;}z޶!Kiڵ~_x}`"ر!C>½ij0H_~кut@Iu]?+/ rz_+h:耾cǎSWXC9pRJvoM<<"'n&Ηnݺ`9 ǦCUUgGĿn& 뺾KFA:;sοnݺ5SSSr;K純]vݭtzyRnk^oQ~YzqA`IK0:~l@+RK8z9"[USJt [vW_}#rn&ΝSJwy!{y]׏O)D 9'zXڶ}fu1U(_WU!c';!0^=RD\[(wH)m۹s!czySXtr7;;єWK#|ⶦi,@97/#➅Z`:缩tv:ΆhKqLʸɀzٛ3w׻tvLOO.Lu:Om+һXB8|_ݸq㿖W֭A}dDi`s CXZ7sγB`99wժUn޼[]J_UsrO=8)MCX:7SJuUU=aڵ7$^)G/1KeMx۶`iM]'[2F\TUǥC&Y4gFq-ĸ.^tu,Vo!ks򪪺*!"-8>tK0\>֕ xx}g~}-|NC[|mۇ`x@[~>V:zUUkKcUMswD-D9iǖ`p:wC`޿f͚lܸqO\ↈKa:"4J0"^?3338c_Yg}"⃥[0hɥC8vJ@a/)~]׻>&-DD[~J͏NT UU~+v-"~3~s0ҟu!΁޵dr]UUtSU[rFĞ-K)7m! ?S޷#^! _D߿wDS`mh@S XZ7缹CX: 1W9״mN۶C`Ԧ^!,7}(۶N#`|霽~)@96m>&"t 0rίhJwpx:~>gϞ_nK)媪%"J-i^Y[יrs~s}̖-[n`TU~-{Q4X:[9߶t K^i)~FESSSnymR0_{K0֯_{zzzCD\Q{ϩJGpp~JNUUyu}c߾}[rt 0RJϬM9TꤔN.~`ٴiUURzu`~s~~sΝ-NDT:!թggg?S+H)=%"W)o5:boDwK0_-m[Nn #`V޽s;`|tOFĦ?nN?wo۶mt30N6,..sss-+V;Jck֬y_]+JLND.N確tcݺuسgϖZk޽!*5M͈!0[}ݺu?(x9WG`]f͚GqJLNDx$_s{`C֤OOO_ҶKND\_:J9smnpf߶cǎSKND+#b:i޻k׮J-I)]bťu]ߡt P:FvϟQ:nEĥ;wSqI)][:F/mtܒ=u}-]'tr4+sΝ1p NO)mk-#,Eċڶ/mw>tr9=㎫fJ-ˁgX:9+AJnN3m>t ܂;8sCNJۥ#`Ys~{4ozE8;t:Kwܹtr҉oeRJ۶c8󩋋ۚ9t rI)}t,SmsJ!>".)tt,W9SsΟl9[nt>ٶmt߿MGky]N(qJ⺮7eM6[D\_:v4Ms!p'>1??tWVyx85~MӜ]:`h@0^NmsVmXZzKQӉH)}ps~q۶^uU9!ta۶(0J:9qn__:nfu#M餓>|嗯.p( X +RJiwu}|&O+Wp׮]'n8[WXX\`it}}.;t##<)4Ms*d9{u}R9#CJIҶm?2??r&ΆW]u)C"c@9/.E P̹~n!L?yWܮt@wzD|i'`LOO_ҶK~a#xW]V1L3;vZ:\5]D|n-H)=3tɕW^S[)+V;n&a kh(<55ݻt"ҝ;wީt0y{@_\\|oD!Ng[۶,H)cqqq{]w)L:OM+r4;/եcߵt09oJʕ+?;77wZ&]O/L##CjFߺNS=t.qCwD-[F{,t: yi9`~_:77[vpx+&Eڶɥcw޶ϗUU]B <+Jq* IDAT0rΧ/[t4'#"8 `9;OLۧϯ/׬Y[e*],KJ38c_D[p͝U:G9!"n` ;EJ^{GhMx4gx@*&"-Cn+">18Z'.lCXOGDju#M0??˥Ce zUUD p\۶.,:Nu-95Ms^`y؀~GD;LG{yB` l@O)~A]d*"QFُ>3ktRJom7JkzD }MN/ڶ!h>;;Ƞ rojC3=""XƵ`o9#2}!ø6 ky^`t e@?!^5MhڀvRzi^Z:(o'У_=`^V+JGe u@zyu@9C#"fgg/J)cRzA]ׯ)1ߎ/ѽਥ۶,,%л59]{9?m7S`, )+~p,rOk-FtK69F'm֜}37ꪶm_s~Rcg?;^WΈk&q{&˓۶޺u;1,rWݻ K}oΊ+N(-gsp$>x#A+bnnt0駟>m۶'nٲet 0K>]-tE06o~  ox-x31H/~ $x܉'8m۶_1x*Ζ^F+Kif͚u]( ^="bϞ=J)]Y':RݻwW:b-[:#?t`<|޽m۶UC)6GD_)gl`%N:×_~!`#"__`@R+WKǮs, s޽6Cc3zc#-,oNo߾]ve'H 333s)V̀sի/-="[Kw|6.ꪫN)#"VZ;X ߿W\qJGfk^+c@F%u]D܀QU՗#_ŀ3SJvC3zDG#`y1#.+tpFv@"❥;X> ONgΝ;T:e#=GDY,t`+sF~@?3Wn`-,,N8;mtpp#?GDzoEă#[[mN,tN+e1GDTUxxD\We@ϟQ:e3GDTU#"> rR~ϖnò#" K0z 2rǩm|݀ޞs~^FXNrΧ/[e:GDzפ^^b@ۧϯ/nn';t`]u]wK$[zDDUU9_`@mSJ;t Le?GDTUxc[XX(p,Nt:m{!0b@O)媪o(@YNc`Mu]o.f,;(ǀSJo$ӥ4Ms]Dt Ko~sss3FW ܜt.l'K$="un`iҀ?6nX:Xގ9_4#xwc9GDzW7Mxc٣8Q92/o~ssYgIOzR\3~ݻK'U񡺮.,ll􈈪Ҷr{>O}tA-,,N~qז`L)}`~~q5'_-1v\۶.jn\2cnE}MӜW:D xVD[:0#=u]?t#":묯ώn`8rKg TJm>t#"zun)?(p8LNmmz7GDr}aJq]ˀLN/C`L#n~sDSǀLojC`="bvvv~aaJ)]T0(E뛦!MaÆo<8ȥ{86t`i畎ʀ~@Jv_o GMӼt,GSSS3t Gǀj楥#`1/X(1DD~EXN p9oKp ?Rݺ_] zWZj}J/Kpx_+-srο4͟Qg@?t:?Rz{̀pPn 9T:Ftfff乹NMqMԨ ӱyKk)om"_SJt Qݻݻ̈*ʀ~ 'ħ?K|f/S۶9?%/#܏ڵk9!te~hTt۶np܈}jfffRzJD|t3'vi40HJv*|t2үvi۶mW@}MOO\Dȥ&wQUƿkX\ڀTEkATQ"zlZVz/VjQD 3AANK a˩G̚4"!=M0\h!IOe `Q\\E Zv97[$th Fm|n =00 o @cw%= i,/@ʕF"/bz `D\N  1ihhXt[H9, 01xI}7tHޑHdA<;d`TVVA0Z;BnT9 e@cu-bXkWYkcΖ&dci @s0@oytH9 )@cIZP]]vtZ 8.sν 97]#3x!aРA0ڵk{J/iI:xsn~4=wM_1a„kÜsƘ%mXx<>wM;+A_"i徛v:IG4 |X Inf2ƌsWd}֭>}[p9-cգ˗`W˟ŋH_L9 `LnQ>˾oB $"ȼx<>:|36dȐZkf͚}scIr2e:oD"I@Z;瞈F}3 l&Lh _ >;a]:@f+++sInV1C}M#|\s ܋@g?;wV^^N_ aohh,iisx<>w_:R" aa1Bҽwuqa ֖-[Ki9H4=wt\/Xk'c9.&4۷%;uc៭YhInV1WWW;ia^A/c8IOHruw—nz^__$Ä 8KRw)D"sX!t1&ёHd?I-]uw—p:@n w i圛Ŏ#IqMd]N$w—j@ {Ykq"]-Ҧ@Xl##TTTl `J*i:Yxu衇jժU:ýv^{ス6_[l3@naKZ@Ks4=wecc]l=93I|7ncƌ?bu]^ :t{7d]TT4\|HMꫯ5 rH$rw|H #h4z@Y|i?&ι7|7Xyyyu4k&M~ZSX&x≪H=vK/0@]eee/ T@zcnF @30@G٨eM6O^z> Xko^Dwr] `Kw@/-VVN7Ɯ%fG|;#CS߾}rz-YD>jjjꫯVCCsOKeee:5rH奥9<@\r;Ϧ{z}g41sء]v}g]$ DQcLT\@f1\;%s)VQQ9箫휛*Hq ͛7Oݺs| 6LÆ K=SiժUzLY `Y<{DR@j9~;3Ƹ n=:v]#C]as=y.{kk\A}Hb-9v$t? g݌1HZ 9͟?_:utw7h )c%i15 Ёѷoߺ fZk8笤w uQz'Ԯ];)Y;3@1&aD g8{o$.aN.(((1D뾛z!N M[8$)wZ,!:9&4R? #iG$%ake|w3h c8v-Y.& +Yk;KnZƘd;AL/...i|70kUW];%<#zgu u0|9w|H- G-H}YkdH$1NI}w#//Ov.B)9e۶m vka9Ƙ|H1W\w {0@&3"H%H}G&Ms~^ۭe1$ sz=Rjl]]իWd@}j!ιJ|Ao?|9eŊ:#?J#w qY[[EZnd>@c\yy0 qt}wn<;#'l۶M'NT]]n_:ZD"&i)uxaah@fcQ뭵uw&@r84yd-_wJe˖5 +K Fc[re[!_~0s% t=g?رca)Yk IDAT̙[}hAmp}W҃[ԡuuu/\@fbxf]n=k%Izw`:#U[M3ϔsתOBZ0 7Apn:ιa[~rž[:! RkZ/HTcfI t555:ꨣi&)YcժU7nnݚ㬵J"'35ਗ਼C:˟ `ssrIn4… 5zh}gS2ޚ5k}O}QҮe9w$rWy"xzѢE Ё {a^Q[[SxIO{N4… 5b}S2kC=T3g 0|2//Bқ[LPXXh4w 30@@eeeAkaDbI.EQ 2DS]]>8s:g+o>w `lٲ|cdW+qΝ!w`֮]!CG1ΝJ)~"Hu2 2[n9[́,]to!Y* ai $ 4SR,7ظqƍgM"%\?^6mJXd  eJ]}akbk)ιn.rν UDB\s_~wNڭ_^ꪫҲB:㬵kWd,s-Xtiw!?9$ Zk$$M{@F @W\qm;'-nv_>lƘ#$m %D"x@1@r1&Q^^vL$휻F҇N_~맇zwNhذa2e6nLg JAwFN2(?^cƌA;IqF=z>o޽~mv1hܹ3vh׮>s4GIHx<~s |HCι3%!فztEz0 uA})g}}V^_|QK.??cRn|gk0@otiB9:ntc `@j0@ϟ߾}csS%UcQ.]j}QΝձcGmV_,xihh͛'>лᆱZuE;vTvTXX(cwvÆ z[oe~; Y^}Ռ濱>aժUQv9?@X,V1f_-q"^q-c`lc)R@Vb Z]xg_%  >D"U$Wwg]%Hb{"] :$yXl@rnH$S%/wX Z sΙx<~}HϜsGaw 9X`-N4twMw@&28k%Nwjgy<;@ιH<?RTI:@ tMVh4Zi#iO-j1flO4.IaIXkH$J|wd0 'nTmsD}:+//_kimmm7c̩n:KZ@R6<\]]}c wiFIS1ߗwb wMТpOW.[I[$6I[kh:VH0 a(H:9&[ι+}HVbc}pΙιJ`@kDS1P;9 YC t^c\OYka|w=Ƙ%}@ch<8p;A\!DI |7[ HZ@9fIC2R<?9wS$sl }hH$snI#k]C; t)ӊJ$%i&tvڍ4w H9VhtƘZX Xxι|wH;' [}+d0 axr~~~wIHZ sm[$1Fz@s1:+}7 !"is[[$s0 e@1 +wƘ}w$[F"^ 91F}w:k7n,tjM4pHzw 0\F/_lw g_ۻ_Rk=@.c wMʹrV[nI? 91 2Z˗}J:[R_9@Nb 'I,}wHcA\Z:Z 眉Fc1c$nrtM=b$͐T@RZ{h8@aq0(P- 28!Вe+U[l)qMw@cUTT|\TTt[$řxNH#VNb%M4^R cRXXbiFD"*((P~~Р۷k֭ڴi6nܨ-[9 VA4sӌ1 -0@FXxqI" 0@@qq<@p۷z}G{キk/iӦܶm>mذA֯_kjzWvZ544wc&xι$n<ι֮];i„ |cMwL"*{Q@ԯ_?]xᅾ33ƨ@m߾][lQmm>#mذAo֭[ui힋BgyD"رsOHJ$͛駟l_^k֬ѫ_] YK/U޽}g覛nR,r:S}gH4eʔ]׿JJJP/_믿-ӾwO6M}]2hWee r7[nʕ+U]]ŋ_fQuuH$N[41fƍOMXslciva7oR__իWkbZxuVi_1qD͜quV-_\K,… `zիWo~tI3RM6m۶|݊+ԯ_4}N:I׆dɴݝ;wև~;kjȑ:cuGx}cg>S=sz5o2EEE4h iӦIjjjciܹo52bx.IǏ{ 6NA1c/_UVNAcTQQN;M'p}'RtG裏$zGCi쐂) 5˗/Z__s{4qƘ+W<_~|@.lWQQZ{< t- RW_}VX^{MUZZ; PVVK.DhTW/~ wVh۶N?t;3 {Tv| Eڴi)S襗^… 5y=zsSO={O4lذy` HH$7@ݺu냫W.:$QYYYnι $ rA>}t_ /O?][fݻ.rzuG*ioO&M)S(?q !sLvtEiݺudԩ:,-\PWեKY@ڄa=J$Q?~5-*H0.H-aI ' 2D3f[o_Wk|'Foz饗4q95s%%%;v dO 2w6_cNw fU\\h4m;r tH!c>a%*I\бcG?׺utu׵s3gjŊ:[Ԫ;L￿UUU;СC}g>`on뤓N /^cǎm񻢠e/Hd}hƘǖ-[4 pz{&[֏c]V^zڴl~i֬Yz6mo4b@׬YZ5۵mVz}ٜ۪}wUTTjjjtqǵ2-J$%@Z__… \Ҭ_~ۂ Z{ss>ٮm۶++h| jtMj.w?ݻƌ;c>l p%%%;jjj 9s(TyyH$2T|-ex֭Xxqv 0 _ -[ttsn&vݻwٳ[nsLHDs^z%1wNJTUUezڶm;nĈ+|g8 ӧx =:|)SVVsn|hOtٌ:dÇf% 1ߕힳ 3F+Vĉ} z衧~Z^{ |$M۶muإb.Q.Q%Ӎ7ިo]ZUF˗nP})vk.|mDE}wd+a X`=aeι}7@j߾fΜɊrgQ׮]}$ŤIf3uԌ_)0sLwB=6m;OV})cJInۂDNC 1@ 5hР ajڵ=%')8K/T't $IEE;Y1Y5:蠃4|p:tٳպuk)"=C:|oۚ={fϞ.]RZ1f|m1-[6  M0Z;Z% S]mN};$ҥϟ &Nm#GTii&,QVVnw$h=z3~xXB{ % x!??U[Yt޾C 0@,2p׬;J1?b=̙3;IRXX/Yq9s}'4|ƙ]z3Ԓ%K9Sι[s -[wd0\$TZMɮ uw(wJUUU;cL2hEEE={sO)-ΨQtWhQ{=}ᇾ3p{?rM|-}C 1@1x 1HIJJLS\\/wu֚;w:u;eڶmɓ'm%%%;v d^z{Q$GҥK͜93kF&N)@Ja܉b< [J}}@&+c ڣ11.$gu[ݻ뮻ѤIԾ}{Qh>Z]toV(HO;H0 g9+٩G}}X,wd* x3EEE$Mwd"M2wR`̘1}F1FӦMl#FPii d+R#G&L.ivgUK"`I/n[KZ/~wd"o^k0c@IK |:3;)NݺuF3>wL$}ݧ)9m۶}g(W_;𢬬lsBS[얮 bXnA$b-LˬSosUnݺ @v2vtNHSO=Um۶,ӹsg͚5KZ򝒓.uwF#$n[3LZ!CAplI Ə;)r 'h3W^3f)..ĉ}g :T^{ӱcG'?bp9*++뭵gJ$@DC S0@( aG/$9 #ꪫdCUUUF$ԩSs8t'){.B_e%m:IG4 |@&`! i9^Ӿ z=z@|:C}gH\ɓ'H:(V#{̘1C [VUUsρof}0H|O-9-c555[7`D"K RaB^xIҤIԾ}{)k=М9sX5'x:v;Es`˗J[@uH$b!tNj/\WIgJԿ H#죞={ %KN:N@Ca:իƌ[IIƎ|w T~~f͚ :( _xb]yz'T__ڴi:HZ :TÇWϞ=STs6ls0],[#Ohm$=F Ð# fIHzLc555=2LT lڰaCתU+tA:C5nܸRm۶cƌ2@j1g;WUU1@GFŠ 2{~3m ͛7kɒ%ZdnVI_<uai5jڵk?S~/ YkCsHwFkmy8}@:0@$UYY:I?[z嵵'H*8b۶mbbշo_]|:S3vdoJ_XXb^ѣJKKeUY=]~ig۶m5yӧ#FTV,6rHs)YLmdB/\\sMʮojƌ1cZj#FաCϟk-Qh4:󨤃|hBCXxk#c Ro߾ubk? L$S%,iei:twWII勞U֭r=C~N>ds1Yqujݺlْ{N4I۷O2g"|Gj]r%Zx}Q)wk֬UW]m۶M?qUUUi̘1:5z=SOa_x$ZINmYEkιy^ y :wgsΦM4w\p ݻnfo՛j8p`gѴivLqꩧr,b̙ի׿ ;̜9s睧R]]̙:Jj}ͺ&5dȐ5kMR h4zH% pc7ZkK%4GO[oqi۶mS$n:묳4tPYwN 0 m9rJKKvLQ\\3:tٳgu־S2~;aKN/Xݻw9眳[q9&LhlcO$C9=1TaZkƘ~)]MRo}g|g};!',]TZpo^-y*c|g 馛n2i~;K6oެ[nEw4yd曍Z=+#q6nhyιx|H xZƘ$I~gԶ'#P4z왖KcƌI˽2AÇ@n2٭Hg֞{;%NQFNhO>D ŋww=2àAڲepIьۢ(O k[kF"aT @vXgtR;}g|IvR~'})O+((gӫW/s=Dߊ|'|Ʉ TZZ;і/_Ç͛9 Çl͚5GKw F3Ƙ[蹾C x eee1ݝs%`eγ0 ɳ}v~3$[ct|^oSLQ~~ 䐣>Z]tikΜ9ܹFkhhЍ7ި8sρ 3a„km%%|hcO|w@seֻ-v!0M%/u4eұ1^z%}3r֜9s|'ȑ#jehر3cJ9wFFsKKKd j=2H[I8Ic=;!ڰaRiRzƪu];CTUU;9&SIIl;kz4c wιC$e9Pvsu4w.W^^ZnƘS%-c4l0YfNiι:c~Ӧ-\ի>])̙믿^ ZF|$]Ν5k,jwW1F~^u͚5KvXm9 a,)s~SƘ+;`w3*++ACs97Cf]lrpŊ3r޺u|'KٵdI;ԻᆱoS$Ig}䠡Ckg}۷ة<7o|M]{gl.AѸP)!-fs>gTuͶEj"S]}*BQ/D[s-QX%!f̹~~}(9:s_yV:3gޟu=yPdddRJ1l#ڿ;x1@%Β4Z&~"w!I=ztD۷N8$"VREzkڵ%{ rrrTJC _:k6m:թSGs mذAFGUTur$==}ڵk;Jzu ccK xug ]':u(77W|mۦ3goW](vZyk IϬp,#\GbHyw]JJʹƘK H$^{^xYW_}Fuiڵ5j~su crG ip222֞#zIpij6mRRR\ȑ#]g$N;uA[l ۷_g͚u/C5mT[v8ոqc;6!oXb넰kРrss;hZlƌ5l0!;8:f%%%],i$ۃhbt@Şy^cLQv1FW^y5l0%%Ə Raa댄ѠA mܸ1k0 kc֭[;9\nnınݺowuK,qQj޼'믿O?ӧkРATrrLeff.ONN@2-I@ 0Z$# I>oyWT,cLI8%j߮˗kptԩSHIIItqкuº^աCy6mڤ?7n\k,;;[kv8O뢋.rUڵ+}댄sF3Zpa2ha[+V/Bos0d]}ծ3bΝ6m댘WF _V\;#~YYY1r7]gr C@b |>;w7o^j׮4ib۶mzwsǎcӮ];5nu)ST~}QϺN(W7n#FhӦM=z~߹N!> ))IA-~S|ME!2h۶m.{nuA'Ntp8 JMMurPii̙ba+6ydڻwoM]' TVMӦMK5w\I'~髯ҴiӔ: @|RRR.]v`@Lc@xoyץk]whź 4x`) ^o}]zꩮs~[aYJ*իWX /YD+W@񋥛pƍouo5j233]gD=ܣ-[(RSSuwkժUرa_0tu ֶ)))`ʕl] |[kZkc>vă@ kV-[ҥK]$5jgϞ7oKuuQڹsgXѣVj'tc6fBoڴZn:ecegguʯTMիNm۶[nq7:,8q"Oq} [ ,^o*uKzK[`x#3fgէ~*kg;(mQŊZjsUƍf͚))|܋10`@X _]{9}WcB a:~O]g/_~iĉS~U5i$uIPuN̞=[<򗿸N999jժb 9cfJ\8*T0wٲeWdffp 10@ϷJҀJJJzH/)qP.\s5:s`͞=[|JJJ\gE7|:!͙3G˗/ZڵS&M²V8;v֭zuׇdggvڼyѤIt_~S~U?Y<딈:t~s7;<}馛4c 9׌1׸pdy-e˖]XFF^^dM6MyyySyuڧ]U^ >?uy=1g[k";M@yPfMqZf~m|>Ipl֬YZhQX֪_:taܸqe>`Z~}ʦo߾JIasxPTT.]h۶mS~URRN:uJDC;w딸b?{u 02Ƅ~]ƘJ]82cLsc`0x:1| $u=N:)hʔ):3\6rsse zeQXXW_}B!?> EewYgcǎ3&6l 7P<"O[o *N}Cz\ĝ\3#jI]8ڏڮC/0cLY) 5Gꫯt-1b^:,kURE{Z0m4/aYkĉ b,Peܹ:7]tEz]gD\QQz!C ȑ#uWf?km+I\8&3]O (' ȗOǗP(={jݺuS~S,2iWӦM+NrNT)¬EGu^II?`]! tʱe>6kA³g1ӵh"wy衇p°׮];5i$lոq¾ٳy氮yrrrTJ;v(;;[we馛tW믿v|>>"|1OnpT$:w߿?y^cI%MT8 9k=͝;W_5ʢD&M Ś8qb=iii޽ YAA:G0g5mTֶm\{C Q]gcL-x Ī%%%o:@|`@ k홒HZ p馛nRn\gܹS_~`ѣVuO/dƌ_"zcڵk@lذA7prT3gUW]s9GC W_}:\֭jԨ:@]x?4u #'ћP>1@ }3gq֪@_tYf:t,Y®G׮]]'c<$pS> ~!~#$I~ǭO.[ km?ʥiӦg1JIII'SN9E5kg (##C 4ZˉjծS+yh׮]#hԨ.\B!%%ٯS:v3fNAB!S1Gf՗_~/R?N?t]~ue3p_UjΝSD N;gy@-v|`a I@˖-;ZZKp6mաoY.RuUW_}]'"99YC M7:GP\\O#FSS"8st9p"77z۱c뤓Nr2ꫯW_1F5RvԶm[]r%:1299Y{NE>o^0li}_ҹ{9K.2++31bG @RJu$uʧ-[^SNT~}M0uanթSu˗+++KO?tķ˓1&k߾5j:TPP~@YkW_iԨQܹjժ&Mo߾2e61N jժ|U)))HZaNIJJ`!btxy1%(i.O6lЭު.L뜃ջwo={V-TPPU\Yzup|rss]' &O1cƸ@@^RϞ=ՠAծ][=z֭[:1"|>dddl)**jĖ*@;!btp\|>_yϒ4@*M(͛6mD<ճgO@vT/6lzJQn=TZ\ .''GUTq;_@O1crssuyS^^}]hNP˖-{9YҬK^:@bNȅ^=K߱c6=(VXS֫WO3RQQƎ?_}͛vmcإ{3aEEEܹn:[N/:uSO=U]vFou ;3Hpb-):w8V'%%% t 61@eV\\\ԩSc?OΎ;ԠAٸڵS&M~]ΦO 7n 7ܠP(:8p@ӝwީ?_M4ѐ!Cl2iǭN:7s[@ p:jر3jӦ넄SZ5vmή籭iӦjժ DyubW_}ÇQF>|~GYǤVZ[\- ܜ9s\'ԢE %%cr :TYYYQnzԡC_'//uG̙3]g FYFC Qݺuu7jʕ~U]'!}zŮ["V0:@7pnƍڻw I)s=uFINN֔)St'Gl^>dggvڮ3PH={Ժu\ĝիu֮3¢X222ԯ_?ٳuE{ؗe׮]m%!RnCpZ[8aÆ~;=#Q^ʕիW]'.55U{v(ٱc~)qbŊ1cϟ9aSZZ_|QYYY׿:0*Tp m۶u3D_"ZJ :{ vK/4*ѣUkuF\0hرjӦRSS5qD=qիuUWSc[%pPI@!܊wK(1:S]gK-;᯽袋t%&|&LMjǎ1F:ucǎ1cDɓuSʵx@7t!﮻Ӎ7ި͛7;* +Vh̘11^\L SGܹs0`@Fo^5r(***RΝuV)N5nܸ_O?]g /SN9%Jeb عs_mP"-2ƘQswanF ())qƏ:ƌ38#֫WO;v \ 7nP(rRnk|ySӟ"\Y{?'[lq|?ڵ[c̳`N:j޼y>,;aGtꩧjرa ///!vW999ϼyuFPvm͞=[UV=;skƌ_| |I')))v~յi& ʙm|%=> @λ $T3ua:!jvڥ[nuQ]uUajrիWC{3>{uFL\f͚s9׸kj*=QF"/==uA;wd w'c=*Isg/㬵;Dt8aȑ#uN9/:!ϟ#G8#Fi=zZjaY @b BѺu\ĤdkBI1 FXk9*ϧŋ6}넨۷onfB!)GԪU+u]eZ]vjҤIZ^^8bŊ˕AE*U;Է~w}Wӟ|SS8h1| p Ndee^hu w r 1jժ|M5ouQouĢEO8j֬ XײUvmpdʔ)=z댘ЩS'1"*JJJRǎkƍzꩧԢE G*iڴi+5ɢE\'#~)ZCcKJJR Թsg9Rׯ… եKiiժU***r<+W8 *hʔ)Xqmz¾1JMMU޽]g/pT-k9`q;dmذAGVǎUjը\kVkrcm6pv 6,7cu #&)~\s;H] *SN駟:uB Q~8}***RϞ=dۅf͚iذa>!۷}QNEEEܹN;49QW^=͜9S'tթSGS~ l2-ZHK,Ѳe_zӭr|1{$ = ZkI*or{0L7X1#~#2;su(,X:`06l#{5k,-\>rիWB:uԡCۮSƍխ[7͙3GII^f͚S$y38kjڵZ~6mڤ-[h֭ڹsݫTJNNI'jժvڪW7n-ZoxMi>oJ0^{o H1pQZZ9sΈ <:v(\I&yڽ{o~~=TZ(СC5|p)QQB͘1C7vr*T&Mg͞=u>Y|EKc+Zkoas{6ϟ۷Έ ɉׯ'|7?s Hħ۫QF3c={uFc4n8iu bԩڷo y_\(S-$cL`087Lvl1e 1eʕ:t댣ӧ_m*===JEpX(RNN֭[:%xtM3+ƌ:@ UTRIn IޠAW,X@9uVM6uF1b>3G5~xviGXWnfURu۱c:߿uJDp_'(xC0-$IקMOup iԨQq;t)R|*((':0jѣյkWYkXzԱcGGe/KnZ]r%3ݻ_tVX}jɮSª]v7n zuyރ@`*\V\5==LJ:ޮ]sϹΈYk׮=ܣQFN9Ν;oԫkenn1sQf˗/ׂ \g&77W/a7R L2E^xrss]E&M4c +X`͛7uWޖt c),,7d7lذ|I $p@{ᇵ}v1m̘11=5j>]rea^z% aC_4kLZrqwjɒ%3ʬvښ={V:" 鮻1O%](-tծ]]`A%!t$5kguBz]vN9Uj„ JJ[=zZjǏ?Yf km :1H]t֭[]ɰaTn] FҲe\g!<[[TTtO\iii3-Ztdž:Ѳa 4uQo^yyy2hs/uFL4I1~٪] Ĉ7[n BSN5m4ׯ_WpD-[^R$Mq@VTivAAAe!~t$Ç>sQL4I3gtqT?rrr: kƍ:#nݪӧ8Ljjjm># :u ۷ovaÆNoԞ={\Q<-@ֶ)))`ʕU\u Ν|uFcU>}bJ*iĈ3sv/#۷RRR\g Yuaԩ:@ Bڵk]{ァLA)4qD=33׬JHpUPaeb+ |_~uJo7p6oެYfΈkm:1fǎ]ɷ~-[N>P>}du/^hu Ȭ-Bм+VTwp 0֯_6mhƍSB^^~'1m*..v1'Oց\g}jԨ Ę+VO>3ʬHwy.R9`u9_?߿I ydɒS]8t$˗uqy+۶mm:#fYk5~xuVM6u1pW^ /:#,>#ٝ ٳuWk߾}SZlRJ[k'n1yJJ`0x:u~pwfΜ &ΈIs]gD\nfURubНwީ%K]vo߾իWΉkƍSN+~1o8pY(ZxZCtĭbu]ҥ:'n # 2uFm޼Y}QzzM:z饗ԬY3-^u DMff"k텒bo{! q4,))G~~9CDqXFR OuRuֹpZqƹΈm۶.//ubc=w}uFD^Z]tQ[o1/u%o߾ڽ{:߿.55"I \ D:HT P۷O?;<~ڲe뤄w^$fΜ9Z~댨3߳UvmQZhڵS"@]vUFK/uRLԧO|>}駮sf͚bBD-@;?O7p$"(k}:5`mذu$}gz']g8Gڧ~իW8Ljjz:1lΝ]D_}}ݗ7Ɇ 4h 5h@cǎe_y-HJ;dw6c t?y]tEjԨz)m߾u_Vr͛5sLNXkc恾}*%%ub؊+ԧOQuV=c:t_O?Unty|8 KA/g~ tĬb}gzբE թSG ŋ~XVXX={uJԽ*..vɓUTT:0uQ\g ƽ+z\gDM(ܹsu7VZٳfΜGyD5%\7x#_Xy1] ĉ˗tĄRYFo^PjԺuk 6LK.U(rcCΈ*. IDATkƍ:ém۶iڴi3(//uʁkŮ3nݚ2e:vN;M;wք ?N+e˖Wz׿Uk֬q<%%I_nVii@ u  BP\?u<*--UQQ߯={hΝھ}~gm޼Y6lw}uow=>?Jedd}mc*TubΜ9)߽{wi߾5jt9: b#8p@]tђ%KtꩧqbϞ=>}O.c5jm۪ujٲ֭:8+VhOk˖- nddd_lYP(4MR{=@:]K^u ό6I:uOvql͘1usZJ5rr{N rQf?7>c\g j֬)󔑑MqjذT۷kÆ Znk}WZbV^͍(G-ISFczn/Ƙ}>_ ^1@@T 4HիWwqVÇ,ԪU+ٹsF:rssUfM j޼y31F~֭:uvڪYjԨjժJ*:䓕Cvٷovޭ_~E{U(Rqq ~lǎںunݪQscā1Ŝpa ߿u:c]1%Ur$]IIIWfff.rě$oYkۈbBЇ`!@aN_tU[TZA~~~[!@D\OOJ,i cK]t5HJJͮ[b1/CXDUffRkH$;XDP\\J҇[Db}* u'.]vZ;u H;Xd\Iҙ# $mq ey\<D1|>;X7!Z-i QXkb t~;Ƙ?Hu @\G:>/I+\ @  0@1EZ[28??9k @iݺuu Qc珶-+Iҙ# $mq| wHzJ<D1f\fff_cLu m|1g1JH˖-{Z, ? |Hu 9`po&\ $nD `!@0@FFFƿ*U3u OKK:\IOO߳vڎw$lIo\ Ҍ6I:ur-#ďƘA OKKnذa Rf-NnUvzg\k B߻?VZE:Z|v Yk/X]ą͛o:餓.4u ږ|r*CpbFzzuu֎t$ ?\xq \6I:ur-#$`08Z;BR -^wʊ'@\|#Hsc>ZbEu!@Y1@qt80ɒ%ʂ:kˍ1-$-s3cL󔔔`t-b!%%bI3]qY(ZxZCa\Iҙ# $mq qYkӒnjkm;x:HƘywH]R 52|v(oyިP(Qn-@kl`…tfKjm y'|T!`y+.t+keƘ]wǂ:Hh>K$c:-u $:@PKp$ڤ`0[8^'$cBi/u^u]G|c$]-i XkkHz3???u p$  {.}MS$ PH26v f*Mrj,PZZ {xz0ᆑScI5HQ )${5?:C?|_>v L̼rSx8tteeˆn ` .|^DF0>! }~g)kyƱcnʀJ)m}mD\=0Aaa9#NR4131"n Q:o߾!a@8%^m>'"v L6ma@8e|aD,nIPJzJ0<;wǟv L'^_;J`"[kGcxvj2 nn1wbvvY۷o!L/MӼ>"^=06 jG0 in"HcsjG0 d~~]333ωn15SJyC`رRʁ-0.;p֎`:VΝ;?|رwn1tkG0J`"[kGcxvz̲x'}d_m۶C..H)%{51ԣG~g`z)|]Dc%>tuvrQDv ϩt1n糳Fĝ[`R.t1۷?p]_c{j0]J`"[kGcxv(̲tsfv M];RJvkK)/=0¾vÀPQxQR;a@iwgWDj;p֎`:F@{o)egD L:v9zWG[F̿t0]vvϏk(/"ɵ{`en`@f=vjV`VY5 R-0IJ)Od3۶ [`B}v&4 ֕#bvL'`;cYgxB QJ2"n gc& ̷EĶ-0Ψd3t:=[`e&Q,,,|Yӹ5"v d3<;K)/ j0K)'>͇j0 wޙs9R`qkD:0֖ԶXXtԎ`t ǎ{Yf)"\X; L:0V2,--}C=ts)3vJ)[PjZ; gG#񵰰UNgODj/yv t` gg[ut`d m۾%3=+0#;شqgkJ)Oԑ9Ta@Fƾ}f7o|eDOUJ L:0wm-HYWtڶݓRj.t1US)+++1??-V\@eGĞ[Nfe{jZ2@%2҈xްawk̀o7WFY{I)gڶ}矿\փI?#"^ZJySD|NGf뛦! /E9[Gĥ^kz3 :"d[K)gffg5` ,..-3v IȈsȑv5`8psgff/=Ѷm/zSj3*8|?̼:">vImza߾}[lyo̳k|{D\k0rKf>v )xӹbnnj1)Z\\{"⹵[NBӹxnnC`$-..~IDQTe揝uY=sOnQe@0 7DĕqFSRʋyGutx?3|Mf>"6x`ff;v_;Ɓ>Cfv̷DxRRJ֎qQjZ; gG#,,,|Cӹ-"v yI!0n\@Dn)eOD-Sflٲm۶ȀT[ZZzFfޜ^nTf~ry{wgtw'NxS۶/3k6lXwt=s#G^|m)kw_€T2 .9zM/prY!0I #pvDQJyu!0m ů=qaUtgfn!0 ~Rm-[V0"nnWj208333oFLUtofzwig@`:t賆"xbUӳ?}Q{9s^4oϭ>RJyQ!f@`,--mognXm=q v-302=m~e5Pfi<<:s:-][bfz<2:ωJ)We{@f捽^ov aÆWR͵{3^wGX7 g[J)_P`d/WܹhJ( IDATD?"֎@ _Ey[J)m^~v p\:Ξ-ku:+Cǀ _7GËd;ovcπ?{8^/3k۶d~~jπ{.4~=v :PD~:eJ)v @1_|C:;Ϟ10}>QJyU!@}>LC}p8|mD6"X?Kv0:X_{Y\\|p87"n 90}y}^x Sd0|Kfv @%m{~~@`NgOf-koCd@` t:Dŵ[*HDiR;mt t]w=3θ!3 {*ܹõCg@ ۸iӦWR-{*d)nCa@ E[" kT֟dǎY;/v0#pvD/"ɵ{FA)]qE-0,{ر#{Fı̼h)%koZ; gG#Wu:=ѫ0B\cǎõC`kyypڈT`D}(3h杵C`ݻwsyp8|s)jw +/ `qq#ֈxv`Dip aiiim=-#n۶Ͽv#1< t:ok({Fذ{/xv 1)GGĆ=,3rfffBa@8 ۸e˖We#bKQ?W}v 2<,..^ZJykf~a1@D!Z; gVB#b{1_ggg_}[\|`="dn4Mk:?O/ܔDDvXٽcǎp [J)F+#bc1PJa [ZZm=qQ)vX*J۶/mHZ :xڶnc/j h֭_3ž}}{_ Xuzp89NǾ/0 |XEzֳg~gjg?t&JBD\=_jy]4?\J1€{5v:V;`4 z'3R;`m۶WϿv(3#СC_<ߖsӔĉW^tE0 Hؿ߭p2"<9ds1"~t֞vn%"| tވi;k ?{YgsD03Ž^7kP@ﭬg< :05MCt` 2^!OӢ-ܚ;<~_;_|#nk0J`"[kG]zW t`]R~wyy<9:6MC{{kc;ڈx[f~qXmK{CT@VMfv9:pJ)m^[2u:+CtXDRJ֎e@۶d~~jj1"K)oߴiu۶m;^;V8)Rnݵ[`-tjcfffkxr<#i~v5:H03/z|R1^ mw/֩;zhc<`Z@>/z_;jr7yMz.`:}nsC`T`If^4}C`x03o3@pO۶Q&Oѹ@xa4v0~gyy<9<0Y>YJd7tKvC`yJDܜsc,3*3/-0\*±cǶ`u@1SJhDv L:Rʻ"n[``<kRv L":C333رpd#j#6nx֞ tMӶe:Ns֗ tG2^Wj42(m{j2@]'"*c`<<33{nn` S;PR~`t@̼iw> tX?z=9d:59I8$Yϫ˒-miK9PJϥUw]՛q=n i溮TJZ|N $\ajruǏg@wD\VUջK̀K(zstt[4SJ{/6@p,zc|||t p\"9rD@񹈸ltpj p322rJ΀qEUUR:8}t85z}؇KV:BJÇo1`q'#)FCN̻92f<#⢪~t ޗs>l~t ͎TU/r`yrk>TX^#k͚5g5 9 !9FJ@`~+|pJJFۥCa4px  c9kR.:C!|Vmjt Л|A#f0:Sn?+> {8Q.4_l6K)-p`{/6:SJ;Ft\зRJ!0:^~Wa۶m}K_zڵk_\XZׯ/H)}vaanG* }=^GDt}SJ6ϗXvx9+"ѥ{_+!`2fjjjdڵj7䜟RRڗR1>>~t 0jj~bݺuL)xIXH)rСXRv{sDLF٥[;v6XvyqGDTү^M6}t0< t:O9EĊ=/DEUUA`EgϞ5V""u{KsaaUgygJɀsmff漜=#quUU( 7:pʦ_VnoDt8iv]}[[ݜdD\l60'aff9 ^+p>R:hu <{qǎ{kJt}_l6 C:xÇ!"Ǖ}9"^SUx(tSFijKbddOx8tt:'#bt }o.|mUUoO)1ĀDDDzaJiWD`#b{UU8QtrϜ%"ΉZ^_n57n+p2 0ݻnʕ/5{L)h4t0iZ+"5)"≥{ )3rSe@!nEmt pJF7J.: v1gn`UvC`@j#tgDX UUݙRꖎX,t@{j^)".z圷7Nf@r=z*"]󮹹lrtR0Y~9"⩥{,).,,?11-Kɀ}nffǻ[<9?jn4/ ЧZY)Ɉ- /o6tr1@i9ߞR- #bGUUXNtV)"XQ>|֭[ΗXntq{Yjժ7Eĺ= {#bgUU{Kb@su:s#█xFW֬YsMZ$:NC9;#Ⅵ[h_9la^`@j)]- ?]XX83L^a@ts~[D2<Dzg^ {7??mutsl6t@/2@\uСץǕ`uSJfx^e@esNNqkDK#:,VV]s."T79foJ3:,Vm- sׯƍJ;:VuvJi2"6n`?R:(0( p  IDAT=tgJK0vX38˥CN޽{bŊ"₈)9Rz]!Ȁ'`vvWEU= N)h4>V:`Pa޽aÆ #ƈxjUUJ)uK 2:ta!<8:+^_""RJ=v7olsNvڟSɑUf]Cxdt^ښRt <@;缣l]NMnwWe[qGfyt '΀@t:O9FDt/$(jvvǏ2ƈxLx09OD9UUMn`@ݻw7lpADO+wj%_)2F-0EkoCXtD۝nGW9sK| ,j#Yv,tdJ[:K~uXY!a@`MMM^v)7G=r[n=Z:r ,snL)RN#UUU!g@`Q;#bt ?Yg!:efff,+-pRhzzSjR5"GDtw6J{ vݷD#bu8A9?ܶm۶166!3555nݺ#xr8 qGcot!t~VNE9/` w!333NFĖ-p#Gpg_:a@;"'KJ)})".j4Wc@pO!". >R8h|t ɀ0Z֣"ʔ#bm8 GsoSJt ˀ0`v]߰aqcDR:hU('sN333;rηFijJrJ)V۽C[@V/+)Ko^b@N>#"vEn=3t:04fggpkygDJ2;sK)1Ћ kZ#⚔"bM()Fct2:0Z֊4ֈxb( G/>|[n=Z:zHv{[DJ@!vMLLYt`t:ɜ[?v[lR't` ;#GK@A_l6KGt۷z8?"{яn~e@ҁ377Ɯ=Pc۶m c2555~ #ƜSJ@aRh4ZC`j~"t{D|G(-Uf[`Pn7GdD]JK)}vaanAc@zV~^D?Uz.l4/ȀNqqD(=kqEUUZ:{Yjժ+"XWzAJi_Ji-0jrεNsUFĭa<͇z tj;#[;[:(j5RJ}[ի/۴iWK1jff99]x&BD\TUae,;v)FĪ=c«<ϔaf@W:t)DJ@9WWU!X"9tGĭ=Ѓf"b{UU[: t:/9FAݜdD\l6X4V)][G},tN!73mXXX5"ΉZQݼy!3l޽V\t/Gk!3'jפ'###玎~t IiZ/O)J@9_[USJt pb iqVqUUS:89taZH)?Vz\_n57n+<:z~SD\=>R:hyo0;;7Fĕ=RJ;22rg-1{ .#⩅sN)hF`qn{GD|GwjP:X<tbV묔dD|ws7TUugJ[:X\tBVkCV=-G.缽lvJKÀCj=1"O)]+J@yU[l9R:X:t{YrSJou{_>p{KKπ,\t:oN)=tjW7ϗnT-gsl!2j-ЇUU[:X~tN9E+o}8Y qÇoݺu| /s=6XUнC Ч<СCjo9?tYM6}t PL9u:WFĭ9ЯP.!@0@iZ[SJQn> y晟):j]C[7VU!@o2@ۿ3ns#VX'缽l]wݻw݊+GģJ@릔vu1@o)VV]s."T"bg?C#:O>s0ǏQU8a>ZSJt /G%UU.:2==);SJ?^ğs>Y:OtXf{}ȍ) #bt h|J)篊"1{`@My{!@3۽{w}Æ DM=0 r߯_-7n+ :,Nc9;";K9"tnUUQ,tXgjɈ-0`vX38˥Cc@E4==Zv{Dl+pJuF7Kˀ~Š+9_+K9FcCf@055zڵK9s])n`kN眈9"t v'&&fJÀ'n`Dgnι7nٲH`̌uɈ-0>R:hi`8ZgohX*s~uB`xyaffn-XUWSJ7_+0R:źVͽ.|mD1==Zm2"[`v;&&& ovr/+C?J<:C<=|KD=0>Rhqc@`u]k׬YxTt);v͛7t #)ˡjH)]GēJ8sw8Q.xNrηG-0$nwߗ8tjdD|W݈#|c<^:d8;#'JfyWSe@``>yaaƜ#bt oϿ~͇K:}ovvǏ2tUD-"n{I-@ڽ{w}Æ GM=0dw^?oll쓥Cn4"n!s4"i4Rʥc2333v'#ť[`vOLL|tR0[nmw,,Rzڵkݸq\2R:w"5t '"✪J,5;ׯ,|MD/Cwj%_) snL)RԡxmUUtr23ZֿI)튈-0*|Nxf@N39痖n!v,tdJ[::ŴZgnQ+CCnwL ,V>xCD.C,q_u֣cJ3l8ѣk# {`}:"^UU*+ ,syE}[J[K>묳X:XRN9Ɉ(WSJ5_/Ћ ,N-@DD| 缳lW:WXTViZ"^Gn۶mB^f@`Qu]kW^}uJ銈xT ""vJ:ejjjdݺuG=?Ց+FGGV:_s="t >TU'C tN̖n;[J?~͛7t@?2pm wDOnSJW6_. <'U׷}t@jWϿ1"֖BDܑsillxAo{sWnQ9/0H\ ZGĝ)M[=>!:t9]t RJ_nTt!7;;E~@OJ)YDh4>U`yA 0UV]F=:s~sUURʥc`LMM^n"⚈xl!cccJ :99["Y{ԍ^M6+0L C|۝L)n?vs&&&t02 v}FDLFĿ)=K)^hN\t߬nu>Rz|J{st:ɜJ''zc|||t ft3339*/Gĕ_/sPPyR("VN"₪S:g@(j=V]s:"֖Nɟ\8::!,:I IDAT29fff^s)"Q8%_+!,.:2~YV3"^P8ez}؇K KnW+"t pRJ:t[Η`iT333YXX-"^pGRJ;JXd{yUFĪ=iy#G.;/3,:|"-=ibD\TU`NS9u:qkDl~tˀp:KrΓ1^8mGSJW#K n"J/缿Vmo4*@9t0;;̅[ez_=CŅ tDž&R**]frveP٭P3-"B`\F1sO-6rdf\Вs><L-ˆnADpO۾}1e@8ܺq'R.3jkcyQ4S;`@^oCDRf>5"RX`KnXF,,,\ύjk拙KMӼvǀo,,,HfrN`M[]]sxFkz޽3ӵ[5um=3KFz^{fff~-"3{5u]fiHFZ_w,--=q=*Ǐ?Ͽv L}͞y晗RwO KY;b@J|^Dܻv J)tGwy1S'3 MGw߫2maa,p{رc:Wj0= *dňxND|_`]=m1#iaa?Enn޼۷vɀ^wvf^v n>o͵Cnt`$>|ϊ#SX7s9k[7nRqF`ݜǷm!/ @^oCyd)ʈK`]-Fm_;Qu~!3WJyi` J)/(x(r^w|aDܧv >5M!pK :t?f 2gjUnyyQ{!pk i۶mKctt:+BOfMe mWf##bC|#v- )9p7n"3g:n浵C`-[UJK)T\877! -ZXXQnm_10 t:th\Rvw~&:+<'"~1?/--=;Q;/X\\`0xJD<:"6DăyGX/znMǎRʓ#ε{PJ|X4:LRJ.,,|ND=r)nk@ t2^̼:"-HywDi!PġC~\Ոxǟ}Ԏ 0+<+".=H1".l`tPܺaÆ'Dq=h)3θb_€mGDĕq=\ӹtnnOj~FĶ-HzCڶ!0\8tw:FĹ[t""׶oQf@1vСt?[YRn!0 0<ݳK'YomW +r~cȑ#w\^^|\D|G`d}4".lok8qc`޽3guC#=s˿|ƀ#t)[xd۶{k2Z\\ WGďnF_\k׮Oqf@sС{u:E/['5M,c`<wߵaÆ+K){Rn!0) Pپ}6oٲ|bDYy3<۶m[ĀR:~xfD=+|"3/nj$2@ D-ظfÆ ر C`R`-..*\UJ-8ܶj3:zD8űh~Cx`xtDlRʕm^10- 0_ƥ_R\+ k1*; ZZZzywvL#:Cݿ\-|H4lvÇo WR~v 0RJyX۶:~33󒈘/eMӼvUt߿3xBDJDܡv0RtݣCe@So߾٭[>""wxѣG}֎o)?7 _[7 =5p+ /nګfggeΝ_2:| G]kKyk39rR§N!3~ɇ{:DD׻CDjf>."ډRckwޙ:!k={0 vvpZ 5"?X{x~)nwv pz L~ߍK)LR.vkqС{u:Fg J)]YYy{v pxMk/3?? vXX;t&־}6y晗RwL|gD\4ͧjkˀ)tRL#IMFf1301KKK{J){&{jc@`߿͛WDkd拶lm۶-Վkv~ƍ//\qR'"⢶mnև tN;+"D9d8 ߛWVVvkǀ@5~"bK`})3/owkˀ;r:"-TRʅnh`y*u.^YY.Rx`zkwL/ܪ^4CSJyCa<j tRJG[RʣkDJ)~xH`2e_j :ߠmE[t2"4 3sP;`t۷osfQD-)\?33gnnpoS;Ѱwޙ[ 9JfnQ׽;_kwSmCD{Vf>v0q޴tv5c!kPW׻,3_^(7Em۾vma@b~J){Ë$̿pΝp[LTRX̧x?f<ƕ t)wEĝj㯔򡙙=sssjL׻Gf#(vDI0[;s;gEkc"nX+.D)iӦk"jcmgmk<& t)W"1mNa ߡC~Yxy8}fffڵCCŐ0>|N|f泎?~tp` D]kc2sO4_;`=F`gyK)?\K9q.90M|`Bz7?G۶!̀0:tNӏ3kcK)tO7& 7ܰo 9pnͽ,3KZ رc/̦v0J);iW6OL~R;kwca/ܼyӶo~v (0L^w.3Yy̋!S;5,9dK);:X\\ 3[̼i?0 -cm?nF־vCFlnNRٵ;tm=3KQ w1#bS`\{9R;`\tjpzJ) 9JD'eyH`0d~~CƑ'е^gff-[PJ'O>|q` ̼$WTJyt!:(x?;;{Ν;?\;`tjp7; ^Rn9"z֎'Ȗ-[kwU}034Mӫ0i<0&رc?l<X.FÇuu}1SmۃCF04͛7_}/f.F׾}0$\D>0luul9p0ڻ|$"6n܉x|۶/7 t4;;R0y#bw۶7s0b9rǕODĝjkfPJ:"vk@1+++&G3mU;[ש*dD\^X3[^^4` @!~vp}!".k!::hyTvًw!6Y;WJy WKm,c\`pif`<]{jp #`޽3mV"%[n}ҶmۖjpF=yFkw'3ivkÀ0\x7>bǎ_nqqN3v mG7M!=  x`ӹpnn#C:@}kjm_1 '*:r|,{ n_;f?sU/_ZZjeo7M-/WzO`dR3ؾ}j0Z ur:::rFw iqVWWW&///lxiq lvoƛ`}ݷvLx׮]Ӣ%3?[&RDy۶mKc<tc@TJDf^vv ˀNJ)2vk6nxَ;P;fXܺaÆc;`_nuC.M~h0q̼i`z`0^r)ʶmL}2c`bSvwq:V;F?fCyGm1SF[J)v.=x_KyE4_π0dN瞥0*Rm{v[S`D3=znk<`$@Riw`03??m5.,3^*zVmv N g@`\333sv50u\ Q)e&3kg8jj@-tᲞ0rQXɀdf^977wufj@mt! p tvS;`eJ7J)7?@R u>vv"õT;+++gmk<[`N`m!0 C'J)3^P;Ɓ'h0TRJѣ?j<S`2x `C`ܸ@Rk70U^9;;;g<`N_̼m۟2;SDܥv733{׮]: `Fs?~_9=RʇK)]T.{oi<r0|xGÛyStHOf3".iƧ@`c+7R4K3Ԏib@٣+++3Gfffvڵ!0:&Ν;X67o|q>nՎ`$}|0\4??׵C`ڹ@X R:9)_,U733sΝ;?\8=pXG |ڍ7csopXG;X왛;T\ RoGĜ& tutرknݺjp)"vg`m@XG;mgmk< `틈mxL۶S;묔M`߻#|[Ǐk׮Վ/kL^ܢ=M}`@ 3Q['N20VWW>33S;omvP t 9眏G{jwy)l9L7d[J);jwL3sss/R;:@%o0J)3m7@DDf^2; "^ym߾d`tx|SD;&ui#C wPJ Do?~|x#`qqNv df^4_Ɨ t077ňxcqTJsWR^#7Rv}Xp! 0^s&'FH)FrD<ѣ7k:ٿ38v `fiW;L.Fw"յ;FMfar0b`08 23{`gFGJ)\`5"6ev߬ruf|JҶj#+ܿvzk3s [ w h53yر6@a~ݥsjw шӶ!ts0J)Ϫ0dy]s`@q "[`}."޶k #n0y& t1v?OL| 67X)%"~[w<34kk t1e0\7n&NxL:`aaqqU`,R޶ 2sP;` #⾵[Rnۯ^<02st./n&}z]m1 )$@s_:):jT @!esΑeS'@$-dlqm$s眫Fڹ!8Ҭ׏xcW<y;7^}>sss]90n\"Mq[`e"n{O `0;"^_XYJ)t:Wuk2Q;UJ"3g"k+RMy\B~\DtjVVivfkwbDp`*tg#gjʾ_;`qJef;11[塔o50p8Z;`~|rqCu0n ;vٸqqI wz?̶v 82]R:ӷRܗ۶!S;+3n{mDaXnsaeWTz ~qfj RUMX;c@`I#yj̼];# tD4#bkf]%3?p`er*t;2/t̶v/cb8T۶y]p@n{d8vR6Vs~̼1"NKn!,:Ş={~nЖRno1,-:M)3D {HR˚]cÀq7 ^R^S]ׯrӦM1PE)%(qD\6"vߑv ǖfff^'qiJ){#j0> , 5"ά;PJy磏>zGc8~ ,;vXqk2R){;%3?2??m۶=V;π:s/"Ωª_mokfv ˃c8m2sKV2֭iӦMԎ`y1RrzzK)3jb<7gnݺ1,OtVRJË""[)3Ѷ֬Ysc@`?oPJٟ}k2X5J)חRGDDMYb@`ٻwFk#⪈=sɶmonjrXyuxcD\aiRw:w:nٲ嫵{X ={tK#{x#3q=۷o`00V|z]D\IǶmXV':ck׮][ ":xوx۶1~t~ʈ(3%"~2"&*'RÝNJ)z=:?w~/m|mDlݴrwӹ~vˀΝ;'6lp^D|) ߟG뫙ۅϞ}];" pDNx3/kRʽi/ĀGazzGyyNDl8rVM`D_J/3ÀK333-..6%"6GYCӎ[J鹹s=0qk׮S֮]|uDrzfnqBeJ)"b_D= j.offsetRecords { j.jsonContent = list[j.offsetRecords:] } else { j.jsonContent = make([]interface{}, 0) } } return j } // Limit limits the number of records in result func (j *JSONQ) Limit(limit int) *JSONQ { j.limitRecords = limit return j } // limit return the number of records in result set depending on the limit value func (j *JSONQ) limit() *JSONQ { if list, ok := j.jsonContent.([]interface{}); ok { if j.limitRecords <= 0 { j.addError(fmt.Errorf("%d is invalid limit", j.limitRecords)) return j } if len(list) > j.limitRecords { j.jsonContent = list[:j.limitRecords] } } return j } // Where builds a where clause. e.g: Where("name", "contains", "doe") func (j *JSONQ) Where(key, cond string, val interface{}) *JSONQ { q := query{ key: key, operator: cond, value: val, } if j.queryIndex == 0 && len(j.queries) == 0 { var qq []query qq = append(qq, q) j.queries = append(j.queries, qq) } else { j.queries[j.queryIndex] = append(j.queries[j.queryIndex], q) } return j } // WhereEqual is an alias of Where("key", "=", val) func (j *JSONQ) WhereEqual(key string, val interface{}) *JSONQ { return j.Where(key, operatorEq, val) } // WhereNotEqual is an alias of Where("key", "!=", val) func (j *JSONQ) WhereNotEqual(key string, val interface{}) *JSONQ { return j.Where(key, operatorNotEq, val) } // WhereNil is an alias of Where("key", "=", nil) func (j *JSONQ) WhereNil(key string) *JSONQ { return j.Where(key, operatorEq, nil) } // WhereNotNil is an alias of Where("key", "!=", nil) func (j *JSONQ) WhereNotNil(key string) *JSONQ { return j.Where(key, operatorNotEq, nil) } // WhereIn is an alias for where("key", "in", []string{"a", "b"}) func (j *JSONQ) WhereIn(key string, val interface{}) *JSONQ { j.Where(key, operatorIn, val) return j } // WhereNotIn is an alias for where("key", "notIn", []string{"a", "b"}) func (j *JSONQ) WhereNotIn(key string, val interface{}) *JSONQ { j.Where(key, operatorNotIn, val) return j } // OrWhere builds an OrWhere clause, basically it's a group of AND clauses func (j *JSONQ) OrWhere(key, cond string, val interface{}) *JSONQ { j.queryIndex++ var qq []query qq = append(qq, query{ key: key, operator: cond, value: val, }) j.queries = append(j.queries, qq) return j } // WhereStartsWith satisfies Where clause which starts with provided value(string) func (j *JSONQ) WhereStartsWith(key string, val interface{}) *JSONQ { return j.Where(key, operatorStartsWith, val) } // WhereEndsWith satisfies Where clause which ends with provided value(string) func (j *JSONQ) WhereEndsWith(key string, val interface{}) *JSONQ { return j.Where(key, operatorEndsWith, val) } // WhereContains satisfies Where clause which contains provided value(string) func (j *JSONQ) WhereContains(key string, val interface{}) *JSONQ { return j.Where(key, operatorContains, val) } // WhereStrictContains satisfies Where clause which contains provided value(string). // This is case sensitive func (j *JSONQ) WhereStrictContains(key string, val interface{}) *JSONQ { return j.Where(key, operatorStrictContains, val) } // WhereLenEqual is an alias of Where("key", "leneq", val) func (j *JSONQ) WhereLenEqual(key string, val interface{}) *JSONQ { return j.Where(key, operatorLenEq, val) } // WhereLenNotEqual is an alias of Where("key", "lenneq", val) func (j *JSONQ) WhereLenNotEqual(key string, val interface{}) *JSONQ { return j.Where(key, operatorLenNotEq, val) } // findInArray traverses through a list and returns the value list. // This helps to process Where/OrWhere queries func (j *JSONQ) findInArray(aa []interface{}) []interface{} { result := make([]interface{}, 0) for _, a := range aa { if m, ok := a.(map[string]interface{}); ok { result = append(result, j.findInMap(m)...) } } return result } // findInMap traverses through a map and returns the matched value list. // This helps to process Where/OrWhere queries func (j *JSONQ) findInMap(vm map[string]interface{}) []interface{} { result := make([]interface{}, 0) orPassed := false for _, qList := range j.queries { andPassed := true for _, q := range qList { cf, ok := j.queryMap[q.operator] if !ok { j.addError(fmt.Errorf("invalid operator %s", q.operator)) return result } nv, errnv := getNestedValue(vm, q.key, j.option.separator) if errnv != nil { j.addError(errnv) andPassed = false } else { qb, err := cf(nv, q.value) if err != nil { j.addError(err) } andPassed = andPassed && qb } } orPassed = orPassed || andPassed } if orPassed { result = append(result, vm) } return result } // processQuery makes the result func (j *JSONQ) processQuery() *JSONQ { if aa, ok := j.jsonContent.([]interface{}); ok { j.jsonContent = j.findInArray(aa) } return j } // prepare builds the queries func (j *JSONQ) prepare() *JSONQ { if len(j.queries) > 0 { j.processQuery() } if j.distinctProperty != "" { j.distinct() } if len(j.attributes) > 0 { j.jsonContent = j.only(j.attributes...) } j.queryIndex = 0 return j } // GroupBy builds a chunk of exact matched data in a group list using provided attribute/column/property func (j *JSONQ) GroupBy(property string) *JSONQ { j.prepare() dt := map[string][]interface{}{} if aa, ok := j.jsonContent.([]interface{}); ok { for _, a := range aa { if vm, ok := a.(map[string]interface{}); ok { v, err := getNestedValue(vm, property, j.option.separator) if err != nil { j.addError(err) } else { dt[toString(v)] = append(dt[toString(v)], vm) } } } } // replace the new result with the previous result j.jsonContent = dt return j } // Sort sorts an array // default ascending order, pass "desc" for descending order func (j *JSONQ) Sort(order ...string) *JSONQ { j.prepare() asc := true if len(order) > 1 { return j.addError(fmt.Errorf("sort accepts only one argument asc/desc")) } if len(order) > 0 && order[0] == "desc" { asc = false } if arr, ok := j.jsonContent.([]interface{}); ok { j.jsonContent = sortList(arr, asc) } return j } // SortBy sorts an array // default ascending order, pass "desc" for descending order func (j *JSONQ) SortBy(order ...string) *JSONQ { j.prepare() asc := true if len(order) == 0 { return j.addError(fmt.Errorf("provide at least one argument as property name")) } if len(order) > 2 { return j.addError(fmt.Errorf("sort accepts only two arguments. first argument property name and second argument asc/desc")) } if len(order) > 1 && order[1] == "desc" { asc = false } return j.sortBy(order[0], asc) } // Distinct builds distinct value using provided attribute/column/property func (j *JSONQ) Distinct(property string) *JSONQ { j.distinctProperty = property return j } // distinct builds distinct value using provided attribute/column/property func (j *JSONQ) distinct() *JSONQ { m := map[string]bool{} var dt = make([]interface{}, 0) if aa, ok := j.jsonContent.([]interface{}); ok { for _, a := range aa { if vm, ok := a.(map[string]interface{}); ok { v, err := getNestedValue(vm, j.distinctProperty, j.option.separator) if err != nil { j.addError(err) } else { if _, exist := m[toString(v)]; !exist { dt = append(dt, vm) m[toString(v)] = true } } } } } // replace the new result with the previous result j.jsonContent = dt return j } // sortBy sorts list of map func (j *JSONQ) sortBy(property string, asc bool) *JSONQ { sortResult, ok := j.jsonContent.([]interface{}) if !ok { return j } if len(sortResult) == 0 { return j } sm := &sortMap{} sm.separator = j.option.separator sm.key = property if !asc { sm.desc = true } sm.Sort(sortResult) for _, e := range sm.errs { j.addError(e) } // replace the new result with the previous result j.jsonContent = sortResult return j } // only return selected properties in result func (j *JSONQ) only(properties ...string) interface{} { var result = make([]interface{}, 0) if aa, ok := j.jsonContent.([]interface{}); ok { for _, am := range aa { tmap := map[string]interface{}{} for _, prop := range properties { node, alias := makeAlias(prop, j.option.separator) rv, errV := getNestedValue(am, node, j.option.separator) if errV != nil { j.addError(errV) continue } tmap[alias] = rv } if len(tmap) > 0 { result = append(result, tmap) } } } return result } // Only collects the properties from a list of object func (j *JSONQ) Only(properties ...string) interface{} { return j.prepare().only(properties...) } // OnlyR collects the properties from a list of object and return as Result instance func (j *JSONQ) OnlyR(properties ...string) (*Result, error) { v := j.Only(properties...) if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // Pluck build an array of values form a property of a list of objects func (j *JSONQ) Pluck(property string) interface{} { j.prepare() if j.distinctProperty != "" { j.distinct() } if j.limitRecords != 0 { j.limit() } var result = make([]interface{}, 0) if aa, ok := j.jsonContent.([]interface{}); ok { for _, am := range aa { if mv, ok := am.(map[string]interface{}); ok { if v, ok := mv[property]; ok { result = append(result, v) } } } } return result } // PluckR build an array of values form a property of a list of objects and return as Result instance func (j *JSONQ) PluckR(property string) (*Result, error) { v := j.Pluck(property) if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // reset resets the current state of JSONQ instance func (j *JSONQ) reset() *JSONQ { j.raw = nil j.jsonContent = j.rootJSONContent j.node = "" j.queries = make([][]query, 0) j.attributes = make([]string, 0) j.queryIndex = 0 j.offsetRecords = 0 j.limitRecords = 0 j.distinctProperty = "" j.errors = make([]error, 0) return j } // Reset resets the current state of JSON instance and make a fresh object with the original json content func (j *JSONQ) Reset() *JSONQ { return j.reset() } // Get return the result func (j *JSONQ) Get() interface{} { j.prepare() if j.offsetRecords != 0 { j.offset() } if j.limitRecords != 0 { j.limit() } return j.jsonContent } // GetR return the query results as Result instance func (j *JSONQ) GetR() (*Result, error) { v := j.Get() if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // First returns the first element of a list func (j *JSONQ) First() interface{} { j.prepare() if arr, ok := j.jsonContent.([]interface{}); ok { if len(arr) > 0 { return arr[0] } } return empty } // FirstR returns the first element of a list as Result instance func (j *JSONQ) FirstR() (*Result, error) { v := j.First() if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // Last returns the last element of a list func (j *JSONQ) Last() interface{} { j.prepare() if arr, ok := j.jsonContent.([]interface{}); ok { if l := len(arr); l > 0 { return arr[l-1] } } return empty } // LastR returns the last element of a list as Result instance func (j *JSONQ) LastR() (*Result, error) { v := j.Last() if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // Nth returns the nth element of a list func (j *JSONQ) Nth(index int) interface{} { if index == 0 { j.addError(fmt.Errorf("index is not zero based")) return empty } j.prepare() if arr, ok := j.jsonContent.([]interface{}); ok { alen := len(arr) if alen == 0 { j.addError(fmt.Errorf("list is empty")) return empty } if abs(index) > alen { j.addError(fmt.Errorf("index out of range")) return empty } if index > 0 { return arr[index-1] } return arr[alen+index] } return empty } // NthR returns the nth element of a list as Result instance func (j *JSONQ) NthR(index int) (*Result, error) { v := j.Nth(index) if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // Find returns the result of a exact matching path func (j *JSONQ) Find(path string) interface{} { return j.From(path).Get() } // FindR returns the result as Result instance from the exact matching path func (j *JSONQ) FindR(path string) (*Result, error) { v := j.Find(path) if err := j.Error(); err != nil { return nil, err } return NewResult(v), nil } // Count returns the number of total items. // This could be a length of list/array/map func (j *JSONQ) Count() int { j.prepare() var lnth int // list of items if list, ok := j.jsonContent.([]interface{}); ok { lnth = len(list) } // return map len // TODO: need to think about map if m, ok := j.jsonContent.(map[string]interface{}); ok { lnth = len(m) } // group data items if m, ok := j.jsonContent.(map[string][]interface{}); ok { lnth = len(m) } return lnth } // Out write the queried data to defined custom type func (j *JSONQ) Out(v interface{}) { data, err := json.Marshal(j.Get()) if err != nil { j.addError(err) return } if err := json.Unmarshal(data, &v); err != nil { j.addError(err) } } // Writer write the queried data to a io.Writer func (j *JSONQ) Writer(w io.Writer) { err := json.NewEncoder(w).Encode(j.Get()) if err != nil { j.addError(err) return } } // More provides the functionality to query over the resultant data. See https://github.com/thedevsaddam/gojsonq/wiki/Queries#More func (j *JSONQ) More() *JSONQ { j.raw = nil j.rootJSONContent = j.Get() j.node = "" j.queries = make([][]query, 0) j.attributes = make([]string, 0) j.queryIndex = 0 j.limitRecords = 0 j.distinctProperty = "" return j } // getFloatValFromArray returns a list of float64 values from array/map for aggregation func (j *JSONQ) getFloatValFromArray(arr []interface{}, property ...string) []float64 { var ff []float64 for _, a := range arr { if av, ok := a.(float64); ok { if len(property) > 0 { j.addError(fmt.Errorf("unnecessary property name for array")) return nil } ff = append(ff, av) } if mv, ok := a.(map[string]interface{}); ok { if len(property) == 0 { j.addError(fmt.Errorf("property name can not be empty for object")) return nil } if fi, ok := mv[property[0]]; ok { if flt, ok := fi.(float64); ok { ff = append(ff, flt) } else { j.addError(fmt.Errorf("property %s's value '%v' is not numeric", property[0], fi)) return nil } } else { j.addError(fmt.Errorf("property '%s' does not exist", property[0])) return nil } } } return ff } // getAggregationValues returns a list of float64 values for aggregation func (j *JSONQ) getAggregationValues(property ...string) []float64 { j.prepare() if j.distinctProperty != "" { j.distinct() } if j.limitRecords != 0 { j.limit() } var ff []float64 if arr, ok := j.jsonContent.([]interface{}); ok { ff = j.getFloatValFromArray(arr, property...) } if mv, ok := j.jsonContent.(map[string]interface{}); ok { if len(property) == 0 { j.addError(fmt.Errorf("property can not be empty for object")) return nil } if fi, ok := mv[property[0]]; ok { if flt, ok := fi.(float64); ok { ff = append(ff, flt) } else { j.addError(fmt.Errorf("property %s's value '%v' is not numeric", property[0], fi)) return nil } } else { j.addError(fmt.Errorf("property '%s' does not exist", property[0])) return nil } } return ff } // Sum returns sum of values from array or from map using property func (j *JSONQ) Sum(property ...string) float64 { var sum float64 for _, flt := range j.getAggregationValues(property...) { sum += flt } return sum } // Avg returns average of values from array or from map using property func (j *JSONQ) Avg(property ...string) float64 { var sum float64 fl := j.getAggregationValues(property...) for _, flt := range fl { sum += flt } return sum / float64(len(fl)) } // Min returns minimum value from array or from map using property func (j *JSONQ) Min(property ...string) float64 { var min float64 flist := j.getAggregationValues(property...) if len(flist) > 0 { min = flist[0] } for _, flt := range flist { if flt < min { min = flt } } return min } // Max returns maximum value from array or from map using property func (j *JSONQ) Max(property ...string) float64 { var max float64 flist := j.getAggregationValues(property...) if len(flist) > 0 { max = flist[0] } for _, flt := range flist { if flt > max { max = flt } } return max } golang-github-thedevsaddam-gojsonq-2.5.2/jsonq_test.go000066400000000000000000001337411375452222100231100ustar00rootroot00000000000000package gojsonq import ( "bytes" "encoding/json" "errors" "fmt" "math" "reflect" "strings" "testing" ) func TestNew(t *testing.T) { jq := New() if reflect.ValueOf(jq).Type().String() != "*gojsonq.JSONQ" { t.Error("failed to match JSONQ type") } } func TestJSONQ_String(t *testing.T) { jq := New() expected := fmt.Sprintf("\nContent: %s\nQueries:%v\n", string(jq.raw), jq.queries) if out := jq.String(); out != expected { t.Errorf("Expected: %v\n Got: %v", expected, out) } } func TestJSONQ_decode(t *testing.T) { testCases := []struct { tag string jsonStr string errExpect bool }{ { tag: "valid json", jsonStr: `{"name": "John Doe", "age": 30}`, errExpect: false, }, { tag: "invalid json should return error", jsonStr: `{"name": "John Doe", "age": 30, "only_key"}`, errExpect: true, }, } for _, tc := range testCases { jq := New() jq.raw = json.RawMessage(tc.jsonStr) jq.decode() if err := jq.Error(); err != nil && !tc.errExpect { t.Errorf("failed %s", tc.tag) } } } func TestJSONQ_Copy(t *testing.T) { jq := New() mp := map[string]int{} for i := 0; i < 100; i++ { adr := fmt.Sprintf("%p", jq.Copy()) if _, ok := mp[adr]; ok { t.Error("failed to copy JSONQ") } else { mp[adr] = i } } } func TestJSONQ_File(t *testing.T) { filename := "data.json" path, f := createTestFile(t, filename) defer f() testCases := []struct { tag string filename string expectedErr bool }{ { tag: "valid file name does not expect error", filename: path, expectedErr: false, }, { tag: "invalid valid file name expecting error", filename: "invalid_file.xjson", expectedErr: true, }, } for _, tc := range testCases { err := New().File(tc.filename).Error() if tc.expectedErr && err == nil { t.Errorf("%s", tc.tag) } } } func TestJSONQ_JSONString(t *testing.T) { testCases := []struct { tag string jsonStr string errExpect bool }{ { tag: "valid json", jsonStr: `{"name": "John Doe", "age": 30}`, errExpect: false, }, { tag: "invalid json should return error", jsonStr: `{"name": "John Doe", "age": 30, "only_key"}`, errExpect: true, }, } for _, tc := range testCases { if err := New().FromString(tc.jsonStr).Error(); err != nil && !tc.errExpect { t.Errorf("failed %s", tc.tag) } } } func TestJSONQ_FromString(t *testing.T) { testCases := []struct { tag string inputStr string errExpect bool }{ // TODO: Doesn't need to test decoder for input content { tag: "valid json", inputStr: `{"name": "John Doe", "age": 30}`, errExpect: false, }, { tag: "invalid json should return error", inputStr: `{"name": "John Doe", "age": 30, "only_key"}`, errExpect: true, }, } for _, tc := range testCases { if err := New().FromString(tc.inputStr).Error(); err != nil && !tc.errExpect { t.Errorf("failed %s", tc.tag) } } } func TestJSONQ_Reader(t *testing.T) { testCases := []struct { tag string jsonStr string errExpect bool }{ { tag: "valid json", jsonStr: `{"name": "John Doe", "age": 30}`, errExpect: false, }, { tag: "invalid json should return error", jsonStr: `{"name": "John Doe", "age": 30, "only_key"}`, errExpect: true, }, } for _, tc := range testCases { rdr := strings.NewReader(tc.jsonStr) if err := New().Reader(rdr).Error(); err != nil && !tc.errExpect { t.Errorf("failed %s", tc.tag) } } } type invalidReader string func (invalidReader) Read(p []byte) (n int, err error) { return 0, errors.New("this reader always return an error") } func TestJSONQ_Reader_expecting_error(t *testing.T) { var rdr invalidReader if err := New().Reader(rdr).Error(); err == nil { t.Errorf("failed to catch Reader error") } } func TestJSONQ_Errors(t *testing.T) { testCases := []struct { tag string jsonStr string }{ { tag: "invalid json 1", jsonStr: `{"name": "John Doe", "age": 30, :""}`, }, { tag: "invalid json 2", jsonStr: `{"name": "John Doe", "age": 30, "only_key"}`, }, } for _, tc := range testCases { if errs := New().FromString(tc.jsonStr).Errors(); len(errs) == 0 { t.Errorf("failed %s", tc.tag) } } } func TestJSONQ_Macro(t *testing.T) { jq := New() jq.Macro("mac1", func(x, y interface{}) (bool, error) { return true, nil }) if _, ok := jq.queryMap["mac1"]; !ok { t.Error("failed to register macro") } jq.Macro("mac1", func(x, y interface{}) (bool, error) { return true, nil }) if jq.Error() == nil { t.Error("failed to throw error for already registered macro") } } func TestJSONQ_From_Set(t *testing.T) { node := "root.items.[0].name" jq := New().From(node) if jq.node != node { t.Error("failed to set node name") } } func TestJSONQ_Select(t *testing.T) { jq := New().Select("id", "name") if len(jq.attributes) != 2 { t.Error("failed to set properties") } } func TestJSONQ_Offset(t *testing.T) { jq := New().Offset(3) if jq.offsetRecords != 3 { t.Error("failed to set offset records value") } } func TestJSONQ_Limit(t *testing.T) { jq := New().Limit(12) if jq.limitRecords != 12 { t.Error("failed to set limit records value") } } func TestJSONQ_reset(t *testing.T) { node := "root.items" jq := New().From(node).Select("name", "age").WhereEqual("price", "1900").WhereEqual("id", 1) jq.reset() if len(jq.queries) != 0 || len(jq.attributes) != 0 || jq.queryIndex != 0 { t.Error("reset failed") } } func TestJSONQ_Reset(t *testing.T) { node := "root.items" jq := New().From(node).WhereEqual("price", "1900").WhereEqual("id", 1) jq.Reset() if len(jq.queries) != 0 || jq.queryIndex != 0 || jq.node != "" { t.Error("reset failed") } } func TestJSONQ_From(t *testing.T) { testCases := []struct { tag string query string expected string expectError bool }{ { tag: "accessing node", query: "vendor.name", expected: `"Star Trek"`, expectError: false, }, { tag: "accessing not existed index", query: "vendor.items.[0]", expected: `{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}`, expectError: false, }, { tag: "accessing not existed index", query: "vendor.items.[10]", expected: `null`, expectError: false, }, { tag: "accessing invalid index error", query: "vendor.items.[x]", expectError: true, }, } for _, tc := range testCases { jq := New().FromString(jsonStr) out := jq.From(tc.query).Get() if tc.expectError && jq.Error() == nil { t.Error("failed to catch error") } if !tc.expectError { assertJSON(t, out, tc.expected, tc.tag) } } jq := New().FromString(jsonStr) expJSON := `[{"id":3,"name":"Sony VAIO","price":1200}]` out := jq.From("vendor.items").GroupBy("price").From("1200").Get() assertJSON(t, out, expJSON, "accessing group by data") } func TestJSONQ_FromInterface(t *testing.T) { var v map[string]interface{} err := json.Unmarshal([]byte(jsonStr), &v) if err != nil { t.Error(err) } jq := New().FromInterface(v) if jq.rootJSONContent == nil || jq.jsonContent == nil { t.Errorf("failed to assign value using FromInterface method") } var customType float64 jq = New().FromInterface(customType) if jq.Error() == nil { t.Errorf("failed to set error properly for FromInterface method") } } func TestJSONQ_Where_single_where(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", "=", 1700) expected := `[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "single Where") } func TestJSONQ_Where_deep_nested_value(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). Where("name.first", "=", "John") expected := `[{"id":1,"name":{"first":"John","last":"Ramboo"}},{"id":3,"name":{"first":"John","last":"Doe"}}]` out := jq.Get() assertJSON(t, out, expected, "single Where with nested value") } func TestJSONQ_Where_multiple_where_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", "=", 1700). Where("id", "=", 2) expected := `[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "multiple Where expecting data") } func TestJSONQ_Where_multiple_where_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", "=", 1700). Where("id", "=", "1700") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "multiple Where expecting empty result") } func TestJSONQ_Where_multiple_where_with_invalid_operator_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", "invalid_op", 1700) jq.Get() if jq.Error() == nil { t.Error("expecting: invalid operator invalid_op") } } func TestJSONQ_Where_multiple_where_with_invalid_operand_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", "contains", 1700) jq.Get() if jq.Error() == nil { t.Error("expecting: invalid operator invalid_op") } } func TestJSONQ_single_WhereEqual(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereEqual("price", 1700) expected := `[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "single WhereEqual") } func TestJSONQ_multiple_WhereEqual_expecting_data(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereEqual("price", 1700). WhereEqual("id", 2) expected := `[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "multiple WhereEqual expecting data") } func TestJSONQ_multiple_WhereEqual_expecting_empty_data(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereEqual("price", 1700). WhereEqual("id", "1700") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "multiple WhereEqual expecting empty result") } func TestJSONQ_single_WhereNotEqual(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereNotEqual("price", 850) expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":3,"name":"Sony VAIO","price":1200},{"id":6,"name":"HP core i7","price":950}]` out := jq.Get() assertJSON(t, out, expected, "single WhereNotEqual") } func TestJSONQ_multiple_WhereNotEqual(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereNotEqual("price", 850). WhereNotEqual("id", 2) expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":3,"name":"Sony VAIO","price":1200},{"id":6,"name":"HP core i7","price":950}]` out := jq.Get() assertJSON(t, out, expected, "multiple WhereNotEqual expecting result") } func TestJSONQ_WhereNil(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereNil("id") expected := `[{"id":null,"name":"HP core i3 SSD","price":850}]` out := jq.Get() assertJSON(t, out, expected) } func TestJSONQ_WhereNotNil(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereNotNil("id") expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":3,"name":"Sony VAIO","price":1200},{"id":4,"name":"Fujitsu","price":850},{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":6,"name":"HP core i7","price":950}]` out := jq.Get() assertJSON(t, out, expected) } func TestJSONQ_WhereIn_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereIn("id", []int{1, 3, 5}) expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":3,"name":"Sony VAIO","price":1200},{"id":5,"key":2300,"name":"HP core i5","price":850}]` out := jq.Get() assertJSON(t, out, expected, "WhereIn expecting result") } func TestJSONQ_WhereIn_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereIn("id", []int{18, 39, 85}) expected := `[]` out := jq.Get() assertJSON(t, out, expected, "WhereIn expecting empty result") } func TestJSONQ_WhereNotIn_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereNotIn("id", []int{1, 3, 5, 6}) expected := `[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":4,"name":"Fujitsu","price":850},{"id":null,"name":"HP core i3 SSD","price":850}]` out := jq.Get() assertJSON(t, out, expected, "WhereIn expecting result") } func TestJSONQ_WhereNotIn_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereNotIn("price", []float64{850, 950, 1200, 1700, 1350}) expected := `[]` out := jq.Get() assertJSON(t, out, expected, "WhereIn expecting empty result") } func TestJSONQ_OrWhere(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). OrWhere("price", ">", 1200) expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "OrWhere expecting result") } func TestJSONQ_WhereStartsWith_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereStartsWith("name", "Mac") expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "WhereStartsWith expecting result") } func TestJSONQ_WhereStartsWith_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereStartsWith("name", "xyz") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "WhereStartsWith expecting empty result") } func TestJSONQ_WhereEndsWith(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereEndsWith("name", "retina") expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "WhereStartsWith expecting result") } func TestJSONQ_WhereEndsWith_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereEndsWith("name", "xyz") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "WhereStartsWith expecting empty result") } func TestJSONQ_WhereContains_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereContains("name", "RetinA") expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "WhereContains expecting result") } func TestJSONQ_WhereContains_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereContains("name", "xyz") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "WhereContains expecting empty result") } func TestJSONQ_WhereStrictContains_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereStrictContains("name", "retina") expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "WhereContains expecting result") } func TestJSONQ_WhereStrictContains_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). WhereStrictContains("name", "RetinA") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "WhereContains expecting empty result") } func TestJSONQ_GroupBy(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). GroupBy("price") expected := `{"1200":[{"id":3,"name":"Sony VAIO","price":1200}],"1350":[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}],"1700":[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}],"850":[{"id":4,"name":"Fujitsu","price":850},{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":null,"name":"HP core i3 SSD","price":850}],"950":[{"id":6,"name":"HP core i7","price":950}]}` out := jq.Get() assertJSON(t, out, expected, "GroupBy expecting result") } func TestJSONQ_GroupBy_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). GroupBy("invalid_key") expected := `{}` out := jq.Get() assertJSON(t, out, expected, "GroupBy expecting empty result") if len(jq.Errors()) == 0 { t.Error("failed to catch GroupBy error") } } func TestJSONQ_GroupBy_nested_property(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). GroupBy("name.first") expected := `{"Ethan":[{"id":2,"name":{"first":"Ethan","last":"Hunt"}}],"John":[{"id":1,"name":{"first":"John","last":"Ramboo"}},{"id":3,"name":{"first":"John","last":"Doe"}}]}` out := jq.Get() assertJSON(t, out, expected, "GroupBy nested expecting result") } func TestJSONQ_GroupBy_nested_property_expecting_error(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). GroupBy("name.invalid_key") out := jq.Get() expected := `{}` assertJSON(t, out, expected, "Nsested GroupBy expecting empty result") if len(jq.errors) == 0 { t.Error("failed to catch GroupBy nested property error") } } func TestJSONQ_Sort_string_ascending_order(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.names"). Sort() expected := `["Abby","Jane Doe","Jerry","John Doe","Nicolas","Tom"]` out := jq.Get() assertJSON(t, out, expected, "sorting array of string in ascending desc") } func TestJSONQ_Sort_float64_descending_order(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices"). Sort("desc") expected := `[2400,2100,1200,400.87,150.1,89.9]` out := jq.Get() assertJSON(t, out, expected, "sorting array of float in descending order") } func TestJSONQ_Sort_with_two_args_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices"). Sort("asc", "desc") jq.Get() if jq.Error() == nil { t.Error("expecting an error") } } func TestJSONQ_SortBy_float_ascending_order(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). SortBy("price") expected := `[{"id":null,"name":"HP core i3 SSD","price":850},{"id":4,"name":"Fujitsu","price":850},{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":6,"name":"HP core i7","price":950},{"id":3,"name":"Sony VAIO","price":1200},{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` out := jq.Get() assertJSON(t, out, expected, "sorting array of object by its key (price-float64) in ascending desc") } func TestJSONQ_SortBy_float_descending_order(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). SortBy("price", "desc") expected := `[{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":3,"name":"Sony VAIO","price":1200},{"id":6,"name":"HP core i7","price":950},{"id":4,"name":"Fujitsu","price":850},{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":null,"name":"HP core i3 SSD","price":850}]` out := jq.Get() assertJSON(t, out, expected, "sorting array of object by its key (price-float64) in descending desc") } func TestJSONQ_SortBy_string_ascending_order(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). SortBy("name") expected := `[{"id":4,"name":"Fujitsu","price":850},{"id":null,"name":"HP core i3 SSD","price":850},{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":6,"name":"HP core i7","price":950},{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":3,"name":"Sony VAIO","price":1200}]` out := jq.Get() assertJSON(t, out, expected, "sorting array of object by its key (name-string) in ascending desc") } func TestJSONQ_SortBy_string_descending_order(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). SortBy("name", "desc") expected := `[{"id":3,"name":"Sony VAIO","price":1200},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":6,"name":"HP core i7","price":950},{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":null,"name":"HP core i3 SSD","price":850},{"id":4,"name":"Fujitsu","price":850}]` out := jq.Get() assertJSON(t, out, expected, "sorting array of object by its key (name-string) in descending desc") } func TestJSONQ_SortBy_deep_nested_string_ascending_order(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). SortBy("name.first") expected := `[{"id":2,"name":{"first":"Ethan","last":"Hunt"}},{"id":1,"name":{"first":"John","last":"Ramboo"}},{"id":3,"name":{"first":"John","last":"Doe"}}]` out := jq.Get() assertJSON(t, out, expected, "sorting array of object by its key (name-string) in descending desc") } func TestJSONQ_SortBy_deep_nested_string_invalid_key_should_return_error(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). SortBy("name.middle") expected := `[{"id":1,"name":{"first":"John","last":"Ramboo"}},{"id":2,"name":{"first":"Ethan","last":"Hunt"}},{"id":3,"name":{"first":"John","last":"Doe"}}]` // no ordering, remain same out := jq.Get() assertJSON(t, out, expected, "sorting array of object by its key (name-string) in descending desc") if len(jq.errors) == 0 { t.Error("invalid path should return error/errors in SortBy") } } func TestJSONQ_SortBy_no_argument_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). SortBy() jq.Get() if jq.Error() == nil { t.Error("expecting an error") } } func TestJSONQ_SortBy_more_than_two_argument_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). SortBy("name", "desc", "asc") jq.Get() if jq.Error() == nil { t.Error("expecting an error") } } func TestJSONQ_SortBy_expecting_as_provided_node_is_not_list(t *testing.T) { jq := New().FromString(jsonStr). From("name"). SortBy("name", "desc") out := jq.Get() expJSON := `"computers"` assertJSON(t, out, expJSON) } func TestJSONQ_SortBy_expecting_empty_as_provided_node_is_not_list(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Where("price", ">", 2500). SortBy("name", "desc") out := jq.Get() expJSON := `[]` assertJSON(t, out, expJSON) } func TestJSONQ_Distinct(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Distinct("price") expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700},{"id":3,"name":"Sony VAIO","price":1200},{"id":4,"name":"Fujitsu","price":850},{"id":6,"name":"HP core i7","price":950}]` out := jq.Get() assertJSON(t, out, expected, "Distinct expecting result") } func TestJSONQ_Distinct_expecting_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Distinct("invalid_key") expected := `[]` out := jq.Get() assertJSON(t, out, expected, "Distinct expecting empty result") if len(jq.Errors()) == 0 { t.Error("failed to catch Distinct error") } } func TestJSONQ_Only(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") expected := `[{"id":1,"price":1350},{"id":2,"price":1700},{"id":3,"price":1200},{"id":4,"price":850},{"id":5,"price":850},{"id":6,"price":950},{"id":null,"price":850}]` out := jq.Only("id", "price") assertJSON(t, out, expected) } func TestJSONQ_Only_with_distinct(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price") expected := `[{"id":1,"price":1350},{"id":2,"price":1700},{"id":3,"price":1200},{"id":4,"price":850},{"id":6,"price":950}]` out := jq.Only("id", "price") assertJSON(t, out, expected) } func TestJSONQ_OnlyR(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") result, err := jq.OnlyR("name", "price") if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_OnlyR_error(t *testing.T) { jq := New().FromString(jsonStr). From("invalid_path") result, err := jq.OnlyR("name", "price") if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_First_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") expected := `{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}` out := jq.First() assertJSON(t, out, expected, "First expecting result") } func TestJSONQ_First_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", ">", 1800) expected := `null` out := jq.First() assertJSON(t, out, expected, "First expecting empty result") } func TestJSONQ_First_distinct_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Where("price", "=", 850) expected := `{"id":4,"name":"Fujitsu","price":850}` out := jq.First() assertJSON(t, out, expected, "First with distinct & where expecting result result") } func TestJSONQ_FirstR(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Where("price", "=", 850) result, err := jq.FirstR() if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_FirstR_error(t *testing.T) { jq := New().FromString(jsonStr). From("invalid").Distinct("price").Where("price", "=", 850) result, err := jq.FirstR() if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_Last_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") expected := `{"id":null,"name":"HP core i3 SSD","price":850}` out := jq.Last() assertJSON(t, out, expected, "Last expecting result") } func TestJSONQ_Last_expecting_empty_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", ">", 1800) expected := `null` out := jq.Last() assertJSON(t, out, expected, "Last expecting empty result") } func TestJSONQ_Last_distinct_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Where("price", "=", 850) expected := `{"id":4,"name":"Fujitsu","price":850}` out := jq.Last() assertJSON(t, out, expected, "Last with distinct & where expecting result result") } func TestJSONQ_LastR(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Where("price", "=", 850) result, err := jq.LastR() if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_LastR_error(t *testing.T) { jq := New().FromString(jsonStr). From("invalid_path").Distinct("price").Where("price", "=", 850) result, err := jq.LastR() if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_Nth_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") expected := `{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}` out := jq.Nth(1) assertJSON(t, out, expected, "Nth expecting result") } func TestJSONQ_Nth_expecting_empty_result_with_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", ">", 1800) expected := `null` out := jq.Nth(1) assertJSON(t, out, expected, "Nth expecting empty result with an error") if jq.Error() == nil { t.Error("expecting an error for empty result nth value") } } func TestJSONQ_Nth_expecting_empty_result_with_error_index_out_of_range(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") expected := `null` out := jq.Nth(100) assertJSON(t, out, expected, "Nth expecting empty result with an error of index out of range") if jq.Error() == nil { t.Error("expecting an error for empty result nth value") } } func TestJSONQ_Nth_expecting_result_from_last_using_negative_index(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") expected := `{"id":null,"name":"HP core i3 SSD","price":850}` out := jq.Nth(-1) assertJSON(t, out, expected, "Nth expecting result form last when providing -1") } func TestJSONQ_Nth_expecting_error_providing_zero_as_index(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("price", ">", 1800) jq.Nth(0) if jq.Error() == nil { t.Error("expecting error") } } func TestJSONQ_Nth_expecting_empty_result_as_node_is_map(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items.[0]") out := jq.Nth(0) expected := `null` assertJSON(t, out, expected, "Nth expecting empty result if the node is a map") } func TestJSONQ_Nth_expecting_empty_result_as_node_is_object(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items.[0]") out := jq.Nth(1) expected := `null` assertJSON(t, out, expected, "Nth expecting empty result if the node is a object") } func TestJSONQ_Nth_distinct_expecting_result(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price") expected := `{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}` out := jq.Nth(1) assertJSON(t, out, expected, "Last with distinct & where expecting result result") } func TestJSONQ_NthR(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Where("price", "=", 850) result, err := jq.NthR(1) if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_NthR_error(t *testing.T) { jq := New().FromString(jsonStr). From("invalid_path").Distinct("price").Where("price", "=", 850) result, err := jq.NthR(1) if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_Find_simple_property(t *testing.T) { jq := New().FromString(jsonStr) out := jq.Find("name") expected := `"computers"` assertJSON(t, out, expected, "Find expecting name computers") } func TestJSONQ_Find_nested_property(t *testing.T) { jq := New().FromString(jsonStr) out := jq.Find("vendor.items.[0]") expected := `{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}` assertJSON(t, out, expected, "Find expecting a nested object") } func TestJSONQ_FindR(t *testing.T) { jq := New().FromString(jsonStr) result, err := jq.FindR("vendor.items.[0]") if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_FindR_error(t *testing.T) { jq := New().FromString(jsonStr) result, err := jq.FindR("invalid_path") if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_Pluck_expecting_list_of_float64(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Pluck("price") expected := `[1350,1700,1200,850,850,950,850]` assertJSON(t, out, expected, "Pluck expecting prices from list of objects") } func TestJSONQ_Pluck_expecting_empty_list_of_float64(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Pluck("invalid_prop") expected := `[]` assertJSON(t, out, expected, "Pluck expecting empty list from list of objects, because of invalid property name") } func TestJSONQ_Pluck_expecting_with_distinct(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Limit(3) out := jq.Pluck("price") expected := `[1350,1700,1200]` assertJSON(t, out, expected, "Expecting distinct price with limit 3") } func TestJSONQ_PluckR(t *testing.T) { jq := New().FromString(jsonStr).From("vendor.items") result, err := jq.PluckR("price") if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_PluckR_error(t *testing.T) { jq := New().FromString(jsonStr).From("invalid_path") result, err := jq.PluckR("price") if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_Count_expecting_int_from_list(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Count() expected := `7` assertJSON(t, out, expected, "Count expecting a int number of total item of an array") } func TestJSONQ_Count_expecting_int_from_list_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items.[0]") out := jq.Count() expected := `3` assertJSON(t, out, expected, "Count expecting a int number of total item of an array of objects") } func TestJSONQ_Count_expecting_int_from_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). GroupBy("price") out := jq.Count() expected := `5` assertJSON(t, out, expected, "Count expecting a int number of total item of an array of grouped objects") } func TestJSONQ_Count_with_Distinct_expecting_int_from_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price") out := jq.Count() expected := `5` assertJSON(t, out, expected, "Count expecting a int number of total item of an array of distinct priced objects") } func TestJSONQ_Out_expecting_result(t *testing.T) { type item struct { ID int `json:"id"` Name string `json:"name"` Price int `json:"price"` } exptItm := item{ ID: 1, Name: "MacBook Pro 13 inch retina", Price: 1350, } itm := item{} jq := New().FromString(jsonStr). From("vendor.items.[0]") jq.Out(&itm) assertInterface(t, exptItm, itm, "failed to get Out result") } func TestJSONQ_Out_expecting_decoding_error(t *testing.T) { type item struct { ID bool `json:"id"` Name string `json:"name"` Price int `json:"price"` } itm := item{} jq := New().FromString(jsonStr). From("vendor.items.[0]") jq.Out(&itm) if jq.Error() == nil { t.Errorf("failed to get Out decoding error: %v", jq.Error()) } } func TestJSONQ_Out_expecting_encoding_error(t *testing.T) { type item struct { ID bool `json:"id"` Name string `json:"name"` Price int `json:"price"` } itm := item{} jq := New() jq.jsonContent = math.Inf(1) jq.Out(&itm) if jq.Error() == nil { t.Errorf("failed to get Out encoding error: %v", jq.Error()) } } func TestJSONQ_Writer_expecting_result(t *testing.T) { var b bytes.Buffer New().FromString(jsonStr).From("vendor.prices").Writer(&b) expected := "[2400,2100,1200,400.87,89.9,150.1]\n" assertInterface(t, expected, b.String(), "failed to get Writer result") } func TestJSONQ_Writer_encoding_error(t *testing.T) { var b bytes.Buffer jq := New().FromString(jsonStr) jq.jsonContent = math.Inf(1) jq.Writer(&b) if jq.Error() == nil { t.Errorf("failed to get Writer encoding error: %v", jq.Error()) } } func TestJSONQ_Sum_of_array_numeric_values(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices") out := jq.Sum() expected := `6340.87` assertJSON(t, out, expected, "Sum expecting sum an array") } func TestJSONQ_Sum_of_array_objects_property_numeric_values(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Sum("price") expected := `7750` assertJSON(t, out, expected, "Sum expecting sum an array of objects property") } func TestJSONQ_Sum_expecting_error_for_providing_property_of_array(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices") jq.Sum("key") if jq.Error() == nil { t.Error("expecting: unnecessary property name for array") } } func TestJSONQ_Sum_expecting_error_for_not_providing_property_of_array_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") jq.Sum() if jq.Error() == nil { t.Error("expecting: property name can not be empty for object") } } func TestJSONQ_Sum_expecting_error_for_not_providing_property_of_object(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items.[0]") jq.Sum() if jq.Error() == nil { t.Error("expecting: property name can not be empty for object") } } func TestJSONQ_Sum_expecting_error_for_providing_invalid_property_of_array_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") jq.Sum("invalid_property") if jq.Error() == nil { t.Error("expecting: property 'invalid_property' does not exist") } } func TestJSONQ_Sum_expecting_error_for_providing_invalid_property_of_object(t *testing.T) { jq := New().FromString(jsonStr). From("vendor") jq.Sum("invalid_property") if jq.Error() == nil { t.Error("expecting: property 'invalid_property' does not exist") } } func TestJSONQ_Sum_expecting_error_for_providing_non_numeric_property_of_array_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") jq.Sum("name") if jq.Error() == nil { t.Error("expecting: property 'MacBook Pro 13 inch retina' is not numeric") } } func TestJSONQ_Sum_expecting_error_for_providing_non_numeric_property_of_object(t *testing.T) { jq := New().FromString(jsonStr). From("vendor") jq.Sum("name") if jq.Error() == nil { t.Error("expecting: property 'invalid_property' does not exist") } } func TestJSONQ_Sum_expecting_result_from_nested_object(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items.[0]") out := jq.Sum("price") expected := `1350` assertJSON(t, out, expected, "Sum expecting result from nested object") } func TestJSONQ_Sum_of_distinct_array_numeric_values(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Distinct("price").Limit(3) out := jq.Sum("price") expected := `4250` assertJSON(t, out, expected, "Sum expecting sum a distinct & limited array") } func TestJSONQ_Avg_array(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices") out := jq.Avg() expected := `1056.8116666666667` assertJSON(t, out, expected, "Avg expecting average an array") } func TestJSONQ_Avg_array_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Avg("price") expected := `1107.142857142857` assertJSON(t, out, expected, "Avg expecting average an array of objects property") } func TestJSONQ_Min_array(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices") out := jq.Min() expected := `89.9` assertJSON(t, out, expected, "Min expecting min an array") } func TestJSONQ_Min_array_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Min("price") expected := `850` assertJSON(t, out, expected, "Min expecting min an array of objects property") } func TestJSONQ_Max_array(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.prices") out := jq.Max() expected := `2400` assertJSON(t, out, expected, "Max expecting max an array") } func TestJSONQ_Max_array_of_objects(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items") out := jq.Max("price") expected := `1700` assertJSON(t, out, expected, "Max expecting max an array of objects property") } // TODO: Need to write some more combined query test func TestJSONQ_CombinedWhereOrWhere(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("id", "=", 1). OrWhere("name", "=", "Sony VAIO"). Where("price", "=", 1200) out := jq.Get() expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":3,"name":"Sony VAIO","price":1200}]` assertJSON(t, out, expected, "combined Where with orWhere") } func TestJSONQ_CombinedWhereOrWhere_invalid_key(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Where("id", "=", 1). OrWhere("invalid_key", "=", "Sony VAIO") out := jq.Get() expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}]` assertJSON(t, out, expected, "combined Where with orWhere containing invalid key") } func TestJSONQ_Get_with_Select_method(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Select("id", "name"). Where("price", "=", 1350) out := jq.Get() expected := `[{"id":1,"name":"MacBook Pro 13 inch retina"}]` assertJSON(t, out, expected, "Select method Using Get") } func TestJSONQ_Get_with_nested_Select_method(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). Select("id as uid", "name.first as fname", "name.last") out := jq.Get() expected := `[{"fname":"John","last":"Ramboo","uid":1},{"fname":"Ethan","last":"Hunt","uid":2},{"fname":"John","last":"Doe","uid":3}]` assertJSON(t, out, expected, "nested Select method using alias") } func TestJSONQ_Get_with_nested_invalid_property_in_Select_method_expecting_error(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). Select("id as uid", "name.middle") out := jq.Get() if jq.Error() == nil { t.Error("nested property in Select method failed to catch error") } expected := `[{"uid":1},{"uid":2},{"uid":3}]` assertJSON(t, out, expected, "nested Select method using alias") } func TestJSONQ_GetR(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items").Select("name") result, err := jq.GetR() if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" && err != nil { t.Error("failed to match Result type") } } func TestJSONQ_GetR_error(t *testing.T) { jq := New().FromString(jsonStr). From("invalid_path") result, err := jq.GetR() if result != nil && err == nil { t.Error("failed to catch error") } } func TestJSONQ_Offset_method(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Offset(4) out := jq.Get() expected := `[{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":6,"name":"HP core i7","price":950},{"id":null,"name":"HP core i3 SSD","price":850}]` assertJSON(t, out, expected, "failed to offset records") } func TestJSONQ_Offset_Where_method(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Offset(4).WhereNotNil("id") out := jq.Get() expected := `[{"id":5,"key":2300,"name":"HP core i5","price":850},{"id":6,"name":"HP core i7","price":950}]` assertJSON(t, out, expected, "failed to limit records") } func TestJSONQ_Offset_greater_than_the_original_value_with_Where_method(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Offset(40).WhereNotNil("id") out := jq.Get() expected := `[]` assertJSON(t, out, expected, "failed to offset records when offset value is greater than the length of orignal result") } func TestJSONQ_Limit_method(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Limit(2) out := jq.Get() expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` assertJSON(t, out, expected, "failed to limit records") } func TestJSONQ_Limit_Where_method(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Limit(2).WhereNotNil("id") out := jq.Get() expected := `[{"id":1,"name":"MacBook Pro 13 inch retina","price":1350},{"id":2,"name":"MacBook Pro 15 inch retina","price":1700}]` assertJSON(t, out, expected, "failed to limit records") } func TestJSONQ_Offset_invalid_number_should_return_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Offset(-2) jq.Get() if jq.Error() == nil { t.Error("failed to catch invalid offset error") } } func TestJSONQ_Limit_invalid_number_should_return_error(t *testing.T) { jq := New().FromString(jsonStr). From("vendor.items"). Limit(-2) jq.Get() if jq.Error() == nil { t.Error("failed to catch invalid limit error") } } func TestJSONQ_WhereLenEqual(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). WhereLenEqual("name.first", 4) expected := `[{"id":1,"name":{"first":"John","last":"Ramboo"}},{"id":3,"name":{"first":"John","last":"Doe"}}]` out := jq.Get() assertJSON(t, out, expected, "single WhereLenEqual") } func TestJSONQ_WhereLenNotEqual(t *testing.T) { jq := New().FromString(jsonStrUsers). From("users"). WhereLenNotEqual("name.first", 4) expected := `[{"id":2,"name":{"first":"Ethan","last":"Hunt"}}]` out := jq.Get() assertJSON(t, out, expected, "single WhereLenEqual") } func TestJSONQ_More(t *testing.T) { jq := New().FromString(jsonStrUsers).From("users") jq.Where("id", "<", 3) jq.More() // start query again jq.Where("id", ">", 1) expected := `[{"id":2,"name":{"first":"Ethan","last":"Hunt"}}]` out := jq.Get() assertJSON(t, out, expected, "More") } // ======================== Benchmark ======================== // func Benchmark_Copy(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.Copy() } } func Benchmark_Find(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.Find("name") } } func Benchmark_Get(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.Get() } } func Benchmark_From_Get(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").Get() } } func Benchmark_From_Where_Get(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").Where("id", "=", 1).Get() } } func Benchmark_From_Where_Select_Get(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").Where("id", "=", 1).Select("id", "name").Get() } } func Benchmark_From_Sum(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").Sum("price") } } func Benchmark_From_Avg(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").Avg("price") } } func Benchmark_From_Count(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").Count() } } func Benchmark_From_First(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").First() } } func Benchmark_From_GroupBy(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").GroupBy("price") } } func Benchmark_From_SortBy(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").SortBy("price") } } func Benchmark_From_Where_nested_element_Get(b *testing.B) { jq := New().FromString(jsonStrUsers) for n := 0; n < b.N; n++ { jq.From("users").WhereEqual("name.first", "John").Get() } } func Benchmark_From_WhereLenEqual_Get(b *testing.B) { jq := New().FromString(jsonStr) for n := 0; n < b.N; n++ { jq.From("vendor.items").WhereLenEqual("name", 10).Get() } } golang-github-thedevsaddam-gojsonq-2.5.2/jsonq_testdata_test.go000066400000000000000000000065301375452222100247740ustar00rootroot00000000000000package gojsonq import ( "bytes" "encoding/json" "io/ioutil" "os" "testing" ) // ==================== Test Data=================== // ==================== DO NOT EDIT=================== var ( jsonStr = ` { "name":"computers", "description":"List of computer products", "vendor":{ "name":"Star Trek", "email":"info@example.com", "website":"www.example.com", "items":[ { "id":1, "name":"MacBook Pro 13 inch retina", "price":1350 }, { "id":2, "name":"MacBook Pro 15 inch retina", "price":1700 }, { "id":3, "name":"Sony VAIO", "price":1200 }, { "id":4, "name":"Fujitsu", "price":850 }, { "id":5, "name":"HP core i5", "price":850, "key": 2300 }, { "id":6, "name":"HP core i7", "price":950 }, { "id":null, "name":"HP core i3 SSD", "price":850 } ], "prices":[ 2400, 2100, 1200, 400.87, 89.90, 150.10 ], "names":[ "John Doe", "Jane Doe", "Tom", "Jerry", "Nicolas", "Abby" ] } } ` jsonStrUsers = `{ "users":[ { "id":1, "name":{ "first":"John", "last":"Ramboo" } }, { "id":2, "name":{ "first":"Ethan", "last":"Hunt" } }, { "id":3, "name":{ "first":"John", "last":"Doe" } } ] }` ) // ================= Test Helpers=========================== func createTestFile(t *testing.T, filename string) (string, func()) { file, err := ioutil.TempFile("", filename) if err != nil { t.Errorf("failed to create %s test file %v", filename, err) } // create data.json file from the jsonStr above if _, err := file.Write([]byte(jsonStr)); err != nil { t.Errorf("failed to create %s test file %v", filename, err) } return file.Name(), func() { if err := os.Remove(file.Name()); err != nil { t.Errorf("failed to remove %s test file %v", filename, err) } } } func assertJSON(t *testing.T, v interface{}, expJSON string, tag ...string) { bb, err := json.Marshal(v) if err != nil { t.Errorf("failed to marshal: %v", err) } eb := []byte(expJSON) if !bytes.Equal(bb, eb) { if len(tag) > 0 { t.Errorf("Tag: %s\nExpected: %v\nGot: %v", tag[0], expJSON, string(bb)) } else { t.Errorf("Expected: %v\nGot: %v", expJSON, string(bb)) } } } func assertInterface(t *testing.T, x, y interface{}, tag ...string) { bbX, err := json.Marshal(x) if err != nil { t.Errorf("failed to marshal x: %v", err) } bbY, err := json.Marshal(y) if err != nil { t.Errorf("failed to marshal x: %v", err) } if !bytes.Equal(bbX, bbY) { if len(tag) > 0 { t.Errorf("Tag: %s\nExpected: %v\nGot: %v", tag[0], x, y) } else { t.Errorf("Expected: %v\nGot: %v", x, y) } } } // cDecoder will be used as a custom decoder for testing// though it use std lib type cDecoder struct { } func (c *cDecoder) Decode(data []byte, v interface{}) error { return json.Unmarshal(data, &v) // let's assume this is a custom unmarshaler } golang-github-thedevsaddam-gojsonq-2.5.2/option.go000066400000000000000000000022131375452222100222140ustar00rootroot00000000000000package gojsonq import "errors" // option describes type for providing configuration options to JSONQ type option struct { decoder Decoder separator string } // OptionFunc represents a contract for option func, it basically set options to jsonq instance options type OptionFunc func(*JSONQ) error // SetDecoder take a custom decoder to decode JSON // Deprecated - use WithDecoder func SetDecoder(u Decoder) OptionFunc { return WithDecoder(u) } // SetSeparator set custom separator for traversing child node, default separator is DOT (.) // Deprecated - use WithSeparator func SetSeparator(s string) OptionFunc { return WithSeparator(s) } // WithDecoder take a custom decoder to decode JSON func WithDecoder(u Decoder) OptionFunc { return func(j *JSONQ) error { if u == nil { return errors.New("decoder can not be nil") } j.option.decoder = u return nil } } // WithSeparator set custom separator for traversing child node, default separator is DOT (.) func WithSeparator(s string) OptionFunc { return func(j *JSONQ) error { if s == "" { return errors.New("separator can not be empty") } j.option.separator = s return nil } } golang-github-thedevsaddam-gojsonq-2.5.2/option_test.go000066400000000000000000000026121375452222100232560ustar00rootroot00000000000000package gojsonq import ( "testing" ) func TestWithDecoder(t *testing.T) { jq := New(WithDecoder(&cDecoder{})) if jq.option.decoder == nil { t.Error("failed to set decoder as option") } } func TestWithDecoder_with_nil_expecting_an_error(t *testing.T) { jq := New(WithDecoder(nil)) if jq.Error() == nil { t.Error("failed to catch nil in WithDecoder") } } func TestWithSeparator(t *testing.T) { jq := New(WithSeparator("->")) if jq.option.separator != "->" { t.Error("failed to set separator as option") } } func TestWithSeparator_with_nil_expecting_an_error(t *testing.T) { jq := New(WithSeparator("")) if jq.Error() == nil { t.Error("failed to catch nil in WithSeparator") } } // to increase the code coverage; will remove in major release func TestSetDecoder(t *testing.T) { jq := New(SetDecoder(&cDecoder{})) if jq.option.decoder == nil { t.Error("failed to set decoder as option") } } func TestSetDecoder_with_nil_expecting_an_error(t *testing.T) { jq := New(SetDecoder(nil)) if jq.Error() == nil { t.Error("failed to catch nil in SetDecoder") } } func TestSetSeparator(t *testing.T) { jq := New(SetSeparator("->")) if jq.option.separator != "->" { t.Error("failed to set separator as option") } } func TestSetSeparator_with_nil_expecting_an_error(t *testing.T) { jq := New(SetSeparator("")) if jq.Error() == nil { t.Error("failed to catch nil in SetSeparator") } } golang-github-thedevsaddam-gojsonq-2.5.2/query.go000066400000000000000000000162721375452222100220630ustar00rootroot00000000000000package gojsonq import ( "fmt" "reflect" "strings" ) const ( operatorEq = "=" operatorEqEng = "eq" operatorNotEq = "!=" operatorNotEqEng = "neq" operatorNotEqAnother = "<>" operatorGt = ">" operatorGtEng = "gt" operatorLt = "<" operatorLtEng = "lt" operatorGtE = ">=" operatorGtEEng = "gte" operatorLtE = "<=" operatorLtEEng = "lte" operatorStrictContains = "strictContains" operatorContains = "contains" operatorEndsWith = "endsWith" operatorStartsWith = "startsWith" operatorIn = "in" operatorNotIn = "notIn" operatorLenEq = "leneq" operatorLenNotEq = "lenneq" operatorLenGt = "lengt" operatorLenGte = "lengte" operatorLenLt = "lenlt" operatorLenLte = "lenlte" ) func defaultQueries() map[string]QueryFunc { return map[string]QueryFunc{ operatorEq: eq, operatorEqEng: eq, operatorNotEq: neq, operatorNotEqEng: neq, operatorNotEqAnother: neq, operatorGt: gt, operatorGtEng: gt, operatorLt: lt, operatorLtEng: lt, operatorGtE: gte, operatorGtEEng: gte, operatorLtE: lte, operatorLtEEng: lte, operatorStrictContains: strStrictContains, operatorContains: strContains, operatorStartsWith: strStartsWith, operatorEndsWith: strEndsWith, operatorIn: in, operatorNotIn: notIn, operatorLenEq: lenEq, operatorLenNotEq: lenNotEq, operatorLenGt: lenGt, operatorLenGte: lenGte, operatorLenLt: lenLt, operatorLenLte: lenLte, } } // QueryFunc describes a conditional function which perform comparison type QueryFunc func(x, y interface{}) (bool, error) // eq checks whether x, y are deeply eq func eq(x, y interface{}) (bool, error) { // if the y value is numeric (int/int8-int64/float32/float64) then convert to float64 if fv, ok := toFloat64(y); ok { y = fv } return reflect.DeepEqual(x, y), nil } // neq checks whether x, y are deeply not equal func neq(x, y interface{}) (bool, error) { b, err := eq(x, y) return !b, err } // gt checks whether x is greather than y func gt(x, y interface{}) (bool, error) { xv, ok := x.(float64) if !ok { return false, fmt.Errorf("%v must be numeric", x) } // if the y value is numeric (int/int8-int64/float32/float64) then convert to float64 if fv, ok := toFloat64(y); ok { return xv > fv, nil } return false, nil } // lt checks whether x is less than y func lt(x, y interface{}) (bool, error) { xv, ok := x.(float64) if !ok { return false, fmt.Errorf("%v must be numeric", x) } // if the y value is numeric (int/int8-int64/float32/float64) then convert to float64 if fv, ok := toFloat64(y); ok { return xv < fv, nil } return false, nil } // gte checks whether x is greater than or equal to y func gte(x, y interface{}) (bool, error) { xv, ok := x.(float64) if !ok { return false, fmt.Errorf("%v must be numeric", x) } // if the y value is numeric (int/int8-int64/float32/float64) then convert to float64 if fv, ok := toFloat64(y); ok { return xv >= fv, nil } return false, nil } // lte checks whether x is less than or equal to y func lte(x, y interface{}) (bool, error) { xv, ok := x.(float64) if !ok { return false, fmt.Errorf("%v must be numeric", x) } // if the y value is numeric (int/int8-int64/float32/float64) then convert to float64 if fv, ok := toFloat64(y); ok { return xv <= fv, nil } return false, nil } // strStrictContains checks if x contains y // This is case sensitive search func strStrictContains(x, y interface{}) (bool, error) { xv, okX := x.(string) if !okX { return false, fmt.Errorf("%v must be string", x) } yv, okY := y.(string) if !okY { return false, fmt.Errorf("%v must be string", y) } return strings.Contains(xv, yv), nil } // strContains checks if x contains y // This is case insensitive search func strContains(x, y interface{}) (bool, error) { xv, okX := x.(string) if !okX { return false, fmt.Errorf("%v must be string", x) } yv, okY := y.(string) if !okY { return false, fmt.Errorf("%v must be string", y) } return strings.Contains(strings.ToLower(xv), strings.ToLower(yv)), nil } // strStartsWith checks if x starts with y func strStartsWith(x, y interface{}) (bool, error) { xv, okX := x.(string) if !okX { return false, fmt.Errorf("%v must be string", x) } yv, okY := y.(string) if !okY { return false, fmt.Errorf("%v must be string", y) } return strings.HasPrefix(xv, yv), nil } // strEndsWith checks if x ends with y func strEndsWith(x, y interface{}) (bool, error) { xv, okX := x.(string) if !okX { return false, fmt.Errorf("%v must be string", x) } yv, okY := y.(string) if !okY { return false, fmt.Errorf("%v must be string", y) } return strings.HasSuffix(xv, yv), nil } // in checks if x exists in y e.g: in("id", []int{1,3,5,8}) func in(x, y interface{}) (bool, error) { if yv, ok := y.([]string); ok { for _, v := range yv { if ok, _ := eq(x, v); ok { return true, nil } } } if yv, ok := y.([]int); ok { for _, v := range yv { if ok, _ := eq(x, v); ok { return true, nil } } } if yv, ok := y.([]float64); ok { for _, v := range yv { if ok, _ := eq(x, v); ok { return true, nil } } } return false, nil } // notIn checks if x doesn't exists in y e.g: in("id", []int{1,3,5,8}) func notIn(x, y interface{}) (bool, error) { b, err := in(x, y) return !b, err } // lenEq checks if the string/array/list value is equal func lenEq(x, y interface{}) (bool, error) { yv, ok := y.(int) if !ok { return false, fmt.Errorf("%v must be integer", y) } xv, err := length(x) if err != nil { return false, err } return xv == yv, nil } // lenNotEq checks if the string/array/list value is not equal func lenNotEq(x, y interface{}) (bool, error) { yv, ok := y.(int) if !ok { return false, fmt.Errorf("%v must be integer", y) } xv, err := length(x) if err != nil { return false, err } return xv != yv, nil } // lenGt checks if the string/array/list value is greater func lenGt(x, y interface{}) (bool, error) { yv, ok := y.(int) if !ok { return false, fmt.Errorf("%v must be integer", y) } xv, err := length(x) if err != nil { return false, err } return xv > yv, nil } // lenLt checks if the string/array/list value is less func lenLt(x, y interface{}) (bool, error) { yv, ok := y.(int) if !ok { return false, fmt.Errorf("%v must be integer", y) } xv, err := length(x) if err != nil { return false, err } return xv < yv, nil } // lenGte checks if the string/array/list value is greater than equal func lenGte(x, y interface{}) (bool, error) { yv, ok := y.(int) if !ok { return false, fmt.Errorf("%v must be integer", y) } xv, err := length(x) if err != nil { return false, err } return xv >= yv, nil } // lenLte checks if the string/array/list value is less than equal func lenLte(x, y interface{}) (bool, error) { yv, ok := y.(int) if !ok { return false, fmt.Errorf("%v must be integer", y) } xv, err := length(x) if err != nil { return false, err } return xv <= yv, nil } golang-github-thedevsaddam-gojsonq-2.5.2/query_test.go000066400000000000000000000321661375452222100231220ustar00rootroot00000000000000package gojsonq import ( "testing" ) func Test_eq(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { // our expectation for json unmarshaller is little bit different. here 9 provided by user will be equal to float64 9 x: 9.0, y: 9, expected: true, }, { x: 110, y: 120, expected: false, }, { x: 10.09, y: 10.09, expected: true, }, { x: 10.09, y: 10.89, expected: false, }, { x: "john", y: "john", expected: true, }, { x: "tom", y: "jane", expected: false, }, { x: "", y: "", expected: true, }, { x: nil, y: nil, expected: true, }, } for _, tc := range testCases { if o, _ := eq(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_neq(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: 9.0, // as x is out json unmarshal value which is float64 y: 9, // our expectation for json unmarshalar is little bit different. here 9 provided by user will be equal to float64 9 expected: false, }, { x: 110, y: 120, expected: true, }, { x: 10.09, y: 10.09, expected: false, }, { x: 10.09, y: 10.89, expected: true, }, { x: "john", y: "john", expected: false, }, { x: "tom", y: "jane", expected: true, }, { x: "", y: "", expected: false, }, { x: nil, y: nil, expected: false, }, } for _, tc := range testCases { if o, _ := neq(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_gt(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: 5, expected: true, }, { x: float64(10), y: 15, expected: false, }, { x: float64(10), y: "10", expected: false, }, { x: "101", y: "101", expected: false, }, } for _, tc := range testCases { if o, _ := gt(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lt(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: 5, expected: false, }, { x: float64(10), y: 15, expected: true, }, { x: float64(10), y: "10", expected: false, }, { x: "101", y: "101", expected: false, }, } for _, tc := range testCases { if o, _ := lt(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_gte(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: 5, expected: true, }, { x: float64(10), y: 15, expected: false, }, { x: float64(18), y: 18, expected: true, }, { x: float64(30.9), y: 30.9, expected: true, }, { x: float64(10), y: "10", expected: false, }, { x: "101", y: "101", expected: false, }, } for _, tc := range testCases { if o, _ := gte(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lte(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: 5, expected: false, }, { x: float64(10), y: 15, expected: true, }, { x: float64(18), y: 18, expected: true, }, { x: float64(30.9), y: 30.9, expected: true, }, { x: float64(40.9), y: 30.9, expected: false, }, { x: float64(10), y: "10", expected: false, }, { x: "101", y: "101", expected: false, }, } for _, tc := range testCases { if o, _ := lte(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_strStrictContains(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: "10", expected: false, }, { x: float64(11), y: float64(11), expected: false, }, { x: "131", y: float64(131), expected: false, }, { x: "458", y: "458", expected: true, }, { x: "arch", y: "arch", expected: true, }, { x: "Arch", y: "arch", expected: false, }, } for _, tc := range testCases { if o, _ := strStrictContains(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_strContains(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: "10", expected: false, }, { x: float64(11), y: float64(11), expected: false, }, { x: "131", y: float64(131), expected: false, }, { x: "458", y: "458", expected: true, }, { x: "arch", y: "arch", expected: true, }, { x: "Arch", y: "arcH", expected: true, }, } for _, tc := range testCases { if o, _ := strContains(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_strStartsWith(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: "10", expected: false, }, { x: float64(11), y: float64(11), expected: false, }, { x: "131", y: float64(131), expected: false, }, { x: "458", y: "458", expected: true, }, { x: "arch", y: "arch", expected: true, }, { x: "erik", y: "er", expected: true, }, } for _, tc := range testCases { if o, _ := strStartsWith(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_strEndsWith(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: float64(10), y: "10", expected: false, }, { x: float64(11), y: float64(11), expected: false, }, { x: "131", y: float64(131), expected: false, }, { x: "458", y: "458", expected: true, }, { x: "arch", y: "arch", expected: true, }, { x: "sky", y: "ky", expected: true, }, } for _, tc := range testCases { if o, _ := strEndsWith(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_in(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: "sky", y: []string{"river", "sun", "moon"}, expected: false, }, { x: "sun", y: []string{"river", "sun", "moon"}, expected: true, }, { x: float64(10), // ass json numeric value will be treat as float64 y: []int{11, 12, 14, 18}, expected: false, }, { x: float64(14), // ass json numeric value will be treat as float64 y: []int{11, 12, 14, 18}, expected: true, }, { x: float64(10), y: []float64{11, 12, 14, 18}, expected: false, }, { x: float64(14), y: []float64{11, 12, 14, 18}, expected: true, }, } for _, tc := range testCases { if o, _ := in(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_notIn(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: "sky", y: []string{"river", "sun", "moon"}, expected: true, }, { x: "sun", y: []string{"river", "sun", "moon"}, expected: false, }, { x: float64(10), // ass json numeric value will be treat as float64 y: []int{11, 12, 14, 18}, expected: true, }, { x: float64(14), // ass json numeric value will be treat as float64 y: []int{11, 12, 14, 18}, expected: false, }, { x: float64(10), y: []float64{11, 12, 14, 18}, expected: true, }, { x: float64(14), y: []float64{11, 12, 14, 18}, expected: false, }, } for _, tc := range testCases { if o, _ := notIn(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lenEq(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: []interface{}{"river", "sun", "moon"}, y: 3, expected: true, }, { x: "sun", y: 3, expected: true, }, { x: 100, y: 3, expected: false, }, { x: 100, y: 3, expected: false, }, { x: "moon", y: 4.0, expected: false, }, } for _, tc := range testCases { if o, _ := lenEq(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lenNotEq(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: []interface{}{"river", "sun", "moon"}, y: 6, expected: true, }, { x: "sun", y: 8, expected: true, }, { x: "moon", y: 4, expected: false, }, { x: 100.6, y: 4, expected: false, }, { x: "moon", y: 4.0, expected: false, }, } for _, tc := range testCases { if o, _ := lenNotEq(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lenGt(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: []interface{}{"river", "sun", "moon"}, y: 6, expected: false, }, { x: "sun", y: 2, expected: true, }, { x: "moon", y: 2, expected: true, }, { x: 100.6, y: 4, expected: false, }, { x: "moon", y: 4.0, expected: false, }, } for _, tc := range testCases { if o, _ := lenGt(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lenLt(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: []interface{}{"river", "sun", "moon"}, y: 6, expected: true, }, { x: "sun", y: 20, expected: true, }, { x: "moon", y: 3, expected: false, }, { x: 100.6, y: 4, expected: false, }, { x: "john", y: 4.0, expected: false, }, } for _, tc := range testCases { if o, _ := lenLt(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lenGte(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: []interface{}{"river", "sun", "moon"}, y: 3, expected: true, }, { x: "sun", y: 2, expected: true, }, { x: "jane", y: 5, expected: false, }, { x: 100.6, y: 4, expected: false, }, { x: "moon", y: 4.0, expected: false, }, } for _, tc := range testCases { if o, _ := lenGte(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_lenLte(t *testing.T) { testCases := []struct { x interface{} y interface{} expected bool }{ { x: []interface{}{"river", "sun", "moon"}, y: 3, expected: true, }, { x: "sun", y: 12, expected: true, }, { x: "jane", y: 2, expected: false, }, { x: 100.6, y: 4, expected: false, }, { x: "moon", y: 4.0, expected: false, }, } for _, tc := range testCases { if o, _ := lenLte(tc.x, tc.y); o != tc.expected { t.Errorf("for %v expected: %v got: %v", tc.x, tc.expected, o) } } } func Test_loadDefaultQueryMap(t *testing.T) { if len(defaultQueries()) != 25 { t.Error("mismatched default query map size") } } golang-github-thedevsaddam-gojsonq-2.5.2/result.go000066400000000000000000000305321375452222100222270ustar00rootroot00000000000000package gojsonq import ( "fmt" "reflect" "strings" "time" ) const errMessage = "gojsonq: wrong method call for %v" // Available named error values var ( ErrExpectsPointer = fmt.Errorf("gojsonq: failed to unmarshal, expects pointer") ErrImmutable = fmt.Errorf("gojsonq: failed to unmarshal, target is not mutable") ErrTypeMismatch = fmt.Errorf("gojsonq: failed to unmarshal, target type misatched") ) // NewResult return an instance of Result func NewResult(v interface{}) *Result { return &Result{value: v} } // Result represent custom type type Result struct { value interface{} } // Nil check the query has result or not func (r *Result) Nil() bool { return r.value == nil } // As sets the value of Result to v; It does not support methods with argument available in Result func (r *Result) As(v interface{}) error { if r.value != nil { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() { return ErrExpectsPointer } elm := rv.Elem() if !elm.CanSet() { return ErrImmutable } method := rv.Type().String() methodMap := map[string]string{ "*string": "String", "*bool": "Bool", "*time.Duration": "Duration", "*int": "Int", "*int8": "Int8", "*int16": "Int16", "*int32": "Int32", "*uint": "Uint", "*uint8": "Uint8", "*uint16": "Uint16", "*uint32": "Uint32", "*float32": "Float32", "*float64": "Float64", "*[]string": "StringSlice", "*[]bool": "BoolSlice", "*[]time.Duration": "DurationSlice", "*[]int": "IntSlice", "*[]int8": "Int8Slice", "*[]int16": "Int16Slice", "*[]int32": "Int32Slice", "*[]uint": "UintSlice", "*[]uint8": "Uint8Slice", "*[]uint16": "Uint16Slice", "*[]uint32": "Uint32Slice", "*[]float32": "Float32Slice", "*[]float64": "Float64Slice", } if methodMap[method] == "" { return fmt.Errorf("gojsonq: type [%T] is not available", v) } vv := reflect.ValueOf(r).MethodByName(methodMap[method]).Call(nil) if vv != nil { if vv[1].Interface() != nil { return ErrTypeMismatch } rv.Elem().Set(vv[0]) } } return nil } // Bool assert the result to boolean value func (r *Result) Bool() (bool, error) { switch v := r.value.(type) { case bool: return v, nil default: return false, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Time assert the result to time.Time func (r *Result) Time(layout string) (time.Time, error) { switch v := r.value.(type) { case string: return time.Parse(layout, v) default: return time.Time{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Duration assert the result to time.Duration func (r *Result) Duration() (time.Duration, error) { switch v := r.value.(type) { case float64: return time.Duration(v), nil case string: if strings.ContainsAny(v, "nsuµmh") { return time.ParseDuration(v) } return time.ParseDuration(v + "ns") default: return time.Duration(0), fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // String assert the result to String func (r *Result) String() (string, error) { switch v := r.value.(type) { case string: return v, nil default: return "", fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int assert the result to int func (r *Result) Int() (int, error) { switch v := r.value.(type) { case float64: return int(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int8 assert the result to int8 func (r *Result) Int8() (int8, error) { switch v := r.value.(type) { case float64: return int8(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int16 assert the result to int16 func (r *Result) Int16() (int16, error) { switch v := r.value.(type) { case float64: return int16(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int32 assert the result to int32 func (r *Result) Int32() (int32, error) { switch v := r.value.(type) { case float64: return int32(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int64 assert the result to int64 func (r *Result) Int64() (int64, error) { switch v := r.value.(type) { case float64: return int64(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint assert the result to uint func (r *Result) Uint() (uint, error) { switch v := r.value.(type) { case float64: return uint(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint8 assert the result to uint8 func (r *Result) Uint8() (uint8, error) { switch v := r.value.(type) { case float64: return uint8(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint16 assert the result to uint16 func (r *Result) Uint16() (uint16, error) { switch v := r.value.(type) { case float64: return uint16(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint32 assert the result to uint32 func (r *Result) Uint32() (uint32, error) { switch v := r.value.(type) { case float64: return uint32(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint64 assert the result to uint64 func (r *Result) Uint64() (uint64, error) { switch v := r.value.(type) { case float64: return uint64(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Float32 assert the result to float32 func (r *Result) Float32() (float32, error) { switch v := r.value.(type) { case float64: return float32(v), nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Float64 assert the result to 64 func (r *Result) Float64() (float64, error) { switch v := r.value.(type) { case float64: return v, nil default: return 0, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // TODO: Slice related methods - ideally they should return nil instead of empty struct // in case of any error or no result. To keep compatibility with older version refactored // to use make, in order to create slices. // BoolSlice assert the result to []bool func (r *Result) BoolSlice() ([]bool, error) { switch v := r.value.(type) { case []interface{}: var bb = make([]bool, 0) for _, si := range v { if s, ok := si.(bool); ok { bb = append(bb, s) } } return bb, nil default: return []bool{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // TimeSlice assert the result to []time.Time func (r *Result) TimeSlice(layout string) ([]time.Time, error) { switch v := r.value.(type) { case []interface{}: var tt = make([]time.Time, 0) for _, si := range v { if s, ok := si.(string); ok { ts, err := time.Parse(layout, s) if err != nil { return tt, err } tt = append(tt, ts) } } return tt, nil default: return []time.Time{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // DurationSlice assert the result to []time.Duration func (r *Result) DurationSlice() ([]time.Duration, error) { switch v := r.value.(type) { case []interface{}: var dd = make([]time.Duration, 0) for _, si := range v { if s, ok := si.(string); ok { var d time.Duration var err error if strings.ContainsAny(s, "nsuµmh") { d, err = time.ParseDuration(s) } else { d, err = time.ParseDuration(s + "ns") } if err != nil { return dd, err } dd = append(dd, d) } if v, ok := si.(float64); ok { dd = append(dd, time.Duration(v)) } } return dd, nil default: return []time.Duration{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // StringSlice assert the result to []string func (r *Result) StringSlice() ([]string, error) { switch v := r.value.(type) { case []interface{}: var ss = make([]string, 0) for _, si := range v { if s, ok := si.(string); ok { ss = append(ss, s) } } return ss, nil default: return []string{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // IntSlice assert the result to []int func (r *Result) IntSlice() ([]int, error) { switch v := r.value.(type) { case []interface{}: var ii = make([]int, 0) for _, si := range v { if s, ok := si.(float64); ok { ii = append(ii, int(s)) } } return ii, nil default: return []int{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int8Slice assert the result to []int8 func (r *Result) Int8Slice() ([]int8, error) { switch v := r.value.(type) { case []interface{}: var ii = make([]int8, 0) for _, si := range v { if s, ok := si.(float64); ok { ii = append(ii, int8(s)) } } return ii, nil default: return []int8{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int16Slice assert the result to []int16 func (r *Result) Int16Slice() ([]int16, error) { switch v := r.value.(type) { case []interface{}: var ii = make([]int16, 0) for _, si := range v { if s, ok := si.(float64); ok { ii = append(ii, int16(s)) } } return ii, nil default: return []int16{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int32Slice assert the result to []int32 func (r *Result) Int32Slice() ([]int32, error) { switch v := r.value.(type) { case []interface{}: var ii = make([]int32, 0) for _, si := range v { if s, ok := si.(float64); ok { ii = append(ii, int32(s)) } } return ii, nil default: return []int32{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Int64Slice assert the result to []int64 func (r *Result) Int64Slice() ([]int64, error) { switch v := r.value.(type) { case []interface{}: var ii = make([]int64, 0) for _, si := range v { if s, ok := si.(float64); ok { ii = append(ii, int64(s)) } } return ii, nil default: return []int64{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // UintSlice assert the result to []uint func (r *Result) UintSlice() ([]uint, error) { switch v := r.value.(type) { case []interface{}: var uu = make([]uint, 0) for _, si := range v { if s, ok := si.(float64); ok { uu = append(uu, uint(s)) } } return uu, nil default: return []uint{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint8Slice assert the result to []uint8 func (r *Result) Uint8Slice() ([]uint8, error) { switch v := r.value.(type) { case []interface{}: var uu = make([]uint8, 0) for _, si := range v { if s, ok := si.(float64); ok { uu = append(uu, uint8(s)) } } return uu, nil default: return []uint8{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint16Slice assert the result to []uint16 func (r *Result) Uint16Slice() ([]uint16, error) { switch v := r.value.(type) { case []interface{}: var uu = make([]uint16, 0) for _, si := range v { if s, ok := si.(float64); ok { uu = append(uu, uint16(s)) } } return uu, nil default: return []uint16{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint32Slice assert the result to []uint32 func (r *Result) Uint32Slice() ([]uint32, error) { switch v := r.value.(type) { case []interface{}: var uu = make([]uint32, 0) for _, si := range v { if s, ok := si.(float64); ok { uu = append(uu, uint32(s)) } } return uu, nil default: return []uint32{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Uint64Slice assert the result to []uint64 func (r *Result) Uint64Slice() ([]uint64, error) { switch v := r.value.(type) { case []interface{}: var uu = make([]uint64, 0) for _, si := range v { if s, ok := si.(float64); ok { uu = append(uu, uint64(s)) } } return uu, nil default: return []uint64{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Float32Slice assert the result to []float32 func (r *Result) Float32Slice() ([]float32, error) { switch v := r.value.(type) { case []interface{}: var ff = make([]float32, 0) for _, si := range v { if s, ok := si.(float64); ok { ff = append(ff, float32(s)) } } return ff, nil default: return []float32{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } // Float64Slice assert the result to []float64 func (r *Result) Float64Slice() ([]float64, error) { switch v := r.value.(type) { case []interface{}: var ff = make([]float64, 0) for _, si := range v { if s, ok := si.(float64); ok { ff = append(ff, s) } } return ff, nil default: return []float64{}, fmt.Errorf(errMessage, reflect.ValueOf(r.value).Kind()) } } golang-github-thedevsaddam-gojsonq-2.5.2/result_test.go000066400000000000000000000715401375452222100232720ustar00rootroot00000000000000package gojsonq import ( "reflect" "testing" "time" ) func TestNewResult(t *testing.T) { result := NewResult("gojsonq") if reflect.ValueOf(result).Type().String() != "*gojsonq.Result" { t.Error("failed to match gojsonq.Result type") } } func TestNil(t *testing.T) { result := NewResult(nil) if result.Nil() == false { t.Error("failed to check Nil") } } func TestAs(t *testing.T) { type flt float64 testCases := []struct { tag string value interface{} newExpectedValue func() interface{} expect func(value, i interface{}) bool errExpect bool }{ { tag: "float64 as int", // golang unmarshal number to float64 value: float64(1), newExpectedValue: func() interface{} { var a int return &a }, expect: func(value, i interface{}) bool { val, ok := i.(int) if !ok { return false } return val == (value.(int)) }, errExpect: false, }, { tag: "float64 as uint", value: float64(1), newExpectedValue: func() interface{} { var a uint return &a }, expect: func(value, i interface{}) bool { val, ok := i.(uint) if !ok { return false } return val == (value.(uint)) }, errExpect: false, }, { tag: "float64 assign to non ptr", value: float64(1), newExpectedValue: func() interface{} { var a float64 return a }, expect: func(value, i interface{}) bool { val, ok := i.(float64) if !ok { return false } return val == (value.(float64)) }, errExpect: true, }, { tag: "string assign to int", value: string("*nop"), newExpectedValue: func() interface{} { var a float64 return &a }, expect: func(value, i interface{}) bool { val, ok := i.(string) if !ok { return false } return val == (value.(string)) }, errExpect: true, }, { tag: "custom type error check", value: string("*nop"), newExpectedValue: func() interface{} { var a flt return &a }, expect: func(value, i interface{}) bool { val, ok := i.(string) if !ok { return false } return val == (value.(string)) }, errExpect: true, }, } for _, tc := range testCases { expected := tc.newExpectedValue() err := NewResult(tc.value).As(expected) if err != nil && !tc.errExpect { t.Error(tc.tag, err) } if tc.expect(tc.value, expected) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.value, reflect.ValueOf(expected).Elem()) } } } func TestBool(t *testing.T) { testCases := []struct { tag string value interface{} valExpect bool errExpect bool }{ {tag: "bool value as expected", value: true, valExpect: true, errExpect: false}, {tag: "invalid bool, error expected", value: 123, valExpect: false, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Bool() if err != nil && !tc.errExpect { t.Error("bool:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestTime(t *testing.T) { layout := "2006-01-02T15:04:05.000Z" str := "2014-11-12T11:45:26.371Z" tm, err := time.Parse(layout, str) if err != nil { t.Error("failed to parse time:", err) } testCases := []struct { tag string value interface{} valExpect time.Time errExpect bool }{ {tag: "time value as expected", value: "2014-11-12T11:45:26.371Z", valExpect: tm, errExpect: false}, {tag: "invalid time, error expected", value: "2014-11-12", valExpect: time.Time{}, errExpect: true}, {tag: "invalid time, error expected", value: 12322, valExpect: time.Time{}, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Time(layout) if err != nil && !tc.errExpect { t.Error("time:", err) } if !reflect.DeepEqual(v, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestDuration(t *testing.T) { testCases := []struct { tag string value interface{} valExpect time.Duration errExpect bool }{ {tag: "duration value as expected", value: "10s", valExpect: time.Duration(10 * time.Second), errExpect: false}, {tag: "duration value as expected", value: "10m", valExpect: time.Duration(10 * time.Minute), errExpect: false}, {tag: "duration value as expected", value: float64(10), valExpect: time.Duration(10 * time.Nanosecond), errExpect: false}, // go decode number to float64 {tag: "invalid duration, error expected", value: "1", valExpect: time.Duration(0), errExpect: true}, {tag: "invalid duration, error expected", value: 1, valExpect: time.Duration(0), errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Duration() if err != nil && !tc.errExpect { t.Error("duration:", err) } if !reflect.DeepEqual(v, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestString(t *testing.T) { testCases := []struct { tag string value interface{} valExpect string errExpect bool }{ {tag: "string value as expected", value: "hello", valExpect: "hello", errExpect: false}, {tag: "invalid string, error expected", value: 123, valExpect: "", errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).String() if err != nil && !tc.errExpect { t.Error("string: ", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestInt(t *testing.T) { testCases := []struct { tag string value interface{} valExpect int errExpect bool }{ {tag: "int value as expected", value: 123.8, valExpect: 123, errExpect: false}, {tag: "int value as expected", value: 12.3, valExpect: 12, errExpect: false}, {tag: "invalid int, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Int() if err != nil && !tc.errExpect { t.Error("int:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestInt8(t *testing.T) { testCases := []struct { tag string value interface{} valExpect int8 errExpect bool }{ {tag: "int8 value as expected", value: 123.8, valExpect: int8(123), errExpect: false}, {tag: "int8 value as expected", value: 12.3, valExpect: int8(12), errExpect: false}, {tag: "invalid int8, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Int8() if err != nil && !tc.errExpect { t.Error("int8:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestInt16(t *testing.T) { testCases := []struct { tag string value interface{} valExpect int16 errExpect bool }{ {tag: "int16 value as expected", value: 123.8, valExpect: int16(123), errExpect: false}, {tag: "int16 value as expected", value: 12.3, valExpect: int16(12), errExpect: false}, {tag: "invalid int16, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Int16() if err != nil && !tc.errExpect { t.Error("int16:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestInt32(t *testing.T) { testCases := []struct { tag string value interface{} valExpect int32 errExpect bool }{ {tag: "int32 value as expected", value: 123.8, valExpect: int32(123), errExpect: false}, {tag: "int32 value as expected", value: 12.3, valExpect: int32(12), errExpect: false}, {tag: "invalid int32, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Int32() if err != nil && !tc.errExpect { t.Error("int32:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestInt64(t *testing.T) { testCases := []struct { tag string value interface{} valExpect int64 errExpect bool }{ {tag: "int64 value as expected", value: 123.8, valExpect: int64(123), errExpect: false}, {tag: "int64 value as expected", value: 12.3, valExpect: int64(12), errExpect: false}, {tag: "invalid int64, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Int64() if err != nil && !tc.errExpect { t.Error("int64:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestUint(t *testing.T) { testCases := []struct { tag string value interface{} valExpect uint errExpect bool }{ {tag: "uint value as expected", value: 123.8, valExpect: uint(123), errExpect: false}, {tag: "uint value as expected", value: 12.3, valExpect: uint(12), errExpect: false}, {tag: "invalid uint, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Uint() if err != nil && !tc.errExpect { t.Error("uint:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestUint8(t *testing.T) { testCases := []struct { tag string value interface{} valExpect uint8 errExpect bool }{ {tag: "uint8 value as expected", value: 123.8, valExpect: uint8(123), errExpect: false}, {tag: "uint8 value as expected", value: 12.3, valExpect: uint8(12), errExpect: false}, {tag: "invalid uint8, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Uint8() if err != nil && !tc.errExpect { t.Error("uint8:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestUint16(t *testing.T) { testCases := []struct { tag string value interface{} valExpect uint16 errExpect bool }{ {tag: "uint16 value as expected", value: 123.8, valExpect: uint16(123), errExpect: false}, {tag: "uint16 value as expected", value: 12.3, valExpect: uint16(12), errExpect: false}, {tag: "invalid uint16, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Uint16() if err != nil && !tc.errExpect { t.Error("uint16:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestUint32(t *testing.T) { testCases := []struct { tag string value interface{} valExpect uint32 errExpect bool }{ {tag: "uint32 value as expected", value: 123.8, valExpect: uint32(123), errExpect: false}, {tag: "uint32 value as expected", value: 12.3, valExpect: uint32(12), errExpect: false}, {tag: "invalid uint32, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Uint32() if err != nil && !tc.errExpect { t.Error("uint32:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestUint64(t *testing.T) { testCases := []struct { tag string value interface{} valExpect uint64 errExpect bool }{ {tag: "uint64 value as expected", value: 123.8, valExpect: uint64(123), errExpect: false}, {tag: "uint64 value as expected", value: 12.3, valExpect: uint64(12), errExpect: false}, {tag: "invalid uint64, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Uint64() if err != nil && !tc.errExpect { t.Error("uint64:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestFloat32(t *testing.T) { testCases := []struct { tag string value interface{} valExpect float32 errExpect bool }{ {tag: "float32 value as expected", value: 123.8, valExpect: float32(123.8), errExpect: false}, {tag: "float32 value as expected", value: 12.3, valExpect: float32(12.3), errExpect: false}, {tag: "invalid float32, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Float32() if err != nil && !tc.errExpect { t.Error("float32:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestFloat64(t *testing.T) { testCases := []struct { tag string value interface{} valExpect float64 errExpect bool }{ {tag: "float64 value as expected", value: 123.8, valExpect: float64(123.8), errExpect: false}, {tag: "float64 value as expected", value: 12.3, valExpect: float64(12.3), errExpect: true}, {tag: "invalid float64, error expected", value: "123", valExpect: 0, errExpect: true}, } for _, tc := range testCases { v, err := NewResult(tc.value).Float64() if err != nil && !tc.errExpect { t.Error("float64:", err) } if v != tc.valExpect && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, v) } } } func TestBoolSlice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []bool errExpect bool }{ {tag: "boolSlice value as expected", value: []interface{}{true, false}, valExpect: []bool{true, false}, errExpect: false}, {tag: "boolSlice value as expected", value: []interface{}{false, true, true}, valExpect: []bool{false, true, true}, errExpect: false}, {tag: "invalid boolSlice, error expected", value: []interface{}{1, 3}, valExpect: []bool{}, errExpect: false}, {tag: "invalid boolSlice, error expected", value: []int{1, 3}, valExpect: []bool{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).BoolSlice() if err != nil && !tc.errExpect { t.Error("boolSlice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestTimelice(t *testing.T) { layout := "2006-01-02T15:04:05.000Z" t1, err1 := time.Parse(layout, "2014-11-12T11:45:26.371Z") if err1 != nil { t.Error("failed to parse time1:", err1) } t2, err2 := time.Parse(layout, "2019-11-12T11:45:26.371Z") if err2 != nil { t.Error("failed to parse time2:", err2) } testCases := []struct { tag string value interface{} timeLayout string valExpect []time.Time errExpect bool }{ {tag: "timeSlice value as expected", value: []interface{}{"2014-11-12T11:45:26.371Z", "2019-11-12T11:45:26.371Z"}, timeLayout: layout, valExpect: []time.Time{t1, t2}, errExpect: false}, {tag: "invalid timeSlice layout, error expected", value: []interface{}{"2014-11-12T11:45:26.371Z", "2019-11-12T11:45:26.371Z"}, timeLayout: "invalid layout", valExpect: []time.Time{}, errExpect: true}, {tag: "invalid timeSlice, error expected", value: []int{1, 3}, timeLayout: layout, valExpect: []time.Time{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).TimeSlice(tc.timeLayout) if err != nil && !tc.errExpect { t.Error("timeSlice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestDurationlice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []time.Duration errExpect bool }{ {tag: "durationSlice value as expected", value: []interface{}{"1s", "1m"}, valExpect: []time.Duration{1 * time.Second, 1 * time.Minute}, errExpect: false}, {tag: "durationSlice value as expected", value: []interface{}{"1", "2"}, valExpect: []time.Duration{1 * time.Nanosecond, 2 * time.Nanosecond}, errExpect: false}, {tag: "durationSlice value as expected", value: []interface{}{float64(2), float64(3)}, valExpect: []time.Duration{2 * time.Nanosecond, 3 * time.Nanosecond}, errExpect: false}, {tag: "invalid durationSlice, error expected", value: []interface{}{"invalid duration 1", "invalid duration 2"}, valExpect: []time.Duration{}, errExpect: true}, {tag: "invalid durationSlice, error expected", value: []float64{3, 5}, valExpect: []time.Duration{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).DurationSlice() if err != nil && !tc.errExpect { t.Error("durationSlice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestStringSlice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []string errExpect bool }{ {tag: "stringSlice value as expected", value: []interface{}{"hello", "world"}, valExpect: []string{"hello", "world"}, errExpect: false}, {tag: "stringSlice value as expected", value: []interface{}{"tom", "jerry"}, valExpect: []string{"tom", "jerry"}, errExpect: false}, {tag: "invalid stringSlice, error expected", value: []interface{}{1, 3}, valExpect: []string{}, errExpect: false}, {tag: "invalid stringSlice, error expected", value: []int{1, 3}, valExpect: []string{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).StringSlice() if err != nil && !tc.errExpect { t.Error("stringSlice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestIntSlice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []int errExpect bool }{ {tag: "intSlice value as expected", value: []interface{}{132.1, 12.99}, valExpect: []int{132, 12}, errExpect: false}, {tag: "intSlice value as expected", value: []interface{}{float64(131), float64(12)}, valExpect: []int{131, 12}, errExpect: false}, // as golang decode number to float64 {tag: "invalid intSlice, error expected", value: []interface{}{1, 3}, valExpect: []int{}, errExpect: false}, {tag: "invalid intSlice, error expected", value: []int{1, 3}, valExpect: []int{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).IntSlice() if err != nil && !tc.errExpect { t.Error("intSlice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestInt8Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []int8 errExpect bool }{ {tag: "int8Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []int8{3, 12}, errExpect: false}, {tag: "int8Slice value as expected", value: []interface{}{float64(11), float64(12)}, valExpect: []int8{11, 12}, errExpect: false}, // as golang decode number to float64 {tag: "invalid int8Slice, error expected", value: []interface{}{1, 3}, valExpect: []int8{}, errExpect: false}, {tag: "invalid int8Slice, error expected", value: []int{1, 3}, valExpect: []int8{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Int8Slice() if err != nil && !tc.errExpect { t.Error("int8Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestInt16Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []int16 errExpect bool }{ {tag: "int16Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []int16{3, 12}, errExpect: false}, {tag: "int16Slice value as expected", value: []interface{}{float64(11), float64(12)}, valExpect: []int16{11, 12}, errExpect: false}, // as golang decode number to float64 {tag: "invalid int16Slice, error expected", value: []interface{}{1, 3}, valExpect: []int16{}, errExpect: false}, {tag: "invalid int16Slice, error expected", value: []int{1, 3}, valExpect: []int16{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Int16Slice() if err != nil && !tc.errExpect { t.Error("int16Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestInt32Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []int32 errExpect bool }{ {tag: "int32Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []int32{3, 12}, errExpect: false}, {tag: "int32Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []int32{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid int32Slice, error expected", value: []interface{}{1, 3}, valExpect: []int32{}, errExpect: false}, {tag: "invalid int32Slice, error expected", value: []int{1, 3}, valExpect: []int32{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Int32Slice() if err != nil && !tc.errExpect { t.Error("int32Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestInt64Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []int64 errExpect bool }{ {tag: "int64Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []int64{3, 12}, errExpect: false}, {tag: "int64Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []int64{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid int64Slice, error expected", value: []interface{}{1, 3}, valExpect: []int64{}, errExpect: false}, {tag: "invalid int64Slice, error expected", value: []int{1, 3}, valExpect: []int64{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Int64Slice() if err != nil && !tc.errExpect { t.Error("int64Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestUintSlice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []uint errExpect bool }{ {tag: "uintSlice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []uint{3, 12}, errExpect: false}, {tag: "uintSlice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []uint{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid uintSlice, error expected", value: []interface{}{1, 3}, valExpect: []uint{}, errExpect: false}, {tag: "invalid uintSlice, error expected", value: []int{1, 3}, valExpect: []uint{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).UintSlice() if err != nil && !tc.errExpect { t.Error("uintSlice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestUint8Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []uint8 errExpect bool }{ {tag: "uint8Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []uint8{3, 12}, errExpect: false}, {tag: "uint8Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []uint8{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid uint8Slice, error expected", value: []interface{}{1, 3}, valExpect: []uint8{}, errExpect: false}, {tag: "invalid uint8Slice, error expected", value: []int{1, 3}, valExpect: []uint8{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Uint8Slice() if err != nil && !tc.errExpect { t.Error("uint8Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestUint16Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []uint16 errExpect bool }{ {tag: "uint16Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []uint16{3, 12}, errExpect: false}, {tag: "uint16Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []uint16{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid uint16Slice, error expected", value: []interface{}{1, 3}, valExpect: []uint16{}, errExpect: false}, {tag: "invalid uint16Slice, error expected", value: []int{1, 3}, valExpect: []uint16{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Uint16Slice() if err != nil && !tc.errExpect { t.Error("uint16Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestUint32Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []uint32 errExpect bool }{ {tag: "uint32Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []uint32{3, 12}, errExpect: false}, {tag: "uint32Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []uint32{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid uint32Slice, error expected", value: []interface{}{1, 3}, valExpect: []uint32{}, errExpect: false}, {tag: "invalid uint32Slice, error expected", value: []int{1, 3}, valExpect: []uint32{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Uint32Slice() if err != nil && !tc.errExpect { t.Error("uint32Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestUint64Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []uint64 errExpect bool }{ {tag: "uint64Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []uint64{3, 12}, errExpect: false}, {tag: "uint64Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []uint64{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid uint64Slice, error expected", value: []interface{}{1, 3}, valExpect: []uint64{}, errExpect: false}, {tag: "invalid uint64Slice, error expected", value: []int{1, 3}, valExpect: []uint64{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Uint64Slice() if err != nil && !tc.errExpect { t.Error("uint64Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestFloat32Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []float32 errExpect bool }{ {tag: "float32Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []float32{3.1, 12.99}, errExpect: false}, {tag: "float32Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []float32{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid float32Slice, error expected", value: []interface{}{1, 3}, valExpect: []float32{}, errExpect: false}, {tag: "invalid float32Slice, error expected", value: []int{1, 3}, valExpect: []float32{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Float32Slice() if err != nil && !tc.errExpect { t.Error("float32Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } } func TestFloat64Slice(t *testing.T) { testCases := []struct { tag string value interface{} valExpect []float64 errExpect bool }{ {tag: "float64Slice value as expected", value: []interface{}{3.1, 12.99}, valExpect: []float64{3.1, 12.99}, errExpect: false}, {tag: "float64Slice value as expected", value: []interface{}{float64(131), float64(132)}, valExpect: []float64{131, 132}, errExpect: false}, // as golang decode number to float64 {tag: "invalid float64Slice, error expected", value: []interface{}{1, 3}, valExpect: []float64{}, errExpect: false}, {tag: "invalid float64Slice, error expected", value: []int{1, 3}, valExpect: []float64{}, errExpect: true}, } for _, tc := range testCases { vv, err := NewResult(tc.value).Float64Slice() if err != nil && !tc.errExpect { t.Error("float64Slice:", err) } if !reflect.DeepEqual(vv, tc.valExpect) && !tc.errExpect { t.Errorf("tag: %s\nexpected: %v got %v", tc.tag, tc.valExpect, vv) } } }