/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 2020-Present 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace couchbase { /** * Options for cluster#analytics_query() and scope#analytics_query(). * * @since 1.0.0 * @committed */ struct analytics_options : public common_options { /** * Immutable value object representing consistent options. * * @since 1.0.0 * @internal */ struct built : public common_options::built { std::optional client_context_id; const bool priority; const bool readonly; std::optional scan_consistency; std::optional scan_wait; std::vector mutation_state; std::vector positional_parameters; std::map> named_parameters; std::map> raw; }; /** * Validates options and returns them as an immutable value. * * @return consistent options as an immutable value * * @exception std::system_error with code errc::common::invalid_argument if the options are not * valid * * @since 1.0.0 * @internal */ [[nodiscard]] auto build() const -> built { return { build_common_options(), client_context_id_, priority_, readonly_, scan_consistency_, scan_wait_, mutation_state_, positional_parameters_, named_parameters_, raw_, }; } /** * Allows to give certain requests higher priority than others. * * @param prioritized if set to true this query will be treated with a higher priority by the * service. * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ auto priority(bool prioritized) -> analytics_options& { priority_ = prioritized; return self(); } /** * Allows explicitly marking a query as being readonly and not mutating and documents on the * server side. * * In addition to providing some security in that you are not accidentally modifying data, setting * this flag to true also helps the client to more proactively retry and re-dispatch a query since * then it can be sure it is idempotent. As a result, if your query is readonly then it is a good * idea to set this flag. * * @param readonly true if readonly should be set, false is the default and will use the server * side default. * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ auto readonly(bool readonly) -> analytics_options& { readonly_ = readonly; return self(); } /** * Allows customizing how long the query engine is willing to wait until the index catches up to * whatever scan consistency is asked for in this query. * * @note that if {@link analytics_scan_consistency::not_bounded} is used, this method doesn't do * anything at all. If no value is provided to this method, the server default is used. * * @param wait the maximum duration the query engine is willing to wait before failing. * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ auto scan_wait(std::chrono::milliseconds wait) -> analytics_options& { if (scan_consistency_ == analytics_scan_consistency::not_bounded) { scan_wait_.reset(); } else { scan_wait_ = wait; } return self(); } /** * Supports providing a custom client context ID for this query. * * If no client context ID is provided by the user, a UUID is generated and sent automatically so * by default it is always possible to identify a query when debugging. * * @param client_context_id the client context ID * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ auto client_context_id(std::string client_context_id) -> analytics_options& { if (client_context_id.empty()) { client_context_id_.reset(); } else { client_context_id_ = std::move(client_context_id); } return self(); } /** * Customizes the consistency guarantees for this query. * * Tuning the scan consistency allows to trade data "freshness" for latency and vice versa. By * default * {@link analytics_scan_consistency::not_bounded} is used, which means that the server returns * the data it has in the index right away. This is fast, but might not include the most recent * mutations. If you want to include all the mutations up to the point of the query, use {@link * analytics_scan_consistency::request_plus}. * * Note that you cannot use this method and {@link #consistent_with(const mutation_state&)} at the * same time, since they are mutually exclusive. As a rule of thumb, if you only care to be * consistent with the mutation you just wrote on the same thread/app, use * {@link #consistent_with(const mutation_state&)}. If you need "global" scan consistency, use * {@link analytics_scan_consistency::request_plus} on this method. * * @param scan_consistency the index scan consistency to be used for this query * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ auto scan_consistency(analytics_scan_consistency scan_consistency) -> analytics_options& { scan_consistency_ = scan_consistency; mutation_state_.clear(); return self(); } /** * Sets the {@link mutation_token}s this query should be consistent with. * * These mutation tokens are returned from mutations (i.e. as part of a {@link mutation_result}) * and if you want your N1QL query to include those you need to pass the mutation tokens into a * {@link mutation_state}. * * Note that you cannot use this method and {@link #scan_consistency(analytics_scan_consistency)} * at the same time, since they are mutually exclusive. As a rule of thumb, if you only care to be * consistent with the mutation you just wrote on the same thread/app, use this method. If you * need "global" scan consistency, use * {@link analytics_scan_consistency#request_plus} on {@link * #scan_consistency(analytics_scan_consistency)}. * * @param state the mutation state containing the mutation tokens. * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ auto consistent_with(const mutation_state& state) -> analytics_options& { mutation_state_ = state.tokens(); scan_consistency_.reset(); return self(); } /** * * @tparam Value * @param name * @param value * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ template auto raw(std::string name, const Value& value) -> analytics_options& { raw_[std::move(name)] = std::move(codec::tao_json_serializer::serialize(value)); return self(); } /** * Set list of positional parameters for a query. * * @tparam Parameters types for the parameters * @param parameters the sequence of positional parameters. Each entry will be encoded into JSON. * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ template auto positional_parameters(const Parameters&... parameters) -> analytics_options& { named_parameters_.clear(); positional_parameters_.clear(); encode_positional_parameters(parameters...); return self(); } /** * Set list of named parameters for a query. * * @tparam Parameters types for the parameter pairs * @param parameters the sequence of name-value pairs. Each value will be encoded into JSON. * @return this options builder for chaining purposes. * * @since 1.0.0 * @committed */ template auto named_parameters(const Parameters&... parameters) -> analytics_options& { named_parameters_.clear(); positional_parameters_.clear(); encode_named_parameters(parameters...); return self(); } /** * Set map of raw options for a query. * * This function expects that all parameters encoded into pairs containing mapping names of the * parameter to valid JSON values encoded as string. * * @note This function is low-level, and instead @ref raw() should be considered. * * @param options mapping of pairs, where each entry contains string with valid JSON value. * @return this options builder for chaining purposes. * * @since 1.0.0 * @uncommitted */ auto encoded_raw_options(std::map> options) -> analytics_options& { raw_ = std::move(options); return self(); } /** * Set list of positional parameters for a query. * * This function expects that all parameters encoded into byte strings containing valid JSON * values. * * @note This function is low-level, and instead @ref positional_parameters() should be * considered. * * @param parameters vector of binaries, where each entry contains string with valid JSON value. * @return this options builder for chaining purposes. * * @since 1.0.0 * @uncommitted */ auto encoded_positional_parameters(std::vector parameters) -> analytics_options& { named_parameters_.clear(); positional_parameters_ = std::move(parameters); return self(); } /** * Set map of named parameters for a query. * * This function expects that all parameters encoded into pairs containing mapping names of the * parameter to valid JSON values encoded as string. * * @note This function is low-level, and instead @ref named_parameters() should be considered. * * @param parameters mapping of pairs, where each entry contains string with valid JSON value. * @return this options builder for chaining purposes. * * @since 1.0.0 * @uncommitted */ auto encoded_named_parameters(std::map> parameters) -> analytics_options& { named_parameters_ = std::move(parameters); positional_parameters_.clear(); return self(); } private: template void encode_positional_parameters(const Parameter& parameter, Rest... args) { positional_parameters_.emplace_back( std::move(codec::tao_json_serializer::serialize(parameter))); if constexpr (sizeof...(args) > 0) { encode_positional_parameters(args...); } } template void encode_named_parameters(const std::pair& parameter, Rest... args) { named_parameters_[parameter.first] = std::move(codec::tao_json_serializer::serialize(parameter.second)); if constexpr (sizeof...(args) > 0) { encode_named_parameters(args...); } } bool priority_{ true }; bool readonly_{ false }; std::optional client_context_id_{}; std::optional scan_wait_{}; std::optional scan_consistency_{}; std::vector mutation_state_{}; std::vector positional_parameters_{}; std::map> raw_{}; std::map> named_parameters_{}; }; /** * The signature for the handler of the @ref cluster#analytics_query() and @ref * scope#analytics_query() operations * * @since 1.0.0 * @uncommitted */ using analytics_handler = std::function; } // namespace couchbase