xref: /6.6.0/subjson/subdoc/subdoc-api.h (revision 3d8f7444)
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_UNKNOWN_COMMAND,
64        GLOBAL_ENOMEM,
65        GLOBAL_ENOSUPPORT,
66        GLOBAL_EINVAL,
67    };
68
69    Code m_code;
70    Error(Code c = SUCCESS) : m_code(c) {}
71    operator int() const { return static_cast<int>(m_code); }
72    bool success() const { return m_code == SUCCESS; }
73    Code code() const { return m_code; }
74    const char *description() const;
75};
76
77/**@name Paths
78 * A Sub-Document _PATH_ is a path to the container of the item you want to
79 * access. Every JSON primitive is stored either as an array element or a
80 * dictionary value. In the case of an array element, the _path_ is the path
81 * to the numeric index of the array; in the case of a dictionary value, the
82 * _path_ is the path to the string key for the value to be accessed (or
83 * modified).
84 *
85 * Path components are separated by a period (`.`). To escape literal `.`
86 * characters, encapsulate the given component in backticks.
87 *
88 * Any other tokens in the path must match _exactly_ the way they might be
89 * represented in the document and must be valid JSON. For example, if an
90 * element in the path contains a literal quote, the quote must be escaped
91 * like so:
92 *
93 * @code
94 * foo.qu\"oted.path
95 * @endcode
96 */
97
98
99
100/**
101 * @name Commands
102 *
103 * Each of these commands operates on a subdoc_PATH. The actual semantics
104 * of the path depends on the operation. However, in general:
105 *
106 * _Dictionary Paths_ are expected to point to a specific dictionary _key_. For
107 * update operations, the existing value is replaced. For removal operations
108 * the key and value are removed. For
109 *
110 *
111 * @{
112 */
113class Command {
114public:
115    enum Code {
116        /* These operations are common because they operate on the _value_ only: */
117        /** Get the value located in the path */
118        GET = 0x00,
119
120        /** Simply check the path exists */
121        EXISTS = 0x01,
122
123        /** Replace the value, if the path exists */
124        REPLACE = 0x02,
125
126        /** Remove the value, if the path exists */
127        REMOVE = 0x03,
128
129        /* Dictionary operations. Only valid if PATH points to a dictionary.
130         * The _P variants are similar to `mkdir -p` and will create intermediate
131         * path entries if they do not exist. For example, consider an empty
132         * document, an `ADD` command for `foo.bar.baz` will fail (since `foo.bar`
133         * does not exist), however an `ADD_P` command will succeed, creating
134         * `foo` and `bar` as dictionaries, resulting in a document that looks
135         * like this:
136         * {"foo":{"bar":{"baz":VALUE}}}
137         */
138
139        /** Add or replace a value for the given path */
140        DICT_UPSERT = 0x04,
141        DICT_UPSERT_P = 0x84,
142
143        /** Add a value for the given path. Fail if the value already exists */
144        DICT_ADD = 0x05,
145        DICT_ADD_P = 0x85,
146
147        /* Array operations. Only valid if PATH points to an array */
148
149        /* Note, there is no insert/upsert for an array, since this would require
150         * padding surrounding elements with something else, which is probably not
151         * what a user wants */
152
153        /* The _P variants will create intermediate path elements, if they do
154         * not exist */
155        ARRAY_PREPEND = 0x06,
156        ARRAY_PREPEND_P = 0x86,
157
158        ARRAY_APPEND = 0x07,
159        ARRAY_APPEND_P = 0x87,
160
161        /**Adds a value to a list, ensuring that the value does not already exist.
162         * Values added can only be primitives, and the list itself must already
163         * only contain primitives. If any of these is violated, the error
164         * SUBDOC_PATH_MISMATCH is returned. */
165        ARRAY_ADD_UNIQUE = 0x08,
166        ARRAY_ADD_UNIQUE_P = 0x88,
167
168        /**Inserts a new value at a given position. Existing values will be
169         * pushed back by one */
170        ARRAY_INSERT = 0x09,
171
172        /* In the protocol this should contain a 64-bit integer
173         *
174         * If the number itself does not fit into a uint64_t (if unsigned) or an
175         * int64_t (if signed), a SUBDOC_NUM_E2BIG error is returned.
176         *
177         * If the resulting item does exist, but is not a signed or unsigned integer,
178         * then a SUBDOC_PATH_MISMATCH error is returned. This is the case for
179         * 'floats' and 'exponents' as well. Only whole integers are supported.
180         */
181        COUNTER = 0x0A,
182        COUNTER_P = 0x8A,
183
184        INVALID = 0xff,
185        FLAG_MKDIR_P = 0x80
186    };
187
188    uint8_t code;
189    Command(uint8_t code = GET) : code(code) {}
190    operator uint8_t() const { return code; }
191
192    /// Whether the command should create intermediates
193    bool is_mkdir_p() const { return (code & FLAG_MKDIR_P) != 0; }
194
195    /// Return the base command (with any modifiers stripped)
196    Code base() const { return static_cast<Code>(code & ~FLAG_MKDIR_P); }
197
198};
199/**@}*/
200}
201
202#endif
203