cequel 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +2 -2
- data/README.md +8 -0
- data/lib/cequel/errors.rb +2 -0
- data/lib/cequel/metal/new_relic_instrumentation.rb +2 -1
- data/lib/cequel/record.rb +8 -0
- data/lib/cequel/record/schema.rb +30 -23
- data/lib/cequel/schema.rb +3 -2
- data/lib/cequel/schema/column.rb +11 -1
- data/lib/cequel/schema/keyspace.rb +18 -7
- data/lib/cequel/schema/patch.rb +152 -0
- data/lib/cequel/schema/table.rb +55 -137
- data/lib/cequel/schema/table_desc_dsl.rb +196 -0
- data/lib/cequel/schema/table_differ.rb +112 -0
- data/lib/cequel/schema/table_property.rb +14 -0
- data/lib/cequel/schema/table_reader.rb +81 -85
- data/lib/cequel/schema/table_updater.rb +0 -17
- data/lib/cequel/schema/table_writer.rb +10 -9
- data/lib/cequel/version.rb +1 -1
- data/spec/examples/metal/data_set_spec.rb +156 -153
- data/spec/examples/metal/keyspace_spec.rb +4 -4
- data/spec/examples/record/associations_spec.rb +6 -0
- data/spec/examples/record/mass_assignment_spec.rb +2 -2
- data/spec/examples/record/properties_spec.rb +1 -0
- data/spec/examples/record/record_set_spec.rb +1 -1
- data/spec/examples/schema/patch_spec.rb +190 -0
- data/spec/examples/schema/table_differ_spec.rb +280 -0
- data/spec/examples/schema/table_reader_spec.rb +379 -354
- data/spec/examples/schema/table_updater_spec.rb +0 -12
- data/spec/examples/spec_helper.rb +5 -5
- data/spec/examples/spec_support/preparation_spec.rb +4 -0
- data/spec/support/helpers.rb +23 -0
- metadata +9 -6
- data/lib/cequel/schema/create_table_dsl.rb +0 -88
- data/lib/cequel/schema/table_synchronizer.rb +0 -180
- data/spec/examples/schema/table_synchronizer_spec.rb +0 -200
@@ -0,0 +1,112 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module Cequel
|
3
|
+
module Schema
|
4
|
+
#
|
5
|
+
# Utility object that calculates a `Patch` to transform one `Table`
|
6
|
+
# into another.
|
7
|
+
#
|
8
|
+
# Currently this support adding columns, adding and removing indexes, and
|
9
|
+
# setting properties on the table. Any other changes are prohibited due to
|
10
|
+
# CQL limitation or data integrity concerns. A `InvalidSchemaMigration` will
|
11
|
+
# be raised if unsupported changes are detected.
|
12
|
+
#
|
13
|
+
class TableDiffer
|
14
|
+
protected def initialize(table_a, table_b)
|
15
|
+
@table_a = table_a
|
16
|
+
@table_b = table_b
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a Patch that will transform table_a in to table_b.
|
20
|
+
#
|
21
|
+
def call
|
22
|
+
(fail InvalidSchemaMigration, "Table renames are not supported") if
|
23
|
+
table_a.name != table_b.name
|
24
|
+
(fail InvalidSchemaMigration, "Changes to key structure is not allowed") if
|
25
|
+
keys_changed?
|
26
|
+
(fail InvalidSchemaMigration, "Type changes are not allowed") if any_types_changed?
|
27
|
+
|
28
|
+
Patch.new(figure_changes)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
attr_reader :table_a, :table_b
|
34
|
+
|
35
|
+
def figure_changes
|
36
|
+
column_changes + property_changes
|
37
|
+
end
|
38
|
+
|
39
|
+
def property_changes
|
40
|
+
if properties_changed? && table_b.properties.any?
|
41
|
+
[Patch::SetTableProperties.new(table_b)]
|
42
|
+
else
|
43
|
+
[]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def column_changes
|
48
|
+
renames
|
49
|
+
.map { |old_and_new_c| Patch::RenameColumn.new(table_b, *old_and_new_c) } +
|
50
|
+
added_columns
|
51
|
+
.map { |new_c| Patch::AddColumn.new(table_b, new_c) } +
|
52
|
+
added_indexes
|
53
|
+
.map { |col_with_new_idx| Patch::AddIndex.new(table_b, col_with_new_idx) } +
|
54
|
+
dropped_indexes
|
55
|
+
.map { |col_with_old_idx| Patch::DropIndex.new(table_b, col_with_old_idx) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def renames
|
59
|
+
table_a.clustering_columns
|
60
|
+
.zip(table_b.clustering_columns)
|
61
|
+
.select { |ks| ks[0].name != ks[1].name }
|
62
|
+
end
|
63
|
+
|
64
|
+
def added_columns
|
65
|
+
table_b
|
66
|
+
.data_columns
|
67
|
+
.reject{|c_a| table_a.data_columns.any?{|c_b| c_b.name == c_a.name } }
|
68
|
+
end
|
69
|
+
|
70
|
+
def added_indexes
|
71
|
+
table_b.columns
|
72
|
+
.select(&:indexed?)
|
73
|
+
.reject{|c| table_a.has_column?(c.name) &&
|
74
|
+
table_a.column(c.name).indexed? } # ignore still indexed columns
|
75
|
+
end
|
76
|
+
|
77
|
+
def dropped_indexes
|
78
|
+
table_a.columns
|
79
|
+
.select(&:indexed?)
|
80
|
+
.reject{|c| !table_b.has_column?(c.name) } # ignore "dropped" columns
|
81
|
+
.reject{|c| table_b.column(c.name).indexed? }
|
82
|
+
end
|
83
|
+
|
84
|
+
def any_types_changed?
|
85
|
+
table_a.columns
|
86
|
+
.select{|c_a| table_b.has_column?(c_a.name) }
|
87
|
+
.any?{|c_a| table_b.column(c_a.name).type != c_a.type}
|
88
|
+
end
|
89
|
+
|
90
|
+
def keys_changed?
|
91
|
+
table_a.partition_key_columns != table_b.partition_key_columns ||
|
92
|
+
table_a.clustering_columns.zip(table_b.clustering_columns)
|
93
|
+
.any? { |ks| !cluster_keys_compatible?(*ks) }
|
94
|
+
end
|
95
|
+
|
96
|
+
def cluster_keys_compatible?(key_a, key_b)
|
97
|
+
return false if key_a.blank? or key_b.blank?
|
98
|
+
|
99
|
+
key_a.type == key_b.type &&
|
100
|
+
key_a.clustering_order == key_b.clustering_order
|
101
|
+
end
|
102
|
+
|
103
|
+
def properties_changed?
|
104
|
+
p_a = table_a.properties.values
|
105
|
+
p_b = table_b.properties.values
|
106
|
+
|
107
|
+
((p_a | p_b) - (p_a & p_b)).any?
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -44,6 +44,20 @@ module Cequel
|
|
44
44
|
"#{@name} = #{value_cql}"
|
45
45
|
end
|
46
46
|
|
47
|
+
# Returns true iff `self` and `other` logically equivalent (same value for
|
48
|
+
# same property).
|
49
|
+
#
|
50
|
+
def ==(other)
|
51
|
+
other.name == self.name &&
|
52
|
+
other.value == self.value
|
53
|
+
end
|
54
|
+
alias_method :eql?, :==
|
55
|
+
|
56
|
+
# Returns a hash code for this object
|
57
|
+
def hash
|
58
|
+
[name, value].hash
|
59
|
+
end
|
60
|
+
|
47
61
|
protected
|
48
62
|
|
49
63
|
def normalized_value=(value)
|
@@ -2,9 +2,8 @@
|
|
2
2
|
module Cequel
|
3
3
|
module Schema
|
4
4
|
#
|
5
|
-
# A TableReader
|
6
|
-
#
|
7
|
-
# that schema
|
5
|
+
# A TableReader interprets table data from the cassandra driver into a table
|
6
|
+
# descriptor (read: `Table`).
|
8
7
|
#
|
9
8
|
class TableReader
|
10
9
|
COMPOSITE_TYPE_PATTERN =
|
@@ -18,25 +17,32 @@ module Cequel
|
|
18
17
|
# database
|
19
18
|
attr_reader :table
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
class << self
|
21
|
+
#
|
22
|
+
# Read the schema defined in the database for a given table and return a
|
23
|
+
# {Table} instance
|
24
|
+
#
|
25
|
+
# @param (see #initialize)
|
26
|
+
# @return (see #read)
|
27
|
+
#
|
28
|
+
def read(keyspace, table_name)
|
29
|
+
table_data = fetch_raw_keyspace(keyspace).table(table_name.to_s)
|
30
|
+
(fail NoSuchTableError) if table_data.blank?
|
31
|
+
|
32
|
+
new(table_data).call
|
33
|
+
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
protected
|
36
|
+
|
37
|
+
def fetch_raw_keyspace(keyspace)
|
38
|
+
cluster = keyspace.cluster
|
39
|
+
cluster.refresh_schema
|
40
|
+
|
41
|
+
(fail NoSuchKeyspaceError, "No such keyspace #{keyspace.name}") unless
|
42
|
+
cluster.has_keyspace?(keyspace.name)
|
43
|
+
|
44
|
+
cluster.keyspace(keyspace.name)
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
42
48
|
#
|
@@ -44,11 +50,11 @@ module Cequel
|
|
44
50
|
# @param table_name [Symbol] name of the table to read
|
45
51
|
# @private
|
46
52
|
#
|
47
|
-
def initialize(
|
48
|
-
@
|
49
|
-
@table = Table.new(
|
53
|
+
def initialize(table_data)
|
54
|
+
@table_data = table_data
|
55
|
+
@table = Table.new(table_data.name,
|
56
|
+
Cassandra::MaterializedView === table_data)
|
50
57
|
end
|
51
|
-
private_class_method(:new)
|
52
58
|
|
53
59
|
#
|
54
60
|
# Read table schema from the database
|
@@ -58,75 +64,70 @@ module Cequel
|
|
58
64
|
#
|
59
65
|
# @api private
|
60
66
|
#
|
61
|
-
def
|
62
|
-
if table_data.
|
63
|
-
read_partition_keys
|
64
|
-
read_clustering_columns
|
65
|
-
read_data_columns
|
66
|
-
read_properties
|
67
|
-
read_table_settings
|
68
|
-
table
|
69
|
-
end
|
70
|
-
end
|
67
|
+
def call
|
68
|
+
return nil if table_data.blank?
|
71
69
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
cluster.keyspace(keyspace.name)
|
81
|
-
.has_materialized_view?(table_name.to_s)
|
70
|
+
read_partition_keys
|
71
|
+
read_clustering_columns
|
72
|
+
read_indexes
|
73
|
+
read_data_columns
|
74
|
+
read_properties
|
75
|
+
read_table_settings
|
76
|
+
|
77
|
+
table
|
82
78
|
end
|
83
79
|
|
84
80
|
protected
|
85
81
|
|
86
|
-
attr_reader :
|
87
|
-
|
88
|
-
private
|
82
|
+
attr_reader :table_data, :table, :indexes
|
89
83
|
|
90
84
|
def read_partition_keys
|
91
85
|
table_data.partition_key.each do |k|
|
92
|
-
table.
|
86
|
+
table.add_column PartitionKey.new(k.name.to_sym, type(k.type))
|
93
87
|
end
|
94
88
|
|
95
89
|
end
|
96
90
|
|
97
91
|
def read_clustering_columns
|
98
|
-
table_data.clustering_columns
|
99
|
-
.each do |c
|
100
|
-
table.
|
92
|
+
table_data.clustering_columns
|
93
|
+
.each do |c|
|
94
|
+
table.add_column ClusteringColumn.new(c.name.to_sym, type(c.type), c.order)
|
101
95
|
end
|
102
96
|
end
|
103
97
|
|
104
|
-
def
|
105
|
-
indexes =
|
98
|
+
def read_indexes
|
99
|
+
@indexes = if table_data.respond_to?(:each_index)
|
100
|
+
Hash[table_data.each_index.map{|i| [i.target, i.name]}]
|
101
|
+
else
|
102
|
+
# materialized view
|
103
|
+
{}
|
104
|
+
end
|
105
|
+
end
|
106
106
|
|
107
|
+
def read_data_columns
|
107
108
|
((table_data.each_column - table_data.partition_key) - table_data.clustering_columns)
|
108
109
|
.each do |c|
|
109
|
-
next if table.
|
110
|
-
|
111
|
-
|
112
|
-
opts = if indexes[c.name]
|
113
|
-
{index: indexes[c.name].to_sym}
|
114
|
-
else
|
115
|
-
{}
|
116
|
-
end
|
117
|
-
table.add_data_column(c.name.to_sym, c.type, opts)
|
118
|
-
when Cassandra::Types::List
|
119
|
-
table.add_list(c.name.to_sym, c.type.value_type)
|
120
|
-
when Cassandra::Types::Set
|
121
|
-
table.add_set(c.name.to_sym, c.type.value_type)
|
122
|
-
when Cassandra::Types::Map
|
123
|
-
table.add_map(c.name.to_sym, c.type.key_type, c.type.value_type)
|
124
|
-
else
|
125
|
-
fail "Unsupported type #{c.type.inspect}"
|
126
|
-
end
|
110
|
+
next if table.has_column?(c.name.to_sym)
|
111
|
+
|
112
|
+
table.add_column interpret_column(c)
|
127
113
|
end
|
128
114
|
end
|
129
115
|
|
116
|
+
def interpret_column(c)
|
117
|
+
case c.type
|
118
|
+
when Cassandra::Types::Simple
|
119
|
+
DataColumn.new(c.name.to_sym, type(c.type), index_name(c))
|
120
|
+
when Cassandra::Types::List
|
121
|
+
List.new(c.name.to_sym, type(c.type.value_type))
|
122
|
+
when Cassandra::Types::Set
|
123
|
+
Set.new(c.name.to_sym, type(c.type.value_type))
|
124
|
+
when Cassandra::Types::Map
|
125
|
+
Map.new(c.name.to_sym, type(c.type.key_type), type(c.type.value_type))
|
126
|
+
else
|
127
|
+
fail "Unsupported type #{c.type.inspect}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
130
131
|
@@prop_extractors = []
|
131
132
|
def self.def_property(name,
|
132
133
|
option_method = name,
|
@@ -136,7 +137,7 @@ module Cequel
|
|
136
137
|
raw_prop_val = table_data.options.public_send(option_method)
|
137
138
|
prop_val = coercion.call(raw_prop_val,table_data)
|
138
139
|
|
139
|
-
table.add_property(name, prop_val)
|
140
|
+
table.add_property TableProperty.build(name, prop_val)
|
140
141
|
}
|
141
142
|
end
|
142
143
|
|
@@ -171,20 +172,15 @@ module Cequel
|
|
171
172
|
table.compact_storage = table_data.options.compact_storage?
|
172
173
|
end
|
173
174
|
|
174
|
-
def
|
175
|
-
|
176
|
-
.table(table_name.to_s)
|
175
|
+
def type(type_info)
|
176
|
+
::Cequel::Type[type_info.kind]
|
177
177
|
end
|
178
178
|
|
179
|
-
def
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
fail(NoSuchKeyspaceError, "No such keyspace #{keyspace.name}") if
|
185
|
-
!cluster.has_keyspace?(keyspace.name)
|
186
|
-
|
187
|
-
cluster
|
179
|
+
def index_name(column_info)
|
180
|
+
if idx_name = indexes[column_info.name]
|
181
|
+
idx_name.to_sym
|
182
|
+
else
|
183
|
+
nil
|
188
184
|
end
|
189
185
|
end
|
190
186
|
end
|
@@ -86,23 +86,6 @@ module Cequel
|
|
86
86
|
add_data_column(Map.new(name, type(key_type), type(value_type)))
|
87
87
|
end
|
88
88
|
|
89
|
-
#
|
90
|
-
# Change an existing column's type
|
91
|
-
#
|
92
|
-
# @param name [Symbol] the name of the column
|
93
|
-
# @param type [Symbol,Type] the new type of the column
|
94
|
-
# @return [void]
|
95
|
-
#
|
96
|
-
# @note Changing the type of a CQL column does not modify the data
|
97
|
-
# currently stored in the column. Thus, client-side handling is needed
|
98
|
-
# to convert old values to the new type at read time. Cequel does not
|
99
|
-
# currently support this functionality, although it may in the future.
|
100
|
-
# Altering column types is not recommended.
|
101
|
-
#
|
102
|
-
def change_column(name, type)
|
103
|
-
add_stmt %Q|ALTER TABLE "#{table_name}" ALTER "#{name}" TYPE #{type}|
|
104
|
-
end
|
105
|
-
|
106
89
|
#
|
107
90
|
# Rename a column
|
108
91
|
#
|
@@ -13,18 +13,16 @@ module Cequel
|
|
13
13
|
# @return (see #apply)
|
14
14
|
#
|
15
15
|
def self.apply(keyspace, table)
|
16
|
-
new(
|
16
|
+
new(table).apply(keyspace)
|
17
17
|
end
|
18
18
|
|
19
19
|
#
|
20
20
|
# @param keyspace [Keyspace] keyspace in which to create the table
|
21
21
|
# @param table [Table] object representation of table schema
|
22
|
-
# @private
|
23
22
|
#
|
24
|
-
def initialize(
|
25
|
-
@
|
23
|
+
def initialize(table)
|
24
|
+
@table = table
|
26
25
|
end
|
27
|
-
private_class_method :new
|
28
26
|
|
29
27
|
#
|
30
28
|
# Create the table in the keyspace
|
@@ -33,14 +31,17 @@ module Cequel
|
|
33
31
|
#
|
34
32
|
# @api private
|
35
33
|
#
|
36
|
-
def apply
|
37
|
-
keyspace.execute(
|
38
|
-
|
34
|
+
def apply(keyspace)
|
35
|
+
statements.each { |statement| keyspace.execute(statement) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def statements
|
39
|
+
[create_statement] + index_statements
|
39
40
|
end
|
40
41
|
|
41
42
|
protected
|
42
43
|
|
43
|
-
attr_reader :
|
44
|
+
attr_reader :table
|
44
45
|
|
45
46
|
private
|
46
47
|
|
data/lib/cequel/version.rb
CHANGED
@@ -2,8 +2,11 @@
|
|
2
2
|
require File.expand_path('../../spec_helper', __FILE__)
|
3
3
|
|
4
4
|
describe Cequel::Metal::DataSet do
|
5
|
+
posts_tn = "posts_#{SecureRandom.hex(4)}"
|
6
|
+
post_act_tn = "post_activity_#{SecureRandom.hex(4)}"
|
7
|
+
|
5
8
|
before :all do
|
6
|
-
cequel.schema.create_table(
|
9
|
+
cequel.schema.create_table(posts_tn) do
|
7
10
|
key :blog_subdomain, :text
|
8
11
|
key :permalink, :text
|
9
12
|
column :title, :text
|
@@ -13,7 +16,7 @@ describe Cequel::Metal::DataSet do
|
|
13
16
|
set :tags, :text
|
14
17
|
map :trackbacks, :timestamp, :text
|
15
18
|
end
|
16
|
-
cequel.schema.create_table
|
19
|
+
cequel.schema.create_table post_act_tn do
|
17
20
|
key :blog_subdomain, :text
|
18
21
|
key :permalink, :text
|
19
22
|
column :visits, :counter
|
@@ -22,14 +25,14 @@ describe Cequel::Metal::DataSet do
|
|
22
25
|
end
|
23
26
|
|
24
27
|
after :each do
|
25
|
-
subdomains = cequel[
|
26
|
-
|
27
|
-
cequel[
|
28
|
+
subdomains = cequel[posts_tn].select(:blog_subdomain)
|
29
|
+
.map { |row| row[:blog_subdomain] }
|
30
|
+
cequel[posts_tn].where(blog_subdomain: subdomains).delete if subdomains.any?
|
28
31
|
end
|
29
32
|
|
30
33
|
after :all do
|
31
|
-
cequel.schema.drop_table(
|
32
|
-
cequel.schema.drop_table(
|
34
|
+
cequel.schema.drop_table(posts_tn)
|
35
|
+
cequel.schema.drop_table(post_act_tn)
|
33
36
|
end
|
34
37
|
|
35
38
|
let(:row_keys) { {blog_subdomain: 'cassandra', permalink: 'big-data'} }
|
@@ -48,53 +51,53 @@ describe Cequel::Metal::DataSet do
|
|
48
51
|
end
|
49
52
|
|
50
53
|
it 'should insert a row' do
|
51
|
-
cequel[
|
52
|
-
expect(cequel[
|
54
|
+
cequel[posts_tn].insert(row)
|
55
|
+
expect(cequel[posts_tn].where(row_keys).first[:title]).to eq('Fun times')
|
53
56
|
end
|
54
57
|
|
55
58
|
it 'should correctly insert a list' do
|
56
|
-
cequel[
|
57
|
-
expect(cequel[
|
59
|
+
cequel[posts_tn].insert(row)
|
60
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).
|
58
61
|
to eq(['Fun', 'Profit'])
|
59
62
|
end
|
60
63
|
|
61
64
|
it 'should correctly insert a set' do
|
62
|
-
cequel[
|
63
|
-
expect(cequel[
|
65
|
+
cequel[posts_tn].insert(row)
|
66
|
+
expect(cequel[posts_tn].where(row_keys).first[:tags]).
|
64
67
|
to eq(Set['cassandra', 'big-data'])
|
65
68
|
end
|
66
69
|
|
67
70
|
it 'should correctly insert a map' do
|
68
|
-
cequel[
|
69
|
-
expect(cequel[
|
71
|
+
cequel[posts_tn].insert(row)
|
72
|
+
expect(cequel[posts_tn].where(row_keys).first[:trackbacks]).
|
70
73
|
to eq(row[:trackbacks])
|
71
74
|
end
|
72
75
|
|
73
76
|
it 'should include ttl argument' do
|
74
|
-
cequel[
|
75
|
-
expect(cequel[
|
77
|
+
cequel[posts_tn].insert(row, :ttl => 10.minutes)
|
78
|
+
expect(cequel[posts_tn].select_ttl(:title).where(row_keys).first.ttl(:title)).
|
76
79
|
to be_within(5).of(10.minutes)
|
77
80
|
end
|
78
81
|
|
79
82
|
it 'should include timestamp argument' do
|
80
|
-
cequel.schema.truncate_table(
|
83
|
+
cequel.schema.truncate_table(posts_tn)
|
81
84
|
time = 1.day.ago
|
82
|
-
cequel[
|
83
|
-
expect(cequel[
|
85
|
+
cequel[posts_tn].insert(row, :timestamp => time)
|
86
|
+
expect(cequel[posts_tn].select_writetime(:title).where(row_keys).
|
84
87
|
first.writetime(:title)).to eq((time.to_f * 1_000_000).to_i)
|
85
88
|
end
|
86
89
|
|
87
90
|
it 'should insert row with given consistency' do
|
88
91
|
expect_query_with_consistency(->(s){/INSERT/ === s.cql}, :one) do
|
89
|
-
cequel[
|
92
|
+
cequel[posts_tn].insert(row, consistency: :one)
|
90
93
|
end
|
91
94
|
end
|
92
95
|
|
93
96
|
it 'should include multiple arguments joined by AND' do
|
94
|
-
cequel.schema.truncate_table(
|
97
|
+
cequel.schema.truncate_table(posts_tn)
|
95
98
|
time = 1.day.ago
|
96
|
-
cequel[
|
97
|
-
result = cequel[
|
99
|
+
cequel[posts_tn].insert(row, :ttl => 600, :timestamp => time)
|
100
|
+
result = cequel[posts_tn].select_ttl(:title).select_writetime(:title).
|
98
101
|
where(row_keys).first
|
99
102
|
expect(result.writetime(:title)).to eq((time.to_f * 1_000_000).to_i)
|
100
103
|
expect(result.ttl(:title)).to be_within(5).of(10.minutes)
|
@@ -103,20 +106,20 @@ describe Cequel::Metal::DataSet do
|
|
103
106
|
|
104
107
|
describe '#update' do
|
105
108
|
it 'should send basic update statement' do
|
106
|
-
cequel[
|
109
|
+
cequel[posts_tn].where(row_keys).
|
107
110
|
update(:title => 'Fun times', :body => 'Fun')
|
108
|
-
expect(cequel[
|
111
|
+
expect(cequel[posts_tn].where(row_keys).
|
109
112
|
first[:title]).to eq('Fun times')
|
110
113
|
end
|
111
114
|
|
112
115
|
it 'should send update statement with options' do
|
113
|
-
cequel.schema.truncate_table(
|
116
|
+
cequel.schema.truncate_table(posts_tn)
|
114
117
|
time = Time.now - 10.minutes
|
115
118
|
|
116
|
-
cequel[
|
119
|
+
cequel[posts_tn].where(row_keys).
|
117
120
|
update({title: 'Fun times', body: 'Fun'}, ttl: 600, timestamp: time)
|
118
121
|
|
119
|
-
row = cequel[
|
122
|
+
row = cequel[posts_tn].
|
120
123
|
select_ttl(:title).select_writetime(:title).
|
121
124
|
where(row_keys).first
|
122
125
|
|
@@ -126,67 +129,67 @@ describe Cequel::Metal::DataSet do
|
|
126
129
|
|
127
130
|
it 'should send update statement with given consistency' do
|
128
131
|
expect_query_with_consistency(->(s){/UPDATE/ === s.cql}, :one) do
|
129
|
-
cequel[
|
132
|
+
cequel[posts_tn].where(row_keys).update(
|
130
133
|
{title: 'Marshmallows'}, consistency: :one)
|
131
134
|
end
|
132
135
|
end
|
133
136
|
|
134
137
|
it 'should overwrite list column' do
|
135
|
-
cequel[
|
138
|
+
cequel[posts_tn].where(row_keys).
|
136
139
|
update(categories: ['Big Data', 'Cassandra'])
|
137
|
-
expect(cequel[
|
140
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).
|
138
141
|
to eq(['Big Data', 'Cassandra'])
|
139
142
|
end
|
140
143
|
|
141
144
|
it 'should overwrite set column' do
|
142
|
-
cequel[
|
143
|
-
expect(cequel[
|
145
|
+
cequel[posts_tn].where(row_keys).update(tags: Set['big-data', 'nosql'])
|
146
|
+
expect(cequel[posts_tn].where(row_keys).first[:tags]).
|
144
147
|
to eq(Set['big-data', 'nosql'])
|
145
148
|
end
|
146
149
|
|
147
150
|
it 'should overwrite map column' do
|
148
151
|
time1 = Time.at(Time.now.to_i)
|
149
152
|
time2 = Time.at(10.minutes.ago.to_i)
|
150
|
-
cequel[
|
153
|
+
cequel[posts_tn].where(row_keys).update(
|
151
154
|
trackbacks: {time1 => 'foo', time2 => 'bar'})
|
152
|
-
expect(cequel[
|
155
|
+
expect(cequel[posts_tn].where(row_keys).first[:trackbacks]).
|
153
156
|
to eq({time1 => 'foo', time2 => 'bar'})
|
154
157
|
end
|
155
158
|
|
156
159
|
it 'should perform various types of update in one go' do
|
157
|
-
cequel[
|
160
|
+
cequel[posts_tn].insert(
|
158
161
|
row_keys.merge(title: 'Big Data',
|
159
162
|
body: 'Cassandra',
|
160
163
|
categories: ['Scalability']))
|
161
|
-
cequel[
|
164
|
+
cequel[posts_tn].where(row_keys).update do
|
162
165
|
set(title: 'Bigger Data')
|
163
166
|
list_append(:categories, 'Fault-Tolerance')
|
164
167
|
end
|
165
|
-
expect(cequel[
|
166
|
-
expect(cequel[
|
168
|
+
expect(cequel[posts_tn].where(row_keys).first[:title]).to eq('Bigger Data')
|
169
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).
|
167
170
|
to eq(%w(Scalability Fault-Tolerance))
|
168
171
|
end
|
169
172
|
|
170
173
|
it 'should use the last value set for a given column' do
|
171
|
-
cequel[
|
174
|
+
cequel[posts_tn].insert(
|
172
175
|
row_keys.merge(title: 'Big Data',
|
173
176
|
body: 'Cassandra',
|
174
177
|
categories: ['Scalability']))
|
175
|
-
cequel[
|
178
|
+
cequel[posts_tn].where(row_keys).update do
|
176
179
|
set(title: 'Bigger Data')
|
177
180
|
set(title: 'Even Bigger Data')
|
178
181
|
end
|
179
|
-
expect(cequel[
|
182
|
+
expect(cequel[posts_tn].where(row_keys).first[:title]).to eq('Even Bigger Data')
|
180
183
|
end
|
181
184
|
end
|
182
185
|
|
183
186
|
describe '#list_prepend' do
|
184
187
|
it 'should prepend a single element to list column' do
|
185
|
-
cequel[
|
188
|
+
cequel[posts_tn].insert(
|
186
189
|
row_keys.merge(categories: ['Big Data', 'Cassandra']))
|
187
|
-
cequel[
|
190
|
+
cequel[posts_tn].where(row_keys).
|
188
191
|
list_prepend(:categories, 'Scalability')
|
189
|
-
expect(cequel[
|
192
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(
|
190
193
|
['Scalability', 'Big Data', 'Cassandra']
|
191
194
|
)
|
192
195
|
end
|
@@ -194,9 +197,9 @@ describe Cequel::Metal::DataSet do
|
|
194
197
|
# breaks in Cassandra 2.0.13+ or 2.1.3+ because reverse order bug was fixed:
|
195
198
|
# https://issues.apache.org/jira/browse/CASSANDRA-8733
|
196
199
|
it 'should prepend multiple elements to list column' do
|
197
|
-
cequel[
|
200
|
+
cequel[posts_tn].insert(
|
198
201
|
row_keys.merge(categories: ['Big Data', 'Cassandra']))
|
199
|
-
cequel[
|
202
|
+
cequel[posts_tn].where(row_keys).
|
200
203
|
list_prepend(:categories, ['Scalability', 'Partition Tolerance'])
|
201
204
|
|
202
205
|
expected = if cequel.bug8733_version?
|
@@ -205,27 +208,27 @@ describe Cequel::Metal::DataSet do
|
|
205
208
|
['Scalability', 'Partition Tolerance', 'Big Data', 'Cassandra']
|
206
209
|
end
|
207
210
|
|
208
|
-
expect(cequel[
|
211
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(expected)
|
209
212
|
end
|
210
213
|
end
|
211
214
|
|
212
215
|
describe '#list_append' do
|
213
216
|
it 'should append single element to list column' do
|
214
|
-
cequel[
|
217
|
+
cequel[posts_tn].insert(
|
215
218
|
row_keys.merge(categories: ['Big Data', 'Cassandra']))
|
216
|
-
cequel[
|
219
|
+
cequel[posts_tn].where(row_keys).
|
217
220
|
list_append(:categories, 'Scalability')
|
218
|
-
expect(cequel[
|
221
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(
|
219
222
|
['Big Data', 'Cassandra', 'Scalability']
|
220
223
|
)
|
221
224
|
end
|
222
225
|
|
223
226
|
it 'should append multiple elements to list column' do
|
224
|
-
cequel[
|
227
|
+
cequel[posts_tn].insert(
|
225
228
|
row_keys.merge(categories: ['Big Data', 'Cassandra']))
|
226
|
-
cequel[
|
229
|
+
cequel[posts_tn].where(row_keys).
|
227
230
|
list_append(:categories, ['Scalability', 'Partition Tolerance'])
|
228
|
-
expect(cequel[
|
231
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(
|
229
232
|
['Big Data', 'Cassandra', 'Scalability', 'Partition Tolerance']
|
230
233
|
)
|
231
234
|
end
|
@@ -233,11 +236,11 @@ describe Cequel::Metal::DataSet do
|
|
233
236
|
|
234
237
|
describe '#list_replace' do
|
235
238
|
it 'should add to list at specified index' do
|
236
|
-
cequel[
|
239
|
+
cequel[posts_tn].insert(
|
237
240
|
row_keys.merge(categories: ['Big Data', 'Cassandra', 'Scalability']))
|
238
|
-
cequel[
|
241
|
+
cequel[posts_tn].where(row_keys).
|
239
242
|
list_replace(:categories, 1, 'C*')
|
240
|
-
expect(cequel[
|
243
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(
|
241
244
|
['Big Data', 'C*', 'Scalability']
|
242
245
|
)
|
243
246
|
end
|
@@ -245,21 +248,21 @@ describe Cequel::Metal::DataSet do
|
|
245
248
|
|
246
249
|
describe '#list_remove' do
|
247
250
|
it 'should remove from list by specified value' do
|
248
|
-
cequel[
|
251
|
+
cequel[posts_tn].insert(
|
249
252
|
row_keys.merge(categories: ['Big Data', 'Cassandra', 'Scalability']))
|
250
|
-
cequel[
|
253
|
+
cequel[posts_tn].where(row_keys).
|
251
254
|
list_remove(:categories, 'Cassandra')
|
252
|
-
expect(cequel[
|
255
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(
|
253
256
|
['Big Data', 'Scalability']
|
254
257
|
)
|
255
258
|
end
|
256
259
|
|
257
260
|
it 'should remove from list by multiple values' do
|
258
|
-
cequel[
|
261
|
+
cequel[posts_tn].insert(
|
259
262
|
row_keys.merge(categories: ['Big Data', 'Cassandra', 'Scalability']))
|
260
|
-
cequel[
|
263
|
+
cequel[posts_tn].where(row_keys).
|
261
264
|
list_remove(:categories, ['Big Data', 'Cassandra'])
|
262
|
-
expect(cequel[
|
265
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).to eq(
|
263
266
|
['Scalability']
|
264
267
|
)
|
265
268
|
end
|
@@ -267,37 +270,37 @@ describe Cequel::Metal::DataSet do
|
|
267
270
|
|
268
271
|
describe '#set_add' do
|
269
272
|
it 'should add one element to set' do
|
270
|
-
cequel[
|
273
|
+
cequel[posts_tn].insert(
|
271
274
|
row_keys.merge(tags: Set['big-data', 'nosql']))
|
272
|
-
cequel[
|
273
|
-
expect(cequel[
|
275
|
+
cequel[posts_tn].where(row_keys).set_add(:tags, 'cassandra')
|
276
|
+
expect(cequel[posts_tn].where(row_keys).first[:tags]).
|
274
277
|
to eq(Set['big-data', 'nosql', 'cassandra'])
|
275
278
|
end
|
276
279
|
|
277
280
|
it 'should add multiple elements to set' do
|
278
|
-
cequel[
|
279
|
-
cequel[
|
281
|
+
cequel[posts_tn].insert(row_keys.merge(tags: Set['big-data', 'nosql']))
|
282
|
+
cequel[posts_tn].where(row_keys).set_add(:tags, 'cassandra')
|
280
283
|
|
281
|
-
expect(cequel[
|
284
|
+
expect(cequel[posts_tn].where(row_keys).first[:tags]).
|
282
285
|
to eq(Set['big-data', 'nosql', 'cassandra'])
|
283
286
|
end
|
284
287
|
end
|
285
288
|
|
286
289
|
describe '#set_remove' do
|
287
290
|
it 'should remove elements from set' do
|
288
|
-
cequel[
|
291
|
+
cequel[posts_tn].insert(
|
289
292
|
row_keys.merge(tags: Set['big-data', 'nosql', 'cassandra']))
|
290
|
-
cequel[
|
291
|
-
expect(cequel[
|
293
|
+
cequel[posts_tn].where(row_keys).set_remove(:tags, 'cassandra')
|
294
|
+
expect(cequel[posts_tn].where(row_keys).first[:tags]).
|
292
295
|
to eq(Set['big-data', 'nosql'])
|
293
296
|
end
|
294
297
|
|
295
298
|
it 'should remove multiple elements from set' do
|
296
|
-
cequel[
|
299
|
+
cequel[posts_tn].insert(
|
297
300
|
row_keys.merge(tags: Set['big-data', 'nosql', 'cassandra']))
|
298
|
-
cequel[
|
301
|
+
cequel[posts_tn].where(row_keys).
|
299
302
|
set_remove(:tags, Set['nosql', 'cassandra'])
|
300
|
-
expect(cequel[
|
303
|
+
expect(cequel[posts_tn].where(row_keys).first[:tags]).
|
301
304
|
to eq(Set['big-data'])
|
302
305
|
end
|
303
306
|
end
|
@@ -307,10 +310,10 @@ describe Cequel::Metal::DataSet do
|
|
307
310
|
time1 = Time.at(Time.now.to_i)
|
308
311
|
time2 = Time.at(10.minutes.ago.to_i)
|
309
312
|
time3 = Time.at(1.hour.ago.to_i)
|
310
|
-
cequel[
|
313
|
+
cequel[posts_tn].insert(row_keys.merge(
|
311
314
|
trackbacks: {time1 => 'foo', time2 => 'bar'}))
|
312
|
-
cequel[
|
313
|
-
expect(cequel[
|
315
|
+
cequel[posts_tn].where(row_keys).map_update(:trackbacks, time3 => 'baz')
|
316
|
+
expect(cequel[posts_tn].where(row_keys).first[:trackbacks]).
|
314
317
|
to eq({time1 => 'foo', time2 => 'bar', time3 => 'baz'})
|
315
318
|
end
|
316
319
|
|
@@ -318,24 +321,24 @@ describe Cequel::Metal::DataSet do
|
|
318
321
|
time1 = Time.at(Time.now.to_i)
|
319
322
|
time2 = Time.at(10.minutes.ago.to_i)
|
320
323
|
time3 = Time.at(1.hour.ago.to_i)
|
321
|
-
cequel[
|
324
|
+
cequel[posts_tn].insert(row_keys.merge(
|
322
325
|
trackbacks: {time1 => 'foo', time2 => 'bar'}))
|
323
|
-
cequel[
|
326
|
+
cequel[posts_tn].where(row_keys).
|
324
327
|
map_update(:trackbacks, time1 => 'FOO', time3 => 'baz')
|
325
|
-
expect(cequel[
|
328
|
+
expect(cequel[posts_tn].where(row_keys).first[:trackbacks]).
|
326
329
|
to eq({time1 => 'FOO', time2 => 'bar', time3 => 'baz'})
|
327
330
|
end
|
328
331
|
end
|
329
332
|
|
330
333
|
describe '#increment' do
|
331
|
-
after { cequel.schema.truncate_table(
|
334
|
+
after { cequel.schema.truncate_table(post_act_tn) }
|
332
335
|
|
333
336
|
it 'should increment counter columns' do
|
334
|
-
cequel[
|
337
|
+
cequel[post_act_tn].
|
335
338
|
where(row_keys).
|
336
339
|
increment(visits: 1, tweets: 2)
|
337
340
|
|
338
|
-
row = cequel[
|
341
|
+
row = cequel[post_act_tn].where(row_keys).first
|
339
342
|
|
340
343
|
expect(row[:visits]).to eq(1)
|
341
344
|
expect(row[:tweets]).to eq(2)
|
@@ -343,13 +346,13 @@ describe Cequel::Metal::DataSet do
|
|
343
346
|
end
|
344
347
|
|
345
348
|
describe '#decrement' do
|
346
|
-
after { cequel.schema.truncate_table(
|
349
|
+
after { cequel.schema.truncate_table(post_act_tn) }
|
347
350
|
|
348
351
|
it 'should decrement counter columns' do
|
349
|
-
cequel[
|
352
|
+
cequel[post_act_tn].where(row_keys).
|
350
353
|
decrement(visits: 1, tweets: 2)
|
351
354
|
|
352
|
-
row = cequel[
|
355
|
+
row = cequel[post_act_tn].where(row_keys).first
|
353
356
|
expect(row[:visits]).to eq(-1)
|
354
357
|
expect(row[:tweets]).to eq(-2)
|
355
358
|
end
|
@@ -357,18 +360,18 @@ describe Cequel::Metal::DataSet do
|
|
357
360
|
|
358
361
|
describe '#delete' do
|
359
362
|
before do
|
360
|
-
cequel[
|
363
|
+
cequel[posts_tn].
|
361
364
|
insert(row_keys.merge(title: 'Big Data', body: 'It\'s big.'))
|
362
365
|
end
|
363
366
|
|
364
367
|
it 'should send basic delete statement' do
|
365
|
-
cequel[
|
366
|
-
expect(cequel[
|
368
|
+
cequel[posts_tn].where(row_keys).delete
|
369
|
+
expect(cequel[posts_tn].where(row_keys).first).to be_nil
|
367
370
|
end
|
368
371
|
|
369
372
|
it 'should send delete statement for specified columns' do
|
370
|
-
cequel[
|
371
|
-
row = cequel[
|
373
|
+
cequel[posts_tn].where(row_keys).delete(:body)
|
374
|
+
row = cequel[posts_tn].where(row_keys).first
|
372
375
|
expect(row[:body]).to be_nil
|
373
376
|
expect(row[:title]).to eq('Big Data')
|
374
377
|
end
|
@@ -376,10 +379,10 @@ describe Cequel::Metal::DataSet do
|
|
376
379
|
it 'should send delete statement with writetime option' do
|
377
380
|
time = Time.now - 10.minutes
|
378
381
|
|
379
|
-
cequel[
|
382
|
+
cequel[posts_tn].where(row_keys).delete(
|
380
383
|
:body, :timestamp => time
|
381
384
|
)
|
382
|
-
row = cequel[
|
385
|
+
row = cequel[posts_tn].select(:body).where(row_keys).first
|
383
386
|
expect(row[:body]).to eq('It\'s big.')
|
384
387
|
# This means timestamp is working, since the earlier timestamp would cause
|
385
388
|
# Cassandra to ignore the deletion
|
@@ -387,25 +390,25 @@ describe Cequel::Metal::DataSet do
|
|
387
390
|
|
388
391
|
it 'should send delete with specified consistency' do
|
389
392
|
expect_query_with_consistency(->(s){/DELETE/ === s.cql}, :one) do
|
390
|
-
cequel[
|
393
|
+
cequel[posts_tn].where(row_keys).delete(:body, :consistency => :one)
|
391
394
|
end
|
392
395
|
end
|
393
396
|
end
|
394
397
|
|
395
398
|
describe '#list_remove_at' do
|
396
399
|
it 'should remove element at specified position from list' do
|
397
|
-
cequel[
|
400
|
+
cequel[posts_tn].
|
398
401
|
insert(row_keys.merge(categories: ['Big Data', 'NoSQL', 'Cassandra']))
|
399
|
-
cequel[
|
400
|
-
expect(cequel[
|
402
|
+
cequel[posts_tn].where(row_keys).list_remove_at(:categories, 1)
|
403
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).
|
401
404
|
to eq(['Big Data', 'Cassandra'])
|
402
405
|
end
|
403
406
|
|
404
407
|
it 'should remove element at specified positions from list' do
|
405
|
-
cequel[
|
408
|
+
cequel[posts_tn].
|
406
409
|
insert(row_keys.merge(categories: ['Big Data', 'NoSQL', 'Cassandra']))
|
407
|
-
cequel[
|
408
|
-
expect(cequel[
|
410
|
+
cequel[posts_tn].where(row_keys).list_remove_at(:categories, 0, 2)
|
411
|
+
expect(cequel[posts_tn].where(row_keys).first[:categories]).
|
409
412
|
to eq(['NoSQL'])
|
410
413
|
end
|
411
414
|
end
|
@@ -415,10 +418,10 @@ describe Cequel::Metal::DataSet do
|
|
415
418
|
time1 = Time.at(Time.now.to_i)
|
416
419
|
time2 = Time.at(10.minutes.ago.to_i)
|
417
420
|
time3 = Time.at(1.hour.ago.to_i)
|
418
|
-
cequel[
|
421
|
+
cequel[posts_tn].insert(row_keys.merge(
|
419
422
|
trackbacks: {time1 => 'foo', time2 => 'bar', time3 => 'baz'}))
|
420
|
-
cequel[
|
421
|
-
expect(cequel[
|
423
|
+
cequel[posts_tn].where(row_keys).map_remove(:trackbacks, time2)
|
424
|
+
expect(cequel[posts_tn].where(row_keys).first[:trackbacks]).
|
422
425
|
to eq({time1 => 'foo', time3 => 'baz'})
|
423
426
|
end
|
424
427
|
|
@@ -426,23 +429,23 @@ describe Cequel::Metal::DataSet do
|
|
426
429
|
time1 = Time.at(Time.now.to_i)
|
427
430
|
time2 = Time.at(10.minutes.ago.to_i)
|
428
431
|
time3 = Time.at(1.hour.ago.to_i)
|
429
|
-
cequel[
|
432
|
+
cequel[posts_tn].insert(row_keys.merge(
|
430
433
|
trackbacks: {time1 => 'foo', time2 => 'bar', time3 => 'baz'}))
|
431
|
-
cequel[
|
432
|
-
expect(cequel[
|
434
|
+
cequel[posts_tn].where(row_keys).map_remove(:trackbacks, time1, time3)
|
435
|
+
expect(cequel[posts_tn].where(row_keys).first[:trackbacks]).
|
433
436
|
to eq({time2 => 'bar'})
|
434
437
|
end
|
435
438
|
end
|
436
439
|
|
437
440
|
describe '#cql' do
|
438
441
|
it 'should generate select statement with all columns' do
|
439
|
-
expect(cequel[
|
442
|
+
expect(cequel[posts_tn].cql.to_s).to eq("SELECT * FROM #{posts_tn}")
|
440
443
|
end
|
441
444
|
end
|
442
445
|
|
443
446
|
describe '#select' do
|
444
447
|
before do
|
445
|
-
cequel[
|
448
|
+
cequel[posts_tn].insert(row_keys.merge(
|
446
449
|
title: 'Big Data',
|
447
450
|
body: 'Fault Tolerance',
|
448
451
|
published_at: Time.now
|
@@ -450,24 +453,24 @@ describe Cequel::Metal::DataSet do
|
|
450
453
|
end
|
451
454
|
|
452
455
|
it 'should generate select statement with given columns' do
|
453
|
-
expect(cequel[
|
456
|
+
expect(cequel[posts_tn].select(:title, :body).where(row_keys).first.
|
454
457
|
keys).to eq(%w(title body))
|
455
458
|
end
|
456
459
|
|
457
460
|
it 'should accept array argument' do
|
458
|
-
expect(cequel[
|
461
|
+
expect(cequel[posts_tn].select([:title, :body]).where(row_keys).first.
|
459
462
|
keys).to eq(%w(title body))
|
460
463
|
end
|
461
464
|
|
462
465
|
it 'should combine multiple selects' do
|
463
|
-
expect(cequel[
|
466
|
+
expect(cequel[posts_tn].select(:title).select(:body).where(row_keys).first.
|
464
467
|
keys).to eq(%w(title body))
|
465
468
|
end
|
466
469
|
end
|
467
470
|
|
468
471
|
describe '#select!' do
|
469
472
|
before do
|
470
|
-
cequel[
|
473
|
+
cequel[posts_tn].insert(row_keys.merge(
|
471
474
|
title: 'Big Data',
|
472
475
|
body: 'Fault Tolerance',
|
473
476
|
published_at: Time.now
|
@@ -475,14 +478,14 @@ describe Cequel::Metal::DataSet do
|
|
475
478
|
end
|
476
479
|
|
477
480
|
it 'should override select statement with given columns' do
|
478
|
-
expect(cequel[
|
481
|
+
expect(cequel[posts_tn].select(:title, :body).select!(:published_at).
|
479
482
|
where(row_keys).first.keys).to eq(%w(published_at))
|
480
483
|
end
|
481
484
|
end
|
482
485
|
|
483
486
|
describe '#where' do
|
484
487
|
before do
|
485
|
-
cequel[
|
488
|
+
cequel[posts_tn].insert(row_keys.merge(
|
486
489
|
title: 'Big Data',
|
487
490
|
body: 'Fault Tolerance',
|
488
491
|
published_at: Time.now
|
@@ -490,49 +493,49 @@ describe Cequel::Metal::DataSet do
|
|
490
493
|
end
|
491
494
|
|
492
495
|
it 'should build WHERE statement from hash' do
|
493
|
-
expect(cequel[
|
496
|
+
expect(cequel[posts_tn].where(blog_subdomain: row_keys[:blog_subdomain]).
|
494
497
|
first[:title]).to eq('Big Data')
|
495
|
-
expect(cequel[
|
498
|
+
expect(cequel[posts_tn].where(blog_subdomain: 'foo').first).to be_nil
|
496
499
|
end
|
497
500
|
|
498
501
|
it 'should build WHERE statement from multi-element hash' do
|
499
|
-
expect(cequel[
|
500
|
-
expect(cequel[
|
502
|
+
expect(cequel[posts_tn].where(row_keys).first[:title]).to eq('Big Data')
|
503
|
+
expect(cequel[posts_tn].where(row_keys.merge(:permalink => 'foo')).
|
501
504
|
first).to be_nil
|
502
505
|
end
|
503
506
|
|
504
507
|
it 'should build WHERE statement with IN' do
|
505
|
-
cequel[
|
508
|
+
cequel[posts_tn].insert(row_keys.merge(
|
506
509
|
blog_subdomain: 'big-data-weekly',
|
507
510
|
title: 'Cassandra',
|
508
511
|
))
|
509
|
-
cequel[
|
512
|
+
cequel[posts_tn].insert(row_keys.merge(
|
510
513
|
blog_subdomain: 'bogus-blog',
|
511
514
|
title: 'Bogus Post',
|
512
515
|
))
|
513
|
-
expect(cequel[
|
516
|
+
expect(cequel[posts_tn].where(
|
514
517
|
:blog_subdomain => %w(cassandra big-data-weekly)
|
515
518
|
).map { |row| row[:title] }).to match_array(['Big Data', 'Cassandra'])
|
516
519
|
end
|
517
520
|
|
518
521
|
it 'should use = if provided one-element array' do
|
519
|
-
expect(cequel[
|
522
|
+
expect(cequel[posts_tn].
|
520
523
|
where(row_keys.merge(blog_subdomain: [row_keys[:blog_subdomain]])).
|
521
524
|
first[:title]).to eq('Big Data')
|
522
525
|
end
|
523
526
|
|
524
527
|
it 'should build WHERE statement from CQL string' do
|
525
|
-
expect(cequel[
|
528
|
+
expect(cequel[posts_tn].where("blog_subdomain = '#{row_keys[:blog_subdomain]}'").
|
526
529
|
first[:title]).to eq('Big Data')
|
527
530
|
end
|
528
531
|
|
529
532
|
it 'should build WHERE statement from CQL string with bind variables' do
|
530
|
-
expect(cequel[
|
533
|
+
expect(cequel[posts_tn].where("blog_subdomain = ?", row_keys[:blog_subdomain]).
|
531
534
|
first[:title]).to eq('Big Data')
|
532
535
|
end
|
533
536
|
|
534
537
|
it 'should aggregate multiple WHERE statements' do
|
535
|
-
expect(cequel[
|
538
|
+
expect(cequel[posts_tn].where(:blog_subdomain => row_keys[:blog_subdomain]).
|
536
539
|
where('permalink = ?', row_keys[:permalink]).
|
537
540
|
first[:title]).to eq('Big Data')
|
538
541
|
end
|
@@ -541,7 +544,7 @@ describe Cequel::Metal::DataSet do
|
|
541
544
|
|
542
545
|
describe '#where!' do
|
543
546
|
before do
|
544
|
-
cequel[
|
547
|
+
cequel[posts_tn].insert(row_keys.merge(
|
545
548
|
title: 'Big Data',
|
546
549
|
body: 'Fault Tolerance',
|
547
550
|
published_at: Time.now
|
@@ -549,7 +552,7 @@ describe Cequel::Metal::DataSet do
|
|
549
552
|
end
|
550
553
|
|
551
554
|
it 'should override chained conditions' do
|
552
|
-
expect(cequel[
|
555
|
+
expect(cequel[posts_tn].where(:permalink => 'bogus').
|
553
556
|
where!(:blog_subdomain => row_keys[:blog_subdomain]).
|
554
557
|
first[:title]).to eq('Big Data')
|
555
558
|
end
|
@@ -557,37 +560,37 @@ describe Cequel::Metal::DataSet do
|
|
557
560
|
|
558
561
|
describe '#limit' do
|
559
562
|
before do
|
560
|
-
cequel[
|
561
|
-
cequel[
|
563
|
+
cequel[posts_tn].insert(row_keys.merge(title: 'Big Data'))
|
564
|
+
cequel[posts_tn].insert(
|
562
565
|
row_keys.merge(permalink: 'marshmallows', title: 'Marshmallows'))
|
563
|
-
cequel[
|
566
|
+
cequel[posts_tn].insert(
|
564
567
|
row_keys.merge(permalink: 'zz-top', title: 'ZZ Top'))
|
565
568
|
end
|
566
569
|
|
567
570
|
it 'should add LIMIT' do
|
568
|
-
expect(cequel[
|
571
|
+
expect(cequel[posts_tn].where(row_keys.slice(:blog_subdomain)).limit(2).
|
569
572
|
map { |row| row[:title] }).to eq(['Big Data', 'Marshmallows'])
|
570
573
|
end
|
571
574
|
end
|
572
575
|
|
573
576
|
describe '#order' do
|
574
577
|
before do
|
575
|
-
cequel[
|
576
|
-
cequel[
|
578
|
+
cequel[posts_tn].insert(row_keys.merge(title: 'Big Data'))
|
579
|
+
cequel[posts_tn].insert(
|
577
580
|
row_keys.merge(permalink: 'marshmallows', title: 'Marshmallows'))
|
578
|
-
cequel[
|
581
|
+
cequel[posts_tn].insert(
|
579
582
|
row_keys.merge(permalink: 'zz-top', title: 'ZZ Top'))
|
580
583
|
end
|
581
584
|
|
582
585
|
it 'should add order' do
|
583
|
-
expect(cequel[
|
586
|
+
expect(cequel[posts_tn].where(row_keys.slice(:blog_subdomain)).
|
584
587
|
order(permalink: 'desc').map { |row| row[:title] }).
|
585
588
|
to eq(['ZZ Top', 'Marshmallows', 'Big Data'])
|
586
589
|
end
|
587
590
|
end
|
588
591
|
|
589
592
|
describe '#consistency' do
|
590
|
-
let(:data_set) { cequel[
|
593
|
+
let(:data_set) { cequel[posts_tn].consistency(:one) }
|
591
594
|
|
592
595
|
it 'should issue SELECT with scoped consistency' do
|
593
596
|
expect_query_with_consistency(anything, :one) { data_set.to_a }
|
@@ -621,7 +624,7 @@ describe Cequel::Metal::DataSet do
|
|
621
624
|
describe 'default consistency' do
|
622
625
|
before(:all) { cequel.default_consistency = :all }
|
623
626
|
after(:all) { cequel.default_consistency = nil }
|
624
|
-
let(:data_set) { cequel[
|
627
|
+
let(:data_set) { cequel[posts_tn] }
|
625
628
|
|
626
629
|
it 'should issue SELECT with default consistency' do
|
627
630
|
expect_query_with_consistency(anything, :all) { data_set.to_a }
|
@@ -653,7 +656,7 @@ describe Cequel::Metal::DataSet do
|
|
653
656
|
end
|
654
657
|
|
655
658
|
describe '#page_size' do
|
656
|
-
let(:data_set) { cequel[
|
659
|
+
let(:data_set) { cequel[posts_tn].page_size(1) }
|
657
660
|
|
658
661
|
it 'should issue SELECT with scoped page size' do
|
659
662
|
expect_query_with_options(->(s){/SELECT/ === s.cql}, :page_size => 1) { data_set.to_a }
|
@@ -661,7 +664,7 @@ describe Cequel::Metal::DataSet do
|
|
661
664
|
end
|
662
665
|
|
663
666
|
describe '#paging_state' do
|
664
|
-
let(:data_set) { cequel[
|
667
|
+
let(:data_set) { cequel[posts_tn].paging_state(nil) }
|
665
668
|
|
666
669
|
it 'should issue SELECT with scoped paging state' do
|
667
670
|
expect_query_with_options(->(s){/SELECT/ === s.cql}, :paging_state => nil) { data_set.to_a }
|
@@ -672,25 +675,25 @@ describe Cequel::Metal::DataSet do
|
|
672
675
|
let(:row) { row_keys.merge(:title => 'Big Data') }
|
673
676
|
|
674
677
|
before do
|
675
|
-
cequel[
|
678
|
+
cequel[posts_tn].insert(row)
|
676
679
|
end
|
677
680
|
|
678
681
|
it 'should enumerate over results' do
|
679
|
-
expect(cequel[
|
682
|
+
expect(cequel[posts_tn].to_a.map { |row| row.select { |k, v| v }}).
|
680
683
|
to eq([row.stringify_keys])
|
681
684
|
end
|
682
685
|
|
683
686
|
it 'should provide results with indifferent access' do
|
684
|
-
expect(cequel[
|
687
|
+
expect(cequel[posts_tn].to_a.first[:blog_permalink]).
|
685
688
|
to eq(row_keys[:blog_permalink])
|
686
689
|
end
|
687
690
|
|
688
691
|
it 'should not run query if no block given to #each' do
|
689
|
-
expect { cequel[
|
692
|
+
expect { cequel[posts_tn].each }.to_not raise_error
|
690
693
|
end
|
691
694
|
|
692
695
|
it 'should return Enumerator if no block given to #each' do
|
693
|
-
expect(cequel[
|
696
|
+
expect(cequel[posts_tn].each.each_with_index.
|
694
697
|
map { |row, i| [row[:blog_permalink], i] }).
|
695
698
|
to eq([[row[:blog_permalink], 0]])
|
696
699
|
end
|
@@ -700,34 +703,34 @@ describe Cequel::Metal::DataSet do
|
|
700
703
|
let(:row) { row_keys.merge(:title => 'Big Data') }
|
701
704
|
|
702
705
|
before do
|
703
|
-
cequel[
|
704
|
-
cequel[
|
706
|
+
cequel[posts_tn].insert(row)
|
707
|
+
cequel[posts_tn].insert(
|
705
708
|
row_keys.merge(:permalink => 'zz-top', :title => 'ZZ Top'))
|
706
709
|
end
|
707
710
|
|
708
711
|
it 'should run a query with LIMIT 1 and return first row' do
|
709
|
-
expect(cequel[
|
712
|
+
expect(cequel[posts_tn].first.select { |k, v| v }).to eq(row.stringify_keys)
|
710
713
|
end
|
711
714
|
end
|
712
715
|
|
713
716
|
describe '#count' do
|
714
717
|
before do
|
715
718
|
4.times do |i|
|
716
|
-
cequel[
|
719
|
+
cequel[posts_tn].insert(row_keys.merge(
|
717
720
|
permalink: "post-#{i}", title: "Post #{i}"))
|
718
721
|
end
|
719
722
|
end
|
720
723
|
|
721
724
|
it 'should raise DangerousQueryError when attempting to count' do
|
722
|
-
expect{ cequel[
|
725
|
+
expect{ cequel[posts_tn].count }.to raise_error(Cequel::Record::DangerousQueryError)
|
723
726
|
end
|
724
727
|
|
725
728
|
it 'should raise DangerousQueryError when attempting to access size' do
|
726
|
-
expect{ cequel[
|
729
|
+
expect{ cequel[posts_tn].size }.to raise_error(Cequel::Record::DangerousQueryError)
|
727
730
|
end
|
728
731
|
|
729
732
|
it 'should raise DangerousQueryError when attempting to access length' do
|
730
|
-
expect{ cequel[
|
733
|
+
expect{ cequel[posts_tn].length }.to raise_error(Cequel::Record::DangerousQueryError)
|
731
734
|
end
|
732
735
|
end
|
733
736
|
end
|