diff --git a/src/it/java/io/weaviate/integration/BackupITest.java b/src/it/java/io/weaviate/integration/BackupITest.java index 67a7bcdf2..bf0997930 100644 --- a/src/it/java/io/weaviate/integration/BackupITest.java +++ b/src/it/java/io/weaviate/integration/BackupITest.java @@ -103,10 +103,10 @@ public void test_lifecycle() throws IOException, TimeoutException { .returns(BackupStatus.CANCELED, Backup::status); // Assert: all 3 backups are present - var all = client.backup.list(backend); + var all = client.backup.list(backend, bu -> bu.sortByStartingTimeAsc(true)); Assertions.assertThat(all).as("all backups") .extracting(Backup::id) - .contains(backup_1, backup_2, backup_3); + .containsExactly(backup_1, backup_2, backup_3); // Act: delete data and restore backup #1 client.collections.delete(nsA); @@ -225,8 +225,8 @@ public void test_lifecycle_async() throws ExecutionException, InterruptedExcepti @Test(expected = IllegalStateException.class) public void test_waitForCompletion_unknown() throws IOException, TimeoutException { - var backup = new Backup("#1", "/tmp/bak/#1", "filesystem", List.of("Things"), BackupStatus.STARTED, null, - null); + var backup = new Backup("#1", "/tmp/bak/#1", "filesystem", List.of("Things"), BackupStatus.STARTED, + null, null, null, null, null); backup.waitForCompletion(client); } diff --git a/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java b/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java index 3f0a7a229..066fe2e08 100644 --- a/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java +++ b/src/main/java/io/weaviate/client6/v1/api/backup/Backup.java @@ -1,6 +1,7 @@ package io.weaviate.client6.v1.api.backup; import java.io.IOException; +import java.time.OffsetDateTime; import java.util.List; import java.util.Optional; import java.util.concurrent.Callable; @@ -28,6 +29,12 @@ public record Backup( @SerializedName("status") BackupStatus status, /** Backup creation / restoration error. */ @SerializedName("error") String error, + /** Time at which the backup creation. */ + @SerializedName("startedAt") OffsetDateTime startedAt, + /** Time at which the backup was completed, successfully or otherwise. */ + @SerializedName("completedAt") OffsetDateTime completedAt, + /** Backup size in GiB. */ + @SerializedName("size") Integer sizeGiB, /** * This value indicates if a backup is being created or restored from. * For operations like LIST this value is null. @@ -37,8 +44,18 @@ public record Backup( @SerializedName("__operation__") Operation operation) { /** Set operation associated with this backup. */ - public Backup withOperation(Operation operation) { - return new Backup(id, path, backend, includesCollections, status, error, operation); + Backup withOperation(Operation operation) { + return new Backup( + id, + path, + backend, + includesCollections, + status, + error, + startedAt, + completedAt, + sizeGiB, + operation); } public enum Operation { diff --git a/src/main/java/io/weaviate/client6/v1/api/backup/ListBackupsRequest.java b/src/main/java/io/weaviate/client6/v1/api/backup/ListBackupsRequest.java index ea3e497a2..19d8e406d 100644 --- a/src/main/java/io/weaviate/client6/v1/api/backup/ListBackupsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/backup/ListBackupsRequest.java @@ -1,21 +1,61 @@ package io.weaviate.client6.v1.api.backup; -import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.function.Function; import com.google.gson.reflect.TypeToken; +import io.weaviate.client6.v1.internal.ObjectBuilder; import io.weaviate.client6.v1.internal.json.JSON; import io.weaviate.client6.v1.internal.rest.Endpoint; import io.weaviate.client6.v1.internal.rest.SimpleEndpoint; -public record ListBackupsRequest(String backend) { +public record ListBackupsRequest(String backend, boolean startingTimeAsc) { @SuppressWarnings("unchecked") public static Endpoint> _ENDPOINT = SimpleEndpoint.noBody( request -> "GET", request -> "/backups/" + request.backend, - request -> Collections.emptyMap(), + request -> new HashMap<>() { + { + if (request.startingTimeAsc) { + put("order", "asc"); + } + } + }, (statusCode, response) -> (List) JSON.deserialize( response, TypeToken.getParameterized(List.class, Backup.class))); + + public static ListBackupsRequest of(String backend) { + return of(backend, ObjectBuilder.identity()); + } + + public static ListBackupsRequest of(String backend, Function> fn) { + return fn.apply(new Builder(backend)).build(); + } + + public ListBackupsRequest(Builder builder) { + this(builder.backend, builder.startingTimeAsc); + } + + public static class Builder implements ObjectBuilder { + private final String backend; + private boolean startingTimeAsc = false; + + public Builder(String backend) { + this.backend = backend; + } + + /** Sort the backups by their starting time, oldest to newest. */ + public Builder sortByStartingTimeAsc(boolean enable) { + this.startingTimeAsc = enable; + return this; + } + + @Override + public ListBackupsRequest build() { + return new ListBackupsRequest(this); + } + } } diff --git a/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClient.java b/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClient.java index e2235d4ce..90bf70b8a 100644 --- a/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClient.java @@ -157,7 +157,23 @@ public Optional getRestoreStatus(String backupId, String backend) throws * or the server being unavailable. */ public List list(String backend) throws IOException { - return this.restTransport.performRequest(new ListBackupsRequest(backend), ListBackupsRequest._ENDPOINT); + return this.restTransport.performRequest(ListBackupsRequest.of(backend), ListBackupsRequest._ENDPOINT); + } + + /** + * List backups in the backend storage. + * + * @param backend Backup storage backend. + * @param fn Lambda expression for optional parameters. + * @throws WeaviateApiException in case the server returned with an + * error status code. + * @throws IOException in case the request was not sent successfully + * due to a malformed request, a networking error + * or the server being unavailable. + */ + public List list(String backend, Function> fn) + throws IOException { + return this.restTransport.performRequest(ListBackupsRequest.of(backend, fn), ListBackupsRequest._ENDPOINT); } /** diff --git a/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClientAsync.java index 02e372810..e0eab8863 100644 --- a/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/backup/WeaviateBackupClientAsync.java @@ -109,7 +109,18 @@ public CompletableFuture> getRestoreStatus(String backupId, Str * @param backend Backup storage backend. */ public CompletableFuture> list(String backend) { - return this.restTransport.performRequestAsync(new ListBackupsRequest(backend), ListBackupsRequest._ENDPOINT); + return this.restTransport.performRequestAsync(ListBackupsRequest.of(backend), ListBackupsRequest._ENDPOINT); + } + + /** + * List backups in the backend storage. + * + * @param backend Backup storage backend. + * @param fn Lambda expression for optional parameters. + */ + public CompletableFuture> list(String backend, + Function> fn) { + return this.restTransport.performRequestAsync(ListBackupsRequest.of(backend, fn), ListBackupsRequest._ENDPOINT); } /** diff --git a/src/main/java/io/weaviate/client6/v1/internal/rest/UrlEncoder.java b/src/main/java/io/weaviate/client6/v1/internal/rest/UrlEncoder.java index 2b53f1c83..f78e94b6d 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/rest/UrlEncoder.java +++ b/src/main/java/io/weaviate/client6/v1/internal/rest/UrlEncoder.java @@ -33,7 +33,9 @@ public static String encodeQuery(Map queryParams) { if (qp == null) { return false; } - if (qp.getValue() instanceof String str) { + if (qp.getValue() == null) { + return false; + } else if (qp.getValue() instanceof String str) { return !str.isBlank(); } return true;