Skip to content

rewrite client to use ServiceTemplate based API #154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
88 changes: 66 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,73 @@ implementation 'com.meilisearch.sdk:meilisearch-java:0.3.1'

```java
import com.meilisearch.sdk.Client;
import com.meilisearch.sdk.ClientBuilder;
import com.meilisearch.sdk.Config;
import com.meilisearch.sdk.Index;
import com.meilisearch.sdk.api.documents.DocumentHandler;
import com.meilisearch.sdk.api.documents.Update;
import com.meilisearch.sdk.api.index.Index;
import com.meilisearch.sdk.exceptions.MeiliSearchRuntimeException;
import com.meilisearch.sdk.http.ApacheHttpClient;
import com.meilisearch.sdk.json.GsonJsonHandler;

class TestMeiliSearch {
import java.util.Collections;
import java.util.Map;

public class TestMeiliSearch {
public static void main(String[] args) throws Exception {

final String documents = "["
+ "{\"book_id\": 123, \"title\": \"Pride and Prejudice\"},"
+ "{\"book_id\": 456, \"title\": \"Le Petit Prince\"},"
+ "{\"book_id\": 1, \"title\": \"Alice In Wonderland\"},"
+ "{\"book_id\": 1344, \"title\": \"The Hobbit\"},"
+ "{\"book_id\": 4, \"title\": \"Harry Potter and the Half-Blood Prince\"},"
+ "{\"book_id\": 2, \"title\": \"The Hitchhiker\'s Guide to the Galaxy\"}"
+ "{\"id\": 123, \"title\": \"Pride and Prejudice\"},"
+ "{\"id\": 456, \"title\": \"Le Petit Prince\"},"
+ "{\"id\": 1, \"title\": \"Alice In Wonderland\"},"
+ "{\"id\": 1344, \"title\": \"The Hobbit\"},"
+ "{\"id\": 4, \"title\": \"Harry Potter and the Half-Blood Prince\"},"
+ "{\"id\": 2, \"title\": \"The Hitchhiker\'s Guide to the Galaxy\"}"
+ "]";

Client client = new Client(new Config("http://localhost:7700", "masterKey"));
Map<String, Class<?>> modelMapping = Collections.singletonMap("books", Book.class);
Config config = new Config("http://localhost:7700", "masterKey", modelMapping);
// set httpClient and JsonHandler explicit
ApacheHttpClient httpClient = new ApacheHttpClient(config);
GsonJsonHandler handler = new GsonJsonHandler();
Client client = ClientBuilder.withConfig(config).withHttpClient(httpClient).withJsonHandler(handler).build();
// let the sdk autodetect jsonhandler and httpclient based on the classes in the classpath
client = ClientBuilder.withConfig(config).build();

try {
Index index = client.index().getOrCreateIndex("books", "id");
DocumentHandler<Book> bookHandler = client.documents("books");
Update update = bookHandler.addDocuments(documents);
bookHandler.waitForPendingUpdate(update.getUpdateId());


} catch (MeiliSearchRuntimeException e) {
// an MeiliSearchRuntimeException will be thrown in case something went wrong
e.printStackTrace();
}
}
}

// An index is where the documents are stored.
Index index = client.index("books");
public class Book {
int id;
String title;

public int getId() {
return id;
}

public Book setId(int id) {
this.id = id;
return this;
}

public String getTitle() {
return title;
}

// If the index 'books' does not exist, MeiliSearch creates it when you first add the documents.
index.addDocuments(documents); // => { "updateId": 0 }
public Book setTitle(String title) {
this.title = title;
return this;
}
}
```
Expand All @@ -101,20 +146,19 @@ With the `updateId`, you can check the status (`enqueued`, `processed` or `faile

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

A basic search can be performed by calling `index.search()` method, with a simple string query.
A basic search can be performed by calling `search()` method on the handler, with a simple string query.

```java
import com.meilisearch.sdk.model.SearchResult;

// MeiliSearch is typo-tolerant:
SearchResult results = index.search("harry pottre");
System.out.println(results);
DocumentHandler<Book> bookHandler = client.documents("books");
SearchResponse<Book> alice = bookHandler.search("Alice");
```

- Output:

```
SearchResult(hits=[{book_id=4.0, title=Harry Potter and the Half-Blood Prince}], offset=0, limit=20, nbHits=1, exhaustiveNbHits=false, facetsDistribution=null, exhaustiveFacetsCount=false, processingTimeMs=3, query=harry pottre)
SearchResponse(hits=[{id=4.0, title=Harry Potter and the Half-Blood Prince}], offset=0, limit=20, nbHits=1, exhaustiveNbHits=false, facetsDistribution=null, exhaustiveFacetsCount=false, processingTimeMs=3, query=harry pottre)
```

#### Custom Search <!-- omit in toc -->
Expand All @@ -127,10 +171,10 @@ import com.meilisearch.sdk.SearchRequest;

// ...

String results = index.search(
SearchResult<Book> result = bookHandler.search(
new SearchRequest("in")
.setMatches(true)
.setAttributesToHighlight(new String[]{"title"})
.setAttributesToHighlight(Arrays.asList("title"))
);
System.out.println(results.getHits());
```
Expand All @@ -139,10 +183,10 @@ System.out.println(results.getHits());

```json
[{
"book_id":1,
"id":1,
"title":"Alice In Wonderland",
"_formatted":{
"book_id":1,
"id":1,
"title":"Alice <em>In</em> Wonderland"
},
"_matchesInfo":{
Expand Down
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ java {

repositories {
mavenCentral() // Required for Lombok dependency
jcenter()
}

configurations {
Expand Down
195 changes: 42 additions & 153 deletions src/main/java/com/meilisearch/sdk/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,178 +3,67 @@
*/
package com.meilisearch.sdk;

import com.google.gson.Gson;
import com.meilisearch.sdk.api.documents.DocumentHandler;
import com.meilisearch.sdk.api.index.IndexHandler;
import com.meilisearch.sdk.api.instance.InstanceHandler;
import com.meilisearch.sdk.api.keys.KeysHandler;

import com.meilisearch.sdk.exceptions.MeiliSearchApiException;
import java.util.Map;
import java.util.stream.Collectors;

/**
* MeiliSearch client
*/
public class Client {
public Config config;
public IndexesHandler indexesHandler;
public Gson gson;
public DumpHandler dumpHandler;
private final IndexHandler indexHandler;
private final InstanceHandler instanceHandler;
private final KeysHandler keysHandler;
private final Map<String, DocumentHandler<?>> handlerMap;
private final ServiceTemplate serviceTemplate;

/**
* Calls instance for MeiliSearch client
*
* @param config Configuration to connect to MeiliSearch instance
*/
public Client(Config config) {
this.config = config;
this.gson = new Gson();
this.indexesHandler = new IndexesHandler(config);
this.dumpHandler = new DumpHandler(config);
Client(Config config, ServiceTemplate serviceTemplate) {
this.serviceTemplate = serviceTemplate;
this.indexHandler = new IndexHandler(serviceTemplate, serviceTemplate.getRequestFactory());
this.instanceHandler = new InstanceHandler(serviceTemplate, serviceTemplate.getRequestFactory());
this.keysHandler = new KeysHandler(serviceTemplate, serviceTemplate.getRequestFactory());
this.handlerMap = config.getModelMapping()
.entrySet()
.stream()
.collect(
Collectors.toMap(
Map.Entry::getKey,
entry -> new DocumentHandler<>(serviceTemplate, serviceTemplate.getRequestFactory(), entry.getKey(), entry.getValue())
)
);
}

/**
* Creates index
* Refer https://docs.meilisearch.com/reference/api/indexes.html#create-an-index
*
* @param uid Unique identifier for the index to create
* @return MeiliSearch API response
* @throws Exception if an error occurs
*/
public Index createIndex(String uid) throws Exception {
return this.createIndex(uid, null);
public IndexHandler index() {
return this.indexHandler;
}

/**
* Creates index
* Refer https://docs.meilisearch.com/reference/api/indexes.html#create-an-index
*
* @param uid Unique identifier for the index to create
* @param primaryKey The primary key of the documents in that index
* @return MeiliSearch API response
* @throws Exception if an error occurs
*/
public Index createIndex(String uid, String primaryKey) throws Exception {
Index index = gson.fromJson(this.indexesHandler.create(uid, primaryKey), Index.class);
index.setConfig(this.config);
return index;
@SuppressWarnings("unchecked")
public <T> DocumentHandler<T> documents(String uid) {
return (DocumentHandler<T>) this.handlerMap.get(uid);
}

/**
* Gets all indexes
* Refer https://docs.meilisearch.com/reference/api/indexes.html#list-all-indexes
*
* @return list of indexes in the MeiliSearch client
* @throws Exception if an error occurs
*/
public Index[] getIndexList() throws Exception {
Index[] meiliSearchIndexList = gson.fromJson(this.indexesHandler.getAll(), Index[].class);
for (Index indexes : meiliSearchIndexList) {
indexes.setConfig(this.config);
}
return meiliSearchIndexList;
}

/**
* Creates a local reference to an index identified by `uid`, without doing an HTTP call.
* Calling this method doesn't create an index by itself, but grants access to all the other methods in the Index class.
*
* @param uid Unique identifier of the index
* @return Index instance
* @throws Exception if an error occurs
*/
public Index index(String uid) throws Exception {
Index index = new Index();
index.uid = uid;
index.setConfig(this.config);
return index;
}

/**
* Gets single index by uid
* Refer https://docs.meilisearch.com/reference/api/indexes.html#get-one-index
*
* @param uid Unique identifier of the index to get
* @return MeiliSearch API response
* @throws Exception if an error occurs
*/
public Index getIndex(String uid) throws Exception {
Index indexes = gson.fromJson(this.indexesHandler.get(uid), Index.class);
indexes.setConfig(this.config);
return indexes;
}

/**
* Updates single index by uid
* Refer https://docs.meilisearch.com/reference/api/indexes.html#update-an-index
*
* @param uid Unique identifier of the index to update
* @param primaryKey Primary key of the documents in the index
* @return MeiliSearch API response
* @throws Exception if an error occurs
*/
public Index updateIndex(String uid, String primaryKey) throws Exception {
Index index = gson.fromJson(this.indexesHandler.updatePrimaryKey(uid, primaryKey), Index.class);
index.setConfig(this.config);
return index;
}

/**
* Deletes single index by uid
* Refer https://docs.meilisearch.com/reference/api/indexes.html#get-one-index
*
* @param uid Unique identifier of the index to delete
* @return MeiliSearch API response
* @throws Exception if an error occurs
*/
public String deleteIndex(String uid) throws Exception {
return this.indexesHandler.delete(uid);
}

/**
* Gets single index by uid or if it does not exists, Create index
*
* @param uid Unique identifier for the index to create
* @param primaryKey The primary key of the documents in that index
* @return Index instance
* @throws Exception if an error occurs
*/
public Index getOrCreateIndex(String uid, String primaryKey) throws Exception {
try {
return this.getIndex(uid);
} catch (MeiliSearchApiException e) {
if (e.getErrorCode().equals("index_not_found")) {
return this.createIndex(uid, primaryKey);
public <T> DocumentHandler<T> documents(String uid, Class<T> model) {
DocumentHandler<T> handler = documents(uid);
if (handler != null) {
if (handler.getIndexModel() == model) {
return handler;
}
throw e;
}
}
handler = new DocumentHandler<>(serviceTemplate, serviceTemplate.getRequestFactory(), uid, model);
handlerMap.put(uid, handler);

/**
* Gets single index by uid or if it does not exists, Create index
*
* @param uid Unique identifier for the index to create
* @return Index instance
* @throws Exception if an error occurs
*/
public Index getOrCreateIndex(String uid) throws Exception {
return getOrCreateIndex(uid, null);
return handler;
}

/**
* Triggers the creation of a MeiliSearch dump.
* Refer https://docs.meilisearch.com/reference/api/dump.html#create-a-dump
*
* @throws Exception if an error occurs
*/
public Dump createDump() throws Exception {
return this.dumpHandler.createDump();
public InstanceHandler instance() {
return instanceHandler;
}

/**
* Gets the status of a MeiliSearch dump.
* https://docs.meilisearch.com/reference/api/dump.html#get-dump-status
*
* @param uid Unique identifier for correspondent dump
* @return String with dump status
* @throws Exception if an error occurs
*/
public String getDumpStatus(String uid) throws Exception {
return this.dumpHandler.getDumpStatus(uid);
public KeysHandler keys() {
return keysHandler;
}
}
Loading