ibrain-core 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/ibrain/base_controller.rb +14 -12
  3. data/app/controllers/ibrain/core/graphql_controller.rb +83 -79
  4. data/app/graphql/ibrain/base_schema.rb +52 -50
  5. data/app/graphql/ibrain/extentions/default_value.rb +11 -7
  6. data/app/graphql/ibrain/extentions/roles.rb +20 -15
  7. data/app/graphql/ibrain/extentions/session_required.rb +14 -10
  8. data/app/graphql/ibrain/lazy/base.rb +6 -2
  9. data/app/graphql/ibrain/loaders/association_loader.rb +55 -51
  10. data/app/graphql/ibrain/mutations/base_mutation.rb +56 -52
  11. data/app/graphql/ibrain/policies/base_policy.rb +47 -43
  12. data/app/graphql/ibrain/policies/graphql_policy.rb +6 -2
  13. data/app/graphql/ibrain/resolvers/base_aggregate.rb +10 -6
  14. data/app/graphql/ibrain/resolvers/base_resolver.rb +12 -8
  15. data/app/graphql/ibrain/types/aggregate_type.rb +8 -4
  16. data/app/graphql/ibrain/types/attribute_type.rb +5 -2
  17. data/app/graphql/ibrain/types/base_api_connection.rb +10 -6
  18. data/app/graphql/ibrain/types/base_api_edge.rb +8 -4
  19. data/app/graphql/ibrain/types/base_api_field.rb +11 -7
  20. data/app/graphql/ibrain/types/base_api_object.rb +10 -6
  21. data/app/graphql/ibrain/types/base_argument.rb +7 -3
  22. data/app/graphql/ibrain/types/base_connection.rb +11 -7
  23. data/app/graphql/ibrain/types/base_edge.rb +7 -3
  24. data/app/graphql/ibrain/types/base_enum.rb +5 -1
  25. data/app/graphql/ibrain/types/base_field.rb +10 -6
  26. data/app/graphql/ibrain/types/base_input_object.rb +10 -6
  27. data/app/graphql/ibrain/types/base_interface.rb +9 -5
  28. data/app/graphql/ibrain/types/base_object.rb +16 -12
  29. data/app/graphql/ibrain/types/base_scalar.rb +5 -1
  30. data/app/graphql/ibrain/types/base_type.rb +10 -4
  31. data/app/graphql/ibrain/types/base_union.rb +7 -3
  32. data/app/graphql/ibrain/types/filter_type.rb +5 -1
  33. data/app/graphql/ibrain/types/node_type.rb +8 -4
  34. data/app/graphql/ibrain/util/field_combiner.rb +9 -5
  35. data/app/graphql/ibrain/util/query_combiner.rb +8 -4
  36. data/app/models/concerns/ibrain/soft_deletable.rb +8 -6
  37. data/app/models/concerns/ibrain/user_api_authentication.rb +16 -14
  38. data/app/models/concerns/ibrain/user_methods.rb +13 -11
  39. data/app/models/ibrain/ability.rb +32 -31
  40. data/app/models/ibrain/aggregate.rb +7 -5
  41. data/app/models/ibrain/application_record.rb +4 -2
  42. data/app/models/ibrain/legacy_user.rb +13 -7
  43. data/app/models/ibrain/role.rb +8 -6
  44. data/app/models/ibrain/role_user.rb +10 -8
  45. data/app/repositories/ibrain/base_repository.rb +11 -9
  46. data/lib/generators/ibrain/core/model_generator.rb +21 -17
  47. data/lib/generators/ibrain/graphql/core.rb +59 -55
  48. data/lib/generators/ibrain/graphql/mutation_generator.rb +66 -58
  49. data/lib/generators/ibrain/graphql/object_generator.rb +70 -58
  50. data/lib/generators/ibrain/graphql/resolver_generator.rb +25 -17
  51. data/lib/generators/ibrain/graphql/resolvers_generator.rb +67 -59
  52. data/lib/generators/ibrain/graphql/templates/aggregate.erb +7 -5
  53. data/lib/generators/ibrain/graphql/templates/input.erb +9 -5
  54. data/lib/generators/ibrain/graphql/templates/mutation.erb +26 -24
  55. data/lib/generators/ibrain/graphql/templates/object.erb +10 -6
  56. data/lib/generators/ibrain/graphql/templates/resolver.erb +11 -9
  57. data/lib/generators/ibrain/graphql/templates/resolvers.erb +10 -8
  58. data/lib/generators/ibrain/graphql/type_generator.rb +88 -84
  59. data/lib/generators/ibrain/install/install_generator.rb +140 -137
  60. data/lib/generators/ibrain/install/templates/graphql/types/mutation_type.rb.tt +15 -13
  61. data/lib/generators/ibrain/install/templates/graphql/types/query_type.rb.tt +13 -11
  62. data/lib/generators/ibrain/install/templates/rubocop.yml.tt +30 -83
  63. data/lib/ibrain/app_configuration.rb +36 -34
  64. data/lib/ibrain/core/class_constantizer.rb +33 -30
  65. data/lib/ibrain/core/controller_helpers/auth.rb +59 -53
  66. data/lib/ibrain/core/controller_helpers/current_host.rb +11 -5
  67. data/lib/ibrain/core/controller_helpers/response.rb +49 -43
  68. data/lib/ibrain/core/controller_helpers/strong_parameters.rb +15 -9
  69. data/lib/ibrain/core/engine.rb +9 -5
  70. data/lib/ibrain/core/environment.rb +9 -5
  71. data/lib/ibrain/core/environment_extension.rb +17 -13
  72. data/lib/ibrain/core/role_configuration.rb +54 -52
  73. data/lib/ibrain/core/validators/email.rb +17 -15
  74. data/lib/ibrain/core/version.rb +2 -2
  75. data/lib/ibrain/core/versioned_value.rb +65 -61
  76. data/lib/ibrain/encryptor.rb +20 -18
  77. data/lib/ibrain/logger.rb +15 -13
  78. data/lib/ibrain/permission_sets/base.rb +26 -22
  79. data/lib/ibrain/permission_sets/super_user.rb +7 -3
  80. data/lib/ibrain/permitted_attributes.rb +20 -18
  81. data/lib/ibrain/preferences/configuration.rb +137 -135
  82. data/lib/ibrain/preferences/preferable.rb +162 -158
  83. data/lib/ibrain/preferences/preferable_class_methods.rb +114 -112
  84. data/lib/ibrain/user_class_handle.rb +24 -22
  85. data/lib/ibrain_core.rb +1 -7
  86. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc329cadb1dbc83c7e0ea6e2a2e9f4eb6ef1ad3b74c8955e0f8ebb376ab329f2
4
- data.tar.gz: 7371a38a6e0b9f531851e4b5ddf046a8e245fcd540211e1b3d51ce3a3dabb1be
3
+ metadata.gz: '09278662f5dace559b2b93ed9a45f39ef9ca822643b31e0e50b44e923e1027dc'
4
+ data.tar.gz: 8f19875c9383f8235aaf53596978f7ab0fb568924a312d018e867fe5b4ae2957
5
5
  SHA512:
6
- metadata.gz: d69016d5aa23c6d5ea594298713db38c410087c56d3d7700302289ecd7e8bfa1d1db0eea2577cabf39036c37c9816f91a2e3f452cbb24161321d2f95f7af6be8
7
- data.tar.gz: 3b1a1bf408ee1ce1ba4d53fcbd0d41042dddd45fd45854cd9cefa93c5b2e6e8ff6317e8153309fbf94a0d3ef929b7424187593a8535cc05e12d42dbdab224a13
6
+ metadata.gz: b68fc74e862182d9295200edb26eced011eccd9f7e6b93b994a8392127a9ecb29e1a4e26405238ce4e450e76b1b86ccbf54a5c3f334752fdae6a04999dc708a2
7
+ data.tar.gz: 31d6e746ca29c99508950469e01e36b98279098cd7d6b97220a1a77de568c0e10da90fa9b0d877fa16375d48852e386f2b25db7f80b1aeb02b2bb60266402de7
@@ -1,18 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::BaseController < Ibrain::Config.parent_controller.constantize
4
- include ActionController::Helpers
5
- include Ibrain::Core::ControllerHelpers::Response
6
- include Ibrain::Core::ControllerHelpers::StrongParameters
7
- include Ibrain::Core::ControllerHelpers::CurrentHost
8
- include Ibrain::Core::ControllerHelpers::Auth
3
+ module Ibrain
4
+ class BaseController < Ibrain::Config.parent_controller.constantize
5
+ include ActionController::Helpers
6
+ include Ibrain::Core::ControllerHelpers::Response
7
+ include Ibrain::Core::ControllerHelpers::StrongParameters
8
+ include Ibrain::Core::ControllerHelpers::CurrentHost
9
+ include Ibrain::Core::ControllerHelpers::Auth
9
10
 
10
- include IbrainErrors
11
- include IbrainHandler
11
+ include IbrainErrors
12
+ include IbrainHandler
12
13
 
13
- protected
14
+ protected
14
15
 
15
- def cryptor
16
- Ibrain::Encryptor.new
16
+ def cryptor
17
+ Ibrain::Encryptor.new
18
+ end
17
19
  end
18
- end
20
+ end
@@ -1,99 +1,103 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::Core::GraphqlController < Ibrain::BaseController
4
- include Devise::Controllers::ScopedViews
5
-
6
- before_action :map_user_class_to_request
7
-
8
- helpers = %w(resource scope_name resource_name signed_in_resource
9
- resource_class resource_params devise_mapping)
10
- helper_method(*helpers)
11
-
12
- def execute
13
- query, variables, operation_name = normalize_entity
14
-
15
- result = schema.execute(
16
- query,
17
- variables: variables,
18
- context: {
19
- session: session,
20
- current_user: try_ibrain_current_user,
21
- controller: self,
22
- request: request
23
- },
24
- operation_name: operation_name,
25
- max_depth: max_depth(operation_name)
26
- )
27
-
28
- render_json_ok(result['data'], nil, result['errors'])
29
- end
3
+ module Ibrain
4
+ module Core
5
+ class GraphqlController < ::Ibrain::BaseController
6
+ include Devise::Controllers::ScopedViews
7
+
8
+ before_action :map_user_class_to_request
9
+
10
+ helpers = %w(resource scope_name resource_name signed_in_resource
11
+ resource_class resource_params devise_mapping)
12
+ helper_method(*helpers)
13
+
14
+ def execute
15
+ query, variables, operation_name = normalize_entity
16
+
17
+ result = schema.execute(
18
+ query,
19
+ variables: variables,
20
+ context: {
21
+ session: session,
22
+ current_user: try_ibrain_current_user,
23
+ controller: self,
24
+ request: request
25
+ },
26
+ operation_name: operation_name,
27
+ max_depth: max_depth(operation_name)
28
+ )
29
+
30
+ render_json_ok(result['data'], nil, result['errors'])
31
+ end
30
32
 
31
- protected
33
+ protected
32
34
 
33
- def normalize_entity
34
- return [params[:query], prepare_variables(params[:variables]), params[:operationName]] if params[:variables].present?
35
- return [params[:query], prepare_variables(params[:variables]), 'IntrospectionQuery'] if params[:query].try(:include?, 'IntrospectionQuery')
35
+ def normalize_entity
36
+ return [params[:query], prepare_variables(params[:variables]), params[:operationName]] if params[:variables].present?
37
+ return [params[:query], prepare_variables(params[:variables]), 'IntrospectionQuery'] if params[:query].try(:include?, 'IntrospectionQuery')
36
38
 
37
- operations = prepare_variables(params[:operations])
38
- query = operations['query'] || params[:query]
39
- variables = operations['variables'] || params[:variables]
40
- operation_name = operations['operationName'] || params[:operationName]
39
+ operations = prepare_variables(params[:operations])
40
+ query = operations['query'] || params[:query]
41
+ variables = operations['variables'] || params[:variables]
42
+ operation_name = operations['operationName'] || params[:operationName]
41
43
 
42
- if params[:map].present?
43
- JSON.parse(params[:map]).each do |k, arguments|
44
- argument_name = arguments.try(:first).try(:split, '.').try(:second)
45
- next if argument_name.blank?
44
+ if params[:map].present?
45
+ JSON.parse(params[:map]).each do |k, arguments|
46
+ argument_name = arguments.try(:first).try(:split, '.').try(:second)
47
+ next if argument_name.blank?
46
48
 
47
- file = params[k]
49
+ file = params[k]
48
50
 
49
- if variables[argument_name].blank?
50
- variables[argument_name] = variables[argument_name].is_a?(Array) ? [file] : file
51
+ if variables[argument_name].blank?
52
+ variables[argument_name] = variables[argument_name].is_a?(Array) ? [file] : file
51
53
 
52
- next
53
- end
54
+ next
55
+ end
56
+
57
+ unless variables[argument_name].is_a?(Array)
58
+ variables[argument_name] = [variables[argument_name]]
59
+ end
54
60
 
55
- unless variables[argument_name].is_a?(Array)
56
- variables[argument_name] = [variables[argument_name]]
61
+ variables[argument_name] = variables[argument_name].concat([file]).compact
62
+ end
57
63
  end
58
64
 
59
- variables[argument_name] = variables[argument_name].concat([file]).compact
65
+ [query, variables, operation_name]
60
66
  end
61
- end
62
-
63
- [query, variables, operation_name]
64
- end
65
67
 
66
- # Handle variables in form data, JSON body, or a blank value
67
- def prepare_variables(variables_param)
68
- case variables_param
69
- when String
70
- if variables_param.present?
71
- JSON.parse(variables_param) || {}
72
- else
73
- {}
68
+ # Handle variables in form data, JSON body, or a blank value
69
+ def prepare_variables(variables_param)
70
+ case variables_param
71
+ when String
72
+ if variables_param.present?
73
+ JSON.parse(variables_param) || {}
74
+ else
75
+ {}
76
+ end
77
+ when Hash
78
+ variables_param
79
+ when ActionController::Parameters
80
+ variables_param.to_unsafe_hash # GraphQLRuby will validate name and type of incoming variables.
81
+ when nil
82
+ {}
83
+ else
84
+ raise ArgumentError, "Unexpected parameter: #{variables_param}"
85
+ end
74
86
  end
75
- when Hash
76
- variables_param
77
- when ActionController::Parameters
78
- variables_param.to_unsafe_hash # GraphQLRuby will validate name and type of incoming variables.
79
- when nil
80
- {}
81
- else
82
- raise ArgumentError, "Unexpected parameter: #{variables_param}"
83
- end
84
- end
85
87
 
86
- def schema
87
- Ibrain::Config.graphql_schema.safe_constantize
88
- end
88
+ def schema
89
+ Ibrain::Config.graphql_schema.safe_constantize
90
+ end
89
91
 
90
- def map_user_class_to_request
91
- return if request.env['devise.mapping'].present?
92
+ def map_user_class_to_request
93
+ return if request.env['devise.mapping'].present?
92
94
 
93
- request.env['devise.mapping'] = Ibrain.user_class
94
- end
95
+ request.env['devise.mapping'] = Ibrain.user_class
96
+ end
95
97
 
96
- def max_depth(operation_name)
97
- operation_name == 'IntrospectionQuery' ? nil : Ibrain::Config.graphql_max_depth
98
+ def max_depth(operation_name)
99
+ operation_name == 'IntrospectionQuery' ? nil : Ibrain::Config.graphql_max_depth
100
+ end
101
+ end
98
102
  end
99
- end
103
+ end
@@ -1,53 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::BaseSchema < GraphQL::Schema
4
- use GraphQL::Batch
5
-
6
- max_depth Ibrain::Config.graphql_max_depth
7
- query_analyzer(Ibrain::LogQueryDepth)
8
-
9
- # use GraphQL::Guard.new(
10
- # policy_object: ::Ibrain::Config.graphql_policy.safe_constantize,
11
- # not_authorized: ->(type, field) { raise IbrainErrors::PermissionError.new("You not have permission to access #{type}.#{field}") }
12
- # )
13
-
14
- # Union and Interface Resolution
15
- def self.resolve_type(_abstract_type, _obj, _ctx)
16
- # TODO: Implement this function
17
- # to return the correct object type for `obj`
18
- raise(GraphQL::RequiredImplementationMissingError)
3
+ module Ibrain
4
+ class BaseSchema < ::GraphQL::Schema
5
+ use GraphQL::Batch
6
+
7
+ max_depth Ibrain::Config.graphql_max_depth
8
+ query_analyzer(Ibrain::LogQueryDepth)
9
+
10
+ # use GraphQL::Guard.new(
11
+ # policy_object: ::Ibrain::Config.graphql_policy.safe_constantize,
12
+ # not_authorized: ->(type, field) { raise IbrainErrors::PermissionError.new("You not have permission to access #{type}.#{field}") }
13
+ # )
14
+
15
+ # Union and Interface Resolution
16
+ def self.resolve_type(_abstract_type, _obj, _ctx)
17
+ # TODO: Implement this function
18
+ # to return the correct object type for `obj`
19
+ raise(GraphQL::RequiredImplementationMissingError)
20
+ end
21
+
22
+ # Relay-style Object Identification:
23
+
24
+ # Return a string UUID for `object`
25
+ def self.id_from_object(object, type_definition, query_ctx)
26
+ # Here's a simple implementation which:
27
+ # - joins the type name & object.id
28
+ # - encodes it with base64:
29
+ # GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
30
+ end
31
+
32
+ # Given a string UUID, find the object
33
+ def self.object_from_id(id, query_ctx)
34
+ # For example, to decode the UUIDs generated above:
35
+ # type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
36
+ #
37
+ # Then, based on `type_name` and `id`
38
+ # find an object in your application
39
+ # ...
40
+ end
41
+
42
+ def self.field(*args, camelize: false, **kwargs, &block)
43
+ # if camelize == false
44
+ # # Also make a camelized field:
45
+ # field(*args, camelize: false, **kwargs, &block)
46
+ # end
47
+ super
48
+ end
49
+
50
+ rescue_from(ActiveRecord::RecordNotFound) do |_err, _obj, _args, _ctx, field|
51
+ # Raise a graphql-friendly error with a custom message
52
+ raise GraphQL::ExecutionError, "#{field.type.unwrap.graphql_name} not found"
53
+ end
19
54
  end
20
-
21
- # Relay-style Object Identification:
22
-
23
- # Return a string UUID for `object`
24
- def self.id_from_object(object, type_definition, query_ctx)
25
- # Here's a simple implementation which:
26
- # - joins the type name & object.id
27
- # - encodes it with base64:
28
- # GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
29
- end
30
-
31
- # Given a string UUID, find the object
32
- def self.object_from_id(id, query_ctx)
33
- # For example, to decode the UUIDs generated above:
34
- # type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
35
- #
36
- # Then, based on `type_name` and `id`
37
- # find an object in your application
38
- # ...
39
- end
40
-
41
- def self.field(*args, camelize: false, **kwargs, &block)
42
- # if camelize == false
43
- # # Also make a camelized field:
44
- # field(*args, camelize: false, **kwargs, &block)
45
- # end
46
- super
47
- end
48
-
49
- rescue_from(ActiveRecord::RecordNotFound) do |_err, _obj, _args, _ctx, field|
50
- # Raise a graphql-friendly error with a custom message
51
- raise GraphQL::ExecutionError, "#{field.type.unwrap.graphql_name} not found"
52
- end
53
- end
55
+ end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::Extentions::DefaultValue < GraphQL::Schema::FieldExtension
4
- def after_resolve(value:, **_rest)
5
- if value.nil?
6
- options[:default_value]
7
- else
8
- value
3
+ module Ibrain
4
+ module Extentions
5
+ class DefaultValue < GraphQL::Schema::FieldExtension
6
+ def after_resolve(value:, **_rest)
7
+ if value.nil?
8
+ options[:default_value]
9
+ else
10
+ value
11
+ end
12
+ end
9
13
  end
10
14
  end
11
- end
15
+ end
@@ -1,22 +1,27 @@
1
1
  # frozen_string_literal: true
2
- class Ibrain::Extentions::Roles < GraphQL::Schema::FieldExtension
3
- def after_resolve(object:, value:, **_rest)
4
- raise IbrainErrors::PermissionError.new("You not have permission to access #{field&.name}") if is_invalid_role(object)
5
2
 
6
- value
7
- end
3
+ module Ibrain
4
+ module Extentions
5
+ class Roles < GraphQL::Schema::FieldExtension
6
+ def after_resolve(object:, value:, **_rest)
7
+ raise IbrainErrors::PermissionError.new("You not have permission to access #{field&.name}") if is_invalid_role(object)
8
+
9
+ value
10
+ end
8
11
 
9
- private
12
+ private
10
13
 
11
- def is_invalid_role(object)
12
- roles = options.try(:fetch, :roles, [])
13
- current_user = object.try(:context).try(:fetch, :current_user, nil)
14
- role = current_user.try(:role) || current_user.try(:graphql_role)
14
+ def is_invalid_role(object)
15
+ roles = options.try(:fetch, :roles, [])
16
+ current_user = object.try(:context).try(:fetch, :current_user, nil)
17
+ role = current_user.try(:role) || current_user.try(:graphql_role)
15
18
 
16
- return if roles.blank?
17
- return true if current_user.blank?
18
- return false if roles.include?(role)
19
+ return if roles.blank?
20
+ return true if current_user.blank?
21
+ return false if roles.include?(role)
19
22
 
20
- true
23
+ true
24
+ end
25
+ end
21
26
  end
22
- end
27
+ end
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::Extentions::SessionRequired < GraphQL::Schema::FieldExtension
4
- def resolve(object:, arguments:, **rest)
5
- raise ActionController::InvalidAuthenticityToken, I18n.t('ibrain.errors.session.invalid_session') if is_invalid_session(object)
3
+ module Ibrain
4
+ module Extentions
5
+ class SessionRequired < GraphQL::Schema::FieldExtension
6
+ def resolve(object:, arguments:, **rest)
7
+ raise ActionController::InvalidAuthenticityToken, I18n.t('ibrain.errors.session.invalid_session') if is_invalid_session(object)
6
8
 
7
- # yield the current time as `memo`
8
- yield(object, arguments, rest)
9
- end
9
+ # yield the current time as `memo`
10
+ yield(object, arguments, rest)
11
+ end
10
12
 
11
- private
13
+ private
12
14
 
13
- def is_invalid_session(object)
14
- object.try(:context).try(:fetch, :current_user, nil).blank? && options.try(:fetch, :session_required, false)
15
+ def is_invalid_session(object)
16
+ object.try(:context).try(:fetch, :current_user, nil).blank? && options.try(:fetch, :session_required, false)
17
+ end
18
+ end
15
19
  end
16
- end
20
+ end
@@ -1,4 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Ibrain::Lazy::Base < GraphQL::Schema::Resolver
4
- end
3
+ module Ibrain
4
+ module Lazy
5
+ class Base < GraphQL::Schema::Resolver
6
+ end
7
+ end
8
+ end
@@ -2,56 +2,60 @@
2
2
 
3
3
  # ref: https://zenn.dev/necocoa/articles/setup-graphql-batch
4
4
 
5
- class Ibrain::Loaders::AssociationLoader < GraphQL::Batch::Loader
6
- def self.validate(model, association_name)
7
- new(model, association_name)
8
- nil
9
- end
10
-
11
- def initialize(model, association_name)
12
- super()
13
- @model = model
14
- @association_name = association_name
15
- validate
16
- end
17
-
18
- def load(record)
19
- unless record.is_a?(@model)
20
- raise TypeError,
21
- "#{@model} loader can't load association for #{record.class}"
5
+ module Ibrain
6
+ module Loaders
7
+ class AssociationLoader < GraphQL::Batch::Loader
8
+ def self.validate(model, association_name)
9
+ new(model, association_name)
10
+ nil
11
+ end
12
+
13
+ def initialize(model, association_name)
14
+ super()
15
+ @model = model
16
+ @association_name = association_name
17
+ validate
18
+ end
19
+
20
+ def load(record)
21
+ unless record.is_a?(@model)
22
+ raise TypeError,
23
+ "#{@model} loader can't load association for #{record.class}"
24
+ end
25
+ return Promise.resolve(read_association(record)) if association_loaded?(record)
26
+
27
+ super
28
+ end
29
+
30
+ # We want to load the associations on all records, even if they have the same id
31
+ def cache_key(record)
32
+ record.object_id
33
+ end
34
+
35
+ def perform(records)
36
+ preload_association(records)
37
+ records.each { |record| fulfill(record, read_association(record)) }
38
+ end
39
+
40
+ private
41
+
42
+ def validate
43
+ return if @model.reflect_on_association(@association_name)
44
+
45
+ raise ArgumentError, "No association #{@association_name} on #{@model}"
46
+ end
47
+
48
+ def preload_association(records)
49
+ ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
50
+ end
51
+
52
+ def read_association(record)
53
+ record.public_send(@association_name)
54
+ end
55
+
56
+ def association_loaded?(record)
57
+ record.association(@association_name).loaded?
58
+ end
22
59
  end
23
- return Promise.resolve(read_association(record)) if association_loaded?(record)
24
-
25
- super
26
- end
27
-
28
- # We want to load the associations on all records, even if they have the same id
29
- def cache_key(record)
30
- record.object_id
31
- end
32
-
33
- def perform(records)
34
- preload_association(records)
35
- records.each { |record| fulfill(record, read_association(record)) }
36
- end
37
-
38
- private
39
-
40
- def validate
41
- return if @model.reflect_on_association(@association_name)
42
-
43
- raise ArgumentError, "No association #{@association_name} on #{@model}"
44
- end
45
-
46
- def preload_association(records)
47
- ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
48
- end
49
-
50
- def read_association(record)
51
- record.public_send(@association_name)
52
- end
53
-
54
- def association_loaded?(record)
55
- record.association(@association_name).loaded?
56
60
  end
57
- end
61
+ end