1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #ifndef __TEST_SET_HPP__
18 #define __TEST_SET_HPP__
19 #include "nullable_value.hpp"
20 #include "test_utils.hpp"
21 
22 namespace test { namespace driver {
23 
24 /**
25  * Set wrapped value
26  */
27 template <typename T>
28 class Set
29     : public Collection
30     , Comparable<Set<T> > {
31 public:
Set()32   Set()
33       : Collection(CASS_COLLECTION_TYPE_SET) {}
34 
Set(const std::set<T> & set)35   Set(const std::set<T>& set)
36       : Collection(CASS_COLLECTION_TYPE_SET, set.size())
37       , set_(set) {
38     // Create the collection
39     for (typename std::set<T>::const_iterator iterator = set.begin(); iterator != set.end();
40          ++iterator) {
41       T value = *iterator;
42       Collection::append<T>(value);
43       set_.insert(value);
44       primary_sub_type_ = value.value_type();
45       secondary_sub_type_ = primary_sub_type_;
46     }
47   }
48 
Set(const std::vector<T> & set)49   Set(const std::vector<T>& set)
50       : Collection(CASS_COLLECTION_TYPE_SET, set.size()) {
51     // Create the collection
52     for (typename std::vector<T>::const_iterator iterator = set.begin(); iterator < set.end();
53          ++iterator) {
54       T value = *iterator;
55       Collection::append<T>(value);
56       set_.insert(value);
57       primary_sub_type_ = value.value_type();
58       secondary_sub_type_ = primary_sub_type_;
59     }
60   }
61 
Set(const CassValue * value)62   Set(const CassValue* value)
63       : Collection(CASS_COLLECTION_TYPE_SET) {
64     initialize(value);
65   }
66 
append(Collection collection)67   void append(Collection collection) { Collection::append(collection); }
68 
cql_type() const69   std::string cql_type() const {
70     std::string cql_type = "set<" + (*set_.begin()).cql_type() + ">";
71     return cql_type;
72   }
73 
cql_value() const74   std::string cql_value() const { return str(); }
75 
is_null() const76   bool is_null() const { return Collection::is_null_; }
77 
78   /**
79    * Comparison operation for driver value set. This comparison is performed in
80    * lexicographical order.
81    *
82    * @param rhs Right hand side to compare
83    * @return -1 if LHS < RHS, 1 if LHS > RHS, and 0 if equal
84    */
compare(const std::set<T> & rhs) const85   int compare(const std::set<T>& rhs) const {
86     // Ensure they are the same size
87     if (set_.size() < rhs.size()) return -1;
88     if (set_.size() > rhs.size()) return 1;
89 
90     // Iterate and compare (sets are already sorted)
91     typename std::set<T>::const_iterator rhs_iterator = rhs.begin();
92     for (typename std::set<T>::const_iterator iterator = set_.begin(); iterator != set_.end();
93          ++iterator) {
94       int comparison = (*iterator).compare(*rhs_iterator);
95       if (comparison != 0) return comparison;
96       ++rhs_iterator;
97     }
98     return 0;
99   }
100 
101   /**
102    * Comparison operation for driver value set. This comparison is performed in
103    * lexicographical order.
104    *
105    * @param rhs Right hand side to compare
106    * @return -1 if LHS < RHS, 1 if LHS > RHS, and 0 if equal
107    */
compare(const Set & rhs) const108   int compare(const Set& rhs) const { return compare(rhs.set_); }
109 
set(Tuple tuple,size_t index)110   void set(Tuple tuple, size_t index) { Collection::set(tuple, index); }
111 
set(UserType user_type,const std::string & name)112   void set(UserType user_type, const std::string& name) { Collection::set(user_type, name); }
113 
114   /**
115    * Get the size of the set
116    *
117    * @return The number of values in the set
118    */
size() const119   size_t size() const { return set_.size(); }
120 
statement_bind(Statement statement,size_t index)121   void statement_bind(Statement statement, size_t index) {
122     if (is_null()) {
123       ASSERT_EQ(CASS_OK, cass_statement_bind_null(statement.get(), index));
124     } else {
125       ASSERT_EQ(CASS_OK, cass_statement_bind_collection(statement.get(), index, get()));
126     }
127   }
128 
statement_bind(Statement statement,const std::string & name)129   void statement_bind(Statement statement, const std::string& name) {
130     if (is_null()) {
131       ASSERT_EQ(CASS_OK, cass_statement_bind_null_by_name(statement.get(), name.c_str()));
132     } else {
133       ASSERT_EQ(CASS_OK,
134                 cass_statement_bind_collection_by_name(statement.get(), name.c_str(), get()));
135     }
136   }
137 
str() const138   std::string str() const {
139     if (is_null()) {
140       return "null";
141     } else if (set_.empty()) {
142       return "{}";
143     } else {
144       std::stringstream set_string;
145       set_string << "{";
146       for (typename std::set<T>::const_iterator iterator = set_.begin(); iterator != set_.end();
147            ++iterator) {
148         set_string << (*iterator).cql_value();
149 
150         // Add a comma separation to the set (unless the last element)
151         if (iterator != --set_.end()) {
152           set_string << ", ";
153         }
154       }
155       set_string << "}";
156       return set_string.str();
157     }
158   }
159 
value() const160   std::set<T> value() const { return set_; }
161 
collection_type() const162   CassCollectionType collection_type() const { return collection_type_; }
163 
value_type() const164   CassValueType value_type() const { return primary_sub_type_; }
165 
166 private:
167   /**
168    * Values used in the set
169    */
170   std::set<T> set_;
171 
initialize(const CassValue * value)172   void initialize(const CassValue* value) {
173     // Call the parent class
174     Collection::initialize(value);
175 
176     // Add the values to the set
177     if (!is_null_) {
178       const CassValue* current_value = next();
179       while (current_value) {
180         set_.insert(T(current_value));
181         current_value = next();
182       }
183     }
184   }
185 };
186 
187 template <class T>
operator <<(std::ostream & os,const Set<T> & set)188 inline std::ostream& operator<<(std::ostream& os, const Set<T>& set) {
189   os << set.cql_value();
190   return os;
191 }
192 
193 }} // namespace test::driver
194 
195 #endif // __TEST_SET_HPP__
196