Skip to content

Commit bde19fd

Browse files
committed
Fix distinct issue with other chained methods
1 parent 9cde93e commit bde19fd

File tree

2 files changed

+112
-20
lines changed

2 files changed

+112
-20
lines changed

jsonq.go

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,18 @@ type query struct {
3535

3636
// JSONQ describes a JSONQ type which contains all the state
3737
type JSONQ struct {
38-
option option // contains options for JSONQ
39-
queryMap map[string]QueryFunc // contains query functions
40-
node string // contains node name
41-
raw json.RawMessage // raw message from source (reader, string or file)
42-
rootJSONContent interface{} // original decoded json data
43-
jsonContent interface{} // copy of original decoded json data for further processing
44-
queryIndex int // contains number of orWhere query call
45-
queries [][]query // nested queries
46-
attributes []string // select attributes that will be available in final resuls
47-
limitRecords int // number of records that willbe available in final result
48-
errors []error // contains all the errors when processing
38+
option option // contains options for JSONQ
39+
queryMap map[string]QueryFunc // contains query functions
40+
node string // contains node name
41+
raw json.RawMessage // raw message from source (reader, string or file)
42+
rootJSONContent interface{} // original decoded json data
43+
jsonContent interface{} // copy of original decoded json data for further processing
44+
queryIndex int // contains number of orWhere query call
45+
queries [][]query // nested queries
46+
attributes []string // select attributes that will be available in final resuls
47+
limitRecords int // number of records that willbe available in final result
48+
distinctProperty string // contain the distinct attribute name
49+
errors []error // contains all the errors when processing
4950
}
5051

5152
// String satisfies stringer interface
@@ -382,14 +383,18 @@ func (j *JSONQ) SortBy(order ...string) *JSONQ {
382383

383384
// Distinct builds distinct value using provided attribute/column/property
384385
func (j *JSONQ) Distinct(property string) *JSONQ {
385-
j.prepare()
386+
j.distinctProperty = property
387+
return j
388+
}
386389

390+
// distinct builds distinct value using provided attribute/column/property
391+
func (j *JSONQ) distinct() *JSONQ {
387392
m := map[string]bool{}
388393
dt := []interface{}{}
389394
if aa, ok := j.jsonContent.([]interface{}); ok {
390395
for _, a := range aa {
391396
if vm, ok := a.(map[string]interface{}); ok {
392-
v, err := getNestedValue(vm, property)
397+
v, err := getNestedValue(vm, j.distinctProperty)
393398
if err != nil {
394399
j.addError(err)
395400
} else {
@@ -435,6 +440,9 @@ func (j *JSONQ) sortBy(property string, asc bool) *JSONQ {
435440
// only return selected properties in result
436441
func (j *JSONQ) only(properties ...string) interface{} {
437442
result := []interface{}{}
443+
if j.distinctProperty != "" {
444+
j.distinct()
445+
}
438446
if aa, ok := j.jsonContent.([]interface{}); ok {
439447
for _, am := range aa {
440448
tmap := map[string]interface{}{}
@@ -463,6 +471,12 @@ func (j *JSONQ) Only(properties ...string) interface{} {
463471
// Pluck build an array of vlaues form a property of a list of objects
464472
func (j *JSONQ) Pluck(property string) interface{} {
465473
j.prepare()
474+
if j.distinctProperty != "" {
475+
j.distinct()
476+
}
477+
if j.limitRecords != 0 {
478+
j.limit()
479+
}
466480
result := []interface{}{}
467481
if aa, ok := j.jsonContent.([]interface{}); ok {
468482
for _, am := range aa {
@@ -484,6 +498,7 @@ func (j *JSONQ) reset() *JSONQ {
484498
j.attributes = make([]string, 0)
485499
j.queryIndex = 0
486500
j.limitRecords = 0
501+
j.distinctProperty = ""
487502
return j
488503
}
489504

@@ -495,6 +510,9 @@ func (j *JSONQ) Reset() *JSONQ {
495510
// Get return the result
496511
func (j *JSONQ) Get() interface{} {
497512
j.prepare()
513+
if j.distinctProperty != "" {
514+
j.distinct()
515+
}
498516
if j.limitRecords != 0 {
499517
j.limit()
500518
}
@@ -506,8 +524,11 @@ func (j *JSONQ) Get() interface{} {
506524

507525
// First returns the first element of a list
508526
func (j *JSONQ) First() interface{} {
509-
res := j.prepare().jsonContent
510-
if arr, ok := res.([]interface{}); ok {
527+
j.prepare()
528+
if j.distinctProperty != "" {
529+
j.distinct()
530+
}
531+
if arr, ok := j.jsonContent.([]interface{}); ok {
511532
if len(arr) > 0 {
512533
return arr[0]
513534
}
@@ -517,8 +538,11 @@ func (j *JSONQ) First() interface{} {
517538

518539
// Last returns the last element of a list
519540
func (j *JSONQ) Last() interface{} {
520-
res := j.prepare().jsonContent
521-
if arr, ok := res.([]interface{}); ok {
541+
j.prepare()
542+
if j.distinctProperty != "" {
543+
j.distinct()
544+
}
545+
if arr, ok := j.jsonContent.([]interface{}); ok {
522546
if l := len(arr); l > 0 {
523547
return arr[l-1]
524548
}
@@ -533,8 +557,11 @@ func (j *JSONQ) Nth(index int) interface{} {
533557
return empty
534558
}
535559

536-
res := j.prepare().jsonContent
537-
if arr, ok := res.([]interface{}); ok {
560+
j.prepare()
561+
if j.distinctProperty != "" {
562+
j.distinct()
563+
}
564+
if arr, ok := j.jsonContent.([]interface{}); ok {
538565
alen := len(arr)
539566
if alen == 0 {
540567
j.addError(fmt.Errorf("list is empty"))
@@ -561,6 +588,9 @@ func (j *JSONQ) Find(path string) interface{} {
561588
// This could be a length of list/array/map
562589
func (j *JSONQ) Count() int {
563590
j.prepare()
591+
if j.distinctProperty != "" {
592+
j.distinct()
593+
}
564594
lnth := 0
565595
// list of items
566596
if list, ok := j.jsonContent.([]interface{}); ok {
@@ -580,7 +610,7 @@ func (j *JSONQ) Count() int {
580610

581611
// Out write the queried data to defined custom type
582612
func (j *JSONQ) Out(v interface{}) {
583-
data, err := json.Marshal(j.jsonContent)
613+
data, err := json.Marshal(j.Get())
584614
if err != nil {
585615
j.addError(err)
586616
return
@@ -626,6 +656,12 @@ func (j *JSONQ) getFloatValFromArray(arr []interface{}, property ...string) []fl
626656
// getAggregationValues returns a list of float64 values for aggregation
627657
func (j *JSONQ) getAggregationValues(property ...string) []float64 {
628658
j.prepare()
659+
if j.distinctProperty != "" {
660+
j.distinct()
661+
}
662+
if j.limitRecords != 0 {
663+
j.limit()
664+
}
629665

630666
ff := []float64{}
631667
if arr, ok := j.jsonContent.([]interface{}); ok {

jsonq_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,14 @@ func TestJSONQ_Only(t *testing.T) {
728728
assertJSON(t, out, expected)
729729
}
730730

731+
func TestJSONQ_Only_with_distinct(t *testing.T) {
732+
jq := New().JSONString(jsonStr).
733+
From("vendor.items").Distinct("price")
734+
expected := `[{"id":1,"price":1350},{"id":2,"price":1700},{"id":3,"price":1200},{"id":4,"price":850},{"id":6,"price":950}]`
735+
out := jq.Only("id", "price")
736+
assertJSON(t, out, expected)
737+
}
738+
731739
func TestJSONQ_First_expecting_result(t *testing.T) {
732740
jq := New().JSONString(jsonStr).
733741
From("vendor.items")
@@ -745,6 +753,14 @@ func TestJSONQ_First_expecting_empty_result(t *testing.T) {
745753
assertJSON(t, out, expected, "First expecting empty result")
746754
}
747755

756+
func TestJSONQ_First_distinct_expecting_result(t *testing.T) {
757+
jq := New().JSONString(jsonStr).
758+
From("vendor.items").Distinct("price").Where("price", "=", 850)
759+
expected := `{"id":4,"name":"Fujitsu","price":850}`
760+
out := jq.First()
761+
assertJSON(t, out, expected, "First with distinct & where expecting result result")
762+
}
763+
748764
func TestJSONQ_Last_expecting_result(t *testing.T) {
749765
jq := New().JSONString(jsonStr).
750766
From("vendor.items")
@@ -762,6 +778,14 @@ func TestJSONQ_Last_expecting_empty_result(t *testing.T) {
762778
assertJSON(t, out, expected, "Last expecting empty result")
763779
}
764780

781+
func TestJSONQ_Last_distinct_expecting_result(t *testing.T) {
782+
jq := New().JSONString(jsonStr).
783+
From("vendor.items").Distinct("price").Where("price", "=", 850)
784+
expected := `{"id":4,"name":"Fujitsu","price":850}`
785+
out := jq.Last()
786+
assertJSON(t, out, expected, "Last with distinct & where expecting result result")
787+
}
788+
765789
func TestJSONQ_Nth_expecting_result(t *testing.T) {
766790
jq := New().JSONString(jsonStr).
767791
From("vendor.items")
@@ -829,6 +853,14 @@ func TestJSONQ_Nth_expecting_empty_result_as_node_is_object(t *testing.T) {
829853
assertJSON(t, out, expected, "Nth expecting empty result if the node is a object")
830854
}
831855

856+
func TestJSONQ_Nth_distinct_expecting_result(t *testing.T) {
857+
jq := New().JSONString(jsonStr).
858+
From("vendor.items").Distinct("price")
859+
expected := `{"id":1,"name":"MacBook Pro 13 inch retina","price":1350}`
860+
out := jq.Nth(1)
861+
assertJSON(t, out, expected, "Last with distinct & where expecting result result")
862+
}
863+
832864
func TestJSONQ_Find_simple_property(t *testing.T) {
833865
jq := New().JSONString(jsonStr)
834866
out := jq.Find("name")
@@ -859,6 +891,14 @@ func TestJSONQ_Pluck_expecting_empty_list_of_float64(t *testing.T) {
859891
assertJSON(t, out, expected, "Pluck expecting empty list from list of objects, because of invalid property name")
860892
}
861893

894+
func TestJSONQ_Pluck_expecting_with_distinct(t *testing.T) {
895+
jq := New().JSONString(jsonStr).
896+
From("vendor.items").Distinct("price").Limit(3)
897+
out := jq.Pluck("price")
898+
expected := `[1350,1700,1200]`
899+
assertJSON(t, out, expected, "Expecting distinct price with limit 3")
900+
}
901+
862902
func TestJSONQ_Count_expecting_int_from_list(t *testing.T) {
863903
jq := New().JSONString(jsonStr).
864904
From("vendor.items")
@@ -884,6 +924,14 @@ func TestJSONQ_Count_expecting_int_from_objects(t *testing.T) {
884924
assertJSON(t, out, expected, "Count expecting a int number of total item of an array of grouped objects")
885925
}
886926

927+
func TestJSONQ_Count_with_Distinct_expecting_int_from_objects(t *testing.T) {
928+
jq := New().JSONString(jsonStr).
929+
From("vendor.items").Distinct("price")
930+
out := jq.Count()
931+
expected := `5`
932+
assertJSON(t, out, expected, "Count expecting a int number of total item of an array of distinct priced objects")
933+
}
934+
887935
func TestJSONQ_Out_expecting_result(t *testing.T) {
888936
type item struct {
889937
ID int `json:"id"`
@@ -1019,6 +1067,14 @@ func TestJSONQ_Sum_expecting_result_from_nested_object(t *testing.T) {
10191067
assertJSON(t, out, expected, "Sum expecting result from nested object")
10201068
}
10211069

1070+
func TestJSONQ_Sum_of_distinct_array_numeric_values(t *testing.T) {
1071+
jq := New().JSONString(jsonStr).
1072+
From("vendor.items").Distinct("price").Limit(3)
1073+
out := jq.Sum("price")
1074+
expected := `4250`
1075+
assertJSON(t, out, expected, "Sum expecting sum a distinct & limited array")
1076+
}
1077+
10221078
func TestJSONQ_Avg_array(t *testing.T) {
10231079
jq := New().JSONString(jsonStr).
10241080
From("vendor.prices")

0 commit comments

Comments
 (0)