From 51acf9ad7fed0be005abbcf7981a2a5aebfda462 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 21 Aug 2024 09:23:54 +0200 Subject: [PATCH 1/8] fix: add validation projection fields --- .rubocop.yml | 1 + .../forest_admin_agent/utils/query_string_parser.rb | 5 ++++- .../validations/field_validator.rb | 12 +++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 5478a02ce..55b0163a6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -242,6 +242,7 @@ Metrics/ClassLength: - 'packages/forest_admin_agent/lib/forest_admin_agent/routes/action/actions.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/routes/resources/related/update_related.rb' - 'packages/forest_admin_agent/lib/forest_admin_agent/utils/schema/frontend_validation_utils.rb' + - 'packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb' - 'packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/utils/query.rb' - 'packages/forest_admin_datasource_active_record/lib/forest_admin_datasource_active_record/collection.rb' - 'packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/collection_customizer.rb' diff --git a/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb b/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb index 747f38078..281a7959a 100644 --- a/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb +++ b/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb @@ -69,7 +69,10 @@ def self.parse_projection(collection, args) end end - Projection.new(fields) + projection = Projection.new(fields) + Validations::ProjectionValidator.validate?(collection, projection) + + projection end def self.parse_projection_with_pks(collection, args) diff --git a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb index 6cc120846..07e649b65 100644 --- a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb +++ b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb @@ -22,14 +22,20 @@ def self.validate(collection, field, values = nil) end end else - prefix = field[0, dot_index] + prefix, suffix = field.split(':') schema = collection.schema[:fields][prefix] raise Exceptions::ValidationError, "Relation not found: '#{collection.name}.#{prefix}'" if schema.nil? - if schema.type != 'ManyToOne' && schema.type != 'OneToOne' + if schema.type != 'ManyToOne' && suffix != '*' raise Exceptions::ValidationError, - "Unexpected field type: '#{collection.name}.#{prefix}' (found '#{schema.type}' expected 'ManyToOne' or 'OneToOne')" + "Unexpected nested field #{suffix} under generic relation: #{collection.name}.#{prefix}" + end + + if schema.type != 'ManyToOne' && schema.type != 'OneToOne' && schema.type != 'PolymorphicManyToOne' && + schema.type != 'PolymorphicOneToOne' + raise Exceptions::ValidationError, + "Unexpected field type: '#{collection.name}.#{prefix}' (found '#{schema.type}')" end suffix = field[dot_index + 1, field.length - dot_index - 1] From 79d1738226fbaaed53e93118d765b2d1d2b9b4f7 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 21 Aug 2024 09:25:17 +0200 Subject: [PATCH 2/8] fix: flattener --- .../decorators/computed/utils/flattener.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/computed/utils/flattener.rb b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/computed/utils/flattener.rb index bd17af2fe..add0941ee 100644 --- a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/computed/utils/flattener.rb +++ b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/computed/utils/flattener.rb @@ -31,7 +31,10 @@ def self.with_null_marker(projection) def self.flatten(records, projection) projection.map do |field| - parts = field.split(':') + # because we don't compute computed fields over polymorphic relation (only usage of *), + # we decide to consider the all record as a value instead of a relation + parts = field.split(':').reject { |part| part == '*' } + records.map do |record| value = record @@ -63,7 +66,7 @@ def self.un_flatten(flatten, projection) records[record_index] = {} projection.each_with_index do |path, path_index| - parts = path.split(':').reject { |part| part == MARKER_NAME } + parts = path.split(':').reject { |part| [MARKER_NAME, '*'].include?(part) } value = flatten[path_index][record_index] # Ignore undefined values. From 9b17c73f62e25ff315c289ba43769be9dd059141 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 21 Aug 2024 09:25:39 +0200 Subject: [PATCH 3/8] fix: publication collection decorator --- .../decorators/publication/publication_collection_decorator.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/publication/publication_collection_decorator.rb b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/publication/publication_collection_decorator.rb index 8685b1417..ea03a8f32 100644 --- a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/publication/publication_collection_decorator.rb +++ b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/publication/publication_collection_decorator.rb @@ -70,7 +70,8 @@ def published?(name) ) end - if field.type == 'OneToOne' || field.type == 'OneToMany' + if field.type == 'OneToOne' || field.type == 'OneToMany' || + field.type == 'PolymorphicOneToOne' || field.type == 'PolymorphicOneToMany' return ( datasource.published?(field.foreign_collection) && datasource.get_collection(field.foreign_collection).published?(field.origin_key) && From e31f7a94b10370e4342152cd1d09f8c438dfb99b Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 21 Aug 2024 09:26:13 +0200 Subject: [PATCH 4/8] fix: rename field collection decorator --- .../rename_field/rename_field_collection_decorator.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/rename_field/rename_field_collection_decorator.rb b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/rename_field/rename_field_collection_decorator.rb index 74e331f94..dbfbe40d0 100644 --- a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/rename_field/rename_field_collection_decorator.rb +++ b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/rename_field/rename_field_collection_decorator.rb @@ -52,6 +52,8 @@ def refine_schema(sub_schema) fields = {} schema = sub_schema.dup + # we don't handle schema modification for polymorphic many to one and reverse relations because + # we forbid to rename foreign key and type fields on polymorphic many to one sub_schema[:fields].each do |old_name, old_schema| case old_schema.type when 'ManyToOne' @@ -160,7 +162,11 @@ def path_to_child_collection(path) paths = path.split(':') relation_name = paths[0] relation_schema = schema[:fields][relation_name] - if relation_schema.type != 'PolymorphicManyToOne' + if relation_schema.type == 'PolymorphicManyToOne' + relation_name = to_child_collection[relation_name] + + return "#{relation_name}:#{paths[1]}" + else relation = datasource.get_collection(relation_schema.foreign_collection) child_field = to_child_collection[relation_name] || relation_name @@ -188,7 +194,8 @@ def record_from_child_collection(child_record) field_schema = schema[:fields][field] # Perform the mapping, recurse for relation - if field_schema.type == 'Column' || field_schema.type == 'PolymorphicManyToOne' || value.nil? + if field_schema.type == 'Column' || value.nil? || field_schema.type == 'PolymorphicManyToOne' || + field_schema.type == 'PolymorphicOneToOne' record[field] = value else relation = datasource.get_collection(field_schema.foreign_collection) From dcdb1e6189c1b326287a397ec9711664ee6f383a Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 21 Aug 2024 09:26:35 +0200 Subject: [PATCH 5/8] fix: search collection decorator --- .../decorators/search/search_collection_decorator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/search/search_collection_decorator.rb b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/search/search_collection_decorator.rb index ca60fe2a3..ed32f323e 100644 --- a/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/search/search_collection_decorator.rb +++ b/packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/search/search_collection_decorator.rb @@ -104,7 +104,7 @@ def get_fields(collection, extended) collection.schema[:fields].each do |name, field| fields.push([name, field]) if field.type == 'Column' - if field.type == 'PolymorphicManyToOne' + if field.type == 'PolymorphicManyToOne' && extended ForestAdminAgent::Facades::Container.logger.log( 'Debug', "We're not searching through #{self.name}.#{name} because it's a polymorphic relation. " \ From 97a97531432709fefa185dae36afba74d71539e4 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Wed, 21 Aug 2024 09:26:58 +0200 Subject: [PATCH 6/8] fix: collection utils --- .../lib/forest_admin_datasource_toolkit/utils/collection.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/utils/collection.rb b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/utils/collection.rb index 1f5ac3869..606350154 100644 --- a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/utils/collection.rb +++ b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/utils/collection.rb @@ -14,6 +14,8 @@ def self.get_inverse_relation(collection, relation_name) inverse = foreign_collection.schema[:fields].select do |_name, field| if polymorphic_relations.include?(relation_field.type) field.is_a?(PolymorphicManyToOneSchema) && + field.foreign_key_type_field == relation_field.origin_type_field && + field.foreign_key == relation_field.origin_key && field.foreign_collections.include?(collection.name) else field.is_a?(RelationSchema) && From 22d8ae048191bbf54896c3d120b8c63a2072b341 Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Fri, 23 Aug 2024 15:32:48 +0200 Subject: [PATCH 7/8] test: update field validator test --- .../validations/field_validator.rb | 2 +- .../validations/field_validator_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb index 07e649b65..bbc83dd3f 100644 --- a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb +++ b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb @@ -27,7 +27,7 @@ def self.validate(collection, field, values = nil) raise Exceptions::ValidationError, "Relation not found: '#{collection.name}.#{prefix}'" if schema.nil? - if schema.type != 'ManyToOne' && suffix != '*' + if schema.type == 'PolymorphicManyToOne' && suffix != '*' raise Exceptions::ValidationError, "Unexpected nested field #{suffix} under generic relation: #{collection.name}.#{prefix}" end diff --git a/packages/forest_admin_datasource_toolkit/spec/lib/forest_admin_datasource_toolkit/validations/field_validator_spec.rb b/packages/forest_admin_datasource_toolkit/spec/lib/forest_admin_datasource_toolkit/validations/field_validator_spec.rb index 6f2c273ef..e887cc2a3 100644 --- a/packages/forest_admin_datasource_toolkit/spec/lib/forest_admin_datasource_toolkit/validations/field_validator_spec.rb +++ b/packages/forest_admin_datasource_toolkit/spec/lib/forest_admin_datasource_toolkit/validations/field_validator_spec.rb @@ -77,7 +77,7 @@ module Validations described_class.validate(@collection_cars, 'id:address') end.to raise_error(ValidationError, - "🌳🌳🌳 Unexpected field type: 'cars.id' (found 'Column' expected 'ManyToOne' or 'OneToOne')") + "🌳🌳🌳 Unexpected field type: 'cars.id' (found 'Column')") end end From a45c55484dc69c8de15c28ff0c68b5175ea00c3a Mon Sep 17 00:00:00 2001 From: Nicolas Alexandre Date: Fri, 23 Aug 2024 15:41:20 +0200 Subject: [PATCH 8/8] fix: parse projection --- .../forest_admin_agent/utils/query_string_parser.rb | 2 +- .../validations/field_validator.rb | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb b/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb index 281a7959a..56ca9718a 100644 --- a/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb +++ b/packages/forest_admin_agent/lib/forest_admin_agent/utils/query_string_parser.rb @@ -70,7 +70,7 @@ def self.parse_projection(collection, args) end projection = Projection.new(fields) - Validations::ProjectionValidator.validate?(collection, projection) + ForestAdminDatasourceToolkit::Validations::ProjectionValidator.validate?(collection, projection) projection end diff --git a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb index bbc83dd3f..7cb4d1e5f 100644 --- a/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb +++ b/packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/validations/field_validator.rb @@ -28,8 +28,7 @@ def self.validate(collection, field, values = nil) raise Exceptions::ValidationError, "Relation not found: '#{collection.name}.#{prefix}'" if schema.nil? if schema.type == 'PolymorphicManyToOne' && suffix != '*' - raise Exceptions::ValidationError, - "Unexpected nested field #{suffix} under generic relation: #{collection.name}.#{prefix}" + raise Exceptions::ValidationError, "Unexpected nested field #{suffix} under generic relation: #{collection.name}.#{prefix}" end if schema.type != 'ManyToOne' && schema.type != 'OneToOne' && schema.type != 'PolymorphicManyToOne' && @@ -38,9 +37,11 @@ def self.validate(collection, field, values = nil) "Unexpected field type: '#{collection.name}.#{prefix}' (found '#{schema.type}')" end - suffix = field[dot_index + 1, field.length - dot_index - 1] - association = collection.datasource.get_collection(schema.foreign_collection) - validate(association, suffix, values) + if schema.type != 'PolymorphicManyToOne' + suffix = field[dot_index + 1, field.length - dot_index - 1] + association = collection.datasource.get_collection(schema.foreign_collection) + validate(association, suffix, values) + end end end