diff --git a/src/main/java/io/weaviate/client/WeaviateClient.java b/src/main/java/io/weaviate/client/WeaviateClient.java index dcd9f3fed..c12a58fc5 100644 --- a/src/main/java/io/weaviate/client/WeaviateClient.java +++ b/src/main/java/io/weaviate/client/WeaviateClient.java @@ -8,6 +8,7 @@ import io.weaviate.client.base.util.DbVersionProvider; import io.weaviate.client.base.util.DbVersionSupport; import io.weaviate.client.base.util.GrpcVersionSupport; +import io.weaviate.client.v1.aliases.Aliases; import io.weaviate.client.v1.async.WeaviateAsyncClient; import io.weaviate.client.v1.auth.provider.AccessTokenProvider; import io.weaviate.client.v1.backup.Backup; @@ -111,6 +112,10 @@ public Users users() { return new Users(httpClient, config); } + public Aliases alias() { + return new Aliases(httpClient, config); + } + private DbVersionProvider initDbVersionProvider() { MetaGetter metaGetter = new Misc(httpClient, config, null).metaGetter(); DbVersionProvider.VersionGetter getter = () -> Optional.ofNullable(metaGetter.run()) diff --git a/src/main/java/io/weaviate/client/base/AsyncBaseClient.java b/src/main/java/io/weaviate/client/base/AsyncBaseClient.java index 2bc88b713..399afbf0f 100644 --- a/src/main/java/io/weaviate/client/base/AsyncBaseClient.java +++ b/src/main/java/io/weaviate/client/base/AsyncBaseClient.java @@ -1,11 +1,8 @@ package io.weaviate.client.base; -import io.weaviate.client.Config; -import io.weaviate.client.base.http.async.ResponseParser; -import io.weaviate.client.base.http.async.WeaviateResponseConsumer; -import io.weaviate.client.v1.auth.provider.AccessTokenProvider; import java.util.Map; import java.util.concurrent.Future; + import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; import org.apache.hc.client5.http.async.methods.SimpleRequestProducer; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; @@ -13,6 +10,11 @@ import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHeaders; +import io.weaviate.client.Config; +import io.weaviate.client.base.http.async.ResponseParser; +import io.weaviate.client.base.http.async.WeaviateResponseConsumer; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; + public abstract class AsyncBaseClient { protected final CloseableHttpAsyncClient client; private final Config config; @@ -30,39 +32,48 @@ protected Future> sendGetRequest(String endpoint, Class classOfT, F return sendRequest(endpoint, null, "GET", classOfT, callback, null); } - protected Future> sendGetRequest(String endpoint, FutureCallback> callback, ResponseParser parser) { + protected Future> sendGetRequest(String endpoint, FutureCallback> callback, + ResponseParser parser) { return sendRequest(endpoint, null, "GET", null, callback, parser); } - protected Future> sendPostRequest(String endpoint, Object payload, Class classOfT, FutureCallback> callback) { + protected Future> sendPostRequest(String endpoint, Object payload, Class classOfT, + FutureCallback> callback) { return sendRequest(endpoint, payload, "POST", classOfT, callback, null); } - protected Future> sendPostRequest(String endpoint, Object payload, FutureCallback> callback, ResponseParser parser) { + protected Future> sendPostRequest(String endpoint, Object payload, FutureCallback> callback, + ResponseParser parser) { return sendRequest(endpoint, payload, "POST", null, callback, parser); } - protected Future> sendPutRequest(String endpoint, Object payload, Class classOfT, FutureCallback> callback) { + protected Future> sendPutRequest(String endpoint, Object payload, Class classOfT, + FutureCallback> callback) { return sendRequest(endpoint, payload, "PUT", classOfT, callback, null); } - protected Future> sendPutRequest(String endpoint, Object payload, FutureCallback> callback, ResponseParser parser) { + protected Future> sendPutRequest(String endpoint, Object payload, FutureCallback> callback, + ResponseParser parser) { return sendRequest(endpoint, payload, "PUT", null, callback, parser); } - protected Future> sendPatchRequest(String endpoint, Object payload, Class classOfT, FutureCallback> callback) { + protected Future> sendPatchRequest(String endpoint, Object payload, Class classOfT, + FutureCallback> callback) { return sendRequest(endpoint, payload, "PATCH", classOfT, callback, null); } - protected Future> sendPatchRequest(String endpoint, Object payload, FutureCallback> callback, ResponseParser parser) { + protected Future> sendPatchRequest(String endpoint, Object payload, FutureCallback> callback, + ResponseParser parser) { return sendRequest(endpoint, payload, "PATCH", null, callback, parser); } - protected Future> sendDeleteRequest(String endpoint, Object payload, Class classOfT, FutureCallback> callback) { + protected Future> sendDeleteRequest(String endpoint, Object payload, Class classOfT, + FutureCallback> callback) { return sendRequest(endpoint, payload, "DELETE", classOfT, callback, null); } - protected Future> sendDeleteRequest(String endpoint, Object payload, FutureCallback> callback, ResponseParser parser) { + protected Future> sendDeleteRequest(String endpoint, Object payload, FutureCallback> callback, + ResponseParser parser) { return sendRequest(endpoint, payload, "DELETE", null, callback, parser); } @@ -70,12 +81,15 @@ protected Future> sendHeadRequest(String endpoint, Class classOfT, return sendRequest(endpoint, null, "HEAD", classOfT, callback, null); } - protected Future> sendHeadRequest(String endpoint, FutureCallback> callback, ResponseParser parser) { + protected Future> sendHeadRequest(String endpoint, FutureCallback> callback, + ResponseParser parser) { return sendRequest(endpoint, null, "HEAD", null, callback, parser); } - private Future> sendRequest(String endpoint, Object payload, String method, Class classOfT, FutureCallback> callback, ResponseParser parser) { - return client.execute(SimpleRequestProducer.create(getRequest(endpoint, payload, method)), new WeaviateResponseConsumer<>(classOfT, parser), callback); + private Future> sendRequest(String endpoint, Object payload, String method, Class classOfT, + FutureCallback> callback, ResponseParser parser) { + return client.execute(SimpleRequestProducer.create(getRequest(endpoint, payload, method)), + new WeaviateResponseConsumer<>(classOfT, parser), callback); } protected SimpleHttpRequest getRequest(String endpoint, Object payload, String method) { diff --git a/src/main/java/io/weaviate/client/v1/aliases/Aliases.java b/src/main/java/io/weaviate/client/v1/aliases/Aliases.java new file mode 100644 index 000000000..aac69243b --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/Aliases.java @@ -0,0 +1,39 @@ +package io.weaviate.client.v1.aliases; + +import io.weaviate.client.Config; +import io.weaviate.client.base.http.HttpClient; +import io.weaviate.client.v1.aliases.api.AliasAllGetter; +import io.weaviate.client.v1.aliases.api.AliasCreator; +import io.weaviate.client.v1.aliases.api.AliasDeleter; +import io.weaviate.client.v1.aliases.api.AliasGetter; +import io.weaviate.client.v1.aliases.api.AliasUpdater; + +public class Aliases { + private final Config config; + private final HttpClient httpClient; + + public Aliases(HttpClient httpClient, Config config) { + this.config = config; + this.httpClient = httpClient; + } + + public AliasCreator creator() { + return new AliasCreator(httpClient, config); + } + + public AliasGetter getter() { + return new AliasGetter(httpClient, config); + } + + public AliasAllGetter allGetter() { + return new AliasAllGetter(httpClient, config); + } + + public AliasDeleter deleter() { + return new AliasDeleter(httpClient, config); + } + + public AliasUpdater updater() { + return new AliasUpdater(httpClient, config); + } +} diff --git a/src/main/java/io/weaviate/client/v1/aliases/api/AliasAllGetter.java b/src/main/java/io/weaviate/client/v1/aliases/api/AliasAllGetter.java new file mode 100644 index 000000000..92d59652d --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/api/AliasAllGetter.java @@ -0,0 +1,45 @@ +package io.weaviate.client.v1.aliases.api; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import io.weaviate.client.Config; +import io.weaviate.client.base.BaseClient; +import io.weaviate.client.base.ClientResult; +import io.weaviate.client.base.Response; +import io.weaviate.client.base.Result; +import io.weaviate.client.base.http.HttpClient; +import io.weaviate.client.v1.aliases.api.AliasAllGetter.ResponseBody; +import io.weaviate.client.v1.aliases.model.Alias; + +public class AliasAllGetter extends BaseClient implements ClientResult> { + private String className; + + public AliasAllGetter(HttpClient httpClient, Config config) { + super(httpClient, config); + } + + /** List aliases defined for this class. */ + public AliasAllGetter withClassName(String className) { + this.className = className; + return this; + } + + static class ResponseBody { + List aliases; + } + + @Override + public Result> run() { + String path = "/aliases" + (className != null ? "?class=" + className : ""); + Response resp = sendGetRequest(path, ResponseBody.class); + if (resp.getErrors() != null) { + return new Result<>(resp, null); + } + Map aliases = resp.getBody().aliases.stream() + .collect(Collectors.toMap(Alias::getAlias, Function.identity())); + return new Result<>(resp, aliases); + } +} diff --git a/src/main/java/io/weaviate/client/v1/aliases/api/AliasCreator.java b/src/main/java/io/weaviate/client/v1/aliases/api/AliasCreator.java new file mode 100644 index 000000000..aa123c392 --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/api/AliasCreator.java @@ -0,0 +1,34 @@ +package io.weaviate.client.v1.aliases.api; + +import io.weaviate.client.Config; +import io.weaviate.client.base.BaseClient; +import io.weaviate.client.base.ClientResult; +import io.weaviate.client.base.Response; +import io.weaviate.client.base.Result; +import io.weaviate.client.base.http.HttpClient; +import io.weaviate.client.v1.aliases.model.Alias; + +public class AliasCreator extends BaseClient implements ClientResult { + private String className; + private String alias; + + public AliasCreator(HttpClient httpClient, Config config) { + super(httpClient, config); + } + + public AliasCreator withClassName(String className) { + this.className = className; + return this; + } + + public AliasCreator withAlias(String alias) { + this.alias = alias; + return this; + } + + @Override + public Result run() { + Response resp = sendPostRequest("/aliases", new Alias(className, alias), Void.class); + return Result.voidToBoolean(resp); + } +} diff --git a/src/main/java/io/weaviate/client/v1/aliases/api/AliasDeleter.java b/src/main/java/io/weaviate/client/v1/aliases/api/AliasDeleter.java new file mode 100644 index 000000000..0bed20b3b --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/api/AliasDeleter.java @@ -0,0 +1,27 @@ +package io.weaviate.client.v1.aliases.api; + +import io.weaviate.client.Config; +import io.weaviate.client.base.BaseClient; +import io.weaviate.client.base.ClientResult; +import io.weaviate.client.base.Response; +import io.weaviate.client.base.Result; +import io.weaviate.client.base.http.HttpClient; + +public class AliasDeleter extends BaseClient implements ClientResult { + private String alias; + + public AliasDeleter(HttpClient httpClient, Config config) { + super(httpClient, config); + } + + public AliasDeleter withAlias(String alias) { + this.alias = alias; + return this; + } + + @Override + public Result run() { + Response resp = sendDeleteRequest("/aliases/" + alias, null, Void.class); + return Result.voidToBoolean(resp); + } +} diff --git a/src/main/java/io/weaviate/client/v1/aliases/api/AliasGetter.java b/src/main/java/io/weaviate/client/v1/aliases/api/AliasGetter.java new file mode 100644 index 000000000..b3a8f9aca --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/api/AliasGetter.java @@ -0,0 +1,26 @@ +package io.weaviate.client.v1.aliases.api; + +import io.weaviate.client.Config; +import io.weaviate.client.base.BaseClient; +import io.weaviate.client.base.ClientResult; +import io.weaviate.client.base.Result; +import io.weaviate.client.base.http.HttpClient; +import io.weaviate.client.v1.aliases.model.Alias; + +public class AliasGetter extends BaseClient implements ClientResult { + private String alias; + + public AliasGetter(HttpClient httpClient, Config config) { + super(httpClient, config); + } + + public AliasGetter withAlias(String alias) { + this.alias = alias; + return this; + } + + @Override + public Result run() { + return new Result<>(sendGetRequest("/aliases/" + alias, Alias.class)); + } +} diff --git a/src/main/java/io/weaviate/client/v1/aliases/api/AliasUpdater.java b/src/main/java/io/weaviate/client/v1/aliases/api/AliasUpdater.java new file mode 100644 index 000000000..8eea4a90f --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/api/AliasUpdater.java @@ -0,0 +1,40 @@ +package io.weaviate.client.v1.aliases.api; + +import com.google.gson.annotations.SerializedName; + +import io.weaviate.client.Config; +import io.weaviate.client.base.BaseClient; +import io.weaviate.client.base.ClientResult; +import io.weaviate.client.base.Response; +import io.weaviate.client.base.Result; +import io.weaviate.client.base.http.HttpClient; + +public class AliasUpdater extends BaseClient implements ClientResult { + private String className; + private String alias; + + public AliasUpdater(HttpClient httpClient, Config config) { + super(httpClient, config); + } + + public AliasUpdater withAlias(String alias) { + this.alias = alias; + return this; + } + + public AliasUpdater withNewClassName(String className) { + this.className = className; + return this; + } + + class Body { + @SerializedName("class") + String className = AliasUpdater.this.className; + } + + @Override + public Result run() { + Response resp = sendPutRequest("/aliases/" + alias, new Body(), Void.class); + return Result.voidToBoolean(resp); + } +} diff --git a/src/main/java/io/weaviate/client/v1/aliases/model/Alias.java b/src/main/java/io/weaviate/client/v1/aliases/model/Alias.java new file mode 100644 index 000000000..b6c99816f --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/aliases/model/Alias.java @@ -0,0 +1,17 @@ +package io.weaviate.client.v1.aliases.model; + +import com.google.gson.annotations.SerializedName; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +@EqualsAndHashCode +public class Alias { + @SerializedName("class") + private final String className; + @SerializedName("alias") + private final String alias; +} diff --git a/src/main/java/io/weaviate/client/v1/async/WeaviateAsyncClient.java b/src/main/java/io/weaviate/client/v1/async/WeaviateAsyncClient.java index c19826587..b8a31f94e 100644 --- a/src/main/java/io/weaviate/client/v1/async/WeaviateAsyncClient.java +++ b/src/main/java/io/weaviate/client/v1/async/WeaviateAsyncClient.java @@ -12,6 +12,7 @@ import io.weaviate.client.base.util.DbVersionProvider; import io.weaviate.client.base.util.DbVersionSupport; import io.weaviate.client.base.util.GrpcVersionSupport; +import io.weaviate.client.v1.async.aliases.Aliases; import io.weaviate.client.v1.async.backup.Backup; import io.weaviate.client.v1.async.batch.Batch; import io.weaviate.client.v1.async.classifications.Classifications; @@ -84,6 +85,10 @@ public Users users() { return new Users(client, config, tokenProvider); } + public Aliases alias() { + return new Aliases(client, config, tokenProvider); + } + private DbVersionProvider initDbVersionProvider() { DbVersionProvider.VersionGetter getter = () -> Optional.ofNullable(this.getMeta()) .filter(result -> !result.hasErrors()) diff --git a/src/main/java/io/weaviate/client/v1/async/aliases/Aliases.java b/src/main/java/io/weaviate/client/v1/async/aliases/Aliases.java new file mode 100644 index 000000000..ee56fc2b6 --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/async/aliases/Aliases.java @@ -0,0 +1,39 @@ +package io.weaviate.client.v1.async.aliases; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; + +import io.weaviate.client.Config; +import io.weaviate.client.v1.async.aliases.api.AliasAllGetter; +import io.weaviate.client.v1.async.aliases.api.AliasCreator; +import io.weaviate.client.v1.async.aliases.api.AliasDeleter; +import io.weaviate.client.v1.async.aliases.api.AliasGetter; +import io.weaviate.client.v1.async.aliases.api.AliasUpdater; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class Aliases { + private final CloseableHttpAsyncClient client; + private final Config config; + private final AccessTokenProvider tokenProvider; + + public AliasCreator creator() { + return new AliasCreator(client, config, tokenProvider); + } + + public AliasGetter getter() { + return new AliasGetter(client, config, tokenProvider); + } + + public AliasAllGetter allGetter() { + return new AliasAllGetter(client, config, tokenProvider); + } + + public AliasDeleter deleter() { + return new AliasDeleter(client, config, tokenProvider); + } + + public AliasUpdater updater() { + return new AliasUpdater(client, config, tokenProvider); + } +} diff --git a/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasAllGetter.java b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasAllGetter.java new file mode 100644 index 000000000..76abe57f6 --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasAllGetter.java @@ -0,0 +1,58 @@ +package io.weaviate.client.v1.async.aliases.api; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpResponse; + +import io.weaviate.client.Config; +import io.weaviate.client.base.AsyncBaseClient; +import io.weaviate.client.base.AsyncClientResult; +import io.weaviate.client.base.Response; +import io.weaviate.client.base.Result; +import io.weaviate.client.base.http.async.ResponseParser; +import io.weaviate.client.v1.aliases.model.Alias; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; + +public class AliasAllGetter extends AsyncBaseClient> + implements AsyncClientResult> { + private String className; + + public AliasAllGetter(CloseableHttpAsyncClient httpClient, Config config, AccessTokenProvider tokenProvider) { + super(httpClient, config, tokenProvider); + } + + /** List aliases defined for this class. */ + public AliasAllGetter withClassName(String className) { + this.className = className; + return this; + } + + @Override + public Future>> run(FutureCallback>> callback) { + String path = "/aliases" + (className != null ? "?class=" + className : ""); + return sendGetRequest(path, callback, new ResponseParser>() { + + class ResponseBody { + List aliases; + } + + @Override + public Result> parse(HttpResponse response, String body, ContentType contentType) { + Response resp = serializer.toResponse(response.getCode(), body, ResponseBody.class); + if (resp.getErrors() != null) { + return new Result<>(resp, null); + } + Map aliases = resp.getBody().aliases.stream() + .collect(Collectors.toMap(Alias::getAlias, Function.identity())); + return new Result<>(resp, aliases); + } + }); + } +} diff --git a/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasCreator.java b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasCreator.java new file mode 100644 index 000000000..cbfa5d4a4 --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasCreator.java @@ -0,0 +1,38 @@ +package io.weaviate.client.v1.async.aliases.api; + +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.concurrent.FutureCallback; + +import io.weaviate.client.Config; +import io.weaviate.client.base.AsyncBaseClient; +import io.weaviate.client.base.AsyncClientResult; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.aliases.model.Alias; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; + +public class AliasCreator extends AsyncBaseClient implements AsyncClientResult { + private String className; + private String alias; + + public AliasCreator(CloseableHttpAsyncClient httpClient, Config config, AccessTokenProvider tokenProvider) { + super(httpClient, config, tokenProvider); + } + + public AliasCreator withClassName(String className) { + this.className = className; + return this; + } + + public AliasCreator withAlias(String alias) { + this.alias = alias; + return this; + } + + @Override + public Future> run(FutureCallback> callback) { + return sendPostRequest("/aliases", new Alias(className, alias), + callback, Result.voidToBooleanParser()); + } +} diff --git a/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasDeleter.java b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasDeleter.java new file mode 100644 index 000000000..0180e5add --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasDeleter.java @@ -0,0 +1,31 @@ +package io.weaviate.client.v1.async.aliases.api; + +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.concurrent.FutureCallback; + +import io.weaviate.client.Config; +import io.weaviate.client.base.AsyncBaseClient; +import io.weaviate.client.base.AsyncClientResult; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; + +public class AliasDeleter extends AsyncBaseClient implements AsyncClientResult { + private String alias; + + public AliasDeleter(CloseableHttpAsyncClient httpClient, Config config, AccessTokenProvider tokenProvider) { + super(httpClient, config, tokenProvider); + } + + public AliasDeleter withAlias(String alias) { + this.alias = alias; + return this; + } + + @Override + public Future> run(FutureCallback> callback) { + return sendDeleteRequest("/aliases/" + alias, null, + callback, Result.voidToBooleanParser()); + } +} diff --git a/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasGetter.java b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasGetter.java new file mode 100644 index 000000000..bc06fd843 --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasGetter.java @@ -0,0 +1,31 @@ +package io.weaviate.client.v1.async.aliases.api; + +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.concurrent.FutureCallback; + +import io.weaviate.client.Config; +import io.weaviate.client.base.AsyncBaseClient; +import io.weaviate.client.base.AsyncClientResult; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.aliases.model.Alias; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; + +public class AliasGetter extends AsyncBaseClient implements AsyncClientResult { + private String alias; + + public AliasGetter(CloseableHttpAsyncClient httpClient, Config config, AccessTokenProvider tokenProvider) { + super(httpClient, config, tokenProvider); + } + + public AliasGetter withAlias(String alias) { + this.alias = alias; + return this; + } + + @Override + public Future> run(FutureCallback> callback) { + return sendGetRequest("/aliases/" + alias, Alias.class, callback); + } +} diff --git a/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasUpdater.java b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasUpdater.java new file mode 100644 index 000000000..06e373e43 --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/async/aliases/api/AliasUpdater.java @@ -0,0 +1,44 @@ +package io.weaviate.client.v1.async.aliases.api; + +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.core5.concurrent.FutureCallback; + +import com.google.gson.annotations.SerializedName; + +import io.weaviate.client.Config; +import io.weaviate.client.base.AsyncBaseClient; +import io.weaviate.client.base.AsyncClientResult; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.auth.provider.AccessTokenProvider; + +public class AliasUpdater extends AsyncBaseClient implements AsyncClientResult { + private String className; + private String alias; + + public AliasUpdater(CloseableHttpAsyncClient httpClient, Config config, AccessTokenProvider tokenProvider) { + super(httpClient, config, tokenProvider); + } + + public AliasUpdater withAlias(String alias) { + this.alias = alias; + return this; + } + + public AliasUpdater withNewClassName(String className) { + this.className = className; + return this; + } + + class Body { + @SerializedName("class") + String className = AliasUpdater.this.className; + } + + @Override + public Future> run(FutureCallback> callback) { + return sendPutRequest("/aliases/" + alias, new Body(), + callback, Result.voidToBooleanParser()); + } +} diff --git a/src/main/java/io/weaviate/client/v1/rbac/api/WeaviatePermission.java b/src/main/java/io/weaviate/client/v1/rbac/api/WeaviatePermission.java index 976f1da91..b4cf28317 100644 --- a/src/main/java/io/weaviate/client/v1/rbac/api/WeaviatePermission.java +++ b/src/main/java/io/weaviate/client/v1/rbac/api/WeaviatePermission.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; +import io.weaviate.client.v1.rbac.model.AliasPermission; import io.weaviate.client.v1.rbac.model.BackupsPermission; import io.weaviate.client.v1.rbac.model.CollectionsPermission; import io.weaviate.client.v1.rbac.model.DataPermission; @@ -25,6 +26,7 @@ @ToString public class WeaviatePermission { String action; + AliasPermission aliases; BackupsPermission backups; CollectionsPermission collections; DataPermission data; @@ -39,7 +41,9 @@ public WeaviatePermission(String action) { public

> WeaviatePermission(String action, Permission

perm) { this.action = action; - if (perm instanceof BackupsPermission) { + if (perm instanceof AliasPermission) { + this.aliases = (AliasPermission) perm; + } else if (perm instanceof BackupsPermission) { this.backups = (BackupsPermission) perm; } else if (perm instanceof CollectionsPermission) { this.collections = (CollectionsPermission) perm; diff --git a/src/main/java/io/weaviate/client/v1/rbac/model/AliasPermission.java b/src/main/java/io/weaviate/client/v1/rbac/model/AliasPermission.java new file mode 100644 index 000000000..99e7f4a8c --- /dev/null +++ b/src/main/java/io/weaviate/client/v1/rbac/model/AliasPermission.java @@ -0,0 +1,31 @@ +package io.weaviate.client.v1.rbac.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Getter +@EqualsAndHashCode(callSuper = true) +public class AliasPermission extends Permission { + final String alias; + + public AliasPermission(String alias, Action... actions) { + super(actions); + this.alias = alias; + } + + AliasPermission(String alias, String action) { + this(alias, RbacAction.fromString(Action.class, action)); + } + + @AllArgsConstructor + public enum Action implements RbacAction { + CREATE("create_aliases"), + READ("read_aliases"), + UPDATE("update_aliases"), + DELETE("delete_aliases"); + + @Getter + private final String value; + } +} diff --git a/src/main/java/io/weaviate/client/v1/rbac/model/Permission.java b/src/main/java/io/weaviate/client/v1/rbac/model/Permission.java index 769cbf6b0..70976837e 100644 --- a/src/main/java/io/weaviate/client/v1/rbac/model/Permission.java +++ b/src/main/java/io/weaviate/client/v1/rbac/model/Permission.java @@ -66,7 +66,9 @@ private WeaviatePermission toWeaviate(String action) { */ public static Permission fromWeaviate(WeaviatePermission perm) { String action = perm.getAction(); - if (perm.getBackups() != null) { + if (perm.getAliases() != null) { + return new AliasPermission(perm.getAliases().getAlias(), action); + } else if (perm.getBackups() != null) { return new BackupsPermission(perm.getBackups().getCollection(), action); } else if (perm.getCollections() != null) { return new CollectionsPermission(perm.getCollections().getCollection(), action); @@ -126,11 +128,22 @@ private Key(Object object) { return result.values().stream().collect(Collectors.toList()); } + /** + * Create {@link AliasPermission} for an alias. + *

+ * Example: + * {@code Permission.alias("PizzaAlias", AliasPermission.Action.CREATE) } + */ + public static AliasPermission alias(String alias, AliasPermission.Action... actions) { + checkDeprecation(actions); + return new AliasPermission(alias, actions); + } + /** * Create {@link BackupsPermission} for a collection. *

* Example: - * {@code Permission.backups(BackupsPermission.Action.MANAGE, "Pizza") } + * {@code Permission.backups("Pizza", BackupsPermission.Action.MANAGE) } */ public static BackupsPermission backups(String collection, BackupsPermission.Action... actions) { checkDeprecation(actions); @@ -140,7 +153,7 @@ public static BackupsPermission backups(String collection, BackupsPermission.Act /** * Create {@link ClusterPermission} permission. *

- * Example: {@code Permission.cluster(ClusterPermission.Action.READ, "Pizza") } + * Example: {@code Permission.cluster(ClusterPermission.Action.READ) } */ public static ClusterPermission cluster(ClusterPermission.Action... actions) { checkDeprecation(actions); diff --git a/src/test/java/io/weaviate/client/v1/rbac/api/WeaviatePermissionTest.java b/src/test/java/io/weaviate/client/v1/rbac/api/WeaviatePermissionTest.java index 8fc41d604..344b6992b 100644 --- a/src/test/java/io/weaviate/client/v1/rbac/api/WeaviatePermissionTest.java +++ b/src/test/java/io/weaviate/client/v1/rbac/api/WeaviatePermissionTest.java @@ -6,6 +6,7 @@ import org.junit.Test; +import io.weaviate.client.v1.rbac.model.AliasPermission; import io.weaviate.client.v1.rbac.model.BackupsPermission; import io.weaviate.client.v1.rbac.model.ClusterPermission; import io.weaviate.client.v1.rbac.model.CollectionsPermission; @@ -26,6 +27,10 @@ public class WeaviatePermissionTest { @Test public void testMergedPermissions() { WeaviatePermission[] apiPermissions = { + // Create and delete PizzaAlias alias + new WeaviatePermission("create_aliases", new AliasPermission("PizzaAlias")), + new WeaviatePermission("delete_aliases", new AliasPermission("PizzaAlias")), + // Manage Pizza backups new WeaviatePermission("manage_backups", new BackupsPermission("Pizza")), @@ -70,6 +75,7 @@ public void testMergedPermissions() { }; Permission[] libraryPermissions = { + new AliasPermission("PizzaAlias", AliasPermission.Action.CREATE, AliasPermission.Action.DELETE), new BackupsPermission("Pizza", BackupsPermission.Action.MANAGE), new DataPermission("Pizza", DataPermission.Action.MANAGE, DataPermission.Action.READ), new DataPermission("Songs", DataPermission.Action.UPDATE, DataPermission.Action.DELETE), diff --git a/src/test/java/io/weaviate/client/v1/rbac/model/PermissionTest.java b/src/test/java/io/weaviate/client/v1/rbac/model/PermissionTest.java index 1d1f3689e..62320a328 100644 --- a/src/test/java/io/weaviate/client/v1/rbac/model/PermissionTest.java +++ b/src/test/java/io/weaviate/client/v1/rbac/model/PermissionTest.java @@ -23,6 +23,7 @@ @RunWith(JParamsTestRunner.class) public class PermissionTest { public static Object[][] serializationTestCases() { + AliasPermission alias = new AliasPermission("PizzaAlias", AliasPermission.Action.CREATE); BackupsPermission backups = new BackupsPermission("Pizza", BackupsPermission.Action.MANAGE); DataPermission data = new DataPermission("Pizza", DataPermission.Action.MANAGE); NodesPermission nodes = new NodesPermission("Pizza", NodesPermission.Action.READ); @@ -33,6 +34,11 @@ public static Object[][] serializationTestCases() { UsersPermission users = new UsersPermission(UsersPermission.Action.READ); return new Object[][] { + { + "alias permission", + (Supplier>) () -> alias, + new WeaviatePermission("create_aliases", alias), + }, { "backup permission", (Supplier>) () -> backups, diff --git a/src/test/java/io/weaviate/integration/client/aliases/ClientAliasesTest.java b/src/test/java/io/weaviate/integration/client/aliases/ClientAliasesTest.java new file mode 100644 index 000000000..83f0f96d2 --- /dev/null +++ b/src/test/java/io/weaviate/integration/client/aliases/ClientAliasesTest.java @@ -0,0 +1,92 @@ +package io.weaviate.integration.client.aliases; + +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.assertj.core.api.Assertions; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; + +import io.weaviate.client.Config; +import io.weaviate.client.WeaviateClient; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.aliases.model.Alias; +import io.weaviate.client.v1.schema.model.WeaviateClass; +import io.weaviate.integration.client.WeaviateDockerCompose; + +public class ClientAliasesTest { + private WeaviateClient client; + + @ClassRule + public static WeaviateDockerCompose compose = new WeaviateDockerCompose(); + + @Before + public void before() { + Config config = new Config("http", compose.getHttpHostAddress()); + client = new WeaviateClient(config); + } + + @Test + public void shouldManageAliases() { + // Arrange + Result createdPaul = client.schema().classCreator().withClass(WeaviateClass.builder() + .className("PaulHewson").build()).run(); + assumeTrue(createdPaul.getResult(), "created PaulHewson collection"); + + Result createdGeorge = client.schema().classCreator().withClass(WeaviateClass.builder() + .className("GeorgeBarnes").build()).run(); + assumeTrue(createdGeorge.getResult(), "created GeorgeBarnes collection"); + + // Act: create alias + client.alias().creator().withClassName("PaulHewson").withAlias("Bono").run(); + client.alias().creator().withClassName("GeorgeBarnes").withAlias("MachineGunKelly").run(); + + // Assert: get all + Result> all = client.alias().allGetter().run(); + + Assertions.assertThat(all.getError()).isNull(); + Assertions.assertThat(all.getResult()) + .as("fetched all aliases") + .containsAllEntriesOf(new HashMap() { + { + put("Bono", new Alias("PaulHewson", "Bono")); + put("MachineGunKelly", new Alias("GeorgeBarnes", "MachineGunKelly")); + } + }); + + // Act: update + Result createdMGK = client.schema().classCreator().withClass(WeaviateClass.builder() + .className("ColsonBaker").build()).run(); + assumeTrue(createdMGK.getResult(), "created ColsonBaker collection"); + + client.alias().updater().withAlias("MachineGunKelly").withNewClassName("ColsonBaker").run(); + + // Assert: get one + Result mgk = client.alias().getter().withAlias("MachineGunKelly").run(); + + Assertions.assertThat(mgk.getResult()) + .as("MachineGunKelly alias points to ColsonBaker") + .returns("MachineGunKelly", Alias::getAlias) + .returns("ColsonBaker", Alias::getClassName); + + Result> colsonAliases = client.alias().allGetter().withClassName("ColsonBaker").run(); + Assertions.assertThat(colsonAliases.getResult()) + .containsOnlyKeys("MachineGunKelly") + .extracting(Map::values, InstanceOfAssertFactories.collection(Alias.class)) + .extracting(Alias::getClassName).containsOnly("ColsonBaker"); + + // Act: delete + client.alias().deleter().withAlias("Bono").run(); + + // Assert + Result bono = client.alias().getter().withAlias("Bono").run(); + Assertions.assertThat(bono) + .as("Bono alias deleted") + .returns(null, Result::getResult) + .extracting(Result::getError).isNull(); + } +} diff --git a/src/test/java/io/weaviate/integration/client/async/aliases/ClientAliasesTest.java b/src/test/java/io/weaviate/integration/client/async/aliases/ClientAliasesTest.java new file mode 100644 index 000000000..9a071151a --- /dev/null +++ b/src/test/java/io/weaviate/integration/client/async/aliases/ClientAliasesTest.java @@ -0,0 +1,100 @@ +package io.weaviate.integration.client.async.aliases; + +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.assertj.core.api.Assertions; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; + +import io.weaviate.client.Config; +import io.weaviate.client.WeaviateClient; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.aliases.model.Alias; +import io.weaviate.client.v1.async.WeaviateAsyncClient; +import io.weaviate.client.v1.schema.model.WeaviateClass; +import io.weaviate.integration.client.WeaviateDockerCompose; + +public class ClientAliasesTest { + private WeaviateAsyncClient client; + + @ClassRule + public static WeaviateDockerCompose compose = new WeaviateDockerCompose(); + + @Before + public void before() { + Config config = new Config("http", compose.getHttpHostAddress()); + client = new WeaviateClient(config).async(); + } + + @After + public void after() { + client.close(); + } + + @Test + public void shouldManageAliases() throws InterruptedException, ExecutionException { + // Arrange + Result createdPaul = client.schema().classCreator().withClass(WeaviateClass.builder() + .className("PaulHewson").build()).run().get(); + assumeTrue(createdPaul.getResult(), "created PaulHewson collection"); + + Result createdGeorge = client.schema().classCreator().withClass(WeaviateClass.builder() + .className("GeorgeBarnes").build()).run().get(); + assumeTrue(createdGeorge.getResult(), "created GeorgeBarnes collection"); + + // Act: create alias + client.alias().creator().withClassName("PaulHewson").withAlias("Bono").run().get(); + client.alias().creator().withClassName("GeorgeBarnes").withAlias("MachineGunKelly").run().get(); + + // Assert: get all + Result> all = client.alias().allGetter().run().get(); + + Assertions.assertThat(all.getError()).isNull(); + Assertions.assertThat(all.getResult()) + .as("fetched all aliases") + .containsAllEntriesOf(new HashMap() { + { + put("Bono", new Alias("PaulHewson", "Bono")); + put("MachineGunKelly", new Alias("GeorgeBarnes", "MachineGunKelly")); + } + }); + + // Act: update + Result createdMGK = client.schema().classCreator().withClass(WeaviateClass.builder() + .className("ColsonBaker").build()).run().get(); + assumeTrue(createdMGK.getResult(), "created ColsonBaker collection"); + + client.alias().updater().withAlias("MachineGunKelly").withNewClassName("ColsonBaker").run().get(); + + // Assert: get one + Result mgk = client.alias().getter().withAlias("MachineGunKelly").run().get(); + + Assertions.assertThat(mgk.getResult()) + .as("MachineGunKelly alias points to ColsonBaker") + .returns("MachineGunKelly", Alias::getAlias) + .returns("ColsonBaker", Alias::getClassName); + + Result> colsonAliases = client.alias().allGetter().withClassName("ColsonBaker").run().get(); + Assertions.assertThat(colsonAliases.getResult()) + .containsOnlyKeys("MachineGunKelly") + .extracting(Map::values, InstanceOfAssertFactories.collection(Alias.class)) + .extracting(Alias::getClassName).containsOnly("ColsonBaker"); + + // Act: delete + client.alias().deleter().withAlias("Bono").run().get(); + + // Assert + Result bono = client.alias().getter().withAlias("Bono").run().get(); + Assertions.assertThat(bono) + .as("Bono alias deleted") + .returns(null, Result::getResult) + .extracting(Result::getError).isNull(); + } +} diff --git a/src/test/java/io/weaviate/integration/tests/rbac/ClientRbacTestSuite.java b/src/test/java/io/weaviate/integration/tests/rbac/ClientRbacTestSuite.java index 651df45b2..b61f5c199 100644 --- a/src/test/java/io/weaviate/integration/tests/rbac/ClientRbacTestSuite.java +++ b/src/test/java/io/weaviate/integration/tests/rbac/ClientRbacTestSuite.java @@ -24,6 +24,7 @@ import io.weaviate.client.Config; import io.weaviate.client.base.Result; +import io.weaviate.client.v1.rbac.model.AliasPermission; import io.weaviate.client.v1.rbac.model.BackupsPermission; import io.weaviate.client.v1.rbac.model.ClusterPermission; import io.weaviate.client.v1.rbac.model.CollectionsPermission; @@ -133,8 +134,10 @@ public void testCreate(String _name, Supplier rbac) { Rbac roles = rbac.get(); String myRole = roleName("VectorOwner"); String myCollection = "Pizza"; + String myCollectionAlias = "PizzaAlias"; Permission[] wantPermissions = new Permission[] { + Permission.alias(myCollectionAlias, AliasPermission.Action.CREATE), Permission.backups(myCollection, BackupsPermission.Action.MANAGE), Permission.cluster(ClusterPermission.Action.READ), Permission.nodes(myCollection, NodesPermission.Action.READ),