diff --git a/.ci/doc/templates/print-result-arraylist.tpl.java b/.ci/doc/templates/print-result-arraylist.tpl.java
new file mode 100644
index 00000000..ca5a96dc
--- /dev/null
+++ b/.ci/doc/templates/print-result-arraylist.tpl.java
@@ -0,0 +1,30 @@
+import io.kuzzle.sdk.Kuzzle;
+import io.kuzzle.sdk.Protocol.WebSocket;
+import io.kuzzle.sdk.Options.Protocol.WebSocketOptions;
+import io.kuzzle.sdk.Options.KuzzleOptions;
+import io.kuzzle.sdk.Options.SubscribeOptions;
+import io.kuzzle.sdk.CoreClasses.Responses.Response;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.ArrayList;
+
+public class SnippetTest {
+ private static Kuzzle kuzzle;
+
+ public static void main(String[] argv) {
+ try {
+ kuzzle = new Kuzzle(new WebSocket("kuzzle"));
+ kuzzle.connect();
+ [snippet-code]
+ for (Object o : result) {
+ System.out.println(o);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (kuzzle != null) {
+ kuzzle.disconnect();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/doc/3/controllers/document/delete-by-query/index.md b/doc/3/controllers/document/delete-by-query/index.md
new file mode 100644
index 00000000..c59a5abc
--- /dev/null
+++ b/doc/3/controllers/document/delete-by-query/index.md
@@ -0,0 +1,46 @@
+---
+code: true
+type: page
+title: deleteByQuery
+description: Delete documents matching query
+---
+
+# deleteByQuery
+
+Deletes documents matching the provided search query.
+
+Kuzzle uses the [ElasticSearch Query DSL](https://www.elastic.co/guide/en/elasticsearch/reference/7.4/query-dsl.html) syntax.
+
+An empty or null query will match all documents in the collection.
+
+
+
+```java
+ public CompletableFuture> deleteByQuery(
+ final String index,
+ final String collection,
+ final ConcurrentHashMap searchQuery) throws NotConnectedException, InternalException
+
+ public CompletableFuture> deleteByQuery(
+ final String index,
+ final String collection,
+ final ConcurrentHashMap searchQuery,
+ final Boolean waitForRefresh) throws NotConnectedException, InternalException
+```
+
+| Argument | Type | Description |
+| ------------------ | -------------------------------------------- | --------------- |
+| `index` | String
| Index name |
+| `collection` | String
| Collection name |
+| `searchQuery` | ConcurrentHashMap
| Query to match |
+| `waitForRefresh` | Boolean
(optional) | If set to `true`, Kuzzle will wait for the persistence layer to finish indexing|
+
+---
+
+## Returns
+
+Returns an `ArrayList` containing the deleted document ids.
+
+## Usage
+
+<<< ./snippets/delete-by-query.js
\ No newline at end of file
diff --git a/doc/3/controllers/document/delete-by-query/snippets/delete-by-query.java b/doc/3/controllers/document/delete-by-query/snippets/delete-by-query.java
new file mode 100644
index 00000000..46b10a9a
--- /dev/null
+++ b/doc/3/controllers/document/delete-by-query/snippets/delete-by-query.java
@@ -0,0 +1,10 @@
+ ConcurrentHashMap searchQuery = new ConcurrentHashMap<>();
+ ConcurrentHashMap query = new ConcurrentHashMap<>();
+ ConcurrentHashMap match = new ConcurrentHashMap<>();
+ match.put("capacity", 4);
+ query.put("match", match);
+ searchQuery.put("query", query);
+ ArrayList result = kuzzle
+ .getDocumentController()
+ .deleteByQuery("nyc-open-data", "yellow-taxi", searchQuery)
+ .get();
diff --git a/doc/3/controllers/document/delete-by-query/snippets/delete-by-query.test.yml b/doc/3/controllers/document/delete-by-query/snippets/delete-by-query.test.yml
new file mode 100644
index 00000000..5d3fd03d
--- /dev/null
+++ b/doc/3/controllers/document/delete-by-query/snippets/delete-by-query.test.yml
@@ -0,0 +1,22 @@
+name: document#deleteByQuery
+description: Delete documents matching query
+hooks:
+ before: |
+ curl -XDELETE kuzzle:7512/nyc-open-data
+ curl -XPOST kuzzle:7512/nyc-open-data/_create
+ curl -XPUT kuzzle:7512/nyc-open-data/yellow-taxi
+ for i in 1 2 3 4 5; do
+ curl -H "Content-type: application/json" -d '{"capacity": 4}' kuzzle:7512/nyc-open-data/yellow-taxi/document_$i/_create
+ done
+ for i in 1 2 3 4 5; do
+ curl -H "Content-type: application/json" -d '{"capacity": 7}' kuzzle:7512/nyc-open-data/yellow-taxi/_create
+ done
+ curl -XPOST kuzzle:7512/nyc-open-data/_refresh
+ after:
+template: print-result-arraylist
+expected:
+ - "document_1"
+ - "document_2"
+ - "document_3"
+ - "document_4"
+ - "document_5"
\ No newline at end of file
diff --git a/src/main/java/io/kuzzle/sdk/API/Controllers/DocumentController.java b/src/main/java/io/kuzzle/sdk/API/Controllers/DocumentController.java
index 07a43590..9e404ad6 100644
--- a/src/main/java/io/kuzzle/sdk/API/Controllers/DocumentController.java
+++ b/src/main/java/io/kuzzle/sdk/API/Controllers/DocumentController.java
@@ -653,6 +653,57 @@ public CompletableFuture>> mCreateOr
return this.mCreateOrReplace(index, collection, documents, null);
}
+ /**
+ * Deletes documents matching the provided search query.
+ *
+ * @param index
+ * @param collection
+ * @param searchQuery
+ * @param waitForRefresh
+ * @return a CompletableFuture
+ * @throws NotConnectedException
+ * @throws InternalException
+ */
+ public CompletableFuture> deleteByQuery(
+ final String index,
+ final String collection,
+ final ConcurrentHashMap searchQuery,
+ final Boolean waitForRefresh) throws NotConnectedException, InternalException {
+
+ final KuzzleMap query = new KuzzleMap();
+
+ query
+ .put("index", index)
+ .put("collection", collection)
+ .put("controller", "document")
+ .put("action", "deleteByQuery")
+ .put("body", new KuzzleMap(searchQuery))
+ .put("waitForRefresh", waitForRefresh);
+
+ return kuzzle
+ .query(query)
+ .thenApplyAsync(
+ (response) -> (ArrayList)((ConcurrentHashMap) response.result).get("ids"));
+ }
+
+ /**
+ * Deletes documents matching the provided search query.
+ *
+ * @param index
+ * @param collection
+ * @param searchQuery
+ * @return a CompletableFuture
+ * @throws NotConnectedException
+ * @throws InternalException
+ */
+ public CompletableFuture> deleteByQuery(
+ final String index,
+ final String collection,
+ final ConcurrentHashMap searchQuery) throws NotConnectedException, InternalException {
+
+ return this.deleteByQuery(index, collection, searchQuery, null);
+ }
+
/**
* Validates data against existing validation rules.
*
diff --git a/src/test/java/io/kuzzle/test/API/Controllers/DocumentTest/DocumentTest.java b/src/test/java/io/kuzzle/test/API/Controllers/DocumentTest/DocumentTest.java
index f1b79737..c1bf6b00 100644
--- a/src/test/java/io/kuzzle/test/API/Controllers/DocumentTest/DocumentTest.java
+++ b/src/test/java/io/kuzzle/test/API/Controllers/DocumentTest/DocumentTest.java
@@ -26,6 +26,37 @@ public class DocumentTest {
private AbstractProtocol networkProtocol = Mockito.mock(WebSocket.class);
+ @Test
+ public void getDocumentTest() throws NotConnectedException, InternalException {
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(networkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ ArgumentCaptor arg = ArgumentCaptor.forClass(KuzzleMap.class);
+
+ kuzzleMock.getDocumentController().get(index, collection, "some-id");
+ Mockito.verify(kuzzleMock, Mockito.times(1)).query((KuzzleMap) arg.capture());
+
+ assertEquals(((KuzzleMap) arg.getValue()).getString("controller"), "document");
+ assertEquals(((KuzzleMap) arg.getValue()).getString("action"), "get");
+ assertEquals(((KuzzleMap) arg.getValue()).getString("index"), "nyc-open-data");
+ assertEquals(((KuzzleMap) arg.getValue()).getString("_id"), "some-id");
+ }
+
+ @Test(expected = NotConnectedException.class)
+ public void getDocumentShouldThrowWhenNotConnected() throws NotConnectedException, InternalException {
+ AbstractProtocol fakeNetworkProtocol = Mockito.mock(WebSocket.class);
+ Mockito.when(fakeNetworkProtocol.getState()).thenAnswer((Answer) invocation -> ProtocolState.CLOSE);
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(fakeNetworkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ kuzzleMock.getDocumentController().get(index, collection, "some-id");
+ }
+
+
@Test
public void createDocumentTestA() throws NotConnectedException, InternalException {
@@ -82,7 +113,6 @@ public void createDocumentTestB() throws NotConnectedException, InternalExceptio
@Test(expected = NotConnectedException.class)
public void createDocumentThrowWhenNotConnected() throws NotConnectedException, InternalException {
-
AbstractProtocol fakeNetworkProtocol = Mockito.mock(WebSocket.class);
Mockito.when(fakeNetworkProtocol.getState()).thenAnswer((Answer) invocation -> ProtocolState.CLOSE);
@@ -97,36 +127,6 @@ public void createDocumentThrowWhenNotConnected() throws NotConnectedException,
kuzzleMock.getDocumentController().create(index, collection, document);
}
- @Test
- public void getDocumentTest() throws NotConnectedException, InternalException {
-
- Kuzzle kuzzleMock = spy(new Kuzzle(networkProtocol));
- String index = "nyc-open-data";
- String collection = "yellow-taxi";
-
- ArgumentCaptor arg = ArgumentCaptor.forClass(KuzzleMap.class);
-
- kuzzleMock.getDocumentController().get(index, collection, "some-id");
- Mockito.verify(kuzzleMock, Mockito.times(1)).query((KuzzleMap) arg.capture());
-
- assertEquals(((KuzzleMap) arg.getValue()).getString("controller"), "document");
- assertEquals(((KuzzleMap) arg.getValue()).getString("action"), "get");
- assertEquals(((KuzzleMap) arg.getValue()).getString("index"), "nyc-open-data");
- assertEquals(((KuzzleMap) arg.getValue()).getString("_id"), "some-id");
- }
-
- @Test(expected = NotConnectedException.class)
- public void getDocumentShouldThrowWhenNotConnected() throws NotConnectedException, InternalException {
- AbstractProtocol fakeNetworkProtocol = Mockito.mock(WebSocket.class);
- Mockito.when(fakeNetworkProtocol.getState()).thenAnswer((Answer) invocation -> ProtocolState.CLOSE);
-
- Kuzzle kuzzleMock = spy(new Kuzzle(fakeNetworkProtocol));
- String index = "nyc-open-data";
- String collection = "yellow-taxi";
-
- kuzzleMock.getDocumentController().get(index, collection, "some-id");
- }
-
@Test
public void createOrReplaceDocumentTestA() throws NotConnectedException, InternalException {
@@ -258,7 +258,24 @@ public void updateShouldThrowWhenNotConnected() throws NotConnectedException, In
ConcurrentHashMap document = new ConcurrentHashMap<>();
document.put("name", "Yoann");
- kuzzleMock.getDocumentController().update(index, collection, id, document);
+ UpdateOptions options = new UpdateOptions();
+ options.setWaitForRefresh(false);
+ options.setSource(true);
+ options.setRetryOnConflict(1);
+
+ ArgumentCaptor arg = ArgumentCaptor.forClass(KuzzleMap.class);
+
+ kuzzleMock.getDocumentController().update(index, collection, "some-id", document, options);
+ Mockito.verify(kuzzleMock, Mockito.times(1)).query((KuzzleMap) arg.capture());
+
+ assertEquals(((KuzzleMap) arg.getValue()).getString("controller"), "document");
+ assertEquals(((KuzzleMap) arg.getValue()).getString("action"), "update");
+ assertEquals(((KuzzleMap) arg.getValue()).getString("index"), "nyc-open-data");
+ assertEquals(((KuzzleMap) arg.getValue()).getString("_id"), "some-id");
+ assertEquals(((KuzzleMap) arg.getValue()).getNumber("retryOnConflict"), 1);
+ assertEquals(((KuzzleMap) arg.getValue()).getBoolean("waitForRefresh"), false);
+ assertEquals(((KuzzleMap) arg.getValue()).getBoolean("source"), true);
+ assertEquals(((ConcurrentHashMap) (((KuzzleMap) arg.getValue()).get("body"))).get("name").toString(), "Yoann");
}
@Test
@@ -919,6 +936,75 @@ public void mCreateOrReplaceDocumentShouldThrowWhenNotConnected() throws NotConn
kuzzleMock.getDocumentController().mCreateOrReplace(index, collection, documents);
}
+ @Test
+ public void deleteByQueryDocumentTestA() throws NotConnectedException, InternalException {
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(networkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ ConcurrentHashMap searchQuery = new ConcurrentHashMap<>();
+ ConcurrentHashMap query = new ConcurrentHashMap<>();
+ ConcurrentHashMap match = new ConcurrentHashMap<>();
+ match.put("Hello", "Clarisse");
+ query.put("match", match);
+ searchQuery.put("query", query);
+
+ ArgumentCaptor arg = ArgumentCaptor.forClass(KuzzleMap.class);
+
+ kuzzleMock.getDocumentController().deleteByQuery(index, collection, searchQuery);
+ Mockito.verify(kuzzleMock, Mockito.times(1)).query(arg.capture());
+
+ assertEquals((arg.getValue()).getString("controller"), "document");
+ assertEquals((arg.getValue()).getString("action"), "deleteByQuery");
+ assertEquals((arg.getValue()).getString("index"), "nyc-open-data");
+ assertEquals((arg.getValue()).getBoolean("waitForRefresh"), null);
+ assertEquals(((ConcurrentHashMap) ((ConcurrentHashMap) (((KuzzleMap) (arg.getValue()).get("body"))).get("query")).get("match")).get("Hello"), "Clarisse");
+ }
+
+ @Test
+ public void deleteByQueryDocumentTestB() throws NotConnectedException, InternalException {
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(networkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ ConcurrentHashMap searchQuery = new ConcurrentHashMap<>();
+ ConcurrentHashMap query = new ConcurrentHashMap<>();
+ ConcurrentHashMap match = new ConcurrentHashMap<>();
+ match.put("Hello", "Clarisse");
+ query.put("match", match);
+ searchQuery.put("query", query);
+
+ ArgumentCaptor arg = ArgumentCaptor.forClass(KuzzleMap.class);
+
+ kuzzleMock.getDocumentController().deleteByQuery(index, collection, searchQuery, false);
+ Mockito.verify(kuzzleMock, Mockito.times(1)).query(arg.capture());
+
+ assertEquals((arg.getValue()).getString("controller"), "document");
+ assertEquals((arg.getValue()).getString("action"), "deleteByQuery");
+ assertEquals((arg.getValue()).getString("index"), "nyc-open-data");
+ assertEquals((arg.getValue()).getBoolean("waitForRefresh"), false);
+ assertEquals(((ConcurrentHashMap) ((ConcurrentHashMap) (((KuzzleMap) (arg.getValue()).get("body"))).get("query")).get("match")).get("Hello"), "Clarisse");
+ }
+
+ @Test(expected = NotConnectedException.class)
+ public void deleteByQueryDocumentShouldThrowWhenNotConnected() throws NotConnectedException, InternalException {
+ AbstractProtocol fakeNetworkProtocol = Mockito.mock(WebSocket.class);
+ Mockito.when(fakeNetworkProtocol.getState()).thenAnswer((Answer) invocation -> ProtocolState.CLOSE);
+
+ Kuzzle kuzzleMock = spy(new Kuzzle(fakeNetworkProtocol));
+ String index = "nyc-open-data";
+ String collection = "yellow-taxi";
+
+ ConcurrentHashMap searchQuery = new ConcurrentHashMap<>();
+ ConcurrentHashMap match = new ConcurrentHashMap<>();
+ match.put("Hello", "Clarisse");
+ searchQuery.put("match", match);
+
+ kuzzleMock.getDocumentController().deleteByQuery(index, collection, searchQuery);
+ }
+
@Test
public void validateDocumentTest() throws NotConnectedException, InternalException {