active_data 0.3.0 → 1.0.0
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 +4 -4
- data/.gitignore +1 -1
- data/.rspec +0 -1
- data/.rvmrc +1 -1
- data/.travis.yml +13 -6
- data/Appraisals +7 -0
- data/Gemfile +1 -5
- data/Guardfile +68 -15
- data/README.md +144 -2
- data/active_data.gemspec +19 -11
- data/gemfiles/rails.4.0.gemfile +14 -0
- data/gemfiles/rails.4.1.gemfile +14 -0
- data/gemfiles/rails.4.2.gemfile +14 -0
- data/gemfiles/rails.5.0.gemfile +14 -0
- data/lib/active_data.rb +120 -3
- data/lib/active_data/active_record/associations.rb +50 -0
- data/lib/active_data/active_record/nested_attributes.rb +24 -0
- data/lib/active_data/config.rb +40 -0
- data/lib/active_data/errors.rb +93 -0
- data/lib/active_data/extensions.rb +33 -0
- data/lib/active_data/model.rb +16 -74
- data/lib/active_data/model/associations.rb +84 -15
- data/lib/active_data/model/associations/base.rb +79 -0
- data/lib/active_data/model/associations/collection/embedded.rb +12 -0
- data/lib/active_data/model/associations/collection/proxy.rb +32 -0
- data/lib/active_data/model/associations/collection/referenced.rb +26 -0
- data/lib/active_data/model/associations/embeds_many.rb +124 -18
- data/lib/active_data/model/associations/embeds_one.rb +90 -15
- data/lib/active_data/model/associations/nested_attributes.rb +180 -0
- data/lib/active_data/model/associations/references_many.rb +96 -0
- data/lib/active_data/model/associations/references_one.rb +83 -0
- data/lib/active_data/model/associations/reflections/base.rb +100 -0
- data/lib/active_data/model/associations/reflections/embeds_many.rb +25 -0
- data/lib/active_data/model/associations/reflections/embeds_one.rb +49 -0
- data/lib/active_data/model/associations/reflections/reference_reflection.rb +45 -0
- data/lib/active_data/model/associations/reflections/references_many.rb +28 -0
- data/lib/active_data/model/associations/reflections/references_one.rb +28 -0
- data/lib/active_data/model/associations/validations.rb +63 -0
- data/lib/active_data/model/attributes.rb +247 -0
- data/lib/active_data/model/attributes/attribute.rb +73 -0
- data/lib/active_data/model/attributes/base.rb +116 -0
- data/lib/active_data/model/attributes/collection.rb +17 -0
- data/lib/active_data/model/attributes/dictionary.rb +26 -0
- data/lib/active_data/model/attributes/localized.rb +42 -0
- data/lib/active_data/model/attributes/reference_many.rb +21 -0
- data/lib/active_data/model/attributes/reference_one.rb +42 -0
- data/lib/active_data/model/attributes/reflections/attribute.rb +55 -0
- data/lib/active_data/model/attributes/reflections/base.rb +62 -0
- data/lib/active_data/model/attributes/reflections/collection.rb +10 -0
- data/lib/active_data/model/attributes/reflections/dictionary.rb +13 -0
- data/lib/active_data/model/attributes/reflections/localized.rb +43 -0
- data/lib/active_data/model/attributes/reflections/reference_many.rb +10 -0
- data/lib/active_data/model/attributes/reflections/reference_one.rb +58 -0
- data/lib/active_data/model/attributes/reflections/represents.rb +55 -0
- data/lib/active_data/model/attributes/represents.rb +64 -0
- data/lib/active_data/model/callbacks.rb +71 -0
- data/lib/active_data/model/conventions.rb +35 -0
- data/lib/active_data/model/dirty.rb +77 -0
- data/lib/active_data/model/lifecycle.rb +307 -0
- data/lib/active_data/model/localization.rb +21 -0
- data/lib/active_data/model/persistence.rb +57 -0
- data/lib/active_data/model/primary.rb +51 -0
- data/lib/active_data/model/scopes.rb +77 -0
- data/lib/active_data/model/validations.rb +27 -0
- data/lib/active_data/model/validations/associated.rb +19 -0
- data/lib/active_data/model/validations/nested.rb +39 -0
- data/lib/active_data/railtie.rb +7 -0
- data/lib/active_data/version.rb +1 -1
- data/spec/lib/active_data/active_record/associations_spec.rb +149 -0
- data/spec/lib/active_data/active_record/nested_attributes_spec.rb +16 -0
- data/spec/lib/active_data/config_spec.rb +44 -0
- data/spec/lib/active_data/model/associations/embeds_many_spec.rb +362 -52
- data/spec/lib/active_data/model/associations/embeds_one_spec.rb +250 -31
- data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +23 -0
- data/spec/lib/active_data/model/associations/references_many_spec.rb +196 -0
- data/spec/lib/active_data/model/associations/references_one_spec.rb +134 -0
- data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +144 -0
- data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +116 -0
- data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +255 -0
- data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +208 -0
- data/spec/lib/active_data/model/associations/validations_spec.rb +153 -0
- data/spec/lib/active_data/model/associations_spec.rb +189 -0
- data/spec/lib/active_data/model/attributes/attribute_spec.rb +144 -0
- data/spec/lib/active_data/model/attributes/base_spec.rb +82 -0
- data/spec/lib/active_data/model/attributes/collection_spec.rb +73 -0
- data/spec/lib/active_data/model/attributes/dictionary_spec.rb +93 -0
- data/spec/lib/active_data/model/attributes/localized_spec.rb +88 -33
- data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +72 -0
- data/spec/lib/active_data/model/attributes/reflections/base_spec.rb +56 -0
- data/spec/lib/active_data/model/attributes/reflections/collection_spec.rb +37 -0
- data/spec/lib/active_data/model/attributes/reflections/dictionary_spec.rb +43 -0
- data/spec/lib/active_data/model/attributes/reflections/localized_spec.rb +37 -0
- data/spec/lib/active_data/model/attributes/reflections/represents_spec.rb +70 -0
- data/spec/lib/active_data/model/attributes/represents_spec.rb +153 -0
- data/spec/lib/active_data/model/attributes_spec.rb +243 -0
- data/spec/lib/active_data/model/callbacks_spec.rb +338 -0
- data/spec/lib/active_data/model/conventions_spec.rb +12 -0
- data/spec/lib/active_data/model/dirty_spec.rb +75 -0
- data/spec/lib/active_data/model/lifecycle_spec.rb +330 -0
- data/spec/lib/active_data/model/nested_attributes.rb +202 -0
- data/spec/lib/active_data/model/persistence_spec.rb +47 -0
- data/spec/lib/active_data/model/primary_spec.rb +84 -0
- data/spec/lib/active_data/model/scopes_spec.rb +88 -0
- data/spec/lib/active_data/model/typecasting_spec.rb +192 -0
- data/spec/lib/active_data/model/validations/associated_spec.rb +94 -0
- data/spec/lib/active_data/model/validations/nested_spec.rb +93 -0
- data/spec/lib/active_data/model/validations_spec.rb +31 -0
- data/spec/lib/active_data/model_spec.rb +1 -32
- data/spec/lib/active_data_spec.rb +12 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/model_helpers.rb +10 -0
- metadata +246 -54
- data/gemfiles/Gemfile.rails-3 +0 -14
- data/lib/active_data/attributes/base.rb +0 -69
- data/lib/active_data/attributes/localized.rb +0 -42
- data/lib/active_data/model/associations/association.rb +0 -30
- data/lib/active_data/model/attributable.rb +0 -122
- data/lib/active_data/model/collectionizable.rb +0 -55
- data/lib/active_data/model/collectionizable/proxy.rb +0 -42
- data/lib/active_data/model/extensions.rb +0 -9
- data/lib/active_data/model/extensions/array.rb +0 -24
- data/lib/active_data/model/extensions/big_decimal.rb +0 -17
- data/lib/active_data/model/extensions/boolean.rb +0 -38
- data/lib/active_data/model/extensions/date.rb +0 -17
- data/lib/active_data/model/extensions/date_time.rb +0 -17
- data/lib/active_data/model/extensions/float.rb +0 -17
- data/lib/active_data/model/extensions/hash.rb +0 -22
- data/lib/active_data/model/extensions/integer.rb +0 -17
- data/lib/active_data/model/extensions/localized.rb +0 -22
- data/lib/active_data/model/extensions/object.rb +0 -17
- data/lib/active_data/model/extensions/string.rb +0 -17
- data/lib/active_data/model/extensions/time.rb +0 -17
- data/lib/active_data/model/localizable.rb +0 -31
- data/lib/active_data/model/nested_attributes.rb +0 -58
- data/lib/active_data/model/parameterizable.rb +0 -29
- data/lib/active_data/validations.rb +0 -7
- data/lib/active_data/validations/associated.rb +0 -17
- data/spec/lib/active_data/model/attributable_spec.rb +0 -191
- data/spec/lib/active_data/model/collectionizable_spec.rb +0 -60
- data/spec/lib/active_data/model/nested_attributes_spec.rb +0 -67
- data/spec/lib/active_data/model/type_cast_spec.rb +0 -116
- data/spec/lib/active_data/validations/associated_spec.rb +0 -88
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module ActiveRecord
|
3
|
+
module Associations
|
4
|
+
module Reflections
|
5
|
+
class EmbedsOne < ActiveData::Model::Associations::Reflections::EmbedsOne
|
6
|
+
def is_a? klass
|
7
|
+
super || klass == ::ActiveRecord::Reflection::AssociationReflection
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class EmbedsMany < ActiveData::Model::Associations::Reflections::EmbedsMany
|
12
|
+
def is_a? klass
|
13
|
+
super || klass == ::ActiveRecord::Reflection::AssociationReflection
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
included do
|
21
|
+
{ embeds_many: Reflections::EmbedsMany, embeds_one: Reflections::EmbedsOne }.each do |(name, reflection_class)|
|
22
|
+
define_singleton_method name do |name, options = {}, &block|
|
23
|
+
reflection = reflection_class.build(self, self, name, options.reverse_merge(
|
24
|
+
read: ->(reflection, object) {
|
25
|
+
value = object.read_attribute(reflection.name)
|
26
|
+
JSON.parse(value) if value.present?
|
27
|
+
},
|
28
|
+
write: ->(reflection, object, value) {
|
29
|
+
object.send(:write_attribute, reflection.name, value ? value.to_json : nil)
|
30
|
+
}
|
31
|
+
), &block)
|
32
|
+
if ::ActiveRecord::Reflection.respond_to? :add_reflection
|
33
|
+
::ActiveRecord::Reflection.add_reflection self, reflection.name, reflection
|
34
|
+
else
|
35
|
+
self.reflections = reflections.merge(reflection.name => reflection)
|
36
|
+
end
|
37
|
+
|
38
|
+
callback_name = :"update_#{reflection.name}_association"
|
39
|
+
before_save callback_name
|
40
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
41
|
+
def #{callback_name}
|
42
|
+
association(:#{reflection.name}).apply_changes!
|
43
|
+
end
|
44
|
+
METHOD
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module ActiveRecord
|
3
|
+
module NestedAttributes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
singleton_class.alias_method_chain :accepts_nested_attributes_for, :active_data
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def accepts_nested_attributes_for_with_active_data *attr_names
|
12
|
+
options = attr_names.extract_options!
|
13
|
+
active_data_associations, active_record_association = attr_names.partition do |association_name|
|
14
|
+
reflect_on_association(association_name).is_a?(ActiveData::Model::Associations::Reflections::Base)
|
15
|
+
end
|
16
|
+
|
17
|
+
ActiveData::Model::Associations::NestedAttributes::NestedAttributesMethods
|
18
|
+
.accepts_nested_attributes_for self, *active_data_associations, options.dup
|
19
|
+
accepts_nested_attributes_for_without_active_data *active_record_association, options.dup
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActiveData
|
2
|
+
class Config
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
attr_accessor :include_root_in_json, :i18n_scope, :logger, :primary_attribute,
|
6
|
+
:_normalizers, :_typecasters
|
7
|
+
|
8
|
+
def self.delegated
|
9
|
+
public_instance_methods - superclass.public_instance_methods - Singleton.public_instance_methods
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@include_root_in_json = false
|
14
|
+
@i18n_scope = :active_data
|
15
|
+
@logger = Logger.new(STDERR)
|
16
|
+
@primary_attribute = :id
|
17
|
+
@_normalizers = {}
|
18
|
+
@_typecasters = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def normalizer name, &block
|
22
|
+
if block
|
23
|
+
_normalizers[name.to_sym] = block
|
24
|
+
else
|
25
|
+
_normalizers[name.to_sym] or raise NormalizerMissing.new(name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def typecaster *classes, &block
|
30
|
+
classes = classes.flatten
|
31
|
+
if block
|
32
|
+
_typecasters[classes.first.to_s.camelize] = block
|
33
|
+
else
|
34
|
+
_typecasters[classes.detect do |klass|
|
35
|
+
_typecasters[klass.to_s.camelize]
|
36
|
+
end.to_s.camelize] or raise TypecasterMissing.new(*classes)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ActiveData
|
2
|
+
class ActiveDataError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class NotFound < ActiveDataError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Backported from active_model 5
|
9
|
+
class ValidationError < ActiveDataError
|
10
|
+
attr_reader :model
|
11
|
+
|
12
|
+
def initialize(model)
|
13
|
+
@model = model
|
14
|
+
errors = @model.errors.full_messages.join(", ")
|
15
|
+
super(I18n.t(:"#{@model.class.i18n_scope}.errors.messages.model_invalid", errors: errors, default: :'errors.messages.model_invalid'))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class UnsavableObject < ActiveDataError
|
20
|
+
end
|
21
|
+
|
22
|
+
class UndestroyableObject < ActiveDataError
|
23
|
+
end
|
24
|
+
|
25
|
+
class ObjectNotSaved < ActiveDataError
|
26
|
+
end
|
27
|
+
|
28
|
+
class ObjectNotDestroyed < ActiveDataError
|
29
|
+
end
|
30
|
+
|
31
|
+
class AssociationChangesNotApplied < ActiveDataError
|
32
|
+
end
|
33
|
+
|
34
|
+
class AssociationTypeMismatch < ActiveDataError
|
35
|
+
def initialize expected, got
|
36
|
+
super "Expected `#{expected}` (##{expected.object_id}), but got `#{got}` (##{got.object_id})"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ObjectNotFound < ActiveDataError
|
41
|
+
def initialize object, association_name, record_id
|
42
|
+
message = "Couldn't find #{object.class.reflect_on_association(association_name).klass.name}" \
|
43
|
+
"with #{object.respond_to?(:_primary_name) ? object._primary_name : 'id'} = #{record_id} for #{object.inspect}"
|
44
|
+
super message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class TooManyObjects < ActiveDataError
|
49
|
+
def initialize limit, actual_size
|
50
|
+
super "Maximum #{limit} objects are allowed. Got #{actual_size} objects instead."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class UndefinedPrimaryAttribute < ActiveDataError
|
55
|
+
def initialize klass, association_name
|
56
|
+
super <<-EOS
|
57
|
+
Undefined primary attribute for `#{association_name}` in #{klass}.
|
58
|
+
It is required for embeds_many nested attributes proper operation.
|
59
|
+
You can define this association as:
|
60
|
+
|
61
|
+
embeds_many :#{association_name} do
|
62
|
+
primary :attribute_name
|
63
|
+
end
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class NormalizerMissing < NoMethodError
|
69
|
+
def initialize name
|
70
|
+
super <<-EOS
|
71
|
+
Could not find normalizer `:#{name}`
|
72
|
+
You can define it with:
|
73
|
+
|
74
|
+
ActiveData.normalizer(:#{name}) do |value, options|
|
75
|
+
# do some staff with value and options
|
76
|
+
end
|
77
|
+
EOS
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class TypecasterMissing < NoMethodError
|
82
|
+
def initialize *classes
|
83
|
+
super <<-EOS
|
84
|
+
Could not find typecaster for #{classes}
|
85
|
+
You can define it with:
|
86
|
+
|
87
|
+
ActiveData.typecaster('#{classes.first}') do |value|
|
88
|
+
# do some staff with value and options
|
89
|
+
end
|
90
|
+
EOS
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
unless defined?(Boolean)
|
2
|
+
class Boolean; end
|
3
|
+
end
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'uuidtools'
|
7
|
+
rescue LoadError
|
8
|
+
else
|
9
|
+
class ActiveData::UUID < UUIDTools::UUID
|
10
|
+
def as_json *_
|
11
|
+
to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_param
|
15
|
+
to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse_string value
|
19
|
+
return nil if value.length == 0
|
20
|
+
if value.length == 36
|
21
|
+
parse value
|
22
|
+
elsif value.length == 32
|
23
|
+
parse_hexdigest value
|
24
|
+
else
|
25
|
+
parse_raw value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
"#<ActiveData::UUID:#{to_s}>"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/active_data/model.rb
CHANGED
@@ -1,88 +1,30 @@
|
|
1
|
-
require 'active_data/model/
|
2
|
-
require 'active_data/model/
|
3
|
-
require 'active_data/model/
|
4
|
-
require 'active_data/model/
|
1
|
+
require 'active_data/model/conventions'
|
2
|
+
require 'active_data/model/attributes'
|
3
|
+
require 'active_data/model/scopes'
|
4
|
+
require 'active_data/model/primary'
|
5
|
+
require 'active_data/model/lifecycle'
|
6
|
+
require 'active_data/model/persistence'
|
7
|
+
require 'active_data/model/callbacks'
|
5
8
|
require 'active_data/model/associations'
|
6
|
-
require 'active_data/model/
|
7
|
-
require 'active_data/model/
|
8
|
-
|
9
|
-
require 'active_data/attributes/base'
|
10
|
-
require 'active_data/attributes/localized'
|
9
|
+
require 'active_data/model/validations'
|
10
|
+
require 'active_data/model/localization'
|
11
|
+
require 'active_data/model/dirty'
|
11
12
|
|
12
13
|
module ActiveData
|
13
14
|
module Model
|
14
|
-
class NotFound < ::StandardError
|
15
|
-
end
|
16
|
-
|
17
15
|
extend ActiveSupport::Concern
|
18
16
|
|
19
17
|
included do
|
20
|
-
include ActiveModel::Conversion
|
21
|
-
include ActiveModel::Validations
|
22
|
-
include ActiveModel::Serialization
|
23
|
-
include ActiveModel::Serializers::JSON
|
24
|
-
|
25
|
-
include Attributable
|
26
|
-
include Localizable
|
27
|
-
include Collectionizable
|
28
|
-
include Associations
|
29
|
-
include NestedAttributes
|
30
|
-
include Parameterizable
|
31
18
|
extend ActiveModel::Naming
|
32
19
|
extend ActiveModel::Translation
|
33
20
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@attributes = self.class.initialize_attributes
|
38
|
-
@new_record = true
|
39
|
-
assign_attributes attributes
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.i18n_scope
|
43
|
-
:active_data
|
44
|
-
end
|
45
|
-
|
46
|
-
def serializable_hash *args
|
47
|
-
super(*args).stringify_keys!
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
module ClassMethods
|
52
|
-
def instantiate data
|
53
|
-
return data if data.class.include? ActiveData::Model
|
54
|
-
|
55
|
-
data = data.symbolize_keys
|
56
|
-
instance = allocate
|
57
|
-
|
58
|
-
attributes = initialize_attributes
|
59
|
-
attributes.merge!(data.slice(*attributes.keys))
|
60
|
-
|
61
|
-
data.slice(*association_names.map(&:to_sym)).each do |association, data|
|
62
|
-
instance.send(:"#{association}=", data)
|
63
|
-
end
|
64
|
-
|
65
|
-
instance.instance_variable_set(:@attributes, attributes)
|
66
|
-
instance.instance_variable_set(:@new_record, false)
|
67
|
-
|
68
|
-
instance
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def errors
|
73
|
-
@errors ||= ActiveModel::Errors.new(self)
|
74
|
-
end
|
75
|
-
|
76
|
-
def persisted?
|
77
|
-
!@new_record
|
78
|
-
end
|
79
|
-
|
80
|
-
def == other
|
81
|
-
other.instance_of?(self.class) && other.attributes == attributes
|
82
|
-
end
|
21
|
+
include ActiveModel::Conversion
|
22
|
+
include ActiveModel::Serialization
|
23
|
+
include ActiveModel::Serializers::JSON
|
83
24
|
|
84
|
-
|
85
|
-
|
25
|
+
include Conventions
|
26
|
+
include Attributes
|
27
|
+
include Validations
|
86
28
|
end
|
87
29
|
end
|
88
30
|
end
|
@@ -1,6 +1,22 @@
|
|
1
|
-
require 'active_data/model/associations/
|
2
|
-
require 'active_data/model/associations/
|
1
|
+
require 'active_data/model/associations/collection/proxy'
|
2
|
+
require 'active_data/model/associations/collection/embedded'
|
3
|
+
require 'active_data/model/associations/collection/referenced'
|
4
|
+
|
5
|
+
require 'active_data/model/associations/reflections/base'
|
6
|
+
require 'active_data/model/associations/reflections/embeds_one'
|
7
|
+
require 'active_data/model/associations/reflections/embeds_many'
|
8
|
+
require 'active_data/model/associations/reflections/reference_reflection'
|
9
|
+
require 'active_data/model/associations/reflections/references_one'
|
10
|
+
require 'active_data/model/associations/reflections/references_many'
|
11
|
+
|
12
|
+
require 'active_data/model/associations/base'
|
3
13
|
require 'active_data/model/associations/embeds_one'
|
14
|
+
require 'active_data/model/associations/embeds_many'
|
15
|
+
require 'active_data/model/associations/references_one'
|
16
|
+
require 'active_data/model/associations/references_many'
|
17
|
+
|
18
|
+
require 'active_data/model/associations/nested_attributes'
|
19
|
+
require 'active_data/model/associations/validations'
|
4
20
|
|
5
21
|
module ActiveData
|
6
22
|
module Model
|
@@ -8,39 +24,92 @@ module ActiveData
|
|
8
24
|
extend ActiveSupport::Concern
|
9
25
|
|
10
26
|
included do
|
11
|
-
|
27
|
+
include NestedAttributes
|
28
|
+
include Validations
|
29
|
+
|
30
|
+
class_attribute :_associations, :_association_aliases, instance_reader: false, instance_writer: false
|
12
31
|
self._associations = {}
|
32
|
+
self._association_aliases = {}
|
33
|
+
|
34
|
+
delegate :association_names, to: 'self.class'
|
13
35
|
|
14
|
-
{
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
36
|
+
{
|
37
|
+
embeds_many: Reflections::EmbedsMany,
|
38
|
+
embeds_one: Reflections::EmbedsOne,
|
39
|
+
references_one: Reflections::ReferencesOne,
|
40
|
+
references_many: Reflections::ReferencesMany
|
41
|
+
}.each do |(name, reflection_class)|
|
42
|
+
define_singleton_method name do |*args, &block|
|
43
|
+
reflection = reflection_class.build self, generated_associations_methods, *args, &block
|
44
|
+
self._associations = _associations.merge(reflection.name => reflection)
|
45
|
+
reflection
|
19
46
|
end
|
20
47
|
end
|
21
48
|
end
|
22
49
|
|
23
50
|
module ClassMethods
|
51
|
+
def reflections
|
52
|
+
_associations
|
53
|
+
end
|
24
54
|
|
25
|
-
def
|
26
|
-
|
55
|
+
def alias_association(alias_name, association_name)
|
56
|
+
reflection = reflect_on_association(association_name)
|
57
|
+
raise ArgumentError.new("Can't alias undefined association `#{attribute_name}` on #{self}") unless reflection
|
58
|
+
reflection.class.generate_methods alias_name, generated_associations_methods
|
59
|
+
self._association_aliases = _association_aliases.merge(alias_name.to_sym => reflection.name)
|
60
|
+
reflection
|
27
61
|
end
|
28
62
|
|
29
|
-
def
|
30
|
-
|
63
|
+
def reflect_on_association name
|
64
|
+
name = name.to_sym
|
65
|
+
_associations[_association_aliases[name] || name]
|
31
66
|
end
|
32
67
|
|
33
68
|
def association_names
|
34
69
|
_associations.keys
|
35
70
|
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def attributes_for_inspect
|
75
|
+
(_associations.map do |name, reflection|
|
76
|
+
"#{name}: #{reflection.inspect}"
|
77
|
+
end + [super]).join(', ')
|
78
|
+
end
|
79
|
+
|
80
|
+
def generated_associations_methods
|
81
|
+
@generated_associations_methods ||= const_set(:GeneratedAssociationsMethods, Module.new)
|
82
|
+
.tap { |proxy| include proxy }
|
83
|
+
end
|
36
84
|
end
|
37
85
|
|
38
86
|
def == other
|
39
|
-
super
|
40
|
-
|
87
|
+
super && association_names.all? do |association|
|
88
|
+
public_send(association) == other.public_send(association)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
alias_method :eql?, :==
|
92
|
+
|
93
|
+
def association name
|
94
|
+
if reflection = self.class.reflect_on_association(name)
|
95
|
+
(@_associations ||= {})[reflection.name] ||= reflection.build_association(self)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def apply_association_changes!
|
100
|
+
association_names.all? do |name|
|
101
|
+
association(name).apply_changes!
|
41
102
|
end
|
42
103
|
end
|
43
104
|
|
105
|
+
private
|
106
|
+
|
107
|
+
def attributes_for_inspect
|
108
|
+
(association_names.map do |name|
|
109
|
+
association = association(name)
|
110
|
+
"#{name}: #{association.inspect}"
|
111
|
+
end + [super]).join(', ')
|
112
|
+
end
|
44
113
|
end
|
45
114
|
end
|
46
|
-
end
|
115
|
+
end
|