%Metamodel A

%(1) All attributes of a data have distint names

attribute_distinct_names:-rdf(Data,mmA:'data.attr_of',Att1),
                        rdf(Data,mmA:'data.attr_of',Att2),
                        Att1\=Att2,
                        rdf(Att1,mmA:'attribute.name',Name1),
                        rdf(Att2,mmA:'attribute.name',Name2),
                        Name1=Name2.
                       
%(2) Each data has a key attribute

exists_key:-setof(Att,(rdf(_,mmA:'data.attr_of',Att),rdf(Att,mmA:'attribute.key',literal(type(_,true)))),Keys),Keys=[].

%(3) Each data has a unique key attribute

unique_key :- rdf(Data,mmA:'data.attr_of',Att1),
            rdf(Data,mmA:'data.attr_of',Att2),
            Att1\=Att2,
            rdf(Att1,mmA:'attribute.key',literal(type(_,true))),
            rdf(Att2,mmA:'attribute.key',literal(type(_,true))).

%(4) Each attribute is associated to exactly one data

unique_data_attribute:-rdf(Att,rdf:type,mmA:attribute),
            rdf(Att,mmA:'attribute.is',Data1),
            rdf(Att,mmA:'attribute.is',Data2),
            Data1\=Data2.


%(5) Each data is contained in exactly one store

unique_store_data:- setof(Store,rdf(_,mmA:'data.contained_in',Store),Stores),Stores=[_,_|_].


%(6) All data have distinct names

unique_name_data :- rdf(Data,mmA:'data.name',Name1),
                    rdf(Data,mmA:'data.name',Name2),
                    Name1\=Name2.

%(7) All data have distinct containers

unique_container_data :-rdf(Data,mmA:'data.container',Container1),
                rdf(Data,mmA:'data.container',Container2),
                Container1\=Container2.


%(8) Each qualifier is associated to exactly one role

unique_role_qualifier :- rdf(Qualifier,mmA:'qualifier.has',Role1),
                        rdf(Qualifier,mmA:'qualifier.has',Role2),
                        Role1\=Role2.

%(9)  All qualifier names of a data are distinct

unique_name_qualifier :- rdf(Qualifier,mmA:'qualifier.name',Name1),
                        rdf(Qualifier,mmA:'qualifier.name',Name2),
                        Name1\=Name2.

%(10) All qualifiers are key attributes

qualifiers_are_keys :- rdf(_,mmA:'qualifier.name',Name),
    \+ (rdf(Attribute,mmA:'attribute.name',Name),rdf(Attribute,mmA:'attribute.key',literal(type(_,true)))).

%(11) Each relation has two roles

two_roles_relation :- setof(Role,rdf(_,mmA:'relation.is_role',Role),Roles),Roles\=[_,_].

%(12) All relation names are distinct

unique_name_relations:-rdf(Relation1,mmA:'relation.name',Name1),
                    rdf(Relation2,mmA:'relation.name',Name2),
                    Relation1\=Relation2,
                    Name1=Name2.

%(13) Each role is associated to exactly one relation

unique_relation_role:-rdf(Role,mmA:'role.has_role',Relation1),
                rdf(Role,mmA:'role.has_role',Relation2),
                Relation1\=Relation2.

%(14) Each role is associated to exactly one data

unique_data_role:-rdf(Role,mmA:'role.isdata',Data1),
            rdf(Role,mmA:'role.isdata',Data2),
            Data1\=Data2.

%(15) All role names of a data are distinct

unique_role_names_data :-rdf(Data,mmA:'data.role_of',Role1),
                rdf(Data,mmA:'data.role_of',Role2),
                rdf(Role1,mmA:'role.name',Name1),
                rdf(Role2,mmA:'role.name',Name2),
                Role1\=Role2,
                Name1=Name2.

%(16) Each store is associated to exactly one data

unique_data_store :- rdf(Store,mmA:'store.contains',Data1),
                    rdf(Store,mmA:'store.contains',Data2),
                    Data1\=Data2.


%Metamodel  B


%(17) All col names of a row are distinct

unique_col_names_row :-rdf(Row,mmB:'row.is_col',Col1),
            rdf(Row,mmB:'row.is_col',Col2),
            Col1\=Col2,
            rdf(Col1,mmB:'col:name',Name1),
            rdf(Col2,mmB:'col:name',Name2),
            Name1=Name2.

%(18) All foreign names of a row are distinct

unique_foreign_names_row :-rdf(Row,mmB:'row.is_foreign',Foreign1),
                rdf(Row,mmB:'row.is_foreign',Foreign2),
                Foreign1\=Foreign2,
                rdf(Foreign1,mmB:'foreign:name',Name1),
                rdf(Foreign2,mmB:'foreign:name',Name2),
                Name1=Name2.

%(19) All key names of a row are distinct

unique_key_names_row :-rdf(Row,mmB:'row.is_key',Key1),
                rdf(Row,mmB:'row.is_key',Key2),
                Key1\=Key2,
                rdf(Key1,mmB:'key:name',Name1),
                rdf(Key2,mmB:'key:name',Name2),
                Name1=Name2.

%(20) All foreigns of a row are keys of another row

foreign_keys:-rdf(R,mmB:'row.is_foreign',A),
            rdf(R,mmB:'row.name',N),
            rdf(A,mmB:'foreign.name',Name),
            N=literal(type(_,RC)),
            Name=literal(type(_,NN)),
            concat(RC,NameKey,NN),
            \+ rdf(_,mmB:'key.name',literal(type(_,NameKey))).

%(21) Each table is associated to exactly one row

unique_table_row :- rdf(Table,mmB:'table.has',Row1),
            rdf(Table,mmB:'table.has',Row2),
            Row1\=Row2.

%(22) Each row is associated to exactly one table

unique_row_table:-rdf(Row,mmB:'row.table',Table1),
            rdf(Row,mmB:'row.table',Table2),
            Table1\=Table2.

%(23) Each key is associated to exactly one row

unique_row_key :- rdf(Key,mmB:'key.has_key',Row1),
            rdf(Key,mmB:'key.has_key',Row2),
            Row1\=Row2.

%(24) Each col is associated to exactly one row

unique_row_col :- rdf(Col,mmB:'col.has_col',Row1),
            rdf(Col,mmB:'col.has_col',Row2),
            Row1\=Row2.

%(25) Each foreign is associated to exactly one row

unique_row_foreign :- rdf(Foreign,mmB:'foreign.has_foreign',Row1),
                rdf(Foreign,mmB:'foreign.has_foreign',Row2),
                Row1\=Row2.

%(26) All table names are distinct

unique_table_names :- rdf(Table1,mmB:'table.name',Name1),
                    rdf(Table2,mmB:'table.name',Name2),
                    Table1\=Table2,
                    Name1=Name2.

%(27) All row names are distinct

unique_row_names :- rdf(Row1,mmB:'row.name',Name1),
                    rdf(Row2,mmB:'row.name',Name2),
                    Row1\=Row2,
                    Name1=Name2.

%(28) All rows have exactly one key

unique_key_row :- rdf(Row,mmB:'row.is_key',Key1),
            rdf(Row,mmB:'row.is_key',Key2),
            Key1\=Key2.

%(29) All rows have either all keys and cols or all foreigns

well_formed_rows:-rdf(Row,mmB:'row.is_key',_),
                    rdf(Row,mmB:'row.is_foreign',_).
well_formed_rows:-rdf(Row,mmB:'row.is_col',_),
                    rdf(Row,mmB:'row.is_foreign',_).


%Transformation

%(30) Key and col names and types are names and types of attributes

names_and_types :- rdf(_,mmB:'key.name',Name),
                    \+rdf(_,mmA:'attribute.name',Name).

names_and_types :- rdf(_,mmB:'key.type',Type),
                    \+rdf(_,mmA:'attribute.type',Type).

names_and_types :- rdf(_,mmB:'col.name',Name),
                    \+rdf(_,mmA:'attribute.name',Name).

names_and_types :- rdf(_,mmB:'col.type',Type),
                    \+rdf(_,mmA:'attribute.type',Type).

%(31) Table names are either container names or role names


containers_or_roles :- rdf(_,mmB:'table.name',Name),
                    \+rdf(_,mmA:'role.name',Name),
                    \+rdf(_,mmA:'data.container',Name).

 
%(32) Row names are data names or concatenations of role names and data

 
data_or_roles_and_data :- rdf(_,mmB:'row.name',Name), Name=literal(type(_,N)),
                    \+ rdf(_,mmA:'data.name',Name),
                    \+     (rdf(_,mmA:'role.name',Name1),
                        rdf(_,mmA:'data.name',Name2),
                        Name1=literal(type(_,N1)),
                        Name2=literal(type(_,N2)),
                        concat(N1,N2,N)).
                   
%(33) Foreign names are concatenations of roles, data and key attributes

foreign_names :- rdf(_,mmB:'foreign.name',Name),Name=literal(type(_,N)),
                \+ (rdf(_,mmA:'role.name',Name1),Name1=literal(type(_,N1)),
                    rdf(_,mmA:'data.name',Name2),Name2=literal(type(_,N2)),
                    rdf(_,mmA:'attribute.name',Name3),Name3=literal(type(_,N3)),
                    rdf(_,mmA:'attribute.key',Key),
                    Key=literal(type(_,true)),
                    concat(N1,N2,NAux),
                    concat(NAux,N3,N)).