activefacts 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/Rakefile +2 -2
- data/bin/afgen +1 -1
- data/bin/cql +118 -27
- data/examples/CQL/Insurance.cql +2 -2
- data/examples/CQL/Metamodel.cql +3 -3
- data/examples/CQL/SchoolActivities.cql +1 -1
- data/examples/CQL/Warehousing.cql +5 -4
- data/lib/activefacts/cql.rb +1 -1
- data/lib/activefacts/cql/Language/English.treetop +2 -1
- data/lib/activefacts/cql/compiler.rb +6 -6
- data/lib/activefacts/cql/compiler/clause.rb +69 -46
- data/lib/activefacts/cql/compiler/constraint.rb +14 -14
- data/lib/activefacts/cql/compiler/entity_type.rb +24 -24
- data/lib/activefacts/cql/compiler/fact.rb +40 -27
- data/lib/activefacts/cql/compiler/fact_type.rb +16 -16
- data/lib/activefacts/cql/compiler/query.rb +12 -12
- data/lib/activefacts/cql/compiler/shared.rb +9 -0
- data/lib/activefacts/cql/compiler/value_type.rb +4 -4
- data/lib/activefacts/cql/parser.rb +9 -9
- data/lib/activefacts/generate/cql.rb +41 -20
- data/lib/activefacts/generate/helpers/oo.rb +33 -70
- data/lib/activefacts/generate/helpers/ordered.rb +61 -87
- data/lib/activefacts/generate/ruby.rb +12 -72
- data/lib/activefacts/generate/transform/surrogate.rb +13 -13
- data/lib/activefacts/input/orm.rb +72 -71
- data/lib/activefacts/persistence/columns.rb +66 -31
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +12 -12
- data/lib/activefacts/persistence/object_type.rb +15 -12
- data/lib/activefacts/persistence/reference.rb +20 -18
- data/lib/activefacts/persistence/tables.rb +40 -36
- data/lib/activefacts/support.rb +69 -123
- data/lib/activefacts/version.rb +2 -2
- data/lib/activefacts/vocabulary/extensions.rb +42 -39
- data/lib/activefacts/vocabulary/metamodel.rb +11 -1
- data/lib/activefacts/vocabulary/verbaliser.rb +28 -28
- data/spec/cql/contractions_spec.rb +1 -1
- data/spec/cql/entity_type_spec.rb +1 -1
- data/spec/cql/fact_type_matching_spec.rb +3 -3
- data/spec/cql/role_matching_spec.rb +4 -4
- data/spec/cql/samples_spec.rb +2 -2
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/helpers/array_matcher.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +2 -2
- data/spec/norma_tables_spec.rb +3 -2
- metadata +47 -68
@@ -7,10 +7,12 @@
|
|
7
7
|
require 'activefacts'
|
8
8
|
require 'activefacts/vocabulary'
|
9
9
|
require 'activefacts/generate/helpers/oo'
|
10
|
+
require 'activefacts/generate/traits/ruby'
|
10
11
|
require 'activefacts/mapping/rails'
|
11
12
|
|
12
13
|
module ActiveFacts
|
13
14
|
module Generate
|
15
|
+
|
14
16
|
# Generate Ruby module containing classes for an ActiveFacts vocabulary.
|
15
17
|
# Invoke as
|
16
18
|
# afgen --ruby[=options] <file>.cql
|
@@ -34,20 +36,12 @@ module ActiveFacts
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
def vocabulary_start
|
38
|
-
puts
|
39
|
-
if @mapping
|
40
|
-
require 'activefacts/persistence'
|
41
|
-
end
|
42
|
-
if @mapping == 'sql'
|
43
|
-
puts "require 'activefacts/persistence'\n"
|
44
|
-
@tables = vocabulary.tables
|
45
|
-
end
|
46
|
-
puts "\nmodule ::#{vocabulary.name}\n\n"
|
39
|
+
def vocabulary_start
|
40
|
+
puts @vocabulary.prelude
|
47
41
|
end
|
48
42
|
|
49
43
|
def vocabulary_end
|
50
|
-
puts
|
44
|
+
puts @vocabulary.finale
|
51
45
|
end
|
52
46
|
|
53
47
|
def emit_mapping o
|
@@ -64,23 +58,7 @@ module ActiveFacts
|
|
64
58
|
end
|
65
59
|
|
66
60
|
def value_type_dump(o, super_type_name, facets)
|
67
|
-
|
68
|
-
scale = (s = o.scale) && s > 0 ? ":scale => #{s}" : nil
|
69
|
-
params = [length,scale].compact * ", "
|
70
|
-
|
71
|
-
ruby_type_name = super_type_name.gsub(/ /,'')
|
72
|
-
name = o.name.sub(/^[a-z]/) {|i| i.upcase}.gsub(/ /,'')
|
73
|
-
if ruby_type_name == name
|
74
|
-
ruby_type_name = '::'+ruby_type_name
|
75
|
-
end
|
76
|
-
|
77
|
-
puts " class #{name} < #{ruby_type_name}\n" +
|
78
|
-
" value_type #{params}\n"
|
79
|
-
emit_mapping o if o.is_table
|
80
|
-
puts " restrict #{o.value_constraint.all_allowed_range_sorted.map{|ar| ar.to_s}*", "}\n" if o.value_constraint
|
81
|
-
puts " \# REVISIT: #{o.name} is in units of #{o.unit.name}\n" if o.unit
|
82
|
-
roles_dump(o)
|
83
|
-
puts " end\n\n"
|
61
|
+
puts o.ruby_definition
|
84
62
|
end
|
85
63
|
|
86
64
|
def subtype_dump(o, supertypes, pi = nil)
|
@@ -94,7 +72,7 @@ module ActiveFacts
|
|
94
72
|
fact_roles_dump(o.fact_type) if o.fact_type
|
95
73
|
roles_dump(o)
|
96
74
|
puts " end\n\n"
|
97
|
-
|
75
|
+
pi.ordered_dumped! if pi
|
98
76
|
end
|
99
77
|
|
100
78
|
def non_subtype_dump(o, pi)
|
@@ -106,7 +84,7 @@ module ActiveFacts
|
|
106
84
|
fact_roles_dump(o.fact_type) if o.fact_type
|
107
85
|
roles_dump(o)
|
108
86
|
puts " end\n\n"
|
109
|
-
|
87
|
+
pi.ordered_dumped!
|
110
88
|
end
|
111
89
|
|
112
90
|
# Dump one fact type.
|
@@ -131,12 +109,12 @@ module ActiveFacts
|
|
131
109
|
roles_dump(o)
|
132
110
|
puts " end\n\n"
|
133
111
|
|
134
|
-
|
112
|
+
fact_type.ordered_dumped!
|
135
113
|
end
|
136
114
|
|
137
115
|
def identified_by_roles_and_facts(entity_type, identifying_role_refs, identifying_facts)
|
138
116
|
identifying_role_refs.map{|role_ref|
|
139
|
-
":"+
|
117
|
+
":"+role_ref.role.preferred_role_name(entity_type)
|
140
118
|
}*", "
|
141
119
|
end
|
142
120
|
|
@@ -144,46 +122,8 @@ module ActiveFacts
|
|
144
122
|
puts " maybe :"+role_name
|
145
123
|
end
|
146
124
|
|
147
|
-
def binary_dump(role, role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil,
|
148
|
-
|
149
|
-
|
150
|
-
# Find whether we need the name of the other role player, and whether it's defined yet:
|
151
|
-
implied_role_name = role_player.name.gsub(/ /,'').sub(/^[a-z]/) {|i| i.upcase}
|
152
|
-
if role_name.camelcase != implied_role_name
|
153
|
-
# Only use Class name if it's not implied by the rolename
|
154
|
-
role_reference = ":class => "+object_type_reference(role_player)
|
155
|
-
end
|
156
|
-
|
157
|
-
other_role_name = ":counterpart => :"+other_role_name.gsub(/ /,'_') if other_role_name
|
158
|
-
|
159
|
-
if vr = role.role_value_constraint
|
160
|
-
value_restriction = ":restrict => #{vr}"
|
161
|
-
end
|
162
|
-
|
163
|
-
options = [
|
164
|
-
ruby_role_name,
|
165
|
-
role_reference,
|
166
|
-
mandatory ? ":mandatory => true" : nil,
|
167
|
-
readings,
|
168
|
-
other_role_name,
|
169
|
-
value_restriction
|
170
|
-
].compact
|
171
|
-
|
172
|
-
line = " #{one_to_one ? "one_to_one" : "has_one" } #{options*', '} "
|
173
|
-
if other_method_name
|
174
|
-
line += " "*(48-line.length) if line.length < 48
|
175
|
-
line += "\# See #{role_player.name.gsub(/ /,'')}.#{other_method_name}"
|
176
|
-
end
|
177
|
-
puts line
|
178
|
-
#puts " \# REVISIT: #{other_role_name} has values restricted to #{role.role_value_constraint}\n" if role.role_value_constraint
|
179
|
-
end
|
180
|
-
|
181
|
-
def object_type_reference object_type
|
182
|
-
if !@object_types_dumped[object_type]
|
183
|
-
'"'+object_type.name.gsub(/ /,'')+'"'
|
184
|
-
else
|
185
|
-
role_reference = object_type.name.gsub(/ /,'')
|
186
|
-
end
|
125
|
+
def binary_dump(role, role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil, counterpart_role_name = nil, counterpart_method_name = nil)
|
126
|
+
puts role.as_binary(role_name, role_player, mandatory, one_to_one, readings, counterpart_role_name, counterpart_method_name)
|
187
127
|
end
|
188
128
|
|
189
129
|
end
|
@@ -71,7 +71,7 @@ module ActiveFacts
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def inject_surrogate
|
74
|
-
|
74
|
+
trace :transform_surrogate, "Adding surrogate ID to Value Type #{name}"
|
75
75
|
add_surrogate('Auto Counter', 'ID')
|
76
76
|
end
|
77
77
|
end
|
@@ -96,22 +96,22 @@ module ActiveFacts
|
|
96
96
|
def needs_surrogate
|
97
97
|
|
98
98
|
# A recursive proc to replace any reference to an Entity Type by its identifying references:
|
99
|
-
|
99
|
+
trace :transform_surrogate_expansion, "Expanding key for #{name}"
|
100
100
|
substitute_identifying_refs = proc do |object|
|
101
101
|
if ref = object.absorbed_via
|
102
102
|
# This shouldn't be necessary, but see the absorbed_via comment above.
|
103
103
|
absorbed_into = ref.from
|
104
|
-
|
104
|
+
trace :transform_surrogate_expansion, "recursing to handle absorption of #{object.name} into #{absorbed_into.name}"
|
105
105
|
[substitute_identifying_refs.call(absorbed_into)]
|
106
106
|
else
|
107
107
|
irf = object.identifying_refs_from
|
108
|
-
|
108
|
+
trace :transform_surrogate_expansion, "Iterating for #{object.name} over #{irf.inspect}" do
|
109
109
|
irf.each_with_index do |ref, i|
|
110
110
|
next if ref.is_unary
|
111
111
|
next if ref.to_role.object_type.kind_of?(ActiveFacts::Metamodel::ValueType)
|
112
112
|
recurse_to = ref.to_role.object_type
|
113
113
|
|
114
|
-
|
114
|
+
trace :transform_surrogate_expansion, "#{i}: recursing to expand #{recurse_to.name} key in #{ref}" do
|
115
115
|
irf[i] = substitute_identifying_refs.call(recurse_to)
|
116
116
|
end
|
117
117
|
end
|
@@ -121,7 +121,7 @@ module ActiveFacts
|
|
121
121
|
end
|
122
122
|
irf = substitute_identifying_refs.call(self)
|
123
123
|
|
124
|
-
|
124
|
+
trace :transform_surrogate, "Does #{name} need a surrogate? it's identified by #{irf.inspect}" do
|
125
125
|
|
126
126
|
pk_fks = identifying_refs_from.map do |ref|
|
127
127
|
ref.to && ref.to.is_table ? ref.to : nil
|
@@ -132,13 +132,13 @@ module ActiveFacts
|
|
132
132
|
# Multi-part identifiers are only allowed if each part is a foreign key (i.e. it's a join table) and the object is not the target of a foreign key:
|
133
133
|
if irf.size >= 2
|
134
134
|
if pk_fks.include?(nil)
|
135
|
-
|
135
|
+
trace :transform_surrogate, "#{self.name} needs a surrogate because its multi-part key contains a non-table"
|
136
136
|
return true
|
137
137
|
elsif references_to.size != 0
|
138
|
-
|
138
|
+
trace :transform_surrogate, "#{self.name} is a join table between #{pk_fks.map(&:name).inspect} but is also an FK target"
|
139
139
|
return true
|
140
140
|
else
|
141
|
-
|
141
|
+
trace :transform_surrogate, "#{self.name} is a join table between #{pk_fks.map(&:name).inspect}"
|
142
142
|
return false
|
143
143
|
end
|
144
144
|
return true
|
@@ -148,7 +148,7 @@ module ActiveFacts
|
|
148
148
|
|
149
149
|
identifying_type = irf[0].to
|
150
150
|
if identifying_type.needs_surrogate
|
151
|
-
|
151
|
+
trace :transform_surrogate, "#{self.name} needs a surrogate because #{irf[0].to.name} is not an AutoCounter, but #{identifying_type.supertypes_transitive.map(&:name).inspect}"
|
152
152
|
return true
|
153
153
|
end
|
154
154
|
|
@@ -157,17 +157,17 @@ module ActiveFacts
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def inject_surrogate
|
160
|
-
|
160
|
+
trace :transform_surrogate, "Injecting a surrogate key into #{self.name}"
|
161
161
|
|
162
162
|
# Disable the preferred identifier:
|
163
163
|
pi = preferred_identifier
|
164
|
-
|
164
|
+
trace :transform_surrogate, "pi for #{name} was '#{pi.describe}'"
|
165
165
|
pi.is_preferred_identifier = false
|
166
166
|
@preferred_identifier = nil # Kill the cache
|
167
167
|
|
168
168
|
add_surrogate
|
169
169
|
|
170
|
-
|
170
|
+
trace :transform_surrogate, "pi for #{name} is now '#{preferred_identifier.describe}'"
|
171
171
|
end
|
172
172
|
|
173
173
|
end
|
@@ -158,7 +158,7 @@ module ActiveFacts
|
|
158
158
|
name = nil if name.size == 0
|
159
159
|
entity_type =
|
160
160
|
@by_id[id] =
|
161
|
-
|
161
|
+
trace :orm, "Asserting new EntityType #{name.inspect}" do
|
162
162
|
@vocabulary.valid_entity_type_name(name) ||
|
163
163
|
@constellation.EntityType(@vocabulary, name, :concept => id_of(x))
|
164
164
|
end
|
@@ -212,13 +212,14 @@ module ActiveFacts
|
|
212
212
|
type_name = t
|
213
213
|
end
|
214
214
|
end
|
215
|
-
|
215
|
+
trace :orm, "Using #{type_name.inspect} as supertype for new #{name}"
|
216
216
|
if !length and type_name =~ /\(([0-9]+)\)/
|
217
217
|
length = $1.to_i
|
218
218
|
end
|
219
219
|
type_name = type_name.sub(/\(([0-9]*)\)/,'')
|
220
220
|
|
221
221
|
subtype_roles = x.xpath("orm:PlayedRoles/orm:SubtypeMetaRole")
|
222
|
+
value_super_type = nil
|
222
223
|
if !subtype_roles.empty?
|
223
224
|
subtype_role_id = subtype_roles[0]['ref']
|
224
225
|
subtype_role = @x_by_id[subtype_role_id]
|
@@ -230,7 +231,7 @@ module ActiveFacts
|
|
230
231
|
supertype_name = x_supertype['Name']
|
231
232
|
raise "Supertype of #{name} is post-defined but recursiving processing failed" unless supertype
|
232
233
|
raise "Supertype #{supertype_name} of #{name} is not a value type" unless supertype.kind_of? ActiveFacts::Metamodel::ValueType
|
233
|
-
|
234
|
+
trace :orm, "Asserting new ValueType #{supertype_name.inspect} for supertype" do
|
234
235
|
value_super_type =
|
235
236
|
@vocabulary.valid_value_type_name(supertype_name) ||
|
236
237
|
@constellation.ValueType(@vocabulary, supertype_name, :concept => id_of(x_supertype))
|
@@ -239,7 +240,7 @@ module ActiveFacts
|
|
239
240
|
# REVISIT: Need to handle standard types better here:
|
240
241
|
value_super_type =
|
241
242
|
if type_name != name
|
242
|
-
|
243
|
+
trace :orm, "Asserting new ValueType #{type_name.inspect} for supertype" do
|
243
244
|
@vocabulary.valid_value_type_name(type_name) ||
|
244
245
|
@constellation.ValueType(@vocabulary.identifying_role_values, type_name, :concept => :new)
|
245
246
|
end
|
@@ -249,7 +250,7 @@ module ActiveFacts
|
|
249
250
|
end
|
250
251
|
|
251
252
|
vt =
|
252
|
-
|
253
|
+
trace :orm, "Asserting new ValueType #{name.inspect}" do
|
253
254
|
@by_id[id] =
|
254
255
|
@vocabulary.valid_value_type_name(name) ||
|
255
256
|
@constellation.ValueType(@vocabulary.identifying_role_values, name, :concept => id_of(x))
|
@@ -298,7 +299,7 @@ module ActiveFacts
|
|
298
299
|
# Handle the fact types:
|
299
300
|
facts = []
|
300
301
|
@x_facts = @x_model.xpath("orm:Facts/orm:Fact")
|
301
|
-
|
302
|
+
trace :orm, "Reading fact types" do
|
302
303
|
@x_facts.each{|x|
|
303
304
|
id = x['id']
|
304
305
|
name = x['Name'] || x['_Name']
|
@@ -306,7 +307,7 @@ module ActiveFacts
|
|
306
307
|
name = "" if !name || name.size == 0
|
307
308
|
# Note that the new metamodel doesn't have a name for a facttype unless it's objectified
|
308
309
|
|
309
|
-
|
310
|
+
trace :orm, "FactType #{name || id}"
|
310
311
|
facts << @by_id[id] = fact_type = @constellation.FactType(id_of(x))
|
311
312
|
}
|
312
313
|
end
|
@@ -326,12 +327,12 @@ module ActiveFacts
|
|
326
327
|
# Handle the subtype fact types:
|
327
328
|
facts = []
|
328
329
|
|
329
|
-
|
330
|
+
trace :orm, "Reading sub-types" do
|
330
331
|
@x_subtypes.each{|x|
|
331
332
|
id = x['id']
|
332
333
|
name = (x['Name'] || x['_Name'] || '').gsub(/\s+/,' ').gsub(/-/,'_').strip
|
333
334
|
name = nil if name.size == 0
|
334
|
-
|
335
|
+
trace :orm, "FactType #{name || id}"
|
335
336
|
|
336
337
|
x_subtype_role = x.xpath('orm:FactRoles/orm:SubtypeMetaRole')[0]
|
337
338
|
subtype_role_id = x_subtype_role['id']
|
@@ -346,7 +347,7 @@ module ActiveFacts
|
|
346
347
|
|
347
348
|
throw "For Subtype fact #{name}, the supertype #{supertype_id} was not found" if !supertype
|
348
349
|
throw "For Subtype fact #{name}, the subtype #{subtype_id} was not found" if !subtype
|
349
|
-
|
350
|
+
trace :orm, "#{subtype.name} is a subtype of #{supertype.name}"
|
350
351
|
|
351
352
|
# We already handled ValueType subtyping:
|
352
353
|
next if subtype.kind_of? ActiveFacts::Metamodel::ValueType or
|
@@ -355,7 +356,7 @@ module ActiveFacts
|
|
355
356
|
inheritance_fact = @constellation.TypeInheritance(subtype, supertype, :concept => id_of(x))
|
356
357
|
if x["IsPrimary"] == "true" or # Old way
|
357
358
|
x["PreferredIdentificationPath"] == "true" # Newer
|
358
|
-
|
359
|
+
trace :orm, "#{supertype.name} is primary supertype of #{subtype.name}"
|
359
360
|
inheritance_fact.provides_identification = true
|
360
361
|
end
|
361
362
|
mapping = @x_mappings.detect{ |m| m['ref'] == id }
|
@@ -390,7 +391,7 @@ module ActiveFacts
|
|
390
391
|
# This happens for all ternaries and higher order facts
|
391
392
|
@nested_types = []
|
392
393
|
x_nested_types = @x_model.xpath("orm:Objects/orm:ObjectifiedType")
|
393
|
-
|
394
|
+
trace :orm, "Reading objectified types" do
|
394
395
|
x_nested_types.each{|x|
|
395
396
|
id = x['id']
|
396
397
|
name = (x['Name'] || "").gsub(/\s+/,' ').gsub(/-/,'_').strip
|
@@ -403,7 +404,7 @@ module ActiveFacts
|
|
403
404
|
fact_type = @by_id[fact_id]
|
404
405
|
next unless fact_type # "Nested fact #{fact_id} not found; objectification of a derived fact type?"
|
405
406
|
|
406
|
-
|
407
|
+
trace :orm, "NestedType #{name} is #{id}, nests #{fact_type.concept.guid}"
|
407
408
|
@nested_types <<
|
408
409
|
@by_id[id] =
|
409
410
|
nested_type = @vocabulary.valid_entity_type_name(name) ||
|
@@ -426,7 +427,7 @@ module ActiveFacts
|
|
426
427
|
end
|
427
428
|
|
428
429
|
def read_roles
|
429
|
-
|
430
|
+
trace :orm, "Reading roles and readings" do
|
430
431
|
@x_facts.each{|x|
|
431
432
|
id = x['id']
|
432
433
|
fact_type = @by_id[id]
|
@@ -437,7 +438,7 @@ module ActiveFacts
|
|
437
438
|
x_fact_roles = x.xpath('orm:FactRoles/*')
|
438
439
|
|
439
440
|
# Deal with FactRoles (Roles):
|
440
|
-
|
441
|
+
trace :orm, "Reading fact roles" do
|
441
442
|
x_fact_roles.each{|x|
|
442
443
|
name = (x['Name'] || "").gsub(/\s+/,' ').gsub(/-/,'_').strip
|
443
444
|
name = nil if name.size == 0
|
@@ -462,7 +463,7 @@ module ActiveFacts
|
|
462
463
|
}[0]
|
463
464
|
other_role_id = x_other_role["id"]
|
464
465
|
other_role = @by_id[other_role_id]
|
465
|
-
|
466
|
+
trace :orm, "Indexing unary FT role #{other_role_id} by implicit boolean role #{id}"
|
466
467
|
@by_id[id] = other_role
|
467
468
|
|
468
469
|
# The role name of the ignored role is the one that applies:
|
@@ -476,14 +477,14 @@ module ActiveFacts
|
|
476
477
|
throw "RolePlayer for '#{name}' #{ref} in fact type #{x.parent.parent['_Name']} was not found"
|
477
478
|
end
|
478
479
|
|
479
|
-
|
480
|
+
trace :orm, "#{@vocabulary.name}, RoleName=#{x['Name'].inspect} played by object_type=#{object_type.name}"
|
480
481
|
throw "Role is played by #{object_type.class} not ObjectType" if !(@constellation.vocabulary.object_type(:ObjectType) === object_type)
|
481
482
|
|
482
|
-
|
483
|
+
trace :orm, "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.concept.guid} played by #{object_type.name}"
|
483
484
|
|
484
485
|
role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :object_type => object_type, :concept => id_of(x))
|
485
486
|
role.role_name = name if name && name != object_type.name
|
486
|
-
|
487
|
+
trace :orm, "Fact #{fact_name} (id #{fact_type.concept.guid}) role #{x['Name']} is played by #{object_type.name}, role is #{role.concept.guid}"
|
487
488
|
|
488
489
|
x_vr = x.xpath("orm:ValueRestriction/orm:RoleValueConstraint")
|
489
490
|
x_vr.each{|vr|
|
@@ -496,14 +497,14 @@ module ActiveFacts
|
|
496
497
|
}
|
497
498
|
}
|
498
499
|
|
499
|
-
|
500
|
+
trace :orm, "Adding Role #{role.role_name || role.object_type.name} to #{fact_type.describe}"
|
500
501
|
#fact_type.add_role(role)
|
501
|
-
|
502
|
+
trace :orm, "Role #{role} is #{id}"
|
502
503
|
}
|
503
504
|
end
|
504
505
|
|
505
506
|
# Deal with Readings:
|
506
|
-
|
507
|
+
trace :orm, "Reading fact readings" do
|
507
508
|
x_reading_orders = x.xpath('orm:ReadingOrders/*')
|
508
509
|
x_reading_orders.each{|x|
|
509
510
|
x_role_sequence = x.xpath('orm:RoleSequence/*')
|
@@ -512,7 +513,7 @@ module ActiveFacts
|
|
512
513
|
# Build an array of the Roles needed:
|
513
514
|
role_array = x_role_sequence.map{|x| @by_id[x['ref']] }
|
514
515
|
|
515
|
-
|
516
|
+
trace :orm, "Reading #{x_readings.map(&:text).inspect}"
|
516
517
|
role_sequence = get_role_sequence(role_array)
|
517
518
|
|
518
519
|
#role_sequence.all_role_ref.each_with_index{|rr, i|
|
@@ -677,7 +678,7 @@ module ActiveFacts
|
|
677
678
|
x_mandatory_constraints = @x_model.xpath("orm:Constraints/orm:MandatoryConstraint")
|
678
679
|
@mandatory_constraints_by_rs = {}
|
679
680
|
@mandatory_constraint_rs_by_id = {}
|
680
|
-
|
681
|
+
trace :orm, "Scanning mandatory constraints" do
|
681
682
|
x_mandatory_constraints.each{|x|
|
682
683
|
name = x["Name"] || ''
|
683
684
|
name = nil if name.size == 0
|
@@ -689,7 +690,7 @@ module ActiveFacts
|
|
689
690
|
role_sequence = map_roles(x_roles, "mandatory constraint #{name}")
|
690
691
|
next if !role_sequence
|
691
692
|
|
692
|
-
|
693
|
+
trace :orm, "New MC #{x['Name']} over #{role_sequence.describe}"
|
693
694
|
@mandatory_constraints_by_rs[role_sequence] = x
|
694
695
|
@mandatory_constraint_rs_by_id[x['id']] = role_sequence
|
695
696
|
}
|
@@ -698,7 +699,7 @@ module ActiveFacts
|
|
698
699
|
|
699
700
|
# Mandatory constraints that didn't get merged with an exclusion constraint or a uniqueness constraint are simple mandatories
|
700
701
|
def read_residual_mandatory_constraints
|
701
|
-
|
702
|
+
trace :orm, "Processing non-absorbed mandatory constraints" do
|
702
703
|
@mandatory_constraints_by_rs.each { |role_sequence, x|
|
703
704
|
id = x['id']
|
704
705
|
# Create a simply-mandatory PresenceConstraint for each mandatory constraint
|
@@ -710,7 +711,7 @@ module ActiveFacts
|
|
710
711
|
join_over, = *ActiveFacts::Metamodel.plays_over(role_sequence.all_role_ref.map{|rr| rr.role}, :proximate)
|
711
712
|
raise "Mandatory join constraint #{name} has incompatible players #{players.map{|o| o.name}.inspect}" unless join_over
|
712
713
|
if players.detect{|p| p != join_over}
|
713
|
-
|
714
|
+
trace :query, "subtyping step simple mandatory constraint #{name} over #{join_over.name}"
|
714
715
|
players.each_with_index do |player, i|
|
715
716
|
next if player != join_over
|
716
717
|
# REVISIT: We don't need to make a subtyping step here (from join_over to player)
|
@@ -735,7 +736,7 @@ module ActiveFacts
|
|
735
736
|
|
736
737
|
def read_uniqueness_constraints
|
737
738
|
x_uniqueness_constraints = @x_model.xpath("orm:Constraints/orm:UniquenessConstraint")
|
738
|
-
|
739
|
+
trace :orm, "Reading uniqueness constraints" do
|
739
740
|
x_uniqueness_constraints.each{|x|
|
740
741
|
name = x["Name"] || ''
|
741
742
|
name = nil if name.size == 0
|
@@ -767,7 +768,7 @@ module ActiveFacts
|
|
767
768
|
end
|
768
769
|
subtyping = players.size > 1 ? 'subtyping ' : ''
|
769
770
|
# REVISIT: Create the Query, the Variable for join_over, and steps from each role_ref to join_over
|
770
|
-
|
771
|
+
trace :query, "#{subtyping}join uniqueness constraint over #{join_over.name} in #{fact_types.map(&:default_reading)*', '}"
|
771
772
|
end
|
772
773
|
|
773
774
|
# There is an implicit uniqueness constraint when any object plays a unary. Skip it.
|
@@ -786,7 +787,7 @@ module ActiveFacts
|
|
786
787
|
|
787
788
|
if (mc = @mandatory_constraints_by_rs[role_sequence])
|
788
789
|
# Remove absorbed mandatory constraints, leaving residual ones.
|
789
|
-
|
790
|
+
trace :orm, "Absorbing MC #{mc['Name']} over #{role_sequence.describe}"
|
790
791
|
@mandatory_constraints_by_rs.delete(role_sequence)
|
791
792
|
mc_id = mc['id']
|
792
793
|
@mandatory_constraint_rs_by_id.delete(mc['id'])
|
@@ -797,7 +798,7 @@ module ActiveFacts
|
|
797
798
|
# That is, the phantom roles are mandatory, even if the visible roles are not.
|
798
799
|
mc = true
|
799
800
|
else
|
800
|
-
|
801
|
+
trace :orm, "No MC to absorb over #{role_sequence.describe}"
|
801
802
|
end
|
802
803
|
|
803
804
|
# A TypeInheritance fact type has a uniqueness constraint on each role.
|
@@ -818,9 +819,9 @@ module ActiveFacts
|
|
818
819
|
pc.min_frequency = mc ? 1 : 0
|
819
820
|
pc.max_frequency = 1
|
820
821
|
pc.is_preferred_identifier = true if pi || unary_identifier || is_supertype_constraint
|
821
|
-
|
822
|
+
trace :orm, "#{name} covers #{role_sequence.describe} has min=#{pc.min_frequency}, max=1, preferred=#{pc.is_preferred_identifier.inspect}"
|
822
823
|
|
823
|
-
|
824
|
+
trace :orm, role_sequence.all_role_ref.to_a[0].role.fact_type.describe + " is subject to " + pc.describe if role_sequence.all_role_ref.all?{|r| r.role.fact_type.is_a? ActiveFacts::Metamodel::TypeInheritance }
|
824
825
|
|
825
826
|
(@constraints_by_rs[role_sequence] ||= []) << pc
|
826
827
|
@by_id[uc_id] = pc
|
@@ -840,7 +841,7 @@ module ActiveFacts
|
|
840
841
|
@constellation.RoleRef(rs, 1, :role => ti.supertype_role)
|
841
842
|
sup_play = @constellation.Play(supertype_node, ti.supertype_role)
|
842
843
|
step = @constellation.Step(sub_play, sup_play, :fact_type => ti)
|
843
|
-
|
844
|
+
trace :query, "New subtyping step #{step.describe}"
|
844
845
|
step
|
845
846
|
end
|
846
847
|
|
@@ -915,10 +916,10 @@ module ActiveFacts
|
|
915
916
|
return true
|
916
917
|
end
|
917
918
|
|
918
|
-
|
919
|
+
trace :query, "#{constraint_type} join constraint #{name} over #{role_sequences.map{|rs|rs.describe}*', '}"
|
919
920
|
|
920
921
|
query = nil
|
921
|
-
|
922
|
+
trace :query, "#{constraint_type} join constraint #{name} constrains #{
|
922
923
|
end_points.zip(end_steps).map{|(p,j)| (p ? p.name : 'NULL')+(j ? ' & subtypes':'')}*', '
|
923
924
|
}#{
|
924
925
|
if role_sequences[0].all_role_ref.size > 1
|
@@ -956,7 +957,7 @@ module ActiveFacts
|
|
956
957
|
unless end_point
|
957
958
|
raise "In #{constraint_type} #{name}, there is a faulty or non-translated query"
|
958
959
|
end
|
959
|
-
|
960
|
+
trace :query, "Variable #{query.all_variable.size} is for #{end_point.name}"
|
960
961
|
end_node = @constellation.Variable(query, query.all_variable.size, :object_type => end_point)
|
961
962
|
|
962
963
|
# We're going to rewrite the constraint to constrain the supertype roles, but assume they're the same:
|
@@ -967,7 +968,7 @@ module ActiveFacts
|
|
967
968
|
projecting_play = nil
|
968
969
|
constrained_play = nil
|
969
970
|
if (subtype = role_ref.role.object_type) != end_point
|
970
|
-
|
971
|
+
trace :query, "Making subtyping steps from #{subtype.name} to #{end_point.name}" do
|
971
972
|
# There may be more than one supertyping level. Make the steps:
|
972
973
|
subtyping_steps = subtype_steps(query, subtype, end_point)
|
973
974
|
step = subtyping_steps[0]
|
@@ -989,10 +990,10 @@ module ActiveFacts
|
|
989
990
|
|
990
991
|
if join_over
|
991
992
|
if !variable # Create the Variable when processing the first role
|
992
|
-
|
993
|
+
trace :query, "Variable #{query.all_variable.size} is over #{join_over.name}"
|
993
994
|
variable = @constellation.Variable(query, query.all_variable.size, :object_type => join_over)
|
994
995
|
end
|
995
|
-
|
996
|
+
trace :query, "Making step from #{end_point.name} to #{join_over.name}" do
|
996
997
|
rs = @constellation.RoleSequence(:new)
|
997
998
|
# Detect the fact type over which we're stepping (may involve objectification)
|
998
999
|
raise "Internal error in #{constraint_type} #{name}: making illegal reference to variable, object type mismatch" if role_ref.role.object_type != role_node.object_type
|
@@ -1003,10 +1004,10 @@ module ActiveFacts
|
|
1003
1004
|
join_play = @constellation.Play(variable, joined_role)
|
1004
1005
|
|
1005
1006
|
step = @constellation.Step(role_play, join_play, :fact_type => joined_role.fact_type)
|
1006
|
-
|
1007
|
+
trace :query, "New step #{step.describe}"
|
1007
1008
|
end
|
1008
1009
|
else
|
1009
|
-
|
1010
|
+
trace :query, "Need step for non-join_over role #{end_point.name} #{role_ref.describe} in #{role_ref.role.fact_type.default_reading}"
|
1010
1011
|
if (roles = role_ref.role.fact_type.all_role.to_a).size > 1
|
1011
1012
|
# Here we have an end join (step already created) but no sequence join
|
1012
1013
|
if variable
|
@@ -1052,7 +1053,7 @@ module ActiveFacts
|
|
1052
1053
|
|
1053
1054
|
# Thoroughly check that this is a valid query
|
1054
1055
|
query.validate
|
1055
|
-
|
1056
|
+
trace :query, "Query has projected nodes #{replacement_rs.describe}"
|
1056
1057
|
|
1057
1058
|
# Constrain the replacement role sequence, which has the attached query:
|
1058
1059
|
role_sequences[role_sequences.index(role_sequence)] = replacement_rs
|
@@ -1060,7 +1061,7 @@ module ActiveFacts
|
|
1060
1061
|
return true
|
1061
1062
|
end
|
1062
1063
|
rescue => e
|
1063
|
-
debugger if
|
1064
|
+
debugger if trace :debug
|
1064
1065
|
$stderr.puts "// #{e.to_s}: #{e.backtrace[0]}"
|
1065
1066
|
return false
|
1066
1067
|
end
|
@@ -1069,7 +1070,7 @@ module ActiveFacts
|
|
1069
1070
|
|
1070
1071
|
def read_exclusion_constraints
|
1071
1072
|
x_exclusion_constraints = @x_model.xpath("orm:Constraints/orm:ExclusionConstraint")
|
1072
|
-
|
1073
|
+
trace :orm, "Reading #{x_exclusion_constraints.size} exclusion constraints" do
|
1073
1074
|
x_exclusion_constraints.each{|x|
|
1074
1075
|
id = x['id']
|
1075
1076
|
name = x["Name"] || ''
|
@@ -1111,7 +1112,7 @@ module ActiveFacts
|
|
1111
1112
|
|
1112
1113
|
def read_equality_constraints
|
1113
1114
|
x_equality_constraints = @x_model.xpath("orm:Constraints/orm:EqualityConstraint")
|
1114
|
-
|
1115
|
+
trace :orm, "Reading equality constraints" do
|
1115
1116
|
x_equality_constraints.each{|x|
|
1116
1117
|
id = x['id']
|
1117
1118
|
name = x["Name"] || ''
|
@@ -1144,7 +1145,7 @@ module ActiveFacts
|
|
1144
1145
|
|
1145
1146
|
def read_subset_constraints
|
1146
1147
|
x_subset_constraints = @x_model.xpath("orm:Constraints/orm:SubsetConstraint")
|
1147
|
-
|
1148
|
+
trace :orm, "Reading subset constraints" do
|
1148
1149
|
x_subset_constraints.each{|x|
|
1149
1150
|
id = x['id']
|
1150
1151
|
name = x["Name"] || ''
|
@@ -1173,7 +1174,7 @@ module ActiveFacts
|
|
1173
1174
|
|
1174
1175
|
def read_ring_constraints
|
1175
1176
|
x_ring_constraints = @x_model.xpath("orm:Constraints/orm:RingConstraint")
|
1176
|
-
|
1177
|
+
trace :orm, "Reading ring constraints" do
|
1177
1178
|
x_ring_constraints.each{|x|
|
1178
1179
|
id = x['id']
|
1179
1180
|
name = x["Name"] || ''
|
@@ -1188,7 +1189,7 @@ module ActiveFacts
|
|
1188
1189
|
if from.object_type != to.object_type
|
1189
1190
|
join_over, = *ActiveFacts::Metamodel.plays_over([from, to], :counterpart)
|
1190
1191
|
raise "Ring constraint has incompatible players #{from.object_type.name}, #{to.object_type.name}" if !join_over
|
1191
|
-
|
1192
|
+
trace :query, "join ring constraint over #{join_over.name}"
|
1192
1193
|
end
|
1193
1194
|
rc = @constellation.RingConstraint(id_of(x))
|
1194
1195
|
rc.vocabulary = @vocabulary
|
@@ -1204,7 +1205,7 @@ module ActiveFacts
|
|
1204
1205
|
|
1205
1206
|
def read_frequency_constraints
|
1206
1207
|
x_frequency_constraints = @x_model.xpath("orm:Constraints/orm:FrequencyConstraint")
|
1207
|
-
|
1208
|
+
trace :orm, "Reading frequency constraints" do
|
1208
1209
|
x_frequency_constraints.each do |x_frequency_constraint|
|
1209
1210
|
id = x_frequency_constraint['id']
|
1210
1211
|
min_frequency = x_frequency_constraint["MinFrequency"].to_i
|
@@ -1216,7 +1217,7 @@ module ActiveFacts
|
|
1216
1217
|
role_sequence = @constellation.RoleSequence(:new)
|
1217
1218
|
role_ref = @constellation.RoleRef(role_sequence, 0, :role => role)
|
1218
1219
|
next unless role # Role missing; belongs to a derived fact type
|
1219
|
-
|
1220
|
+
trace :orm, "FrequencyConstraint(min #{min_frequency.inspect} max #{max_frequency.inspect} over #{role.fact_type.describe(role)} #{id} role ref = #{x_roles[0]["ref"]}"
|
1220
1221
|
@by_id[id] = @constellation.PresenceConstraint(
|
1221
1222
|
id_of(x_frequency_constraint),
|
1222
1223
|
:vocabulary => @vocabulary,
|
@@ -1232,14 +1233,14 @@ module ActiveFacts
|
|
1232
1233
|
end
|
1233
1234
|
|
1234
1235
|
def read_instances
|
1235
|
-
|
1236
|
+
trace :orm, "Reading sample data" do
|
1236
1237
|
population = @constellation.Population(@vocabulary, "sample", :concept => :new)
|
1237
1238
|
|
1238
1239
|
# Value instances first, then entities then facts:
|
1239
1240
|
|
1240
1241
|
x_values = @x_model.xpath("orm:Objects/orm:ValueType/orm:Instances/orm:ValueTypeInstance/orm:Value")
|
1241
1242
|
#pp x_values.map{|v| [ v.parent['id'], v.text ] }
|
1242
|
-
|
1243
|
+
trace :orm, "Reading sample values" do
|
1243
1244
|
x_values.each{|v|
|
1244
1245
|
id = v.parent['id']
|
1245
1246
|
# Get details of the ValueType:
|
@@ -1264,7 +1265,7 @@ module ActiveFacts
|
|
1264
1265
|
last_et_id = nil
|
1265
1266
|
last_et = nil
|
1266
1267
|
et = nil
|
1267
|
-
|
1268
|
+
trace :orm, "Reading sample entities" do
|
1268
1269
|
x_entities.each{|v|
|
1269
1270
|
id = v['id']
|
1270
1271
|
|
@@ -1282,7 +1283,7 @@ module ActiveFacts
|
|
1282
1283
|
|
1283
1284
|
instance = @constellation.Instance(id_of(v), :population => population, :object_type => et, :value => nil)
|
1284
1285
|
@by_id[id] = instance
|
1285
|
-
|
1286
|
+
trace :orm, "Made new EntityType #{etname}"
|
1286
1287
|
}
|
1287
1288
|
end
|
1288
1289
|
|
@@ -1291,14 +1292,14 @@ module ActiveFacts
|
|
1291
1292
|
# We create implicit PI facts after all the instances.
|
1292
1293
|
entity_count = 0
|
1293
1294
|
pi_fact_count = 0
|
1294
|
-
|
1295
|
+
trace :orm, "Creating identifying facts for entities" do
|
1295
1296
|
x_entities.each do |v|
|
1296
1297
|
id = v['id']
|
1297
1298
|
instance = @by_id[id]
|
1298
1299
|
et = @by_id[v.parent.parent['id']]
|
1299
1300
|
next unless (preferred_id = et.preferred_identifier)
|
1300
1301
|
|
1301
|
-
|
1302
|
+
trace :orm, "Create identifying facts using #{preferred_id}"
|
1302
1303
|
|
1303
1304
|
# Collate the referenced objects by role:
|
1304
1305
|
role_instances = v.elements[0].elements.inject({}){|h, v|
|
@@ -1315,14 +1316,14 @@ module ActiveFacts
|
|
1315
1316
|
preferred_id.role_sequence.all_role_ref.map { |rr| rr.role.fact_type }.uniq
|
1316
1317
|
identifying_fact_types.
|
1317
1318
|
each do |ft|
|
1318
|
-
|
1319
|
+
trace :orm, "For FactType #{ft}" do
|
1319
1320
|
fact = @constellation.Fact(:new, :population => population, :fact_type => ft)
|
1320
1321
|
fact_roles = ft.all_role.map do |role|
|
1321
1322
|
if role.object_type == et
|
1322
1323
|
object = instance
|
1323
1324
|
else
|
1324
1325
|
object = role_instances[role]
|
1325
|
-
|
1326
|
+
trace :orm, "instance for role #{role} is #{object}"
|
1326
1327
|
end
|
1327
1328
|
@constellation.RoleValue(:instance => object, :population => population, :fact => fact, :role => role)
|
1328
1329
|
end
|
@@ -1333,7 +1334,7 @@ module ActiveFacts
|
|
1333
1334
|
entity_count += 1
|
1334
1335
|
end
|
1335
1336
|
end
|
1336
|
-
|
1337
|
+
trace :orm, "Created #{pi_fact_count} facts to identify #{entity_count} entities"
|
1337
1338
|
|
1338
1339
|
# Use the "ref" attribute of FactTypeRoleInstance:
|
1339
1340
|
x_fact_roles = @x_model.xpath("orm:Facts/orm:Fact/orm:Instances/orm:FactTypeInstance/orm:RoleInstances/orm:FactTypeRoleInstance")
|
@@ -1342,7 +1343,7 @@ module ActiveFacts
|
|
1342
1343
|
last_id = nil
|
1343
1344
|
fact = nil
|
1344
1345
|
fact_roles = []
|
1345
|
-
|
1346
|
+
trace :orm, "Reading sample facts" do
|
1346
1347
|
x_fact_roles.each do |v|
|
1347
1348
|
fact_type_id = v.parent.parent.parent.parent['id']
|
1348
1349
|
id = v.parent.parent['id']
|
@@ -1371,13 +1372,13 @@ module ActiveFacts
|
|
1371
1372
|
|
1372
1373
|
def read_diagrams
|
1373
1374
|
x_diagrams = @document.root.xpath("ormDiagram:ORMDiagram")
|
1374
|
-
|
1375
|
+
trace :orm, "Reading diagrams" do
|
1375
1376
|
x_diagrams.each do |x|
|
1376
1377
|
name = (x["Name"] || '').strip
|
1377
1378
|
diagram = @constellation.ORMDiagram(@vocabulary, name)
|
1378
|
-
|
1379
|
+
trace :diagram, "Starting to read diagram #{name}"
|
1379
1380
|
shapes = x.xpath("ormDiagram:Shapes/*")
|
1380
|
-
|
1381
|
+
trace :orm, "Reading shapes" do
|
1381
1382
|
shapes.map do |x_shape|
|
1382
1383
|
x_subject = x_shape.xpath("ormDiagram:Subject")[0]
|
1383
1384
|
subject = @by_id[x_subject["ref"]]
|
@@ -1449,9 +1450,9 @@ module ActiveFacts
|
|
1449
1450
|
|
1450
1451
|
# $stderr.puts "#{fact_type.describe}: bounds=#{bounds} -> location = (#{location.x}, #{location.y})"
|
1451
1452
|
|
1452
|
-
|
1453
|
+
trace :orm, "REVISIT: Can't place rotated fact type correctly on diagram yet" if rotation_setting
|
1453
1454
|
|
1454
|
-
|
1455
|
+
trace :orm, "fact type at #{location.x},#{location.y} has display_role_names_setting=#{display_role_names_setting.inspect}, rotation_setting=#{rotation_setting.inspect}"
|
1455
1456
|
shape = @constellation.FactTypeShape(
|
1456
1457
|
:guid => id_of(x_shape),
|
1457
1458
|
:orm_diagram => diagram,
|
@@ -1465,7 +1466,7 @@ module ActiveFacts
|
|
1465
1466
|
x_role_display = x_shape.xpath("ormDiagram:RoleDisplayOrder/ormDiagram:Role")
|
1466
1467
|
# print "Fact type '#{fact_type.preferred_reading.expand}' (#{fact_type.all_role.map{|r|r.object_type.name}*' '})"
|
1467
1468
|
if x_role_display.size > 0
|
1468
|
-
|
1469
|
+
trace :orm, " has roleDisplay (#{x_role_display.map{|rd| @by_id[rd['ref']].object_type.name}*','})'"
|
1469
1470
|
x_role_display.each_with_index do |rd, ordinal|
|
1470
1471
|
role_display = @constellation.RoleDisplay(shape, ordinal, :role => @by_id[rd['ref']])
|
1471
1472
|
end
|
@@ -1473,7 +1474,7 @@ module ActiveFacts
|
|
1473
1474
|
# Decide whether to create all RoleDisplay objects for this fact type, which is in role order
|
1474
1475
|
# Omitting this here might lead to incomplete RoleDisplay sequences,
|
1475
1476
|
# because each RoleNameShape or ValueConstraintShape creates just one.
|
1476
|
-
|
1477
|
+
trace :orm, " has no roleDisplay"
|
1477
1478
|
end
|
1478
1479
|
|
1479
1480
|
relative_shapes = x_shape.xpath('ormDiagram:RelativeShapes/*')
|
@@ -1492,7 +1493,7 @@ module ActiveFacts
|
|
1492
1493
|
when 'RoleNameShape'
|
1493
1494
|
role = @by_id[xr_shape.xpath("ormDiagram:Subject")[0]['ref']]
|
1494
1495
|
role_display = role_display_for_role(shape, x_role_display, role)
|
1495
|
-
|
1496
|
+
trace :orm, "Fact type '#{fact_type.preferred_reading.expand}' has #{xr_shape.name}"
|
1496
1497
|
@constellation.RoleNameShape(
|
1497
1498
|
:guid => id_of(xr_shape), :orm_diagram => diagram, :location => location, :is_expanded => false,
|
1498
1499
|
:role_display => role_display
|
@@ -1500,10 +1501,10 @@ module ActiveFacts
|
|
1500
1501
|
when 'ValueConstraintShape'
|
1501
1502
|
vc_subject_id = xr_shape.xpath("ormDiagram:Subject")[0]['ref']
|
1502
1503
|
constraint = @by_id[vc_subject_id]
|
1503
|
-
|
1504
|
+
trace :orm, "Fact type '#{fact_type.preferred_reading.expand}' has #{xr_shape.name} for #{constraint.inspect}"
|
1504
1505
|
|
1505
1506
|
role_display = role_display_for_role(shape, x_role_display, constraint.role)
|
1506
|
-
|
1507
|
+
trace :orm, "ValueConstraintShape is on #{role_display.ordinal}'th role (by #{x_role_display.size > 0 ? 'role_display' : 'fact roles'})"
|
1507
1508
|
@constellation.ValueConstraintShape(
|
1508
1509
|
:guid => id_of(xr_shape), :orm_diagram => diagram, :location => location, :is_expanded => false,
|
1509
1510
|
:constraint => constraint,
|