datamappify 0.60.0 → 0.70.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.md +20 -0
- data/README.md +120 -3
- data/datamappify.gemspec +3 -3
- data/lib/datamappify/data/criteria/active_record/count.rb +0 -2
- data/lib/datamappify/data/criteria/active_record/criteria.rb +10 -0
- data/lib/datamappify/data/criteria/active_record/criteria_method.rb +65 -0
- data/lib/datamappify/data/criteria/active_record/find.rb +10 -2
- data/lib/datamappify/data/criteria/active_record/find_by_key.rb +4 -2
- data/lib/datamappify/data/criteria/active_record/limit.rb +10 -0
- data/lib/datamappify/data/criteria/active_record/match.rb +40 -0
- data/lib/datamappify/data/criteria/active_record/order.rb +41 -0
- data/lib/datamappify/data/criteria/active_record/rollback.rb +13 -0
- data/lib/datamappify/data/criteria/active_record/save.rb +1 -4
- data/lib/datamappify/data/criteria/active_record/save_by_key.rb +0 -1
- data/lib/datamappify/data/criteria/active_record/where.rb +18 -0
- data/lib/datamappify/data/criteria/common.rb +5 -2
- data/lib/datamappify/data/criteria/concerns/update_primary_record.rb +2 -0
- data/lib/datamappify/data/criteria/relational/concerns/find.rb +35 -0
- data/lib/datamappify/data/criteria/relational/concerns/find_by_key.rb +19 -0
- data/lib/datamappify/data/criteria/relational/criteria.rb +29 -0
- data/lib/datamappify/data/criteria/relational/{find_multiple.rb → criteria_base_method.rb} +2 -28
- data/lib/datamappify/data/criteria/relational/criteria_method.rb +44 -0
- data/lib/datamappify/data/criteria/relational/limit.rb +13 -0
- data/lib/datamappify/data/criteria/relational/save.rb +12 -0
- data/lib/datamappify/data/criteria/sequel/count.rb +0 -2
- data/lib/datamappify/data/criteria/sequel/criteria.rb +10 -0
- data/lib/datamappify/data/criteria/sequel/criteria_method.rb +51 -0
- data/lib/datamappify/data/criteria/sequel/find.rb +10 -2
- data/lib/datamappify/data/criteria/sequel/find_by_key.rb +4 -2
- data/lib/datamappify/data/criteria/sequel/limit.rb +10 -0
- data/lib/datamappify/data/criteria/sequel/match.rb +22 -0
- data/lib/datamappify/data/criteria/sequel/order.rb +22 -0
- data/lib/datamappify/data/criteria/sequel/rollback.rb +13 -0
- data/lib/datamappify/data/criteria/sequel/save.rb +1 -4
- data/lib/datamappify/data/criteria/sequel/save_by_key.rb +0 -1
- data/lib/datamappify/data/criteria/sequel/where.rb +18 -0
- data/lib/datamappify/data/errors.rb +8 -9
- data/lib/datamappify/data/mapper/attribute.rb +13 -33
- data/lib/datamappify/data/mapper.rb +13 -2
- data/lib/datamappify/data/provider/active_record.rb +8 -6
- data/lib/datamappify/data/provider/common_provider.rb +2 -2
- data/lib/datamappify/data/provider/sequel.rb +9 -6
- data/lib/datamappify/entity/association/reference.rb +63 -0
- data/lib/datamappify/entity/association/validation.rb +59 -0
- data/lib/datamappify/entity/association.rb +44 -0
- data/lib/datamappify/entity/{active_model/compatibility.rb → compatibility/active_model.rb} +2 -2
- data/lib/datamappify/entity/compatibility/active_record.rb +22 -0
- data/lib/datamappify/entity/compatibility/association/active_record.rb +43 -0
- data/lib/datamappify/entity/composable/attributes.rb +8 -16
- data/lib/datamappify/entity.rb +8 -6
- data/lib/datamappify/lazy/attributes_handler.rb +1 -1
- data/lib/datamappify/lazy.rb +0 -1
- data/lib/datamappify/repository/mapping_dsl.rb +9 -0
- data/lib/datamappify/repository/query_method/criteria.rb +21 -0
- data/lib/datamappify/repository/query_method/destroy.rb +1 -1
- data/lib/datamappify/repository/query_method/exists.rb +1 -1
- data/lib/datamappify/repository/query_method/find.rb +1 -9
- data/lib/datamappify/repository/query_method/method/multi_result_blender.rb +24 -0
- data/lib/datamappify/repository/query_method/method/reference_handler.rb +60 -0
- data/lib/datamappify/repository/query_method/method/source_attributes_walker.rb +19 -4
- data/lib/datamappify/repository/query_method/method.rb +58 -17
- data/lib/datamappify/repository/query_method/save.rb +4 -4
- data/lib/datamappify/repository/query_method/where_or_match.rb +24 -0
- data/lib/datamappify/repository/query_methods.rb +21 -5
- data/lib/datamappify/repository/unit_of_work/persistent_states/object.rb +2 -2
- data/lib/datamappify/version.rb +1 -1
- data/spec/entity/{relation_spec.rb → association/reference_spec.rb} +2 -2
- data/spec/repository/associations/has_many_spec.rb +259 -0
- data/spec/repository/dirty_tracking_spec.rb +68 -57
- data/spec/repository/finders/all_spec.rb +29 -0
- data/spec/repository/finders/criteria_spec.rb +61 -0
- data/spec/repository/finders/different_providers_spec.rb +81 -0
- data/spec/repository/finders/find_spec.rb +21 -0
- data/spec/repository/finders/match_spec.rb +28 -0
- data/spec/repository/finders/where_spec.rb +18 -0
- data/spec/repository/reverse_mapped_spec.rb +20 -4
- data/spec/support/entities/group.rb +4 -0
- data/spec/support/entities/super_user.rb +9 -0
- data/spec/support/entities/user.rb +5 -0
- data/spec/support/entities/user_info.rb +5 -0
- data/spec/support/repositories/active_record/group_repository.rb +4 -0
- data/spec/support/repositories/active_record/super_user_repository.rb +23 -0
- data/spec/support/repositories/active_record/user_repository.rb +6 -4
- data/spec/support/repositories/sequel/group_repository.rb +4 -0
- data/spec/support/repositories/sequel/super_user_repository.rb +23 -0
- data/spec/support/repositories/sequel/user_repository.rb +6 -4
- data/spec/support/shared/contexts.rb +8 -1
- data/spec/support/shared/examples/repository/finders/where_or_match.rb +130 -0
- data/spec/support/tables/active_record.rb +20 -10
- data/spec/support/tables/sequel.rb +20 -7
- data/spec/unit/entity/{relation_spec.rb → association/reference_spec.rb} +5 -5
- data/spec/unit/repository/query_method_spec.rb +9 -2
- metadata +74 -42
- data/lib/datamappify/data/criteria/active_record/find_multiple.rb +0 -40
- data/lib/datamappify/data/criteria/relational/find.rb +0 -25
- data/lib/datamappify/data/criteria/relational/find_by_key.rb +0 -18
- data/lib/datamappify/data/criteria/sequel/find_multiple.rb +0 -43
- data/lib/datamappify/entity/relation.rb +0 -61
- data/lib/datamappify/repository/query_method/find_multiple.rb +0 -28
- data/spec/repository/finders_spec.rb +0 -211
@@ -0,0 +1,59 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Entity
|
3
|
+
module Association
|
4
|
+
# Passes referenced validation errors onto the main entity
|
5
|
+
module Validation
|
6
|
+
def self.included(klass)
|
7
|
+
klass.class_eval do
|
8
|
+
attr_accessor :referenced_errors
|
9
|
+
|
10
|
+
validate :association_validation
|
11
|
+
|
12
|
+
def referenced_errors
|
13
|
+
@referenced_errors ||= {}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param context [Symbol]
|
19
|
+
# e.g. :create or :update
|
20
|
+
#
|
21
|
+
# @return [Boolean]
|
22
|
+
def valid?(context = nil)
|
23
|
+
aggregate_validation_errors(context)
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# @param (see #valid?)
|
31
|
+
#
|
32
|
+
# @return [void]
|
33
|
+
def aggregate_validation_errors(context)
|
34
|
+
self.associations.each do |association|
|
35
|
+
self.send(association).reject(&:destroy?).each do |entity|
|
36
|
+
entity.invalid?(context) && referenced_entity_validation_errors(entity)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param (see #valid?)
|
42
|
+
#
|
43
|
+
# @return [void]
|
44
|
+
def referenced_entity_validation_errors(entity)
|
45
|
+
entity.errors.messages.each do |attr, msgs|
|
46
|
+
self.referenced_errors["#{entity.class.model_name.element}__#{attr}"] = msgs
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [void]
|
51
|
+
def association_validation
|
52
|
+
self.referenced_errors.each do |name, msgs|
|
53
|
+
self.errors.add name, msgs.join(', ')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'datamappify/entity/compatibility/association/active_record'
|
2
|
+
require 'datamappify/entity/association/reference'
|
3
|
+
require 'datamappify/entity/association/validation'
|
4
|
+
|
5
|
+
module Datamappify
|
6
|
+
module Entity
|
7
|
+
module Association
|
8
|
+
def self.included(klass)
|
9
|
+
klass.class_eval do
|
10
|
+
cattr_accessor :associations
|
11
|
+
self.associations = []
|
12
|
+
|
13
|
+
include Reference
|
14
|
+
include Validation
|
15
|
+
extend DSL
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module DSL
|
20
|
+
prepend Compatibility::Association::ActiveRecord
|
21
|
+
|
22
|
+
# @param name [Symbol, String]
|
23
|
+
#
|
24
|
+
# @param options [Hash]
|
25
|
+
#
|
26
|
+
# @return [void]
|
27
|
+
def belongs_to(name, options = {})
|
28
|
+
references name
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param name [Symbol, String]
|
32
|
+
#
|
33
|
+
# @param options [Hash]
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
def has_many(name, options = {})
|
37
|
+
attribute name, Array[options[:via]]
|
38
|
+
|
39
|
+
self.associations << name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Entity
|
3
|
+
module Compatibility
|
4
|
+
# Add non-entity related stuff so that an entity can be used in say, forms
|
5
|
+
module ActiveRecord
|
6
|
+
# @return [Array<Symbol>]
|
7
|
+
IGNORED_ATTRIBUTE_NAMES = [:_destroy]
|
8
|
+
|
9
|
+
def self.included(klass)
|
10
|
+
klass.class_eval do
|
11
|
+
attribute :_destroy, Virtus::Attribute::Boolean, :default => false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Boolean]
|
16
|
+
def destroy?
|
17
|
+
!!_destroy
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Entity
|
3
|
+
module Compatibility
|
4
|
+
module Association
|
5
|
+
# Compatibility layer for ActionRecord
|
6
|
+
module ActiveRecord
|
7
|
+
# Adds `association_name_attributes` as required by
|
8
|
+
# nested attributes assignment
|
9
|
+
#
|
10
|
+
# @param (see DSL#has_many)
|
11
|
+
def has_many(name, options = {})
|
12
|
+
super
|
13
|
+
|
14
|
+
self.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
15
|
+
def #{name}_attributes=(params = {})
|
16
|
+
new_entites = params.map do |index, attributes|
|
17
|
+
attributes.delete('id') if attributes['id'].blank?
|
18
|
+
#{options[:via]}.new(attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
# resets the association attribute if nil,
|
22
|
+
# this will reset it back to an empty array
|
23
|
+
self.#{name} ||= nil
|
24
|
+
|
25
|
+
self.#{name} = self.#{name}.map do |entity|
|
26
|
+
new_entites.detect { |e| e.id == entity.id } || entity
|
27
|
+
end
|
28
|
+
|
29
|
+
new_entites.each do |entity|
|
30
|
+
entity_is_already_added = entity.id && self.#{name}.map(&:id).include?(entity.id)
|
31
|
+
|
32
|
+
unless entity_is_already_added
|
33
|
+
self.#{name} << entity
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
CODE
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -17,35 +17,27 @@ module Datamappify
|
|
17
17
|
def build_attributes
|
18
18
|
@entity_class.attribute_set.each do |attribute|
|
19
19
|
unless excluded_attributes.include?(attribute.name)
|
20
|
-
@entity.attribute_set << build_attribute(attribute
|
20
|
+
@entity.attribute_set << build_attribute(attribute)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
# @return [Array]
|
26
26
|
def excluded_attributes
|
27
|
-
@excluded_attributes ||= @entity_class.reference_keys
|
27
|
+
@excluded_attributes ||= @entity_class.reference_keys + [:id, *@entity_class::IGNORED_ATTRIBUTE_NAMES]
|
28
28
|
end
|
29
29
|
|
30
|
-
# @param
|
31
|
-
#
|
32
|
-
# @param attribute_writer [Virtus::Attribute::Writer]
|
30
|
+
# @param attribute [Virtus::Attribute]
|
33
31
|
#
|
34
32
|
# @return [Virtus::Attribute]
|
35
|
-
def build_attribute(
|
36
|
-
|
37
|
-
Attribute.prefix(
|
33
|
+
def build_attribute(attribute)
|
34
|
+
attribute_name = if @options[:prefix_with]
|
35
|
+
Attribute.prefix(attribute.name, @options[:prefix_with])
|
38
36
|
else
|
39
|
-
|
37
|
+
attribute.name
|
40
38
|
end
|
41
39
|
|
42
|
-
Virtus::Attribute.build(
|
43
|
-
name,
|
44
|
-
attribute_writer.primitive,
|
45
|
-
:default => attribute_writer.default_value,
|
46
|
-
:visibility => attribute_writer.visibility,
|
47
|
-
:coercer => attribute_writer.coercer
|
48
|
-
)
|
40
|
+
Virtus::Attribute.build(attribute.type, attribute.options.merge(:name => attribute_name))
|
49
41
|
end
|
50
42
|
end
|
51
43
|
end
|
data/lib/datamappify/entity.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'observer'
|
2
2
|
require 'virtus'
|
3
|
-
require 'datamappify/entity/active_model
|
3
|
+
require 'datamappify/entity/compatibility/active_model'
|
4
|
+
require 'datamappify/entity/compatibility/active_record'
|
4
5
|
require 'datamappify/entity/lazy_checking'
|
5
6
|
require 'datamappify/entity/composable'
|
6
|
-
require 'datamappify/entity/
|
7
|
+
require 'datamappify/entity/association'
|
7
8
|
require 'datamappify/entity/inspectable'
|
8
9
|
|
9
10
|
module Datamappify
|
@@ -11,13 +12,14 @@ module Datamappify
|
|
11
12
|
def self.included(klass)
|
12
13
|
klass.class_eval do
|
13
14
|
include Observable
|
15
|
+
include Virtus.model
|
16
|
+
include Equalizer.new(*klass.attribute_set)
|
14
17
|
include ::ActiveModel::Model
|
15
|
-
include ActiveModel
|
16
|
-
include
|
17
|
-
include Virtus::Equalizer.new(inspect)
|
18
|
+
include Compatibility::ActiveModel
|
19
|
+
include Compatibility::ActiveRecord
|
18
20
|
include LazyChecking
|
19
21
|
include Composable
|
20
|
-
include
|
22
|
+
include Association
|
21
23
|
include Inspectable
|
22
24
|
|
23
25
|
attribute :id, Integer
|
@@ -8,7 +8,7 @@ module Datamappify
|
|
8
8
|
# @param entity [Entity]
|
9
9
|
def initialize(entity)
|
10
10
|
@entity = entity
|
11
|
-
@uncached_attributes = entity.attributes.keys
|
11
|
+
@uncached_attributes = entity.attributes.keys - entity.class::IGNORED_ATTRIBUTE_NAMES
|
12
12
|
|
13
13
|
entity.add_observer(self)
|
14
14
|
end
|
data/lib/datamappify/lazy.rb
CHANGED
@@ -43,6 +43,15 @@ module Datamappify
|
|
43
43
|
|
44
44
|
self.current_group_options = {}
|
45
45
|
end
|
46
|
+
|
47
|
+
# @param name [Symbol, String]
|
48
|
+
#
|
49
|
+
# @param options [Hash]
|
50
|
+
#
|
51
|
+
# @return [void]
|
52
|
+
def references(name, options = {})
|
53
|
+
data_mapper.references[name.to_sym] = options
|
54
|
+
end
|
46
55
|
end
|
47
56
|
end
|
48
57
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Repository
|
3
|
+
module QueryMethod
|
4
|
+
class Criteria < Method
|
5
|
+
# @return [Array<Entity>]
|
6
|
+
def perform
|
7
|
+
results = dispatch_criteria_to_default_source(
|
8
|
+
:Criteria, data_mapper.entity_class, criteria, data_mapper.attributes
|
9
|
+
)
|
10
|
+
|
11
|
+
MultiResultBlender.new(self).blend(results)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see Method#reader?
|
15
|
+
def reader?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -2,18 +2,10 @@ module Datamappify
|
|
2
2
|
module Repository
|
3
3
|
module QueryMethod
|
4
4
|
class Find < Method
|
5
|
-
# @param options (see Method#initialize)
|
6
|
-
#
|
7
|
-
# @param id [Integer]
|
8
|
-
def initialize(options, id)
|
9
|
-
super
|
10
|
-
@id = id
|
11
|
-
end
|
12
|
-
|
13
5
|
# @return [Entity, nil]
|
14
6
|
def perform
|
15
7
|
entity = data_mapper.entity_class.new
|
16
|
-
entity.id =
|
8
|
+
entity.id = criteria
|
17
9
|
|
18
10
|
if dispatch_criteria_to_default_source(:Exists, entity)
|
19
11
|
dispatch_criteria_to_providers(:FindByKey, entity)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Repository
|
3
|
+
module QueryMethod
|
4
|
+
class Method
|
5
|
+
class MultiResultBlender
|
6
|
+
# @param method_instance [Method]
|
7
|
+
def initialize(method_instance)
|
8
|
+
@method = method_instance
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param results [Array<Entity>]
|
12
|
+
#
|
13
|
+
# @return [Array<Entity>]
|
14
|
+
def blend(results)
|
15
|
+
results.each do |entity|
|
16
|
+
@method.states.find(entity)
|
17
|
+
@method.walk_references(:Find, entity)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Repository
|
3
|
+
module QueryMethod
|
4
|
+
class Method
|
5
|
+
class ReferenceHandler
|
6
|
+
def initialize(options = {})
|
7
|
+
@entity = options[:entity]
|
8
|
+
@criteria_name = options[:criteria_name]
|
9
|
+
@reference_name = options[:reference_name]
|
10
|
+
@repository = options[:reference_options][:via]
|
11
|
+
@query_method = options[:query_method]
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [void]
|
15
|
+
def execute
|
16
|
+
perform_read if @query_method.reader?
|
17
|
+
perform_write if @query_method.writer?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# @return [void]
|
23
|
+
def perform_read
|
24
|
+
@entity.send("#{@reference_name}=", fetch_referenced_entities)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [void]
|
28
|
+
def perform_write
|
29
|
+
referenced_entities.each do |entity|
|
30
|
+
if entity.destroy?
|
31
|
+
if entity.persisted?
|
32
|
+
@repository.destroy!(entity)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
entity.send("#{reference_key}=", @entity.id)
|
36
|
+
@repository.states.mark_as_dirty(entity)
|
37
|
+
@repository.save!(entity)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Array]
|
43
|
+
def fetch_referenced_entities
|
44
|
+
@repository.where(reference_key => @entity.id)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Array]
|
48
|
+
def referenced_entities
|
49
|
+
@entity.send(@reference_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return (see Data::Mapper::Attribute#reference_key)
|
53
|
+
def reference_key
|
54
|
+
@query_method.data_mapper.attributes.first.reference_key
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -27,16 +27,31 @@ module Datamappify
|
|
27
27
|
#
|
28
28
|
# @return [void]
|
29
29
|
def execute(&block)
|
30
|
-
@
|
31
|
-
|
32
|
-
|
33
|
-
walk_performed(attributes)
|
30
|
+
if @query_method && @query_method.writer?
|
31
|
+
@attributes.classify(&:source_class).each do |source_class, attributes|
|
32
|
+
perform_walk(source_class, attributes, &block)
|
34
33
|
end
|
34
|
+
else
|
35
|
+
perform_walk(@attributes.first.source_class, @attributes, &block)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
private
|
39
40
|
|
41
|
+
# @param source_class [Class]
|
42
|
+
#
|
43
|
+
# @param attributes [Set<Data::Mapper::Attribute>]
|
44
|
+
#
|
45
|
+
# @yield (see #execute)
|
46
|
+
#
|
47
|
+
# @return [void]
|
48
|
+
def perform_walk(source_class, attributes, &block)
|
49
|
+
if do_walk?(source_class, attributes)
|
50
|
+
block.call(@provider_name, source_class, attributes)
|
51
|
+
walk_performed(attributes)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
40
55
|
# Whether it is necessary to do the walk
|
41
56
|
#
|
42
57
|
# @param source_class [Class]
|
@@ -11,17 +11,24 @@ module Datamappify
|
|
11
11
|
# @return [UnitOfWork::PersistentStates]
|
12
12
|
attr_reader :states
|
13
13
|
|
14
|
+
# @return [Entity, Hash, nil]
|
15
|
+
attr_reader :entity
|
16
|
+
|
17
|
+
# @return [Entity, Hash, nil]
|
18
|
+
attr_reader :criteria
|
19
|
+
|
14
20
|
# @param options [Hash]
|
15
21
|
# a hash containing required items like data_mapper and states
|
16
22
|
#
|
17
|
-
# @param
|
23
|
+
# @param entity_or_criteria [Entity, Hash]
|
18
24
|
#
|
19
25
|
# @param args [any]
|
20
|
-
def initialize(options,
|
26
|
+
def initialize(options, entity_or_criteria = nil, *args)
|
21
27
|
@data_mapper = options[:data_mapper]
|
22
28
|
@states = options[:states]
|
23
29
|
@lazy_load = options[:lazy_load?]
|
24
|
-
|
30
|
+
|
31
|
+
@entity = @criteria = entity_or_criteria
|
25
32
|
end
|
26
33
|
|
27
34
|
# Should the method be aware of the dirty state?
|
@@ -52,8 +59,6 @@ module Datamappify
|
|
52
59
|
false
|
53
60
|
end
|
54
61
|
|
55
|
-
private
|
56
|
-
|
57
62
|
# Dispatches a {Criteria} according to
|
58
63
|
# the {Data::Mapper data mapper}'s default provider and default source class
|
59
64
|
#
|
@@ -74,10 +79,28 @@ module Datamappify
|
|
74
79
|
#
|
75
80
|
# @return [void]
|
76
81
|
def dispatch_criteria_to_providers(criteria_name, entity)
|
82
|
+
UnitOfWork::Transaction.new(data_mapper) do
|
83
|
+
walk_attributes(criteria_name, entity)
|
84
|
+
walk_references(criteria_name, entity)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Walks through the references and performs actions on them
|
89
|
+
#
|
90
|
+
# @param (see #dispatch_criteria_to_providers)
|
91
|
+
#
|
92
|
+
# @return [void]
|
93
|
+
def walk_attributes(criteria_name, entity)
|
77
94
|
_primary_record = nil
|
78
95
|
|
79
96
|
attributes_walker(entity) do |provider_name, source_class, attributes|
|
80
|
-
|
97
|
+
walk_path = if reader?
|
98
|
+
{ nil => attributes }
|
99
|
+
else
|
100
|
+
attributes.classify { |attr| attr.options[:via] }
|
101
|
+
end
|
102
|
+
|
103
|
+
walk_path.each do |via, attrs|
|
81
104
|
record = data_mapper.provider(provider_name).build_criteria(
|
82
105
|
criteria_name,
|
83
106
|
source_class,
|
@@ -106,20 +129,38 @@ module Datamappify
|
|
106
129
|
#
|
107
130
|
# @see SourceAttributesWalker#execute
|
108
131
|
def attributes_walker(entity, &block)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
132
|
+
data_mapper.classified_attributes.each do |provider_name, attributes|
|
133
|
+
source_attributes_walker.new({
|
134
|
+
:entity => entity,
|
135
|
+
:provider_name => provider_name,
|
136
|
+
:attributes => attributes,
|
137
|
+
:dirty_aware? => dirty_aware?,
|
138
|
+
:dirty_attributes => states.find(entity).changed,
|
139
|
+
:query_method => self
|
140
|
+
}).execute(&block)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Walks through the references and performs actions on them
|
145
|
+
#
|
146
|
+
# @param (see #dispatch_criteria_to_providers)
|
147
|
+
#
|
148
|
+
# @return [void]
|
149
|
+
def walk_references(criteria_name, entity)
|
150
|
+
data_mapper.references.each do |reference_name, options|
|
151
|
+
ReferenceHandler.new({
|
152
|
+
:entity => entity,
|
153
|
+
:criteria_name => criteria_name,
|
154
|
+
:reference_name => reference_name,
|
155
|
+
:reference_options => options,
|
156
|
+
:query_method => self
|
157
|
+
}).execute
|
120
158
|
end
|
121
159
|
end
|
122
160
|
|
161
|
+
private
|
162
|
+
|
163
|
+
# return [Class]
|
123
164
|
def source_attributes_walker
|
124
165
|
if @lazy_load
|
125
166
|
Lazy::SourceAttributesWalker
|
@@ -4,11 +4,11 @@ module Datamappify
|
|
4
4
|
class Save < Method
|
5
5
|
# @return [Entity, false]
|
6
6
|
def perform
|
7
|
-
states.update(
|
8
|
-
create_or_update(
|
7
|
+
states.update(entity) do
|
8
|
+
create_or_update(entity)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
entity
|
12
12
|
rescue Data::EntityInvalid
|
13
13
|
false
|
14
14
|
end
|
@@ -31,7 +31,7 @@ module Datamappify
|
|
31
31
|
#
|
32
32
|
# @return [Entity]
|
33
33
|
def create_or_update(entity)
|
34
|
-
raise Data::EntityInvalid.new(entity) if entity.invalid?(context)
|
34
|
+
raise Data::EntityInvalid.new(entity.errors) if entity.invalid?(context)
|
35
35
|
|
36
36
|
dispatch_criteria_to_providers(:SaveByKey, entity)
|
37
37
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Repository
|
3
|
+
module QueryMethod
|
4
|
+
class WhereOrMatch < Method
|
5
|
+
# @return [Array<Entity>]
|
6
|
+
def perform
|
7
|
+
results = dispatch_criteria_to_default_source(
|
8
|
+
self.class.name.demodulize.to_sym, data_mapper.entity_class, criteria, data_mapper.attributes
|
9
|
+
)
|
10
|
+
|
11
|
+
MultiResultBlender.new(self).blend(results)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see Method#reader?
|
15
|
+
def reader?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Where < WhereOrMatch; end
|
21
|
+
class Match < WhereOrMatch; end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|