1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2017 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 #pragma once 19 20 #include <cJSON.h> 21 #include <algorithm> 22 #include <cstdint> 23 #include <string> 24 #include <vector> 25 26 #include "collections/collections_types.h" 27 28 namespace Collections { 29 30 /** 31 * Manifest is an object that is constructed from JSON data as per 32 * a set_collections command 33 * 34 * Users of this class can then obtain the revision, separator and 35 * all collections that are included in the manifest. 36 */ 37 class Manifest { 38 public: 39 // Manfifest::Identifier stores/owns name 40 class Identifier : public IdentifierInterface<Identifier> { 41 public: Identifier(const std::string & name,uid_t uid)42 Identifier(const std::string& name, uid_t uid) : name(name), uid(uid) { 43 } 44 45 template <class T> Identifier(const IdentifierInterface<T> & identifier)46 Identifier(const IdentifierInterface<T>& identifier) 47 : name(identifier.getName().data(), identifier.getName().size()), 48 uid(identifier.getUid()) { 49 } 50 getName()51 cb::const_char_buffer getName() const { 52 return {name}; 53 } 54 getUid()55 uid_t getUid() const { 56 return uid; 57 } 58 59 bool operator==(const Collections::Identifier& rhs) const { 60 return rhs.getName() == name.c_str() && rhs.getUid() == uid; 61 } 62 63 private: 64 std::string name; 65 uid_t uid; 66 }; 67 68 /* 69 * Create a manifest from json. 70 * Validates the json as per SET_COLLECTIONS rules. 71 * @param json a string containing the JSON data 72 * @param maxNumberOfCollections an upper limit on the number of collections 73 * allowed, defaults to 1000. 74 */ 75 Manifest(const std::string& json, size_t maxNumberOfCollections = 1000); 76 getSeparator()77 const std::string& getSeparator() const { 78 return separator; 79 } 80 doesDefaultCollectionExist()81 bool doesDefaultCollectionExist() const { 82 return defaultCollectionExists; 83 } 84 85 using container = std::vector<Identifier>; 86 begin()87 container::const_iterator begin() const { 88 return collections.begin(); 89 } 90 end()91 container::const_iterator end() const { 92 return collections.end(); 93 } 94 size()95 size_t size() const { 96 return collections.size(); 97 } 98 99 /// return the UID of the Manifest getUid()100 uid_t getUid() const { 101 return uid; 102 } 103 104 /** 105 * Try and find an identifier in this Manifest (name/uid match) 106 * @return iterator to the matching entry or end() if not found. 107 */ find(const Collections::Identifier & identifier)108 container::const_iterator find( 109 const Collections::Identifier& identifier) const { 110 return std::find_if( 111 begin(), end(), [identifier](const Identifier& entry) { 112 return entry == identifier; 113 }); 114 } 115 116 /// @todo enhance filters with UIDs - this find remains for Filter code find(const char * name)117 container::const_iterator find(const char* name) const { 118 return std::find_if(begin(), end(), [name](const Identifier& entry) { 119 return entry.getName() == name; 120 }); 121 } 122 123 /** 124 * @returns this manifest as a std::string (JSON formatted) 125 */ 126 std::string toJson() const; 127 128 /** 129 * Write to std::cerr this 130 */ 131 void dump() const; 132 133 private: 134 /** 135 * Set defaultCollectionExists to true if name matches $default 136 * @param name C-string collection name 137 */ 138 void enableDefaultCollection(const char* name); 139 140 /** 141 * Get json sub-object from the json object for key and check the type. 142 * @param json The parent object in which to find key. 143 * @param key The key to look for. 144 * @param expectedType The type the found object must be. 145 * @return A cJSON object for key. 146 * @throws std::invalid_argument if key is not found or the wrong type. 147 */ 148 cJSON* getJsonObject(cJSON* json, const char* key, int expectedType); 149 150 /** 151 * Constructor helper function, throws invalid_argument with a string 152 * indicating if the cJSON struct is nullptr or not the expectedType. 153 * 154 * @param errorKey the JSON key associated with the cJSON struct 155 * @param cJsonHandle the struct handed back by cJSON functions 156 * @param expectedType the cJSON type we expect cJsonHandle to be 157 * @throws std::invalid_argument if cJsonHandle is null or !expectedType 158 */ 159 static void throwIfNullOrWrongType(const std::string& errorKey, 160 cJSON* cJsonHandle, 161 int expectedType); 162 163 /** 164 * Check if the C-string input has a length > 0 and < 250. 165 * 166 * @param separator a C-string representing the separator. 167 */ 168 static bool validSeparator(const char* separator); 169 170 /** 171 * Check if the C-string represents a legal collection name. 172 * Current validation is to ensure we block creation of _ prefixed 173 * collections and only accept $default for $ prefixed names. 174 * 175 * @param collection a C-string representing a collection name. 176 */ 177 static bool validCollection(const char* collection); 178 179 friend std::ostream& operator<<(std::ostream& os, const Manifest& manifest); 180 181 bool defaultCollectionExists; 182 std::string separator; 183 container collections; 184 uid_t uid; 185 186 // strings used in JSON parsing 187 static constexpr char const* SeparatorKey = "separator"; 188 static constexpr int SeparatorType = cJSON_String; 189 static constexpr char const* CollectionsKey = "collections"; 190 static constexpr int CollectionsType = cJSON_Array; 191 static constexpr char const* CollectionNameKey = "name"; 192 static constexpr int CollectionNameType = cJSON_String; 193 static constexpr char const* CollectionUidKey = "uid"; 194 static constexpr int CollectionUidType = cJSON_String; 195 }; 196 197 std::ostream& operator<<(std::ostream& os, const Manifest& manifest); 198 199 } // end namespace Collections 200