diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cddb272 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**/.vscode diff --git a/orm-rel-generator/example/event_registration.orm b/orm-rel-generator/example/event_registration.orm index 1802923..43f94aa 100644 --- a/orm-rel-generator/example/event_registration.orm +++ b/orm-rel-generator/example/event_registration.orm @@ -15,6 +15,7 @@ + @@ -61,7 +62,7 @@ - + @@ -98,6 +99,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -280,7 +302,7 @@ - + @@ -296,9 +318,9 @@ - {0} "presents at" {1} at {2} + {0} presents at {1} at {2} - + @@ -314,7 +336,7 @@ - + @@ -359,7 +381,7 @@ - + @@ -404,7 +426,7 @@ - + @@ -659,6 +681,186 @@ + + + + + + + + + + + + + + {0} has {1} + + + + + + + + + + + + + + {0} is of {1} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0} lives at {1} + + + + + + + + + + + + + + {0} has tenant- {1} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0} is involved in {1} + + + + + + + + + + + + + + {0} involves {1} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0} is involved in {1} + + + + + + + + + + + + + + {0} involves {1} + + + + + + + + + + + + + + + + + @@ -918,6 +1120,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -936,29 +1198,29 @@ - + - + - + - + - + - + - + @@ -992,6 +1254,21 @@ + + + + + + + + + + + + + + + @@ -1053,12 +1330,123 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orm-rel-generator/example/run-example.jl b/orm-rel-generator/example/run-example.jl index 6e752d8..0199496 100644 --- a/orm-rel-generator/example/run-example.jl +++ b/orm-rel-generator/example/run-example.jl @@ -3,8 +3,10 @@ project_root = "$(@__DIR__)/.." include("$project_root/julia/code_gen.jl") function run_example() - generate("$project_root/example/event_registration.orm", - "$project_root/example/output") + generate("/Users/mbur/git/ey-forms/modeling/1065-fed-2020.orm","/Users/mbur/temp/") + + # generate("$project_root/example/event_registration.orm", + # "$project_root/example/output") end run_example() diff --git a/orm-rel-generator/julia/code_gen.jl b/orm-rel-generator/julia/code_gen.jl index f1a1e6b..ffc5930 100644 --- a/orm-rel-generator/julia/code_gen.jl +++ b/orm-rel-generator/julia/code_gen.jl @@ -9,8 +9,7 @@ import Pkg -# Pkg.activate((ENV["ORM_REL_GENERATOR"])) -Pkg.activate((".")) +Pkg.activate((ENV["ORM_REL_GENERATOR"])) using EzXML @@ -137,10 +136,15 @@ function user_named_relations_for(ft, M)::Vector{Predicate} else key_uc = uc_that_excludes_role_in_fact_type(role, ft, M) if key_uc === nothing - println("[Warning]: Cannot generate relation for role with name " * - role_name * - " in fact type " * fact_name(ft) * - " because model lacks a non-spanning UC that excludes this role.") + # only print warning if it is not a unary fact type + # in which case there is always a second implicit boolean role player + rids = extract_role_ids(ft) + if !is_implicit_boolean(rids[1], M) & !is_implicit_boolean(rids[2], M) + println("[Warning]: Cannot generate relation for role with name " * + role_name * + " in fact type " * fact_name(ft) * + " because model lacks a non-spanning UC that excludes this role.") + end else roles = extract_role_ids_from_simple(key_uc) rel = Predicate(role_name, id(key_uc), roles, id(role)) @@ -184,6 +188,16 @@ function rel_mandatory_constraint(mc_id, rel, M)::IC Implication(RelAtom(role_player, var), atom)) end +""" +Given an ORM unary fact ft, a Rel predicate rel, + and a model M, construct a Rel subset constraint. +""" +function rel_subset_constraint(ft, rel, M)::Clause + constraint_name = "$(rel.relname)_subset" + r_id = extract_role_ids(ft)[1] + IC(constraint_name, Implication(RelAtom(rel,"v"), RelAtom(rel_type_of_role_player(r_id, M),"v"))) +end + """ Given an ORM uniqueness constraint id uc_id, a Rel predicate rel, and a model M, construct a Rel many-to-one constraint. @@ -244,7 +258,10 @@ function rel_constraints_for(ft, M)::Vector{Clause} else for rel in relations_for_non_refmode(ft, M) push!(relations, rel) - if size(rel.value_role_seq)[1] > 0 + # Separate if for unary facts + if is_implicit_boolean(rel.value_role_seq[1], M) & size(rel.key_role_seq)[1] == 1 + push!(constraints, rel_subset_constraint(ft, rel, M)) + elseif size(rel.value_role_seq)[1] + size(rel.key_role_seq)[1] > 0 # Then there must be at least one non-spanning UC for uc_id in extract_uc_ids_of(ft) push!(constraints, rel_many_one_constraint(uc_id, rel, M)) @@ -253,7 +270,10 @@ function rel_constraints_for(ft, M)::Vector{Clause} end end for rel in relations - push!(constraints, rel_type_constraint(rel, M)) + # Exclude unary facts + if !(is_implicit_boolean(rel.value_role_seq[1], M) & size(rel.key_role_seq)[1] == 1) + push!(constraints, rel_type_constraint(rel, M)) + end for mc_id in extract_mc_ids_of(ft) push!(constraints, rel_mandatory_constraint(mc_id, rel, M)) end @@ -323,7 +343,10 @@ function generate(orm_model::String, output_folder::String) concept === nothing && continue filename = lowercase(name(concept)) * "_schema.rel" - open("$output_folder/$filename", "w") do io + # Instead of opening a file for writing, + # use the line below for debugging purposes from vscode + let io = Base.stdout + # open("$output_folder/$filename", "w") do io println(io) println(io, "// Constraints for the '" * name(concept) * "' concept and its subtypes") concept_constraints = Clause[] @@ -340,7 +363,7 @@ function generate(orm_model::String, output_folder::String) end for ft in fact_types println(io) - println(io, "// Constraints for relations modeled by the '" * name(concept) * "' fact type") + println(io, "// Constraints for relations modeled by the '" * fact_name(ft) * "' fact type") for ft_constraint in rel_constraints_for(ft, M) println(io, emit(ft_constraint)) end diff --git a/orm-rel-generator/julia/orm_api.jl b/orm-rel-generator/julia/orm_api.jl index 4a27a8b..ad8c274 100644 --- a/orm-rel-generator/julia/orm_api.jl +++ b/orm-rel-generator/julia/orm_api.jl @@ -68,7 +68,7 @@ Given a diagram D that should depict a central concept """ function central_concept(D, M) - concept_name_pattern = Regex("(?[^(:| )]+):concept") + concept_name_pattern = Regex("^(?[^(:| )]+)(?:.*):concept") concept_match = match(concept_name_pattern, name(D)) if concept_match !== nothing @@ -240,6 +240,19 @@ function has_named_roles(ft)::Bool return false end +""" +Check whether the role is played by an implicit boolean value type, which is +used in the case of unary fact types +""" +function is_implicit_boolean(r_id, M) + player = role_player_by_id(r_id,M) + key = "IsImplicitBooleanValue" + if haskey(player, key) + return player[key] == "true" + end + return false +end + """ Check whether the model element is drawn on diagram D """