1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2016 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 #ifndef LCB_SUBDOC_H
18 #define LCB_SUBDOC_H
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /**@ingroup lcb-public-api
25  * @defgroup lcb-subdoc Sub-Document API
26  * @brief Experimental in-document API access
27  * @details The sub-document API uses features from the upcoming Couchbase
28  * 4.5 release which allows access to parts of the document. These parts are
29  * called _sub-documents_ and can be accessed using the sub-document API
30  *
31  * @addtogroup lcb-subdoc
32  * @{
33  */
34 
35 /**
36  * @brief Sub-Document command codes
37  *
38  * These command codes should be applied as values to lcb_SDSPEC::sdcmd and
39  * indicate which type of subdoc command the server should perform.
40  */
41 typedef enum {
42     /**
43      * Retrieve the value for a path
44      */
45     LCB_SDCMD_GET = 1,
46 
47     /**
48      * Check if the value for a path exists. If the path exists then the error
49      * code will be @ref LCB_SUCCESS
50      */
51     LCB_SDCMD_EXISTS,
52 
53     /**
54      * Replace the value at the specified path. This operation can work
55      * on any existing and valid path.
56      */
57     LCB_SDCMD_REPLACE,
58 
59     /**
60      * Add the value at the given path, if the given path does not exist.
61      * The penultimate path component must point to an array. The operation
62      * may be used in conjunction with @ref LCB_SDSPEC_F_MKINTERMEDIATES to
63      * create the parent dictionary (and its parents as well) if it does not
64      * yet exist.
65      */
66     LCB_SDCMD_DICT_ADD,
67 
68     /**
69      * Unconditionally set the value at the path. This logically
70      * attempts to perform a @ref LCB_SDCMD_REPLACE, and if it fails, performs
71      * an @ref LCB_SDCMD_DICT_ADD.
72      */
73     LCB_SDCMD_DICT_UPSERT,
74 
75     /**
76      * Prepend the value(s) to the array indicated by the path. The path should
77      * reference an array. When the @ref LCB_SDSPEC_F_MKINTERMEDIATES flag
78      * is specified then the array may be created if it does not exist.
79      *
80      * Note that it is possible to add more than a single value to an array
81      * in an operation (this is valid for this commnand as well as
82      * @ref LCB_SDCMD_ARRAY_ADD_LAST and @ref LCB_SDCMD_ARRAY_INSERT). Multiple
83      * items can be specified by placing a comma between then (the values should
84      * otherwise be valid JSON).
85      */
86     LCB_SDCMD_ARRAY_ADD_FIRST,
87 
88     /**
89      * Identical to @ref LCB_SDCMD_ARRAY_ADD_FIRST but places the item(s)
90      * at the end of the array rather than at the beginning.
91      */
92     LCB_SDCMD_ARRAY_ADD_LAST,
93 
94     /**
95      * Add the value to the array indicated by the path, if the value is not
96      * already in the array. The @ref LCB_SDSPEC_F_MKINTERMEDIATES flag can
97      * be specified to create the array if it does not already exist.
98      *
99      * Currently the value for this operation must be a JSON primitive (i.e.
100      * no arrays or dictionaries) and the existing array itself must also
101      * contain only primitives (otherwise a @ref LCB_SUBDOC_PATH_MISMATCH
102      * error will be received).
103      */
104     LCB_SDCMD_ARRAY_ADD_UNIQUE,
105 
106     /**
107      * Add the value at the given array index. Unlike other array operations,
108      * the path specified should include the actual index at which the item(s)
109      * should be placed, for example `array[2]` will cause the value(s) to be
110      * the 3rd item(s) in the array.
111      *
112      * The array must already exist and the @ref LCB_SDSPEC_F_MKINTERMEDIATES
113      * flag is not honored.
114      */
115     LCB_SDCMD_ARRAY_INSERT,
116 
117     /**
118      * Increment or decrement an existing numeric path. If the number does
119      * not exist, it will be created (though its parents will not, unless
120      * @ref LCB_SDSPEC_F_MKINTERMEDIATES is specified).
121      *
122      * The value for this operation should be a valid JSON-encoded integer and
123      * must be between `INT64_MIN` and `INT64_MAX`, inclusive.
124      */
125     LCB_SDCMD_COUNTER,
126 
127     /**
128      * Remove an existing path in the document.
129      */
130     LCB_SDCMD_REMOVE,
131 
132     /**
133      * Count the number of elements in an array or dictionary
134      */
135     LCB_SDCMD_GET_COUNT,
136 
137     /**
138      * Retrieve the entire document
139      */
140     LCB_SDCMD_GET_FULLDOC,
141 
142     /**
143      * Replace the entire document
144      */
145     LCB_SDCMD_SET_FULLDOC,
146 
147     /**
148      * Remove the entire document
149      */
150     LCB_SDCMD_REMOVE_FULLDOC,
151 
152     LCB_SDCMD_MAX
153 } lcb_SUBDOCOP;
154 
155 /**
156  * @brief Subdoc command specification.
157  * This structure describes an operation and its path, and possibly its value.
158  * This structure is provided in an array to the lcb_CMDSUBDOC::specs field.
159  */
160 typedef struct {
161     /**
162      * The command code, @ref lcb_SUBDOCOP. There is no default for this
163      * value, and it therefore must be set.
164      */
165     lcb_U32 sdcmd;
166 
167     /**
168      * Set of option flags for the command. Currently the only option known
169      * is @ref LCB_SDSPEC_F_MKINTERMEDIATES
170      */
171     lcb_U32 options;
172 
173     /**
174      * Path for the operation. This should be assigned using
175      * @ref LCB_SDSPEC_SET_PATH. The contents of the path should be valid
176      * until the operation is scheduled (lcb_subdoc3())
177      */
178     lcb_KEYBUF path;
179 
180     /**
181      * Value for the operation. This should be assigned using
182      * @ref LCB_SDSPEC_SET_VALUE. The contents of the value should be valid
183      * until the operation is scheduled (i.e. lcb_subdoc3())
184      */
185     lcb_VALBUF value;
186 } lcb_SDSPEC;
187 
188 /** Create intermediate paths */
189 #define LCB_SDSPEC_F_MKINTERMEDIATES (1<<16)
190 
191 /** Access document XATTR path */
192 #define LCB_SDSPEC_F_XATTRPATH (1<<18)
193 
194 /** Access document virtual/materialized path. Implies F_XATTRPATH */
195 #define LCB_SDSPEC_F_XATTR_MACROVALUES (1<<19)
196 
197 /** Access Xattrs of deleted documents */
198 #define LCB_SDSPEC_F_XATTR_DELETED_OK (1<<20)
199 
200 /**
201  * Set the path for an @ref lcb_SDSPEC structure
202  * @param s pointer to spec
203  * @param p the path buffer
204  * @param n the length of the path buffer
205  */
206 #define LCB_SDSPEC_SET_PATH(s, p, n) do { \
207     (s)->path.contig.bytes = p; \
208     (s)->path.contig.nbytes = n; \
209     (s)->path.type = LCB_KV_COPY; \
210 } while (0);
211 
212 /**
213  * Set the value for the @ref lcb_SDSPEC structure
214  * @param s pointer to spec
215  * @param v the value buffer
216  * @param n the length of the value buffer
217  */
218 #define LCB_SDSPEC_SET_VALUE(s, v, n) \
219     LCB_CMD_SET_VALUE(s, v, n)
220 
221 #define LCB_SDSPEC_INIT(spec, cmd_, path_, npath_, val_, nval_) do { \
222     (spec)->sdcmd = cmd_; \
223     LCB_SDSPEC_SET_PATH(spec, path_, npath_); \
224     LCB_CMD_SET_VALUE(spec, val_, nval_); \
225 } while (0);
226 
227 #define LCB_SDMULTI_MODE_INVALID 0
228 #define LCB_SDMULTI_MODE_LOOKUP 1
229 #define LCB_SDMULTI_MODE_MUTATE 2
230 
231 /**
232  * This command flag should be used if the document is to be created
233  * if it does not exist.
234  */
235 #define LCB_CMDSUBDOC_F_UPSERT_DOC (1<<16)
236 
237 /**
238  * This command flag should be used if the document must be created anew.
239  * In this case, it will fail if it already exists
240  */
241 #define LCB_CMDSUBDOC_F_INSERT_DOC (1<<17)
242 
243 /**
244  * Access a potentially deleted document. For internal Couchbase use
245  */
246 #define LCB_CMDSUBDOC_F_ACCESS_DELETED (1<<18)
247 
248 typedef struct {
249     LCB_CMD_BASE;
250 
251     /**
252      * An array of one or more command specifications. The storage
253      * for the array need only persist for the duration of the
254      * lcb_subdoc3() call.
255      *
256      * The specs array must be valid only through the invocation
257      * of lcb_subdoc3(). As such, they can reside on the stack and
258      * be re-used for scheduling multiple commands. See subdoc-simple.cc
259      */
260     const lcb_SDSPEC *specs;
261     /**
262      * Number of entries in #specs
263      */
264     size_t nspecs;
265     /**
266      * If the scheduling of the command failed, the index of the entry which
267      * caused the failure will be written to this pointer.
268      *
269      * If the value is -1 then the failure took place at the command level
270      * and not at the spec level.
271      */
272     int *error_index;
273     /**
274      * Operation mode to use. This can either be @ref LCB_SDMULTI_MODE_LOOKUP
275      * or @ref LCB_SDMULTI_MODE_MUTATE.
276      *
277      * This field may be left empty, in which case the mode is implicitly
278      * derived from the _first_ command issued.
279      */
280     lcb_U32 multimode;
281 } lcb_CMDSUBDOC;
282 
283 /**
284  * Perform one or more subdocument operations.
285  */
286 LIBCOUCHBASE_API
287 lcb_error_t
288 lcb_subdoc3(lcb_t instance, const void *cookie, const lcb_CMDSUBDOC *cmd);
289 
290 /**
291  * Response structure for multi lookups. If the top level response is successful
292  * then the individual results may be retrieved using lcb_sdmlookup_next()
293  */
294 typedef struct {
295     LCB_RESP_BASE
296     const void *responses;
297     /** Use with lcb_backbuf_ref/unref */
298     void *bufh;
299 } lcb_RESPSUBDOC;
300 
301 /**
302  * Structure for a single sub-document mutation or lookup result.
303  * Note that #value and #nvalue are only valid if #status is ::LCB_SUCCESS
304  */
305 typedef struct {
306     /** Value for the mutation (only applicable for ::LCB_SDCMD_COUNTER, currently) */
307     const void *value;
308     /** Length of the value */
309     size_t nvalue;
310     /** Status code */
311     lcb_error_t status;
312 
313     /**
314      * Request index which this result pertains to. This field only
315      * makes sense for multi mutations where not all request specs are returned
316      * in the result
317      */
318     lcb_U8 index;
319 } lcb_SDENTRY;
320 
321 /**
322  * Iterate over the results for a subdocument response.
323  *
324  * @warning
325  * This function _must_ be called from within the callback. The response itself
326  * may contain a pointer to internal stack data which is no longer valid
327  * once the callback exits.
328  *
329  * @param resp the response received from within the callback.
330  * @param[out] out structure to store the current result
331  * @param[in,out] iter internal iterator. First call should initialize this to 0
332  * Note that this value may be 0, in which case only the first response is
333  * returned.
334  *
335  * @return If this function returns nonzero then `out` will contain a valid
336  * entry. If this function returns 0 then `ent` is invalid and no more results
337  * remain for the response.
338  */
339 LIBCOUCHBASE_API
340 int
341 lcb_sdresult_next(const lcb_RESPSUBDOC *resp, lcb_SDENTRY *out, size_t *iter);
342 
343 /**@}*/
344 #ifdef __cplusplus
345 }
346 #endif
347 #endif
348