
io.stargate.sdk.doc.CollectionClient Maven / Gradle / Ivy
/*
* Copyright DataStax, 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 io.stargate.sdk.doc;
import com.fasterxml.jackson.core.type.TypeReference;
import io.stargate.sdk.api.ApiResponse;
import io.stargate.sdk.api.odm.RecordMapper;
import io.stargate.sdk.core.domain.Page;
import io.stargate.sdk.doc.domain.CollectionDefinition;
import io.stargate.sdk.doc.domain.PageableQuery;
import io.stargate.sdk.doc.domain.Query;
import io.stargate.sdk.http.LoadBalancedHttpClient;
import io.stargate.sdk.http.ServiceHttp;
import io.stargate.sdk.http.domain.ApiResponseHttp;
import io.stargate.sdk.utils.Assert;
import io.stargate.sdk.utils.JsonUtils;
import io.stargate.sdk.utils.Utils;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Work on a dedicated collection without using the Pojo className.
*
* @author Cedrick LUNVEN (@clunven)
*/
public class CollectionClient {
/** Read document id. */
public static final String DOCUMENT_ID = "documentId";
/** Read document id. */
public static final String BATCH_ID_PATH = "id-path";
/** Get Topology of the nodes. */
private final LoadBalancedHttpClient stargateHttpClient;
/** Namespace. */
protected NamespaceClient namespaceClient;
/** Collection name. */
protected String collectionName;
/* Mapping type. */
private static TypeReference>>> RESPONSE_SEARCH =
new TypeReference>>>(){};
/**
* Full constructor.
*
* @param stargateHttpClient http client
* @param namespaceClient NamespaceClient
* @param collectionName String
*/
public CollectionClient(LoadBalancedHttpClient stargateHttpClient, NamespaceClient namespaceClient, String collectionName) {
this.namespaceClient = namespaceClient;
this.collectionName = collectionName;
this.stargateHttpClient = stargateHttpClient;
}
/**
* Get metadata of the collection. There is no dedicated resources we
* use the list and filter with what we need.
*
* @see Reference Documentation
*
* @return
* metadata of the collection if its exist or empty
*/
public Optional find() {
return namespaceClient.collections()
.filter(c -> collectionName.equalsIgnoreCase(c.getName()))
.findFirst();
}
/**
* Check if the collection exist.
*
* @return if the collection exists.
*/
public boolean exist() {
return namespaceClient.collectionNames()
.anyMatch(collectionName::equals);
}
/**
* Create the collection.
*
* @see Reference Documentation
*/
public void create() {
stargateHttpClient.POST(collectionResource,
"{\"name\":\"" + collectionName + "\"}");
}
/**
* Upgrade the collection.
* This is not relevant in ASTRA.
*/
public void upgradeSAI() {
upgrade(CollectionUpgradeType.SAI_INDEX_UPGRADE);
}
/**
* Update a collection to SAI.
*
* @param index
* collection SAI
*/
public void upgrade(CollectionUpgradeType index) {
stargateHttpClient.POST(collectionUpgradeResource,
"{\"upgradeType\":\"" + index.name() + "\"}");
}
/**
* Deleting the collection
*
* @see Reference Documentation
*/
public void delete() {
stargateHttpClient.DELETE(collectionResource);
}
/**
* Create a new document from any serializable object.
* The doc could be a the String value.
*
* @see Reference Documentation
*
* @param
* working bean type
* @param doc
* working bean instance
* @return
* created document id
*/
public String create(DOC doc) {
ApiResponseHttp res = stargateHttpClient.POST(collectionResource, JsonUtils.marshall(doc));
try {
return (String) JsonUtils.unmarshallBean(res.getBody(), Map.class).get(DOCUMENT_ID);
} catch (Exception e) {
throw new RuntimeException("Cannot marshall document id", e);
}
}
/**
* Create a new document from any serializable object.
* The doc could be a the String value.
*
* @see Reference Documentation
*
* @param doc
* working bean instance
* @return
* created document id
*/
public String create(String doc) {
ApiResponseHttp res = stargateHttpClient.POST(collectionResource, doc);
try {
return (String) JsonUtils.unmarshallBean(res.getBody(), Map.class).get(DOCUMENT_ID);
} catch (Exception e) {
throw new RuntimeException("Cannot marshall document id", e);
}
}
/**
* Use the resource batch to insert massively in the DB.
*
* @param records
* list of records
* @param idPath
* id path to enforced ids
* @param
* working document
* @return
* list of inserted ids
*/
@SuppressWarnings("unchecked")
public List batchInsert(List records, String idPath) {
Assert.notNull(records, "Records should be provided");
ApiResponseHttp res;
if (Utils.hasLength(idPath)) {
res = stargateHttpClient.POST(collectionBatchResource, JsonUtils.marshall(records),
"?" + BATCH_ID_PATH + "=" + idPath);
} else {
res = stargateHttpClient.POST(collectionBatchResource, JsonUtils.marshall(records));
}
Map doc = JsonUtils.unmarshallBean(res.getBody(), Map.class);
if (doc.containsKey("documentIds")) {
return (List) doc.get("documentIds");
}
return new ArrayList<>();
}
/**
* Use the resource batch to insert massively in the DB.
*
* @param records
* list of records
* @param idPath
* id path to enforced ids
* @return
* list of inserted ids
*/
@SuppressWarnings("unchecked")
public List batchInsertRaw(List records, String idPath) {
Assert.notNull(records, "Records should be provided");
ApiResponseHttp res;
if (Utils.hasLength(idPath)) {
res = stargateHttpClient.POST(collectionBatchResource, JsonUtils.marshall(records),
"?" + BATCH_ID_PATH + "=" + idPath);
} else {
res = stargateHttpClient.POST(collectionBatchResource, JsonUtils.marshall(records));
}
Map doc = JsonUtils.unmarshallBean(res.getBody(), Map.class);
if (doc.containsKey("documentIds")) {
return (List) doc.get("documentIds");
}
return new ArrayList<>();
}
/**
* Insert multiple record with a single resource.
*
* @param records
* list of records
* @param
* working document
* @return
* list of inserted ids
*/
public List batchInsert(List records) {
return batchInsert(records, null);
}
/**
* Insert multiple record with a single resource.
*
* @param records
* list of records
* @return
* list of inserted ids
*/
public List batchInsertRaw(List records) {
return batchInsert(records, null);
}
/**
* Count items in a collection, it can be slow as we iterate over pages limitating
* payload and marshalling as much as possible.
*
* @return
* number of record
*/
public long count() {
// limit fields to be retrieved to limit payload and read count
return findAll(Query.builder().select("field_not_exist").build()).count();
}
// --- Find all ---
/**
* This function will retrieve all documents in the Collection without any mapping.
*
* USE WITH CAUTION. Default behaviour is using paging, here we are
* fetching all pages until no more.
*
* @return
* all items in the the collection
*/
public Stream> findAll() {
return findAll(Query.builder().build());
}
/**
* This function will retrieve all documents in the Collection providing a custom mapping logic.
*
* USE WITH CAUTION. Default behaviour is using paging, here we are
* fetching all pages until no more.
*
* @param
* generic for working bean
* @param documentMapper
* mapper from a record to the document bean
* @return
* all items in the the collection
*/
public Stream> findAll(RecordMapper documentMapper) {
return findAll(Query.builder().build(), documentMapper);
}
/**
* This function will retrieve all documents in the Collection with automatic marshalling (jackson).
*
* USE WITH CAUTION. Default behaviour is using paging, here we are
* fetching all pages until no more.
*
* @param
* generic for working bean
* @param beanClass
* class for working bean
* @return
* all items in the the collection
*/
public Stream> findAll(Class beanClass) {
return findAll(Query.builder().build(), beanClass);
}
/**
* Find all document matching the query.
*
* USE WITH CAUTION. Default behaviour is using paging, here we are
* fetching all pages until no more.
*
* @param query
* list of filters
* @return
* all items matchin criteria
*/
public Stream> findAll(Query query) {
return findAll(query, (PageSupplier) (cc, q) -> cc.findPage(q));
}
/**
* Find all document matching the query.
*
* USE WITH CAUTION. Default behaviour is using paging, here we are
* fetching all pages until no more.
*
* @param
* generic for working bean
* @param query
* list of filters
* @param documentMapper
* custom mapping implementation
* @return
* all items matchin criteria
*/
public Stream> findAll(Query query, RecordMapper documentMapper) {
return findAll(query, (PageSupplier) (cc, q) -> cc.findPage(q, documentMapper));
}
/**
* Find all document matching the query.
*
* USE WITH CAUTION. Default behaviour is using paging, here we are
* fetching all pages until no more.
*
* @param
* generic for working bean
* @param query
* list of filters
* @param beanClass
* class for working bean
* @return
* all items matchin criteria
*/
public Stream> findAll(Query query, Class beanClass) {
return findAll(query, (PageSupplier) (cc, q) -> cc.findPage(q, beanClass));
}
/**
* Mutualization of searching on multiple pages to do findAll().
*
* @param
* current working class
* @param query
* current query
* @param pageLoader
* single page retrieve
* @return
*/
private Stream> findAll(Query query, PageSupplier pageLoader) {
List> documents = new ArrayList<>();
PageableQuery pageQuery = new PageableQuery(query);
String pageState = null;
do {
Page> pageX = pageLoader.findPage(this, pageQuery);
if (pageX.getPageState().isPresent()) {
pageState = pageX.getPageState().get();
} else {
pageState = null;
}
documents.addAll(pageX.getResults());
pageQuery.setPageState(pageState);
} while(pageState != null);
return documents.stream();
}
/**
* find next page during a findAll
*
* @author Cedrick LUNVEN (@clunven)
*
* @param
* list items.
*/
public interface PageSupplier {
/**
* Get a page
* @param cc
* collection client
* @param q
* query
* @return
* page of results
*/
Page> findPage(CollectionClient cc, PageableQuery q);
}
// --- Find Page ---
/**
* Search for a page (without marshalling).
* There is no filter either.
*
* @return
* a page of results
*/
public Page> findPage() {
return findPage(PageableQuery.builder().build());
}
/**
* Find a page given some search (without marshalling the documents).
*
* @param query
* query
* @return
* output
*/
public Page> findPage(PageableQuery query) {
ApiResponse
© 2015 - 2025 Weber Informatics LLC | Privacy Policy