From e046194f375c517fd7e8a22c5cddcfcd509926a7 Mon Sep 17 00:00:00 2001 From: Muhammad Nawzad Date: Sun, 12 Nov 2023 10:07:05 +0300 Subject: [PATCH] Adds included schema generator --- lib/schemable/included_schema_generator.rb | 72 +++++++++++++++++++++ sig/schemable/included_schema_generator.rbs | 16 +++++ 2 files changed, 88 insertions(+) create mode 100644 lib/schemable/included_schema_generator.rb create mode 100644 sig/schemable/included_schema_generator.rbs diff --git a/lib/schemable/included_schema_generator.rb b/lib/schemable/included_schema_generator.rb new file mode 100644 index 0000000..8bc6997 --- /dev/null +++ b/lib/schemable/included_schema_generator.rb @@ -0,0 +1,72 @@ +module Schemable + class IncludedSchemaGenerator + attr_accessor :model_definition, :schema_modifier, :configuration, :relationships, :expand, :relationships_to_exclude_from_expansion + + def initialize(model_definition, relationships_to_exclude_from_expansion: [], expand: false) + @expand = expand + @model_definition = model_definition + @schema_modifier = SchemaModifier.new + @configuration = Schemable.configuration + @relationships = @model_definition.relationships + @relationships_to_exclude_from_expansion = relationships_to_exclude_from_expansion + end + + def prepare_schema_for_included(model_definition, expand: false, relationships_to_exclude_from_expansion: []) + attributes_schema = AttributeSchemaGenerator.new(model_definition).generate_attributes_schema + relationships_schema = RelationshipSchemaGenerator.new(model_definition, relationships_to_exclude_from_expansion:, expand:) + + { + type: :object, + properties: { + type: { type: :string, default: model_definition.model_name }, + id: { type: :string }, + attributes: attributes_schema, + relationships: relationships_schema ? {} : relationships_schema + } + }.compact_blank + end + + def generate(expand: false, relationships_to_exclude_from_expansion: []) + return {} if @relationships.blank? + return {} if @relationships == { belongs_to: {}, has_many: {} } + + definitions = [] + + %i[belongs_to has_many addition_to_included].each do |relation_type| + next if @relationships[relation_type].blank? + + definitions << @relationships[relation_type].values + end + + definitions.flatten! + definition_names = definitions.map(&:model_name) + + included_schemas = definitions.map do |definition| + if expand && relationships_to_exclude_from_expansion.exclude?(definition.model_name) + definition_relations = definition.relationships[:belongs_to].keys.map(&:to_s) + definition.relationships[:has_many].keys.map(&:to_s) + relations_to_exclude = [] + definition_relations.each do |relation| + relations_to_exclude << relation if definition_names.exclude?(relation) + end + + prepare_schema_for_included(definition, expand:, relationships_to_exclude_from_expansion: relations_to_exclude) + else + prepare_schema_for_included(definition) + end + end + + schema = { + included: { + type: :array, + items: { + anyOf: included_schemas + } + } + } + + @schema_modifier.add_properties(schema, @model_definition.additional_response_included, 'included.items') if @model_definition.additional_response_included.present? + + schema + end + end +end diff --git a/sig/schemable/included_schema_generator.rbs b/sig/schemable/included_schema_generator.rbs new file mode 100644 index 0000000..796b6ea --- /dev/null +++ b/sig/schemable/included_schema_generator.rbs @@ -0,0 +1,16 @@ +module Schemable + class IncludedSchemaGenerator + attr_accessor expand: bool + attr_accessor model_definition: Definition + attr_accessor configuration: Configuration + attr_accessor schema_modifier: SchemaModifier + attr_accessor relationships: Hash[Symbol, any] + attr_accessor relationships_to_exclude_from_expansion: Array[String] + + def initialize: (Definition, ?relationships_to_exclude_from_expansion: Array[String], ?expand: bool) -> void + + def prepare_schema_for_included: (Definition, ?relationships_to_exclude_from_expansion: Array[String], ?expand: bool) -> Hash[Symbol, any] + + def generate: (?relationships_to_exclude_from_expansion: Array[String], ?expand: bool) -> (Hash[Symbol, any] | Array[Hash[Symbol, any]]) + end +end