Skip to content

Commit c200065

Browse files
Merge pull request #71 from graphql-devise/refactor-mount-method-option-validator
Refactor mount method option validator
2 parents 85086a0 + 879f9c5 commit c200065

24 files changed

Lines changed: 448 additions & 299 deletions

.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Style/MethodCalledOnDoEndBlock:
5959
Enabled: false
6060

6161
Naming/VariableNumber:
62-
Enabled: false
62+
EnforcedColonStyle: normalcase
6363

6464
Style/StringLiterals:
6565
ConsistentQuotesInMultiline: true

lib/graphql_devise.rb

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,28 @@
22
require 'graphql'
33
require 'devise_token_auth'
44

5+
module GraphqlDevise
6+
class Error < StandardError; end
7+
8+
class InvalidMountOptionsError < GraphqlDevise::Error; end
9+
end
10+
511
require 'graphql_devise/concerns/controller_methods'
612
require 'graphql_devise/types/authenticatable_type'
713
require 'graphql_devise/types/credential_type'
814
require 'graphql_devise/types/mutation_type'
915
require 'graphql_devise/types/query_type'
10-
require 'graphql_devise/mutations/base'
11-
require 'graphql_devise/mutations/login'
12-
require 'graphql_devise/mutations/logout'
13-
require 'graphql_devise/mutations/resend_confirmation'
14-
require 'graphql_devise/mutations/send_password_reset'
15-
require 'graphql_devise/mutations/sign_up'
16-
require 'graphql_devise/mutations/update_password'
17-
require 'graphql_devise/resolvers/base'
18-
require 'graphql_devise/resolvers/check_password_token'
19-
require 'graphql_devise/resolvers/confirm_account'
16+
require 'graphql_devise/default_operations/mutations'
17+
require 'graphql_devise/default_operations/resolvers'
2018
require 'graphql_devise/resolvers/dummy'
2119

2220
require 'graphql_devise/engine'
2321
require 'graphql_devise/version'
2422
require 'graphql_devise/error_codes'
2523
require 'graphql_devise/user_error'
2624
require 'graphql_devise/detailed_user_error'
27-
require 'graphql_devise/rails/queries_preparer'
28-
require 'graphql_devise/rails/mutations_preparer'
29-
require 'graphql_devise/rails/operation_checker'
30-
require 'graphql_devise/rails/operation_sanitizer'
3125

32-
module GraphqlDevise
33-
class Error < StandardError; end
34-
end
26+
require 'graphql_devise/mount_method/options_validator'
27+
require 'graphql_devise/mount_method/queries_preparer'
28+
require 'graphql_devise/mount_method/mutations_preparer'
29+
require 'graphql_devise/mount_method/operation_sanitizer'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
require 'graphql_devise/mutations/base'
2+
require 'graphql_devise/mutations/login'
3+
require 'graphql_devise/mutations/logout'
4+
require 'graphql_devise/mutations/resend_confirmation'
5+
require 'graphql_devise/mutations/send_password_reset'
6+
require 'graphql_devise/mutations/sign_up'
7+
require 'graphql_devise/mutations/update_password'
8+
9+
module GraphqlDevise
10+
module DefaultOperations
11+
MUTATIONS = {
12+
login: GraphqlDevise::Mutations::Login,
13+
logout: GraphqlDevise::Mutations::Logout,
14+
sign_up: GraphqlDevise::Mutations::SignUp,
15+
update_password: GraphqlDevise::Mutations::UpdatePassword,
16+
send_password_reset: GraphqlDevise::Mutations::SendPasswordReset,
17+
resend_confirmation: GraphqlDevise::Mutations::ResendConfirmation
18+
}.freeze
19+
end
20+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
require 'graphql_devise/resolvers/base'
2+
require 'graphql_devise/resolvers/check_password_token'
3+
require 'graphql_devise/resolvers/confirm_account'
4+
5+
module GraphqlDevise
6+
module DefaultOperations
7+
QUERIES = {
8+
confirm_account: GraphqlDevise::Resolvers::ConfirmAccount,
9+
check_password_token: GraphqlDevise::Resolvers::CheckPasswordToken
10+
}.freeze
11+
end
12+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module GraphqlDevise
2+
module MountMethod
3+
class MutationsPreparer
4+
def self.call(resource:, mutations:, authenticatable_type:)
5+
new(resource: resource, mutations: mutations, authenticatable_type: authenticatable_type).call
6+
end
7+
8+
def initialize(resource:, mutations:, authenticatable_type:)
9+
@mapping_name = resource.underscore.tr('/', '_').to_sym
10+
@mutations = mutations
11+
@authenticatable_type = authenticatable_type
12+
end
13+
14+
def call
15+
@mutations.each_with_object({}) do |(action, mutation), result|
16+
mapped_action = "#{@mapping_name}_#{action}".to_sym
17+
new_mutation = Class.new(mutation)
18+
new_mutation.graphql_name(mapped_action.to_s.camelize(:upper))
19+
new_mutation.field(:authenticatable, @authenticatable_type, null: true)
20+
new_mutation.instance_variable_set(:@resource_name, @mapping_name)
21+
22+
result[mapped_action] = new_mutation
23+
end
24+
end
25+
end
26+
end
27+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module GraphqlDevise
2+
module MountMethod
3+
class OperationSanitizer
4+
def self.call(default:, custom:, only:, skipped:)
5+
new(
6+
default: default,
7+
custom: custom,
8+
only: only,
9+
skipped: skipped
10+
).call
11+
end
12+
13+
def initialize(default:, custom:, only:, skipped:)
14+
@default = default
15+
@custom = custom
16+
@only = only
17+
@skipped = skipped
18+
end
19+
20+
def call
21+
result = @default.merge(@custom.slice(*operations_whitelist))
22+
result = result.slice(*@only) if @only.present?
23+
result = result.except(*@skipped) if @skipped.present?
24+
25+
result
26+
end
27+
28+
private
29+
30+
def operations_whitelist
31+
@default.keys
32+
end
33+
end
34+
end
35+
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
require_relative 'supported_operations_validator'
2+
3+
module GraphqlDevise
4+
module MountMethod
5+
module OptionValidators
6+
class ProvidedOperationsValidator
7+
def initialize(options: {}, supported_operations: {})
8+
@options = options || {}
9+
@supported_operations = supported_operations
10+
end
11+
12+
def validate!
13+
skipped = @options.fetch(:skip, [])
14+
only = @options.fetch(:only, [])
15+
operations = @options.fetch(:operations, {})
16+
supported_keys = @supported_operations.keys
17+
18+
raise_on_invalid_option_type!(:skip, skipped, Array)
19+
raise_on_invalid_option_type!(:only, only, Array)
20+
raise_on_invalid_option_type!(:operations, operations, Hash)
21+
22+
custom = operations.keys
23+
24+
[
25+
SupportedOperationsValidator.new(provided_operations: skipped, key: :skip, supported_operations: supported_keys),
26+
SupportedOperationsValidator.new(provided_operations: only, key: :only, supported_operations: supported_keys),
27+
SupportedOperationsValidator.new(provided_operations: custom, key: :operations, supported_operations: supported_keys)
28+
].each(&:validate!)
29+
end
30+
31+
private
32+
33+
def raise_on_invalid_option_type!(key, value, expected_class)
34+
unless value.is_a?(expected_class)
35+
raise(
36+
GraphqlDevise::InvalidMountOptionsError,
37+
"#{key} option contains value of invalid value. Value must be #{expected_class.name}."
38+
)
39+
end
40+
end
41+
end
42+
end
43+
end
44+
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module GraphqlDevise
2+
module MountMethod
3+
module OptionValidators
4+
class SkipOnlyValidator
5+
def initialize(options: {})
6+
@options = options || {}
7+
end
8+
9+
def validate!
10+
if [@options[:skip], @options[:only]].all?(&:present?)
11+
raise(
12+
GraphqlDevise::InvalidMountOptionsError,
13+
"Can't specify both `skip` and `only` options when mounting the route."
14+
)
15+
end
16+
end
17+
end
18+
end
19+
end
20+
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module GraphqlDevise
2+
module MountMethod
3+
module OptionValidators
4+
class SupportedOperationsValidator
5+
def initialize(provided_operations: [], supported_operations: [], key:)
6+
@provided_operations = provided_operations
7+
@supported_operations = supported_operations
8+
@key = key
9+
end
10+
11+
def validate!
12+
unsupported_operations = @provided_operations - @supported_operations
13+
14+
if unsupported_operations.present?
15+
raise(
16+
GraphqlDevise::InvalidMountOptionsError,
17+
"#{@key} option contains unsupported operations: \"#{unsupported_operations.join(', ')}\". Check for typos."
18+
)
19+
end
20+
end
21+
end
22+
end
23+
end
24+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require_relative 'option_validators/skip_only_validator'
2+
require_relative 'option_validators/provided_operations_validator'
3+
4+
module GraphqlDevise
5+
module MountMethod
6+
class OptionsValidator
7+
def initialize(validators = [])
8+
@validators = validators
9+
end
10+
11+
def validate!
12+
@validators.each(&:validate!)
13+
end
14+
end
15+
end
16+
end

0 commit comments

Comments
 (0)