cequel 0.5.6 → 1.0.0.pre.1
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 +7 -0
- data/lib/cequel.rb +5 -8
- data/lib/cequel/errors.rb +1 -0
- data/lib/cequel/metal.rb +17 -0
- data/lib/cequel/metal/batch.rb +62 -0
- data/lib/cequel/metal/cql_row_specification.rb +26 -0
- data/lib/cequel/metal/data_set.rb +461 -0
- data/lib/cequel/metal/deleter.rb +47 -0
- data/lib/cequel/metal/incrementer.rb +35 -0
- data/lib/cequel/metal/inserter.rb +53 -0
- data/lib/cequel/metal/keyspace.rb +213 -0
- data/lib/cequel/metal/row.rb +48 -0
- data/lib/cequel/metal/row_specification.rb +37 -0
- data/lib/cequel/metal/statement.rb +30 -0
- data/lib/cequel/metal/updater.rb +65 -0
- data/lib/cequel/metal/writer.rb +73 -0
- data/lib/cequel/model.rb +12 -84
- data/lib/cequel/model/association_collection.rb +23 -0
- data/lib/cequel/model/associations.rb +84 -80
- data/lib/cequel/model/base.rb +74 -0
- data/lib/cequel/model/belongs_to_association.rb +31 -0
- data/lib/cequel/model/callbacks.rb +14 -10
- data/lib/cequel/model/collection.rb +255 -0
- data/lib/cequel/model/errors.rb +6 -6
- data/lib/cequel/model/has_many_association.rb +26 -0
- data/lib/cequel/model/mass_assignment.rb +31 -0
- data/lib/cequel/model/persistence.rb +119 -115
- data/lib/cequel/model/properties.rb +89 -87
- data/lib/cequel/model/railtie.rb +21 -14
- data/lib/cequel/model/record_set.rb +285 -0
- data/lib/cequel/model/schema.rb +33 -0
- data/lib/cequel/model/scoped.rb +5 -48
- data/lib/cequel/model/validations.rb +18 -18
- data/lib/cequel/schema.rb +15 -0
- data/lib/cequel/schema/column.rb +135 -0
- data/lib/cequel/schema/create_table_dsl.rb +56 -0
- data/lib/cequel/schema/keyspace.rb +50 -0
- data/lib/cequel/schema/table.rb +120 -0
- data/lib/cequel/schema/table_property.rb +67 -0
- data/lib/cequel/schema/table_reader.rb +139 -0
- data/lib/cequel/schema/table_synchronizer.rb +114 -0
- data/lib/cequel/schema/table_updater.rb +83 -0
- data/lib/cequel/schema/table_writer.rb +80 -0
- data/lib/cequel/schema/update_table_dsl.rb +60 -0
- data/lib/cequel/type.rb +232 -0
- data/lib/cequel/version.rb +1 -1
- data/spec/environment.rb +5 -1
- data/spec/examples/metal/data_set_spec.rb +608 -0
- data/spec/examples/model/associations_spec.rb +84 -74
- data/spec/examples/model/callbacks_spec.rb +66 -59
- data/spec/examples/model/list_spec.rb +393 -0
- data/spec/examples/model/map_spec.rb +229 -0
- data/spec/examples/model/mass_assignment_spec.rb +55 -0
- data/spec/examples/model/naming_spec.rb +11 -4
- data/spec/examples/model/persistence_spec.rb +140 -150
- data/spec/examples/model/properties_spec.rb +122 -75
- data/spec/examples/model/record_set_spec.rb +285 -0
- data/spec/examples/model/schema_spec.rb +44 -0
- data/spec/examples/model/serialization_spec.rb +20 -14
- data/spec/examples/model/set_spec.rb +133 -0
- data/spec/examples/model/spec_helper.rb +0 -10
- data/spec/examples/model/validations_spec.rb +51 -38
- data/spec/examples/schema/table_reader_spec.rb +328 -0
- data/spec/examples/schema/table_synchronizer_spec.rb +172 -0
- data/spec/examples/schema/table_updater_spec.rb +157 -0
- data/spec/examples/schema/table_writer_spec.rb +225 -0
- data/spec/examples/spec_helper.rb +29 -0
- data/spec/examples/type_spec.rb +204 -0
- data/spec/support/helpers.rb +67 -8
- metadata +121 -152
- data/lib/cequel/batch.rb +0 -58
- data/lib/cequel/cql_row_specification.rb +0 -22
- data/lib/cequel/data_set.rb +0 -371
- data/lib/cequel/keyspace.rb +0 -205
- data/lib/cequel/model/class_internals.rb +0 -49
- data/lib/cequel/model/column.rb +0 -20
- data/lib/cequel/model/counter.rb +0 -35
- data/lib/cequel/model/dictionary.rb +0 -126
- data/lib/cequel/model/dirty.rb +0 -53
- data/lib/cequel/model/dynamic.rb +0 -31
- data/lib/cequel/model/inheritable.rb +0 -48
- data/lib/cequel/model/instance_internals.rb +0 -23
- data/lib/cequel/model/local_association.rb +0 -42
- data/lib/cequel/model/magic.rb +0 -79
- data/lib/cequel/model/mass_assignment_security.rb +0 -21
- data/lib/cequel/model/naming.rb +0 -17
- data/lib/cequel/model/observer.rb +0 -42
- data/lib/cequel/model/readable_dictionary.rb +0 -182
- data/lib/cequel/model/remote_association.rb +0 -40
- data/lib/cequel/model/scope.rb +0 -362
- data/lib/cequel/model/subclass_internals.rb +0 -45
- data/lib/cequel/model/timestamps.rb +0 -52
- data/lib/cequel/model/translation.rb +0 -17
- data/lib/cequel/row_specification.rb +0 -63
- data/lib/cequel/statement.rb +0 -23
- data/spec/examples/data_set_spec.rb +0 -444
- data/spec/examples/keyspace_spec.rb +0 -84
- data/spec/examples/model/counter_spec.rb +0 -94
- data/spec/examples/model/dictionary_spec.rb +0 -301
- data/spec/examples/model/dirty_spec.rb +0 -39
- data/spec/examples/model/dynamic_spec.rb +0 -41
- data/spec/examples/model/inheritable_spec.rb +0 -45
- data/spec/examples/model/magic_spec.rb +0 -199
- data/spec/examples/model/mass_assignment_security_spec.rb +0 -13
- data/spec/examples/model/observer_spec.rb +0 -86
- data/spec/examples/model/scope_spec.rb +0 -677
- data/spec/examples/model/timestamps_spec.rb +0 -52
- data/spec/examples/model/translation_spec.rb +0 -23
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1b840b678aaff8377efff196f7e011a37939fbbc
|
4
|
+
data.tar.gz: b0726b2298165f250f382cf13177c425dd819fcd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5606d970c9051fa1e45168b0f249c1e2ebe0be2009fb8ab0270af1d75151c96ee990978c73affe468d85394190dfc2d1abf3516c57c86a4edf20266882e4b47f
|
7
|
+
data.tar.gz: 98d44471f0dfc64ee16bd31168d76793647a22afb6c17d7fe91b85e38bf65ea88f7017486a91d04a5d8b6804153fe6dd7cda133943eb4514e894b046c98e26bb
|
data/lib/cequel.rb
CHANGED
@@ -1,17 +1,14 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
|
-
require 'cassandra-cql'
|
2
|
+
require 'cassandra-cql/1.2'
|
3
3
|
require 'connection_pool'
|
4
4
|
|
5
|
-
require 'cequel/batch'
|
6
5
|
require 'cequel/errors'
|
7
|
-
require 'cequel/
|
8
|
-
require 'cequel/
|
9
|
-
require 'cequel/
|
10
|
-
require 'cequel/row_specification'
|
11
|
-
require 'cequel/statement'
|
6
|
+
require 'cequel/metal'
|
7
|
+
require 'cequel/schema'
|
8
|
+
require 'cequel/type'
|
12
9
|
|
13
10
|
module Cequel
|
14
11
|
def self.connect(configuration = nil)
|
15
|
-
Keyspace.new(configuration || {})
|
12
|
+
Metal::Keyspace.new(configuration || {})
|
16
13
|
end
|
17
14
|
end
|
data/lib/cequel/errors.rb
CHANGED
data/lib/cequel/metal.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'cequel/metal/batch'
|
2
|
+
require 'cequel/metal/cql_row_specification'
|
3
|
+
require 'cequel/metal/data_set'
|
4
|
+
require 'cequel/metal/keyspace'
|
5
|
+
require 'cequel/metal/row'
|
6
|
+
require 'cequel/metal/row_specification'
|
7
|
+
require 'cequel/metal/statement'
|
8
|
+
require 'cequel/metal/writer'
|
9
|
+
require 'cequel/metal/deleter'
|
10
|
+
require 'cequel/metal/incrementer'
|
11
|
+
require 'cequel/metal/inserter'
|
12
|
+
require 'cequel/metal/updater'
|
13
|
+
|
14
|
+
module Cequel
|
15
|
+
module Metal
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module Cequel
|
4
|
+
|
5
|
+
module Metal
|
6
|
+
|
7
|
+
#
|
8
|
+
# Encapsulates a batch operation
|
9
|
+
#
|
10
|
+
# @see Keyspace::batch
|
11
|
+
#
|
12
|
+
class Batch
|
13
|
+
|
14
|
+
#
|
15
|
+
# @param keyspace [Keyspace] the keyspace that this batch will be executed on
|
16
|
+
# @param options [Hash]
|
17
|
+
# @option options (see Keyspace#batch)
|
18
|
+
# @see Keyspace#batch
|
19
|
+
# @todo support batch-level consistency options
|
20
|
+
#
|
21
|
+
def initialize(keyspace, options = {})
|
22
|
+
@keyspace = keyspace
|
23
|
+
@auto_apply = options[:auto_apply]
|
24
|
+
reset
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Add a statement to the batch.
|
29
|
+
#
|
30
|
+
# @param (see Keyspace#execute)
|
31
|
+
#
|
32
|
+
def execute(cql, *bind_vars)
|
33
|
+
@statement.append("#{cql}\n", *bind_vars)
|
34
|
+
@statement_count += 1
|
35
|
+
if @auto_apply && @statement_count >= @auto_apply
|
36
|
+
apply
|
37
|
+
reset
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Send the batch to Cassandra
|
43
|
+
#
|
44
|
+
def apply
|
45
|
+
return if @statement_count.zero?
|
46
|
+
@statement.append("APPLY BATCH\n")
|
47
|
+
@keyspace.execute(*@statement.args)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def reset
|
53
|
+
@statement = Statement.new
|
54
|
+
@statement.append("BEGIN BATCH\n")
|
55
|
+
@statement_count = 0
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Cequel
|
2
|
+
|
3
|
+
module Metal
|
4
|
+
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
class CqlRowSpecification
|
9
|
+
|
10
|
+
def self.build(condition, bind_vars)
|
11
|
+
[new(condition, bind_vars)]
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(condition, bind_vars)
|
15
|
+
@condition, @bind_vars = condition, bind_vars
|
16
|
+
end
|
17
|
+
|
18
|
+
def cql
|
19
|
+
[@condition, *@bind_vars]
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,461 @@
|
|
1
|
+
module Cequel
|
2
|
+
|
3
|
+
module Metal
|
4
|
+
|
5
|
+
#
|
6
|
+
# Encapsulates a data set, specified as a column family and optionally
|
7
|
+
# various query elements.
|
8
|
+
#
|
9
|
+
# @todo Support ALTER, CREATE, CREATE INDEX, DROP
|
10
|
+
#
|
11
|
+
class DataSet
|
12
|
+
|
13
|
+
include Enumerable
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
attr_reader :keyspace, :table_name, :select_columns, :ttl_columns,
|
17
|
+
:writetime_columns, :row_specifications, :sort_order, :row_limit
|
18
|
+
|
19
|
+
def_delegator :keyspace, :execute, :execute_cql
|
20
|
+
def_delegator :keyspace, :write
|
21
|
+
|
22
|
+
#
|
23
|
+
# @param table_name [Symbol] column family for this data set
|
24
|
+
# @param keyspace [Keyspace] keyspace this data set's column family lives in
|
25
|
+
#
|
26
|
+
# @see Keyspace#[]
|
27
|
+
#
|
28
|
+
def initialize(table_name, keyspace)
|
29
|
+
@table_name, @keyspace = table_name, keyspace
|
30
|
+
@select_columns, @ttl_columns, @writetime_columns, @row_specifications,
|
31
|
+
@sort_order = [], [], [], [], {}
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Insert a row into the column family.
|
36
|
+
#
|
37
|
+
# @param [Hash] data column-value pairs. The first entry *must* be the key column.
|
38
|
+
# @param [Options] options options for persisting the row
|
39
|
+
# @option (see #generate_upsert_options)
|
40
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
41
|
+
#
|
42
|
+
def insert(data, options = {})
|
43
|
+
inserter(options) { insert(data) }.execute
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Update rows
|
48
|
+
#
|
49
|
+
# @param [Hash] data column-value pairs
|
50
|
+
# @param [Options] options options for persisting the column data
|
51
|
+
# @option (see #generate_upsert_options)
|
52
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
53
|
+
#
|
54
|
+
def update(*args, &block)
|
55
|
+
if block
|
56
|
+
updater(args.extract_options!, &block).execute
|
57
|
+
else
|
58
|
+
data = args.shift
|
59
|
+
updater(args.extract_options!) { set(data) }.execute
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def increment(data, options = {})
|
64
|
+
incrementer(options) { increment(data) }.execute
|
65
|
+
end
|
66
|
+
|
67
|
+
def decrement(data, options = {})
|
68
|
+
incrementer(options) { decrement(data) }.execute
|
69
|
+
end
|
70
|
+
alias_method :decr, :decrement
|
71
|
+
|
72
|
+
#
|
73
|
+
# Prepend element(s) to a list in the row(s) matched by this data set.
|
74
|
+
#
|
75
|
+
# @param [Symbol] column name of list column to prepend to
|
76
|
+
# @param [Object,Array] elements one element or an array of elements to prepend
|
77
|
+
# @param [Options] options options for persisting the column data
|
78
|
+
# @option (see #generate_upsert_options)
|
79
|
+
# @note If multiple elements are passed, they will appear in the list in reverse order.
|
80
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
81
|
+
#
|
82
|
+
def list_prepend(column, elements, options = {})
|
83
|
+
updater(options) { list_prepend(column, elements) }.execute
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Append element(s) to a list in the row(s) matched by this data set.
|
88
|
+
#
|
89
|
+
# @param [Symbol] column name of list column to append to
|
90
|
+
# @param [Object,Array] elements one element or an array of elements to append
|
91
|
+
# @param [Options] options options for persisting the column data
|
92
|
+
# @option (see #generate_upsert_options)
|
93
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
94
|
+
#
|
95
|
+
def list_append(column, elements, options = {})
|
96
|
+
updater(options) { list_append(column, elements) }.execute
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Replace a list element at a specified index with a new value
|
101
|
+
#
|
102
|
+
# @param [Symbol] column name of list column
|
103
|
+
# @param [Integer] index which element to replace
|
104
|
+
# @param [Object] value new value at this index
|
105
|
+
# @param [Options] options options for persisting the data
|
106
|
+
# @option (see #generate_upsert_options)
|
107
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
108
|
+
#
|
109
|
+
def list_replace(column, index, value, options = {})
|
110
|
+
updater(options) { list_replace(column, index, value) }.execute
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Remove all occurrences of a given value from a list column
|
115
|
+
#
|
116
|
+
# @param [Symbol] column name of list column
|
117
|
+
# @param [Object] value value to remove
|
118
|
+
# @param [Options] options for persisting the data
|
119
|
+
# @option (see #generate_upsert_options)
|
120
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
121
|
+
#
|
122
|
+
def list_remove(column, value, options = {})
|
123
|
+
updater(options) { list_remove(column, value) }.execute
|
124
|
+
end
|
125
|
+
|
126
|
+
#
|
127
|
+
# Remove all occurrences of a given value from a list column
|
128
|
+
#
|
129
|
+
# @param [Symbol] column name of list column
|
130
|
+
# @param [Object] position position in list to remove value from
|
131
|
+
# @param [Options] options for persisting the data
|
132
|
+
# @option (see #generate_upsert_options)
|
133
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
134
|
+
#
|
135
|
+
def list_remove_at(column, *positions)
|
136
|
+
options = positions.extract_options!
|
137
|
+
deleter(options) { list_remove_at(column, *positions) }.execute
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Remove a given key from a map column
|
142
|
+
#
|
143
|
+
# @param [Symbol] column name of map column
|
144
|
+
# @param [Object] key map key to remove
|
145
|
+
# @param [Options] options for persisting the data
|
146
|
+
# @option (see #generate_upsert_options)
|
147
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
148
|
+
#
|
149
|
+
def map_remove(column, *keys)
|
150
|
+
options = keys.extract_options!
|
151
|
+
deleter(options) { map_remove(column, *keys) }.execute
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Add one or more elements to a set
|
156
|
+
#
|
157
|
+
# @param [Symbol] column name of set column
|
158
|
+
# @param [Object,Set] value value or values to add
|
159
|
+
# @param [Options] options for persisting the data
|
160
|
+
# @option (see #generate_upsert_options)
|
161
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
162
|
+
#
|
163
|
+
def set_add(column, values, options = {})
|
164
|
+
updater(options) { set_add(column, values) }.execute
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# Remove one or more elements from a set
|
169
|
+
#
|
170
|
+
# @param [Symbol] column name of set column
|
171
|
+
# @param [Object,Set] value value or values to add
|
172
|
+
# @param [Options] options for persisting the data
|
173
|
+
# @option (see #generate_upsert_options)
|
174
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
175
|
+
#
|
176
|
+
def set_remove(column, value, options = {})
|
177
|
+
updater(options) { set_remove(column, value) }.execute
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Update one or more map elements
|
182
|
+
#
|
183
|
+
# @param [Symbol] column name of set column
|
184
|
+
# @param [Hash] map updates
|
185
|
+
# @param [Options] options for persisting the data
|
186
|
+
# @option (see #generate_upsert_options)
|
187
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
188
|
+
#
|
189
|
+
def map_update(column, updates, options = {})
|
190
|
+
updater(options) { map_update(column, updates) }.execute
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Delete data from the column family
|
195
|
+
#
|
196
|
+
# @param columns zero or more columns to delete. Deletes the entire row if none specified.
|
197
|
+
# @param options persistence options
|
198
|
+
# @note if a enclosed in a Keyspace#batch block, this method will be executed as part of the batch.
|
199
|
+
#
|
200
|
+
def delete(*columns, &block)
|
201
|
+
options = columns.extract_options!
|
202
|
+
if block
|
203
|
+
deleter(options, &block).execute
|
204
|
+
elsif columns.empty?
|
205
|
+
deleter(options) { delete_row }.execute
|
206
|
+
else
|
207
|
+
deleter(options) { delete_columns(*columns) }.execute
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
#
|
212
|
+
# Select specified columns from this data set.
|
213
|
+
#
|
214
|
+
# @param *columns [Symbol,Array] columns to select
|
215
|
+
# @return [DataSet] new data set scoped to specified columns
|
216
|
+
#
|
217
|
+
def select(*columns)
|
218
|
+
clone.tap do |data_set|
|
219
|
+
data_set.select_columns.concat(columns.flatten)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
#
|
224
|
+
# Return the remaining TTL for the specified columns from this data set.
|
225
|
+
#
|
226
|
+
# @param *columns [Symbol,Array] columns to select
|
227
|
+
# @return [DataSet] new data set scoped to specified columns
|
228
|
+
#
|
229
|
+
def select_ttl(*columns)
|
230
|
+
clone.tap do |data_set|
|
231
|
+
data_set.ttl_columns.concat(columns.flatten)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
#
|
236
|
+
# Return the write time for the specified columns in the data set
|
237
|
+
#
|
238
|
+
# @param *columns [Symbol,Array] columns to select
|
239
|
+
# @return [DataSet] new data set scoped to specified columns
|
240
|
+
#
|
241
|
+
def select_writetime(*columns)
|
242
|
+
clone.tap do |data_set|
|
243
|
+
data_set.writetime_columns.concat(columns.flatten)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
#
|
248
|
+
# Select specified columns from this data set, overriding chained scope.
|
249
|
+
#
|
250
|
+
# @param *columns [Symbol,Array] columns to select
|
251
|
+
# @return [DataSet] new data set scoped to specified columns
|
252
|
+
#
|
253
|
+
def select!(*columns)
|
254
|
+
clone.tap do |data_set|
|
255
|
+
data_set.select_columns.replace(columns.flatten)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
#
|
260
|
+
# Add a row_specification to this data set
|
261
|
+
#
|
262
|
+
# @param row_specification [Hash, String] row_specification statement
|
263
|
+
# @param *bind_vars bind variables, only if using a CQL string row_specification
|
264
|
+
# @return [DataSet] new data set scoped to this row_specification
|
265
|
+
# @example Using a simple hash
|
266
|
+
# DB[:posts].where(:title => 'Hey')
|
267
|
+
# @example Using a CQL string
|
268
|
+
# DB[:posts].where("title = 'Hey'")
|
269
|
+
# @example Using a CQL string with bind variables
|
270
|
+
# DB[:posts].where('title = ?', 'Hey')
|
271
|
+
# @example Use another data set as an input -- inner data set must return a single column per row!
|
272
|
+
# DB[:blogs].where(:id => DB[:posts].select(:blog_id).where(:title => 'Hey'))
|
273
|
+
#
|
274
|
+
def where(row_specification, *bind_vars)
|
275
|
+
clone.tap do |data_set|
|
276
|
+
data_set.row_specifications.
|
277
|
+
concat(build_row_specifications(row_specification, bind_vars))
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def where!(row_specification, *bind_vars)
|
282
|
+
clone.tap do |data_set|
|
283
|
+
data_set.row_specifications.
|
284
|
+
replace(build_row_specifications(row_specification, bind_vars))
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
#
|
289
|
+
# Limit the number of rows returned by this data set
|
290
|
+
#
|
291
|
+
# @param limit [Integer] maximum number of rows to return
|
292
|
+
# @return [DataSet] new data set scoped with given limit
|
293
|
+
#
|
294
|
+
def limit(limit)
|
295
|
+
clone.tap { |data_set| data_set.row_limit = limit }
|
296
|
+
end
|
297
|
+
|
298
|
+
#
|
299
|
+
# Control how the result rows are sorted. Note that you can only sort by
|
300
|
+
# clustering keys, and in the case of multiple clustering keys you can only
|
301
|
+
# sort by the schema's clustering order or the reverse of the clustering
|
302
|
+
# order for all keys.
|
303
|
+
#
|
304
|
+
def order(pairs)
|
305
|
+
clone.tap do |data_set|
|
306
|
+
data_set.sort_order.merge!(pairs.symbolize_keys)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
# Enumerate over rows in this data set. Along with #each, all other
|
312
|
+
# Enumerable methods are implemented.
|
313
|
+
#
|
314
|
+
# @yield [Hash] result rows
|
315
|
+
# @return [Enumerator] enumerator for rows, if no block given
|
316
|
+
#
|
317
|
+
def each
|
318
|
+
if block_given?
|
319
|
+
begin
|
320
|
+
keyspace.execute(*cql).fetch do |row|
|
321
|
+
yield Row.from_result_row(row)
|
322
|
+
end
|
323
|
+
rescue EmptySubquery
|
324
|
+
# Noop -- yield no results
|
325
|
+
end
|
326
|
+
else
|
327
|
+
enum_for(:each)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
#
|
332
|
+
# @return [Hash] the first row in this data set
|
333
|
+
#
|
334
|
+
def first
|
335
|
+
row = keyspace.execute(*limit(1).cql).fetch_row
|
336
|
+
Row.from_result_row(row)
|
337
|
+
rescue EmptySubquery
|
338
|
+
nil
|
339
|
+
end
|
340
|
+
|
341
|
+
#
|
342
|
+
# @return [Fixnum] the number of rows in this data set
|
343
|
+
#
|
344
|
+
def count
|
345
|
+
keyspace.execute(*count_cql).fetch_row['count']
|
346
|
+
rescue EmptySubquery
|
347
|
+
0
|
348
|
+
end
|
349
|
+
|
350
|
+
#
|
351
|
+
# @return [String] CQL select statement encoding this data set's scope.
|
352
|
+
#
|
353
|
+
def cql
|
354
|
+
statement = Statement.new.
|
355
|
+
append(select_cql).
|
356
|
+
append(" FROM #{table_name}").
|
357
|
+
append(*row_specifications_cql).
|
358
|
+
append(sort_order_cql).
|
359
|
+
append(limit_cql).
|
360
|
+
args
|
361
|
+
end
|
362
|
+
|
363
|
+
#
|
364
|
+
# @return [String] CQL statement to get count of rows in this data set
|
365
|
+
#
|
366
|
+
def count_cql
|
367
|
+
Statement.new.
|
368
|
+
append("SELECT COUNT(*) FROM #{table_name}").
|
369
|
+
append(*row_specifications_cql).
|
370
|
+
append(limit_cql).args
|
371
|
+
end
|
372
|
+
|
373
|
+
def inspect
|
374
|
+
"#<#{self.class.name}: #{CassandraCQL::Statement.sanitize(cql.first, cql[1..-1])}>"
|
375
|
+
end
|
376
|
+
|
377
|
+
def ==(other)
|
378
|
+
cql == other.cql
|
379
|
+
end
|
380
|
+
|
381
|
+
def inserter(options = {}, &block)
|
382
|
+
Inserter.new(self, options, &block)
|
383
|
+
end
|
384
|
+
|
385
|
+
def updater(options = {}, &block)
|
386
|
+
Updater.new(self, options, &block)
|
387
|
+
end
|
388
|
+
|
389
|
+
def incrementer(options = {}, &block)
|
390
|
+
Incrementer.new(self, options, &block)
|
391
|
+
end
|
392
|
+
|
393
|
+
def deleter(options = {}, &block)
|
394
|
+
Deleter.new(self, options, &block)
|
395
|
+
end
|
396
|
+
|
397
|
+
def row_specifications_cql
|
398
|
+
if row_specifications.any?
|
399
|
+
cql_fragments, bind_vars = [], []
|
400
|
+
row_specifications.each do |spec|
|
401
|
+
cql_with_vars = spec.cql
|
402
|
+
cql_fragments << cql_with_vars.shift
|
403
|
+
bind_vars.concat(cql_with_vars)
|
404
|
+
end
|
405
|
+
[" WHERE #{cql_fragments.join(' AND ')}", *bind_vars]
|
406
|
+
else ['']
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
protected
|
411
|
+
attr_writer :row_limit
|
412
|
+
|
413
|
+
private
|
414
|
+
|
415
|
+
def initialize_copy(source)
|
416
|
+
super
|
417
|
+
@select_columns = source.select_columns.clone
|
418
|
+
@ttl_columns = source.ttl_columns.clone
|
419
|
+
@writetime_columns = source.writetime_columns.clone
|
420
|
+
@row_specifications = source.row_specifications.clone
|
421
|
+
@sort_order = source.sort_order.clone
|
422
|
+
end
|
423
|
+
|
424
|
+
def select_cql
|
425
|
+
all_columns = select_columns +
|
426
|
+
ttl_columns.map { |column| "TTL(#{column})" } +
|
427
|
+
writetime_columns.map { |column| "WRITETIME(#{column})" }
|
428
|
+
|
429
|
+
if all_columns.any?
|
430
|
+
"SELECT #{all_columns.join(',')}"
|
431
|
+
else
|
432
|
+
'SELECT *'
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def limit_cql
|
437
|
+
row_limit ? " LIMIT #{row_limit}" : ''
|
438
|
+
end
|
439
|
+
|
440
|
+
def sort_order_cql
|
441
|
+
if sort_order.any?
|
442
|
+
order = sort_order.
|
443
|
+
map { |column, direction| "#{column} #{direction.to_s.upcase}" }.
|
444
|
+
join(', ')
|
445
|
+
" ORDER BY #{order}"
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def build_row_specifications(row_specification, bind_vars)
|
450
|
+
case row_specification
|
451
|
+
when Hash then RowSpecification.build(row_specification)
|
452
|
+
when String then CqlRowSpecification.build(row_specification, bind_vars)
|
453
|
+
else raise ArgumentError, "Invalid argument #{row_specification.inspect}; expected Hash or String"
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|