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