graphiti-activegraph 1.3.1 → 1.3.2
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/.github/workflows/specs.yml +58 -59
- data/.gitignore +59 -59
- data/.hound.yml +4 -0
- data/.rspec +1 -1
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +58 -54
- data/CHANGELOG_PRE_1.0.0.md +70 -70
- data/Gemfile +3 -3
- data/LICENSE.txt +21 -21
- data/README.md +130 -130
- data/docs/deserializer.md +40 -40
- data/graphiti-activegraph.gemspec +34 -34
- data/lib/graphiti/active_graph/adapters/active_graph/function_sideload.rb +7 -7
- data/lib/graphiti/active_graph/adapters/active_graph/has_many_sideload.rb +7 -7
- data/lib/graphiti/active_graph/adapters/active_graph/has_one_sideload.rb +7 -7
- data/lib/graphiti/active_graph/adapters/active_graph/polymorphic_belongs_to.rb +11 -11
- data/lib/graphiti/active_graph/adapters/active_graph/sideload.rb +26 -26
- data/lib/graphiti/active_graph/adapters/active_graph.rb +183 -183
- data/lib/graphiti/active_graph/concerns/path_relationships.rb +44 -44
- data/lib/graphiti/active_graph/concerns/relationships.rb +15 -15
- data/lib/graphiti/active_graph/deserializer.rb +138 -138
- data/lib/graphiti/active_graph/extensions/context.rb +17 -17
- data/lib/graphiti/active_graph/extensions/grouping/params.rb +101 -52
- data/lib/graphiti/active_graph/extensions/query_dsl/performer.rb +38 -38
- data/lib/graphiti/active_graph/extensions/query_dsl/query_generator.rb +20 -20
- data/lib/graphiti/active_graph/extensions/query_params.rb +27 -27
- data/lib/graphiti/active_graph/extensions/resources/authorizationable.rb +29 -29
- data/lib/graphiti/active_graph/extensions/resources/payload_combinable.rb +24 -24
- data/lib/graphiti/active_graph/extensions/resources/preloadable.rb +19 -19
- data/lib/graphiti/active_graph/extensions/resources/rel.rb +19 -19
- data/lib/graphiti/active_graph/jsonapi_ext/include_directive.rb +66 -66
- data/lib/graphiti/active_graph/jsonapi_ext/serializable/resource_ext.rb +8 -8
- data/lib/graphiti/active_graph/query.rb +76 -76
- data/lib/graphiti/active_graph/request_validators/validator.rb +9 -9
- data/lib/graphiti/active_graph/resource.rb +103 -103
- data/lib/graphiti/active_graph/resource_proxy.rb +86 -86
- data/lib/graphiti/active_graph/resources/interface.rb +14 -14
- data/lib/graphiti/active_graph/resources/persistence.rb +25 -25
- data/lib/graphiti/active_graph/runner.rb +39 -39
- data/lib/graphiti/active_graph/scope.rb +28 -28
- data/lib/graphiti/active_graph/scoping/association_eager_load.rb +34 -34
- data/lib/graphiti/active_graph/scoping/filter.rb +49 -49
- data/lib/graphiti/active_graph/scoping/filterable.rb +12 -12
- data/lib/graphiti/active_graph/scoping/include.rb +48 -48
- data/lib/graphiti/active_graph/scoping/internal/extra_field_normalizer.rb +76 -76
- data/lib/graphiti/active_graph/scoping/internal/include_normalizer.rb +82 -82
- data/lib/graphiti/active_graph/scoping/internal/path_descriptor.rb +94 -94
- data/lib/graphiti/active_graph/scoping/internal/sort_normalizer.rb +54 -54
- data/lib/graphiti/active_graph/scoping/internal/sorting_aliases.rb +35 -35
- data/lib/graphiti/active_graph/scoping/internal/sparse_fields_eagerloading.rb +28 -28
- data/lib/graphiti/active_graph/serializer.rb +15 -15
- data/lib/graphiti/active_graph/sideload_resolve.rb +119 -119
- data/lib/graphiti/active_graph/util/parsers/rel_chain.rb +27 -27
- data/lib/graphiti/active_graph/util/relationship_payload.rb +33 -33
- data/lib/graphiti/active_graph/util/serializer_attribute.rb +17 -17
- data/lib/graphiti/active_graph/util/serializer_relationship.rb +28 -28
- data/lib/graphiti/active_graph/util/transformers/relation_param.rb +56 -56
- data/lib/graphiti/active_graph/version.rb +5 -5
- data/lib/graphiti/sidepost_configuration.rb +9 -9
- data/lib/graphiti-activegraph.rb +43 -43
- metadata +5 -3
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
module Graphiti
|
|
2
|
-
module ActiveGraph
|
|
3
|
-
class Resource < Graphiti::Resource
|
|
4
|
-
include Extensions::Resources::Authorizationable
|
|
5
|
-
include Extensions::Resources::PayloadCombinable
|
|
6
|
-
include Extensions::Resources::Preloadable
|
|
7
|
-
include Extensions::Resources::Rel
|
|
8
|
-
|
|
9
|
-
self.adapter = Adapters::ActiveGraph
|
|
10
|
-
self.abstract_class = true
|
|
11
|
-
|
|
12
|
-
def self.use_uuid
|
|
13
|
-
define_singleton_method(:inherited) do |klass|
|
|
14
|
-
super(klass)
|
|
15
|
-
klass.attribute :id, :uuid
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.guard_nil_id!(params)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def self.extra_attribute?(name)
|
|
23
|
-
extra_attributes.has_key?(name)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.sideload_config(sideload_name)
|
|
27
|
-
config[:sideloads][sideload_name]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.sideload_resource_class(sideload_name)
|
|
31
|
-
sideload_config(sideload_name)&.resource_class
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def self.custom_eagerload(sideload_name)
|
|
35
|
-
sideload_config(sideload_name)&.custom_eagerload
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def extra_attribute?(name)
|
|
39
|
-
self.class.extra_attribute?(name)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def build_scope(base, query, opts = {})
|
|
43
|
-
scoping_class.new(base, self, query, opts)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def handle_includes(scope, includes, sorts, **opts)
|
|
47
|
-
includes_str = JSONAPI::IncludeDirective.new(includes, retain_rel_limit: true).to_string.split(',')
|
|
48
|
-
extra_includes_str = opts.delete(:extra_fields_includes) || []
|
|
49
|
-
options = opts.merge(max_page_size:).merge!(authorize_scope_params)
|
|
50
|
-
scope.with_ordered_associations(includes_str.union(extra_includes_str), sorts, options)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def sideload_name_arr(query)
|
|
54
|
-
query.sideloads.keys.map(&:to_sym)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def resolve(scope)
|
|
58
|
-
adapter.resolve(scope, relation_resource?)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def typecast(name, value, flag)
|
|
62
|
-
att = get_attr!(name, flag, request: true)
|
|
63
|
-
|
|
64
|
-
# in case of attribute is not declared on resource
|
|
65
|
-
# do not throw error, return original value without typecast
|
|
66
|
-
return value unless att
|
|
67
|
-
|
|
68
|
-
type_name = att[:type]
|
|
69
|
-
if flag == :filterable
|
|
70
|
-
type_name = filters[name][:type]
|
|
71
|
-
end
|
|
72
|
-
type = Graphiti::Types[type_name]
|
|
73
|
-
return if value.nil? && type[:kind] != "array"
|
|
74
|
-
begin
|
|
75
|
-
flag = :read if flag == :readable
|
|
76
|
-
flag = :write if flag == :writable
|
|
77
|
-
flag = :params if [:sortable, :filterable].include?(flag)
|
|
78
|
-
type[flag][value]
|
|
79
|
-
rescue => e
|
|
80
|
-
raise Errors::TypecastFailed.new(self, name, value, e, type_name)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def authorize_scope_params
|
|
85
|
-
{}
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def all_models
|
|
89
|
-
polymorphic? ? self.class.children.map(&:model) : [model]
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
private
|
|
93
|
-
|
|
94
|
-
def scoping_class
|
|
95
|
-
Scope
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def update_foreign_key(*)
|
|
99
|
-
true
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
1
|
+
module Graphiti
|
|
2
|
+
module ActiveGraph
|
|
3
|
+
class Resource < Graphiti::Resource
|
|
4
|
+
include Extensions::Resources::Authorizationable
|
|
5
|
+
include Extensions::Resources::PayloadCombinable
|
|
6
|
+
include Extensions::Resources::Preloadable
|
|
7
|
+
include Extensions::Resources::Rel
|
|
8
|
+
|
|
9
|
+
self.adapter = Adapters::ActiveGraph
|
|
10
|
+
self.abstract_class = true
|
|
11
|
+
|
|
12
|
+
def self.use_uuid
|
|
13
|
+
define_singleton_method(:inherited) do |klass|
|
|
14
|
+
super(klass)
|
|
15
|
+
klass.attribute :id, :uuid
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.guard_nil_id!(params)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.extra_attribute?(name)
|
|
23
|
+
extra_attributes.has_key?(name)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.sideload_config(sideload_name)
|
|
27
|
+
config[:sideloads][sideload_name]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.sideload_resource_class(sideload_name)
|
|
31
|
+
sideload_config(sideload_name)&.resource_class
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.custom_eagerload(sideload_name)
|
|
35
|
+
sideload_config(sideload_name)&.custom_eagerload
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def extra_attribute?(name)
|
|
39
|
+
self.class.extra_attribute?(name)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def build_scope(base, query, opts = {})
|
|
43
|
+
scoping_class.new(base, self, query, opts)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def handle_includes(scope, includes, sorts, **opts)
|
|
47
|
+
includes_str = JSONAPI::IncludeDirective.new(includes, retain_rel_limit: true).to_string.split(',')
|
|
48
|
+
extra_includes_str = opts.delete(:extra_fields_includes) || []
|
|
49
|
+
options = opts.merge(max_page_size:).merge!(authorize_scope_params)
|
|
50
|
+
scope.with_ordered_associations(includes_str.union(extra_includes_str), sorts, options)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def sideload_name_arr(query)
|
|
54
|
+
query.sideloads.keys.map(&:to_sym)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resolve(scope)
|
|
58
|
+
adapter.resolve(scope, relation_resource?)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def typecast(name, value, flag)
|
|
62
|
+
att = get_attr!(name, flag, request: true)
|
|
63
|
+
|
|
64
|
+
# in case of attribute is not declared on resource
|
|
65
|
+
# do not throw error, return original value without typecast
|
|
66
|
+
return value unless att
|
|
67
|
+
|
|
68
|
+
type_name = att[:type]
|
|
69
|
+
if flag == :filterable
|
|
70
|
+
type_name = filters[name][:type]
|
|
71
|
+
end
|
|
72
|
+
type = Graphiti::Types[type_name]
|
|
73
|
+
return if value.nil? && type[:kind] != "array"
|
|
74
|
+
begin
|
|
75
|
+
flag = :read if flag == :readable
|
|
76
|
+
flag = :write if flag == :writable
|
|
77
|
+
flag = :params if [:sortable, :filterable].include?(flag)
|
|
78
|
+
type[flag][value]
|
|
79
|
+
rescue => e
|
|
80
|
+
raise Errors::TypecastFailed.new(self, name, value, e, type_name)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def authorize_scope_params
|
|
85
|
+
{}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def all_models
|
|
89
|
+
polymorphic? ? self.class.children.map(&:model) : [model]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def scoping_class
|
|
95
|
+
Scope
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def update_foreign_key(*)
|
|
99
|
+
true
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
module Graphiti::ActiveGraph
|
|
2
|
-
module ResourceProxy
|
|
3
|
-
include Graphiti::ActiveGraph::SideloadResolve
|
|
4
|
-
attr_reader :preloaded
|
|
5
|
-
|
|
6
|
-
def initialize(resource, scope, query,
|
|
7
|
-
payload: nil,
|
|
8
|
-
single: false,
|
|
9
|
-
raise_on_missing: false,
|
|
10
|
-
preloaded: false)
|
|
11
|
-
@resource = resource
|
|
12
|
-
@scope = scope
|
|
13
|
-
@query = query
|
|
14
|
-
@payload = payload
|
|
15
|
-
@single = single
|
|
16
|
-
@raise_on_missing = raise_on_missing
|
|
17
|
-
@preloaded = preloaded
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def data
|
|
21
|
-
return @data if @data
|
|
22
|
-
|
|
23
|
-
return super unless @preloaded
|
|
24
|
-
|
|
25
|
-
resolve_sideloads(@preloaded)
|
|
26
|
-
@single ? data_for_preloaded_record : data_for_preloaded_records
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
alias_method :resolve_data, :data
|
|
30
|
-
|
|
31
|
-
def data_for_preloaded_record
|
|
32
|
-
@preloaded = @preloaded.is_a?(Array) ? @preloaded[0] : @preloaded
|
|
33
|
-
@resource.decorate_record(@preloaded)
|
|
34
|
-
@data = @preloaded
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def data_for_preloaded_records
|
|
38
|
-
@preloaded.each do |r|
|
|
39
|
-
@resource.decorate_record(r)
|
|
40
|
-
end
|
|
41
|
-
@data = @preloaded
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def stats
|
|
45
|
-
@stats ||= if @query.stats && !resource.relation_resource?
|
|
46
|
-
payload = ::Graphiti::Stats::Payload.new @resource,
|
|
47
|
-
@query,
|
|
48
|
-
@scope.unpaginated_object,
|
|
49
|
-
data
|
|
50
|
-
payload.generate
|
|
51
|
-
else
|
|
52
|
-
{}
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def save(action: :create)
|
|
57
|
-
# TODO: remove this. Only used for persisting many-to-many with AR
|
|
58
|
-
# (see activerecord adapter)
|
|
59
|
-
original = Graphiti.context[:namespace]
|
|
60
|
-
begin
|
|
61
|
-
Graphiti.context[:namespace] = action
|
|
62
|
-
::Graphiti::RequestValidator.new(@resource, @payload.params, action).validate!
|
|
63
|
-
validator = persist {
|
|
64
|
-
@resource.persist_with_relationships \
|
|
65
|
-
@payload.meta(action: action),
|
|
66
|
-
@payload.attributes,
|
|
67
|
-
@payload.relationships
|
|
68
|
-
}
|
|
69
|
-
ensure
|
|
70
|
-
Graphiti.context[:namespace] = original
|
|
71
|
-
end
|
|
72
|
-
@data, success = validator.to_a
|
|
73
|
-
|
|
74
|
-
if success && !resource.relation_resource?
|
|
75
|
-
# If the context namespace is `update` or `create`, certain
|
|
76
|
-
# adapters will cause N+1 validation calls, so lets explicitly
|
|
77
|
-
# switch to a lookup context.
|
|
78
|
-
Graphiti.with_context(Graphiti.context[:object], :show) do
|
|
79
|
-
@scope.resolve_sideloads([@data])
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
success
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
1
|
+
module Graphiti::ActiveGraph
|
|
2
|
+
module ResourceProxy
|
|
3
|
+
include Graphiti::ActiveGraph::SideloadResolve
|
|
4
|
+
attr_reader :preloaded
|
|
5
|
+
|
|
6
|
+
def initialize(resource, scope, query,
|
|
7
|
+
payload: nil,
|
|
8
|
+
single: false,
|
|
9
|
+
raise_on_missing: false,
|
|
10
|
+
preloaded: false)
|
|
11
|
+
@resource = resource
|
|
12
|
+
@scope = scope
|
|
13
|
+
@query = query
|
|
14
|
+
@payload = payload
|
|
15
|
+
@single = single
|
|
16
|
+
@raise_on_missing = raise_on_missing
|
|
17
|
+
@preloaded = preloaded
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def data
|
|
21
|
+
return @data if @data
|
|
22
|
+
|
|
23
|
+
return super unless @preloaded
|
|
24
|
+
|
|
25
|
+
resolve_sideloads(@preloaded)
|
|
26
|
+
@single ? data_for_preloaded_record : data_for_preloaded_records
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias_method :resolve_data, :data
|
|
30
|
+
|
|
31
|
+
def data_for_preloaded_record
|
|
32
|
+
@preloaded = @preloaded.is_a?(Array) ? @preloaded[0] : @preloaded
|
|
33
|
+
@resource.decorate_record(@preloaded)
|
|
34
|
+
@data = @preloaded
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def data_for_preloaded_records
|
|
38
|
+
@preloaded.each do |r|
|
|
39
|
+
@resource.decorate_record(r)
|
|
40
|
+
end
|
|
41
|
+
@data = @preloaded
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def stats
|
|
45
|
+
@stats ||= if @query.stats && !resource.relation_resource?
|
|
46
|
+
payload = ::Graphiti::Stats::Payload.new @resource,
|
|
47
|
+
@query,
|
|
48
|
+
@scope.unpaginated_object,
|
|
49
|
+
data
|
|
50
|
+
payload.generate
|
|
51
|
+
else
|
|
52
|
+
{}
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def save(action: :create)
|
|
57
|
+
# TODO: remove this. Only used for persisting many-to-many with AR
|
|
58
|
+
# (see activerecord adapter)
|
|
59
|
+
original = Graphiti.context[:namespace]
|
|
60
|
+
begin
|
|
61
|
+
Graphiti.context[:namespace] = action
|
|
62
|
+
::Graphiti::RequestValidator.new(@resource, @payload.params, action).validate!
|
|
63
|
+
validator = persist {
|
|
64
|
+
@resource.persist_with_relationships \
|
|
65
|
+
@payload.meta(action: action),
|
|
66
|
+
@payload.attributes,
|
|
67
|
+
@payload.relationships
|
|
68
|
+
}
|
|
69
|
+
ensure
|
|
70
|
+
Graphiti.context[:namespace] = original
|
|
71
|
+
end
|
|
72
|
+
@data, success = validator.to_a
|
|
73
|
+
|
|
74
|
+
if success && !resource.relation_resource?
|
|
75
|
+
# If the context namespace is `update` or `create`, certain
|
|
76
|
+
# adapters will cause N+1 validation calls, so lets explicitly
|
|
77
|
+
# switch to a lookup context.
|
|
78
|
+
Graphiti.with_context(Graphiti.context[:object], :show) do
|
|
79
|
+
@scope.resolve_sideloads([@data])
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
success
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
module Graphiti::ActiveGraph
|
|
2
|
-
module Resources
|
|
3
|
-
module Interface
|
|
4
|
-
extend ActiveSupport::Concern
|
|
5
|
-
class_methods do
|
|
6
|
-
def build(params, base_scope = nil, opts = {})
|
|
7
|
-
validate_request!(params)
|
|
8
|
-
runner = ::Graphiti::Runner.new(self, params)
|
|
9
|
-
runner.proxy(base_scope, { single: true, raise_on_missing: true }.merge(opts) )
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
1
|
+
module Graphiti::ActiveGraph
|
|
2
|
+
module Resources
|
|
3
|
+
module Interface
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
class_methods do
|
|
6
|
+
def build(params, base_scope = nil, opts = {})
|
|
7
|
+
validate_request!(params)
|
|
8
|
+
runner = ::Graphiti::Runner.new(self, params)
|
|
9
|
+
runner.proxy(base_scope, { single: true, raise_on_missing: true }.merge(opts) )
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
module Graphiti::ActiveGraph
|
|
2
|
-
module Resources
|
|
3
|
-
module Persistence
|
|
4
|
-
def update(update_params, meta = nil)
|
|
5
|
-
model_instance = nil
|
|
6
|
-
id = update_params[:id]
|
|
7
|
-
update_params = update_params.except(:id)
|
|
8
|
-
|
|
9
|
-
run_callbacks :persistence, :update, update_params, meta do
|
|
10
|
-
run_callbacks :attributes, :update, update_params, meta do |params|
|
|
11
|
-
model_instance = id ? model.find(id) : self.class._find(id: id).data
|
|
12
|
-
call_with_meta(:assign_attributes, model_instance, params, meta)
|
|
13
|
-
model_instance
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
run_callbacks :save, :update, model_instance, meta do
|
|
17
|
-
model_instance = call_with_meta(:save, model_instance, meta)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
model_instance
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
1
|
+
module Graphiti::ActiveGraph
|
|
2
|
+
module Resources
|
|
3
|
+
module Persistence
|
|
4
|
+
def update(update_params, meta = nil)
|
|
5
|
+
model_instance = nil
|
|
6
|
+
id = update_params[:id]
|
|
7
|
+
update_params = update_params.except(:id)
|
|
8
|
+
|
|
9
|
+
run_callbacks :persistence, :update, update_params, meta do
|
|
10
|
+
run_callbacks :attributes, :update, update_params, meta do |params|
|
|
11
|
+
model_instance = id ? model.find(id) : self.class._find(id: id).data
|
|
12
|
+
call_with_meta(:assign_attributes, model_instance, params, meta)
|
|
13
|
+
model_instance
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
run_callbacks :save, :update, model_instance, meta do
|
|
17
|
+
model_instance = call_with_meta(:save, model_instance, meta)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
model_instance
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
module Graphiti::ActiveGraph
|
|
2
|
-
module Runner
|
|
3
|
-
def initialize(resource_class, params, query = nil, action = nil)
|
|
4
|
-
@resource_class = resource_class
|
|
5
|
-
@params = params
|
|
6
|
-
@query = query
|
|
7
|
-
@action = action
|
|
8
|
-
|
|
9
|
-
validator = ::Graphiti::RequestValidator.new(jsonapi_resource, params, action)
|
|
10
|
-
|
|
11
|
-
validator.validate! unless params[:skip_render_val]
|
|
12
|
-
|
|
13
|
-
@deserialized_payload = validator.deserialized_payload
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def proxy(base = nil, opts = {})
|
|
17
|
-
base ||= jsonapi_resource.base_scope
|
|
18
|
-
scope_opts = opts.slice(:sideload_parent_length,
|
|
19
|
-
:default_paginate,
|
|
20
|
-
:after_resolve,
|
|
21
|
-
:sideload,
|
|
22
|
-
:parent,
|
|
23
|
-
:params,
|
|
24
|
-
:preloaded).merge(unpaginated_query: params[:unpaginated_query])
|
|
25
|
-
scope = jsonapi_scope(base, scope_opts)
|
|
26
|
-
preloaded = opts[:preloaded]
|
|
27
|
-
options = { payload: deserialized_payload,
|
|
28
|
-
single: opts[:single],
|
|
29
|
-
raise_on_missing: opts[:raise_on_missing],
|
|
30
|
-
preloaded: preloaded
|
|
31
|
-
}
|
|
32
|
-
::Graphiti::ResourceProxy.new jsonapi_resource,
|
|
33
|
-
scope,
|
|
34
|
-
query,
|
|
35
|
-
**options
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
1
|
+
module Graphiti::ActiveGraph
|
|
2
|
+
module Runner
|
|
3
|
+
def initialize(resource_class, params, query = nil, action = nil)
|
|
4
|
+
@resource_class = resource_class
|
|
5
|
+
@params = params
|
|
6
|
+
@query = query
|
|
7
|
+
@action = action
|
|
8
|
+
|
|
9
|
+
validator = ::Graphiti::RequestValidator.new(jsonapi_resource, params, action)
|
|
10
|
+
|
|
11
|
+
validator.validate! unless params[:skip_render_val]
|
|
12
|
+
|
|
13
|
+
@deserialized_payload = validator.deserialized_payload
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def proxy(base = nil, opts = {})
|
|
17
|
+
base ||= jsonapi_resource.base_scope
|
|
18
|
+
scope_opts = opts.slice(:sideload_parent_length,
|
|
19
|
+
:default_paginate,
|
|
20
|
+
:after_resolve,
|
|
21
|
+
:sideload,
|
|
22
|
+
:parent,
|
|
23
|
+
:params,
|
|
24
|
+
:preloaded).merge(unpaginated_query: params[:unpaginated_query])
|
|
25
|
+
scope = jsonapi_scope(base, scope_opts)
|
|
26
|
+
preloaded = opts[:preloaded]
|
|
27
|
+
options = { payload: deserialized_payload,
|
|
28
|
+
single: opts[:single],
|
|
29
|
+
raise_on_missing: opts[:raise_on_missing],
|
|
30
|
+
preloaded: preloaded
|
|
31
|
+
}
|
|
32
|
+
::Graphiti::ResourceProxy.new jsonapi_resource,
|
|
33
|
+
scope,
|
|
34
|
+
query,
|
|
35
|
+
**options
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
module Graphiti
|
|
2
|
-
module ActiveGraph
|
|
3
|
-
class Scope < Graphiti::Scope
|
|
4
|
-
def non_applicable_for_unpaginated
|
|
5
|
-
%i[association_eagerload]
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def apply_scoping(scope, opts)
|
|
9
|
-
opts[:query_obj] = @query
|
|
10
|
-
super
|
|
11
|
-
|
|
12
|
-
append_scopings(opts) unless @resource.remote?
|
|
13
|
-
@object
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def append_scopings(opts)
|
|
17
|
-
add_scoping(:include, Scoping::Include, opts)
|
|
18
|
-
add_scoping(:association_eagerload, Scoping::AssociationEagerLoad, opts)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def add_scoping(key, scoping_class, opts, _ = {})
|
|
22
|
-
@object = scoping_class.new(@resource, @query.hash, @object, opts).apply
|
|
23
|
-
return if non_applicable_for_unpaginated.include?(key)
|
|
24
|
-
@unpaginated_object = scoping_class.new(@resource, @query.hash, @unpaginated_object, opts.merge(unpaginated_query: true)).apply
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
1
|
+
module Graphiti
|
|
2
|
+
module ActiveGraph
|
|
3
|
+
class Scope < Graphiti::Scope
|
|
4
|
+
def non_applicable_for_unpaginated
|
|
5
|
+
%i[association_eagerload]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def apply_scoping(scope, opts)
|
|
9
|
+
opts[:query_obj] = @query
|
|
10
|
+
super
|
|
11
|
+
|
|
12
|
+
append_scopings(opts) unless @resource.remote?
|
|
13
|
+
@object
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def append_scopings(opts)
|
|
17
|
+
add_scoping(:include, Scoping::Include, opts)
|
|
18
|
+
add_scoping(:association_eagerload, Scoping::AssociationEagerLoad, opts)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add_scoping(key, scoping_class, opts, _ = {})
|
|
22
|
+
@object = scoping_class.new(@resource, @query.hash, @object, opts).apply
|
|
23
|
+
return if non_applicable_for_unpaginated.include?(key)
|
|
24
|
+
@unpaginated_object = scoping_class.new(@resource, @query.hash, @unpaginated_object, opts.merge(unpaginated_query: true)).apply
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
module Graphiti::ActiveGraph
|
|
2
|
-
module Scoping
|
|
3
|
-
class AssociationEagerLoad < Graphiti::Scoping::Base
|
|
4
|
-
def custom_scope
|
|
5
|
-
nil
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def apply_standard_scope
|
|
9
|
-
return @scope unless eagerload_associations?
|
|
10
|
-
if (ids = @scope.collect(&:id)).present?
|
|
11
|
-
@opts[:query_obj].include_hash.each_key do |key|
|
|
12
|
-
eagerload_association(key, ids)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
@scope
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def eagerload_associations?
|
|
19
|
-
@opts[:query_obj].include_hash.present? && @resource.model.include?(ActiveGraph::Node) &&
|
|
20
|
-
@resource.model.associations_to_eagerload.present?
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def eagerload_association(key, ids)
|
|
24
|
-
return unless @resource.model.eagerload_association?(key)
|
|
25
|
-
nodes = @resource.model.association_nodes(key, ids, @resource.context.send(:association_filter_params))
|
|
26
|
-
@scope.each { |node| node.send("#{key}=", nodes[node.id] || nil_or_empty(key)) }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def nil_or_empty(key)
|
|
30
|
-
@resource.class.config[:sideloads][key].type == :has_one ? nil : []
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
1
|
+
module Graphiti::ActiveGraph
|
|
2
|
+
module Scoping
|
|
3
|
+
class AssociationEagerLoad < Graphiti::Scoping::Base
|
|
4
|
+
def custom_scope
|
|
5
|
+
nil
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def apply_standard_scope
|
|
9
|
+
return @scope unless eagerload_associations?
|
|
10
|
+
if (ids = @scope.collect(&:id)).present?
|
|
11
|
+
@opts[:query_obj].include_hash.each_key do |key|
|
|
12
|
+
eagerload_association(key, ids)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
@scope
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def eagerload_associations?
|
|
19
|
+
@opts[:query_obj].include_hash.present? && @resource.model.include?(ActiveGraph::Node) &&
|
|
20
|
+
@resource.model.associations_to_eagerload.present?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def eagerload_association(key, ids)
|
|
24
|
+
return unless @resource.model.eagerload_association?(key)
|
|
25
|
+
nodes = @resource.model.association_nodes(key, ids, @resource.context.send(:association_filter_params))
|
|
26
|
+
@scope.each { |node| node.send("#{key}=", nodes[node.id] || nil_or_empty(key)) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def nil_or_empty(key)
|
|
30
|
+
@resource.class.config[:sideloads][key].type == :has_one ? nil : []
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|