com.couchbase.client.java.manager.analytics.AsyncAnalyticsIndexManager Maven / Gradle / Ivy
Show all versions of java-client Show documentation
/*
* Copyright 2019 Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.couchbase.client.java.manager.analytics;
import com.couchbase.client.core.Core;
import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.cnc.CbTracing;
import com.couchbase.client.core.cnc.RequestSpan;
import com.couchbase.client.core.cnc.TracingIdentifiers;
import com.couchbase.client.core.deps.com.fasterxml.jackson.core.type.TypeReference;
import com.couchbase.client.core.endpoint.http.CoreHttpClient;
import com.couchbase.client.core.error.AuthenticationFailureException;
import com.couchbase.client.core.error.CompilationFailureException;
import com.couchbase.client.core.error.CouchbaseException;
import com.couchbase.client.core.error.DatasetExistsException;
import com.couchbase.client.core.error.DatasetNotFoundException;
import com.couchbase.client.core.error.DataverseExistsException;
import com.couchbase.client.core.error.DataverseNotFoundException;
import com.couchbase.client.core.error.IndexExistsException;
import com.couchbase.client.core.error.IndexNotFoundException;
import com.couchbase.client.core.error.InvalidArgumentException;
import com.couchbase.client.core.error.LinkExistsException;
import com.couchbase.client.core.error.LinkNotFoundException;
import com.couchbase.client.core.json.Mapper;
import com.couchbase.client.core.manager.CoreAnalyticsLinkManager;
import com.couchbase.client.core.msg.RequestTarget;
import com.couchbase.client.java.AsyncCluster;
import com.couchbase.client.java.CommonOptions;
import com.couchbase.client.java.analytics.AnalyticsOptions;
import com.couchbase.client.java.analytics.AnalyticsResult;
import com.couchbase.client.java.manager.analytics.link.AnalyticsLink;
import com.couchbase.client.java.manager.analytics.link.AnalyticsLinkType;
import com.couchbase.client.java.manager.analytics.link.CouchbaseRemoteAnalyticsLink;
import com.couchbase.client.java.manager.analytics.link.S3ExternalAnalyticsLink;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import static com.couchbase.client.core.endpoint.http.CoreHttpPath.path;
import static com.couchbase.client.core.logging.RedactableArgument.redactMeta;
import static com.couchbase.client.core.util.Validators.notNull;
import static com.couchbase.client.core.util.Validators.notNullOrEmpty;
import static com.couchbase.client.java.analytics.AnalyticsOptions.analyticsOptions;
import static com.couchbase.client.java.manager.analytics.ConnectLinkAnalyticsOptions.connectLinkAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.CreateDatasetAnalyticsOptions.createDatasetAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.CreateDataverseAnalyticsOptions.createDataverseAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.CreateIndexAnalyticsOptions.createIndexAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.CreateLinkAnalyticsOptions.createLinkAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.DisconnectLinkAnalyticsOptions.disconnectLinkAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.DropDatasetAnalyticsOptions.dropDatasetAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.DropDataverseAnalyticsOptions.dropDataverseAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.DropIndexAnalyticsOptions.dropIndexAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.DropLinkAnalyticsOptions.dropLinkAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.GetAllDatasetsAnalyticsOptions.getAllDatasetsAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.GetAllDataversesAnalyticsOptions.getAllDataversesAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.GetAllIndexesAnalyticsOptions.getAllIndexesAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.GetLinksAnalyticsOptions.getLinksAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.GetPendingMutationsAnalyticsOptions.getPendingMutationsAnalyticsOptions;
import static com.couchbase.client.java.manager.analytics.ReplaceLinkAnalyticsOptions.replaceLinkAnalyticsOptions;
import static java.util.Collections.singletonMap;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
/**
* Performs management operations on analytics indexes.
*/
public class AsyncAnalyticsIndexManager {
private final AsyncCluster cluster;
private final Core core;
private final CoreHttpClient httpClient;
private final CoreAnalyticsLinkManager linkManager;
private static final String DEFAULT_DATAVERSE = "Default";
private static final String DEFAULT_LINK = "Local";
/**
* Creates a new {@link AsyncAnalyticsIndexManager}.
*
* This API is not intended to be called by the user directly, use {@link AsyncCluster#analyticsIndexes()}
* instead.
*
* @param cluster the async cluster to perform the analytics queries on.
*/
@Stability.Internal
public AsyncAnalyticsIndexManager(final AsyncCluster cluster) {
this.cluster = requireNonNull(cluster);
this.core = cluster.core();
this.httpClient = core.httpClient(RequestTarget.analytics());
this.linkManager = new CoreAnalyticsLinkManager(core);
}
/**
* Creates a new dataverse (analytics scope) if it does not already exist.
*
* @param dataverseName the name of the dataverse to create.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DataverseExistsException (async) if the dataverse already exists.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture createDataverse(final String dataverseName) {
return createDataverse(dataverseName, createDataverseAnalyticsOptions());
}
/**
* Creates a new dataverse (analytics scope) if it does not already exist with custom options.
*
* @param dataverseName the name of the dataverse to create.
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DataverseExistsException (async) if the dataverse already exists.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture createDataverse(final String dataverseName,
final CreateDataverseAnalyticsOptions options) {
notNullOrEmpty(dataverseName, "DataverseName");
notNull(options, "Options");
final CreateDataverseAnalyticsOptions.Built builtOpts = options.build();
String statement = "CREATE DATAVERSE " + quoteDataverse(dataverseName);
if (builtOpts.ignoreIfExists()) {
statement += " IF NOT EXISTS";
}
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_CREATE_DATAVERSE)
.thenApply(result -> null);
}
/**
* Fetches all dataverses (analytics scopes) from the analytics service.
*
* @return a {@link CompletableFuture} completing with a (potentially empty) list of dataverses or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
@Stability.Uncommitted
public CompletableFuture> getAllDataverses() {
return getAllDataverses(getAllDataversesAnalyticsOptions());
}
/**
* Fetches all dataverses (analytics scopes) from the analytics service with custom options.
*
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing with a (potentially empty) list of dataverses or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
@Stability.Uncommitted
public CompletableFuture> getAllDataverses(final GetAllDataversesAnalyticsOptions options) {
notNull(options, "Options");
final GetAllDataversesAnalyticsOptions.Built builtOpts = options.build();
String statement = "SELECT DataverseName from Metadata.`Dataverse`";
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_GET_ALL_DATAVERSES)
.thenApply(result -> result.rowsAsObject().stream()
.map((dv) -> dv.put("DataverseName",((String)dv.get("DataverseName")).replace("@.",".")))
.map(AnalyticsDataverse::new)
.collect(toList())
);
}
/**
* Drops (deletes) a dataverse.
*
* @param dataverseName the name of the dataverse to drop.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DataverseNotFoundException (async) if the dataverse does not exist.
* @throws CompilationFailureException (async) if a dataverse that cannot be dropped (i.e. Default) is attempted.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture dropDataverse(final String dataverseName) {
return dropDataverse(dataverseName, dropDataverseAnalyticsOptions());
}
/**
* Drops (deletes) a dataverse with custom options.
*
* @param dataverseName the name of the dataverse to drop.
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DataverseNotFoundException (async) if the dataverse does not exist.
* @throws CompilationFailureException (async) if a dataverse that cannot be dropped (i.e. Default) is attempted.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture dropDataverse(final String dataverseName,
final DropDataverseAnalyticsOptions options) {
notNullOrEmpty(dataverseName, "DataverseName");
notNull(options, "Options");
final DropDataverseAnalyticsOptions.Built builtOpts = options.build();
String statement = "DROP DATAVERSE " + quoteDataverse(dataverseName);
if (builtOpts.ignoreIfNotExists()) {
statement += " IF EXISTS";
}
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_DROP_DATAVERSE)
.thenApply(result -> null);
}
/**
* Creates a new dataset (analytics collection) if it does not already exist.
*
* @param datasetName the name of the dataset to create.
* @param bucketName the name of the bucket where the dataset is stored inside.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DatasetExistsException (async) if the dataset already exists.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture createDataset(final String datasetName, final String bucketName) {
return createDataset(datasetName, bucketName, createDatasetAnalyticsOptions());
}
/**
* Creates a new dataset (analytics collection) if it does not already exist with custom options.
*
* @param datasetName the name of the dataset to create.
* @param bucketName the name of the bucket where the dataset is stored inside.
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DatasetExistsException (async) if the dataset already exists.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture createDataset(final String datasetName, final String bucketName,
final CreateDatasetAnalyticsOptions options) {
notNullOrEmpty(datasetName, "DatasetName");
notNullOrEmpty(bucketName, "BucketName");
notNull(options, "Options");
final CreateDatasetAnalyticsOptions.Built builtOpts = options.build();
final String dataverseName = builtOpts.dataverseName().orElse(DEFAULT_DATAVERSE);
final String condition = builtOpts.condition().orElse(null);
String statement = "CREATE DATASET ";
if (builtOpts.ignoreIfExists()) {
statement += "IF NOT EXISTS ";
}
statement += quoteDataverse(dataverseName, datasetName) + " ON " + quote(bucketName);
if (condition != null) {
statement += " WHERE " + condition;
}
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_CREATE_DATASET)
.thenApply(result -> null);
}
/**
* Drops (deletes) a dataset.
*
* @param datasetName the name of the dataset to create.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DatasetNotFoundException (async) if the dataset to drop does not exist.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture dropDataset(final String datasetName) {
return dropDataset(datasetName, dropDatasetAnalyticsOptions());
}
/**
* Drops (deletes) a dataset with custom options.
*
* @param datasetName the name of the dataset to create.
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws DatasetNotFoundException (async) if the dataset to drop does not exist.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture dropDataset(final String datasetName, final DropDatasetAnalyticsOptions options) {
notNullOrEmpty(datasetName, "DatasetName");
notNull(options, "Options");
final DropDatasetAnalyticsOptions.Built builtOpts = options.build();
final String dataverseName = builtOpts.dataverseName().orElse(DEFAULT_DATAVERSE);
String statement = "DROP DATASET " + quoteDataverse(dataverseName, datasetName);
if (builtOpts.ignoreIfNotExists()) {
statement += " IF EXISTS";
}
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_DROP_DATASET)
.thenApply(result -> null);
}
/**
* Fetches all datasets (analytics collections) from the analytics service.
*
* @return a {@link CompletableFuture} completing with a (potentially empty) list of datasets or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture> getAllDatasets() {
return getAllDatasets(getAllDatasetsAnalyticsOptions());
}
/**
* Fetches all datasets (analytics collections) from the analytics service with custom options.
*
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing with a (potentially empty) list of datasets or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture> getAllDatasets(final GetAllDatasetsAnalyticsOptions options) {
notNull(options, "Options");
final GetAllDatasetsAnalyticsOptions.Built builtOpts = options.build();
String statement = "SELECT d.* FROM Metadata.`Dataset` d WHERE d.DataverseName <> \"Metadata\"";
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_GET_ALL_DATASETS)
.thenApply(result -> result.rowsAsObject().stream()
.map(AnalyticsDataset::new)
.collect(toList())
);
}
/**
* Creates a new analytics index if it does not exist.
*
* @param indexName the name of the index to create.
* @param datasetName the name of the dataset in which the index should be created.
* @param fields the fields that should be indexed.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws IndexExistsException (async) if the index already exists and not ignored in the options.
* @throws DataverseNotFoundException (async) if a dataverse is provided in the options that does not exist.
* @throws DatasetNotFoundException (async) if a dataset is provided which does not exist.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture createIndex(final String indexName, final String datasetName,
final Map fields) {
return createIndex(indexName, datasetName, fields, createIndexAnalyticsOptions());
}
/**
* Creates a new analytics index if it does not exist with custom options.
*
* @param indexName the name of the index to create.
* @param datasetName the name of the dataset in which the index should be created.
* @param fields the fields that should be indexed.
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws IndexExistsException (async) if the index already exists and not ignored in the options.
* @throws DataverseNotFoundException (async) if a dataverse is provided in the options that does not exist.
* @throws DatasetNotFoundException (async) if a dataset is provided which does not exist.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture createIndex(final String indexName, final String datasetName,
final Map fields,
final CreateIndexAnalyticsOptions options) {
notNullOrEmpty(indexName, "IndexName");
notNullOrEmpty(datasetName, "DatasetName");
notNull(fields, "Fields");
notNull(options, "Options");
final CreateIndexAnalyticsOptions.Built builtOpts = options.build();
final String dataverseName = builtOpts.dataverseName().orElse(DEFAULT_DATAVERSE);
String statement = "CREATE INDEX " + quote(indexName);
if (builtOpts.ignoreIfExists()) {
statement += " IF NOT EXISTS";
}
statement += " ON " + quoteDataverse(dataverseName, datasetName) + " " + formatIndexFields(fields);
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_CREATE_INDEX)
.thenApply(result -> null);
}
/**
* Lists all analytics indexes.
*
* @return a {@link CompletableFuture} completing with a list of indexes or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture> getAllIndexes() {
return getAllIndexes(getAllIndexesAnalyticsOptions());
}
/**
* Lists all analytics indexes with custom options.
*
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing with a (potentially empty) list of indexes or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture> getAllIndexes(final GetAllIndexesAnalyticsOptions options) {
notNull(options, "Options");
final GetAllIndexesAnalyticsOptions.Built builtOpts = options.build();
String statement = "SELECT d.* FROM Metadata.`Index` d WHERE d.DataverseName <> \"Metadata\"";
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_GET_ALL_INDEXES)
.thenApply(result -> result.rowsAsObject().stream()
.map(AnalyticsIndex::new)
.collect(toList())
);
}
/**
* Drops (removes) an index if it exists.
*
* @param indexName the name of the index to drop.
* @param datasetName the dataset in which the index exists.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws IndexNotFoundException (async) if the index does not exist and not ignored via options.
* @throws DataverseNotFoundException (async) if a dataverse is provided in the options that does not exist.
* @throws DatasetNotFoundException (async) if a dataset is provided which does not exist.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture dropIndex(final String indexName, final String datasetName) {
return dropIndex(indexName, datasetName, dropIndexAnalyticsOptions());
}
/**
* Drops (removes) an index if it exists with custom options.
*
* @param indexName the name of the index to drop.
* @param datasetName the dataset in which the index exists.
* @param options the custom options to apply.
* @return a {@link CompletableFuture} completing when the operation is applied or failed with an error.
* @throws IndexNotFoundException (async) if the index does not exist and not ignored via options.
* @throws DataverseNotFoundException (async) if a dataverse is provided in the options that does not exist.
* @throws DatasetNotFoundException (async) if a dataset is provided which does not exist.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture dropIndex(final String indexName, final String datasetName,
final DropIndexAnalyticsOptions options) {
notNullOrEmpty(indexName, "IndexName");
notNullOrEmpty(datasetName, "DatasetName");
notNull(options, "Options");
final DropIndexAnalyticsOptions.Built builtOpts = options.build();
final String dataverseName = builtOpts.dataverseName().orElse(DEFAULT_DATAVERSE);
String statement = "DROP INDEX " + quoteDataverse(dataverseName, datasetName, indexName);
if (builtOpts.ignoreIfNotExists()) {
statement += " IF EXISTS";
}
return exec(statement, builtOpts, TracingIdentifiers.SPAN_REQUEST_MA_DROP_INDEX)
.thenApply(result -> null);
}
/**
* Returns the pending mutations for different dataverses.
*
* @return a {@link CompletableFuture} completing with the pending mutations or failed with an error.
* @throws CouchbaseException (async) if any other generic unhandled/unexpected errors.
*/
public CompletableFuture