xref: /6.0.3/subjson/subdoc/subdoc-api.h (revision ea70ef53)
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 = 0x00, /* PROTOCOL_BINARY_RESPONSE_SUCCESS*/
32         /** Document exists, but the given path was not found in the document */
33         PATH_ENOENT = 0x501,
34         /** There was a conflict between the data and the path */
35         PATH_MISMATCH = 0x502,
36         /** The path is not a valid path (i.e. does not parse correctly) */
37         PATH_EINVAL = 0x503,
38         /** The document reference exists, but is not JSON */
39         DOC_NOTJSON = 0x504,
40         /**The requested operation required the value did not already exist, but it exists */
41         DOC_EEXISTS = 0x505,
42         /**The path requested is too long/deep to traverse */
43         PATH_E2BIG = 0x506,
44         /**The number to increment was too big (could not fit in an int64_t) */
45         NUM_E2BIG = 0x507,
46         /**Delta is too big (bigger than INT64_MAX) */
47         DELTA_E2BIG = 0x508,
48         /**Invalid value for insertion. Inserting this value would invalidate
49          * the JSON document */
50         VALUE_CANTINSERT = 0x509,
51         /** Document too deep to parse */
52         DOC_ETOODEEP = 0x50A,
53 
54         /* MEMCACHED ERROR CODES */
55         GLOBAL_UNKNOWN_COMMAND = 0x81,
56         GLOBAL_ENOMEM = 0x82,
57         GLOBAL_ENOSUPPORT = 0x83,
58         GLOBAL_EINVAL = 0x04,
59     };
60 
61     Code m_code;
62     Error(Code c = SUCCESS) : m_code(c) {}
63     operator int() const { return static_cast<int>(m_code); }
64     bool success() const { return m_code == SUCCESS; }
65     const char *description() const;
66 };
67 
68 // Provide definitions for older code (temporary)
69 #define SUBDOC_XERR(X) \
70     X(SUCCESS) \
71     X(PATH_ENOENT) \
72     X(PATH_MISMATCH) \
73     X(PATH_EINVAL) \
74     X(DOC_NOTJSON) \
75     X(DOC_EEXISTS) \
76     X(PATH_E2BIG) \
77     X(NUM_E2BIG) \
78     X(DELTA_E2BIG) \
79     X(VALUE_CANTINSERT) \
80     X(DOC_ETOODEEP) \
81     X(GLOBAL_UNKNOWN_COMMAND) \
82     X(GLOBAL_EINVAL)
83 
84 /**@name Paths
85  * A Sub-Document _PATH_ is a path to the container of the item you want to
86  * access. Every JSON primitive is stored either as an array element or a
87  * dictionary value. In the case of an array element, the _path_ is the path
88  * to the numeric index of the array; in the case of a dictionary value, the
89  * _path_ is the path to the string key for the value to be accessed (or
90  * modified).
91  *
92  * Path components are separated by a period (`.`). To escape literal `.`
93  * characters, encapsulate the given component in backticks.
94  *
95  * Any other tokens in the path must match _exactly_ the way they might be
96  * represented in the document and must be valid JSON. For example, if an
97  * element in the path contains a literal quote, the quote must be escaped
98  * like so:
99  *
100  * @code
101  * foo.qu\"oted.path
102  * @endcode
103  */
104 
105 
106 
107 /**
108  * @name Commands
109  *
110  * Each of these commands operates on a subdoc_PATH. The actual semantics
111  * of the path depends on the operation. However, in general:
112  *
113  * _Dictionary Paths_ are expected to point to a specific dictionary _key_. For
114  * update operations, the existing value is replaced. For removal operations
115  * the key and value are removed. For
116  *
117  *
118  * @{
119  */
120 class Command {
121 public:
122     enum Code {
123         /* These operations are common because they operate on the _value_ only: */
124         /** Get the value located in the path */
125         GET = 0x00,
126 
127         /** Simply check the path exists */
128         EXISTS = 0x01,
129 
130         /** Replace the value, if the path exists */
131         REPLACE = 0x02,
132 
133         /** Remove the value, if the path exists */
134         REMOVE = 0x03,
135 
136         /* Dictionary operations. Only valid if PATH points to a dictionary.
137          * The _P variants are similar to `mkdir -p` and will create intermediate
138          * path entries if they do not exist. For example, consider an empty
139          * document, an `ADD` command for `foo.bar.baz` will fail (since `foo.bar`
140          * does not exist), however an `ADD_P` command will succeed, creating
141          * `foo` and `bar` as dictionaries, resulting in a document that looks
142          * like this:
143          * {"foo":{"bar":{"baz":VALUE}}}
144          */
145 
146         /** Add or replace a value for the given path */
147         DICT_UPSERT = 0x04,
148         DICT_UPSERT_P = 0x84,
149 
150         /** Add a value for the given path. Fail if the value already exists */
151         DICT_ADD = 0x05,
152         DICT_ADD_P = 0x85,
153 
154         /* Array operations. Only valid if PATH points to an array */
155 
156         /* Note, there is no insert/upsert for an array, since this would require
157          * padding surrounding elements with something else, which is probably not
158          * what a user wants */
159 
160         /* The _P variants will create intermediate path elements, if they do
161          * not exist */
162         ARRAY_PREPEND = 0x06,
163         ARRAY_PREPEND_P = 0x86,
164 
165         ARRAY_APPEND = 0x07,
166         ARRAY_APPEND_P = 0x87,
167 
168         /**Adds a value to a list, ensuring that the value does not already exist.
169          * Values added can only be primitives, and the list itself must already
170          * only contain primitives. If any of these is violated, the error
171          * SUBDOC_PATH_MISMATCH is returned. */
172         ARRAY_ADD_UNIQUE = 0x08,
173         ARRAY_ADD_UNIQUE_P = 0x88,
174 
175 
176         /* In the protocol this should contain a 64-bit integer
177          *
178          * If the number itself does not fit into a uint64_t (if unsigned) or an
179          * int64_t (if signed), a SUBDOC_NUM_E2BIG error is returned.
180          *
181          * If the resulting item does exist, but is not a signed or unsigned integer,
182          * then a SUBDOC_PATH_MISMATCH error is returned. This is the case for
183          * 'floats' and 'exponents' as well. Only whole integers are supported.
184          */
185         INCREMENT = 0x09,
186         INCREMENT_P = 0x89,
187         DECREMENT = 0x0A,
188         DECREMENT_P = 0x8A,
189 
190         INVALID = 0xff,
191         FLAG_MKDIR_P = 0x80
192     };
193 
194     uint8_t code;
195     Command(uint8_t code = GET) : code(code) {}
196     operator uint8_t() const { return code; }
197 
198     bool is_mkdir_p() const { return (code & FLAG_MKDIR_P) != 0; }
199 };
200 
201 #define SUBDOC_XOPCODES(X) \
202     X(GET) \
203     X(EXISTS) \
204     X(REPLACE) \
205     X(REMOVE) \
206     X(DICT_UPSERT) \
207     X(DICT_UPSERT_P) \
208     X(DICT_ADD) \
209     X(DICT_ADD_P) \
210     X(ARRAY_PREPEND) \
211     X(ARRAY_PREPEND_P) \
212     X(ARRAY_APPEND) \
213     X(ARRAY_APPEND_P) \
214     X(ARRAY_ADD_UNIQUE) \
215     X(ARRAY_ADD_UNIQUE_P) \
216     X(INCREMENT) \
217     X(INCREMENT_P) \
218     X(DECREMENT) \
219     X(DECREMENT_P)
220 /**@}*/
221 }
222 
223 #define X(b) static const Subdoc::Error::Code SUBDOC_STATUS_##b = Subdoc::Error::b;
224 SUBDOC_XERR(X)
225 #undef X
226 
227 static const int SUBDOC_CMD_FLAG_MKDIR_P = 0x80;
228 #define X(b) static const Subdoc::Command::Code SUBDOC_CMD_##b = Subdoc::Command::b;
229 SUBDOC_XOPCODES(X)
230 #undef X
231 static const Subdoc::Command::Code SUBDOC_CMD_DELETE = SUBDOC_CMD_REMOVE;
232 
233 #endif
234