From 50d7f81b63a437e47ac83bbc749dcafbeb5b2710 Mon Sep 17 00:00:00 2001 From: Toshiya Kawasaki Date: Tue, 14 Jun 2022 18:07:27 +0900 Subject: [PATCH 1/4] Add getRecordsWithTotalCount method to App --- app.go | 53 ++++++++++++++++++++++++++++++-------------------- cursor.go | 2 +- record.go | 11 ++++++----- record_test.go | 2 +- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/app.go b/app.go index c84748b..eb5581c 100644 --- a/app.go +++ b/app.go @@ -377,39 +377,50 @@ func (app *App) GetRecord(id uint64) (*Record, error) { return rec, nil } -// GetRecords fetches records matching given conditions. -// -// This method can retrieve up to 100 records at once. -// To retrieve more records, you need to call GetRecords with -// increasing "offset" query parameter until the number of records -// retrieved becomes less than 100. -// -// If fields is nil, all fields are retrieved. -// See API specs how to construct query strings. -func (app *App) GetRecords(fields []string, query string) ([]*Record, error) { +func (app *App) getRecords(fields []string, query string, totalCount bool) ([]*Record, string, error) { type request_body struct { - App uint64 `json:"app,string"` - Fields []string `json:"fields"` - Query string `json:"query"` + App uint64 `json:"app,string"` + Fields []string `json:"fields"` + Query string `json:"query"` + TotalCount bool `json:"totalCount"` } - data, _ := json.Marshal(request_body{app.AppId, fields, query}) + data, _ := json.Marshal(request_body{app.AppId, fields, query, totalCount}) req, err := app.newRequest("GET", "records", bytes.NewReader(data)) if err != nil { - return nil, err + return nil, "", err } resp, err := app.do(req) if err != nil { - return nil, err + return nil, "", err } body, err := parseResponse(resp) if err != nil { - return nil, err + return nil, "", err } - recs, err := DecodeRecords(body) + recs, respTotalCount, err := DecodeRecords(body) if err != nil { - return nil, ErrInvalidResponse + return nil, "", ErrInvalidResponse } - return recs, nil + return recs, respTotalCount, nil +} + +// GetRecords fetches records matching given conditions. +// +// This method can retrieve up to 100 records at once. +// To retrieve more records, you need to call GetRecords with +// increasing "offset" query parameter until the number of records +// retrieved becomes less than 100. +// +// If fields is nil, all fields are retrieved. +// See API specs how to construct query strings. +func (app *App) GetRecords(fields []string, query string) ([]*Record, error) { + records, _, err := app.getRecords(fields, query, false) + return records, err +} + +// GetRecordsWithTotalCount fetches records matching given conditions and returns totalCount of query result. +func (app *App) GetRecordsWithTotalCount(fields []string, query string) ([]*Record, string, error) { + return app.getRecords(fields, query, true) } // GetAllRecords fetches all records. @@ -440,7 +451,7 @@ func (app *App) GetAllRecords(fields []string) ([]*Record, error) { if err != nil { return nil, err } - r, err := DecodeRecords(body) + r, _, err := DecodeRecords(body) if err != nil { return nil, ErrInvalidResponse } diff --git a/cursor.go b/cursor.go index c474796..96b554c 100644 --- a/cursor.go +++ b/cursor.go @@ -32,7 +32,7 @@ func DecodeGetRecordsCursorResponse(b []byte) (rc *GetRecordsCursorResponse, err if err != nil { return nil, err } - listRecord, err := DecodeRecords(b) + listRecord, _, err := DecodeRecords(b) if err != nil { return nil, err } diff --git a/record.go b/record.go index ac4c8dc..de28643 100644 --- a/record.go +++ b/record.go @@ -322,24 +322,25 @@ func decodeRecordData(data recordData) (*Record, error) { } // DecodeRecords decodes JSON response for multi-get API. -func DecodeRecords(b []byte) ([]*Record, error) { +func DecodeRecords(b []byte) ([]*Record, string, error) { var t struct { - Records []recordData `json:"records"` + Records []recordData `json:"records"` + TotalCount string `json:"total_count"` } err := json.Unmarshal(b, &t) if err != nil { - return nil, errors.New("Invalid JSON format") + return nil, "", errors.New("Invalid JSON format") } rec_list := make([]*Record, len(t.Records)) for i, rd := range t.Records { r, err := decodeRecordData(rd) if err != nil { - return nil, err + return nil, "", err } rec_list[i] = r } - return rec_list, nil + return rec_list, t.TotalCount, nil } // DecodeRecord decodes JSON response for single-get API. diff --git a/record_test.go b/record_test.go index 238e149..9736440 100644 --- a/record_test.go +++ b/record_test.go @@ -371,7 +371,7 @@ func TestDecodeRecords(t *testing.T) { } ] }`) - rec, err := DecodeRecords(j) + rec, _, err := DecodeRecords(j) if err != nil { t.Fatal(err) } From 5b8a6c923c7597c5f7ba9c204b6a92fbadb3ca90 Mon Sep 17 00:00:00 2001 From: voduchau Date: Fri, 10 Feb 2023 15:59:50 +0700 Subject: [PATCH 2/4] Adding the totalCount property to get records api function --- app.go | 55 ++++++++++++++++++++++++++++++------------------ app_test.go | 48 ++++++++++++++++++++++++++++++++++++++++-- app_test_json.go | 49 ++++++++++++++++++++++++++++++++++++++++++ record.go | 22 +++++++++++++++++++ 4 files changed, 152 insertions(+), 22 deletions(-) diff --git a/app.go b/app.go index 52d97fe..68ea1f0 100644 --- a/app.go +++ b/app.go @@ -316,6 +316,7 @@ func isJSON(contentType string) bool { func parseResponse(resp *http.Response) ([]byte, error) { body, err := ioutil.ReadAll(resp.Body) resp.Body.Close() + if err != nil { return nil, err } @@ -377,39 +378,53 @@ func (app *App) GetRecord(id uint64) (*Record, error) { return rec, nil } -// GetRecords fetches records matching given conditions. -// -// This method can retrieve up to 100 records at once. -// To retrieve more records, you need to call GetRecords with -// increasing "offset" query parameter until the number of records -// retrieved becomes less than 100. -// -// If fields is nil, all fields are retrieved. -// See API specs how to construct query strings. -func (app *App) GetRecords(fields []string, query string) ([]*Record, error) { +func (app *App) getRecords(fields []string, query string, totalCount bool) ([]*Record, string, error) { type request_body struct { - App uint64 `json:"app,string"` - Fields []string `json:"fields"` - Query string `json:"query"` + App uint64 `json:"app,string"` + Fields []string `json:"fields"` + Query string `json:"query"` + TotalCount bool `json:"totalCount"` } - data, _ := json.Marshal(request_body{app.AppId, fields, query}) + + data, _ := json.Marshal(request_body{app.AppId, fields, query, totalCount}) + req, err := app.newRequest("GET", "records", bytes.NewReader(data)) if err != nil { - return nil, err + return nil, "", err } resp, err := app.do(req) if err != nil { - return nil, err + return nil, "", err } body, err := parseResponse(resp) if err != nil { - return nil, err + return nil, "", err } - recs, err := DecodeRecords(body) + recs, respTotalCount, err := DecodeRecordsWithTotalCount(body) + if err != nil { - return nil, ErrInvalidResponse + return nil, "", ErrInvalidResponse } - return recs, nil + return recs, respTotalCount, nil +} + +// GetRecords fetches records matching given conditions. +// +// This method can retrieve up to 100 records at once. +// To retrieve more records, you need to call GetRecords with +// increasing "offset" query parameter until the number of records +// retrieved becomes less than 100. +// +// If fields is nil, all fields are retrieved. +// See API specs how to construct query strings. +func (app *App) GetRecords(fields []string, query string) ([]*Record, error) { + records, _, err := app.getRecords(fields, query, false) + return records, err +} + +// GetRecordsWithTotalCount fetches records matching given conditions and returns totalCount of query result. +func (app *App) GetRecordsWithTotalCount(fields []string, query string) ([]*Record, string, error) { + return app.getRecords(fields, query, true) } // GetAllRecords fetches all records. diff --git a/app_test.go b/app_test.go index 67574f5..1c2c551 100644 --- a/app_test.go +++ b/app_test.go @@ -7,6 +7,7 @@ package kintone import ( "crypto/tls" "encoding/base64" + "encoding/json" "fmt" "io" "io/ioutil" @@ -168,8 +169,30 @@ func handleResponseGetRecords(response http.ResponseWriter, request *http.Reques checkAuth(response, request) checkContentType(response, request) if request.Method == "GET" { - testData := GetTestDataGetRecords() - fmt.Fprint(response, testData.output) + type RequestBody struct { + App uint64 `json:"app,string"` + Fields []string `json:"fields"` + Query string `json:"query"` + TotalCount bool `json:"totalCount"` + } + + body, err := ioutil.ReadAll(request.Body) + if err != nil { + http.Error(response, "Bad request", http.StatusBadRequest) + return + } + var bodyRequest RequestBody + if err := json.Unmarshal([]byte(body), &bodyRequest); err != nil { + http.Error(response, "Body incorrect", http.StatusBadRequest) + } + + if bodyRequest.TotalCount { + testData := GetTestDataGetRecordsWithTotalCount() + fmt.Fprint(response, testData.output) + } else { + testData := GetTestDataGetRecords() + fmt.Fprint(response, testData.output) + } } else if request.Method == "DELETE" { testData := GetTestDataDeleteRecords() fmt.Fprint(response, testData.output) @@ -179,6 +202,8 @@ func handleResponseGetRecords(response http.ResponseWriter, request *http.Reques } } +//end + func handleResponseGetRecordsComments(response http.ResponseWriter, request *http.Request) { checkAuth(response, request) checkContentType(response, request) @@ -302,6 +327,25 @@ func TestGetRecord(t *testing.T) { } } +// test +func TestGetRecordWithTotalCount(t *testing.T) { + testDataRecords := GetTestDataGetRecordsWithTotalCount() + app := newApp() + + if recs, totalCount, err := app.GetRecordsWithTotalCount(testDataRecords.input[0].([]string), testDataRecords.input[1].(string)); err != nil { + t.Error(err) + } else { + if len(recs) > 3 { + t.Error("Too many records") + } + if totalCount != "999" { + t.Error("TotalCount incorrect", err) + } + } +} + +// end test + func TestUpdateRecord(t *testing.T) { testData := GetTestDataGetRecord() testDataRecords := GetTestDataGetRecords() diff --git a/app_test_json.go b/app_test_json.go index 39b2276..6583e22 100644 --- a/app_test_json.go +++ b/app_test_json.go @@ -161,6 +161,55 @@ func GetTestDataGetRecords() *TestData { } } +func GetTestDataGetRecordsWithTotalCount() *TestData { + return &TestData{ + input: []interface{}{ + []string{}, + "limit 3 offset 3", + }, + output: ` + { + "records":[ + { + "Created_datetime":{ + "type":"CREATED_TIME", + "value":"2019-03-11T04:50:00Z" + }, + "Created_by":{ + "type":"CREATOR", + "value":{ + "code":"Administrator", + "name":"Administrator" + } + }, + "$id":{ + "type":"__ID__", + "value":"1" + } + }, + { + "Created_datetime":{ + "type":"CREATED_TIME", + "value":"2019-03-11T06:42:00Z" + }, + "Created_by":{ + "type":"CREATOR", + "value":{ + "code":"Administrator", + "name":"Administrator" + } + }, + "$id":{ + "type":"__ID__", + "value":"2" + } + } + ], + "totalCount": "999" + }`, + } +} + func GetDataTestUploadFile() *TestData { return &TestData{ output: ` diff --git a/record.go b/record.go index ac4c8dc..cc45832 100644 --- a/record.go +++ b/record.go @@ -342,6 +342,28 @@ func DecodeRecords(b []byte) ([]*Record, error) { return rec_list, nil } +func DecodeRecordsWithTotalCount(b []byte) ([]*Record, string, error) { + var t struct { + Records []recordData `json:"records"` + TotalCount string `json:"totalCount"` + } + err := json.Unmarshal(b, &t) + if err != nil { + return nil, "", errors.New("Invalid JSON format") + } + + rec_list := make([]*Record, len(t.Records)) + for i, rd := range t.Records { + r, err := decodeRecordData(rd) + if err != nil { + return nil, "", err + } + rec_list[i] = r + } + + return rec_list, t.TotalCount, nil +} + // DecodeRecord decodes JSON response for single-get API. func DecodeRecord(b []byte) (*Record, error) { var t struct { From 10f4d372a121aec315fdbaee93113e9a8f24c940 Mon Sep 17 00:00:00 2001 From: voduchau Date: Mon, 13 Feb 2023 08:45:26 +0700 Subject: [PATCH 3/4] add unit test for TestDecodeRecordsWithTotalCount function --- app_test.go | 3 --- record_test.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/app_test.go b/app_test.go index 1c2c551..10b51e2 100644 --- a/app_test.go +++ b/app_test.go @@ -327,7 +327,6 @@ func TestGetRecord(t *testing.T) { } } -// test func TestGetRecordWithTotalCount(t *testing.T) { testDataRecords := GetTestDataGetRecordsWithTotalCount() app := newApp() @@ -344,8 +343,6 @@ func TestGetRecordWithTotalCount(t *testing.T) { } } -// end test - func TestUpdateRecord(t *testing.T) { testData := GetTestDataGetRecord() testDataRecords := GetTestDataGetRecords() diff --git a/record_test.go b/record_test.go index 238e149..dd2d5b9 100644 --- a/record_test.go +++ b/record_test.go @@ -389,3 +389,76 @@ func TestDecodeRecords(t *testing.T) { t.Error("dropdown must be invalid") } } + +func TestDecodeRecordsWithTotalCount(t *testing.T) { + b := []byte(` + { + "records": [ + { + "record_id": { + "type": "RECORD_NUMBER", + "value": "1" + }, + "created_time": { + "type": "CREATED_TIME", + "value": "2012-02-03T08:50:00Z" + }, + "updated_time": { + "type": "UPDATED_TIME", + "value": "2018-10-24T08:50:00Z" + }, + "dropdown": { + "type": "DROP_DOWN", + "value": null + } + }, + { + "record_id": { + "type": "RECORD_NUMBER", + "value": "2" + }, + "created_time": { + "type": "CREATED_TIME", + "value": "2012-02-03T09:22:00Z" + }, + "updated_time": { + "type": "UPDATED_TIME", + "value": "2018-10-24T09:22:00Z" + }, + "dropdown": { + "type": "DROP_DOWN", + "value": null + } + } + ], + "totalCount": "9999" + }`) + + type Record struct { + id uint64 + revision int64 + Fields map[string]interface{} + } + + rec, totalCount, err := DecodeRecordsWithTotalCount(b) + + if err != nil { + t.Fatal(err) + } + if totalCount != "9999" { + t.Error("totalCount is incorrect") + } + if len(rec) != 2 { + t.Error("length mismatch") + } + if _, ok := rec[0].Fields["record_id"]; !ok { + t.Error("record_id must exist") + } + dropdown, ok := rec[0].Fields["dropdown"] + if !ok { + t.Error("null dropdown field must exist") + } + if dropdown.(SingleSelectField).Valid { + t.Error("dropdown must be invalid") + } +} From f14b3bc7814dc9e388ffb7a8e28bc46462c595df Mon Sep 17 00:00:00 2001 From: voduchau Date: Tue, 21 Feb 2023 16:39:30 +0700 Subject: [PATCH 4/4] SSR-2417: resolve conflict --- app.go | 2 +- app_test.go | 2 -- cursor.go | 2 +- record.go | 11 +++++------ record_test.go | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app.go b/app.go index 7bd3fee..68ea1f0 100644 --- a/app.go +++ b/app.go @@ -455,7 +455,7 @@ func (app *App) GetAllRecords(fields []string) ([]*Record, error) { if err != nil { return nil, err } - r, _, err := DecodeRecords(body) + r, err := DecodeRecords(body) if err != nil { return nil, ErrInvalidResponse } diff --git a/app_test.go b/app_test.go index 10b51e2..df82a1b 100644 --- a/app_test.go +++ b/app_test.go @@ -202,8 +202,6 @@ func handleResponseGetRecords(response http.ResponseWriter, request *http.Reques } } -//end - func handleResponseGetRecordsComments(response http.ResponseWriter, request *http.Request) { checkAuth(response, request) checkContentType(response, request) diff --git a/cursor.go b/cursor.go index 96b554c..c474796 100644 --- a/cursor.go +++ b/cursor.go @@ -32,7 +32,7 @@ func DecodeGetRecordsCursorResponse(b []byte) (rc *GetRecordsCursorResponse, err if err != nil { return nil, err } - listRecord, _, err := DecodeRecords(b) + listRecord, err := DecodeRecords(b) if err != nil { return nil, err } diff --git a/record.go b/record.go index b7e990e..cc45832 100644 --- a/record.go +++ b/record.go @@ -322,25 +322,24 @@ func decodeRecordData(data recordData) (*Record, error) { } // DecodeRecords decodes JSON response for multi-get API. -func DecodeRecords(b []byte) ([]*Record, string, error) { +func DecodeRecords(b []byte) ([]*Record, error) { var t struct { - Records []recordData `json:"records"` - TotalCount string `json:"total_count"` + Records []recordData `json:"records"` } err := json.Unmarshal(b, &t) if err != nil { - return nil, "", errors.New("Invalid JSON format") + return nil, errors.New("Invalid JSON format") } rec_list := make([]*Record, len(t.Records)) for i, rd := range t.Records { r, err := decodeRecordData(rd) if err != nil { - return nil, "", err + return nil, err } rec_list[i] = r } - return rec_list, t.TotalCount, nil + return rec_list, nil } func DecodeRecordsWithTotalCount(b []byte) ([]*Record, string, error) { diff --git a/record_test.go b/record_test.go index b0c9e1d..dd2d5b9 100644 --- a/record_test.go +++ b/record_test.go @@ -371,7 +371,7 @@ func TestDecodeRecords(t *testing.T) { } ] }`) - rec, _, err := DecodeRecords(j) + rec, err := DecodeRecords(j) if err != nil { t.Fatal(err) }