Skip to content

Commit

Permalink
Merge #247
Browse files Browse the repository at this point in the history
247: Changes related to the next MeiliSearch release (v0.25.0) r=alallema a=meili-bot

Related to this issue: meilisearch/integration-guides#157

This PR:
- gathers the changes related to the next MeiliSearch release (v0.25.0) so that this package is ready when the official release is out.
- should pass the tests against the [latest pre-release of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases).
- might eventually contain test failures until the MeiliSearch v0.25.0 is out.

⚠️ This PR should NOT be merged until the next release of MeiliSearch (v0.25.0) is out.

_This PR is auto-generated for the [pre-release week](https://github.com/meilisearch/integration-guides/blob/master/guides/pre-release-week.md) purpose._

Done:
- #254 
- #255 
- #256 
- #257
- #262 
- #264
- #265 
- #266 

Co-authored-by: meili-bot <74670311+meili-bot@users.noreply.github.com>
Co-authored-by: Amélie <alallema@users.noreply.github.com>
Co-authored-by: alallema <amelie@meilisearch.com>
Co-authored-by: bors[bot] <26634292+bors[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Feb 8, 2022
2 parents 6db58ec + 28393a1 commit b9b10bf
Show file tree
Hide file tree
Showing 17 changed files with 3,251 additions and 1,639 deletions.
75 changes: 71 additions & 4 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,34 @@ delete_documents_1: |-
})
search_post_1: |-
client.Index("movies").Search("american ninja", &meilisearch.SearchRequest{})
get_update_1: |-
client.Index("movies").GetUpdateStatus(1)
get_all_updates_1: |-
client.Index("movies").GetAllUpdateStatus()
get_task_1: |-
client.GetTask(1);
get_all_tasks_1: |-
client.GetTasks();
get_task_by_index_1: |-
client.Index("movies").GetTask(1)
get_all_tasks_by_index_1: |-
client.Index("movies").GetTasks()
get_one_key_1: |-
client.GetKey("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4")
get_keys_1: |-
client.GetKeys()
create_a_key_1: |-
client.CreateKey(&meilisearch.Key{
Description: "Add documents: Products API key",
Actions: []string{"documents.add"},
Indexes: []string{"products"},
ExpiresAt: time.Date(2042, time.April, 02, 0, 42, 42, 0, time.UTC),
})
update_a_key_1: |-
client.UpdateKey("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", &meilisearch.Key{
Description: "Manage documents: Products/Reviews API key",
Actions: []string{"documents.add", "document.delete"},
Indexes: []string{"products", "reviews"},
ExpiresAt: time.Date(2042, time.April, 02, 0, 42, 42, 0, time.UTC),
})
delete_a_key_1: |-
client.DeleteKey("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4")
get_settings_1: |-
client.Index("movies").GetSettings()
update_settings_1: |-
Expand Down Expand Up @@ -516,3 +538,48 @@ geosearch_guide_sort_usage_2: |-
"rating:desc",
},
})
security_guide_search_key_1: |-
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
ApiKey: "apiKey",
})
client.Index("patient_medical_records").Search();
security_guide_update_key_1: |-
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
ApiKey: "masterKey",
})
client.UpdateKey("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", &meilisearch.Key{
Indexes: []string{"doctors"},
})
security_guide_create_key_1: |-
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
ApiKey: "masterKey",
})
client.CreateKey(&meilisearch.Key{
Description: "Search patient records key",
Actions: []string{"search"},
Indexes: []string{"patient_medical_records"},
ExpiresAt: time.Date(2042, time.April, 02, 0, 42, 42, 0, time.UTC),
})
security_guide_list_keys_1: |-
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
ApiKey: "masterKey",
})
client.GetKeys();
security_guide_delete_key_1: |-
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
ApiKey: "masterKey",
})
client.DeleteKey("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4");
authorization_header_1: |-
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
ApiKey: "masterKey",
})
client.GetKeys();
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,17 @@ func main() {
{ "id": 5, "title": "Moana", "genres": []string{"Fantasy", "Action"} },
{ "id": 6, "title": "Philadelphia", "genres": []string{"Drama"} },
}
update, err := index.AddDocuments(documents)
task, err := index.AddDocuments(documents)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

fmt.Println(update.UpdateID)
fmt.Println(task.taskID)
}
```

With the `updateId`, you can check the status (`enqueued`, `processing`, `processed` or `failed`) of your documents addition using the [update endpoint](https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status).
With the `taskID`, you can check the status (`enqueued`, `processing`, `succeeded` or `failed`) of your documents addition using the [task endpoint](https://docs.meilisearch.com/learn/advanced/asynchronous_operations.html#task-status).

#### Basic Search <!-- omit in toc -->

Expand Down Expand Up @@ -192,12 +192,12 @@ JSON output:
If you want to enable filtering, you must add your attributes to the `filterableAttributes` index setting.

```go
updateId, err := index.UpdateFilterableAttributes(&[]string{"id", "genres"})
task, err := index.UpdateFilterableAttributes(&[]string{"id", "genres"})
```

You only need to perform this operation once.

Note that Meilisearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [update status](https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status).
Note that Meilisearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [task status](https://docs.meilisearch.com/learn/advanced/asynchronous_operations.html#task-status).

Then, you can perform the search:

Expand Down Expand Up @@ -227,7 +227,7 @@ searchRes, err := index.Search("wonder",

## 🤖 Compatibility with Meilisearch

This package only guarantees the compatibility with the [version v0.24.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.24.0).
This package only guarantees the compatibility with the [version v0.25.0 of Meilisearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.25.0).

## 💡 Learn More

Expand Down
172 changes: 165 additions & 7 deletions client.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package meilisearch

import (
"context"
"net/http"
"strconv"
"time"

"github.com/valyala/fasthttp"
Expand All @@ -21,25 +23,35 @@ type ClientConfig struct {
Timeout time.Duration
}

type waitParams struct {
Context context.Context
Interval time.Duration
}

// ClientInterface is interface for all Meilisearch client
type ClientInterface interface {
Index(uid string) *Index
GetIndex(indexID string) (resp *Index, err error)
GetRawIndex(uid string) (resp map[string]interface{}, err error)
GetAllIndexes() (resp []*Index, err error)
GetAllRawIndexes() (resp []map[string]interface{}, err error)
CreateIndex(config *IndexConfig) (resp *Index, err error)
GetOrCreateIndex(config *IndexConfig) (resp *Index, err error)
DeleteIndex(uid string) (bool, error)
DeleteIndexIfExists(uid string) (bool, error)
GetKeys() (resp *Keys, err error)
CreateIndex(config *IndexConfig) (resp *Task, err error)
DeleteIndex(uid string) (resp *Task, err error)
CreateKey(request *Key) (resp *Key, err error)
GetKey(identifier string) (resp *Key, err error)
GetKeys() (resp *ResultKey, err error)
UpdateKey(identifier string, request *Key) (resp *Key, err error)
DeleteKey(identifier string) (resp bool, err error)
GetAllStats() (resp *Stats, err error)
CreateDump() (resp *Dump, err error)
GetDumpStatus(dumpUID string) (resp *Dump, err error)
Version() (*Version, error)
GetVersion() (resp *Version, err error)
Health() (*Health, error)
IsHealthy() bool
GetTask(taskID int64) (resp *Task, err error)
GetTasks() (resp *ResultTask, err error)
WaitForTask(task *Task, options ...waitParams) (*Task, error)
}

var _ ClientInterface = &Client{}
Expand Down Expand Up @@ -101,8 +113,42 @@ func (c *Client) GetAllStats() (resp *Stats, err error) {
return resp, nil
}

func (c *Client) GetKeys() (resp *Keys, err error) {
resp = &Keys{}
func (c *Client) CreateKey(request *Key) (resp *Key, err error) {
parsedRequest := convertKeyToParsedKey(*request)
resp = &Key{}
req := internalRequest{
endpoint: "/keys",
method: http.MethodPost,
contentType: contentTypeJSON,
withRequest: &parsedRequest,
withResponse: resp,
acceptedStatusCodes: []int{http.StatusCreated},
functionName: "CreateKey",
}
if err := c.executeRequest(req); err != nil {
return nil, err
}
return resp, nil
}

func (c *Client) GetKey(identifier string) (resp *Key, err error) {
resp = &Key{}
req := internalRequest{
endpoint: "/keys/" + identifier,
method: http.MethodGet,
withRequest: nil,
withResponse: resp,
acceptedStatusCodes: []int{http.StatusOK},
functionName: "GetKey",
}
if err := c.executeRequest(req); err != nil {
return nil, err
}
return resp, nil
}

func (c *Client) GetKeys() (resp *ResultKey, err error) {
resp = &ResultKey{}
req := internalRequest{
endpoint: "/keys",
method: http.MethodGet,
Expand All @@ -117,6 +163,39 @@ func (c *Client) GetKeys() (resp *Keys, err error) {
return resp, nil
}

func (c *Client) UpdateKey(identifier string, request *Key) (resp *Key, err error) {
parsedRequest := convertKeyToParsedKey(*request)
resp = &Key{}
req := internalRequest{
endpoint: "/keys/" + identifier,
method: http.MethodPatch,
contentType: contentTypeJSON,
withRequest: &parsedRequest,
withResponse: resp,
acceptedStatusCodes: []int{http.StatusOK},
functionName: "UpdateKey",
}
if err := c.executeRequest(req); err != nil {
return nil, err
}
return resp, nil
}

func (c *Client) DeleteKey(identifier string) (resp bool, err error) {
req := internalRequest{
endpoint: "/keys/" + identifier,
method: http.MethodDelete,
withRequest: nil,
withResponse: nil,
acceptedStatusCodes: []int{http.StatusNoContent},
functionName: "DeleteKey",
}
if err := c.executeRequest(req); err != nil {
return false, err
}
return true, nil
}

func (c *Client) Health() (resp *Health, err error) {
resp = &Health{}
req := internalRequest{
Expand Down Expand Up @@ -172,3 +251,82 @@ func (c *Client) GetDumpStatus(dumpUID string) (resp *Dump, err error) {
}
return resp, nil
}

func (c *Client) GetTask(taskID int64) (resp *Task, err error) {
resp = &Task{}
req := internalRequest{
endpoint: "/tasks/" + strconv.FormatInt(taskID, 10),
method: http.MethodGet,
withRequest: nil,
withResponse: resp,
acceptedStatusCodes: []int{http.StatusOK},
functionName: "GetTask",
}
if err := c.executeRequest(req); err != nil {
return nil, err
}
return resp, nil
}

func (c *Client) GetTasks() (resp *ResultTask, err error) {
resp = &ResultTask{}
req := internalRequest{
endpoint: "/tasks",
method: http.MethodGet,
withRequest: nil,
withResponse: &resp,
acceptedStatusCodes: []int{http.StatusOK},
functionName: "GetTasks",
}
if err := c.executeRequest(req); err != nil {
return nil, err
}
return resp, nil
}

// WaitForTask waits for a task to be processed.
// The function will check by regular interval provided in parameter interval
// the TaskStatus.
// If no ctx and interval are provided WaitForTask will check each 50ms the
// status of a task.
func (c *Client) WaitForTask(task *Task, options ...waitParams) (*Task, error) {
if options == nil {
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
defer cancelFunc()
options = []waitParams{
{
Context: ctx,
Interval: time.Millisecond * 50,
},
}
}
for {
if err := options[0].Context.Err(); err != nil {
return nil, err
}
getTask, err := c.GetTask(task.UID)
if err != nil {
return nil, err
}
if getTask.Status != TaskStatusEnqueued && getTask.Status != TaskStatusProcessing {
return getTask, nil
}
time.Sleep(options[0].Interval)
}
}

// This function allows the user to create a Key with an ExpiredAt in time.Time
// and transform the Key structure into a KeyParsed structure to send the time format
// managed by Meilisearch
func convertKeyToParsedKey(key Key) (resp KeyParsed) {
resp = KeyParsed{Description: key.Description, Actions: key.Actions, Indexes: key.Indexes}

// Convert time.Time to *string to feat the exact ISO-8601
// format of Meilisearch
if !key.ExpiresAt.IsZero() {
const Format = "2006-01-02T15:04:05"
timeParsedToString := key.ExpiresAt.Format(Format)
resp.ExpiresAt = &timeParsedToString
}
return resp
}
Loading

0 comments on commit b9b10bf

Please sign in to comment.