Skip to content

Commit

Permalink
fix(search): collection is not always searchable (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasalexandre9 authored Jan 6, 2025
1 parent 45fe772 commit 96824b7
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ def replace_search(definition)
push_customization { @stack.search.get_collection(@name).replace_search(definition) }
end

# Disable the search bar
# Example:
# collection.disable_search
def disable_search
push_customization { @stack.search.get_collection(@name).disable_search }
end

def add_field(name, definition)
push_customization do
collection_before_relations = @stack.early_computed.get_collection(@name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ class SearchCollectionDecorator < ForestAdminDatasourceToolkit::Decorators::Coll
def initialize(child_collection, datasource)
super
@replacer = nil
@disabled_search = get_fields(false).empty?
end

def disable_search
@disabled_search = true
end

def replace_search(replacer)
@replacer = replacer
end

def refine_schema(sub_schema)
sub_schema.merge({ searchable: true })
sub_schema.merge({ searchable: !@disabled_search })
end

def refine_filter(caller, filter)
Expand Down Expand Up @@ -48,7 +53,7 @@ def refine_filter(caller, filter)
private

def default_replacer(search, extended)
searchable_fields = get_fields(@child_collection, extended)
searchable_fields = get_fields(extended)

conditions = searchable_fields.map do |field, schema|
build_condition(field, schema, search)
Expand All @@ -64,11 +69,11 @@ def build_condition(field, schema, search_string)
is_number = number?(search_string)
is_uuid = uuid?(search_string)

if column_type == PrimitiveType::NUMBER && is_number && filter_operators&.include?(Operators::EQUAL)
if column_type == PrimitiveType::NUMBER && is_number
return Nodes::ConditionTreeLeaf.new(field, Operators::EQUAL, search_string.to_f)
end

if column_type == PrimitiveType::ENUM && filter_operators&.include?(Operators::EQUAL)
if column_type == PrimitiveType::ENUM
search_value = lenient_find(enum_values, search_string)

return Nodes::ConditionTreeLeaf.new(field, Operators::EQUAL, search_value) if search_value
Expand All @@ -92,17 +97,17 @@ def build_condition(field, schema, search_string)
return Nodes::ConditionTreeLeaf.new(field, operator, search_string) if operator
end

if column_type == PrimitiveType::UUID && is_uuid && filter_operators&.include?(Operators::EQUAL)
if column_type == PrimitiveType::UUID && is_uuid
return Nodes::ConditionTreeLeaf.new(field, Operators::EQUAL, search_string)
end

nil
end

def get_fields(collection, extended)
def get_fields(extended)
fields = []
collection.schema[:fields].each do |name, field|
fields.push([name, field]) if field.type == 'Column'
@child_collection.schema[:fields].each do |name, field|
fields.push([name, field]) if field.type == 'Column' && searchable_field?(field)

if field.type == 'PolymorphicManyToOne' && extended
ForestAdminAgent::Facades::Container.logger.log(
Expand All @@ -116,16 +121,30 @@ def get_fields(collection, extended)
next unless extended &&
(field.type == 'ManyToOne' || field.type == 'OneToOne' || field.type == 'PolymorphicOneToOne')

related = collection.datasource.get_collection(field.foreign_collection)
related = @child_collection.datasource.get_collection(field.foreign_collection)

related.schema[:fields].each do |sub_name, sub_field|
fields.push(["#{name}:#{sub_name}", sub_field]) if sub_field.type == 'Column'
fields.push(["#{name}:#{sub_name}", sub_field]) if sub_field.type == 'Column' &&
searchable_field?(sub_field)
end
end

fields
end

def searchable_field?(field)
operators = field.filter_operators

if field.column_type == PrimitiveType::STRING
return operators&.include?(Operators::EQUAL) ||
operators&.include?(Operators::CONTAINS) ||
operators&.include?(Operators::I_CONTAINS)
end

[PrimitiveType::UUID, PrimitiveType::ENUM, PrimitiveType::NUMBER].include?(field.column_type) &&
operators&.include?(Operators::EQUAL)
end

def lenient_find(haystack, needle)
haystack&.find { |v| v == needle.strip } || haystack&.find { |v| v.downcase == needle.downcase.strip }
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module ForestAdminDatasourceCustomizer
module Decorators
module Search
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
include ForestAdminDatasourceToolkit::Components::Query
include ForestAdminDatasourceToolkit::Schema

Expand Down Expand Up @@ -70,11 +71,30 @@ module Search

context 'when refine_schema' do
it 'sets the schema searchable' do
collection = instance_double(ForestAdminDatasourceToolkit::Collection)
collection = collection_build(
schema: {
fields: { 'foo' => column_build(filter_operators: [Operators::EQUAL]) }
}
)
search_collection_decorator = described_class.new(collection, datasource)
unsearchable_schema = { searchable: false }
expect(search_collection_decorator.refine_schema(unsearchable_schema)).to eq({ searchable: true })
end

context 'when disable search' do
it 'sets the schema not searchable' do
collection = collection_build(
schema: {
fields: { 'foo' => column_build(filter_operators: [Operators::EQUAL]) }
}
)
search_collection_decorator = described_class.new(collection, datasource)
unsearchable_schema = { searchable: true }
expect(search_collection_decorator.refine_schema(unsearchable_schema)).to eq({ searchable: true })
search_collection_decorator.disable_search
expect(search_collection_decorator.refine_schema(unsearchable_schema)).to eq({ searchable: false })
end
end
end

context 'when refine_filter' do
Expand All @@ -98,7 +118,11 @@ module Search

context 'when the search value is null' do
it 'returns the given filter to return all records' do
collection = instance_double(ForestAdminDatasourceToolkit::Collection)
collection = collection_build(
schema: {
fields: { 'foo' => column_build(filter_operators: [Operators::EQUAL]) }
}
)
search_collection_decorator = described_class.new(collection, datasource)
filter = Filter.new(search: nil)
expect(search_collection_decorator.refine_filter(nil, filter).to_h).to eq(filter.to_h)
Expand All @@ -121,6 +145,7 @@ module Search
ForestAdminDatasourceToolkit::Collection,
name: 'foo',
schema: {
fields: { 'foo' => column_build(filter_operators: [Operators::EQUAL]) },
searchable: true
}
)
Expand All @@ -140,7 +165,7 @@ module Search
ForestAdminDatasourceToolkit::Collection,
name: 'foo',
schema: {
fields: { id: ColumnSchema.new(column_type: 'Number', is_primary_key: true) }
fields: { id: numeric_primary_key_build }
}
)
filter = Filter.new(search: 'something')
Expand All @@ -166,6 +191,7 @@ module Search
ForestAdminDatasourceToolkit::Collection,
name: 'foo',
schema: {
fields: { 'foo' => column_build(filter_operators: [Operators::EQUAL]) },
searchable: false
}
)
Expand All @@ -188,19 +214,19 @@ module Search
fields: {
'fieldName' => ColumnSchema.new(
column_type: 'String',
filter_operators: [ConditionTree::Operators::I_CONTAINS]
filter_operators: [Operators::I_CONTAINS]
)
}
}
)

filter = Filter.new(
search: 'a text',
condition_tree: ConditionTree::Nodes::ConditionTreeBranch.new(
condition_tree: Nodes::ConditionTreeBranch.new(
'And',
[
ConditionTree::Nodes::ConditionTreeLeaf.new('aFieldName', ConditionTree::Operators::EQUAL,
'fieldValue')
Nodes::ConditionTreeLeaf.new('aFieldName', Operators::EQUAL,
'fieldValue')
]
)
)
Expand All @@ -213,9 +239,9 @@ module Search
condition_tree: have_attributes(
aggregator: 'And',
conditions: [
have_attributes(field: 'aFieldName', operator: ConditionTree::Operators::EQUAL,
have_attributes(field: 'aFieldName', operator: Operators::EQUAL,
value: 'fieldValue'),
have_attributes(field: 'fieldName', operator: ConditionTree::Operators::I_CONTAINS,
have_attributes(field: 'fieldName', operator: Operators::I_CONTAINS,
value: 'a text')
]
)
Expand Down Expand Up @@ -442,9 +468,9 @@ module Search
schema: {
searchable: false,
fields: {
'fieldName' => ColumnSchema.new(
column_type: 'Enum'
# enum values is not defined
'fieldName' => column_build(
column_type: 'Enum',
filter_operators: [Operators::EQUAL]
)
}
}
Expand Down Expand Up @@ -484,7 +510,7 @@ module Search
refined_filter = search_collection_decorator.refine_filter(caller, filter)
expect(refined_filter).to have_attributes(
search: nil,
condition_tree: have_attributes(aggregator: 'Or', conditions: [])
condition_tree: nil
)
end
end
Expand All @@ -500,11 +526,11 @@ module Search
fields: {
'numberField1' => ColumnSchema.new(
column_type: 'Number',
filter_operators: [ConditionTree::Operators::EQUAL]
filter_operators: [Operators::EQUAL]
),
'numberField2' => ColumnSchema.new(
column_type: 'Number',
filter_operators: [ConditionTree::Operators::EQUAL]
filter_operators: [Operators::EQUAL]
),
'fieldNotReturned' => ColumnSchema.new(column_type: 'Uuid')
}
Expand All @@ -521,8 +547,8 @@ module Search
condition_tree: have_attributes(
aggregator: 'Or',
conditions: [
have_attributes(field: 'numberField1', operator: ConditionTree::Operators::EQUAL, value: 1584),
have_attributes(field: 'numberField2', operator: ConditionTree::Operators::EQUAL, value: 1584)
have_attributes(field: 'numberField1', operator: Operators::EQUAL, value: 1584),
have_attributes(field: 'numberField2', operator: Operators::EQUAL, value: 1584)
]
)
)
Expand All @@ -539,7 +565,7 @@ module Search
'id' => ColumnSchema.new(
column_type: 'Uuid',
is_primary_key: true,
filter_operators: [ConditionTree::Operators::EQUAL]
filter_operators: [Operators::EQUAL]
),
'my_persons' => Relations::OneToOneSchema.new(
origin_key: 'person_id',
Expand All @@ -563,12 +589,12 @@ module Search
'book_id' => ColumnSchema.new(
column_type: 'Uuid',
is_primary_key: true,
filter_operators: [ConditionTree::Operators::EQUAL]
filter_operators: [Operators::EQUAL]
),
'person_id' => ColumnSchema.new(
column_type: 'Uuid',
is_primary_key: true,
filter_operators: [ConditionTree::Operators::EQUAL]
filter_operators: [Operators::EQUAL]
)
}
)
Expand All @@ -582,7 +608,7 @@ module Search
'id' => ColumnSchema.new(
column_type: 'Uuid',
is_primary_key: true,
filter_operators: [ConditionTree::Operators::EQUAL]
filter_operators: [Operators::EQUAL]
)
}
)
Expand All @@ -605,13 +631,13 @@ module Search
condition_tree: have_attributes(
aggregator: 'Or',
conditions: [
have_attributes(field: 'id', operator: ConditionTree::Operators::EQUAL,
have_attributes(field: 'id', operator: Operators::EQUAL,
value: '2d162303-78bf-599e-b197-93590ac3d315'),
have_attributes(field: 'my_persons:id', operator: ConditionTree::Operators::EQUAL,
have_attributes(field: 'my_persons:id', operator: Operators::EQUAL,
value: '2d162303-78bf-599e-b197-93590ac3d315'),
have_attributes(field: 'my_book_persons:book_id', operator: ConditionTree::Operators::EQUAL,
have_attributes(field: 'my_book_persons:book_id', operator: Operators::EQUAL,
value: '2d162303-78bf-599e-b197-93590ac3d315'),
have_attributes(field: 'my_book_persons:person_id', operator: ConditionTree::Operators::EQUAL,
have_attributes(field: 'my_book_persons:person_id', operator: Operators::EQUAL,
value: '2d162303-78bf-599e-b197-93590ac3d315')
]
)
Expand Down

0 comments on commit 96824b7

Please sign in to comment.