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,5 +1,10 @@
1
1
  module Cequel
2
2
  module Record
3
+ #
4
+ # Rails generator for a default configuration file
5
+ #
6
+ # @since 1.0.0
7
+ #
3
8
  class ConfigurationGenerator < Rails::Generators::Base
4
9
  namespace 'cequel:configuration'
5
10
  source_root File.expand_path('../../../../templates/', __FILE__)
@@ -0,0 +1,86 @@
1
+ module Cequel
2
+ module Record
3
+ #
4
+ # This is a utility class to construct a {Metal::DataSet} for a given
5
+ # {RecordSet}.
6
+ #
7
+ # @api private
8
+ #
9
+ class DataSetBuilder
10
+ extend Forwardable
11
+
12
+ #
13
+ # Build a data set for the given record set
14
+ #
15
+ # @param (see #initialize)
16
+ # @return [Metal::DataSet] a DataSet exposing the rows for the record set
17
+ #
18
+ def self.build_for(record_set)
19
+ new(record_set).build
20
+ end
21
+
22
+ #
23
+ # @param record_set [RecordSet] record set for which to construct data
24
+ # set
25
+ #
26
+ def initialize(record_set)
27
+ @record_set = record_set
28
+ @data_set = record_set.connection[record_set.target_class.table_name]
29
+ end
30
+ private_class_method :new
31
+
32
+ def build
33
+ add_limit
34
+ add_select_columns
35
+ add_where_statement
36
+ add_bounds
37
+ add_order
38
+ data_set
39
+ end
40
+
41
+ protected
42
+
43
+ attr_accessor :data_set
44
+ attr_reader :record_set
45
+ def_delegators :record_set, :row_limit, :select_columns,
46
+ :scoped_key_names, :scoped_key_values,
47
+ :scoped_indexed_column, :lower_bound,
48
+ :upper_bound, :reversed?, :order_by_column
49
+
50
+ private
51
+
52
+ def add_limit
53
+ self.data_set = data_set.limit(row_limit) if row_limit
54
+ end
55
+
56
+ def add_select_columns
57
+ self.data_set = data_set.select(*select_columns) if select_columns
58
+ end
59
+
60
+ def add_where_statement
61
+ if scoped_key_values
62
+ key_conditions = Hash[scoped_key_names.zip(scoped_key_values)]
63
+ self.data_set = data_set.where(key_conditions)
64
+ end
65
+ if scoped_indexed_column
66
+ self.data_set = data_set.where(scoped_indexed_column)
67
+ end
68
+ end
69
+
70
+ def add_bounds
71
+ if lower_bound
72
+ self.data_set =
73
+ data_set.where(*lower_bound.to_cql_with_bind_variables)
74
+ end
75
+ if upper_bound
76
+ self.data_set =
77
+ data_set.where(*upper_bound.to_cql_with_bind_variables)
78
+ end
79
+ end
80
+
81
+ def add_order
82
+ self.data_set = data_set.order(order_by_column => :desc) if reversed?
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,15 +1,21 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # Cequel provides support for dirty attribute tracking via ActiveModel.
5
+ # Modifications to collection columns are registered by this mechanism.
6
+ #
7
+ # @see http://api.rubyonrails.org/classes/ActiveModel/Dirty.html Rails
8
+ # documentation for ActiveModel::Dirty
9
+ #
10
+ # @since 0.1.0
11
+ #
5
12
  module Dirty
6
-
7
13
  extend ActiveSupport::Concern
8
14
 
9
15
  included { include ActiveModel::Dirty }
10
16
 
17
+ # @private
11
18
  module ClassMethods
12
-
13
19
  def key(name, *)
14
20
  define_attribute_method(name)
15
21
  super
@@ -34,9 +40,9 @@ module Cequel
34
40
  define_attribute_method(name)
35
41
  super
36
42
  end
37
-
38
43
  end
39
44
 
45
+ # @private
40
46
  def save(options = {})
41
47
  super.tap do |success|
42
48
  if success
@@ -54,9 +60,6 @@ module Cequel
54
60
  end
55
61
  super
56
62
  end
57
-
58
63
  end
59
-
60
64
  end
61
-
62
65
  end
@@ -1,14 +1,48 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # Raised when attempting to access an attribute of a record when that
5
+ # attribute hasn't been loaded
6
+ #
7
+ # @since 1.0.0
8
+ #
5
9
  MissingAttributeError = Class.new(ArgumentError)
10
+ #
11
+ # Raised when attempting to read or write an attribute that isn't defined
12
+ # on the record
13
+ #
14
+ # @since 1.0.0
15
+ #
6
16
  UnknownAttributeError = Class.new(ArgumentError)
17
+ #
18
+ # Raised when attempting to load a record by key when that record does not
19
+ # exist
20
+ #
7
21
  RecordNotFound = Class.new(StandardError)
22
+ #
23
+ # Raised when attempting to configure a record in a way that is not
24
+ # possible
25
+ #
26
+ # @since 1.0.0
27
+ #
8
28
  InvalidRecordConfiguration = Class.new(StandardError)
29
+ #
30
+ # Raised when attempting to save a record that is invalid
31
+ #
9
32
  RecordInvalid = Class.new(StandardError)
33
+ #
34
+ # Raised when attempting to construct a {RecordSet} that cannot construct
35
+ # a valid CQL query
36
+ #
37
+ # @since 1.0.0
38
+ #
10
39
  IllegalQuery = Class.new(StandardError)
11
-
40
+ #
41
+ # Raised when attempting to persist a Cequel::Record without defining all
42
+ # primary key columns
43
+ #
44
+ # @since 1.0.0
45
+ #
46
+ MissingKeyError = Class.new(StandardError)
12
47
  end
13
-
14
48
  end
@@ -1,26 +1,59 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # Represents a child association declared by
5
+ # {Associations::ClassMethods#has_many has_many}.
6
+ #
7
+ # @see Associations::ClassMethods#child_associations
8
+ # @since 1.0.0
9
+ #
5
10
  class HasManyAssociation
6
-
7
- attr_reader :owner_class, :name, :association_class_name
8
-
11
+ # @return [Class] Record class that declares this association
12
+ attr_reader :owner_class
13
+ # @return [Symbol] name of this association
14
+ attr_reader :name
15
+ # @return [Symbol] name of the child class that this association contains
16
+ attr_reader :association_class_name
17
+ # @return [Boolean] behavior for propagating destruction from parent to
18
+ # children
19
+ attr_reader :dependent
20
+
21
+ #
22
+ # @param owner_class [Class] Record class that declares this association
23
+ # @param name [Symbol] name of the association
24
+ # @param options [Options] options for the association
25
+ # @option options [Symbol] :class_name name of the child class
26
+ # @option options [Boolean] :dependent propagation behavior for destroy
27
+ #
28
+ # @api private
29
+ #
9
30
  def initialize(owner_class, name, options = {})
31
+ options.assert_valid_keys(:class_name, :dependent)
32
+
10
33
  @owner_class, @name = owner_class, name
11
- @association_class_name = options.fetch(:class_name, name.to_s.classify)
34
+ @association_class_name =
35
+ options.fetch(:class_name, name.to_s.classify)
36
+ case options[:dependent]
37
+ when :destroy, :delete, nil
38
+ @dependent = options[:dependent]
39
+ else
40
+ fail ArgumentError,
41
+ "Invalid :dependent option #{options[:dependent].inspect}. " \
42
+ "Valid values are :destroy, :delete"
43
+ end
12
44
  end
13
45
 
46
+ #
47
+ # @return [Class] class of child association
48
+ #
14
49
  def association_class
15
50
  @association_class ||= association_class_name.constantize
16
51
  end
17
52
 
53
+ # @private
18
54
  def instance_variable_name
19
55
  @instance_variable_name ||= :"@#{name}"
20
56
  end
21
-
22
57
  end
23
-
24
58
  end
25
-
26
59
  end
@@ -1,19 +1,36 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # Encapsulates a collection of unloaded {Record} instances. In the case
5
+ # where a record set is scoped to fully specify the keys of multiple
6
+ # records, those records will be returned unloaded in a
7
+ # LazyRecordCollection. When an attribute is read from any of the records
8
+ # in a LazyRecordCollection, it will eagerly load all of the records' rows
9
+ # from the database.
10
+ #
11
+ # @since 1.0.0
12
+ #
5
13
  class LazyRecordCollection < DelegateClass(Array)
6
-
7
14
  extend Forwardable
8
15
  include BulkWrites
9
-
16
+ #
17
+ # @!method table
18
+ # (see RecordSet#table)
19
+ # @!method connection
20
+ # (see RecordSet#connection)
10
21
  def_delegators :record_set, :table, :connection
11
22
 
23
+ #
24
+ # @param record_set [RecordSet] record set representing the records in
25
+ # this collection
26
+ # @api private
27
+ #
12
28
  def initialize(record_set)
13
- raise ArgumentError if record_set.nil?
29
+ fail ArgumentError if record_set.nil?
30
+ @record_set = record_set
14
31
 
15
32
  exploded_key_attributes = [{}].tap do |all_key_attributes|
16
- record_set.key_columns.zip(record_set.scoped_key_attributes.values) do |column, values|
33
+ key_columns.zip(scoped_key_values) do |column, values|
17
34
  all_key_attributes.replace(Array(values).flat_map do |value|
18
35
  all_key_attributes.map do |key_attributes|
19
36
  key_attributes.merge(column.name => value)
@@ -27,9 +44,12 @@ module Cequel
27
44
  end
28
45
 
29
46
  super(unloaded_records)
30
- @record_set = record_set
31
47
  end
32
48
 
49
+ #
50
+ # Hydrate all the records in this collection from a database query
51
+ #
52
+ # @return [LazyRecordCollection] self
33
53
  def load!
34
54
  records_by_identity = index_by { |record| record.key_values }
35
55
 
@@ -37,17 +57,26 @@ module Cequel
37
57
  identity = row.values_at(*record_set.key_column_names)
38
58
  records_by_identity[identity].hydrate(row)
39
59
  end
60
+
61
+ loaded_count = count { |record| record.loaded? }
62
+ if loaded_count < count
63
+ fail Cequel::Record::RecordNotFound,
64
+ "Expected #{count} results; got #{loaded_count}"
65
+ end
66
+
67
+ self
40
68
  end
41
69
 
42
70
  private
71
+
43
72
  attr_reader :record_set
44
73
 
74
+ def_delegators :record_set, :key_columns, :scoped_key_values
75
+ private :key_columns, :scoped_key_values
76
+
45
77
  def key_attributes_for_each_row
46
78
  map { |record| record.key_attributes }
47
79
  end
48
-
49
80
  end
50
-
51
81
  end
52
-
53
82
  end
@@ -5,11 +5,21 @@ rescue LoadError
5
5
  end
6
6
 
7
7
  module Cequel
8
-
9
8
  module Record
10
-
9
+ #
10
+ # Cequel supports mass-assignment protection in both the Rails 3 and Rails
11
+ # 4 paradigms. Rails 3 applications may define `attr_protected` and
12
+ # `attr_accessible` attributes in {Record} classes. In Rails 4, Cequel will
13
+ # respect strong parameters.
14
+ #
15
+ # @see https://github.com/rails/strong_parameters Rails 4 Strong Parameters
16
+ # @see
17
+ # http://api.rubyonrails.org/v3.2.15/classes/ActiveModel/MassAssignmentSecurity.html
18
+ # Rails 3 mass-assignment security
19
+ #
20
+ # @since 1.0.0
21
+ #
11
22
  module MassAssignment
12
-
13
23
  extend ActiveSupport::Concern
14
24
 
15
25
  included do
@@ -20,12 +30,10 @@ module Cequel
20
30
  end
21
31
  end
22
32
 
33
+ # @private
23
34
  def attributes=(attributes)
24
35
  super(sanitize_for_mass_assignment(attributes))
25
36
  end
26
-
27
37
  end
28
-
29
38
  end
30
-
31
39
  end
@@ -1,68 +1,173 @@
1
1
  module Cequel
2
-
3
2
  module Record
4
-
3
+ #
4
+ # This module provides functionality for loading and saving records to the
5
+ # Cassandra database.
6
+ #
7
+ # @see ClassMethods
8
+ #
9
+ # @since 0.1.0
10
+ #
5
11
  module Persistence
6
-
7
12
  extend ActiveSupport::Concern
8
13
  extend Forwardable
9
14
 
15
+ #
16
+ # Class-level functionality for loading and saving records
17
+ #
10
18
  module ClassMethods
11
-
12
19
  extend Forwardable
13
- def_delegator 'Cequel::Record', :connection
14
20
 
21
+ #
22
+ # Initialize a new record instance, assign attributes, and immediately
23
+ # save it.
24
+ #
25
+ # @param attributes [Hash] attributes to assign to the new record
26
+ # @yieldparam record [Record] record to make modifications before
27
+ # saving
28
+ # @return [Record] self
29
+ #
30
+ # @example Create a new record with attribute assignment
31
+ # Post.create(
32
+ # blog_subdomain: 'cassandra',
33
+ # permalink: 'cequel',
34
+ # title: 'Cequel: The Next Generation'
35
+ # )
36
+ #
37
+ # @example Create a new record with a block
38
+ # Post.create do |post|
39
+ # post.blog = blog
40
+ # post.permalink = 'cequel'
41
+ # post.title = 'Cequel: The Next Generation'
42
+ # end
43
+ #
15
44
  def create(attributes = {}, &block)
16
45
  new(attributes, &block).tap { |record| record.save }
17
46
  end
18
47
 
48
+ # @private
19
49
  def table
20
50
  connection[table_name]
21
51
  end
22
52
 
53
+ # @private
23
54
  def hydrate(row)
24
55
  new_empty(row).__send__(:hydrated!)
25
56
  end
26
57
 
58
+ # @private
59
+ def_delegator 'Cequel::Record', :connection
27
60
  end
28
61
 
29
- def_delegators 'self.class', :connection, :table
30
-
62
+ #
63
+ # @return [Hash] the attributes of this record that make up the primary
64
+ # key
65
+ #
66
+ # @example
67
+ # post = Post.new
68
+ # post.blog_subdomain = 'cassandra'
69
+ # post.permalink = 'cequel'
70
+ # post.title = 'Cequel: The Next Generation'
71
+ # post.key_attributes
72
+ # #=> {:blog_subdomain=>'cassandra', :permalink=>'cequel'}
73
+ #
74
+ # @since 1.0.0
75
+ #
31
76
  def key_attributes
32
77
  @attributes.slice(*self.class.key_column_names)
33
78
  end
34
79
 
80
+ #
81
+ # @return [Array] the values of the primary key columns for this record
82
+ #
83
+ # @see #key_attributes
84
+ # @since 1.0.0
85
+ #
35
86
  def key_values
36
87
  key_attributes.values
37
88
  end
38
89
 
90
+ #
91
+ # Check if an unloaded record exists in the database
92
+ #
93
+ # @return `true` if the record has a corresponding row in the
94
+ # database
95
+ #
96
+ # @since 1.0.0
97
+ #
39
98
  def exists?
40
99
  load!
41
100
  true
42
101
  rescue RecordNotFound
43
102
  false
44
103
  end
45
- alias :exist? :exists?
46
-
104
+ alias_method :exist?, :exists?
105
+
106
+ #
107
+ # Load an unloaded record's row from the database and hydrate the
108
+ # record's attributes
109
+ #
110
+ # @return [Record] self
111
+ #
112
+ # @since 1.0.0
113
+ #
47
114
  def load
48
115
  assert_keys_present!
49
116
  record_collection.load! unless loaded?
50
117
  self
51
118
  end
52
119
 
120
+ #
121
+ # Attempt to load an unloaded record and raise an error if the record
122
+ # does not correspond to a row in the database
123
+ #
124
+ # @return [Record] self
125
+ # @raise [RecordNotFound] if row does not exist in the database
126
+ #
127
+ # @see #load
128
+ # @since 1.0.0
129
+ #
53
130
  def load!
54
131
  load.tap do
55
132
  if transient?
56
- raise RecordNotFound,
57
- "Couldn't find #{self.class.name} with #{key_attributes.inspect}"
133
+ fail RecordNotFound,
134
+ "Couldn't find #{self.class.name} with " \
135
+ "#{key_attributes.inspect}"
58
136
  end
59
137
  end
60
138
  end
61
139
 
140
+ #
141
+ # @overload loaded?
142
+ # @return [Boolean] true if this record's attributes have been loaded
143
+ # from the database
144
+ #
145
+ # @overload loaded?(column)
146
+ # @param [Symbol] column name of column to check if loaded
147
+ # @return [Boolean] true if the named column is loaded in memory
148
+ #
149
+ # @return [Boolean]
150
+ #
151
+ # @since 1.0.0
152
+ #
62
153
  def loaded?(column = nil)
63
154
  !!@loaded && (column.nil? || @attributes.key?(column.to_sym))
64
155
  end
65
156
 
157
+ #
158
+ # Persist the record to the database. If this is a new record, it will
159
+ # be saved using an INSERT statement. If it is an existing record, it
160
+ # will be persisted using a series of `UPDATE` and `DELETE` statements
161
+ # which will persist all changes to the database, including atomic
162
+ # collection modifications.
163
+ #
164
+ # @param options [Options] options for save
165
+ # @option options [Boolean] :validate (true) whether to run validations
166
+ # before saving
167
+ # @return [Boolean] true if record saved successfully, false if invalid
168
+ #
169
+ # @see Validations#save!
170
+ #
66
171
  def save(options = {})
67
172
  options.assert_valid_keys
68
173
  if new_record? then create
@@ -72,11 +177,26 @@ module Cequel
72
177
  true
73
178
  end
74
179
 
180
+ #
181
+ # Set attributes and save the record
182
+ #
183
+ # @param attributes [Hash] hash of attributes to update
184
+ # @return [Boolean] true if saved successfully
185
+ #
186
+ # @see #save
187
+ # @see Properties#attributes=
188
+ # @see Validations#update_attributes!
189
+ #
75
190
  def update_attributes(attributes)
76
191
  self.attributes = attributes
77
192
  save
78
193
  end
79
194
 
195
+ #
196
+ # Remove this record from the database
197
+ #
198
+ # @return [Record] self
199
+ #
80
200
  def destroy
81
201
  assert_keys_present!
82
202
  metal_scope.delete
@@ -84,18 +204,34 @@ module Cequel
84
204
  self
85
205
  end
86
206
 
207
+ #
208
+ # @return true if this is a new, unsaved record
209
+ #
210
+ # @since 1.0.0
211
+ #
87
212
  def new_record?
88
213
  !!@new_record
89
214
  end
90
215
 
216
+ #
217
+ # @return true if this record is persisted in the database
218
+ #
219
+ # @see #transient?
220
+ #
91
221
  def persisted?
92
222
  !!@persisted
93
223
  end
94
224
 
225
+ #
226
+ # @return true if this record is not persisted in the database
227
+ #
228
+ # @see persisted?
229
+ #
95
230
  def transient?
96
231
  !persisted?
97
232
  end
98
233
 
234
+ # @private
99
235
  def hydrate(row)
100
236
  @attributes = row
101
237
  hydrated!
@@ -140,6 +276,9 @@ module Cequel
140
276
 
141
277
  private
142
278
 
279
+ def_delegators 'self.class', :connection, :table
280
+ private :connection, :table
281
+
143
282
  def read_attribute(attribute)
144
283
  super
145
284
  rescue MissingAttributeError
@@ -149,13 +288,14 @@ module Cequel
149
288
 
150
289
  def write_attribute(name, value)
151
290
  column = self.class.reflect_on_column(name)
152
- raise UnknownAttributeError, "unknown attribute: #{name}" unless column
291
+ fail UnknownAttributeError, "unknown attribute: #{name}" unless column
153
292
  value = column.cast(value) unless value.nil?
154
293
 
155
294
  super.tap do
156
295
  unless new_record?
157
296
  if key_attributes.keys.include?(name)
158
- raise ArgumentError, "Can't update key #{name} on persisted record"
297
+ fail ArgumentError,
298
+ "Can't update key #{name} on persisted record"
159
299
  end
160
300
 
161
301
  if value.nil?
@@ -169,8 +309,8 @@ module Cequel
169
309
 
170
310
  def record_collection
171
311
  @record_collection ||=
172
- LazyRecordCollection.new(self.class.at(*key_values)).
173
- tap { |set| set.__setobj__([self]) }
312
+ LazyRecordCollection.new(self.class.at(*key_values))
313
+ .tap { |set| set.__setobj__([self]) }
174
314
  end
175
315
 
176
316
  def hydrated!
@@ -206,13 +346,10 @@ module Cequel
206
346
  def assert_keys_present!
207
347
  missing_keys = key_attributes.select { |k, v| v.nil? }
208
348
  if missing_keys.any?
209
- raise MissingKeyError,
210
- "Missing required key values: #{missing_keys.keys.join(', ')}"
349
+ fail MissingKeyError,
350
+ "Missing required key values: #{missing_keys.keys.join(', ')}"
211
351
  end
212
352
  end
213
-
214
353
  end
215
-
216
354
  end
217
-
218
355
  end