feat(conditional): add include operator

This commit is contained in:
simon lehericey 2022-09-09 15:36:50 +02:00
parent 84c52099fb
commit fcb9b55bc4
7 changed files with 77 additions and 5 deletions

View file

@ -119,6 +119,10 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
[t('is', scope: 'logic'), Eq.name],
[t('is_not', scope: 'logic'), NotEq.name]
]
when ChampValue::CHAMP_VALUE_TYPE.fetch(:enums)
[
[t(IncludeOperator.name, scope: 'logic.operators'), IncludeOperator.name]
]
when ChampValue::CHAMP_VALUE_TYPE.fetch(:number)
[Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq]
.map(&:name)
@ -151,7 +155,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
options_for_select(empty_target_for_select),
id: input_id_for('value', row_index)
)
when :enum
when :enum, :enums
enums_for_select = left.options
if right_invalid

View file

@ -8,7 +8,7 @@ module Logic
end
def self.class_from_name(name)
[ChampValue, Constant, Empty, LessThan, LessThanEq, Eq, NotEq, GreaterThanEq, GreaterThan, EmptyOperator, And, Or]
[ChampValue, Constant, Empty, LessThan, LessThanEq, Eq, NotEq, GreaterThanEq, GreaterThan, EmptyOperator, IncludeOperator, And, Or]
.find { |c| c.name == name }
end
@ -24,6 +24,8 @@ module Logic
operator_class = EmptyOperator
in [:enum, _]
operator_class = Eq
in [:enums, _]
operator_class = IncludeOperator
in [:number, EmptyOperator]
operator_class = Eq
in [:number, _]
@ -35,7 +37,7 @@ module Logic
Constant.new(true)
when :empty
Empty.new
when :enum
when :enum, :enums
Constant.new(left.options.first.second)
when :number
Constant.new(0)
@ -49,7 +51,7 @@ module Logic
case [left.type, right.type]
in [a, ^a] # syntax for same type
true
in [:enum, :string]
in [:enum, :string] | [:enums, :string]
left.options.map(&:second).include?(right.value)
else
false
@ -84,6 +86,8 @@ module Logic
def less_than_eq(left, right) = Logic::LessThanEq.new(left, right)
def ds_include(left, right) = Logic::IncludeOperator.new(left, right)
def constant(value) = Logic::Constant.new(value)
def champ_value(stable_id) = Logic::ChampValue.new(stable_id)

View file

@ -4,13 +4,15 @@ class Logic::ChampValue < Logic::Term
:checkbox,
:integer_number,
:decimal_number,
:drop_down_list
:drop_down_list,
:multiple_drop_down_list
)
CHAMP_VALUE_TYPE = {
boolean: :boolean,
number: :number,
enum: :enum,
enums: :enums,
empty: :empty,
unmanaged: :unmanaged
}
@ -35,6 +37,8 @@ class Logic::ChampValue < Logic::Term
targeted_champ.for_api
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
targeted_champ.selected
when MANAGED_TYPE_DE_CHAMP.fetch(:multiple_drop_down_list)
targeted_champ.selected_options
end
end
@ -49,6 +53,8 @@ class Logic::ChampValue < Logic::Term
CHAMP_VALUE_TYPE.fetch(:number)
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
CHAMP_VALUE_TYPE.fetch(:enum)
when MANAGED_TYPE_DE_CHAMP.fetch(:multiple_drop_down_list)
CHAMP_VALUE_TYPE.fetch(:enums)
else
CHAMP_VALUE_TYPE.fetch(:unmanaged)
end

View file

@ -0,0 +1,29 @@
class Logic::IncludeOperator < Logic::BinaryOperator
def operation = :include?
def errors(stable_ids = [])
result = []
if left_not_a_list?
result << { type: :required_list }
elsif right_value_not_in_list?
result << {
type: :not_included,
stable_id: @left.stable_id,
right: @right
}
end
result + @left.errors(stable_ids) + @right.errors(stable_ids)
end
private
def left_not_a_list?
@left.type != :enums
end
def right_value_not_in_list?
!@left.options.map(&:second).include?(@right.value)
end
end

View file

@ -12,3 +12,4 @@ fr:
'Logic::And': Et
'Logic::Or': Ou
'Logic::NotEq': N'est pas
'Logic::IncludeOperator': Contient

View file

@ -0,0 +1,20 @@
describe Logic::IncludeOperator do
include Logic
let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') }
describe '#compute' do
it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(true) }
it { expect(ds_include(champ_value(champ.stable_id), constant('something else')).compute([champ])).to be(false) }
end
describe '#errors' do
it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).errors).to be_empty }
it { expect(ds_include(champ_value(champ.stable_id), constant('something else')).errors).to eq(["« something else » ne fait pas partie de « #{champ.libelle} »"]) }
it { expect(ds_include(constant(1), constant('val1')).errors).to eq(["Lʼopérateur inclusion ne sʼapplique que sur une liste"]) }
end
describe '#==' do
it { expect(ds_include(champ_value(champ.stable_id), constant('val1'))).to eq(ds_include(champ_value(champ.stable_id), constant('val1'))) }
end
end

View file

@ -49,6 +49,14 @@ describe Logic do
it { is_expected.to eq(ds_eq(champ_value(drop_down), constant(first_option))) }
end
context 'when multiple dropdown empty operator true' do
let(:multiple_drop_down) { create(:type_de_champ_multiple_drop_down_list) }
let(:first_option) { multiple_drop_down.drop_down_list_enabled_non_empty_options.first }
let(:condition) { empty_operator(champ_value(multiple_drop_down), constant(true)) }
it { is_expected.to eq(ds_include(champ_value(multiple_drop_down), constant(first_option))) }
end
end
describe '.compatible_type?' do