jsonapi-resources 0.10.0.beta2 → 0.10.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 +5 -5
- data/lib/jsonapi/{active_relation_resource_finder → active_relation}/adapters/join_left_active_record_adapter.rb +2 -2
- data/lib/jsonapi/active_relation/join_manager.rb +297 -0
- data/lib/jsonapi/{active_relation_resource_finder.rb → active_relation_resource.rb} +189 -146
- data/lib/jsonapi/acts_as_resource_controller.rb +4 -3
- data/lib/jsonapi/basic_resource.rb +1162 -0
- data/lib/jsonapi/cached_response_fragment.rb +66 -49
- data/lib/jsonapi/configuration.rb +18 -13
- data/lib/jsonapi/include_directives.rb +6 -8
- data/lib/jsonapi/link_builder.rb +71 -85
- data/lib/jsonapi/operation_result.rb +2 -2
- data/lib/jsonapi/path.rb +8 -0
- data/lib/jsonapi/path_segment.rb +17 -5
- data/lib/jsonapi/processor.rb +6 -7
- data/lib/jsonapi/relationship.rb +32 -3
- data/lib/jsonapi/request_parser.rb +44 -10
- data/lib/jsonapi/resource.rb +3 -1106
- data/lib/jsonapi/resource_controller_metal.rb +3 -0
- data/lib/jsonapi/resource_serializer.rb +39 -33
- data/lib/jsonapi/resource_set.rb +118 -48
- data/lib/jsonapi/resources/railtie.rb +9 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +7 -2
- data/lib/jsonapi/routing_ext.rb +24 -4
- data/lib/jsonapi-resources.rb +12 -3
- data/lib/tasks/check_upgrade.rake +52 -0
- metadata +28 -12
- data/lib/jsonapi/active_relation_resource_finder/join_tree.rb +0 -227
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jsonapi-resources
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.10.0
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dan Gebhardt
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2019-
|
|
12
|
+
date: 2019-09-30 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|
|
@@ -17,14 +17,14 @@ dependencies:
|
|
|
17
17
|
requirements:
|
|
18
18
|
- - "~>"
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
|
-
version:
|
|
20
|
+
version: 1.17.3
|
|
21
21
|
type: :development
|
|
22
22
|
prerelease: false
|
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
|
24
24
|
requirements:
|
|
25
25
|
- - "~>"
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
|
-
version:
|
|
27
|
+
version: 1.17.3
|
|
28
28
|
- !ruby/object:Gem::Dependency
|
|
29
29
|
name: rake
|
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -115,6 +115,20 @@ dependencies:
|
|
|
115
115
|
- - ">="
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
117
|
version: '0'
|
|
118
|
+
- !ruby/object:Gem::Dependency
|
|
119
|
+
name: database_cleaner
|
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
type: :development
|
|
126
|
+
prerelease: false
|
|
127
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
118
132
|
- !ruby/object:Gem::Dependency
|
|
119
133
|
name: activerecord
|
|
120
134
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -176,10 +190,11 @@ files:
|
|
|
176
190
|
- lib/generators/jsonapi/templates/jsonapi_controller.rb
|
|
177
191
|
- lib/generators/jsonapi/templates/jsonapi_resource.rb
|
|
178
192
|
- lib/jsonapi-resources.rb
|
|
179
|
-
- lib/jsonapi/
|
|
180
|
-
- lib/jsonapi/
|
|
181
|
-
- lib/jsonapi/
|
|
193
|
+
- lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb
|
|
194
|
+
- lib/jsonapi/active_relation/join_manager.rb
|
|
195
|
+
- lib/jsonapi/active_relation_resource.rb
|
|
182
196
|
- lib/jsonapi/acts_as_resource_controller.rb
|
|
197
|
+
- lib/jsonapi/basic_resource.rb
|
|
183
198
|
- lib/jsonapi/cached_response_fragment.rb
|
|
184
199
|
- lib/jsonapi/callbacks.rb
|
|
185
200
|
- lib/jsonapi/compiled_json.rb
|
|
@@ -208,9 +223,11 @@ files:
|
|
|
208
223
|
- lib/jsonapi/resource_identity.rb
|
|
209
224
|
- lib/jsonapi/resource_serializer.rb
|
|
210
225
|
- lib/jsonapi/resource_set.rb
|
|
226
|
+
- lib/jsonapi/resources/railtie.rb
|
|
211
227
|
- lib/jsonapi/resources/version.rb
|
|
212
228
|
- lib/jsonapi/response_document.rb
|
|
213
229
|
- lib/jsonapi/routing_ext.rb
|
|
230
|
+
- lib/tasks/check_upgrade.rake
|
|
214
231
|
homepage: https://github.com/cerebris/jsonapi-resources
|
|
215
232
|
licenses:
|
|
216
233
|
- MIT
|
|
@@ -223,15 +240,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
223
240
|
requirements:
|
|
224
241
|
- - ">="
|
|
225
242
|
- !ruby/object:Gem::Version
|
|
226
|
-
version: '2.
|
|
243
|
+
version: '2.3'
|
|
227
244
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
228
245
|
requirements:
|
|
229
|
-
- - "
|
|
246
|
+
- - ">="
|
|
230
247
|
- !ruby/object:Gem::Version
|
|
231
|
-
version:
|
|
248
|
+
version: '0'
|
|
232
249
|
requirements: []
|
|
233
|
-
|
|
234
|
-
rubygems_version: 2.6.14.3
|
|
250
|
+
rubygems_version: 3.0.3
|
|
235
251
|
signing_key:
|
|
236
252
|
specification_version: 4
|
|
237
253
|
summary: Easily support JSON API in Rails.
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
module JSONAPI
|
|
2
|
-
module ActiveRelationResourceFinder
|
|
3
|
-
class JoinTree
|
|
4
|
-
# Stores relationship paths starting from the resource_klass. This allows consolidation of duplicate paths from
|
|
5
|
-
# relationships, filters and sorts. This enables the determination of table aliases as they are joined.
|
|
6
|
-
|
|
7
|
-
attr_reader :resource_klass, :options, :source_relationship, :resource_joins, :joins
|
|
8
|
-
|
|
9
|
-
def initialize(resource_klass:,
|
|
10
|
-
options: {},
|
|
11
|
-
source_relationship: nil,
|
|
12
|
-
relationships: nil,
|
|
13
|
-
filters: nil,
|
|
14
|
-
sort_criteria: nil)
|
|
15
|
-
|
|
16
|
-
@resource_klass = resource_klass
|
|
17
|
-
@options = options
|
|
18
|
-
|
|
19
|
-
@resource_joins = {
|
|
20
|
-
root: {
|
|
21
|
-
join_type: :root,
|
|
22
|
-
resource_klasses: {
|
|
23
|
-
resource_klass => {
|
|
24
|
-
relationships: {}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
add_source_relationship(source_relationship)
|
|
30
|
-
add_sort_criteria(sort_criteria)
|
|
31
|
-
add_filters(filters)
|
|
32
|
-
add_relationships(relationships)
|
|
33
|
-
|
|
34
|
-
@joins = {}
|
|
35
|
-
construct_joins(@resource_joins)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def add_join(path, default_type = :inner, default_polymorphic_join_type = :left)
|
|
41
|
-
if source_relationship
|
|
42
|
-
if source_relationship.polymorphic?
|
|
43
|
-
# Polymorphic paths will come it with the resource_type as the first segment (for example `#documents.comments`)
|
|
44
|
-
# We just need to prepend the relationship portion the
|
|
45
|
-
sourced_path = "#{source_relationship.name}#{path}"
|
|
46
|
-
else
|
|
47
|
-
sourced_path = "#{source_relationship.name}.#{path}"
|
|
48
|
-
end
|
|
49
|
-
else
|
|
50
|
-
sourced_path = path
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
join_tree, _field = parse_path_to_tree(sourced_path, resource_klass, default_type, default_polymorphic_join_type)
|
|
54
|
-
|
|
55
|
-
@resource_joins[:root].deep_merge!(join_tree) { |key, val, other_val|
|
|
56
|
-
if key == :join_type
|
|
57
|
-
if val == other_val
|
|
58
|
-
val
|
|
59
|
-
else
|
|
60
|
-
:inner
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
}
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def process_path_to_tree(path_segments, resource_klass, default_join_type, default_polymorphic_join_type)
|
|
67
|
-
node = {
|
|
68
|
-
resource_klasses: {
|
|
69
|
-
resource_klass => {
|
|
70
|
-
relationships: {}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
segment = path_segments.shift
|
|
76
|
-
|
|
77
|
-
if segment.is_a?(PathSegment::Relationship)
|
|
78
|
-
node[:resource_klasses][resource_klass][:relationships][segment.relationship] ||= {}
|
|
79
|
-
|
|
80
|
-
# join polymorphic as left joins
|
|
81
|
-
node[:resource_klasses][resource_klass][:relationships][segment.relationship][:join_type] ||=
|
|
82
|
-
segment.relationship.polymorphic? ? default_polymorphic_join_type : default_join_type
|
|
83
|
-
|
|
84
|
-
segment.relationship.resource_types.each do |related_resource_type|
|
|
85
|
-
related_resource_klass = resource_klass.resource_klass_for(related_resource_type)
|
|
86
|
-
|
|
87
|
-
# If the resource type was specified in the path segment we want to only process the next segments for
|
|
88
|
-
# that resource type, otherwise process for all
|
|
89
|
-
process_all_types = !segment.path_specified_resource_klass?
|
|
90
|
-
|
|
91
|
-
if process_all_types || related_resource_klass == segment.resource_klass
|
|
92
|
-
related_resource_tree = process_path_to_tree(path_segments.dup, related_resource_klass, default_join_type, default_polymorphic_join_type)
|
|
93
|
-
node[:resource_klasses][resource_klass][:relationships][segment.relationship].deep_merge!(related_resource_tree)
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
node
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def parse_path_to_tree(path_string, resource_klass, default_join_type = :inner, default_polymorphic_join_type = :left)
|
|
101
|
-
path = JSONAPI::Path.new(resource_klass: resource_klass, path_string: path_string)
|
|
102
|
-
field = path.segments[-1]
|
|
103
|
-
return process_path_to_tree(path.segments, resource_klass, default_join_type, default_polymorphic_join_type), field
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def add_source_relationship(source_relationship)
|
|
107
|
-
@source_relationship = source_relationship
|
|
108
|
-
|
|
109
|
-
if @source_relationship
|
|
110
|
-
resource_klasses = {}
|
|
111
|
-
source_relationship.resource_types.each do |related_resource_type|
|
|
112
|
-
related_resource_klass = resource_klass.resource_klass_for(related_resource_type)
|
|
113
|
-
resource_klasses[related_resource_klass] = {relationships: {}}
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
join_type = source_relationship.polymorphic? ? :left : :inner
|
|
117
|
-
|
|
118
|
-
@resource_joins[:root][:resource_klasses][resource_klass][:relationships][@source_relationship] = {
|
|
119
|
-
source: true, resource_klasses: resource_klasses, join_type: join_type
|
|
120
|
-
}
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def add_filters(filters)
|
|
125
|
-
return if filters.blank?
|
|
126
|
-
filters.each_key do |filter|
|
|
127
|
-
# Do not add joins for filters with an apply callable. This can be overridden by setting perform_joins to true
|
|
128
|
-
next if resource_klass._allowed_filters[filter].try(:[], :apply) &&
|
|
129
|
-
!resource_klass._allowed_filters[filter].try(:[], :perform_joins)
|
|
130
|
-
|
|
131
|
-
add_join(filter)
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def add_sort_criteria(sort_criteria)
|
|
136
|
-
return if sort_criteria.blank?
|
|
137
|
-
|
|
138
|
-
sort_criteria.each do |sort|
|
|
139
|
-
add_join(sort[:field], :left)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def add_relationships(relationships)
|
|
144
|
-
return if relationships.blank?
|
|
145
|
-
relationships.each do |relationship|
|
|
146
|
-
add_join(relationship, :left)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# Create a nested set of hashes from an array of path components. This will be used by the `join` methods.
|
|
151
|
-
# [post, comments] => { post: { comments: {} }
|
|
152
|
-
def relation_join_hash(path, path_hash = {})
|
|
153
|
-
relation = path.shift
|
|
154
|
-
if relation
|
|
155
|
-
path_hash[relation] = {}
|
|
156
|
-
relation_join_hash(path, path_hash[relation])
|
|
157
|
-
end
|
|
158
|
-
path_hash
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# Returns the paths from shortest to longest, allowing the capture of the table alias for earlier paths. For
|
|
162
|
-
# example posts, posts.comments and then posts.comments.author joined in that order will allow each
|
|
163
|
-
# alias to be determined whereas just joining posts.comments.author will only record the author alias.
|
|
164
|
-
# ToDo: Dependence on this specialized logic should be removed in the future, if possible.
|
|
165
|
-
def construct_joins(node, current_relation_path = [], current_relationship_path = [])
|
|
166
|
-
node.each do |relationship, relationship_details|
|
|
167
|
-
join_type = relationship_details[:join_type]
|
|
168
|
-
if relationship == :root
|
|
169
|
-
@joins[:root] = {alias: resource_klass._table_name, join_type: :root}
|
|
170
|
-
|
|
171
|
-
# alias to the default table unless a source_relationship is specified
|
|
172
|
-
unless source_relationship
|
|
173
|
-
@joins[''] = {alias: resource_klass._table_name, join_type: :root}
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
return construct_joins(relationship_details[:resource_klasses].values[0][:relationships],
|
|
177
|
-
current_relation_path,
|
|
178
|
-
current_relationship_path)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
relationship_details[:resource_klasses].each do |resource_klass, resource_details|
|
|
182
|
-
if relationship.polymorphic? && relationship.belongs_to?
|
|
183
|
-
current_relationship_path << "#{relationship.name.to_s}##{resource_klass._type.to_s}"
|
|
184
|
-
relation_name = resource_klass._type.to_s.singularize
|
|
185
|
-
else
|
|
186
|
-
current_relationship_path << relationship.name.to_s
|
|
187
|
-
relation_name = relationship.relation_name(options).to_s
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
current_relation_path << relation_name
|
|
191
|
-
|
|
192
|
-
rel_path = calc_path_string(current_relationship_path)
|
|
193
|
-
|
|
194
|
-
@joins[rel_path] = {
|
|
195
|
-
alias: nil,
|
|
196
|
-
join_type: join_type,
|
|
197
|
-
relation_join_hash: relation_join_hash(current_relation_path.dup)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
construct_joins(resource_details[:relationships],
|
|
201
|
-
current_relation_path.dup,
|
|
202
|
-
current_relationship_path.dup)
|
|
203
|
-
|
|
204
|
-
current_relation_path.pop
|
|
205
|
-
current_relationship_path.pop
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def calc_path_string(path_array)
|
|
211
|
-
if source_relationship
|
|
212
|
-
if source_relationship.polymorphic?
|
|
213
|
-
_relationship_name, resource_name = path_array[0].split('#', 2)
|
|
214
|
-
path = path_array.dup
|
|
215
|
-
path[0] = "##{resource_name}"
|
|
216
|
-
else
|
|
217
|
-
path = path_array.dup.drop(1)
|
|
218
|
-
end
|
|
219
|
-
else
|
|
220
|
-
path = path_array.dup
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
path.join('.')
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
end
|