xref: /5.5.2/subjson/subdoc/subdoc-api.h (revision 65d3f053)
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>
21namespace 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 */
28class Error {
29public:
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;
67    Error(Code c = SUCCESS) : m_code(c) {}
68    operator int() const { return static_cast<int>(m_code); }
69    bool success() const { return m_code == SUCCESS; }
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 */
110class Command {
111public:
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        INVALID = 0xff,
182        FLAG_MKDIR_P = 0x80
183    };
184
185    uint8_t code;
186    Command(uint8_t code = GET) : code(code) {}
187    operator uint8_t() const { return code; }
188
189    /// Whether the command should create intermediates
190    bool is_mkdir_p() const { return (code & FLAG_MKDIR_P) != 0; }
191
192    /// Return the base command (with any modifiers stripped)
193    Code base() const { return static_cast<Code>(code & ~FLAG_MKDIR_P); }
194
195};
196/**@}*/
197}
198
199#endif
200