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;
Error(Code c = SUCCESS)67     Error(Code c = SUCCESS) : m_code(c) {}
operator int() const68     operator int() const { return static_cast<int>(m_code); }
success() const69     bool success() const { return m_code == SUCCESS; }
code() const70     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;
Command(uint8_t code = GET)192     Command(uint8_t code = GET) : code(code) {}
operator uint8_t() const193     operator uint8_t() const { return code; }
194 
195     /// Whether the command should create intermediates
is_mkdir_p() const196     bool is_mkdir_p() const { return (code & FLAG_MKDIR_P) != 0; }
197 
198     /// Return the base command (with any modifiers stripped)
base() const199     Code base() const { return static_cast<Code>(code & ~FLAG_MKDIR_P); }
200 
201 };
202 /**@}*/
203 }
204 
205 #endif
206