lib/activefacts/cql/compiler.rb in activefacts-0.8.5 vs lib/activefacts/cql/compiler.rb in activefacts-0.8.6
- old
+ new
@@ -67,11 +67,11 @@
def context
@context ||= Context.new(self)
end
private
- def value_type(name, base_type_name, parameters, unit, ranges, mapping_pragmas)
+ def value_type(name, base_type_name, parameters, unit, ranges, mapping_pragmas, enforcement)
length, scale = *parameters
# Create the base type:
base_type = nil
if (base_type_name != name)
@@ -89,27 +89,33 @@
vt.scale = scale if scale
# REVISIT: Find and apply the units
if ranges.size != 0
- vt.value_restriction = value_restriction ranges
+ vt.value_restriction = value_restriction(ranges, enforcement)
end
end
- def value_restriction(ranges)
+ def value_restriction(ranges, enforcement)
vr = @constellation.ValueRestriction(:new)
ranges.each do |range|
min, max = Array === range ? range : [range, range]
v_range = @constellation.ValueRange(
min ? [[String === min ? eval(min) : min.to_s, String === min, nil], true] : nil,
max ? [[String === max ? eval(max) : max.to_s, String === max, nil], true] : nil
)
ar = @constellation.AllowedRange(vr, v_range)
end
+ apply_enforcement(vr, enforcement) if enforcement
vr
end
+ def apply_enforcement(constraint, enforcement)
+ constraint.enforcement = enforcement[0]
+ constraint.enforcement.agent = enforcement[1] if enforcement[1]
+ end
+
def entity_type(name, supertypes, identification, mapping_pragmas, clauses)
#puts "Entity Type #{name}, supertypes #{supertypes.inspect}, id #{identification.inspect}, clauses = #{clauses.inspect}"
debug :entity, "Defining Entity Type #{name}" do
# Assert the entity:
# If this entity was forward referenced, this won't be a new object, and will subsume its roles
@@ -137,11 +143,11 @@
vt.scale = scale if scale
end
end
# REVISIT: If we do this, it gets emitted twice when we generate CQL. The generator should detect that the restriction is the same and not emit it.
#if (ranges = identification[:restriction])
- # vt.value_restriction = value_restriction(ranges)
+ # vt.value_restriction = value_restriction(ranges, identification[:enforcement])
#end
end
# Use a two-pass algorithm for entity fact types...
# The first step is to find all role references and definitions in the clauses
@@ -267,11 +273,11 @@
debug :mode, "Creating new fact type to identify #{name}"
end
# REVISIT: The restriction applies only to the value role. There is good reason to apply it above to the value type as well.
if (ranges = identification[:restriction])
- value_role.role_value_restriction = value_restriction(ranges)
+ value_role.role_value_restriction = value_restriction(ranges, identification[:enforcement])
end
# Forward reading, if it doesn't already exist:
rss = entity_role.all_role_ref.map{|rr| rr.role_sequence.all_role_ref.size == 2 ? rr.role_sequence : nil }.compact
# Find or create RoleSequences for the forward and reverse readings:
@@ -313,14 +319,13 @@
else
rs0 = rs0.role_sequence
debug :mode, "Using existing EntityType role sequence"
end
if (rs0.all_presence_constraint.size == 0)
- @constellation.PresenceConstraint(
+ constraint = @constellation.PresenceConstraint(
:new,
:name => '',
- :enforcement => '',
:vocabulary => @vocabulary,
:role_sequence => rs0,
:min_frequency => 1,
:max_frequency => 1,
:is_preferred_identifier => false,
@@ -342,14 +347,13 @@
else
rs1 = rs1.role_sequence
debug :mode, "Using existing ValueType role sequence"
end
if (rs1.all_presence_constraint.size == 0)
- @constellation.PresenceConstraint(
+ constraint = @constellation.PresenceConstraint(
:new,
:name => '',
- :enforcement => '',
:vocabulary => @vocabulary,
:role_sequence => rs1,
:min_frequency => 0,
:max_frequency => 1,
:is_preferred_identifier => true,
@@ -868,11 +872,11 @@
end
role_sequences
end
- def presence_constraint(constrained_role_names, quantifier, phrases_list, context)
+ def presence_constraint(constrained_role_names, quantifier, phrases_list, context, enforcement)
raise "REVISIT: Join presence constraints not supported yet" if phrases_list[0].size > 1
phrases_list = phrases_list.map{|r| r[0] }
#p phrases_list
@symbols = SymbolTable.new(@constellation, @vocabulary)
@@ -927,57 +931,58 @@
end
#puts "New external PresenceConstraint with quantifier = #{quantifier.inspect} over #{rs.describe}"
# REVISIT: Check that no existing PC spans the same roles (nor a superset nor subset?)
- @constellation.PresenceConstraint(
+ constraint = @constellation.PresenceConstraint(
:new,
:name => '',
- :enforcement => '',
:vocabulary => @vocabulary,
:role_sequence => rs,
:min_frequency => quantifier[0],
:max_frequency => quantifier[1],
:is_preferred_identifier => false,
:is_mandatory => quantifier[0] && quantifier[0] > 0
)
+ apply_enforcement(constraint, enforcement) if enforcement
end
- def set_constraint(constrained_roles, quantifier, joins_list, context)
+ def set_constraint(constrained_roles, quantifier, joins_list, context, enforcement)
role_sequences = bind_joins_as_role_sequences(joins_list)
if quantifier[1] == nil
# create a presence constraint instead if we get quantifier = [N,nil] (at least N)
# We massage the bound role sequences to make this work.
raise "either/or constraint must have one common role" if role_sequences.size != 2 || role_sequences[0].all_role_ref.size != 1
second_role = role_sequences[1].all_role_ref.single.role
second_role_ref = @constellation.RoleRef(:role_sequence => role_sequences[0], :ordinal => 1, :role => second_role)
@constellation.deny(role_sequences[1].all_role_ref.single)
@constellation.deny(role_sequences[1])
- @constellation.PresenceConstraint(
+ constraint = @constellation.PresenceConstraint(
:new,
:name => '',
- :enforcement => '',
:vocabulary => @vocabulary,
:role_sequence => role_sequences[0],
:min_frequency => quantifier[0],
:max_frequency => nil,
:is_preferred_identifier => false,
:is_mandatory => true
)
+ apply_enforcement(constraint, enforcement) if enforcement
else
# Create a normal (mandatory) exclusion constraint:
constraint = @constellation.SetExclusionConstraint(:new)
constraint.vocabulary = @vocabulary
role_sequences.each_with_index do |rs, i|
@constellation.SetComparisonRoles(constraint, i, :role_sequence => rs)
end
+ apply_enforcement(constraint, enforcement) if enforcement
constraint.is_mandatory = quantifier[0] == 1
end
end
- def subset_constraint(joins_list, context)
+ def subset_constraint(joins_list, context, enforcement)
role_sequences = bind_joins_as_role_sequences(joins_list)
#puts "subset_constraint:\n\t#{subset_readings.inspect}\n\t#{superset_readings.inspect}"
#puts "\t#{role_sequences.map{|rs| rs.describe}.inspect}"
#puts "subset_role_sequence = #{role_sequences[0].describe}"
@@ -988,23 +993,25 @@
constraint.vocabulary = @vocabulary
#constraint.name = nil
#constraint.enforcement =
constraint.subset_role_sequence = role_sequences[0]
constraint.superset_role_sequence = role_sequences[1]
+ apply_enforcement(constraint, enforcement) if enforcement
end
- def equality_constraint(joins_list, context)
- #puts "REVISIT: equality\n\t#{joins_list.map{|rl| rl.inspect}*"\n\tif and only if\n\t"}"
+ def equality_constraint(joins_list, context, enforcement)
+ #puts "equality\n\t#{joins_list.map{|rl| rl.inspect}*"\n\tif and only if\n\t"}"
role_sequences = bind_joins_as_role_sequences(joins_list)
# Create the constraint:
constraint = @constellation.SetEqualityConstraint(:new)
constraint.vocabulary = @vocabulary
role_sequences.each_with_index do |rs, i|
@constellation.SetComparisonRoles(constraint, i, :role_sequence => rs)
end
+ apply_enforcement(constraint, enforcement) if enforcement
end
# Search the supertypes of 'subtype' looking for an inheritance path to 'supertype',
# and returning the array of TypeInheritance fact types from supertype to subtype.
def inheritance_path(subtype, supertype)
@@ -1193,10 +1200,10 @@
player = role.concept
end
# Save a role value restriction
if (ranges = role_phrase[:restriction])
- role.role_value_restriction = value_restriction(ranges)
+ role.role_value_restriction = value_restriction(ranges, role_phrase[:restriction_enforcement])
end
roles << role
# Create the RoleRefs for the RoleSequence