Couchbase C Client  3.2.4
Asynchronous C Client for Couchbase
example/subdoc/subdoc-xattrs.c

Shows how to work with XATTRs using subdocument API.

/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright 2017-2020 Couchbase, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
static void subdoc_callback(lcb_INSTANCE *instance, int type, const lcb_RESPSUBDOC *resp)
{
lcb_STATUS rc = lcb_respsubdoc_status(resp);
size_t idx, total;
if (rc != LCB_SUCCESS) {
printf("Failure: %s\n", lcb_strerror_short(rc));
return;
}
total = lcb_respsubdoc_result_size(resp);
for (idx = 0; idx < total; idx++) {
const char *value;
size_t nvalue;
rc = lcb_respsubdoc_result_status(resp, idx);
lcb_respsubdoc_result_value(resp, idx, &value, &nvalue);
printf("[%lu]: 0x%x. %.*s\n", idx, rc, (int)nvalue, value);
}
}
static void n1qlrow_callback(lcb_INSTANCE *instance, int type, const lcb_RESPQUERY *resp)
{
lcb_STATUS rc = lcb_respquery_status(resp);
const char *row;
size_t nrow;
lcb_respquery_row(resp, &row, &nrow);
if (rc != LCB_SUCCESS) {
const lcb_RESPHTTP *http;
uint16_t status;
lcb_respquery_http_response(resp, &http);
printf("Failure: 0x%x, %s\n", rc, lcb_strerror_short(rc));
lcb_resphttp_http_status(http, &status);
printf("HTTP status: %d\n", (int)status);
{
const char *const *hdr;
lcb_resphttp_headers(http, &hdr);
for (; hdr && *hdr; hdr++) {
printf("%s", *hdr);
if (hdr + 1) {
printf(" = %s", *(++hdr));
}
printf("\n");
}
}
printf("%.*s\n", (int)nrow, row);
return;
}
char *start = "{\"docID\":\"";
char *stop = "\"";
char *key = strstr(row, start);
if (key == NULL || key != row) {
return;
}
key += strlen(start);
char *z = strstr(key, stop);
if (z == NULL) {
return;
}
*z = '\0';
lcb_sched_enter(instance);
{
char *path = "discounts.jsmith123";
lcb_SUBDOCSPECS *specs;
lcb_subdocspecs_create(&specs, 2);
lcb_subdocspecs_exists(specs, 0, LCB_SUBDOCSPECS_F_XATTRPATH, path, strlen(path));
lcb_subdocspecs_exists(specs, 1, LCB_SUBDOCSPECS_F_XATTRPATH, path, strlen(path));
lcb_CMDSUBDOC *cmd;
lcb_cmdsubdoc_create(&cmd);
lcb_cmdsubdoc_key(cmd, key, strlen(key));
lcb_cmdsubdoc_specs(cmd, specs);
rc = lcb_subdoc(instance, NULL, cmd);
lcb_subdocspecs_destroy(specs);
lcb_cmdsubdoc_destroy(cmd);
assert(rc == LCB_SUCCESS);
}
lcb_sched_leave(instance);
}
#define DEFAULT_CONNSTR "couchbase://localhost/travel-sample"
static lcb_INSTANCE *connect_as(char *username, char *password)
{
lcb_CREATEOPTS *crst = NULL;
lcb_createopts_create(&crst, LCB_TYPE_BUCKET);
lcb_createopts_connstr(crst, DEFAULT_CONNSTR, strlen(DEFAULT_CONNSTR));
lcb_createopts_credentials(crst, username, strlen(username), password, strlen(password));
lcb_INSTANCE *instance;
rc = lcb_create(&instance, crst);
lcb_createopts_destroy(crst);
assert(rc == LCB_SUCCESS);
rc = lcb_connect(instance);
assert(rc == LCB_SUCCESS);
rc = lcb_get_bootstrap_status(instance);
assert(rc == LCB_SUCCESS);
lcb_install_callback(instance, LCB_CALLBACK_SDMUTATE, (lcb_RESPCALLBACK)subdoc_callback);
return instance;
}
int main()
{
lcb_INSTANCE *instance;
instance = connect_as("Administrator", "password");
// Add key-value pairs to hotel_10138, representing traveller-Ids and associated discount percentages
{
lcb_SUBDOCSPECS *specs;
lcb_subdocspecs_create(&specs, 4);
{
char *path = "discounts.jsmith123";
char *val = "20";
lcb_subdocspecs_dict_upsert(specs, 0, LCB_SUBDOCSPECS_F_MKINTERMEDIATES | LCB_SUBDOCSPECS_F_XATTRPATH, path,
strlen(path), val, strlen(val));
}
{
char *path = "discounts.pjones356";
char *val = "30";
lcb_subdocspecs_dict_upsert(specs, 1, LCB_SUBDOCSPECS_F_MKINTERMEDIATES | LCB_SUBDOCSPECS_F_XATTRPATH, path,
strlen(path), val, strlen(val));
}
// The following lines, "insert" and "remove", simply demonstrate insertion and
// removal of the same path and value
{
char *path = "discounts.jbrown789";
char *val = "25";
lcb_subdocspecs_dict_add(specs, 2, LCB_SUBDOCSPECS_F_MKINTERMEDIATES | LCB_SUBDOCSPECS_F_XATTRPATH, path,
strlen(path), val, strlen(val));
}
{
char *path = "discounts.jbrown789";
lcb_subdocspecs_remove(specs, 3, LCB_SUBDOCSPECS_F_XATTRPATH, path, strlen(path));
}
char *key = "hotel_10138";
lcb_CMDSUBDOC *cmd;
lcb_cmdsubdoc_create(&cmd);
lcb_cmdsubdoc_key(cmd, key, strlen(key));
lcb_cmdsubdoc_specs(cmd, specs);
rc = lcb_subdoc(instance, NULL, cmd);
lcb_subdocspecs_destroy(specs);
lcb_cmdsubdoc_destroy(cmd);
assert(rc == LCB_SUCCESS);
}
// Add key - value pairs to hotel_10142, again representing traveller - Ids and associated discount percentages
{
lcb_SUBDOCSPECS *specs;
lcb_subdocspecs_create(&specs, 2);
{
char *path = "discounts.jsmith123";
char *val = "15";
lcb_subdocspecs_dict_upsert(specs, 0, LCB_SUBDOCSPECS_F_MKINTERMEDIATES | LCB_SUBDOCSPECS_F_XATTRPATH, path,
strlen(path), val, strlen(val));
}
{
char *path = "discounts.pjones356";
char *val = "10";
lcb_subdocspecs_dict_upsert(specs, 1, LCB_SUBDOCSPECS_F_MKINTERMEDIATES | LCB_SUBDOCSPECS_F_XATTRPATH, path,
strlen(path), val, strlen(val));
}
char *key = "hotel_10142";
lcb_CMDSUBDOC *cmd;
lcb_cmdsubdoc_create(&cmd);
lcb_cmdsubdoc_key(cmd, key, strlen(key));
lcb_cmdsubdoc_specs(cmd, specs);
rc = lcb_subdoc(instance, NULL, cmd);
lcb_subdocspecs_destroy(specs);
lcb_cmdsubdoc_destroy(cmd);
assert(rc == LCB_SUCCESS);
}
// Create a user and assign roles. This user will search for their available discounts.
{
lcb_CMDHTTP *cmd;
char *path = "/settings/rbac/users/local/jsmith123";
char *payload = "password=jsmith123pwd&name=John+Smith"
"&roles=data_reader[travel-sample],query_select[travel-sample],data_writer[travel-sample]";
char *content_type = "application/x-www-form-urlencoded";
lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_MANAGEMENT);
lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_PUT);
lcb_cmdhttp_path(cmd, path, strlen(path));
lcb_cmdhttp_body(cmd, payload, strlen(payload));
lcb_cmdhttp_content_type(cmd, content_type, strlen(content_type));
lcb_http(instance, NULL, cmd);
lcb_cmdhttp_destroy(cmd);
}
lcb_destroy(instance);
// reconnect using new user
instance = connect_as("jsmith123", "jsmith123pwd");
// Perform a N1QL Query to return document IDs from the bucket. These IDs will be
// used to reference each document in turn, and check for extended attributes
// corresponding to discounts.
{
char *query = "SELECT id, meta(`travel-sample`).id AS docID FROM `travel-sample`";
lcb_cmdquery_statement(cmd, query, strlen(query));
lcb_cmdquery_callback(cmd, n1qlrow_callback);
printf("User \"jsmith123\" has discounts in the hotels below:\n");
lcb_query(instance, NULL, cmd);
}
lcb_destroy(instance);
}
Main header file for Couchbase.
#define LCB_SUBDOCSPECS_F_MKINTERMEDIATES
Create intermediate paths.
Definition: couchbase.h:3217
#define LCB_SUBDOCSPECS_F_XATTRPATH
Access document XATTR path.
Definition: couchbase.h:3220
lcb_STATUS lcb_resphttp_headers(const lcb_RESPHTTP *resp, const char *const **headers)
List of key-value headers.
struct lcb_RESPHTTP_ lcb_RESPHTTP
Definition: couchbase.h:1627
@ LCB_HTTP_TYPE_MANAGEMENT
Execute a management API request.
Definition: couchbase.h:1516
void lcb_destroy(lcb_INSTANCE *instance)
Destroy (and release all allocated resources) an instance of lcb.
LCB_INTERNAL_API const char * lcb_strerror_short(lcb_STATUS error)
Get a shorter textual description of an error message.
lcb_STATUS
Error codes returned by the library.
Definition: error.h:212
lcb_STATUS lcb_get_bootstrap_status(lcb_INSTANCE *instance)
Gets the initial bootstrap status.
lcb_STATUS lcb_create(lcb_INSTANCE **instance, const lcb_CREATEOPTS *options)
Create an instance of lcb.
struct lcb_st lcb_INSTANCE
Library handle representing a connection to a cluster and its data buckets.
Definition: couchbase.h:35
lcb_STATUS lcb_connect(lcb_INSTANCE *instance)
Schedule the initial connection This function will schedule the initial connection for the handle.
@ LCB_TYPE_BUCKET
Handle for data access (default)
Definition: couchbase.h:256
lcb_RESPCALLBACK lcb_install_callback(lcb_INSTANCE *instance, int cbtype, lcb_RESPCALLBACK cb)
void(* lcb_RESPCALLBACK)(lcb_INSTANCE *instance, int cbtype, const lcb_RESPBASE *resp)
Callback invoked for responses.
Definition: couchbase.h:554
@ LCB_CALLBACK_SDLOOKUP
<for lcb_storedur3()
Definition: couchbase.h:487
lcb_STATUS lcb_query(lcb_INSTANCE *instance, void *cookie, const lcb_CMDQUERY *cmd)
Execute a N1QL query.
lcb_STATUS lcb_cmdquery_statement(lcb_CMDQUERY *cmd, const char *statement, size_t statement_len)
Sets the actual statement to be executed.
struct lcb_RESPQUERY_ lcb_RESPQUERY
Opaque query response structure.
Definition: couchbase.h:2798
lcb_STATUS lcb_cmdquery_create(lcb_CMDQUERY **cmd)
Create a new lcb_CMDQUERY object.
struct lcb_CMDQUERY_ lcb_CMDQUERY
Opaque query command structure.
Definition: couchbase.h:2803
lcb_STATUS lcb_cmdquery_destroy(lcb_CMDQUERY *cmd)
Free the command structure.
void lcb_sched_leave(lcb_INSTANCE *instance)
Leave the current scheduling context, scheduling the commands within the context to be flushed to the...
void lcb_sched_enter(lcb_INSTANCE *instance)
Enter a scheduling context.
lcb_STATUS lcb_wait(lcb_INSTANCE *instance, lcb_WAITFLAGS flags)
Wait for completion of scheduled operations.
@ LCB_WAIT_DEFAULT
Behave like the old lcb_wait()
Definition: couchbase.h:1814