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
"""