Skip to content

Commit

Permalink
add filter and order entities
Browse files Browse the repository at this point in the history
  • Loading branch information
simonfranzen committed Sep 19, 2020
1 parent dde6fcf commit f1ff783
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 6 deletions.
9 changes: 6 additions & 3 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,28 @@ ruby '2.6.5'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3'
gem 'rails-i18n', '~> 6.0.0'

# Use postgresql as the database for Active Record
gem 'pg'

gem 'bcrypt', '~> 3.1.7' # Use ActiveModel has_secure_password
gem 'devise' # Use devise as authentication module
gem 'devise-i18n' # Install default translations
gem 'graphql', '~> 1.11.4' # GraphQL as API
gem 'graphql-auth', git: 'https://github.com/simonfranzen/graphql-auth.git', branch: 'rails6'
gem 'graphql-errors' # GrapqhQL error handling
gem 'search_object_graphql' # Search Object for graphql-ruby
gem 'rack-cors' # Rack CORS settings
gem 'rails_admin', '~> 2.0.2' # Admin interface
gem 'rails_admin-i18n' # Use default rails_admin translations
gem 'cancancan' # Defining abilities
gem 'image_processing', '~> 1.2' # Image processing
gem 'mini_magick' # Image manipulation with rmagick
gem 'friendly_id', '5.3.0' # Auto generate slugs for resources

# I18n
gem 'rails-i18n', '~> 6.0.0'
gem 'devise-i18n' # Install default translations
gem 'rails_admin-i18n' # Use default rails_admin translations

# gem 'graphiql-rails', group: :development

# Use Puma as the app server
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
search_object (1.2.4)
search_object_graphql (0.3.2)
graphql (~> 1.8)
search_object (~> 1.2.2)
shoulda-matchers (4.0.0.rc1)
activesupport (>= 4.2.0)
simplecov (0.16.1)
Expand Down Expand Up @@ -380,6 +384,7 @@ DEPENDENCIES
rubocop-performance
rubocop-rails
rubocop-rspec
search_object_graphql
shoulda-matchers (= 4.0.0.rc1)
simplecov
spring
Expand Down
41 changes: 40 additions & 1 deletion app/graphql/resolvers/base_resolver.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,47 @@
# frozen_string_literal: true

module Resolvers
# Base resolver class
# Base resolver class include everything you need for sorting and filtering entities
class BaseResolver < GraphQL::Schema::Resolver
# override in your resolver to allow order by attributes
def allowed_filter_attributes
raise 'Return an array with your allowed filter attributes.'
end

# apply_filter recursively loops through "OR" branches
def apply_filter(scope, value)
branches = normalize_filters(value).reduce { |a, b| a.or(b) }
scope.merge branches
end

def normalize_filters(value, branches = [])
scope = resources
allowed_filter_attributes.each do |filter_attr|
if value[filter_attr.to_sym].present?
scope = scope.where("#{filter_attr} LIKE ?", "%#{value[filter_attr.to_sym]}%")
end
end
branches << scope
value[:OR].reduce(branches) { |s, v| normalize_filters(v, s) } if value[:OR].present?
branches
end

# override in your resolver to allow order by attributes
def allowed_order_attributes
raise 'Return an array with your allowed order attributes.'
end

# apply order_by
def apply_order_by(scope, value)
direction = 'asc'
if value[:attribute].present? &&
allowed_order_attributes.include?(value[:attribute])
direction = value[:direction] if value[:direction].present? && %w[asc desc].include?(value[:direction].downcase)
scope = scope.order("#{value[:attribute]} #{direction}")
end
scope
end

def current_ability
Ability.new(context[:current_user])
end
Expand Down
25 changes: 23 additions & 2 deletions app/graphql/resolvers/users/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,33 @@ module Resolvers
module Users
# Resolver to return a user
class Users < Resolvers::BaseResolver
type Types::Users::UserType.connection_type, null: true
include ::SearchObject.module(:graphql)

type Types::Users::UserType.connection_type, null: false
description 'Returns all user for the current user company'
scope { resources }

def resolve(**_args)
def resources
::User.accessible_by(current_ability).includes(:company)
end

# when "order_by" is passed "apply_order_by" would be called to order the relation
option :order_by, type: Types::ItemOrderType, with: :apply_order_by
def allowed_order_attributes
%w[email first_name last_name created_at updated_at]
end

# inline input type definition for the advanced filter
class UserFilterType < ::Types::BaseInputObject
argument :OR, [self], required: false
argument :email, String, required: false
argument :first_name, String, required: false
argument :last_name, String, required: false
end
option :filter, type: UserFilterType, with: :apply_filter
def allowed_filter_attributes
%w[email first_name last_name]
end
end
end
end
9 changes: 9 additions & 0 deletions app/graphql/types/item_order_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module Types
# Base type for sort objects
class ItemOrderType < BaseInputObject
argument :attribute, String, required: true, description: 'The attribute you want to order by.'
argument :direction, String, required: true, description: 'Set a direction with "asc" or "desc".'
end
end
4 changes: 4 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
# require 'action_cable/engine'
# require 'rails/test_unit/railtie'

# We had to require this module manually. No idea why...
require 'search_object'
require 'search_object/plugin/graphql'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
Expand Down

0 comments on commit f1ff783

Please sign in to comment.