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