cequel 0.5.6 → 1.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cequel.rb +5 -8
  3. data/lib/cequel/errors.rb +1 -0
  4. data/lib/cequel/metal.rb +17 -0
  5. data/lib/cequel/metal/batch.rb +62 -0
  6. data/lib/cequel/metal/cql_row_specification.rb +26 -0
  7. data/lib/cequel/metal/data_set.rb +461 -0
  8. data/lib/cequel/metal/deleter.rb +47 -0
  9. data/lib/cequel/metal/incrementer.rb +35 -0
  10. data/lib/cequel/metal/inserter.rb +53 -0
  11. data/lib/cequel/metal/keyspace.rb +213 -0
  12. data/lib/cequel/metal/row.rb +48 -0
  13. data/lib/cequel/metal/row_specification.rb +37 -0
  14. data/lib/cequel/metal/statement.rb +30 -0
  15. data/lib/cequel/metal/updater.rb +65 -0
  16. data/lib/cequel/metal/writer.rb +73 -0
  17. data/lib/cequel/model.rb +12 -84
  18. data/lib/cequel/model/association_collection.rb +23 -0
  19. data/lib/cequel/model/associations.rb +84 -80
  20. data/lib/cequel/model/base.rb +74 -0
  21. data/lib/cequel/model/belongs_to_association.rb +31 -0
  22. data/lib/cequel/model/callbacks.rb +14 -10
  23. data/lib/cequel/model/collection.rb +255 -0
  24. data/lib/cequel/model/errors.rb +6 -6
  25. data/lib/cequel/model/has_many_association.rb +26 -0
  26. data/lib/cequel/model/mass_assignment.rb +31 -0
  27. data/lib/cequel/model/persistence.rb +119 -115
  28. data/lib/cequel/model/properties.rb +89 -87
  29. data/lib/cequel/model/railtie.rb +21 -14
  30. data/lib/cequel/model/record_set.rb +285 -0
  31. data/lib/cequel/model/schema.rb +33 -0
  32. data/lib/cequel/model/scoped.rb +5 -48
  33. data/lib/cequel/model/validations.rb +18 -18
  34. data/lib/cequel/schema.rb +15 -0
  35. data/lib/cequel/schema/column.rb +135 -0
  36. data/lib/cequel/schema/create_table_dsl.rb +56 -0
  37. data/lib/cequel/schema/keyspace.rb +50 -0
  38. data/lib/cequel/schema/table.rb +120 -0
  39. data/lib/cequel/schema/table_property.rb +67 -0
  40. data/lib/cequel/schema/table_reader.rb +139 -0
  41. data/lib/cequel/schema/table_synchronizer.rb +114 -0
  42. data/lib/cequel/schema/table_updater.rb +83 -0
  43. data/lib/cequel/schema/table_writer.rb +80 -0
  44. data/lib/cequel/schema/update_table_dsl.rb +60 -0
  45. data/lib/cequel/type.rb +232 -0
  46. data/lib/cequel/version.rb +1 -1
  47. data/spec/environment.rb +5 -1
  48. data/spec/examples/metal/data_set_spec.rb +608 -0
  49. data/spec/examples/model/associations_spec.rb +84 -74
  50. data/spec/examples/model/callbacks_spec.rb +66 -59
  51. data/spec/examples/model/list_spec.rb +393 -0
  52. data/spec/examples/model/map_spec.rb +229 -0
  53. data/spec/examples/model/mass_assignment_spec.rb +55 -0
  54. data/spec/examples/model/naming_spec.rb +11 -4
  55. data/spec/examples/model/persistence_spec.rb +140 -150
  56. data/spec/examples/model/properties_spec.rb +122 -75
  57. data/spec/examples/model/record_set_spec.rb +285 -0
  58. data/spec/examples/model/schema_spec.rb +44 -0
  59. data/spec/examples/model/serialization_spec.rb +20 -14
  60. data/spec/examples/model/set_spec.rb +133 -0
  61. data/spec/examples/model/spec_helper.rb +0 -10
  62. data/spec/examples/model/validations_spec.rb +51 -38
  63. data/spec/examples/schema/table_reader_spec.rb +328 -0
  64. data/spec/examples/schema/table_synchronizer_spec.rb +172 -0
  65. data/spec/examples/schema/table_updater_spec.rb +157 -0
  66. data/spec/examples/schema/table_writer_spec.rb +225 -0
  67. data/spec/examples/spec_helper.rb +29 -0
  68. data/spec/examples/type_spec.rb +204 -0
  69. data/spec/support/helpers.rb +67 -8
  70. metadata +121 -152
  71. data/lib/cequel/batch.rb +0 -58
  72. data/lib/cequel/cql_row_specification.rb +0 -22
  73. data/lib/cequel/data_set.rb +0 -371
  74. data/lib/cequel/keyspace.rb +0 -205
  75. data/lib/cequel/model/class_internals.rb +0 -49
  76. data/lib/cequel/model/column.rb +0 -20
  77. data/lib/cequel/model/counter.rb +0 -35
  78. data/lib/cequel/model/dictionary.rb +0 -126
  79. data/lib/cequel/model/dirty.rb +0 -53
  80. data/lib/cequel/model/dynamic.rb +0 -31
  81. data/lib/cequel/model/inheritable.rb +0 -48
  82. data/lib/cequel/model/instance_internals.rb +0 -23
  83. data/lib/cequel/model/local_association.rb +0 -42
  84. data/lib/cequel/model/magic.rb +0 -79
  85. data/lib/cequel/model/mass_assignment_security.rb +0 -21
  86. data/lib/cequel/model/naming.rb +0 -17
  87. data/lib/cequel/model/observer.rb +0 -42
  88. data/lib/cequel/model/readable_dictionary.rb +0 -182
  89. data/lib/cequel/model/remote_association.rb +0 -40
  90. data/lib/cequel/model/scope.rb +0 -362
  91. data/lib/cequel/model/subclass_internals.rb +0 -45
  92. data/lib/cequel/model/timestamps.rb +0 -52
  93. data/lib/cequel/model/translation.rb +0 -17
  94. data/lib/cequel/row_specification.rb +0 -63
  95. data/lib/cequel/statement.rb +0 -23
  96. data/spec/examples/data_set_spec.rb +0 -444
  97. data/spec/examples/keyspace_spec.rb +0 -84
  98. data/spec/examples/model/counter_spec.rb +0 -94
  99. data/spec/examples/model/dictionary_spec.rb +0 -301
  100. data/spec/examples/model/dirty_spec.rb +0 -39
  101. data/spec/examples/model/dynamic_spec.rb +0 -41
  102. data/spec/examples/model/inheritable_spec.rb +0 -45
  103. data/spec/examples/model/magic_spec.rb +0 -199
  104. data/spec/examples/model/mass_assignment_security_spec.rb +0 -13
  105. data/spec/examples/model/observer_spec.rb +0 -86
  106. data/spec/examples/model/scope_spec.rb +0 -677
  107. data/spec/examples/model/timestamps_spec.rb +0 -52
  108. 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/cql_row_specification'
8
- require 'cequel/data_set'
9
- require 'cequel/keyspace'
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
@@ -1,4 +1,5 @@
1
1
  module Cequel
2
2
  Error = Class.new(StandardError)
3
3
  EmptySubquery = Class.new(Error)
4
+ InvalidSchemaMigration = Class.new(Error)
4
5
  end
@@ -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