cequel 1.0.0.rc1 → 1.0.0.rc2

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cequel.rb +18 -0
  3. data/lib/cequel/errors.rb +8 -4
  4. data/lib/cequel/metal.rb +14 -0
  5. data/lib/cequel/metal/batch.rb +21 -11
  6. data/lib/cequel/metal/batch_manager.rb +74 -0
  7. data/lib/cequel/metal/cql_row_specification.rb +19 -6
  8. data/lib/cequel/metal/data_set.rb +400 -163
  9. data/lib/cequel/metal/deleter.rb +45 -11
  10. data/lib/cequel/metal/incrementer.rb +23 -10
  11. data/lib/cequel/metal/inserter.rb +19 -6
  12. data/lib/cequel/metal/keyspace.rb +82 -159
  13. data/lib/cequel/metal/logger.rb +71 -0
  14. data/lib/cequel/metal/logging.rb +47 -0
  15. data/lib/cequel/metal/new_relic_instrumentation.rb +26 -0
  16. data/lib/cequel/metal/row.rb +36 -10
  17. data/lib/cequel/metal/row_specification.rb +21 -8
  18. data/lib/cequel/metal/statement.rb +30 -6
  19. data/lib/cequel/metal/updater.rb +89 -12
  20. data/lib/cequel/metal/writer.rb +23 -14
  21. data/lib/cequel/record.rb +52 -6
  22. data/lib/cequel/record/association_collection.rb +13 -6
  23. data/lib/cequel/record/associations.rb +146 -54
  24. data/lib/cequel/record/belongs_to_association.rb +34 -7
  25. data/lib/cequel/record/bound.rb +69 -12
  26. data/lib/cequel/record/bulk_writes.rb +29 -1
  27. data/lib/cequel/record/callbacks.rb +22 -6
  28. data/lib/cequel/record/collection.rb +273 -36
  29. data/lib/cequel/record/configuration_generator.rb +5 -0
  30. data/lib/cequel/record/data_set_builder.rb +86 -0
  31. data/lib/cequel/record/dirty.rb +11 -8
  32. data/lib/cequel/record/errors.rb +38 -4
  33. data/lib/cequel/record/has_many_association.rb +42 -9
  34. data/lib/cequel/record/lazy_record_collection.rb +39 -10
  35. data/lib/cequel/record/mass_assignment.rb +14 -6
  36. data/lib/cequel/record/persistence.rb +157 -20
  37. data/lib/cequel/record/properties.rb +147 -24
  38. data/lib/cequel/record/railtie.rb +15 -2
  39. data/lib/cequel/record/record_set.rb +504 -75
  40. data/lib/cequel/record/schema.rb +77 -13
  41. data/lib/cequel/record/scoped.rb +16 -11
  42. data/lib/cequel/record/secondary_indexes.rb +42 -6
  43. data/lib/cequel/record/tasks.rb +2 -1
  44. data/lib/cequel/record/validations.rb +51 -11
  45. data/lib/cequel/schema.rb +9 -0
  46. data/lib/cequel/schema/column.rb +172 -33
  47. data/lib/cequel/schema/create_table_dsl.rb +62 -31
  48. data/lib/cequel/schema/keyspace.rb +106 -7
  49. data/lib/cequel/schema/migration_validator.rb +128 -0
  50. data/lib/cequel/schema/table.rb +183 -20
  51. data/lib/cequel/schema/table_property.rb +92 -34
  52. data/lib/cequel/schema/table_reader.rb +45 -15
  53. data/lib/cequel/schema/table_synchronizer.rb +101 -43
  54. data/lib/cequel/schema/table_updater.rb +114 -19
  55. data/lib/cequel/schema/table_writer.rb +31 -13
  56. data/lib/cequel/schema/update_table_dsl.rb +71 -40
  57. data/lib/cequel/type.rb +214 -53
  58. data/lib/cequel/util.rb +6 -9
  59. data/lib/cequel/version.rb +2 -1
  60. data/spec/examples/record/associations_spec.rb +12 -12
  61. data/spec/examples/record/persistence_spec.rb +5 -5
  62. data/spec/examples/record/record_set_spec.rb +62 -50
  63. data/spec/examples/schema/table_synchronizer_spec.rb +37 -11
  64. data/spec/examples/schema/table_updater_spec.rb +3 -3
  65. data/spec/examples/spec_helper.rb +2 -11
  66. data/spec/examples/type_spec.rb +3 -3
  67. metadata +23 -4
  68. data/lib/cequel/new_relic_instrumentation.rb +0 -22
@@ -1,31 +1,58 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # Represents a parent association declared by
5
+ # {Associations::ClassMethods#belongs_to belongs_to}
6
+ #
7
+ # @see Associations::ClassMethods#parent_association
8
+ # @since 1.0.0
9
+ #
5
10
  class BelongsToAssociation
6
-
7
11
  extend Forwardable
8
12
 
9
- attr_reader :owner_class, :name, :association_class_name
13
+ # @return [Class] child class that declared `belongs_to`
14
+ attr_reader :owner_class
15
+ # @return [Symbol] name of the association
16
+ attr_reader :name
17
+ # @return [String] name of parent class
18
+ attr_reader :association_class_name
10
19
 
20
+ # @!attribute [r] association_key_columns
21
+ # @return [Array<Schema::Column>] key columns on the parent class
11
22
  def_delegator :association_class, :key_columns, :association_key_columns
12
23
 
24
+ #
25
+ # @param owner_class [Class] child class that declared `belongs_to`
26
+ # @param name [Symbol] name of the association
27
+ # @param options [Options] options for association
28
+ # @option options [String] :class_name name of parent class
29
+ #
30
+ # @api private
31
+ #
13
32
  def initialize(owner_class, name, options = {})
33
+ options.assert_valid_keys(:class_name)
34
+
14
35
  @owner_class, @name = owner_class, name.to_sym
15
36
  @association_class_name =
16
37
  options.fetch(:class_name, @name.to_s.classify)
17
38
  end
18
39
 
40
+ #
41
+ # @return [Class] parent class declared by `belongs_to`
42
+ #
19
43
  def association_class
20
44
  @association_class ||= association_class_name.constantize
21
45
  end
22
46
 
47
+ #
48
+ # @return [Symbol] instance variable name to use for storing the parent
49
+ # instance in a record
50
+ #
51
+ # @api private
52
+ #
23
53
  def instance_variable_name
24
54
  @instance_variable_name ||= :"@#{name}"
25
55
  end
26
-
27
56
  end
28
-
29
57
  end
30
-
31
58
  end
@@ -1,15 +1,33 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # An upper or lower bound for a range query.
5
+ #
6
+ # @abstract Subclasses must implement the `to_cql` method, and may override
7
+ # the `operator` and `bind_value` methods.
8
+ #
9
+ # @api private
10
+ # @since 1.0.0
11
+ #
5
12
  class Bound
6
- attr_reader :column, :value
7
-
13
+ # @return [Schema::Column] column bound applies to
14
+ attr_reader :column
15
+ # @return value for bound
16
+ attr_reader :value
17
+
18
+ #
19
+ # Create a bound object for the given column. This method returns an
20
+ # instance of the appropriate `Bound` subclass given the type of the
21
+ # column and the class of the value.
22
+ #
23
+ # @param (see #initialize)
24
+ # @return [Bound] instance of appropriate bound implementation
25
+ #
8
26
  def self.create(column, gt, inclusive, value)
9
27
  implementation =
10
28
  if column.partition_key?
11
29
  PartitionKeyBound
12
- elsif column.type?(Type::Timeuuid) && !value.is_a?(CassandraCQL::UUID)
30
+ elsif column.type?(:timeuuid) && !value.is_a?(CassandraCQL::UUID)
13
31
  TimeuuidBound
14
32
  else
15
33
  ClusteringColumnBound
@@ -18,27 +36,47 @@ module Cequel
18
36
  implementation.new(column, gt, inclusive, value)
19
37
  end
20
38
 
39
+ #
40
+ # @param column [Schema::Column] column bound applies to
41
+ # @param gt [Boolean] `true` if this is a lower bound
42
+ # @param inclusive [Boolean] `true` if this is an inclusive bound
43
+ # @param value value for bound
44
+ #
21
45
  def initialize(column, gt, inclusive, value)
22
46
  @column, @gt, @inclusive, @value = column, gt, inclusive, value
23
47
  end
24
48
 
49
+ #
50
+ # @return [Array] pair containing CQL string and bind value
51
+ #
25
52
  def to_cql_with_bind_variables
26
53
  [to_cql, bind_value]
27
54
  end
28
55
 
29
-
56
+ #
57
+ # @return [Boolean] `true` if this is a lower bound
58
+ #
30
59
  def gt?
31
60
  !!@gt
32
61
  end
33
62
 
63
+ #
64
+ # @return [Boolean] `true` if this is an upper bound
65
+ #
34
66
  def lt?
35
67
  !gt?
36
68
  end
37
69
 
70
+ #
71
+ # @return [Boolean] `true` if this is an inclusive bound
72
+ #
38
73
  def inclusive?
39
74
  !!@inclusive
40
75
  end
41
76
 
77
+ #
78
+ # @return [Boolean] `true` if this is an exclusive bound
79
+ #
42
80
  def exclusive?
43
81
  !inclusive?
44
82
  end
@@ -56,28 +94,49 @@ module Cequel
56
94
  def base_operator
57
95
  lt? ? '<' : '>'
58
96
  end
59
-
60
97
  end
61
98
 
99
+ #
100
+ # A bound on a partition key.
101
+ #
102
+ # @api private
103
+ # @since 1.0.0
104
+ #
62
105
  class PartitionKeyBound < Bound
106
+ protected
107
+
63
108
  def to_cql
64
109
  "TOKEN(#{column.name}) #{operator} TOKEN(?)"
65
110
  end
66
111
  end
67
112
 
113
+ #
114
+ # A bound on a clustering column.
115
+ #
116
+ # @api private
117
+ # @since 1.0.0
118
+ #
68
119
  class ClusteringColumnBound < Bound
120
+ protected
121
+
69
122
  def to_cql
70
123
  "#{column.name} #{operator} ?"
71
124
  end
72
125
  end
73
126
 
74
- class TimeuuidBound < Bound
127
+ #
128
+ # A bound on a column of type `timeuuid` whose bound value is a `timestamp`
129
+ #
130
+ # @api private
131
+ # @since 1.0.0
132
+ #
133
+ class TimeuuidBound < ClusteringColumnBound
134
+ protected
135
+
75
136
  def to_cql
76
137
  "#{column.name} #{operator} #{function}(?)"
77
138
  end
78
139
 
79
- protected
80
-
81
140
  def operator
82
141
  base_operator
83
142
  end
@@ -95,7 +154,5 @@ module Cequel
95
154
  lt? ^ exclusive? ? 'maxTimeuuid' : 'minTimeuuid'
96
155
  end
97
156
  end
98
-
99
157
  end
100
-
101
158
  end
@@ -1,14 +1,42 @@
1
1
  module Cequel
2
2
  module Record
3
+ #
4
+ # This module implements bulk update and delete functionality for classes
5
+ # that expose a collection of result rows.
6
+ #
7
+ # @abstract Including modules must implement `key_attributes_for_each_row`,
8
+ # which should yield successive fully-specified key attributes for each
9
+ # result row.
10
+ #
11
+ # @since 1.0.0
12
+ #
3
13
  module BulkWrites
14
+ #
15
+ # Update all matched records with the given column values, without
16
+ # executing callbacks.
17
+ #
18
+ # @param attributes [Hash] map of column names to values
19
+ # @return [void]
20
+ #
4
21
  def update_all(attributes)
5
22
  each_data_set { |data_set| data_set.update(attributes) }
6
23
  end
7
24
 
25
+ #
26
+ # Delete all matched records without executing callbacks
27
+ #
28
+ # @return [void]
29
+ #
8
30
  def delete_all
9
31
  each_data_set { |data_set| data_set.delete }
10
32
  end
11
33
 
34
+ #
35
+ # Destroy all matched records, executing destroy callbacks for each
36
+ # record.
37
+ #
38
+ # @return [void]
39
+ #
12
40
  def destroy_all
13
41
  each { |record| record.destroy }
14
42
  end
@@ -17,7 +45,7 @@ module Cequel
17
45
 
18
46
  def each_data_set
19
47
  key_attributes_for_each_row.each_slice(100) do |batch|
20
- connection.batch(:unlogged => true) do
48
+ connection.batch(unlogged: true) do
21
49
  batch.each { |key_attributes| yield table.where(key_attributes) }
22
50
  end
23
51
  end
@@ -1,9 +1,26 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # Cequel::Record models provide lifecycle callbacks for `create`, `update`,
5
+ # `save`, `destroy`, and `validation`.
6
+ #
7
+ # @example
8
+ # class User
9
+ # include Cequel::Record
10
+ #
11
+ # key :login, :text
12
+ # column :name, :text
13
+ #
14
+ # after_create :send_welcome_email
15
+ # after_update :reindex_posts_for_search
16
+ # after_save :reindex_for_search
17
+ # after_destroy :send_farewell_email
18
+ # before_validation :set_permalink
19
+ # end
20
+ #
21
+ # @since 0.1.0
22
+ #
5
23
  module Callbacks
6
-
7
24
  extend ActiveSupport::Concern
8
25
 
9
26
  included do
@@ -11,10 +28,12 @@ module Cequel
11
28
  define_model_callbacks :save, :create, :update, :destroy
12
29
  end
13
30
 
31
+ # (see Persistence#save)
14
32
  def save(options = {})
15
33
  connection.batch { run_callbacks(:save) { super }}
16
34
  end
17
35
 
36
+ # (see Persistence#save)
18
37
  def destroy
19
38
  connection.batch { run_callbacks(:destroy) { super }}
20
39
  end
@@ -28,9 +47,6 @@ module Cequel
28
47
  def update
29
48
  run_callbacks(:update) { super }
30
49
  end
31
-
32
50
  end
33
-
34
51
  end
35
-
36
52
  end
@@ -1,37 +1,117 @@
1
1
  require 'delegate'
2
2
 
3
3
  module Cequel
4
-
5
4
  module Record
6
-
5
+ #
6
+ # The value of a collection column in a {Record}. Collections track
7
+ # modifications that can be expressed as atomic collection mutations in
8
+ # CQL, and persist those modifications when their owning record is saved.
9
+ # Such modifications can be done even if the collection has not loaded
10
+ # data from CQL, in the case of an unloaded record or where the collection
11
+ # column was not included in the `SELECT` statement.
12
+ #
13
+ # Mutation operations that require reading data before writing it are not
14
+ # supported (e.g. `Array#map!).
15
+ #
16
+ # Each collection implementation wraps a built-in Ruby collection type.
17
+ #
18
+ # @abstract Including classes must descend from `Delegator` and implement
19
+ # the `::empty` class method.
20
+ #
21
+ # @example
22
+ # class Blog
23
+ # include Cequel::Record
24
+ #
25
+ # key :subdomain
26
+ #
27
+ # list :categories, :text
28
+ # end
29
+ #
30
+ # # Get an unloaded Blog instance; no data read
31
+ # blog = Blog['cassandra']
32
+ #
33
+ # # Stage modification to collection, still no data read
34
+ # blog.categories << 'Big Data'
35
+ #
36
+ # # Issue an UPDATE statement which pushes "Big Data" onto the
37
+ # # collection. Still no data read
38
+ # blog.save!
39
+ #
40
+ # # Stage another modification to the collection
41
+ # blog.categories.unshift('Distributed Database')
42
+ #
43
+ # # Collection is lazily read from the database, and then staged
44
+ # # modifications are made to the loaded collection
45
+ # puts blog.categories.join(', ')
46
+ #
47
+ # # Issues an UPDATE statement which prepends "Distributed Data" onto the
48
+ # # collection
49
+ # blog.save!
50
+ #
51
+ # @since 1.0.0
52
+ #
7
53
  module Collection
8
-
9
54
  extend ActiveSupport::Concern
10
55
  extend Forwardable
11
56
 
57
+ #
58
+ # @!method loaded?
59
+ # @return [Boolean] `true` if the collection's contents are loaded into
60
+ # memory
61
+ #
12
62
  def_delegators :@model, :loaded?, :updater, :deleter
63
+ private :updater, :deleter
64
+
65
+ #
66
+ # @!method column_name
67
+ # @return [Symbol] the name of the collection column
68
+ #
13
69
  def_delegator :@column, :name, :column_name
70
+
14
71
  def_delegators :__getobj__, :clone, :dup
15
72
 
16
73
  included do
17
- private
18
74
  define_method(
19
75
  :method_missing,
20
76
  BasicObject.instance_method(:method_missing))
77
+ private :method_missing
21
78
  end
22
79
 
80
+ #
81
+ # @param model [Record] record that contains this collection
82
+ # @param column [Schema::Column] column this collection's data belongs to
83
+ # @return [Collection] a new collection
84
+ #
23
85
  def initialize(model, column)
24
86
  @model, @column = model, column
25
87
  end
26
88
 
89
+ #
90
+ # @return [String] inspected underlying Ruby collection object
91
+ #
27
92
  def inspect
28
93
  __getobj__.inspect
29
94
  end
30
95
 
96
+ #
97
+ # Notify the collection that its underlying data is loaded in memory.
98
+ #
99
+ # @return [void]
100
+ #
101
+ # @api private
102
+ #
31
103
  def loaded!
32
- modifications.each { |modification| modification.() }.clear
104
+ modifications.each { |modification| modification.call() }.clear
33
105
  end
34
106
 
107
+ #
108
+ # Notify the collection that its staged changes have been written to the
109
+ # data store.
110
+ #
111
+ # @return [void]
112
+ #
113
+ # @api private
114
+ #
35
115
  def persisted!
36
116
  modifications.clear
37
117
  end
@@ -44,10 +124,11 @@ module Cequel
44
124
  end
45
125
 
46
126
  def __setobj__(obj)
47
- raise "Attempted to call __setobj__ on read-only delegate!"
127
+ fail "Attempted to call __setobj__ on read-only delegate!"
48
128
  end
49
129
 
50
130
  private
131
+
51
132
  attr_reader :model, :column
52
133
  def_delegator :column, :cast, :cast_collection
53
134
  def_delegator 'column.type', :cast, :cast_element
@@ -56,7 +137,7 @@ module Cequel
56
137
  def to_modify(&block)
57
138
  if loaded?
58
139
  model.__send__("#{column_name}_will_change!")
59
- block.()
140
+ block.call()
60
141
  else modifications << block
61
142
  end
62
143
  self
@@ -65,13 +146,20 @@ module Cequel
65
146
  def modifications
66
147
  @modifications ||= []
67
148
  end
68
-
69
149
  end
70
150
 
151
+ #
152
+ # The value of a list column in a {Record} instance. List collections
153
+ # encapsulate and behave like the built-in `Array` type.
154
+ #
155
+ # @see http://www.datastax.com/documentation/cql/3.0/webhelp/index.html#cql/cql_using/use_collections_c.html#task_ds_lqp_krj_zj CQL documentation for the list type
156
+ # @since 1.0.0
157
+ #
71
158
  class List < DelegateClass(Array)
72
-
73
159
  include Collection
74
160
 
161
+ # These methods are not available on lists because they require reading
162
+ # collection data before writing it.
75
163
  NON_ATOMIC_MUTATORS = [
76
164
  :collect!,
77
165
  :delete_if,
@@ -92,14 +180,50 @@ module Cequel
92
180
  :sort_by!,
93
181
  :uniq!
94
182
  ]
95
- NON_ATOMIC_MUTATORS.
96
- each { |method| undef_method(method) if method_defined? method }
97
-
183
+ NON_ATOMIC_MUTATORS
184
+ .each { |method| undef_method(method) if method_defined? method }
185
+
186
+ #
187
+ # @return [Array] an empty array
188
+ #
189
+ # @api private
190
+ #
98
191
  def self.empty; []; end
99
192
 
193
+ #
194
+ # Set the value at a position or range of positions. This modification
195
+ # will be staged and persisted as an atomic list update when the record
196
+ # is saved. If the collection data is loaded in memory, it will also be
197
+ # modified accordingly.
198
+ #
199
+ # @return [void]
200
+ #
201
+ # @see DataSet#list_replace
202
+ # @note Negative positions are not supported, as they are not allowed in
203
+ # CQL list operations.
204
+ #
205
+ # @overload []=(position, element)
206
+ #
207
+ # @param position [Integer] position at which to set element
208
+ # @param element element to insert at position in list
209
+ #
210
+ # @overload []=(range, elements)
211
+ #
212
+ # @param range [Range] range of positions at which to replace elements
213
+ # @param elements [Array] new elements to replace in this range
214
+ #
215
+ # @overload []=(start_position, count, elements)
216
+ #
217
+ # @param start_position [Integer] position at which to begin replacing
218
+ # elements
219
+ # @param count [Integer] number of elements to replace
220
+ # @param elements [Array] new elements to replace in this range
221
+ #
100
222
  def []=(position, *args)
101
- if Range === position then first, count = position.first, position.count
102
- else first, count = position, args[-2]
223
+ if position.is_a?(Range)
224
+ first, count = position.first, position.count
225
+ else
226
+ first, count = position, args[-2]
103
227
  end
104
228
 
105
229
  element = args[-1] =
@@ -108,8 +232,9 @@ module Cequel
108
232
  end
109
233
 
110
234
  if first < 0
111
- raise ArgumentError,
112
- "Bad index #{position}: CQL lists do not support negative indices"
235
+ fail ArgumentError,
236
+ "Bad index #{position}: CQL lists do not support negative " \
237
+ "indices"
113
238
  end
114
239
 
115
240
  if count.nil?
@@ -127,53 +252,105 @@ module Cequel
127
252
  to_modify { super }
128
253
  end
129
254
 
255
+ #
256
+ # Remove all elements from the list. This will propagate to the database
257
+ # as a DELETE of the list column.
258
+ #
259
+ # @return [List] self
260
+ #
130
261
  def clear
131
262
  deleter.delete_columns(column_name)
132
263
  to_modify { super }
133
264
  end
134
265
 
266
+ #
267
+ # Concatenate another collection onto this list.
268
+ #
269
+ # @param array [Array] elements to concatenate
270
+ # @return [List] self
271
+ #
135
272
  def concat(array)
136
273
  array = cast_collection(array)
137
274
  updater.list_append(column_name, array)
138
275
  to_modify { super }
139
276
  end
140
277
 
278
+ #
279
+ # Remove all instances of a given value from the list.
280
+ #
281
+ # @param object value to remove
282
+ # @return [List] self
283
+ #
141
284
  def delete(object)
142
285
  object = cast_element(object)
143
286
  updater.list_remove(column_name, object)
144
287
  to_modify { super }
145
288
  end
146
289
 
290
+ #
291
+ # Remove the element at a given position from the list.
292
+ #
293
+ # @param index [Integer] position from which to remove the element
294
+ # @return [List] self
295
+ #
147
296
  def delete_at(index)
148
297
  deleter.list_remove_at(column_name, index)
149
298
  to_modify { super }
150
299
  end
151
300
 
152
- def push(object)
153
- object = cast_element(object)
154
- updater.list_append(column_name, object)
301
+ #
302
+ # Push (append) one or more elements to the end of the list.
303
+ #
304
+ # @param objects value(s) to add to the end of the list
305
+ # @return [List] self
306
+ #
307
+ def push(*objects)
308
+ objects.map! { |object| cast_element(object) }
309
+ updater.list_append(column_name, objects)
155
310
  to_modify { super }
156
311
  end
157
312
  alias_method :<<, :push
158
-
313
+ alias_method :append, :push
314
+
315
+ #
316
+ # Replace the entire contents of this list with a new collection
317
+ #
318
+ # @param array [Array] new elements for this list
319
+ # @return [List] self
320
+ #
159
321
  def replace(array)
160
322
  array = cast_collection(array)
161
323
  updater.set(column_name => array)
162
324
  to_modify { super }
163
325
  end
164
326
 
165
- def unshift(*objs)
166
- objs.map!(&method(:cast_element))
167
- updater.list_prepend(column_name, objs.reverse)
327
+ #
328
+ # Prepend one or more values to the beginning of this list
329
+ #
330
+ # @param objects value(s) to add to the beginning of the list
331
+ # @return [List] self
332
+ #
333
+ def unshift(*objects)
334
+ objects.map!(&method(:cast_element))
335
+ updater.list_prepend(column_name, objects.reverse)
168
336
  to_modify { super }
169
337
  end
170
-
338
+ alias_method :prepend, :unshift
171
339
  end
172
340
 
341
+ #
342
+ # The value of a set column in a {Record} instance. Contains an unordered,
343
+ # unique set of elements. Encapsulates and behaves like the `Set` type from
344
+ # the standard library.
345
+ #
346
+ # @see http://www.datastax.com/documentation/cql/3.0/webhelp/index.html#cql/cql_using/use_collections_c.html#task_ds_agt_3kj_zj CQL documentation for set columns
347
+ # @since 1.0.0
348
+ #
173
349
  class Set < DelegateClass(::Set)
174
-
175
350
  include Collection
176
351
 
352
+ # These methods are not implemented because they cannot be expressed as a
353
+ # single CQL3 write operation.
177
354
  NON_ATOMIC_MUTATORS = [
178
355
  :add?,
179
356
  :collect!,
@@ -185,9 +362,15 @@ module Cequel
185
362
  :reject!,
186
363
  :select!
187
364
  ]
188
- NON_ATOMIC_MUTATORS.
189
- each { |method| undef_method(method) if method_defined? method }
190
-
365
+ NON_ATOMIC_MUTATORS
366
+ .each { |method| undef_method(method) if method_defined? method }
367
+
368
+ #
369
+ # Add an element to the set
370
+ #
371
+ # @param object element to add
372
+ # @return [Set] self
373
+ #
191
374
  def add(object)
192
375
  object = cast_element(object)
193
376
  updater.set_add(column_name, object)
@@ -195,30 +378,55 @@ module Cequel
195
378
  end
196
379
  alias_method :<<, :add
197
380
 
381
+ #
382
+ # Remove everything from the set. Equivalent to deleting the collection
383
+ # column from the record's row.
384
+ #
385
+ # @return [Set] self
386
+ #
198
387
  def clear
199
388
  deleter.delete_columns(column_name)
200
389
  to_modify { super }
201
390
  end
202
391
 
392
+ #
393
+ # Remove a single element from the set
394
+ #
395
+ # @param object element to remove
396
+ # @return [Set] self
397
+ #
203
398
  def delete(object)
204
399
  object = cast_element(object)
205
400
  updater.set_remove(column_name, object)
206
401
  to_modify { super }
207
402
  end
208
403
 
404
+ #
405
+ # Replace the entire contents of this set with another set
406
+ #
407
+ # @param set [::Set] set containing new elements
408
+ # @return [Set] self
409
+ #
209
410
  def replace(set)
210
411
  set = cast_collection(set)
211
412
  updater.set(column_name => set)
212
413
  to_modify { super }
213
414
  end
214
-
215
415
  end
216
416
 
417
+ #
418
+ # The value of a `map` column in a {Record} instance. Encapsulates and
419
+ # behaves like a built-in `Hash`.
420
+ #
421
+ # @see http://www.datastax.com/documentation/cql/3.0/webhelp/index.html#cql/cql_using/use_collections_c.html#task_ds_cvq_kcl_zj CQL documentation for map columns
422
+ # @since 1.0.0
423
+ #
217
424
  class Map < DelegateClass(::Hash)
218
-
219
425
  include Collection
220
426
  extend Forwardable
221
427
 
428
+ # These methods involve mutation that cannot be expressed as a CQL
429
+ # operation, so are not implemented.
222
430
  NON_ATOMIC_MUTATORS = [
223
431
  :default,
224
432
  :default=,
@@ -240,9 +448,16 @@ module Cequel
240
448
  :to_options!,
241
449
  :transform_keys!
242
450
  ]
243
- NON_ATOMIC_MUTATORS.
244
- each { |method| undef_method(method) if method_defined? method }
245
-
451
+ NON_ATOMIC_MUTATORS
452
+ .each { |method| undef_method(method) if method_defined? method }
453
+
454
+ #
455
+ # Set the value of a given key
456
+ #
457
+ # @param key the key
458
+ # @param value the value
459
+ # @return [Map] self
460
+ #
246
461
  def []=(key, value)
247
462
  key = cast_key(key)
248
463
  updater.map_update(column_name, key => value)
@@ -250,17 +465,35 @@ module Cequel
250
465
  end
251
466
  alias_method :store, :[]=
252
467
 
468
+ #
469
+ # Remove all elements from this map. Equivalent to deleting the column
470
+ # value from the row in CQL
471
+ #
472
+ # @return [Map] self
473
+ #
253
474
  def clear
254
475
  deleter.delete_columns(column_name)
255
476
  to_modify { super }
256
477
  end
257
478
 
479
+ #
480
+ # Delete one key from the map
481
+ #
482
+ # @param key the key to delete
483
+ # @return [Map] self
484
+ #
258
485
  def delete(key)
259
486
  key = cast_key(key)
260
487
  deleter.map_remove(column_name, key)
261
488
  to_modify { super }
262
489
  end
263
490
 
491
+ #
492
+ # Update a collection of keys and values given by a hash
493
+ #
494
+ # @param hash [Hash] hash containing keys and values to set
495
+ # @return [Map] self
496
+ #
264
497
  def merge!(hash)
265
498
  hash = cast_collection(hash)
266
499
  updater.map_update(column_name, hash)
@@ -268,6 +501,12 @@ module Cequel
268
501
  end
269
502
  alias_method :update, :merge!
270
503
 
504
+ #
505
+ # Replace the entire contents of this map with a new one
506
+ #
507
+ # @param hash [Hash] hash containing new keys and values
508
+ # @return [Map] self
509
+ #
271
510
  def replace(hash)
272
511
  hash = cast_collection(hash)
273
512
  updater.set(column_name => hash)
@@ -275,11 +514,9 @@ module Cequel
275
514
  end
276
515
 
277
516
  private
517
+
278
518
  def_delegator 'column.key_type', :cast, :cast_key
279
519
  private :cast_key
280
-
281
520
  end
282
-
283
521
  end
284
-
285
522
  end