1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2015 Couchbase, Inc 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #ifndef LCB_SUBDOCAPI_H 19 #define LCB_SUBDOCAPI_H 20 #include <cstdint> 21 namespace Subdoc { 22 23 /** 24 * The following error codes are returned when a certain sub-document 25 * manipulation function could not be executed. Traditional memcached 26 * errors may also be returned. 27 */ 28 class Error { 29 public: 30 enum Code { 31 SUCCESS = 0, /* PROTOCOL_BINARY_RESPONSE_SUCCESS*/ 32 /** Document exists, but the given path was not found in the document */ 33 PATH_ENOENT, 34 /** There was a conflict between the data and the path */ 35 PATH_MISMATCH, 36 /** The path is not a valid path (i.e. does not parse correctly) */ 37 PATH_EINVAL, 38 /** The document reference exists, but is not JSON */ 39 DOC_NOTJSON, 40 /**The requested operation required the value did not already exist, but it exists */ 41 DOC_EEXISTS, 42 /**The path requested is too long/deep to traverse */ 43 PATH_E2BIG, 44 /**The number to increment was too big (could not fit in an int64_t) */ 45 NUM_E2BIG, 46 /**Combining the delta with the number would cause an over/underflow*/ 47 DELTA_OVERFLOW, 48 /**Delta is either not a number, 0, or not within range of int64 */ 49 DELTA_EINVAL, 50 /**Invalid value for insertion. Inserting this value would invalidate 51 * the JSON document */ 52 VALUE_CANTINSERT, 53 /** Document too deep to parse */ 54 DOC_ETOODEEP, 55 56 /** Missing a value */ 57 VALUE_EMPTY, 58 59 /** Inserting the value would cause the document to be too deep */ 60 VALUE_ETOODEEP, 61 62 /* MEMCACHED ERROR CODES */ 63 GLOBAL_ENOSUPPORT, 64 }; 65 66 Code m_code; m_code(c)67 Error(Code c = SUCCESS) : m_code(c) {} 68 operator int() const { return static_cast<int>(m_code); } success()69 bool success() const { return m_code == SUCCESS; } code()70 Code code() const { return m_code; } 71 const char *description() const; 72 }; 73 74 /**@name Paths 75 * A Sub-Document _PATH_ is a path to the container of the item you want to 76 * access. Every JSON primitive is stored either as an array element or a 77 * dictionary value. In the case of an array element, the _path_ is the path 78 * to the numeric index of the array; in the case of a dictionary value, the 79 * _path_ is the path to the string key for the value to be accessed (or 80 * modified). 81 * 82 * Path components are separated by a period (`.`). To escape literal `.` 83 * characters, encapsulate the given component in backticks. 84 * 85 * Any other tokens in the path must match _exactly_ the way they might be 86 * represented in the document and must be valid JSON. For example, if an 87 * element in the path contains a literal quote, the quote must be escaped 88 * like so: 89 * 90 * @code 91 * foo.qu\"oted.path 92 * @endcode 93 */ 94 95 96 97 /** 98 * @name Commands 99 * 100 * Each of these commands operates on a subdoc_PATH. The actual semantics 101 * of the path depends on the operation. However, in general: 102 * 103 * _Dictionary Paths_ are expected to point to a specific dictionary _key_. For 104 * update operations, the existing value is replaced. For removal operations 105 * the key and value are removed. For 106 * 107 * 108 * @{ 109 */ 110 class Command { 111 public: 112 enum Code { 113 /* These operations are common because they operate on the _value_ only: */ 114 /** Get the value located in the path */ 115 GET = 0x00, 116 117 /** Simply check the path exists */ 118 EXISTS = 0x01, 119 120 /** Replace the value, if the path exists */ 121 REPLACE = 0x02, 122 123 /** Remove the value, if the path exists */ 124 REMOVE = 0x03, 125 126 /* Dictionary operations. Only valid if PATH points to a dictionary. 127 * The _P variants are similar to `mkdir -p` and will create intermediate 128 * path entries if they do not exist. For example, consider an empty 129 * document, an `ADD` command for `foo.bar.baz` will fail (since `foo.bar` 130 * does not exist), however an `ADD_P` command will succeed, creating 131 * `foo` and `bar` as dictionaries, resulting in a document that looks 132 * like this: 133 * {"foo":{"bar":{"baz":VALUE}}} 134 */ 135 136 /** Add or replace a value for the given path */ 137 DICT_UPSERT = 0x04, 138 DICT_UPSERT_P = 0x84, 139 140 /** Add a value for the given path. Fail if the value already exists */ 141 DICT_ADD = 0x05, 142 DICT_ADD_P = 0x85, 143 144 /* Array operations. Only valid if PATH points to an array */ 145 146 /* Note, there is no insert/upsert for an array, since this would require 147 * padding surrounding elements with something else, which is probably not 148 * what a user wants */ 149 150 /* The _P variants will create intermediate path elements, if they do 151 * not exist */ 152 ARRAY_PREPEND = 0x06, 153 ARRAY_PREPEND_P = 0x86, 154 155 ARRAY_APPEND = 0x07, 156 ARRAY_APPEND_P = 0x87, 157 158 /**Adds a value to a list, ensuring that the value does not already exist. 159 * Values added can only be primitives, and the list itself must already 160 * only contain primitives. If any of these is violated, the error 161 * SUBDOC_PATH_MISMATCH is returned. */ 162 ARRAY_ADD_UNIQUE = 0x08, 163 ARRAY_ADD_UNIQUE_P = 0x88, 164 165 /**Inserts a new value at a given position. Existing values will be 166 * pushed back by one */ 167 ARRAY_INSERT = 0x09, 168 169 /* In the protocol this should contain a 64-bit integer 170 * 171 * If the number itself does not fit into a uint64_t (if unsigned) or an 172 * int64_t (if signed), a SUBDOC_NUM_E2BIG error is returned. 173 * 174 * If the resulting item does exist, but is not a signed or unsigned integer, 175 * then a SUBDOC_PATH_MISMATCH error is returned. This is the case for 176 * 'floats' and 'exponents' as well. Only whole integers are supported. 177 */ 178 COUNTER = 0x0A, 179 COUNTER_P = 0x8A, 180 181 /** 182 * Returns the number of elements in a list or key-value pairs in a 183 * dictionary. 184 */ 185 GET_COUNT = 0x0B, 186 187 INVALID = 0xff, 188 FLAG_MKDIR_P = 0x80 189 }; 190 191 uint8_t code; code(code)192 Command(uint8_t code = GET) : code(code) {} uint8_t()193 operator uint8_t() const { return code; } 194 195 /// Whether the command should create intermediates is_mkdir_p()196 bool is_mkdir_p() const { return (code & FLAG_MKDIR_P) != 0; } 197 198 /// Return the base command (with any modifiers stripped) base()199 Code base() const { return static_cast<Code>(code & ~FLAG_MKDIR_P); } 200 201 }; 202 /**@}*/ 203 } 204 205 #endif 206