#ifndef QDB_API_BLOB_H
#define QDB_API_BLOB_H

//! \file blob.h
//! \defgroup blob Binary large objects (blob) operations

/*
 *
 * Official quasardb C API 2.0.02.0.1
 * c64b446 2017-10-09 19:58:02 +0000
 *
 * Copyright (c) 2009-2017, quasardb SAS
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of quasardb nor the names of its contributors may
 *      be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY QUASARDB AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "client.h"

#ifdef __cplusplus
extern "C" {
#endif

//! \ingroup blob
//! \brief Retrieves an entry's content from the quasardb server. The caller
//!        is responsible for allocating and freeing the provided buffer.
//!
//! If the entry does not exist, the function will fail and return
//! `qdb_e_alias_not_found`.
//!
//! If the buffer is not large enough to hold the data, the function will fail
//! and return `qdb_e_buffer_too_small`. \p content_length will nevertheless be
//! updated with entry size so that the caller may resize its buffer and try
//! again.
//!
//! \param handle         A valid handle previously initialized by ::qdb_open or
//!                       ::qdb_open_tcp.
//! \param alias          A pointer to a null-terminated UTF-8 string
//!                       representing the alias of the entry.
//! \param content        A pointer to a user-allocated buffer that will
//!                       receive the entry's content.
//! \param content_length A pointer to a ::qdb_size_t initialized with the length
//!                       of the destination buffer, in bytes. It will be
//!                       updated with the length of the retrieved content,
//!                       even if the buffer is not large enough to hold all
//!                       the data.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_blob_get_noalloc(qdb_handle_t handle,
                                                 const char * alias,
                                                 void * content,
                                                 qdb_size_t * content_length);

//! \ingroup blob
//! \brief Retrieves an entry's content from the quasardb server.
//!
//! If the entry does not exist, the function will fail and return
//! `qdb_e_alias_not_found`.
//!
//! The function will allocate a buffer large enough to hold the entry's
//! content. This buffer must be released by the caller with a call to
//! ::qdb_free_buffer().
//!
//! \param handle         A valid handle previously initialized by ::qdb_open or
//!                       ::qdb_open_tcp.
//! \param alias          A pointer to a null-terminated UTF-8 string
//!                       representing the alias of the entry.
//! \param content        A pointer to a pointer that will be set to a
//!                       function-allocated buffer holding the entry's content.
//! \param content_length A pointer to a ::qdb_size_t that will be set to the
//!                       content's size, in bytes.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_blob_get(qdb_handle_t handle,
                                         const char * alias,
                                         const void ** content,
                                         qdb_size_t * content_length);

//! \ingroup blob
//! \brief Retrieves a part of an entry's content from the quasardb server.
//!
//! If the entry does not exist, the function will fail and return
//! `qdb_e_alias_not_found`.
//!
//! The function will allocate a buffer large enough to hold the entry's
//! content. This buffer must be released by the caller with a call to
//! ::qdb_free_buffer().
//!
//! The returned content will be a subset of the entry's data in the range
//! <tt>[</tt>\p offset<tt>, </tt>\p offset<tt> + *</tt>\p content_length<tt>)</tt>.
//!
//! \param handle         A valid handle previously initialized by ::qdb_open or
//!                       ::qdb_open_tcp.
//! \param alias          A pointer to a null-terminated UTF-8 string
//!                       representing the alias of the entry.
//! \param content        A pointer to a pointer that will be set to a
//!                       function-allocated buffer holding the entry's content.
//! \param content_length A pointer to a ::qdb_size_t that holds the length of the
//!                       requested content and that will be set to the returned
//!                       content's size, in bytes. If content length is equal
//!                       to zero or is greater than entry's length minus
//!                       offset, then all the content from offset until the end
//!                       will be returned.
//! \param offset         Offset from which to get content, in bytes.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_reserved_blob_get(qdb_handle_t handle,
                                                  const char * alias,
                                                  const void ** content,
                                                  qdb_size_t * content_length,
                                                  qdb_size_t offset);

//! \ingroup blob
//! \brief Atomically gets an entry from the quasardb server and removes it.
//!
//! If the entry does not exist, the function will fail and return
//! `qdb_e_alias_not_found`.
//!
//! The function will allocate a buffer large enough to hold the entry's
//! content. This buffer must be released by the caller with a call to
//! ::qdb_free_buffer().
//!
//! If the buffer is not large enough to hold the data, the function will fail
//! and return `qdb_e_buffer_too_small`. \p content_length will nevertheless be
//! updated with entry size so that the caller may resize its buffer and try
//! again.
//!
//! \param handle         A valid handle previously initialized by ::qdb_open or
//!                       ::qdb_open_tcp.
//! \param alias          A pointer to a null-terminated UTF-8 string
//!                       representing the alias of the entry.
//! \param content        A pointer to a pointer that will be set to a
//!                       function-allocated buffer holding the entry's content.
//! \param content_length A pointer to a ::qdb_size_t that will be set to the
//!                       content's size, in bytes.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t
qdb_blob_get_and_remove(qdb_handle_t handle,
                        const char * alias,
                        const void ** content,
                        qdb_size_t * content_length);

//! \ingroup blob
//! \brief Creates a new entry and sets its content to the provided blob
//!
//! If the entry already exists the function will fail and will return
//! `qdb_e_alias_already_exists`.
//!
//! You can specify an expiry or use `qdb_never_expires` if you don't want the
//! entry to expire.
//!
//! There is no software-defined limit to the size of blobs. To operate on
//! entries that do not fit in RAM, consider using streams.
//!
//! \param handle A valid handle previously initialized by ::qdb_open or
//! ::qdb_open_tcp.
//! \param alias A pointer to a null-terminated UTF-8 string representing the
//! alias of the entry.
//! \param content A pointer to the buffer with the blob content
//! \param content_length The length of the buffer, in bytes
//! \param expiry_time An optional absolute expiry time expressed in UTC UNIX
//! epoch.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_blob_put(qdb_handle_t handle,
                                         const char * alias,
                                         const void * content,
                                         qdb_size_t content_length,
                                         qdb_time_t expiry_time);

//! \ingroup blob
//! \brief Creates or updates an entry and sets its content to the provided blob
//!
//! If the entry already exists, the function will modify the entry.
//!
//! You can specify an expiry or use `qdb_never_expires` if you don't want the
//! entry to expire.
//!
//! There is no software-defined limit to the size of blobs. To operate on
//! entries that do not fit in RAM, consider using streams.
//!
//! \param handle A valid handle previously initialized by ::qdb_open or
//! ::qdb_open_tcp.
//! \param alias A pointer to a null-terminated UTF-8 string representing the
//! alias of the entry.
//! \param content A pointer to the buffer with the blob content
//! \param content_length The length of the buffer, in bytes
//! \param expiry_time An optional absolute expiry time expressed in UTC UNIX
//! epoch.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_blob_update(qdb_handle_t handle,
                                            const char * alias,
                                            const void * content,
                                            qdb_size_t content_length,
                                            qdb_time_t expiry_time);

//! \ingroup blob
//! \brief This function is reserved for internal use and its usage is
//! discouraged.
//! \param handle A valid handle previously initialized by ::qdb_open or
//! ::qdb_open_tcp.
//! \param alias A pointer to a null-terminated UTF-8 string representing the
//! alias of the entry.
//! \param content A pointer to the content to merge
//! \param content_length The length of the buffer, in bytes
//! \param offset Offset at which merge content
//! \param truncate 1 - the entry will be truncated at the end of the new buffer.
//!                 0 - the original content will be preserved.
//! \param expiry_time An optional absolute expiry time expressed in UTC UNIX
//! epoch.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_reserved_blob_merge(qdb_handle_t handle,
                                                    const char * alias,
                                                    const void * content,
                                                    qdb_size_t content_length,
                                                    qdb_size_t offset,
                                                    int truncate,
                                                    qdb_time_t expiry_time);

//! \ingroup blob
//! \brief Atomically gets and updates (in this order) the entry on the quasardb
//! server.
//!
//! The entry must already exist.
//!
//! \param handle A valid handle previously initialized by ::qdb_open or
//! ::qdb_open_tcp.
//! \param alias A pointer to a null-terminated UTF-8 string representing the
//! alias of the entry.
//! \param update_content A pointer to the buffer with the new blob content
//! \param update_content_length The length of the buffer, in bytes
//! \param expiry_time An optional absolute expiry time expressed in UTC UNIX
//! epoch.
//! \param get_content A pointer to a pointer to an API-allocated buffer holding
//! the entry
//!                    content, before the update.
//! \param get_content_length A pointer to a ::qdb_size_t that will be set to the
//! content's size,
//!                           in bytes.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t
qdb_blob_get_and_update(qdb_handle_t handle,
                        const char * alias,
                        const void * update_content,
                        qdb_size_t update_content_length,
                        qdb_time_t expiry_time,
                        const void ** get_content,
                        qdb_size_t * get_content_length);

//! \ingroup blob
//! \brief Atomically compares the entry with comparand and updates it to
//!        \p new_value if, and only if, they match.
//!
//! The function returns the original value of the entry in case of a
//! mismatch. When it matches, no content is returned.
//!
//! The entry must already exist.
//!
//! Update will occur if and only if the content of the entry matches bit for
//! bit the content of the comparand buffer.
//!
//! \param handle                A valid handle previously initialized by
//!                              ::qdb_open or ::qdb_open_tcp.
//! \param alias                 A pointer to a null-terminated UTF-8 string
//!                              representing the alias of the entry.
//! \param new_value             A pointer to a buffer that represents the
//!                              entry's content to be updated to the server in
//!                              case of match.
//! \param new_value_length      The length of the buffer, in bytes
//! \param comparand             A pointer to a buffer that represents the
//!                              entry's content to be compared to.
//! \param comparand_length      The length of the buffer, in bytes
//! \param expiry_time           An optional absolute expiry time expressed in
//!                              UTC UNIX epoch.
//! \param original_value        A pointer to a pointer that will be set to a
//!                              function-allocated buffer holding the entry's
//!                              original content, before the update, if any.
//! \param original_value_length A pointer to a ::qdb_size_t that will be set to
//!                              the content's size, in bytes.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t
qdb_blob_compare_and_swap(qdb_handle_t handle,
                          const char * alias,
                          const void * new_value,
                          qdb_size_t new_value_length,
                          const void * comparand,
                          qdb_size_t comparand_length,
                          qdb_time_t expiry_time,
                          const void ** original_value,
                          qdb_size_t * original_value_length);

// partial comparand, complete swap
QDB_API_LINKAGE qdb_error_t
qdb_reserved_blob_cas_partial(qdb_handle_t handle,
                              const char * alias,
                              const void * new_value,
                              qdb_size_t new_value_length,
                              const void * comparand,
                              qdb_size_t comparand_length,
                              qdb_size_t comparand_offset,
                              qdb_time_t expiry_time,
                              const void ** original_value,
                              qdb_size_t * original_value_length);

//! \ingroup blob
//! \brief Atomically removes the entry on the server if the content matches.
//!
//! The entry must already exist.
//!
//! Removal will occur if and only if the content of the entry matches bit for
//! bit the content of the comparand buffer.
//!
//! \param handle           A valid handle previously initialized by ::qdb_open
//!                         or ::qdb_open_tcp.
//! \param alias            A pointer to a null-terminated UTF-8 string
//!                         representing the alias of the entry.
//! \param comparand        A pointer to a buffer to use a comparand
//! \param comparand_length The length of the buffer, in bytes
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_blob_remove_if(qdb_handle_t handle,
                                               const char * alias,
                                               const void * comparand,
                                               qdb_size_t comparand_length);

//! \ingroup blob
//! \brief Retrieves all blobs that have content matching the specified pattern
//!
//! \warning This function is experimental.
//!
//! The complexity of this function is linear in the number of entries.
//!
//! \param handle         A valid handle previously initialized by ::qdb_open or
//!                       ::qdb_open_tcp.
//! \param pattern        A pointer to the pattern buffer to search for
//! \param pattern_length The length of the pattern buffer, in bytes
//! \param max_count      An integer limiting the number of results returned by
//!                       the function
//! \param aliases        A pointer to an array of null-terminated UTF-8 string
//!                       that will list the aliases of the entries matching the
//!                       requested pattern.
//! \param alias_count    A pointer to an integer that will receive the number
//!                       of returned aliases.
//!
//! \return A ::qdb_error_t code indicating success or failure.
QDB_API_LINKAGE qdb_error_t qdb_blob_scan(qdb_handle_t handle,
                                          const void * pattern,
                                          qdb_size_t pattern_length,
                                          qdb_int_t max_count,
                                          const char *** aliases,
                                          size_t * alias_count);

//! \ingroup blob
//! \brief   Retrieves all blobs that have content matching the specified
//! regular expression (regex)
//!
//! \warning This function is experimental.
//!
//! The complexity of this function is linear in the number of entries.
//!
//! \param handle      A valid handle previously initialized by ::qdb_open or
//!                    ::qdb_open_tcp.
//! \param pattern     A pointer to a null-terminated UTF-8 string representing
//!                    the regular expression to search for. The regex syntax is
//!                    defined by ECMA-262 grammar.
//! \param max_count   An integer limiting the number of results returned by the
//!                    function
//! \param aliases     A pointer to an array of null-terminated UTF-8 string
//!                    that will list the aliases of the entries matching the
//!                    requested pattern.
//! \param alias_count A pointer to an integer that will receive the number
//!                    of returned aliases.
//!
//! \return A ::qdb_error_t code indicating success or failure.
//!
//! \see    http://ecma-international.org/ecma-262/5.1/#sec-15.10
QDB_API_LINKAGE qdb_error_t qdb_blob_scan_regex(qdb_handle_t handle,
                                                const char * pattern,
                                                qdb_int_t max_count,
                                                const char *** aliases,
                                                size_t * alias_count);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif
