From 7adb5858b0fdf5063fac44c87890394401e2a12b Mon Sep 17 00:00:00 2001 From: alallema Date: Mon, 27 Mar 2023 16:52:28 +0200 Subject: [PATCH] Configure Csv delimiter --- index.go | 8 +- index_documents.go | 104 +++++++---- index_documents_test.go | 390 +++++++++++++++++++++++++++++++++++++++- types.go | 5 + types_easyjson.go | 115 ++++++++++-- 5 files changed, 557 insertions(+), 65 deletions(-) diff --git a/index.go b/index.go index d5924e62..b10d8894 100644 --- a/index.go +++ b/index.go @@ -28,14 +28,14 @@ type IndexInterface interface { AddDocuments(documentsPtr interface{}, primaryKey ...string) (resp *TaskInfo, err error) AddDocumentsInBatches(documentsPtr interface{}, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) - AddDocumentsCsv(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) - AddDocumentsCsvInBatches(documents []byte, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) + AddDocumentsCsv(documents []byte, options *CsvDocumentsQuery) (resp *TaskInfo, err error) + AddDocumentsCsvInBatches(documents []byte, batchSize int, options *CsvDocumentsQuery) (resp []TaskInfo, err error) AddDocumentsNdjson(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) AddDocumentsNdjsonInBatches(documents []byte, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) UpdateDocuments(documentsPtr interface{}, primaryKey ...string) (resp *TaskInfo, err error) UpdateDocumentsInBatches(documentsPtr interface{}, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) - UpdateDocumentsCsv(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) - UpdateDocumentsCsvInBatches(documents []byte, batchsize int, primaryKey ...string) (resp []TaskInfo, err error) + UpdateDocumentsCsv(documents []byte, options *CsvDocumentsQuery) (resp *TaskInfo, err error) + UpdateDocumentsCsvInBatches(documents []byte, batchsize int, options *CsvDocumentsQuery) (resp []TaskInfo, err error) UpdateDocumentsNdjson(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) UpdateDocumentsNdjsonInBatches(documents []byte, batchsize int, primaryKey ...string) (resp []TaskInfo, err error) GetDocument(uid string, request *DocumentQuery, documentPtr interface{}) error diff --git a/index_documents.go b/index_documents.go index d16bb48e..6ad8d6f9 100644 --- a/index_documents.go +++ b/index_documents.go @@ -4,16 +4,42 @@ import ( "bufio" "bytes" "encoding/csv" + "encoding/json" "fmt" "io" "math" "net/http" + "net/url" "reflect" "strconv" "strings" ) -func sendCsvRecords(documentsCsvFunc func(recs []byte, pk ...string) (resp *TaskInfo, err error), records [][]string, primaryKey ...string) (*TaskInfo, error) { +func transformStringVariadicToMap(primaryKey ...string) (options map[string]string) { + if primaryKey != nil { + return map[string]string{ + "primaryKey": primaryKey[0], + } + } + return nil +} + +func transformCsvDocumentsQueryToMap(options *CsvDocumentsQuery) map[string]string { + var optionsMap map[string]string + data, _ := json.Marshal(options) + _ = json.Unmarshal(data, &optionsMap) + return optionsMap +} + +func generateQueryForOptions(options map[string]string) (urlQuery string) { + q := url.Values{} + for key, val := range options { + q.Add(key, val) + } + return q.Encode() +} + +func sendCsvRecords(documentsCsvFunc func(recs []byte, op *CsvDocumentsQuery) (resp *TaskInfo, err error), records [][]string, options *CsvDocumentsQuery) (*TaskInfo, error) { b := new(bytes.Buffer) w := csv.NewWriter(b) w.UseCRLF = true @@ -23,14 +49,14 @@ func sendCsvRecords(documentsCsvFunc func(recs []byte, pk ...string) (resp *Task return nil, fmt.Errorf("could not write CSV records: %w", err) } - resp, err := documentsCsvFunc(b.Bytes(), primaryKey...) + resp, err := documentsCsvFunc(b.Bytes(), options) if err != nil { return nil, err } return resp, nil } -func (i Index) saveDocumentsFromReaderInBatches(documents io.Reader, batchSize int, documentsCsvFunc func(recs []byte, pk ...string) (resp *TaskInfo, err error), primaryKey ...string) (resp []TaskInfo, err error) { +func (i Index) saveDocumentsFromReaderInBatches(documents io.Reader, batchSize int, documentsCsvFunc func(recs []byte, op *CsvDocumentsQuery) (resp *TaskInfo, err error), options *CsvDocumentsQuery) (resp []TaskInfo, err error) { // Because of the possibility of multiline fields it's not safe to split // into batches by lines, we'll have to parse the file and reassemble it // into smaller parts. RFC 4180 compliant input with a header row is @@ -71,7 +97,7 @@ func (i Index) saveDocumentsFromReaderInBatches(documents io.Reader, batchSize i // After reaching batchSize (not counting the header record) assemble a CSV file and send records if len(records) == batchSize+1 { - resp, err := sendCsvRecords(documentsCsvFunc, records, primaryKey...) + resp, err := sendCsvRecords(documentsCsvFunc, records, options) if err != nil { return nil, err } @@ -82,7 +108,7 @@ func (i Index) saveDocumentsFromReaderInBatches(documents io.Reader, batchSize i // Send remaining records as the last batch if there is any if len(records) > 0 { - resp, err := sendCsvRecords(documentsCsvFunc, records, primaryKey...) + resp, err := sendCsvRecords(documentsCsvFunc, records, options) if err != nil { return nil, err } @@ -174,14 +200,18 @@ func (i Index) GetDocuments(request *DocumentsQuery, resp *DocumentsResult) erro return nil } -func (i Index) addDocuments(documentsPtr interface{}, contentType string, primaryKey ...string) (resp *TaskInfo, err error) { +func (i *Index) addDocuments(documentsPtr interface{}, contentType string, options map[string]string) (resp *TaskInfo, err error) { resp = &TaskInfo{} endpoint := "" - if primaryKey == nil { + if options == nil { endpoint = "/indexes/" + i.UID + "/documents" } else { - i.PrimaryKey = primaryKey[0] //nolint:golint,staticcheck - endpoint = "/indexes/" + i.UID + "/documents?primaryKey=" + primaryKey[0] + for key, val := range options { + if key == "primaryKey" { + i.PrimaryKey = val + } + } + endpoint = "/indexes/" + i.UID + "/documents?" + generateQueryForOptions(options) } req := internalRequest{ endpoint: endpoint, @@ -199,40 +229,40 @@ func (i Index) addDocuments(documentsPtr interface{}, contentType string, primar } func (i Index) AddDocuments(documentsPtr interface{}, primaryKey ...string) (resp *TaskInfo, err error) { - return i.addDocuments(documentsPtr, contentTypeJSON, primaryKey...) + return i.addDocuments(documentsPtr, contentTypeJSON, transformStringVariadicToMap(primaryKey...)) } func (i Index) AddDocumentsInBatches(documentsPtr interface{}, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { return i.saveDocumentsInBatches(documentsPtr, batchSize, i.AddDocuments, primaryKey...) } -func (i Index) AddDocumentsCsv(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) { +func (i Index) AddDocumentsCsv(documents []byte, options *CsvDocumentsQuery) (resp *TaskInfo, err error) { // []byte avoids JSON conversion in Client.sendRequest() - return i.addDocuments(documents, contentTypeCSV, primaryKey...) + return i.addDocuments(documents, contentTypeCSV, transformCsvDocumentsQueryToMap(options)) } -func (i Index) AddDocumentsCsvFromReader(documents io.Reader, primaryKey ...string) (resp *TaskInfo, err error) { +func (i Index) AddDocumentsCsvFromReader(documents io.Reader, options *CsvDocumentsQuery) (resp *TaskInfo, err error) { // Using io.Reader would avoid JSON conversion in Client.sendRequest(), but // read content to memory anyway because of problems with streamed bodies data, err := io.ReadAll(documents) if err != nil { return nil, fmt.Errorf("could not read documents: %w", err) } - return i.addDocuments(data, contentTypeCSV, primaryKey...) + return i.addDocuments(data, contentTypeCSV, transformCsvDocumentsQueryToMap(options)) } -func (i Index) AddDocumentsCsvInBatches(documents []byte, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { +func (i Index) AddDocumentsCsvInBatches(documents []byte, batchSize int, options *CsvDocumentsQuery) (resp []TaskInfo, err error) { // Reuse io.Reader implementation - return i.AddDocumentsCsvFromReaderInBatches(bytes.NewReader(documents), batchSize, primaryKey...) + return i.AddDocumentsCsvFromReaderInBatches(bytes.NewReader(documents), batchSize, options) } -func (i Index) AddDocumentsCsvFromReaderInBatches(documents io.Reader, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { - return i.saveDocumentsFromReaderInBatches(documents, batchSize, i.AddDocumentsCsv, primaryKey...) +func (i Index) AddDocumentsCsvFromReaderInBatches(documents io.Reader, batchSize int, options *CsvDocumentsQuery) (resp []TaskInfo, err error) { + return i.saveDocumentsFromReaderInBatches(documents, batchSize, i.AddDocumentsCsv, options) } func (i Index) AddDocumentsNdjson(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) { // []byte avoids JSON conversion in Client.sendRequest() - return i.addDocuments([]byte(documents), contentTypeNDJSON, primaryKey...) + return i.addDocuments([]byte(documents), contentTypeNDJSON, transformStringVariadicToMap(primaryKey...)) } func (i Index) AddDocumentsNdjsonFromReader(documents io.Reader, primaryKey ...string) (resp *TaskInfo, err error) { @@ -242,7 +272,7 @@ func (i Index) AddDocumentsNdjsonFromReader(documents io.Reader, primaryKey ...s if err != nil { return nil, fmt.Errorf("could not read documents: %w", err) } - return i.addDocuments(data, contentTypeNDJSON, primaryKey...) + return i.addDocuments(data, contentTypeNDJSON, transformStringVariadicToMap(primaryKey...)) } func (i Index) AddDocumentsNdjsonInBatches(documents []byte, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { @@ -318,14 +348,18 @@ func (i Index) AddDocumentsNdjsonFromReaderInBatches(documents io.Reader, batchS return responses, nil } -func (i Index) updateDocuments(documentsPtr interface{}, contentType string, primaryKey ...string) (resp *TaskInfo, err error) { +func (i *Index) updateDocuments(documentsPtr interface{}, contentType string, options map[string]string) (resp *TaskInfo, err error) { resp = &TaskInfo{} endpoint := "" - if primaryKey == nil { + if options == nil { endpoint = "/indexes/" + i.UID + "/documents" } else { - i.PrimaryKey = primaryKey[0] //nolint:golint,staticcheck - endpoint = "/indexes/" + i.UID + "/documents?primaryKey=" + primaryKey[0] + for key, val := range options { + if key == "primaryKey" { + i.PrimaryKey = val + } + } + endpoint = "/indexes/" + i.UID + "/documents?" + generateQueryForOptions(options) } req := internalRequest{ endpoint: endpoint, @@ -343,38 +377,38 @@ func (i Index) updateDocuments(documentsPtr interface{}, contentType string, pri } func (i Index) UpdateDocuments(documentsPtr interface{}, primaryKey ...string) (resp *TaskInfo, err error) { - return i.updateDocuments(documentsPtr, contentTypeJSON, primaryKey...) + return i.updateDocuments(documentsPtr, contentTypeJSON, transformStringVariadicToMap(primaryKey...)) } func (i Index) UpdateDocumentsInBatches(documentsPtr interface{}, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { return i.saveDocumentsInBatches(documentsPtr, batchSize, i.UpdateDocuments, primaryKey...) } -func (i Index) UpdateDocumentsCsv(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) { - return i.updateDocuments(documents, contentTypeCSV, primaryKey...) +func (i Index) UpdateDocumentsCsv(documents []byte, options *CsvDocumentsQuery) (resp *TaskInfo, err error) { + return i.updateDocuments(documents, contentTypeCSV, transformCsvDocumentsQueryToMap(options)) } -func (i Index) UpdateDocumentsCsvFromReader(documents io.Reader, primaryKey ...string) (resp *TaskInfo, err error) { +func (i Index) UpdateDocumentsCsvFromReader(documents io.Reader, options *CsvDocumentsQuery) (resp *TaskInfo, err error) { // Using io.Reader would avoid JSON conversion in Client.sendRequest(), but // read content to memory anyway because of problems with streamed bodies data, err := io.ReadAll(documents) if err != nil { return nil, fmt.Errorf("could not read documents: %w", err) } - return i.updateDocuments(data, contentTypeCSV, primaryKey...) + return i.updateDocuments(data, contentTypeCSV, transformCsvDocumentsQueryToMap(options)) } -func (i Index) UpdateDocumentsCsvInBatches(documents []byte, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { +func (i Index) UpdateDocumentsCsvInBatches(documents []byte, batchSize int, options *CsvDocumentsQuery) (resp []TaskInfo, err error) { // Reuse io.Reader implementation - return i.UpdateDocumentsCsvFromReaderInBatches(bytes.NewReader(documents), batchSize, primaryKey...) + return i.UpdateDocumentsCsvFromReaderInBatches(bytes.NewReader(documents), batchSize, options) } -func (i Index) UpdateDocumentsCsvFromReaderInBatches(documents io.Reader, batchSize int, primaryKey ...string) (resp []TaskInfo, err error) { - return i.saveDocumentsFromReaderInBatches(documents, batchSize, i.UpdateDocumentsCsv, primaryKey...) +func (i Index) UpdateDocumentsCsvFromReaderInBatches(documents io.Reader, batchSize int, options *CsvDocumentsQuery) (resp []TaskInfo, err error) { + return i.saveDocumentsFromReaderInBatches(documents, batchSize, i.UpdateDocumentsCsv, options) } func (i Index) UpdateDocumentsNdjson(documents []byte, primaryKey ...string) (resp *TaskInfo, err error) { - return i.updateDocuments(documents, contentTypeNDJSON, primaryKey...) + return i.updateDocuments(documents, contentTypeNDJSON, transformStringVariadicToMap(primaryKey...)) } func (i Index) UpdateDocumentsNdjsonFromReader(documents io.Reader, primaryKey ...string) (resp *TaskInfo, err error) { @@ -384,7 +418,7 @@ func (i Index) UpdateDocumentsNdjsonFromReader(documents io.Reader, primaryKey . if err != nil { return nil, fmt.Errorf("could not read documents: %w", err) } - return i.updateDocuments(data, contentTypeNDJSON, primaryKey...) + return i.updateDocuments(data, contentTypeNDJSON, transformStringVariadicToMap(primaryKey...)) } func (i Index) UpdateDocumentsNdjsonInBatches(documents []byte, batchsize int, primaryKey ...string) (resp []TaskInfo, err error) { diff --git a/index_documents_test.go b/index_documents_test.go index 4f448a63..a9116dbf 100644 --- a/index_documents_test.go +++ b/index_documents_test.go @@ -624,9 +624,127 @@ func TestIndex_AddDocumentsCsv(t *testing.T) { ) if testReader { - gotResp, err = i.AddDocumentsCsvFromReader(bytes.NewReader(tt.args.documents)) + gotResp, err = i.AddDocumentsCsvFromReader(bytes.NewReader(tt.args.documents), nil) } else { - gotResp, err = i.AddDocumentsCsv(tt.args.documents) + gotResp, err = i.AddDocumentsCsv(tt.args.documents, nil) + } + + require.NoError(t, err) + require.GreaterOrEqual(t, gotResp.TaskUID, tt.wantResp.TaskUID) + require.Equal(t, tt.wantResp.Status, gotResp.Status) + require.Equal(t, tt.wantResp.Type, gotResp.Type) + require.NotZero(t, gotResp.EnqueuedAt) + + testWaitForTask(t, i, gotResp) + + var documents DocumentsResult + err = i.GetDocuments(&DocumentsQuery{}, &documents) + require.NoError(t, err) + require.Equal(t, wantDocs, documents.Results) + }) + } + + for _, tt := range tests { + // Test both the string and io.Reader receiving versions + testAddDocumentsCsv(t, tt, false) + testAddDocumentsCsv(t, tt, true) + } +} + +func TestIndex_AddDocumentsCsvWithOptions(t *testing.T) { + type args struct { + UID string + client *Client + documents []byte + options *CsvDocumentsQuery + } + type testData struct { + name string + args args + wantResp *TaskInfo + } + + tests := []testData{ + { + name: "TestIndexBasicAddDocumentsCsvWithOptions", + args: args{ + UID: "csv", + client: defaultClient, + documents: testCsvDocuments, + options: &CsvDocumentsQuery{ + PrimaryKey: "id", + CsvDelimiter: ",", + }, + }, + wantResp: &TaskInfo{ + TaskUID: 0, + Status: "enqueued", + Type: "documentAdditionOrUpdate", + }, + }, + { + name: "TestIndexBasicAddDocumentsCsvWithPrimaryKey", + args: args{ + UID: "csv", + client: defaultClient, + documents: testCsvDocuments, + options: &CsvDocumentsQuery{ + PrimaryKey: "id", + }, + }, + wantResp: &TaskInfo{ + TaskUID: 0, + Status: "enqueued", + Type: "documentAdditionOrUpdate", + }, + }, + { + name: "TestIndexBasicAddDocumentsCsvWithCsvDelimiter", + args: args{ + UID: "csv", + client: defaultClient, + documents: testCsvDocuments, + options: &CsvDocumentsQuery{ + CsvDelimiter: ",", + }, + }, + wantResp: &TaskInfo{ + TaskUID: 0, + Status: "enqueued", + Type: "documentAdditionOrUpdate", + }, + }, + } + + testAddDocumentsCsv := func(t *testing.T, tt testData, testReader bool) { + name := tt.name + "AddDocumentsCsv" + if testReader { + name += "FromReader" + } + + uid := tt.args.UID + if testReader { + uid += "-reader" + } else { + uid += "-string" + } + + t.Run(name, func(t *testing.T) { + c := tt.args.client + i := c.Index(uid) + t.Cleanup(cleanup(c)) + + wantDocs := testParseCsvDocuments(t, bytes.NewReader(tt.args.documents)) + + var ( + gotResp *TaskInfo + err error + ) + + if testReader { + gotResp, err = i.AddDocumentsCsvFromReader(bytes.NewReader(tt.args.documents), tt.args.options) + } else { + gotResp, err = i.AddDocumentsCsv(tt.args.documents, tt.args.options) } require.NoError(t, err) @@ -720,9 +838,9 @@ func TestIndex_AddDocumentsCsvInBatches(t *testing.T) { ) if testReader { - gotResp, err = i.AddDocumentsCsvFromReaderInBatches(bytes.NewReader(tt.args.documents), tt.args.batchSize) + gotResp, err = i.AddDocumentsCsvFromReaderInBatches(bytes.NewReader(tt.args.documents), tt.args.batchSize, nil) } else { - gotResp, err = i.AddDocumentsCsvInBatches(tt.args.documents, tt.args.batchSize) + gotResp, err = i.AddDocumentsCsvInBatches(tt.args.documents, tt.args.batchSize, nil) } require.NoError(t, err) @@ -1872,9 +1990,127 @@ func TestIndex_UpdateDocumentsCsv(t *testing.T) { ) if testReader { - gotResp, err = i.UpdateDocumentsCsvFromReader(bytes.NewReader(tt.args.documents)) + gotResp, err = i.UpdateDocumentsCsvFromReader(bytes.NewReader(tt.args.documents), nil) + } else { + gotResp, err = i.UpdateDocumentsCsv(tt.args.documents, nil) + } + + require.NoError(t, err) + require.GreaterOrEqual(t, gotResp.TaskUID, tt.wantResp.TaskUID) + require.Equal(t, tt.wantResp.Status, gotResp.Status) + require.Equal(t, tt.wantResp.Type, gotResp.Type) + require.NotZero(t, gotResp.EnqueuedAt) + + testWaitForTask(t, i, gotResp) + + var documents DocumentsResult + err = i.GetDocuments(&DocumentsQuery{}, &documents) + require.NoError(t, err) + require.Equal(t, wantDocs, documents.Results) + }) + } + + for _, tt := range tests { + // Test both the string and io.Reader receiving versions + testUpdateDocumentsCsv(t, tt, false) + testUpdateDocumentsCsv(t, tt, true) + } +} + +func TestIndex_UpdateDocumentsCsvWithOptions(t *testing.T) { + type args struct { + UID string + client *Client + documents []byte + options *CsvDocumentsQuery + } + type testData struct { + name string + args args + wantResp *TaskInfo + } + + tests := []testData{ + { + name: "TestIndexBasicUpdateDocumentsCsvWithOptions", + args: args{ + UID: "csv", + client: defaultClient, + documents: testCsvDocuments, + options: &CsvDocumentsQuery{ + PrimaryKey: "id", + CsvDelimiter: ",", + }, + }, + wantResp: &TaskInfo{ + TaskUID: 0, + Status: "enqueued", + Type: "documentAdditionOrUpdate", + }, + }, + { + name: "TestIndexBasicUpdateDocumentsCsvWithPrimaryKey", + args: args{ + UID: "csv", + client: defaultClient, + documents: testCsvDocuments, + options: &CsvDocumentsQuery{ + PrimaryKey: "id", + }, + }, + wantResp: &TaskInfo{ + TaskUID: 0, + Status: "enqueued", + Type: "documentAdditionOrUpdate", + }, + }, + { + name: "TestIndexBasicUpdateDocumentsCsvWithCsvDelimiter", + args: args{ + UID: "csv", + client: defaultClient, + documents: testCsvDocuments, + options: &CsvDocumentsQuery{ + CsvDelimiter: ",", + }, + }, + wantResp: &TaskInfo{ + TaskUID: 0, + Status: "enqueued", + Type: "documentAdditionOrUpdate", + }, + }, + } + + testUpdateDocumentsCsv := func(t *testing.T, tt testData, testReader bool) { + name := tt.name + "UpdateDocumentsCsv" + if testReader { + name += "FromReader" + } + + uid := tt.args.UID + if testReader { + uid += "-reader" + } else { + uid += "-string" + } + + t.Run(name, func(t *testing.T) { + c := tt.args.client + i := c.Index(uid) + t.Cleanup(cleanup(c)) + + wantDocs := testParseCsvDocuments(t, bytes.NewReader(tt.args.documents)) + + var ( + gotResp *TaskInfo + err error + ) + + if testReader { + gotResp, err = i.UpdateDocumentsCsvFromReader(bytes.NewReader(tt.args.documents), tt.args.options) } else { - gotResp, err = i.UpdateDocumentsCsv(tt.args.documents) + gotResp, err = i.UpdateDocumentsCsv(tt.args.documents, tt.args.options) } require.NoError(t, err) @@ -1968,9 +2204,9 @@ func TestIndex_UpdateDocumentsCsvInBatches(t *testing.T) { ) if testReader { - gotResp, err = i.UpdateDocumentsCsvFromReaderInBatches(bytes.NewReader(tt.args.documents), tt.args.batchSize) + gotResp, err = i.UpdateDocumentsCsvFromReaderInBatches(bytes.NewReader(tt.args.documents), tt.args.batchSize, nil) } else { - gotResp, err = i.UpdateDocumentsCsvInBatches(tt.args.documents, tt.args.batchSize) + gotResp, err = i.UpdateDocumentsCsvInBatches(tt.args.documents, tt.args.batchSize, nil) } require.NoError(t, err) @@ -2175,3 +2411,141 @@ func TestIndex_UpdateDocumentsNdjsonInBatches(t *testing.T) { testUpdateDocumentsNdjsonInBatches(t, tt, true) } } + +func Test_transformStringVariadicToMap(t *testing.T) { + type args struct { + primaryKey []string + } + tests := []struct { + name string + args args + wantOptions map[string]string + }{ + { + name: "TestCreateOptionsInterface", + args: args{ + []string{ + "id", + }, + }, + wantOptions: map[string]string{ + "primaryKey": "id", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotOptions := transformStringVariadicToMap(tt.args.primaryKey...) + require.Equal(t, tt.wantOptions, gotOptions) + }) + } +} + +func Test_generateQueryForOptions(t *testing.T) { + type args struct { + options map[string]string + } + tests := []struct { + name string + args args + wantUrlQuery string + }{ + { + name: "TestGenerateQueryForOptions", + args: args{ + options: map[string]string{ + "primaryKey": "id", + "csvDelimiter": ",", + }, + }, + wantUrlQuery: "csvDelimiter=%2C&primaryKey=id", + }, + { + name: "TestGenerateQueryForPrimaryKey", + args: args{ + options: map[string]string{ + "primaryKey": "id", + }, + }, + wantUrlQuery: "primaryKey=id", + }, + { + name: "TestGenerateQueryForCsvDelimiter", + args: args{ + options: map[string]string{ + "csvDelimiter": ",", + }, + }, + wantUrlQuery: "csvDelimiter=%2C", + }, + { + name: "TestGenerateQueryWithNull", + args: args{ + options: nil, + }, + wantUrlQuery: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotUrlQuery := generateQueryForOptions(tt.args.options) + require.Equal(t, tt.wantUrlQuery, gotUrlQuery) + }) + } +} + +func Test_transformCsvDocumentsQueryToMap(t *testing.T) { + type args struct { + options *CsvDocumentsQuery + } + tests := []struct { + name string + args args + want map[string]string + }{ + { + name: "TestTransformCsvDocumentsQueryToMap", + args: args{ + options: &CsvDocumentsQuery{ + PrimaryKey: "id", + CsvDelimiter: ",", + }, + }, + want: map[string]string{ + "primaryKey": "id", + "csvDelimiter": ",", + }, + }, + { + name: "TestTransformCsvDocumentsQueryToMapWithPrimaryKey", + args: args{ + options: &CsvDocumentsQuery{ + PrimaryKey: "id", + }, + }, + want: map[string]string{ + "primaryKey": "id", + }, + }, + { + name: "TestTransformCsvDocumentsQueryToMapEmpty", + args: args{ + options: &CsvDocumentsQuery{}, + }, + want: map[string]string{}, + }, + { + name: "TestTransformCsvDocumentsQueryToMapNull", + args: args{ + options: nil, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := transformCsvDocumentsQueryToMap(tt.args.options) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/types.go b/types.go index 324df33b..bf6a8a1e 100644 --- a/types.go +++ b/types.go @@ -354,6 +354,11 @@ type DocumentsQuery struct { Fields []string `json:"fields,omitempty"` } +type CsvDocumentsQuery struct { + PrimaryKey string `json:"primaryKey,omitempty"` + CsvDelimiter string `json:"csvDelimiter,omitempty"` +} + type DocumentsResult struct { Results []map[string]interface{} `json:"results"` Limit int64 `json:"limit"` diff --git a/types_easyjson.go b/types_easyjson.go index 00b6aa92..f0484ce3 100644 --- a/types_easyjson.go +++ b/types_easyjson.go @@ -5370,7 +5370,86 @@ func (v *DeleteTasksQuery) UnmarshalJSON(data []byte) error { func (v *DeleteTasksQuery) UnmarshalEasyJSON(l *jlexer.Lexer) { easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo34(l, v) } -func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(in *jlexer.Lexer, out *CreateIndexRequest) { +func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(in *jlexer.Lexer, out *CsvDocumentsQuery) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "primaryKey": + out.PrimaryKey = string(in.String()) + case "csvDelimiter": + out.CsvDelimiter = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(out *jwriter.Writer, in CsvDocumentsQuery) { + out.RawByte('{') + first := true + _ = first + if in.PrimaryKey != "" { + const prefix string = ",\"primaryKey\":" + first = false + out.RawString(prefix[1:]) + out.String(string(in.PrimaryKey)) + } + if in.CsvDelimiter != "" { + const prefix string = ",\"csvDelimiter\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.CsvDelimiter)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v CsvDocumentsQuery) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v CsvDocumentsQuery) MarshalEasyJSON(w *jwriter.Writer) { + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *CsvDocumentsQuery) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *CsvDocumentsQuery) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(l, v) +} +func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(in *jlexer.Lexer, out *CreateIndexRequest) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5403,7 +5482,7 @@ func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(in *jlexer.Lexer, in.Consumed() } } -func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(out *jwriter.Writer, in CreateIndexRequest) { +func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(out *jwriter.Writer, in CreateIndexRequest) { out.RawByte('{') first := true _ = first @@ -5429,27 +5508,27 @@ func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(out *jwriter.Writ // MarshalJSON supports json.Marshaler interface func (v CreateIndexRequest) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(&w, v) + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface func (v CreateIndexRequest) MarshalEasyJSON(w *jwriter.Writer) { - easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo35(w, v) + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(w, v) } // UnmarshalJSON supports json.Unmarshaler interface func (v *CreateIndexRequest) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(&r, v) + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *CreateIndexRequest) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo35(l, v) + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(l, v) } -func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(in *jlexer.Lexer, out *Client) { +func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(in *jlexer.Lexer, out *Client) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5478,7 +5557,7 @@ func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(in *jlexer.Lexer, in.Consumed() } } -func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(out *jwriter.Writer, in Client) { +func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(out *jwriter.Writer, in Client) { out.RawByte('{') first := true _ = first @@ -5488,27 +5567,27 @@ func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(out *jwriter.Writ // MarshalJSON supports json.Marshaler interface func (v Client) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(&w, v) + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface func (v Client) MarshalEasyJSON(w *jwriter.Writer) { - easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo36(w, v) + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(w, v) } // UnmarshalJSON supports json.Unmarshaler interface func (v *Client) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(&r, v) + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Client) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo36(l, v) + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(l, v) } -func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(in *jlexer.Lexer, out *CancelTasksQuery) { +func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo38(in *jlexer.Lexer, out *CancelTasksQuery) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -5645,7 +5724,7 @@ func easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(in *jlexer.Lexer, in.Consumed() } } -func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(out *jwriter.Writer, in CancelTasksQuery) { +func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo38(out *jwriter.Writer, in CancelTasksQuery) { out.RawByte('{') first := true _ = first @@ -5739,23 +5818,23 @@ func easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(out *jwriter.Writ // MarshalJSON supports json.Marshaler interface func (v CancelTasksQuery) MarshalJSON() ([]byte, error) { w := jwriter.Writer{} - easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(&w, v) + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo38(&w, v) return w.Buffer.BuildBytes(), w.Error } // MarshalEasyJSON supports easyjson.Marshaler interface func (v CancelTasksQuery) MarshalEasyJSON(w *jwriter.Writer) { - easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo37(w, v) + easyjson6601e8cdEncodeGithubComMeilisearchMeilisearchGo38(w, v) } // UnmarshalJSON supports json.Unmarshaler interface func (v *CancelTasksQuery) UnmarshalJSON(data []byte) error { r := jlexer.Lexer{Data: data} - easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(&r, v) + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo38(&r, v) return r.Error() } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *CancelTasksQuery) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo37(l, v) + easyjson6601e8cdDecodeGithubComMeilisearchMeilisearchGo38(l, v) }