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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +53 -0
  4. data/lib/generators/jsonapi/USAGE +13 -0
  5. data/lib/generators/jsonapi/controller_generator.rb +14 -0
  6. data/lib/generators/jsonapi/resource_generator.rb +14 -0
  7. data/lib/generators/jsonapi/templates/jsonapi_controller.rb +4 -0
  8. data/lib/generators/jsonapi/templates/jsonapi_resource.rb +4 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +320 -0
  10. data/lib/jsonapi/cached_resource_fragment.rb +127 -0
  11. data/lib/jsonapi/callbacks.rb +51 -0
  12. data/lib/jsonapi/compiled_json.rb +36 -0
  13. data/lib/jsonapi/configuration.rb +258 -0
  14. data/lib/jsonapi/error.rb +47 -0
  15. data/lib/jsonapi/error_codes.rb +60 -0
  16. data/lib/jsonapi/exceptions.rb +563 -0
  17. data/lib/jsonapi/formatter.rb +169 -0
  18. data/lib/jsonapi/include_directives.rb +100 -0
  19. data/lib/jsonapi/link_builder.rb +152 -0
  20. data/lib/jsonapi/mime_types.rb +41 -0
  21. data/lib/jsonapi/naive_cache.rb +30 -0
  22. data/lib/jsonapi/operation.rb +24 -0
  23. data/lib/jsonapi/operation_dispatcher.rb +88 -0
  24. data/lib/jsonapi/operation_result.rb +65 -0
  25. data/lib/jsonapi/operation_results.rb +35 -0
  26. data/lib/jsonapi/paginator.rb +209 -0
  27. data/lib/jsonapi/processor.rb +328 -0
  28. data/lib/jsonapi/relationship.rb +94 -0
  29. data/lib/jsonapi/relationship_builder.rb +167 -0
  30. data/lib/jsonapi/request_parser.rb +678 -0
  31. data/lib/jsonapi/resource.rb +1255 -0
  32. data/lib/jsonapi/resource_controller.rb +5 -0
  33. data/lib/jsonapi/resource_controller_metal.rb +16 -0
  34. data/lib/jsonapi/resource_serializer.rb +531 -0
  35. data/lib/jsonapi/resources/version.rb +5 -0
  36. data/lib/jsonapi/response_document.rb +135 -0
  37. data/lib/jsonapi/routing_ext.rb +262 -0
  38. data/lib/jsonapi-resources.rb +27 -0
  39. 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