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