/* -*- 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 #include #include #include #include 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; lcb_STATUS rc; rc = lcb_create(&instance, crst); lcb_createopts_destroy(crst); assert(rc == LCB_SUCCESS); rc = lcb_connect(instance); assert(rc == LCB_SUCCESS); lcb_wait(instance, LCB_WAIT_DEFAULT); rc = lcb_get_bootstrap_status(instance); assert(rc == LCB_SUCCESS); lcb_install_callback(instance, LCB_CALLBACK_SDLOOKUP, (lcb_RESPCALLBACK)subdoc_callback); lcb_install_callback(instance, LCB_CALLBACK_SDMUTATE, (lcb_RESPCALLBACK)subdoc_callback); return instance; } int main() { lcb_STATUS rc; 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); } lcb_wait(instance, LCB_WAIT_DEFAULT); // 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_wait(instance, LCB_WAIT_DEFAULT); } 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 *cmd; lcb_cmdquery_create(&cmd); 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_cmdquery_destroy(cmd); lcb_wait(instance, LCB_WAIT_DEFAULT); } lcb_destroy(instance); }