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
@@ -0,0 +1,65 @@
|
|
1
|
+
module Cequel
|
2
|
+
|
3
|
+
module Metal
|
4
|
+
|
5
|
+
class Updater < Writer
|
6
|
+
|
7
|
+
def set(data)
|
8
|
+
data.each_pair do |column, value|
|
9
|
+
prepare_upsert_value(value) do |binding, *values|
|
10
|
+
statements << "#{column} = #{binding}"
|
11
|
+
bind_vars.concat(values)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def list_prepend(column, elements)
|
17
|
+
statements << "#{column} = [?] + #{column}"
|
18
|
+
bind_vars << elements
|
19
|
+
end
|
20
|
+
|
21
|
+
def list_append(column, elements)
|
22
|
+
statements << "#{column} = #{column} + [?]"
|
23
|
+
bind_vars << elements
|
24
|
+
end
|
25
|
+
|
26
|
+
def list_remove(column, value)
|
27
|
+
statements << "#{column} = #{column} - [?]"
|
28
|
+
bind_vars << value
|
29
|
+
end
|
30
|
+
|
31
|
+
def list_replace(column, index, value)
|
32
|
+
statements << "#{column}[#{index}] = ?"
|
33
|
+
bind_vars << value
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_add(column, values)
|
37
|
+
statements << "#{column} = #{column} + {?}"
|
38
|
+
bind_vars << values
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_remove(column, value)
|
42
|
+
statements << "#{column} = #{column} - {?}"
|
43
|
+
bind_vars << ::Kernel.Array(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def map_update(column, updates)
|
47
|
+
binding_pairs = ::Array.new(updates.length) { '?:?' }.join(',')
|
48
|
+
statements << "#{column} = #{column} + {#{binding_pairs}}"
|
49
|
+
bind_vars.concat(updates.flatten)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def write_to_statement(statement)
|
55
|
+
statement.append("UPDATE #{table_name}").
|
56
|
+
append(generate_upsert_options).
|
57
|
+
append(" SET ").
|
58
|
+
append(statements.join(', '), *bind_vars)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Cequel
|
4
|
+
|
5
|
+
module Metal
|
6
|
+
|
7
|
+
class Writer
|
8
|
+
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def initialize(data_set, options = {}, &block)
|
12
|
+
@data_set, @options, @block = data_set, options, block
|
13
|
+
@statements, @bind_vars = [], []
|
14
|
+
SimpleDelegator.new(self).instance_eval(&block) if block
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
return if empty?
|
19
|
+
statement = Statement.new
|
20
|
+
write_to_statement(statement)
|
21
|
+
statement.append(*data_set.row_specifications_cql)
|
22
|
+
data_set.write(*statement.args)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
attr_reader :data_set, :options, :statements, :bind_vars
|
27
|
+
def_delegator :data_set, :table_name
|
28
|
+
def_delegator :statements, :empty?
|
29
|
+
|
30
|
+
def prepare_upsert_value(value)
|
31
|
+
case value
|
32
|
+
when ::Array
|
33
|
+
yield '[?]', value
|
34
|
+
when ::Set then
|
35
|
+
yield '{?}', value.to_a
|
36
|
+
when ::Hash then
|
37
|
+
binding_pairs = ::Array.new(value.length) { '?:?' }.join(',')
|
38
|
+
yield "{#{binding_pairs}}", *value.flatten
|
39
|
+
else
|
40
|
+
yield '?', value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Generate CQL option statement for inserts and updates
|
46
|
+
#
|
47
|
+
# @param [Hash] options options for insert
|
48
|
+
# @option options [Symbol,String] :consistency required consistency for the write
|
49
|
+
# @option options [Integer] :ttl time-to-live in seconds for the written data
|
50
|
+
# @option options [Time,Integer] :timestamp the timestamp associated with the column values
|
51
|
+
#
|
52
|
+
def generate_upsert_options
|
53
|
+
if options.empty?
|
54
|
+
''
|
55
|
+
else
|
56
|
+
' USING ' <<
|
57
|
+
options.map do |key, value|
|
58
|
+
serialized_value =
|
59
|
+
case key
|
60
|
+
when :consistency then value.to_s.upcase
|
61
|
+
when :timestamp then (value.to_f * 1_000_000).to_i
|
62
|
+
else value
|
63
|
+
end
|
64
|
+
"#{key.to_s.upcase} #{serialized_value}"
|
65
|
+
end.join(' AND ')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/lib/cequel/model.rb
CHANGED
@@ -1,100 +1,28 @@
|
|
1
1
|
require 'active_model'
|
2
2
|
|
3
3
|
require 'cequel'
|
4
|
-
require 'cequel/model/associations'
|
5
|
-
require 'cequel/model/callbacks'
|
6
|
-
require 'cequel/model/class_internals'
|
7
|
-
require 'cequel/model/column'
|
8
|
-
require 'cequel/model/counter'
|
9
|
-
require 'cequel/model/dictionary'
|
10
|
-
require 'cequel/model/dirty'
|
11
|
-
require 'cequel/model/dynamic'
|
12
4
|
require 'cequel/model/errors'
|
13
|
-
require 'cequel/model/
|
14
|
-
require 'cequel/model/instance_internals'
|
15
|
-
require 'cequel/model/local_association'
|
16
|
-
require 'cequel/model/mass_assignment_security'
|
17
|
-
require 'cequel/model/magic'
|
18
|
-
require 'cequel/model/naming'
|
19
|
-
require 'cequel/model/observer'
|
20
|
-
require 'cequel/model/persistence'
|
5
|
+
require 'cequel/model/schema'
|
21
6
|
require 'cequel/model/properties'
|
22
|
-
require 'cequel/model/
|
23
|
-
require 'cequel/model/
|
7
|
+
require 'cequel/model/collection'
|
8
|
+
require 'cequel/model/persistence'
|
9
|
+
require 'cequel/model/record_set'
|
24
10
|
require 'cequel/model/scoped'
|
25
|
-
require 'cequel/model/
|
26
|
-
require 'cequel/model/
|
27
|
-
require 'cequel/model/
|
11
|
+
require 'cequel/model/associations'
|
12
|
+
require 'cequel/model/association_collection'
|
13
|
+
require 'cequel/model/belongs_to_association'
|
14
|
+
require 'cequel/model/has_many_association'
|
15
|
+
require 'cequel/model/mass_assignment'
|
16
|
+
require 'cequel/model/callbacks'
|
28
17
|
require 'cequel/model/validations'
|
29
18
|
|
19
|
+
require 'cequel/model/base'
|
20
|
+
|
30
21
|
if defined? Rails
|
31
22
|
require 'cequel/model/railtie'
|
32
23
|
end
|
33
24
|
|
34
25
|
module Cequel
|
35
|
-
|
36
|
-
#
|
37
|
-
# This module adds Cassandra persistence to a class using Cequel.
|
38
|
-
#
|
39
26
|
module Model
|
40
|
-
|
41
|
-
@lock = Monitor.new
|
42
|
-
|
43
|
-
extend ActiveSupport::Concern
|
44
|
-
extend ActiveModel::Observing::ClassMethods
|
45
|
-
|
46
|
-
included do
|
47
|
-
@_cequel = ClassInternals.new(self)
|
48
|
-
|
49
|
-
include Properties
|
50
|
-
include Persistence
|
51
|
-
include Scoped
|
52
|
-
include Naming
|
53
|
-
include Callbacks
|
54
|
-
include Validations
|
55
|
-
include ActiveModel::Observing
|
56
|
-
include Dirty
|
57
|
-
include MassAssignmentSecurity
|
58
|
-
include Associations
|
59
|
-
extend Inheritable
|
60
|
-
extend Magic
|
61
|
-
|
62
|
-
include ActiveModel::Serializers::JSON
|
63
|
-
include ActiveModel::Serializers::Xml
|
64
|
-
|
65
|
-
extend Translation
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.keyspace
|
69
|
-
@lock.synchronize do
|
70
|
-
@keyspace ||= Cequel.connect(@configuration).tap do |keyspace|
|
71
|
-
keyspace.logger = @logger if @logger
|
72
|
-
keyspace.slowlog = @slowlog if @slowlog
|
73
|
-
keyspace.slowlog_threshold = @slowlog_threshold if @slowlog_threshold
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def self.configure(configuration)
|
79
|
-
@configuration = configuration
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.logger=(logger)
|
83
|
-
@logger = logger
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.slowlog=(slowlog)
|
87
|
-
@slowlog = slowlog
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.slowlog_threshold=(slowlog_threshold)
|
91
|
-
@slowlog_threshold = slowlog_threshold
|
92
|
-
end
|
93
|
-
|
94
|
-
def initialize
|
95
|
-
@_cequel = InstanceInternals.new(self)
|
96
|
-
end
|
97
|
-
|
98
27
|
end
|
99
|
-
|
100
28
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Cequel
|
2
|
+
|
3
|
+
module Model
|
4
|
+
|
5
|
+
class AssociationCollection < DelegateClass(RecordSet)
|
6
|
+
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def each(&block)
|
10
|
+
target.each(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def target
|
16
|
+
@target ||= __getobj__.entries
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -6,115 +6,119 @@ module Cequel
|
|
6
6
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@_cequel.associations[name] = association
|
15
|
-
column(association.foreign_key_name, association.primary_key.type)
|
9
|
+
included do
|
10
|
+
class_attribute :parent_association
|
11
|
+
class_attribute :child_associations
|
12
|
+
self.child_associations = {}
|
13
|
+
end
|
16
14
|
|
17
|
-
|
18
|
-
def #{name}
|
19
|
-
if @_cequel.associations.key?(#{name.inspect})
|
20
|
-
return @_cequel.associations[#{name.inspect}]
|
21
|
-
end
|
22
|
-
key = __send__(:#{name}_id)
|
23
|
-
if key
|
24
|
-
@_cequel.associations[#{name.inspect}] =
|
25
|
-
self.class.reflect_on_association(#{name.inspect}).
|
26
|
-
scope(self).first
|
27
|
-
else
|
28
|
-
@_cequel.associations[#{name.inspect}] = nil
|
29
|
-
end
|
30
|
-
end
|
15
|
+
module ClassMethods
|
31
16
|
|
32
|
-
|
33
|
-
@_cequel.associations[#{name.inspect}] = instance
|
34
|
-
if instance.nil?
|
35
|
-
key = nil
|
36
|
-
else
|
37
|
-
key = instance.__send__(instance.class.key_alias)
|
38
|
-
end
|
39
|
-
write_attribute(#{association.foreign_key_name.inspect}, key)
|
40
|
-
end
|
17
|
+
include Forwardable
|
41
18
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
19
|
+
def belongs_to(name)
|
20
|
+
if parent_association
|
21
|
+
raise InvalidRecordConfiguration,
|
22
|
+
"Can't declare more than one belongs_to association"
|
23
|
+
end
|
24
|
+
if table_schema.key_columns.any?
|
25
|
+
raise InvalidRecordConfiguration,
|
26
|
+
"belongs_to association must be declared before declaring key(s)"
|
27
|
+
end
|
28
|
+
self.parent_association = BelongsToAssociation.new(self, name.to_sym)
|
29
|
+
parent_association.association_key_columns.each do |column|
|
30
|
+
key :"#{name}_#{column.name}", column.type
|
31
|
+
end
|
32
|
+
def_parent_association_accessors
|
47
33
|
end
|
48
34
|
|
49
|
-
def has_many(name
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
module_eval <<-RUBY, __FILE__, __LINE__+1
|
55
|
-
def #{name}
|
56
|
-
self.class.reflect_on_association(#{name.inspect}).scope(self)
|
57
|
-
end
|
58
|
-
RUBY
|
35
|
+
def has_many(name)
|
36
|
+
association = HasManyAssociation.new(self, name.to_sym)
|
37
|
+
self.child_associations =
|
38
|
+
child_associations.merge(name => association)
|
39
|
+
def_child_association_reader(association)
|
59
40
|
end
|
60
41
|
|
61
|
-
|
62
|
-
name = name.to_sym
|
63
|
-
@_cequel.associations[name] =
|
64
|
-
RemoteAssociation.new(name, self, options.symbolize_keys)
|
42
|
+
private
|
65
43
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
RUBY
|
44
|
+
def def_parent_association_accessors
|
45
|
+
def_parent_association_reader
|
46
|
+
def_parent_association_writer
|
71
47
|
end
|
72
48
|
|
73
|
-
def
|
74
|
-
|
49
|
+
def def_parent_association_reader
|
50
|
+
def_delegator 'self', :read_parent_association,
|
51
|
+
parent_association.name
|
75
52
|
end
|
76
53
|
|
77
|
-
def
|
78
|
-
|
54
|
+
def def_parent_association_writer
|
55
|
+
def_delegator 'self', :write_parent_association,
|
56
|
+
"#{parent_association.name}="
|
79
57
|
end
|
80
58
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
59
|
+
def def_child_association_reader(association)
|
60
|
+
module_eval <<-RUBY, __FILE__, __LINE__+1
|
61
|
+
def #{association.name}(reload = false)
|
62
|
+
read_child_association(#{association.name.inspect}, reload)
|
63
|
+
end
|
64
|
+
RUBY
|
65
|
+
end
|
87
66
|
|
88
|
-
def destroy(*args)
|
89
|
-
destroy_associated
|
90
|
-
super
|
91
67
|
end
|
92
68
|
|
93
69
|
private
|
94
70
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
71
|
+
def read_parent_association
|
72
|
+
ivar_name = parent_association.instance_variable_name
|
73
|
+
if instance_variable_defined?(ivar_name)
|
74
|
+
return instance_variable_get(ivar_name)
|
75
|
+
end
|
76
|
+
parent_key_values = key_values.
|
77
|
+
first(parent_association.association_key_columns.length)
|
78
|
+
if parent_key_values.none? { |value| value.nil? }
|
79
|
+
clazz = parent_association.association_class
|
80
|
+
parent = parent_key_values.inject(clazz) do |record_set, key_value|
|
81
|
+
record_set[key_value]
|
102
82
|
end
|
83
|
+
instance_variable_set(ivar_name, parent)
|
103
84
|
end
|
104
85
|
end
|
105
86
|
|
106
|
-
def
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
87
|
+
def write_parent_association(parent)
|
88
|
+
unless parent.is_a?(parent_association.association_class)
|
89
|
+
raise ArgumentError,
|
90
|
+
"Wrong class for #{parent_association.name}; expected " +
|
91
|
+
"#{parent_association.association_class.name}, got " +
|
92
|
+
"#{parent.class.name}"
|
93
|
+
end
|
94
|
+
instance_variable_set "@#{parent_association.name}", parent
|
95
|
+
key_column_names = self.class.key_column_names
|
96
|
+
parent.key_attributes.
|
97
|
+
zip(key_column_names) do |(parent_column_name, value), column_name|
|
98
|
+
if value.nil?
|
99
|
+
raise ArgumentError,
|
100
|
+
"Can't set parent association #{parent_association.name.inspect} " +
|
101
|
+
"without value in key #{parent_column_name.inspect}"
|
111
102
|
end
|
103
|
+
write_attribute(column_name, value)
|
112
104
|
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def read_child_association(association_name, reload = false)
|
108
|
+
association = child_associations[association_name]
|
109
|
+
ivar = association.instance_variable_name
|
110
|
+
if !reload && instance_variable_defined?(ivar)
|
111
|
+
return instance_variable_get(ivar)
|
113
112
|
end
|
113
|
+
association_record_set = key_values.inject(association.association_class) do |record_set, key_value|
|
114
|
+
record_set[key_value]
|
115
|
+
end
|
116
|
+
instance_variable_set(
|
117
|
+
ivar, AssociationCollection.new(association_record_set))
|
114
118
|
end
|
115
119
|
|
116
120
|
end
|
117
|
-
|
121
|
+
|
118
122
|
end
|
119
123
|
|
120
124
|
end
|