-module(prequel@internals@checker). -compile([no_auto_import, nowarn_unused_vars]). -export([check_module/1]). -spec gather_errors( list(fun((prequel@ast:module_()) -> list(prequel@error@validation_error:validation_error()))), prequel@ast:module_() ) -> list(prequel@error@validation_error:validation_error()). gather_errors(Validation_steps, Module) -> gleam@list:flat_map(Validation_steps, fun(Validate) -> Validate(Module) end). -spec cardinality_from_attribute(prequel@ast:attribute()) -> prequel@ast:cardinality(). cardinality_from_attribute(Attribute) -> erlang:element(4, Attribute). -spec cardinalities_from_relationship(prequel@ast:relationship()) -> list({prequel@span:span(), prequel@ast:cardinality()}). cardinalities_from_relationship(Relationship) -> {relationship, Span, _, Entity, Entities, Attributes} = Relationship, Inner_entities = [Entity | non_empty_list:to_list(Entities)], Cardinality_from_inner_entities = fun(Entity@1) -> erlang:element(4, Entity@1) end, _pipe = [gleam@list:map(Attributes, fun cardinality_from_attribute/1), gleam@list:map(Inner_entities, Cardinality_from_inner_entities)], _pipe@1 = gleam@list:concat(_pipe), gleam@list:map(_pipe@1, fun(Cardinality) -> {Span, Cardinality} end). -spec cardinalities_from_entity(prequel@ast:entity()) -> list({prequel@span:span(), prequel@ast:cardinality()}). cardinalities_from_entity(Entity) -> {entity, Span, _, _, Attributes, Inner_relationships, Children} = Entity, Inner_relationship_cardinalities = gleam@list:flat_map( Inner_relationships, fun cardinalities_from_relationship/1 ), Children_cardinalities = case Children of none -> []; {some, {hierarchy, _, _, _, Children@1}} -> _pipe = non_empty_list:to_list(Children@1), gleam@list:flat_map(_pipe, fun cardinalities_from_entity/1) end, _pipe@1 = [gleam@list:map(Attributes, fun cardinality_from_attribute/1)], _pipe@2 = gleam@list:concat(_pipe@1), _pipe@3 = gleam@list:map( _pipe@2, fun(Cardinality) -> {Span, Cardinality} end ), _pipe@4 = gleam@list:append(_pipe@3, Inner_relationship_cardinalities), gleam@list:append(_pipe@4, Children_cardinalities). -spec cardinalities_from_module(prequel@ast:module_()) -> list({prequel@span:span(), prequel@ast:cardinality()}). cardinalities_from_module(Module) -> _pipe = [gleam@list:flat_map( erlang:element(2, Module), fun cardinalities_from_entity/1 ), gleam@list:flat_map( erlang:element(3, Module), fun cardinalities_from_relationship/1 )], gleam@list:concat(_pipe). -spec cardinality_has_valid_bounds(prequel@ast:cardinality()) -> boolean(). cardinality_has_valid_bounds(Cardinality) -> case Cardinality of {bounded, _, Lower_bound, Upper_bound} when Lower_bound > Upper_bound -> false; {unbounded, _, _} -> true; {bounded, _, _, _} -> true end. -spec check_cardinality_bounds(prequel@span:span(), prequel@ast:cardinality()) -> gleam@option:option(prequel@error@validation_error:validation_error()). check_cardinality_bounds(Enclosing_definition, Cardinality) -> case cardinality_has_valid_bounds(Cardinality) of true -> none; false -> {some, {lower_bound_greater_than_upper_bound, {some, <<"TODO: add hint"/utf8>>}, Enclosing_definition, Cardinality}} end. -spec check_cardinalities_bounds(prequel@ast:module_()) -> list(prequel@error@validation_error:validation_error()). check_cardinalities_bounds(Module) -> _pipe = cardinalities_from_module(Module), _pipe@1 = prequel@internals@extra@list:map_pairs( _pipe, fun check_cardinality_bounds/2 ), gleam@option:values(_pipe@1). -spec entities_from_entity(prequel@ast:entity()) -> list(prequel@ast:entity()). entities_from_entity(Entity) -> case erlang:element(7, Entity) of none -> []; {some, Hierarchy} -> Children = non_empty_list:to_list(erlang:element(5, Hierarchy)), _pipe = gleam@list:flat_map(Children, fun entities_from_entity/1), gleam@list:append(_pipe, Children) end. -spec entities_from_module(prequel@ast:module_()) -> list(prequel@ast:entity()). entities_from_module(Module) -> Top_level_entities = erlang:element(2, Module), Sub_entities = gleam@list:flat_map( Top_level_entities, fun entities_from_entity/1 ), gleam@list:append(Top_level_entities, Sub_entities). -spec to_duplicate_entity_error( prequel@ast:entity(), non_empty_list:non_empty_list(prequel@ast:entity()) ) -> prequel@error@validation_error:validation_error(). to_duplicate_entity_error(First_entity, Other_entities) -> _assert_subject = gleam@list:sort( [First_entity, erlang:element(2, Other_entities)], fun(One, Other) -> gleam@int:compare( erlang:element(2, erlang:element(2, One)), erlang:element(2, erlang:element(2, Other)) ) end ), [First, Other@1] = case _assert_subject of [_, _] -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"prequel/internals/checker"/utf8>>, function => <<"to_duplicate_entity_error"/utf8>>, line => 162}) end, {duplicate_entity_name, {some, <<"TODO: add hint"/utf8>>}, First, Other@1}. -spec check_all_entities_have_different_names(prequel@ast:module_()) -> list(prequel@error@validation_error:validation_error()). check_all_entities_have_different_names(Module) -> _pipe = entities_from_module(Module), _pipe@1 = prequel@internals@extra@list:duplicates( _pipe, fun(Entity) -> erlang:element(3, Entity) end ), prequel@internals@extra@list:map_pairs( _pipe@1, fun to_duplicate_entity_error/2 ). -spec relationships_from_entity(prequel@ast:entity()) -> list(prequel@ast:relationship()). relationships_from_entity(Entity) -> Sub_relationships = case erlang:element(7, Entity) of {some, Hierarchy} -> _pipe = non_empty_list:to_list(erlang:element(5, Hierarchy)), gleam@list:flat_map(_pipe, fun relationships_from_entity/1); none -> [] end, gleam@list:append(erlang:element(6, Entity), Sub_relationships). -spec relationships_from_module(prequel@ast:module_()) -> list(prequel@ast:relationship()). relationships_from_module(Module) -> Top_level_relationships = erlang:element(3, Module), All_entities = entities_from_module(Module), Inner_relationships = gleam@list:flat_map( All_entities, fun relationships_from_entity/1 ), gleam@list:append(Top_level_relationships, Inner_relationships). -spec to_duplicate_relationship_error( prequel@ast:relationship(), non_empty_list:non_empty_list(prequel@ast:relationship()) ) -> prequel@error@validation_error:validation_error(). to_duplicate_relationship_error(First_relationship, Other_relationships) -> _assert_subject = gleam@list:sort( [First_relationship, erlang:element(2, Other_relationships)], fun(One, Other) -> gleam@int:compare( erlang:element(2, erlang:element(2, One)), erlang:element(2, erlang:element(2, Other)) ) end ), [First, Other@1] = case _assert_subject of [_, _] -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"prequel/internals/checker"/utf8>>, function => <<"to_duplicate_relationship_error"/utf8>>, line => 209}) end, {duplicate_relationship_name, {some, <<"TODO: add hint"/utf8>>}, First, Other@1}. -spec check_all_relationships_have_different_names(prequel@ast:module_()) -> list(prequel@error@validation_error:validation_error()). check_all_relationships_have_different_names(Module) -> _pipe = relationships_from_module(Module), _pipe@1 = prequel@internals@extra@list:duplicates( _pipe, fun(Relationship) -> erlang:element(3, Relationship) end ), prequel@internals@extra@list:map_pairs( _pipe@1, fun to_duplicate_relationship_error/2 ). -spec check_module(prequel@ast:module_()) -> list(prequel@error@validation_error:validation_error()). check_module(Module) -> _pipe = [fun check_cardinalities_bounds/1, fun check_all_entities_have_different_names/1, fun check_all_relationships_have_different_names/1], gather_errors(_pipe, Module).