diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml
index b2187067..bd563c80 100644
--- a/.code-samples.meilisearch.yaml
+++ b/.code-samples.meilisearch.yaml
@@ -854,3 +854,5 @@ export_post_1: |-
client.export(request);
compact_index_1: |-
client.index("INDEX_NAME").compact();
+rename_an_index_1: |-
+ client.updateIndex("indexA", null, "indexB");
diff --git a/build.gradle b/build.gradle
index f0d9233b..2a17c04b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,7 +7,6 @@
*/
plugins {
- // Apply the java-library plugin to add support for Java Library
id 'java-library'
id 'maven-publish'
id 'signing'
@@ -24,8 +23,8 @@ base {
}
jacoco {
- toolVersion = "0.8.8"
- reportsDirectory = layout.buildDirectory.dir("$projectDir/tmp/coverage")
+ toolVersion = "0.8.8"
+ reportsDirectory = layout.buildDirectory.dir("$projectDir/tmp/coverage")
}
jacocoTestCoverageVerification {
@@ -47,23 +46,24 @@ configurations {
}
dependencies {
- // This dependency is used internally, and not exposed to consumers on their own compile classpath.
+ // Library dependencies
implementation 'com.google.code.gson:gson:2.13.2'
implementation 'org.json:json:20250517'
- // https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5
api 'com.squareup.okhttp3:okhttp:5.3.0'
- // Use JUnit test framework
+ // JUnit 6
testImplementation(platform('org.junit:junit-bom:6.0.1'))
testImplementation('org.junit.jupiter:junit-jupiter:6.0.1')
- // https://mvnrepository.com/artifact/org.mockito/mockito-core
+
+ // Test libs
testImplementation 'org.mockito:mockito-core:4.11.0'
testImplementation 'org.hamcrest:hamcrest:3.0'
testImplementation 'com.squareup.okio:okio:3.16.2'
testImplementation 'com.squareup.okhttp3:okhttp:5.3.0'
+ testImplementation 'com.squareup.okhttp3:mockwebserver:5.3.0'
+
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.20.1'
- // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
compileOnly group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.20.1'
// Lombok
@@ -72,16 +72,15 @@ dependencies {
testCompileOnly 'org.projectlombok:lombok:1.18.42'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.42'
- // Jwt
+ // JWT
implementation 'com.auth0:java-jwt:4.5.0'
}
-task buildJar(type: Jar) {
+tasks.register('buildJar', Jar) {
archiveBaseName = 'meilisearch-java'
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
- }
- {
+ } {
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
exclude 'META-INF/*.RSA'
@@ -91,11 +90,11 @@ task buildJar(type: Jar) {
test {
useJUnitPlatform {
- excludeTags 'integration'
+ excludeTags 'integration'
}
finalizedBy jacocoTestReport
testLogging {
- events 'passed', 'skipped', 'failed'
+ events 'passed', 'skipped', 'failed'
}
}
@@ -109,7 +108,7 @@ jacocoTestReport {
finalizedBy jacocoTestCoverageVerification
}
-task integrationTest(type: Test) {
+tasks.register('integrationTest', Test) {
useJUnitPlatform {
includeTags 'integration'
}
@@ -128,7 +127,8 @@ java {
}
tasks.withType(JavaCompile).configureEach {
- options.compilerArgs += ['-Xlint:deprecation', '-Xlint:unchecked']
+ options.compilerArgs += ['-Xlint:deprecation', '-Xlint:unchecked']
+ options.encoding = 'UTF-8'
}
publishing {
@@ -168,13 +168,10 @@ publishing {
nexusPublishing {
repositories {
sonatype {
- // Point to new Central Portal staging API (replaces oss.sonatype.org)
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
- // Credentials: use Central Portal token (username/password)
- username.set(System.getenv("MAVEN_CENTRAL_USERNAME")) // portal token user
- password.set(System.getenv("MAVEN_CENTRAL_PASSWORD")) // portal token password
- // packageGroup or stagingProfileId not needed if using nexus-publish-plugin
+ username.set(System.getenv("MAVEN_CENTRAL_USERNAME"))
+ password.set(System.getenv("MAVEN_CENTRAL_PASSWORD"))
}
}
}
@@ -185,17 +182,13 @@ signing {
}
javadoc {
- if(JavaVersion.current().isJava9Compatible()) {
+ if (JavaVersion.current().isJava9Compatible()) {
options.addBooleanOption('html5', true)
}
}
spotless {
-
java {
- // don't need to set target, it is inferred from java
-
- // apply a specific flavor of google-java-format
googleJavaFormat('1.10.0').aosp()
}
}
diff --git a/src/main/java/com/meilisearch/sdk/Client.java b/src/main/java/com/meilisearch/sdk/Client.java
index 3a871eb8..888a52dd 100644
--- a/src/main/java/com/meilisearch/sdk/Client.java
+++ b/src/main/java/com/meilisearch/sdk/Client.java
@@ -10,11 +10,7 @@
import com.meilisearch.sdk.model.*;
import com.meilisearch.sdk.model.batch.req.BatchesQuery;
import com.meilisearch.sdk.model.batch.res.Batch;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.UUID;
+import java.util.*;
/** Meilisearch client */
public class Client {
@@ -169,6 +165,15 @@ public TaskInfo updateIndex(String uid, String primaryKey) throws MeilisearchExc
return this.indexesHandler.updatePrimaryKey(uid, primaryKey);
}
+ /** Update an index: either update primary key or rename the index by passing indexUid. */
+ public TaskInfo updateIndex(String uid, String primaryKey, String indexUid)
+ throws MeilisearchException {
+ if (indexUid != null) {
+ return this.indexesHandler.updateIndexUid(uid, indexUid);
+ }
+ return this.indexesHandler.updatePrimaryKey(uid, primaryKey);
+ }
+
/**
* Deletes single index by its unique identifier
*
diff --git a/src/main/java/com/meilisearch/sdk/IndexesHandler.java b/src/main/java/com/meilisearch/sdk/IndexesHandler.java
index 9a9996f5..181af836 100644
--- a/src/main/java/com/meilisearch/sdk/IndexesHandler.java
+++ b/src/main/java/com/meilisearch/sdk/IndexesHandler.java
@@ -12,7 +12,7 @@
*
* @see API specification
*/
-class IndexesHandler {
+public class IndexesHandler {
private final HttpClient httpClient;
/**
@@ -121,6 +121,20 @@ TaskInfo updatePrimaryKey(String uid, String primaryKey) throws MeilisearchExcep
return httpClient.patch(indexesPath().addSubroute(uid).getURL(), index, TaskInfo.class);
}
+ /**
+ * Rename an index by changing its uid.
+ *
+ * @param uid Unique identifier of the index to rename
+ * @param indexUid New unique identifier for the index
+ * @return Meilisearch API response as TaskInfo
+ * @throws MeilisearchException if an error occurs
+ */
+ TaskInfo updateIndexUid(String uid, String indexUid) throws MeilisearchException {
+ HashMap body = new HashMap<>();
+ body.put("uid", indexUid);
+ return httpClient.patch(indexesPath().addSubroute(uid).getURL(), body, TaskInfo.class);
+ }
+
/**
* Deletes an index in the Meilisearch instance
*
diff --git a/src/main/java/com/meilisearch/sdk/model/SearchResult.java b/src/main/java/com/meilisearch/sdk/model/SearchResult.java
index ef8c424a..0640d4d2 100644
--- a/src/main/java/com/meilisearch/sdk/model/SearchResult.java
+++ b/src/main/java/com/meilisearch/sdk/model/SearchResult.java
@@ -18,6 +18,7 @@ public class SearchResult implements Searchable {
Object facetDistribution;
HashMap facetStats;
int processingTimeMs;
+ ArrayList queryVector;
String query;
int offset;
int limit;
diff --git a/src/main/java/com/meilisearch/sdk/model/SearchResultPaginated.java b/src/main/java/com/meilisearch/sdk/model/SearchResultPaginated.java
index 239077f5..474ba742 100644
--- a/src/main/java/com/meilisearch/sdk/model/SearchResultPaginated.java
+++ b/src/main/java/com/meilisearch/sdk/model/SearchResultPaginated.java
@@ -23,6 +23,7 @@ public class SearchResultPaginated implements Searchable {
Object facetDistribution;
HashMap facetStats;
int processingTimeMs;
+ ArrayList queryVector;
String query;
public SearchResultPaginated() {}
diff --git a/src/main/java/com/meilisearch/sdk/model/SwapIndexesParams.java b/src/main/java/com/meilisearch/sdk/model/SwapIndexesParams.java
index 53229791..bc8c5c2b 100644
--- a/src/main/java/com/meilisearch/sdk/model/SwapIndexesParams.java
+++ b/src/main/java/com/meilisearch/sdk/model/SwapIndexesParams.java
@@ -10,6 +10,7 @@
@Accessors(chain = true)
public class SwapIndexesParams {
protected String[] indexes;
+ protected Boolean rename;
public SwapIndexesParams() {}
}
diff --git a/src/test/java/com/meilisearch/sdk/IndexRenameTest.java b/src/test/java/com/meilisearch/sdk/IndexRenameTest.java
new file mode 100644
index 00000000..2c59a88f
--- /dev/null
+++ b/src/test/java/com/meilisearch/sdk/IndexRenameTest.java
@@ -0,0 +1,52 @@
+package com.meilisearch.sdk;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+import com.meilisearch.sdk.model.TaskInfo;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class IndexRenameTest {
+
+ private MockWebServer server;
+ private Client client;
+
+ @BeforeEach
+ void setup() throws Exception {
+ server = new MockWebServer();
+ server.start();
+
+ client = new Client(new Config(server.url("/").toString(), "masterKey"));
+ }
+
+ @AfterEach
+ void teardown() throws Exception {
+ server.shutdown();
+ }
+
+ @Test
+ void testRenameIndex() throws Exception {
+ String response = "{ \"taskUid\": 123 }";
+
+ server.enqueue(new MockResponse().setBody(response).setResponseCode(202));
+
+ TaskInfo task = client.updateIndex("oldIndex", null, "newIndex");
+
+ assertThat(task, notNullValue());
+ assertThat(task.getTaskUid(), equalTo(123));
+
+ RecordedRequest req = server.takeRequest();
+
+ assertThat(req.getMethod(), equalTo("PATCH"));
+ assertThat(req.getPath(), equalTo("//indexes/oldIndex"));
+
+ String body = req.getBody().readUtf8();
+ assertThat(body, containsString("\"uid\":\"newIndex\""));
+ assertThat(req.getHeader("Authorization"), equalTo("Bearer masterKey"));
+ }
+}
diff --git a/src/test/java/com/meilisearch/sdk/SearchResultQueryVectorTest.java b/src/test/java/com/meilisearch/sdk/SearchResultQueryVectorTest.java
new file mode 100644
index 00000000..7f7fc4a5
--- /dev/null
+++ b/src/test/java/com/meilisearch/sdk/SearchResultQueryVectorTest.java
@@ -0,0 +1,56 @@
+package com.meilisearch.sdk;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+import com.meilisearch.sdk.model.SearchResult;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class SearchResultQueryVectorTest {
+
+ private MockWebServer server;
+ private Client client;
+
+ @BeforeEach
+ void setup() throws Exception {
+ server = new MockWebServer();
+ server.start();
+
+ client = new Client(new Config(server.url("/").toString(), "masterKey"));
+ }
+
+ @AfterEach
+ void teardown() throws Exception {
+ server.shutdown();
+ }
+
+ @Test
+ void testQueryVectorDeserialization() throws Exception {
+ String json =
+ """
+ {
+ "hits": [],
+ "queryVector": [1.1, -2.5, 3.14],
+ "offset": 0,
+ "limit": 20,
+ "estimatedTotalHits": 0,
+ "query": "hello",
+ "processingTimeMs": 1
+ }
+ """;
+
+ server.enqueue(new MockResponse().setResponseCode(200).setBody(json));
+
+ SearchResult res = client.index("movies").search("hello");
+
+ assertThat(res, notNullValue());
+ assertThat(res.getQueryVector(), hasSize(3));
+ assertThat(res.getQueryVector().get(0), equalTo(1.1f));
+ assertThat(res.getQueryVector().get(1), equalTo(-2.5f));
+ assertThat(res.getQueryVector().get(2), equalTo(3.14f));
+ }
+}
diff --git a/src/test/java/com/meilisearch/sdk/SwapIndexRenameTest.java b/src/test/java/com/meilisearch/sdk/SwapIndexRenameTest.java
new file mode 100644
index 00000000..6b477772
--- /dev/null
+++ b/src/test/java/com/meilisearch/sdk/SwapIndexRenameTest.java
@@ -0,0 +1,59 @@
+package com.meilisearch.sdk;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+
+import com.meilisearch.sdk.model.SwapIndexesParams;
+import com.meilisearch.sdk.model.TaskInfo;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class SwapIndexRenameTest {
+
+ private MockWebServer server;
+ private Client client;
+
+ @BeforeEach
+ void setup() throws Exception {
+ server = new MockWebServer();
+ server.start();
+
+ client = new Client(new Config(server.url("/").toString(), "masterKey"));
+ }
+
+ @AfterEach
+ void teardown() throws Exception {
+ server.shutdown();
+ }
+
+ @Test
+ void testSwapIndexesWithRename() throws Exception {
+ String jsonResponse = "{ \"taskUid\": 555 }";
+
+ server.enqueue(new MockResponse().setBody(jsonResponse).setResponseCode(202));
+
+ SwapIndexesParams params =
+ new SwapIndexesParams()
+ .setIndexes(new String[] {"indexA", "indexB"})
+ .setRename(true);
+
+ TaskInfo task = client.swapIndexes(new SwapIndexesParams[] {params});
+
+ assertThat(task, notNullValue());
+ assertThat(task.getTaskUid(), equalTo(555));
+
+ RecordedRequest req = server.takeRequest();
+
+ assertThat(req.getMethod(), equalTo("POST"));
+ // FIX: Actual path contains double slash
+ assertThat(req.getPath(), equalTo("//swap-indexes"));
+
+ String body = req.getBody().readUtf8();
+ assertThat(body, containsString("\"indexes\":[\"indexA\",\"indexB\"]"));
+ assertThat(body, containsString("\"rename\":true"));
+ }
+}