From 8e13b2906a18fee40e1155ef751f3db57a974c58 Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Thu, 11 Jan 2024 21:46:10 +0100 Subject: [PATCH] feat: allow finders to be inherited feat: change configuration from hash to configuration object --- .../finder/activities/prepare_adapter.rb | 2 +- .../finder/activities/prepare_entity.rb | 8 +- .../finder/activities/prepare_filters.rb | 8 +- .../finder/activities/prepare_paging.rb | 10 +- .../finder/activities/prepare_properties.rb | 12 +-- .../finder/activities/prepare_sorting.rb | 12 +-- .../finder/activities/process_adapters.rb | 7 +- lib/trailblazer/finder/dsl.rb | 91 ++++++++++++------- test/support/operations.rb | 2 + test/trailblazer/finder/dsl_spec.rb | 12 +-- test/trailblazer/operation/finder_spec.rb | 10 +- 11 files changed, 100 insertions(+), 74 deletions(-) diff --git a/lib/trailblazer/finder/activities/prepare_adapter.rb b/lib/trailblazer/finder/activities/prepare_adapter.rb index 0071758..e93d5ac 100644 --- a/lib/trailblazer/finder/activities/prepare_adapter.rb +++ b/lib/trailblazer/finder/activities/prepare_adapter.rb @@ -5,7 +5,7 @@ class Finder module Activities class PrepareAdapter < Trailblazer::Activity::Railway def set_adapter(ctx, **) - ctx[:adapter] = ctx.dig(:config, :adapter) || "Basic" + ctx[:adapter] = ctx[:config].adapter end def validate_adapter(_ctx, adapter:, **) diff --git a/lib/trailblazer/finder/activities/prepare_entity.rb b/lib/trailblazer/finder/activities/prepare_entity.rb index 122f9b2..a39a170 100644 --- a/lib/trailblazer/finder/activities/prepare_entity.rb +++ b/lib/trailblazer/finder/activities/prepare_entity.rb @@ -4,16 +4,16 @@ module Trailblazer class Finder module Activities class PrepareEntity < Trailblazer::Activity::Railway - def validate_entity(ctx, **) - ctx.dig(:options, :entity) || ctx.dig(:config, :entity) + def validate_entity(ctx, config:, **) + ctx.dig(:options, :entity) || config.entity end def invalid_entity_error(ctx, **) (ctx[:errors] ||= []) << {entity: "Invalid entity specified"} end - def set_entity(ctx, **) - ctx[:entity] = ctx.dig(:options, :entity) || instance_eval(&ctx[:config][:entity]) + def set_entity(ctx, config:, **) + ctx[:entity] = ctx.dig(:options, :entity) || instance_eval(&config.entity) end step :validate_entity diff --git a/lib/trailblazer/finder/activities/prepare_filters.rb b/lib/trailblazer/finder/activities/prepare_filters.rb index 11709b4..74308cf 100644 --- a/lib/trailblazer/finder/activities/prepare_filters.rb +++ b/lib/trailblazer/finder/activities/prepare_filters.rb @@ -4,8 +4,8 @@ module Trailblazer class Finder module Activities class PrepareFilters < Trailblazer::Activity::Railway - def validate_filters(ctx, **) - filters = ctx.dig(:config, :filters) + def validate_filters(_ctx, config:, **) + filters = config.filters filters.each do |key, _value| return false if !filters[key][:with].nil? && !filters[key][:with].is_a?(Symbol) end @@ -16,8 +16,8 @@ def invalid_filters_error(ctx, **) (ctx[:errors] ||= []) << {filters: "One or more filters are missing a with method definition"} end - def set_filters(ctx, **) - ctx[:filters] = ctx[:config][:filters] + def set_filters(ctx, config:, **) + ctx[:filters] = config.filters end step :validate_filters diff --git a/lib/trailblazer/finder/activities/prepare_paging.rb b/lib/trailblazer/finder/activities/prepare_paging.rb index 44ffd10..8ad9f83 100644 --- a/lib/trailblazer/finder/activities/prepare_paging.rb +++ b/lib/trailblazer/finder/activities/prepare_paging.rb @@ -4,15 +4,15 @@ module Trailblazer class Finder module Activities class PreparePaging < Trailblazer::Activity::Railway - def check_paging(ctx, **) - paging = ctx[:config][:paging] || nil - return false if ctx[:config][:paging].empty? || paging.nil? + def check_paging(_ctx, config:, **) + paging = config.paging + return false if config.paging.empty? || paging.nil? true end - def set_paging(ctx, **) - ctx[:paging] = ctx.dig(:config, :paging) || {} + def set_paging(ctx, config:, **) + ctx[:paging] = config.paging ctx[:paging][:current_page] = ctx.dig(:params, :page) || 1 return true unless ctx[:params][:per_page] diff --git a/lib/trailblazer/finder/activities/prepare_properties.rb b/lib/trailblazer/finder/activities/prepare_properties.rb index 2c84bdd..8d5f5be 100644 --- a/lib/trailblazer/finder/activities/prepare_properties.rb +++ b/lib/trailblazer/finder/activities/prepare_properties.rb @@ -4,8 +4,8 @@ module Trailblazer class Finder module Activities class PrepareProperties < Trailblazer::Activity::Railway - def check_property_types(ctx, **) - properties = ctx[:config][:properties] || {} + def check_property_types(_ctx, config:, **) + properties = config.properties return true if properties.empty? properties.each do |key, _value| @@ -13,8 +13,8 @@ def check_property_types(ctx, **) end end - def validate_property_types(ctx, **) - properties = ctx[:config][:properties] || {} + def validate_property_types(_ctx, config:, **) + properties = config.properties return true if properties.empty? properties.each do |key, _value| @@ -26,8 +26,8 @@ def invalid_properties_error(ctx, **) (ctx[:errors] ||= []) << {properties: "One or more properties are missing a valid type"} end - def set_properties(ctx, **) - ctx[:properties] = ctx[:config][:properties] + def set_properties(ctx, config:, **) + ctx[:properties] = config.properties end step :check_property_types diff --git a/lib/trailblazer/finder/activities/prepare_sorting.rb b/lib/trailblazer/finder/activities/prepare_sorting.rb index 8f29616..1a9541b 100644 --- a/lib/trailblazer/finder/activities/prepare_sorting.rb +++ b/lib/trailblazer/finder/activities/prepare_sorting.rb @@ -4,20 +4,20 @@ module Trailblazer class Finder module Activities class PrepareSorting < Trailblazer::Activity::Railway - def check_sorting(ctx, **) - sorting = ctx[:config][:sorting] || nil - return true unless ctx[:config][:sorting].empty? || sorting.nil? + def check_sorting(_ctx, config:, **) + sorting = config.sorting + return true unless sorting.empty? || sorting.nil? end - def set_sorting(ctx, **) + def set_sorting(ctx, config:, **) return true if ctx[:params][:sort].nil? sorting = ctx[:params][:sort] - config = ctx[:config][:sorting] + sorting_config = config.sorting ctx[:sorting] = ctx[:sorting] || {} sorting.split(",").each do |sorter| spt = sorter.split - ctx[:sorting][spt[0]] = fetch_sort_direction(config[spt[0].to_sym], spt[1]) if config.include?(spt[0].to_sym) + ctx[:sorting][spt[0]] = fetch_sort_direction(sorting_config[spt[0].to_sym], spt[1]) if sorting_config.include?(spt[0].to_sym) end end diff --git a/lib/trailblazer/finder/activities/process_adapters.rb b/lib/trailblazer/finder/activities/process_adapters.rb index 07d6111..7e790ad 100644 --- a/lib/trailblazer/finder/activities/process_adapters.rb +++ b/lib/trailblazer/finder/activities/process_adapters.rb @@ -15,7 +15,7 @@ def set_adapter((ctx, _flow_options), **) end def set_paginator(ctx, **) - paginator = ctx.dig(:config, :paginator) + paginator = ctx[:config].paginator return true unless paginator return false unless EXT_ORM_ADAPTERS.(ctx[:orm][:adapter]) return false unless PAGING_ADAPTERS.(paginator) @@ -26,10 +26,7 @@ def set_paginator(ctx, **) def invalid_paginator_error(ctx, **) (ctx[:errors] ||= []) << { - paginator: "Can't use paginator #{ctx.dig( - :config, - :paginator - )} without using an ORM like ActiveRecord or Sequel" + paginator: "Can't use paginator #{ctx[:config].paginator} without using an ORM like ActiveRecord or Sequel" } end diff --git a/lib/trailblazer/finder/dsl.rb b/lib/trailblazer/finder/dsl.rb index 52be226..a6bdd84 100644 --- a/lib/trailblazer/finder/dsl.rb +++ b/lib/trailblazer/finder/dsl.rb @@ -1,72 +1,95 @@ -# frozen_string_literal: true - module Trailblazer class Finder + class Configuration + attr_accessor :entity, :paging, :properties, :sorting, + :filters, :adapter, :paginator + + def initialize + @paging = {} + @properties = {} + @sorting = {} + @filters = {} + @paginator = nil + @adapter = "Basic" + end + + def clone + new_config = Configuration.new + new_config.entity = entity + new_config.paging = paging.clone + new_config.properties = properties.clone + new_config.sorting = sorting.clone + new_config.filters = filters.clone + new_config.adapter = adapter + new_config.paginator = paginator + new_config + end + end + module Dsl def config - @config ||= apply_config({}) + @config ||= Configuration.new end + def inherited(base) ## We don't want to inherit the config from Trailblazer::Finder return if name == 'Trailblazer::Finder' - base.apply_config(config) + base.config = config.clone end def entity(&block) - config[:entity] = block + config.entity = block end - def paging(**options) - config[:paging][:per_page] = options[:per_page] || 25 - config[:paging][:min_per_page] = options[:min_per_page] || 10 - config[:paging][:max_per_page] = options[:max_per_page] || 100 + def paging(per_page: 25, min_per_page: 10, max_per_page: 100) + config.paging[:per_page] = per_page + config.paging[:min_per_page] = min_per_page + config.paging[:max_per_page] = max_per_page end def property(name, options = {}) - config[:properties][name] = options - config[:properties][name][:type] = options[:type] || Types::String - config[:sorting][name] = options[:sort_direction] || :desc if options[:sortable] + config.properties[name] = options + config.properties[name][:type] = options[:type] || Types::String + config.sorting[name] = options[:sort_direction] || :desc if options[:sortable] end def filter_by(name, options = {}, &block) filter_name = name.to_sym - config[:filters][filter_name] = {} - config[:filters][filter_name][:name] = name - config[:filters][filter_name][:with] = options[:with] if options.include?(:with) - config[:filters][filter_name][:block] = block || nil + config.filters[filter_name] = {} + config.filters[filter_name][:name] = name + config.filters[filter_name][:with] = options[:with] if options.include?(:with) + config.filters[filter_name][:block] = block || nil end - def adapter(adapter) - config[:adapter] = adapter.to_s + def adapter(adapter_name) + config.adapter = adapter_name.to_s end - def paginator(paginator) - config[:paginator] = paginator.to_s + def paginator(paginator_name) + config.paginator = paginator_name.to_s end def current_adapter - config[:adapter] + config.adapter end def current_paginator - config[:paginator] + config.paginator + end + + def filters_count + config.filters.count end - def apply_config(options, **) - return @config = options unless options.empty? - - @config = { - actions: {}, - entity: nil, - properties: {}, - filters: {}, - paging: {}, - sorting: {}, - adapters: [] - } + def properties_count + config.properties.count end + + protected + + attr_writer :config end end end diff --git a/test/support/operations.rb b/test/support/operations.rb index bd551f8..ac26bf7 100644 --- a/test/support/operations.rb +++ b/test/support/operations.rb @@ -34,7 +34,9 @@ def apply_escaped_name(entity, _attribute, value) end class FinderInherited < FinderWithEntity + property :raw_price, type: Types::Float, sortable: true filter_by :price, with: :apply_price + paginator 'Kaminari' def apply_price(entity, _attribute, value) return if value.blank? diff --git a/test/trailblazer/finder/dsl_spec.rb b/test/trailblazer/finder/dsl_spec.rb index f12b2de..fd56ec6 100644 --- a/test/trailblazer/finder/dsl_spec.rb +++ b/test/trailblazer/finder/dsl_spec.rb @@ -42,7 +42,7 @@ def new_finder(default_entity = [], filter = {}, &block) property :value, type: Base end - assert_equal finder.class.config[:adapter], 'ActiveRecord' + assert_equal finder.class.config.adapter, 'ActiveRecord' end end @@ -62,7 +62,7 @@ def new_finder(default_entity = [], filter = {}, &block) property :value, type: Base end - assert_equal finder.class.config[:properties], value: { type: Trailblazer::Finder::Base } + assert_equal finder.class.config.properties, value: { type: Trailblazer::Finder::Base } end end @@ -74,9 +74,9 @@ def new_finder(default_entity = [], filter = {}, &block) property :value, type: Types::String end - assert_equal finder.class.config[:paging][:per_page], 2 - assert_equal finder.class.config[:paging][:min_per_page], 1 - assert_equal finder.class.config[:paging][:max_per_page], 5 + assert_equal finder.class.config.paging[:per_page], 2 + assert_equal finder.class.config.paging[:min_per_page], 1 + assert_equal finder.class.config.paging[:max_per_page], 5 end it "does not load paging stuff if paging isn't called in the finder class" do @@ -85,7 +85,7 @@ def new_finder(default_entity = [], filter = {}, &block) property :value, type: Types::String end - assert_empty finder.class.config[:paging] + assert_empty finder.class.config.paging end end diff --git a/test/trailblazer/operation/finder_spec.rb b/test/trailblazer/operation/finder_spec.rb index 7eabc1a..81dad01 100644 --- a/test/trailblazer/operation/finder_spec.rb +++ b/test/trailblazer/operation/finder_spec.rb @@ -74,13 +74,17 @@ class Operation::FinderSpec < Minitest::TrailblazerSpec end - it 'Can work with inherited finders' do + it 'can inherit finders' do assert_equal Product::Finders::FinderWithEntity.current_adapter, 'ActiveRecord' assert_nil Product::Finders::FinderWithEntity.current_paginator + ## the parent class has 1 filter and 2 properties and not being overwritten by the child class + assert_equal Product::Finders::FinderWithEntity.properties_count, 2 + assert_equal Product::Finders::FinderWithEntity.filters_count, 1 assert_equal Product::Finders::FinderInherited.current_adapter, 'ActiveRecord' - assert_nil Product::Finders::FinderInherited.current_paginator - binding.irb + assert_equal Product::Finders::FinderInherited.current_paginator, 'Kaminari' + assert_equal Product::Finders::FinderInherited.properties_count, 3 + assert_equal Product::Finders::FinderInherited.filters_count, 2 end end end