sessionm-cassandra_object 2.2.51 → 2.2.52
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.
data/lib/cassandra_object.rb
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
module CassandraObject
|
|
2
|
-
class
|
|
2
|
+
class CassandraObjectError < StandardError
|
|
3
3
|
end
|
|
4
4
|
|
|
5
|
-
class RecordNotSaved <
|
|
5
|
+
class RecordNotSaved < CassandraObjectError
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
class RecordNotFound <
|
|
8
|
+
class RecordNotFound < CassandraObjectError
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
class InvalidKey <
|
|
11
|
+
class InvalidKey < CassandraObjectError
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
require 'active_support/core_ext/hash/except'
|
|
2
|
+
require 'active_support/core_ext/object/try'
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
|
5
|
+
|
|
6
|
+
module CassandraObject
|
|
7
|
+
module NestedAttributes #:nodoc:
|
|
8
|
+
class TooManyRecords < CassandraObjectError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
|
|
13
|
+
included do
|
|
14
|
+
class_inheritable_accessor :nested_attributes_options, :instance_writer => false
|
|
15
|
+
self.nested_attributes_options = {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
module ClassMethods
|
|
19
|
+
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } }
|
|
20
|
+
|
|
21
|
+
def accepts_nested_attributes_for(*attr_names)
|
|
22
|
+
options = { :allow_destroy => false, :update_only => false }
|
|
23
|
+
options.update(attr_names.extract_options!)
|
|
24
|
+
options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only)
|
|
25
|
+
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
|
|
26
|
+
|
|
27
|
+
attr_names.each do |association_name|
|
|
28
|
+
if reflection = reflect_on_association(association_name)
|
|
29
|
+
reflection.options[:autosave] = true
|
|
30
|
+
add_autosave_association_callbacks(reflection)
|
|
31
|
+
nested_attributes_options[association_name.to_sym] = options
|
|
32
|
+
type = (reflection.collection? ? :collection : :one_to_one)
|
|
33
|
+
|
|
34
|
+
# def pirate_attributes=(attributes)
|
|
35
|
+
# assign_nested_attributes_for_one_to_one_association(:pirate, attributes)
|
|
36
|
+
# end
|
|
37
|
+
class_eval <<-eoruby, __FILE__, __LINE__ + 1
|
|
38
|
+
if method_defined?(:#{association_name}_attributes=)
|
|
39
|
+
remove_method(:#{association_name}_attributes=)
|
|
40
|
+
end
|
|
41
|
+
def #{association_name}_attributes=(attributes)
|
|
42
|
+
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
|
|
43
|
+
end
|
|
44
|
+
eoruby
|
|
45
|
+
else
|
|
46
|
+
raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def _destroy
|
|
53
|
+
marked_for_destruction?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
UNASSIGNABLE_KEYS = %w( id _destroy )
|
|
59
|
+
|
|
60
|
+
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
|
61
|
+
options = nested_attributes_options[association_name]
|
|
62
|
+
attributes = attributes.with_indifferent_access
|
|
63
|
+
check_existing_record = (options[:update_only] || !attributes['id'].blank?)
|
|
64
|
+
|
|
65
|
+
if check_existing_record && (record = send(association_name)) &&
|
|
66
|
+
(options[:update_only] || record.id.to_s == attributes['id'].to_s)
|
|
67
|
+
assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
|
|
68
|
+
|
|
69
|
+
elsif !attributes['id'].blank?
|
|
70
|
+
raise_nested_attributes_record_not_found(association_name, attributes['id'])
|
|
71
|
+
|
|
72
|
+
elsif !reject_new_record?(association_name, attributes)
|
|
73
|
+
method = "build_#{association_name}"
|
|
74
|
+
if respond_to?(method)
|
|
75
|
+
send(method, attributes.except(*UNASSIGNABLE_KEYS))
|
|
76
|
+
else
|
|
77
|
+
raise ArgumentError, "Cannot build association #{association_name}. Are you trying to build a polymorphic one-to-one association?"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
|
83
|
+
options = nested_attributes_options[association_name]
|
|
84
|
+
|
|
85
|
+
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
|
86
|
+
raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if options[:limit] && attributes_collection.size > options[:limit]
|
|
90
|
+
raise TooManyRecords, "Maximum #{options[:limit]} records are allowed. Got #{attributes_collection.size} records instead."
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if attributes_collection.is_a? Hash
|
|
94
|
+
keys = attributes_collection.keys
|
|
95
|
+
attributes_collection = if keys.include?('id') || keys.include?(:id)
|
|
96
|
+
Array.wrap(attributes_collection)
|
|
97
|
+
else
|
|
98
|
+
attributes_collection.sort_by { |i, _| i.to_i }.map { |_, attributes| attributes }
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
association = send(association_name)
|
|
103
|
+
|
|
104
|
+
existing_records = if association.loaded?
|
|
105
|
+
association.to_a
|
|
106
|
+
else
|
|
107
|
+
attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
|
|
108
|
+
attribute_ids.present? ? association.all(:conditions => {association.primary_key => attribute_ids}) : []
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
attributes_collection.each do |attributes|
|
|
112
|
+
attributes = attributes.with_indifferent_access
|
|
113
|
+
|
|
114
|
+
if attributes['id'].blank?
|
|
115
|
+
unless reject_new_record?(association_name, attributes)
|
|
116
|
+
association.build(attributes.except(*UNASSIGNABLE_KEYS))
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
|
|
120
|
+
association.send(:add_record_to_target_with_callbacks, existing_record) if !association.loaded? && !call_reject_if(association_name, attributes)
|
|
121
|
+
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
|
122
|
+
|
|
123
|
+
else
|
|
124
|
+
raise_nested_attributes_record_not_found(association_name, attributes['id'])
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Updates a record with the +attributes+ or marks it for destruction if
|
|
130
|
+
# +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
|
|
131
|
+
def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
|
|
132
|
+
record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
|
|
133
|
+
record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Determines if a hash contains a truthy _destroy key.
|
|
137
|
+
def has_destroy_flag?(hash)
|
|
138
|
+
value = hash['_destroy']
|
|
139
|
+
if value.is_a?(String) && value.blank?
|
|
140
|
+
nil
|
|
141
|
+
else
|
|
142
|
+
[true, 1, '1', 't', 'T', 'true', 'TRUE'].include?(value)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Determines if a new record should be build by checking for
|
|
147
|
+
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
|
148
|
+
# association and evaluates to +true+.
|
|
149
|
+
def reject_new_record?(association_name, attributes)
|
|
150
|
+
has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def call_reject_if(association_name, attributes)
|
|
154
|
+
return false if has_destroy_flag?(attributes)
|
|
155
|
+
case callback = nested_attributes_options[association_name][:reject_if]
|
|
156
|
+
when Symbol
|
|
157
|
+
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
|
|
158
|
+
when Proc
|
|
159
|
+
callback.call(attributes)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def raise_nested_attributes_record_not_found(association_name, record_id)
|
|
164
|
+
reflection = self.class.reflect_on_association(association_name)
|
|
165
|
+
raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
metadata
CHANGED
|
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
|
5
5
|
segments:
|
|
6
6
|
- 2
|
|
7
7
|
- 2
|
|
8
|
-
-
|
|
9
|
-
version: 2.2.
|
|
8
|
+
- 52
|
|
9
|
+
version: 2.2.52
|
|
10
10
|
platform: ruby
|
|
11
11
|
authors:
|
|
12
12
|
- Michael Koziarski
|
|
@@ -16,7 +16,7 @@ autorequire:
|
|
|
16
16
|
bindir: bin
|
|
17
17
|
cert_chain: []
|
|
18
18
|
|
|
19
|
-
date: 2012-05-
|
|
19
|
+
date: 2012-05-29 00:00:00 -04:00
|
|
20
20
|
default_executable:
|
|
21
21
|
dependencies:
|
|
22
22
|
- !ruby/object:Gem::Dependency
|
|
@@ -106,6 +106,7 @@ files:
|
|
|
106
106
|
- lib/cassandra_object/migrations.rb
|
|
107
107
|
- lib/cassandra_object/migrations/migration.rb
|
|
108
108
|
- lib/cassandra_object/mocking.rb
|
|
109
|
+
- lib/cassandra_object/nested_attributes.rb
|
|
109
110
|
- lib/cassandra_object/persistence.rb
|
|
110
111
|
- lib/cassandra_object/railtie.rb
|
|
111
112
|
- lib/cassandra_object/row_ttl.rb
|