sanger-jsonapi-resources 0.1.1 → 0.2.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +35 -12
  4. data/lib/bug_report_templates/rails_5_latest.rb +125 -0
  5. data/lib/bug_report_templates/rails_5_master.rb +140 -0
  6. data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +26 -0
  7. data/lib/jsonapi/active_relation/join_manager.rb +297 -0
  8. data/lib/jsonapi/active_relation_resource.rb +898 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +130 -113
  10. data/lib/jsonapi/basic_resource.rb +1164 -0
  11. data/lib/jsonapi/cached_response_fragment.rb +129 -0
  12. data/lib/jsonapi/callbacks.rb +2 -0
  13. data/lib/jsonapi/compatibility_helper.rb +29 -0
  14. data/lib/jsonapi/compiled_json.rb +13 -1
  15. data/lib/jsonapi/configuration.rb +88 -21
  16. data/lib/jsonapi/error.rb +29 -0
  17. data/lib/jsonapi/error_codes.rb +4 -0
  18. data/lib/jsonapi/exceptions.rb +82 -50
  19. data/lib/jsonapi/formatter.rb +5 -3
  20. data/lib/jsonapi/include_directives.rb +22 -67
  21. data/lib/jsonapi/link_builder.rb +76 -80
  22. data/lib/jsonapi/mime_types.rb +6 -10
  23. data/lib/jsonapi/naive_cache.rb +2 -0
  24. data/lib/jsonapi/operation.rb +18 -5
  25. data/lib/jsonapi/operation_result.rb +76 -16
  26. data/lib/jsonapi/paginator.rb +2 -0
  27. data/lib/jsonapi/path.rb +45 -0
  28. data/lib/jsonapi/path_segment.rb +78 -0
  29. data/lib/jsonapi/processor.rb +193 -115
  30. data/lib/jsonapi/relationship.rb +145 -14
  31. data/lib/jsonapi/request.rb +734 -0
  32. data/lib/jsonapi/resource.rb +3 -1251
  33. data/lib/jsonapi/resource_controller.rb +2 -0
  34. data/lib/jsonapi/resource_controller_metal.rb +7 -1
  35. data/lib/jsonapi/resource_fragment.rb +56 -0
  36. data/lib/jsonapi/resource_identity.rb +44 -0
  37. data/lib/jsonapi/resource_serializer.rb +158 -284
  38. data/lib/jsonapi/resource_set.rb +196 -0
  39. data/lib/jsonapi/resource_tree.rb +236 -0
  40. data/lib/jsonapi/resources/railtie.rb +9 -0
  41. data/lib/jsonapi/resources/version.rb +1 -1
  42. data/lib/jsonapi/response_document.rb +107 -83
  43. data/lib/jsonapi/routing_ext.rb +50 -26
  44. data/lib/jsonapi-resources.rb +23 -5
  45. data/lib/tasks/check_upgrade.rake +52 -0
  46. metadata +43 -31
  47. data/lib/jsonapi/cached_resource_fragment.rb +0 -127
  48. data/lib/jsonapi/operation_dispatcher.rb +0 -88
  49. data/lib/jsonapi/operation_results.rb +0 -35
  50. data/lib/jsonapi/relationship_builder.rb +0 -167
  51. data/lib/jsonapi/request_parser.rb +0 -678
@@ -1,88 +0,0 @@
1
- module JSONAPI
2
- class OperationDispatcher
3
-
4
- def initialize(transaction: lambda { |&block| block.yield },
5
- rollback: lambda { },
6
- server_error_callbacks: [])
7
-
8
- @transaction = transaction
9
- @rollback = rollback
10
- @server_error_callbacks = server_error_callbacks
11
- end
12
-
13
- def process(operations)
14
- results = JSONAPI::OperationResults.new
15
-
16
- # Use transactions if more than one operation and if one of the operations can be transactional
17
- # Even if transactional transactions won't be used unless the derived OperationsProcessor supports them.
18
- transactional = false
19
-
20
- operations.each do |operation|
21
- transactional |= operation.transactional?
22
- end if JSONAPI.configuration.allow_transactions
23
-
24
- transaction(transactional) do
25
- # Links and meta data global to the set of operations
26
- operations_meta = {}
27
- operations_links = {}
28
- operations.each do |operation|
29
- results.add_result(process_operation(operation))
30
- rollback(transactional) if results.has_errors?
31
- end
32
- results.meta = operations_meta
33
- results.links = operations_links
34
- end
35
- results
36
- end
37
-
38
- private
39
-
40
- def transaction(transactional)
41
- if transactional
42
- @transaction.call do
43
- yield
44
- end
45
- else
46
- yield
47
- end
48
- end
49
-
50
- def rollback(transactional)
51
- if transactional
52
- @rollback.call
53
- end
54
- end
55
-
56
- def process_operation(operation)
57
- with_default_handling do
58
- operation.process
59
- end
60
- end
61
-
62
- def with_default_handling(&block)
63
- block.yield
64
- rescue => e
65
- if JSONAPI.configuration.exception_class_whitelisted?(e)
66
- raise e
67
- else
68
- @server_error_callbacks.each { |callback|
69
- safe_run_callback(callback, e)
70
- }
71
-
72
- internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
73
- Rails.logger.error { "Internal Server Error: #{e.message} #{e.backtrace.join("\n")}" }
74
- return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
75
- end
76
- end
77
-
78
- def safe_run_callback(callback, error)
79
- begin
80
- callback.call(error)
81
- rescue => e
82
- Rails.logger.error { "Error in error handling callback: #{e.message} #{e.backtrace.join("\n")}" }
83
- internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
84
- return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
85
- end
86
- end
87
- end
88
- end
@@ -1,35 +0,0 @@
1
- module JSONAPI
2
- class OperationResults
3
- attr_accessor :results
4
- attr_accessor :meta
5
- attr_accessor :links
6
-
7
- def initialize
8
- @results = []
9
- @has_errors = false
10
- @meta = {}
11
- @links = {}
12
- end
13
-
14
- def add_result(result)
15
- @has_errors = true if result.is_a?(JSONAPI::ErrorsOperationResult)
16
- @results.push(result)
17
- end
18
-
19
- def has_errors?
20
- @has_errors
21
- end
22
-
23
- def all_errors
24
- errors = []
25
- if @has_errors
26
- @results.each do |result|
27
- if result.is_a?(JSONAPI::ErrorsOperationResult)
28
- errors.concat(result.errors)
29
- end
30
- end
31
- end
32
- errors
33
- end
34
- end
35
- end
@@ -1,167 +0,0 @@
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