activefacts 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,
|