sanger-jsonapi-resources 0.1.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 +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +53 -0
- data/lib/generators/jsonapi/USAGE +13 -0
- data/lib/generators/jsonapi/controller_generator.rb +14 -0
- data/lib/generators/jsonapi/resource_generator.rb +14 -0
- data/lib/generators/jsonapi/templates/jsonapi_controller.rb +4 -0
- data/lib/generators/jsonapi/templates/jsonapi_resource.rb +4 -0
- data/lib/jsonapi/acts_as_resource_controller.rb +320 -0
- data/lib/jsonapi/cached_resource_fragment.rb +127 -0
- data/lib/jsonapi/callbacks.rb +51 -0
- data/lib/jsonapi/compiled_json.rb +36 -0
- data/lib/jsonapi/configuration.rb +258 -0
- data/lib/jsonapi/error.rb +47 -0
- data/lib/jsonapi/error_codes.rb +60 -0
- data/lib/jsonapi/exceptions.rb +563 -0
- data/lib/jsonapi/formatter.rb +169 -0
- data/lib/jsonapi/include_directives.rb +100 -0
- data/lib/jsonapi/link_builder.rb +152 -0
- data/lib/jsonapi/mime_types.rb +41 -0
- data/lib/jsonapi/naive_cache.rb +30 -0
- data/lib/jsonapi/operation.rb +24 -0
- data/lib/jsonapi/operation_dispatcher.rb +88 -0
- data/lib/jsonapi/operation_result.rb +65 -0
- data/lib/jsonapi/operation_results.rb +35 -0
- data/lib/jsonapi/paginator.rb +209 -0
- data/lib/jsonapi/processor.rb +328 -0
- data/lib/jsonapi/relationship.rb +94 -0
- data/lib/jsonapi/relationship_builder.rb +167 -0
- data/lib/jsonapi/request_parser.rb +678 -0
- data/lib/jsonapi/resource.rb +1255 -0
- data/lib/jsonapi/resource_controller.rb +5 -0
- data/lib/jsonapi/resource_controller_metal.rb +16 -0
- data/lib/jsonapi/resource_serializer.rb +531 -0
- data/lib/jsonapi/resources/version.rb +5 -0
- data/lib/jsonapi/response_document.rb +135 -0
- data/lib/jsonapi/routing_ext.rb +262 -0
- data/lib/jsonapi-resources.rb +27 -0
- metadata +223 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
class RelationshipBuilder
|
3
|
+
attr_reader :model_class, :options, :relationship_class
|
4
|
+
delegate :register_relationship, to: :@resource_class
|
5
|
+
|
6
|
+
def initialize(relationship_class, model_class, options)
|
7
|
+
@relationship_class = relationship_class
|
8
|
+
@model_class = model_class
|
9
|
+
@resource_class = options[:parent_resource]
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def define_relationship_methods(relationship_name)
|
14
|
+
# Initialize from an ActiveRecord model's properties
|
15
|
+
if model_class && model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base')
|
16
|
+
model_association = model_class.reflect_on_association(relationship_name)
|
17
|
+
if model_association
|
18
|
+
options[:class_name] ||= model_association.class_name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
relationship = register_relationship(
|
23
|
+
relationship_name,
|
24
|
+
relationship_class.new(relationship_name, options)
|
25
|
+
)
|
26
|
+
|
27
|
+
foreign_key = define_foreign_key_setter(relationship.foreign_key)
|
28
|
+
|
29
|
+
case relationship
|
30
|
+
when JSONAPI::Relationship::ToOne
|
31
|
+
associated = define_resource_relationship_accessor(:one, relationship_name)
|
32
|
+
args = [relationship, foreign_key, associated, relationship_name]
|
33
|
+
|
34
|
+
relationship.belongs_to? ? build_belongs_to(*args) : build_has_one(*args)
|
35
|
+
when JSONAPI::Relationship::ToMany
|
36
|
+
associated = define_resource_relationship_accessor(:many, relationship_name)
|
37
|
+
|
38
|
+
build_to_many(relationship, foreign_key, associated, relationship_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def define_foreign_key_setter(foreign_key)
|
43
|
+
define_on_resource "#{foreign_key}=" do |value|
|
44
|
+
@model.method("#{foreign_key}=").call(value)
|
45
|
+
end
|
46
|
+
foreign_key
|
47
|
+
end
|
48
|
+
|
49
|
+
def define_resource_relationship_accessor(type, relationship_name)
|
50
|
+
associated_records_method_name = {
|
51
|
+
one: "record_for_#{relationship_name}",
|
52
|
+
many: "records_for_#{relationship_name}"
|
53
|
+
}
|
54
|
+
.fetch(type)
|
55
|
+
|
56
|
+
define_on_resource associated_records_method_name do |options = {}|
|
57
|
+
relationship = self.class._relationships[relationship_name]
|
58
|
+
relation_name = relationship.relation_name(context: @context)
|
59
|
+
records = records_for(relation_name)
|
60
|
+
|
61
|
+
resource_klass = relationship.resource_klass
|
62
|
+
|
63
|
+
filters = options.fetch(:filters, {})
|
64
|
+
unless filters.nil? || filters.empty?
|
65
|
+
records = resource_klass.apply_filters(records, filters, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
sort_criteria = options.fetch(:sort_criteria, {})
|
69
|
+
unless sort_criteria.nil? || sort_criteria.empty?
|
70
|
+
order_options = relationship.resource_klass.construct_order_options(sort_criteria)
|
71
|
+
records = resource_klass.apply_sort(records, order_options, @context)
|
72
|
+
end
|
73
|
+
|
74
|
+
paginator = options[:paginator]
|
75
|
+
if paginator
|
76
|
+
records = resource_klass.apply_pagination(records, paginator, order_options)
|
77
|
+
end
|
78
|
+
|
79
|
+
records
|
80
|
+
end
|
81
|
+
|
82
|
+
associated_records_method_name
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_belongs_to(relationship, foreign_key, associated_records_method_name, relationship_name)
|
86
|
+
# Calls method matching foreign key name on model instance
|
87
|
+
define_on_resource foreign_key do
|
88
|
+
@model.method(foreign_key).call
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns instantiated related resource object or nil
|
92
|
+
define_on_resource relationship_name do |options = {}|
|
93
|
+
relationship = self.class._relationships[relationship_name]
|
94
|
+
|
95
|
+
if relationship.polymorphic?
|
96
|
+
associated_model = public_send(associated_records_method_name)
|
97
|
+
resource_klass = self.class.resource_for_model(associated_model) if associated_model
|
98
|
+
return resource_klass.new(associated_model, @context) if resource_klass
|
99
|
+
else
|
100
|
+
resource_klass = relationship.resource_klass
|
101
|
+
if resource_klass
|
102
|
+
associated_model = public_send(associated_records_method_name)
|
103
|
+
return associated_model ? resource_klass.new(associated_model, @context) : nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def build_has_one(relationship, foreign_key, associated_records_method_name, relationship_name)
|
110
|
+
# Returns primary key name of related resource class
|
111
|
+
define_on_resource foreign_key do
|
112
|
+
relationship = self.class._relationships[relationship_name]
|
113
|
+
|
114
|
+
record = public_send(associated_records_method_name)
|
115
|
+
return nil if record.nil?
|
116
|
+
record.public_send(relationship.resource_klass._primary_key)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns instantiated related resource object or nil
|
120
|
+
define_on_resource relationship_name do |options = {}|
|
121
|
+
relationship = self.class._relationships[relationship_name]
|
122
|
+
|
123
|
+
if relationship.polymorphic?
|
124
|
+
associated_model = public_send(associated_records_method_name)
|
125
|
+
resource_klass = self.class.resource_for_model(associated_model) if associated_model
|
126
|
+
return resource_klass.new(associated_model, @context) if resource_klass && associated_model
|
127
|
+
else
|
128
|
+
resource_klass = relationship.resource_klass
|
129
|
+
if resource_klass
|
130
|
+
associated_model = public_send(associated_records_method_name)
|
131
|
+
return associated_model ? resource_klass.new(associated_model, @context) : nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def build_to_many(relationship, foreign_key, associated_records_method_name, relationship_name)
|
138
|
+
# Returns array of primary keys of related resource classes
|
139
|
+
define_on_resource foreign_key do
|
140
|
+
records = public_send(associated_records_method_name)
|
141
|
+
return records.collect do |record|
|
142
|
+
record.public_send(relationship.resource_klass._primary_key)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns array of instantiated related resource objects
|
147
|
+
define_on_resource relationship_name do |options = {}|
|
148
|
+
relationship = self.class._relationships[relationship_name]
|
149
|
+
|
150
|
+
resource_klass = relationship.resource_klass
|
151
|
+
records = public_send(associated_records_method_name, options)
|
152
|
+
|
153
|
+
return records.collect do |record|
|
154
|
+
if relationship.polymorphic?
|
155
|
+
resource_klass = self.class.resource_for_model(record)
|
156
|
+
end
|
157
|
+
resource_klass.new(record, @context)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def define_on_resource(method_name, &block)
|
163
|
+
return if @resource_class.method_defined?(method_name)
|
164
|
+
@resource_class.inject_method_definition(method_name, block)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|