All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.stargate.sdk.doc.DocumentClient Maven / Gradle / Ivy

There is a newer version: 2.3.7
Show newest version
/*
 * 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 com.datastax.stargate.sdk.doc;

import static com.datastax.stargate.sdk.core.ApiSupport.getHttpClient;
import static com.datastax.stargate.sdk.core.ApiSupport.getObjectMapper;
import static com.datastax.stargate.sdk.core.ApiSupport.handleError;
import static com.datastax.stargate.sdk.core.ApiSupport.startRequest;
import static com.datastax.stargate.sdk.doc.NamespaceClient.PATH_COLLECTIONS;
import static com.datastax.stargate.sdk.doc.NamespaceClient.PATH_NAMESPACES;

import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.Map;
import java.util.Optional;

import com.datastax.stargate.sdk.utils.Assert;

/**
 * Part of the Document API in stargate wrapper for methods at the document level.
 *
 * @author Cedrick LUNVEN (@clunven)
 */
public class DocumentClient {
     
    /** Astra Client. */
    private final ApiDocumentClient docClient;
    
    /** Namespace. */
    private final NamespaceClient namespaceClient;
    
    /** Namespace. */
    private final CollectionClient collectionClient;
    
    /** Unique document identifer. */
    private final String docId;
    
    /**
     * Full constructor.
     * 
     * @param docClient ApiDocumentClient
     * @param namespaceClient NamespaceClient
     * @param collectionClient CollectionClient
     * @param docId String
     */
    public DocumentClient(
            ApiDocumentClient docClient, NamespaceClient namespaceClient, 
            CollectionClient collectionClient, String docId) {
        this.docClient         = docClient;
        this.namespaceClient   = namespaceClient;
        this.collectionClient  = collectionClient;
        this.docId             = docId;
    }
    
    /**
     * Build endpoint of the resource
     */
    private String getEndpoint() {
        return docClient.getEndPointApiDocument()
                + PATH_NAMESPACES  + "/" + namespaceClient.getNamespace() 
                + PATH_COLLECTIONS + "/" + collectionClient.getCollectionName()
                + "/" + docId;
    }
    
    /**
     * Leverage find() to check existence without eventual formatting issues. 
     * https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/getDocById
     * 
     * @return boolean
     */
    public boolean exist() {
        Assert.hasLength(docId, "documentId");
        try {
            return HttpURLConnection.HTTP_OK == getHttpClient().send(
                    startRequest(getEndpoint(), docClient.getToken())
                      .GET().build(), BodyHandlers.discarding()).statusCode();
        } catch (Exception e) {
            throw new RuntimeException("Cannot test document existence", e);
        }
    }
    
    /**
     * Replace a document. https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/replaceDoc
     * 
     * @param  working class
     * @param doc DOC
     * @return DOC
     */
    public  String upsert(DOC doc) {
        Assert.notNull(doc, "document");
        Assert.hasLength(docId, "Document identifier");
        HttpResponse response;
        try {
            String reqBody = getObjectMapper().writeValueAsString(doc);
           response = getHttpClient().send(
                   startRequest(getEndpoint(), docClient.getToken())
                   .PUT(BodyPublishers.ofString(reqBody)).build(),
                   BodyHandlers.ofString());
        } catch (Exception e) {
            throw new RuntimeException("Cannot save document:", e);
        }    
        
        handleError(response);
        return marshallDocumentId(response.body());
    }
  
    /**
     * Update part of a document. https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/updatePartOfDoc
     * 
     * @param  working class
     * @param doc working class
     * @return DOC
     */
    public  String update(DOC doc) {
        Assert.notNull(doc, "document");
        Assert.hasLength(docId, "Document identifier");
        HttpResponse response;
        try {
           String reqBody = getObjectMapper().writeValueAsString(doc);
           response = getHttpClient().send(
                   startRequest(getEndpoint(), docClient.getToken()).method("PATCH", BodyPublishers.ofString(reqBody)).build(),
                   BodyHandlers.ofString());
        } catch (Exception e) {
            throw new RuntimeException("Cannot save document:", e);
        }
        handleError(response);
        return marshallDocumentId(response.body());
    }
    
    
    
    /**
     * Get a document by {document-id}. https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/getDocById
     *
     * @param  working class
     * @param clazz working class
     * @return a document if exist
     */
    public  Optional find(Class clazz) {
        Assert.hasLength(docId, "documentId");
        Assert.notNull(clazz, "className");
        HttpResponse response;
        try {
            response = getHttpClient().send(
                    startRequest(getEndpoint() + "?raw=true", docClient.getToken())
                        .GET().build(), BodyHandlers.ofString());
        } catch (Exception e) {
            throw new RuntimeException("Cannot invoke API to find document:", e);
        }
        handleError(response);
        if (HttpURLConnection.HTTP_OK == response.statusCode()) {
           return Optional.of(marshallDocument(response.body(), clazz));
        }
        return Optional.empty();
    }

    /**
     * Delete a document. https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/deleteDoc
     *           
     */
    public void delete() {
        Assert.hasLength(docId, "documentId");
        if (!exist()) {
            throw new RuntimeException("Document '"+ docId + "' has not been found");
        }
        HttpResponse response;
        try {
            response = getHttpClient().send(
                    startRequest(getEndpoint(), docClient.getToken())
                     .DELETE().build(), BodyHandlers.ofString());
            if (HttpURLConnection.HTTP_NO_CONTENT == response.statusCode()) {
                return;
            }
        } catch (Exception e) {
            throw new RuntimeException("Cannot invoke API to delete a document:", e);
        }
        handleError(response);
    }
    
    /**
     * Get a sub document by {document-path}.
     * https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/GetSubDocByPath
     *
     * @param  working class
     * @param path subpath in the doc
     * @param className  working class
     * @return SUBDOC
     */
    public  Optional findSubDocument(String path, Class className) {
        Assert.hasLength(docId, "documentId");
        Assert.hasLength(path, "hasLength");
        Assert.notNull(className, "expectedClass");
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        HttpResponse response;
        try {
           response = getHttpClient().send(startRequest(getEndpoint() + path + "?raw=true", docClient.getToken())
                    .GET().build(), BodyHandlers.ofString());
        } catch (Exception e) {
            throw new RuntimeException("Cannot invoke API to find sub document:", e);
        }
        handleError(response);
        if (HttpURLConnection.HTTP_OK == response.statusCode()) {
            return Optional.of(marshallDocument(response.body(), className));
        }
        return Optional.empty();
    }
    
    
    /**
     * Replace a subpart of the document.
     * https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/replaceSubDoc
     * 
     * @param  working class
     * @param path subpath in the doc
     * @param newValue object for the new value
     */
    public  void replaceSubDocument(String path, SUBDOC newValue) {
        Assert.hasLength(path, "path");
        Assert.notNull(newValue, "newValue");
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        HttpResponse response;
        try {
            response = getHttpClient().send(
                    startRequest(getEndpoint() + path, docClient.getToken())
                     .PUT(BodyPublishers.ofString(getObjectMapper().writeValueAsString(newValue))).build(), 
                    BodyHandlers.ofString());
        } catch (Exception e) {
            throw new RuntimeException("An error occured when updating sub documents", e);
        }
        handleError(response);
    }
    
    /**
     * Update part of a sub document
     * https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/updatePartOfSubDoc
     * 
     * @param  working class
     * @param path subpath in the doc
     * @param newValue object for the new value
     */
    public  void updateSubDocument(String path, SUBDOC newValue) {
        Assert.hasLength(path, "path");
        Assert.notNull(newValue, "newValue");
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        HttpResponse response;
        try {
            response = getHttpClient().send(
                    startRequest(getEndpoint() + path + "?raw=true", docClient.getToken())
                     .method("PATCH", BodyPublishers.ofString(getObjectMapper().writeValueAsString(newValue))).build(), 
                    BodyHandlers.ofString());
        } catch (Exception e) {
            throw new RuntimeException("An error occured when updating sub documents", e);
        }
        handleError(response);
    }
    
    
    /**
     * Delete a sub document.
     * https://docs.datastax.com/en/astra/docs/_attachments/docv2.html#operation/deleteSubDoc
     * 
     * @param path sub document path
     */
    public void deleteSubDocument(String path) {
        Assert.hasLength(path, "path");
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        HttpResponse response;
        try {
            response = getHttpClient().send(
                        startRequest(getEndpoint() + path + "?raw=true", docClient.getToken())
                            .DELETE().build(), BodyHandlers.ofString());
            
        } catch (Exception e) {
            throw new RuntimeException("An error occured when deleting sub documents", e);
        }
        handleError(response);
    }
    
    /**
     * marshallDocumentId
     * 
     * @param body String
     * @return String
     */
    private String marshallDocumentId(String body) {
        try {
            return (String) getObjectMapper()
                    .readValue(body, Map.class)
                    .get(CollectionClient.DOCUMENT_ID);
        } catch (Exception e) {
            throw new RuntimeException("Cannot marshall document after 'upsert'", e);
        }
    }
    
    /**
     * marshallDocument
     * 
     * @param  DOC
     * @param body String
     * @param clazz DOC
     * @return DOC
     */
    private   DOC marshallDocument(String body,  Class clazz) {
        try {
            return getObjectMapper().readValue(body, clazz);
        } catch (Exception e) {
            throw new RuntimeException("Cannot marshal output '" + body + "' into class '"+ clazz +"'", e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy