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_LIST_HPP__
18 #define __TEST_LIST_HPP__
19 #include "nullable_value.hpp"
20 #include "test_utils.hpp"
21 
22 #include <algorithm>
23 
24 namespace test { namespace driver {
25 
26 /**
27  * List wrapped value
28  */
29 template <typename T>
30 class List
31     : public Collection
32     , Comparable<List<T> > {
33 public:
List()34   List()
35       : Collection(CASS_COLLECTION_TYPE_LIST) {}
36 
List(const std::vector<T> & list)37   List(const std::vector<T>& list)
38       : Collection(CASS_COLLECTION_TYPE_LIST, list.size())
39       , list_(list) {
40     // Create the collection
41     for (typename std::vector<T>::const_iterator iterator = list.begin(); iterator != list.end();
42          ++iterator) {
43       T value = *iterator;
44       Collection::append<T>(value);
45       primary_sub_type_ = value.value_type();
46       secondary_sub_type_ = primary_sub_type_;
47     }
48   }
49 
List(const CassValue * value)50   List(const CassValue* value)
51       : Collection(CASS_COLLECTION_TYPE_LIST) {
52     initialize(value);
53   }
54 
append(Collection collection)55   void append(Collection collection) { Collection::append(collection); }
56 
cql_type() const57   std::string cql_type() const {
58     std::string cql_type = "list<" + list_[0].cql_type() + ">";
59     return cql_type;
60   }
61 
cql_value() const62   std::string cql_value() const { return str(); }
63 
64   /**
65    * Comparison operation for driver value list. This comparison is performed in
66    * lexicographical order.
67    *
68    * @param rhs Right hand side to compare
69    * @return -1 if LHS < RHS, 1 if LHS > RHS, and 0 if equal
70    */
compare(const std::vector<T> & rhs) const71   int compare(const std::vector<T>& rhs) const {
72     // Ensure they are the same size
73     if (list_.size() < rhs.size()) return -1;
74     if (list_.size() > rhs.size()) return 1;
75 
76     // Sort the values for lexicographical comparison
77     std::vector<T> lhs_sorted(list_);
78     std::vector<T> rhs_sorted(rhs);
79     std::sort(lhs_sorted.begin(), lhs_sorted.end());
80     std::sort(rhs_sorted.begin(), rhs_sorted.end());
81 
82     // Iterate and compare
83     for (size_t i = 0; i < lhs_sorted.size(); ++i) {
84       int comparison = lhs_sorted[i].compare(rhs_sorted[i]);
85       if (comparison != 0) return comparison;
86     }
87     return 0;
88   }
89 
90   /**
91    * Comparison operation for driver value list. This comparison is performed in
92    * lexicographical order.
93    *
94    * @param rhs Right hand side to compare
95    * @return -1 if LHS < RHS, 1 if LHS > RHS, and 0 if equal
96    */
compare(const List & rhs) const97   int compare(const List& rhs) const { return compare(rhs.list_); }
98 
is_null() const99   bool is_null() const { return Collection::is_null_; }
100 
set(Tuple tuple,size_t index)101   void set(Tuple tuple, size_t index) { Collection::set(tuple, index); }
102 
set(UserType user_type,const std::string & name)103   void set(UserType user_type, const std::string& name) { Collection::set(user_type, name); }
104 
105   /**
106    * Get the size of the list
107    *
108    * @return The number of values in the list
109    */
size() const110   size_t size() const { return list_.size(); }
111 
statement_bind(Statement statement,size_t index)112   void statement_bind(Statement statement, size_t index) {
113     if (is_null()) {
114       ASSERT_EQ(CASS_OK, cass_statement_bind_null(statement.get(), index));
115     } else {
116       ASSERT_EQ(CASS_OK, cass_statement_bind_collection(statement.get(), index, get()));
117     }
118   }
119 
statement_bind(Statement statement,const std::string & name)120   void statement_bind(Statement statement, const std::string& name) {
121     if (is_null()) {
122       ASSERT_EQ(CASS_OK, cass_statement_bind_null_by_name(statement.get(), name.c_str()));
123     } else {
124       ASSERT_EQ(CASS_OK,
125                 cass_statement_bind_collection_by_name(statement.get(), name.c_str(), get()));
126     }
127   }
128 
str() const129   std::string str() const {
130     if (is_null()) {
131       return "null";
132     } else if (list_.empty()) {
133       return "[]";
134     } else {
135       std::stringstream list_string;
136       list_string << "[";
137       for (typename std::vector<T>::const_iterator iterator = list_.begin();
138            iterator != list_.end(); ++iterator) {
139         list_string << (*iterator).cql_value();
140 
141         // Add a comma separation to the list (unless the last element)
142         if ((iterator + 1) != list_.end()) {
143           list_string << ", ";
144         }
145       }
146       list_string << "]";
147       return list_string.str();
148     }
149   }
150 
value() const151   std::vector<T> value() const { return list_; }
152 
collection_type() const153   CassCollectionType collection_type() const { return collection_type_; }
154 
value_type() const155   CassValueType value_type() const { return primary_sub_type_; }
156 
157 private:
158   /**
159    * Values used in the list
160    */
161   std::vector<T> list_;
162 
initialize(const CassValue * value)163   void initialize(const CassValue* value) {
164     // Call the parent class
165     Collection::initialize(value);
166 
167     // Add the values to the list
168     if (!is_null_) {
169       const CassValue* current_value = next();
170       while (current_value) {
171         list_.push_back(T(current_value));
172         current_value = next();
173       }
174     }
175   }
176 };
177 
178 template <class T>
operator <<(std::ostream & os,const List<T> & list)179 inline std::ostream& operator<<(std::ostream& os, const List<T>& list) {
180   os << list.cql_value();
181   return os;
182 }
183 
184 }} // namespace test::driver
185 
186 #endif // __TEST_LIST_HPP__
187