activefacts 0.8.16 → 0.8.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Manifest.txt +10 -4
- data/bin/afgen +26 -20
- data/bin/cql +1 -1
- data/css/orm2.css +89 -9
- data/examples/CQL/CompanyDirectorEmployee.cql +4 -4
- data/examples/CQL/Genealogy.cql +5 -5
- data/examples/CQL/Metamodel.cql +121 -91
- data/examples/CQL/MonthInSeason.cql +2 -6
- data/examples/CQL/SeparateSubtype.cql +11 -9
- data/examples/CQL/ServiceDirector.cql +21 -33
- data/examples/CQL/Supervision.cql +0 -3
- data/examples/CQL/WindowInRoomInBldg.cql +10 -4
- data/examples/CQL/unit.cql +1 -1
- data/lib/activefacts.rb +1 -0
- data/lib/activefacts/cql/CQLParser.treetop +5 -1
- data/lib/activefacts/cql/Context.treetop +2 -7
- data/lib/activefacts/cql/Expressions.treetop +2 -2
- data/lib/activefacts/cql/FactTypes.treetop +37 -31
- data/lib/activefacts/cql/Language/English.treetop +21 -4
- data/lib/activefacts/cql/LexicalRules.treetop +59 -1
- data/lib/activefacts/cql/ObjectTypes.treetop +22 -12
- data/lib/activefacts/cql/Terms.treetop +13 -9
- data/lib/activefacts/cql/ValueTypes.treetop +30 -11
- data/lib/activefacts/cql/compiler.rb +34 -5
- data/lib/activefacts/cql/compiler/clause.rb +207 -116
- data/lib/activefacts/cql/compiler/constraint.rb +129 -105
- data/lib/activefacts/cql/compiler/entity_type.rb +49 -27
- data/lib/activefacts/cql/compiler/expression.rb +71 -42
- data/lib/activefacts/cql/compiler/fact.rb +70 -64
- data/lib/activefacts/cql/compiler/fact_type.rb +108 -57
- data/lib/activefacts/cql/compiler/query.rb +178 -0
- data/lib/activefacts/cql/compiler/shared.rb +13 -12
- data/lib/activefacts/cql/compiler/value_type.rb +10 -4
- data/lib/activefacts/cql/nodes.rb +1 -1
- data/lib/activefacts/cql/parser.rb +6 -2
- data/lib/activefacts/generate/absorption.rb +6 -3
- data/lib/activefacts/generate/cql.rb +140 -84
- data/lib/activefacts/generate/dm.rb +12 -6
- data/lib/activefacts/generate/help.rb +25 -6
- data/lib/activefacts/generate/helpers/oo.rb +195 -0
- data/lib/activefacts/generate/helpers/ordered.rb +589 -0
- data/lib/activefacts/generate/helpers/rails.rb +57 -0
- data/lib/activefacts/generate/html/glossary.rb +274 -54
- data/lib/activefacts/generate/json.rb +25 -22
- data/lib/activefacts/generate/null.rb +1 -0
- data/lib/activefacts/generate/rails/models.rb +244 -0
- data/lib/activefacts/generate/rails/schema.rb +185 -0
- data/lib/activefacts/generate/records.rb +1 -0
- data/lib/activefacts/generate/ruby.rb +51 -30
- data/lib/activefacts/generate/sql/mysql.rb +5 -3
- data/lib/activefacts/generate/sql/server.rb +8 -4
- data/lib/activefacts/generate/text.rb +1 -0
- data/lib/activefacts/generate/transform/surrogate.rb +209 -0
- data/lib/activefacts/generate/version.rb +1 -0
- data/lib/activefacts/input/orm.rb +234 -181
- data/lib/activefacts/mapping/rails.rb +122 -0
- data/lib/activefacts/persistence/columns.rb +34 -18
- data/lib/activefacts/persistence/foreignkey.rb +129 -71
- data/lib/activefacts/persistence/index.rb +42 -12
- data/lib/activefacts/persistence/reference.rb +37 -23
- data/lib/activefacts/persistence/tables.rb +53 -19
- data/lib/activefacts/registry.rb +11 -0
- data/lib/activefacts/support.rb +28 -10
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +246 -117
- data/lib/activefacts/vocabulary/metamodel.rb +105 -65
- data/lib/activefacts/vocabulary/verbaliser.rb +226 -194
- data/spec/absorption_spec.rb +1 -0
- data/spec/cql/comparison_spec.rb +8 -8
- data/spec/cql/contractions_spec.rb +16 -43
- data/spec/cql/entity_type_spec.rb +2 -1
- data/spec/cql/expressions_spec.rb +2 -2
- data/spec/cql/fact_type_matching_spec.rb +4 -1
- data/spec/cql/parser/bad_literals_spec.rb +30 -30
- data/spec/cql/parser/entity_types_spec.rb +6 -6
- data/spec/cql/parser/expressions_spec.rb +25 -19
- data/spec/cql/samples_spec.rb +5 -4
- data/spec/cql_cql_spec.rb +2 -1
- data/spec/cql_dm_spec.rb +4 -0
- data/spec/cql_mysql_spec.rb +4 -0
- data/spec/cql_parse_spec.rb +2 -0
- data/spec/cql_ruby_spec.rb +4 -0
- data/spec/cql_sql_spec.rb +4 -0
- data/spec/cqldump_spec.rb +7 -4
- data/spec/helpers/parse_to_ast_matcher.rb +7 -3
- data/spec/helpers/test_parser.rb +2 -0
- data/spec/norma_cql_spec.rb +5 -2
- data/spec/norma_ruby_spec.rb +4 -1
- data/spec/norma_ruby_sql_spec.rb +4 -1
- data/spec/norma_sql_spec.rb +4 -1
- data/spec/norma_tables_spec.rb +2 -2
- data/spec/ruby_api_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/transform_surrogate_spec.rb +59 -0
- metadata +70 -60
- data/TODO +0 -308
- data/lib/activefacts/cql/compiler/join.rb +0 -162
- data/lib/activefacts/generate/oo.rb +0 -176
- data/lib/activefacts/generate/ordered.rb +0 -602
@@ -144,28 +144,35 @@ module ActiveFacts
|
|
144
144
|
read_diagrams if @options.include?("diagrams")
|
145
145
|
end
|
146
146
|
|
147
|
+
def id_of(x)
|
148
|
+
x['id'][1..-1]
|
149
|
+
end
|
150
|
+
|
147
151
|
def read_entity_types
|
148
152
|
# get and process all the entity types:
|
149
153
|
entity_types = []
|
150
154
|
x_entity_types = @x_model.xpath("orm:Objects/orm:EntityType")
|
151
|
-
x_entity_types.each
|
155
|
+
x_entity_types.each do |x|
|
152
156
|
id = x['id']
|
153
157
|
name = (x['Name'] || "").gsub(/\s+/,' ').gsub(/-/,'_').strip
|
154
158
|
name = nil if name.size == 0
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
entity_type =
|
160
|
+
@by_id[id] =
|
161
|
+
debug :orm, "Asserting new EntityType #{name.inspect}" do
|
162
|
+
@vocabulary.valid_entity_type_name(name) ||
|
163
|
+
@constellation.EntityType(@vocabulary, name, :guid => id_of(x))
|
164
|
+
end
|
165
|
+
entity_types << entity_type
|
166
|
+
independent = x['IsIndependent']
|
167
|
+
entity_type.is_independent = true if independent && independent == 'true'
|
168
|
+
personal = x['IsPersonal']
|
169
|
+
entity_type.pronoun = 'personal' if personal && personal == 'true'
|
163
170
|
# x_pref = x.xpath("orm:PreferredIdentifier")[0]
|
164
171
|
# if x_pref
|
165
172
|
# pi_id = x_pref['ref']
|
166
173
|
# @pref_id_for[pi_id] = x
|
167
174
|
# end
|
168
|
-
|
175
|
+
end
|
169
176
|
end
|
170
177
|
|
171
178
|
def read_value_types
|
@@ -198,7 +205,14 @@ module ActiveFacts
|
|
198
205
|
type_name.sub!(/^orm:/,'')
|
199
206
|
|
200
207
|
type_name.sub!(/DataType\Z/,'')
|
201
|
-
|
208
|
+
if t = DataTypeMapping[type_name]
|
209
|
+
existing = @constellation.ObjectType[[@vocabulary.identifying_role_values, t]]
|
210
|
+
if !existing || existing.is_a?(ActiveFacts::Metamodel::ValueType)
|
211
|
+
# There's no type conflict, so use the mapped name.
|
212
|
+
type_name = t
|
213
|
+
end
|
214
|
+
end
|
215
|
+
debug :orm, "Using #{type_name.inspect} as supertype for new #{name}"
|
202
216
|
if !length and type_name =~ /\(([0-9]+)\)/
|
203
217
|
length = $1.to_i
|
204
218
|
end
|
@@ -216,14 +230,30 @@ module ActiveFacts
|
|
216
230
|
supertype_name = x_supertype['Name']
|
217
231
|
raise "Supertype of #{name} is post-defined but recursiving processing failed" unless supertype
|
218
232
|
raise "Supertype #{supertype_name} of #{name} is not a value type" unless supertype.kind_of? ActiveFacts::Metamodel::ValueType
|
219
|
-
|
233
|
+
debug :orm, "Asserting new ValueType #{supertype_name.inspect} for supertype" do
|
234
|
+
value_super_type =
|
235
|
+
@vocabulary.valid_value_type_name(supertype_name) ||
|
236
|
+
@constellation.ValueType(@vocabulary, supertype_name, :guid => id_of(x_supertype))
|
237
|
+
end
|
220
238
|
else
|
221
239
|
# REVISIT: Need to handle standard types better here:
|
222
|
-
value_super_type =
|
240
|
+
value_super_type =
|
241
|
+
if type_name != name
|
242
|
+
debug :orm, "Asserting new ValueType #{type_name.inspect} for supertype" do
|
243
|
+
@vocabulary.valid_value_type_name(type_name) ||
|
244
|
+
@constellation.ValueType(@vocabulary.identifying_role_values, type_name, :guid => :new)
|
245
|
+
end
|
246
|
+
else
|
247
|
+
nil
|
248
|
+
end
|
223
249
|
end
|
224
250
|
|
225
|
-
|
226
|
-
|
251
|
+
vt =
|
252
|
+
debug :orm, "Asserting new ValueType #{name.inspect}" do
|
253
|
+
@by_id[id] =
|
254
|
+
@vocabulary.valid_value_type_name(name) ||
|
255
|
+
@constellation.ValueType(@vocabulary.identifying_role_values, name, :guid => id_of(x))
|
256
|
+
end
|
227
257
|
vt.supertype = value_super_type
|
228
258
|
vt.length = length if length
|
229
259
|
vt.scale = scale if scale && scale != 0
|
@@ -236,7 +266,7 @@ module ActiveFacts
|
|
236
266
|
x_vr.each{|vr|
|
237
267
|
x_ranges = vr.xpath("orm:ValueRanges/orm:ValueRange")
|
238
268
|
next if x_ranges.size == 0
|
239
|
-
vt.value_constraint = @by_id[vr['id']] = @constellation.ValueConstraint(
|
269
|
+
vt.value_constraint = @by_id[vr['id']] = @constellation.ValueConstraint(id_of(vr))
|
240
270
|
x_ranges.each{|x_range|
|
241
271
|
v_range = value_range(x_range)
|
242
272
|
ar = @constellation.AllowedRange(vt.value_constraint, v_range)
|
@@ -245,16 +275,23 @@ module ActiveFacts
|
|
245
275
|
vt
|
246
276
|
end
|
247
277
|
|
278
|
+
def assert_value(val, string)
|
279
|
+
if val
|
280
|
+
@constellation.Value(val.to_s, string, nil)
|
281
|
+
else
|
282
|
+
nil
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
248
286
|
def value_range(x_range)
|
249
287
|
min = x_range['MinValue']
|
250
288
|
max = x_range['MaxValue']
|
251
289
|
|
252
|
-
strings =
|
290
|
+
strings = is_literal_string(min) || is_literal_string(max)
|
253
291
|
# ValueRange takes a minimum and/or a maximum Bound, each takes value and whether inclusive
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
)
|
292
|
+
@constellation.ValueRange(
|
293
|
+
min.length > 0 ? @constellation.Bound(assert_value(min, strings), true) : nil,
|
294
|
+
max.length > 0 ? @constellation.Bound(assert_value(max, strings), true) : nil)
|
258
295
|
end
|
259
296
|
|
260
297
|
def read_fact_types
|
@@ -271,7 +308,7 @@ module ActiveFacts
|
|
271
308
|
next if x.xpath("orm:DerivationRule").size > 0
|
272
309
|
|
273
310
|
debug :orm, "FactType #{name || id}"
|
274
|
-
facts << @by_id[id] = fact_type = @constellation.FactType(
|
311
|
+
facts << @by_id[id] = fact_type = @constellation.FactType(id_of(x))
|
275
312
|
}
|
276
313
|
end
|
277
314
|
end
|
@@ -316,7 +353,7 @@ module ActiveFacts
|
|
316
353
|
next if subtype.kind_of? ActiveFacts::Metamodel::ValueType or
|
317
354
|
supertype.kind_of? ActiveFacts::Metamodel::ValueType
|
318
355
|
|
319
|
-
inheritance_fact = @constellation.TypeInheritance(subtype, supertype, :guid =>
|
356
|
+
inheritance_fact = @constellation.TypeInheritance(subtype, supertype, :guid => id_of(x))
|
320
357
|
if x["IsPrimary"] == "true" or # Old way
|
321
358
|
x["PreferredIdentificationPath"] == "true" # Newer
|
322
359
|
debug :orm, "#{supertype.name} is primary supertype of #{subtype.name}"
|
@@ -328,22 +365,22 @@ module ActiveFacts
|
|
328
365
|
facts << @by_id[id] = inheritance_fact
|
329
366
|
|
330
367
|
# Create the new Roles so we can find constraints on them:
|
331
|
-
subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :object_type => subtype, :guid =>
|
332
|
-
supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :object_type => supertype, :guid =>
|
368
|
+
subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :object_type => subtype, :guid => id_of(x_subtype_role))
|
369
|
+
supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :object_type => supertype, :guid => id_of(x_supertype_role))
|
333
370
|
|
334
371
|
# Create readings, so constraints can be verbalised for example:
|
335
372
|
rs = @constellation.RoleSequence(:new)
|
336
373
|
@constellation.RoleRef(rs, 0, :role => subtype_role)
|
337
374
|
@constellation.RoleRef(rs, 1, :role => supertype_role)
|
338
|
-
@constellation.Reading(inheritance_fact, 0, :role_sequence => rs, :text => "{0} is a kind of {1}")
|
339
|
-
@constellation.Reading(inheritance_fact, 1, :role_sequence => rs, :text => "{0} is a subtype of {1}")
|
375
|
+
@constellation.Reading(inheritance_fact, 0, :role_sequence => rs, :text => "{0} is a kind of {1}", :is_negative => false)
|
376
|
+
@constellation.Reading(inheritance_fact, 1, :role_sequence => rs, :text => "{0} is a subtype of {1}", :is_negative => false)
|
340
377
|
|
341
378
|
rs2 = @constellation.RoleSequence(:new)
|
342
379
|
@constellation.RoleRef(rs2, 0, :role => supertype_role)
|
343
380
|
@constellation.RoleRef(rs2, 1, :role => subtype_role)
|
344
381
|
n = 'aeiouh'.include?(subtype_role.object_type.name.downcase[0]) ? 1 : 0
|
345
|
-
@constellation.Reading(inheritance_fact, 2+n, :role_sequence => rs2, :text => "{0} is a {1}")
|
346
|
-
@constellation.Reading(inheritance_fact, 3-n, :role_sequence => rs2, :text => "{0} is an {1}")
|
382
|
+
@constellation.Reading(inheritance_fact, 2+n, :role_sequence => rs2, :text => "{0} is a {1}", :is_negative => false)
|
383
|
+
@constellation.Reading(inheritance_fact, 3-n, :role_sequence => rs2, :text => "{0} is an {1}", :is_negative => false)
|
347
384
|
}
|
348
385
|
end
|
349
386
|
end
|
@@ -366,12 +403,13 @@ module ActiveFacts
|
|
366
403
|
fact_id = x_fact_type['ref']
|
367
404
|
fact_type = @by_id[fact_id]
|
368
405
|
next if x.xpath("orm:DerivationRule").size > 0
|
369
|
-
|
406
|
+
next unless fact_type # "Nested fact #{fact_id} not found; objectification of a derived fact type?"
|
370
407
|
|
371
408
|
debug :orm, "NestedType #{name} is #{id}, nests #{fact_type.guid}"
|
372
409
|
@nested_types <<
|
373
410
|
@by_id[id] =
|
374
|
-
|
411
|
+
nested_type = @vocabulary.valid_entity_type_name(name) ||
|
412
|
+
@constellation.EntityType(@vocabulary, name, :guid => id_of(x))
|
375
413
|
independent = x['IsIndependent']
|
376
414
|
nested_type.is_independent = true if independent && independent == 'true' && !is_implied
|
377
415
|
nested_type.is_implied_by_objectification = is_implied
|
@@ -382,8 +420,8 @@ module ActiveFacts
|
|
382
420
|
|
383
421
|
def complete_nested_types
|
384
422
|
@nested_types.each do |nested_type|
|
385
|
-
# Create the phantom roles here. These will be used later when we create objectification
|
386
|
-
# but for now there's nothing we import from NORMA which requires objectification
|
423
|
+
# Create the phantom roles here. These will be used later when we create objectification steps,
|
424
|
+
# but for now there's nothing we import from NORMA which requires objectification steps.
|
387
425
|
# Consequently there's no need to index them against NORMA's phantom roles.
|
388
426
|
nested_type.create_implicit_fact_types
|
389
427
|
end
|
@@ -400,7 +438,6 @@ module ActiveFacts
|
|
400
438
|
fact_name = nil if fact_name == ''
|
401
439
|
|
402
440
|
x_fact_roles = x.xpath('orm:FactRoles/*')
|
403
|
-
x_reading_orders = x.xpath('orm:ReadingOrders/*')
|
404
441
|
|
405
442
|
# Deal with FactRoles (Roles):
|
406
443
|
debug :orm, "Reading fact roles" do
|
@@ -438,14 +475,14 @@ module ActiveFacts
|
|
438
475
|
@by_id.delete(ref) # and de-index it from our list
|
439
476
|
next
|
440
477
|
end
|
441
|
-
throw "RolePlayer for '#{name}' #{ref} was not found" if !object_type
|
478
|
+
throw "RolePlayer for '#{name}' #{ref} in fact type #{x.parent.parent['_Name']} was not found" if !object_type
|
442
479
|
|
443
480
|
debug :orm, "#{@vocabulary.name}, RoleName=#{x['Name'].inspect} played by object_type=#{object_type.name}"
|
444
481
|
throw "Role is played by #{object_type.class} not ObjectType" if !(@constellation.vocabulary.object_type(:ObjectType) === object_type)
|
445
482
|
|
446
483
|
debug :orm, "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.guid} played by #{object_type.name}"
|
447
484
|
|
448
|
-
role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :object_type => object_type, :guid =>
|
485
|
+
role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :object_type => object_type, :guid => id_of(x))
|
449
486
|
role.role_name = name if name && name != object_type.name
|
450
487
|
debug :orm, "Fact #{fact_name} (id #{fact_type.guid.object_id}) role #{x['Name']} is played by #{object_type.name}, role is #{role.object_id}"
|
451
488
|
|
@@ -453,7 +490,7 @@ module ActiveFacts
|
|
453
490
|
x_vr.each{|vr|
|
454
491
|
x_ranges = vr.xpath("orm:ValueRanges/orm:ValueRange")
|
455
492
|
next if x_ranges.size == 0
|
456
|
-
role.role_value_constraint = @by_id[vr['id']] = @constellation.ValueConstraint(
|
493
|
+
role.role_value_constraint = @by_id[vr['id']] = @constellation.ValueConstraint(id_of(vr))
|
457
494
|
x_ranges.each{|x_range|
|
458
495
|
v_range = value_range(x_range)
|
459
496
|
ar = @constellation.AllowedRange(role.role_value_constraint, v_range)
|
@@ -468,6 +505,7 @@ module ActiveFacts
|
|
468
505
|
|
469
506
|
# Deal with Readings:
|
470
507
|
debug :orm, "Reading fact readings" do
|
508
|
+
x_reading_orders = x.xpath('orm:ReadingOrders/*')
|
471
509
|
x_reading_orders.each{|x|
|
472
510
|
x_role_sequence = x.xpath('orm:RoleSequence/*')
|
473
511
|
x_readings = x.xpath('orm:Readings/orm:Reading/orm:Data')
|
@@ -483,7 +521,7 @@ module ActiveFacts
|
|
483
521
|
# }
|
484
522
|
|
485
523
|
x_readings.each_with_index{|x, i|
|
486
|
-
reading = @constellation.Reading(fact_type, fact_type.all_reading.size)
|
524
|
+
reading = @constellation.Reading(fact_type, fact_type.all_reading.size, :is_negative => false)
|
487
525
|
reading.role_sequence = role_sequence
|
488
526
|
# REVISIT: The downcase here only needs to be the initial letter of each word, but be safe:
|
489
527
|
reading.text = extract_adjectives(x.text, role_sequence)
|
@@ -672,18 +710,18 @@ module ActiveFacts
|
|
672
710
|
#puts "Residual Mandatory #{name}: #{role_sequence.to_s}"
|
673
711
|
|
674
712
|
if (players = role_sequence.all_role_ref.map{|rr| rr.role.object_type}).uniq.size > 1
|
675
|
-
join_over, = *ActiveFacts::Metamodel.
|
713
|
+
join_over, = *ActiveFacts::Metamodel.plays_over(role_sequence.all_role_ref.map{|rr| rr.role}, :proximate)
|
676
714
|
raise "Mandatory join constraint #{name} has incompatible players #{players.map{|o| o.name}.inspect}" unless join_over
|
677
715
|
if players.detect{|p| p != join_over}
|
678
|
-
debug :
|
716
|
+
debug :query, "subtyping step simple mandatory constraint #{name} over #{join_over.name}"
|
679
717
|
players.each_with_index do |player, i|
|
680
718
|
next if player != join_over
|
681
|
-
# REVISIT: We don't need to make a subtyping
|
719
|
+
# REVISIT: We don't need to make a subtyping step here (from join_over to player)
|
682
720
|
end
|
683
721
|
end
|
684
722
|
end
|
685
723
|
|
686
|
-
pc = @constellation.PresenceConstraint(
|
724
|
+
pc = @constellation.PresenceConstraint(id_of(x))
|
687
725
|
pc.vocabulary = @vocabulary
|
688
726
|
pc.name = name
|
689
727
|
pc.role_sequence = role_sequence
|
@@ -718,15 +756,21 @@ module ActiveFacts
|
|
718
756
|
next if !role_sequence
|
719
757
|
#puts "uc: #{role_sequence.all_role_ref.map{|rr|rr.role.fact_type.default_reading}*', '}"
|
720
758
|
|
721
|
-
# Check for a
|
759
|
+
# Check for a query
|
722
760
|
if (fact_types = role_sequence.all_role_ref.map{|rr| rr.role.fact_type}).uniq.size > 1
|
723
|
-
join_over, = *ActiveFacts::Metamodel.
|
761
|
+
join_over, = *ActiveFacts::Metamodel.plays_over(role_sequence.all_role_ref.map{|rr| rr.role}, :counterpart)
|
724
762
|
|
725
763
|
players = role_sequence.all_role_ref.map{|rr| rr.role.object_type.name}.uniq
|
726
|
-
|
764
|
+
unless join_over
|
765
|
+
if x.xpath("orm:RoleSequence/orm:JoinRule").size > 0
|
766
|
+
$stderr.puts "Ignoring Join #{name} because its query is not understood"
|
767
|
+
next
|
768
|
+
end
|
769
|
+
raise "Uniqueness join constraint #{name} has incompatible players #{players.inspect}"
|
770
|
+
end
|
727
771
|
subtyping = players.size > 1 ? 'subtyping ' : ''
|
728
|
-
# REVISIT: Create the
|
729
|
-
debug :
|
772
|
+
# REVISIT: Create the Query, the Variable for join_over, and steps from each role_ref to join_over
|
773
|
+
debug :query, "#{subtyping}join uniqueness constraint over #{join_over.name} in #{fact_types.map(&:default_reading)*', '}"
|
730
774
|
end
|
731
775
|
|
732
776
|
# There is an implicit uniqueness constraint when any object plays a unary. Skip it.
|
@@ -769,7 +813,7 @@ module ActiveFacts
|
|
769
813
|
role.object_type == fact_type.supertype &&
|
770
814
|
fact_type.provides_identification
|
771
815
|
|
772
|
-
pc = @constellation.PresenceConstraint(
|
816
|
+
pc = @constellation.PresenceConstraint(id_of(x))
|
773
817
|
pc.vocabulary = @vocabulary
|
774
818
|
pc.name = name
|
775
819
|
pc.role_sequence = role_sequence
|
@@ -788,23 +832,23 @@ module ActiveFacts
|
|
788
832
|
end
|
789
833
|
end
|
790
834
|
|
791
|
-
def
|
792
|
-
subtype_node =
|
793
|
-
@constellation.
|
794
|
-
supertype_node =
|
795
|
-
@constellation.
|
835
|
+
def subtype_step(query, ti)
|
836
|
+
subtype_node = query.all_variable.detect{|jn| jn.object_type == ti.subtype } ||
|
837
|
+
@constellation.Variable(query, query.all_variable.size, :object_type => ti.subtype)
|
838
|
+
supertype_node = query.all_variable.detect{|jn| jn.object_type == ti.supertype } ||
|
839
|
+
@constellation.Variable(query, query.all_variable.size, :object_type => ti.supertype)
|
796
840
|
rs = @constellation.RoleSequence(:new)
|
797
841
|
@constellation.RoleRef(rs, 0, :role => ti.subtype_role)
|
798
|
-
|
842
|
+
sub_play = @constellation.Play(subtype_node, ti.subtype_role)
|
799
843
|
@constellation.RoleRef(rs, 1, :role => ti.supertype_role)
|
800
|
-
|
801
|
-
|
802
|
-
debug :
|
803
|
-
|
844
|
+
sup_play = @constellation.Play(supertype_node, ti.supertype_role)
|
845
|
+
step = @constellation.Step(sub_play, sup_play, :fact_type => ti)
|
846
|
+
debug :query, "New subtyping step #{step.describe}"
|
847
|
+
step
|
804
848
|
end
|
805
849
|
|
806
|
-
# Make as many
|
807
|
-
def
|
850
|
+
# Make as many steps as it takes to get from subtype to supertype
|
851
|
+
def subtype_steps(query, subtype, supertype)
|
808
852
|
primary_ti = nil
|
809
853
|
other_ti = nil
|
810
854
|
subtype.all_type_inheritance_as_subtype.each do |ti|
|
@@ -816,24 +860,24 @@ module ActiveFacts
|
|
816
860
|
end
|
817
861
|
end
|
818
862
|
ti = primary_ti || other_ti
|
819
|
-
# Make supertype
|
820
|
-
(ti.supertype == supertype ? [] :
|
821
|
-
[
|
863
|
+
# Make supertype steps first:
|
864
|
+
(ti.supertype == supertype ? [] : subtype_steps(query, ti.supertype, supertype)) +
|
865
|
+
[subtype_step(query, ti)]
|
822
866
|
end
|
823
867
|
|
824
|
-
# Equality and subset
|
868
|
+
# Equality and subset join constraints involve two or more role sequences,
|
825
869
|
# and the respective roles from each sequence must be compatible,
|
826
|
-
# Compatibility might involve subtyping
|
870
|
+
# Compatibility might involve subtyping steps but not objectification steps
|
827
871
|
# to the respective end-point (constrained object type).
|
828
872
|
# Also, all roles in each sequence constitute a join over a single
|
829
|
-
# object type, which might involve subtyping or objectification
|
873
|
+
# object type, which might involve subtyping or objectification steps.
|
830
874
|
#
|
831
|
-
def
|
875
|
+
def make_queries(constraint_type, name, role_sequences)
|
832
876
|
begin
|
833
877
|
# Get the object types constrained for each position in the role sequences.
|
834
|
-
# Supertyping
|
878
|
+
# Supertyping steps may be needed to reach them.
|
835
879
|
end_points = [] # An array of the common supertype for matching role_refs across the sequences
|
836
|
-
|
880
|
+
end_steps = [] # An array of booleans indicating whether any role_sequence requires subtyping steps
|
837
881
|
role_sequences[0].all_role_ref.size.times do |i|
|
838
882
|
role_refs = role_sequences.map{|rs| rs.all_role_ref.detect{|rr| rr.ordinal == i}}
|
839
883
|
if (fact_types = role_refs.map{|rr| rr.role.fact_type}).uniq.size == 1
|
@@ -842,9 +886,9 @@ module ActiveFacts
|
|
842
886
|
end
|
843
887
|
if (players = role_refs.map{|rr| rr.role.object_type}).uniq.size == 1
|
844
888
|
end_point = players[0]
|
845
|
-
|
889
|
+
end_steps[i] = false
|
846
890
|
else
|
847
|
-
# Can the players be joined using
|
891
|
+
# Can the players be joined using subtyping steps?
|
848
892
|
common_supertypes = players[1..-1].
|
849
893
|
inject(players[0].supertypes_transitive) do |remaining, player|
|
850
894
|
remaining & player.supertypes_transitive
|
@@ -852,33 +896,33 @@ module ActiveFacts
|
|
852
896
|
end_point = common_supertypes[0]
|
853
897
|
|
854
898
|
raise "constrained roles of #{constraint_type} #{name} are incompatible (#{players.map(&:name)*', '})" if common_supertypes.size == 0
|
855
|
-
|
899
|
+
end_steps[i] = true
|
856
900
|
end
|
857
901
|
end_points[i] = end_point
|
858
902
|
end
|
859
903
|
|
860
904
|
# For each role_sequence, find the object type over which the join is implied (nil if no join)
|
861
905
|
sequence_join_over = []
|
862
|
-
if role_sequences[0].all_role_ref.size > 1 # There are
|
906
|
+
if role_sequences[0].all_role_ref.size > 1 # There are queries within each sequence.
|
863
907
|
sequence_join_over = []
|
864
908
|
sequence_joined_roles = []
|
865
909
|
role_sequences.map do |rs|
|
866
|
-
join_over, joined_roles = *ActiveFacts::Metamodel.
|
910
|
+
join_over, joined_roles = *ActiveFacts::Metamodel.plays_over(rs.all_role_ref.map{|rr| rr.role})
|
867
911
|
sequence_join_over << join_over
|
868
912
|
sequence_joined_roles << joined_roles
|
869
913
|
end
|
870
914
|
end
|
871
915
|
|
872
|
-
# If there are no
|
873
|
-
if sequence_join_over.compact.empty? && !
|
916
|
+
# If there are no queries, we can drop out here.
|
917
|
+
if sequence_join_over.compact.empty? && !end_steps.detect{|e| true}
|
874
918
|
return true
|
875
919
|
end
|
876
920
|
|
877
|
-
debug :
|
921
|
+
debug :query, "#{constraint_type} join constraint #{name} over #{role_sequences.map{|rs|rs.describe}*', '}"
|
878
922
|
|
879
|
-
|
880
|
-
debug :
|
881
|
-
end_points.zip(
|
923
|
+
query = nil
|
924
|
+
debug :query, "#{constraint_type} join constraint #{name} constrains #{
|
925
|
+
end_points.zip(end_steps).map{|(p,j)| (p ? p.name : 'NULL')+(j ? ' & subtypes':'')}*', '
|
882
926
|
}#{
|
883
927
|
if role_sequences[0].all_role_ref.size > 1
|
884
928
|
", joined over #{
|
@@ -891,134 +935,136 @@ module ActiveFacts
|
|
891
935
|
end
|
892
936
|
}" do
|
893
937
|
|
894
|
-
# There may be one
|
938
|
+
# There may be one query per role sequence:
|
895
939
|
role_sequences.zip(sequence_join_over||[], sequence_joined_roles||[]).map do |role_sequence, join_over, joined_roles|
|
896
|
-
# Skip if there's no
|
940
|
+
# Skip if there's no query here (sequence join nor end-point subset join)
|
897
941
|
role_refs = role_sequence.all_role_ref_in_order
|
898
942
|
if !join_over and !role_refs.detect{|rr| rr.role.object_type != end_points[rr.ordinal]}
|
899
943
|
# No sequence join nor end_point join here
|
900
944
|
next
|
901
945
|
end
|
902
946
|
|
903
|
-
# A RoleSequence for the actual
|
947
|
+
# A RoleSequence for the actual query end-points
|
904
948
|
replacement_rs = @constellation.RoleSequence(:new)
|
905
949
|
|
906
|
-
|
907
|
-
|
908
|
-
|
950
|
+
query = @constellation.Query(:new)
|
951
|
+
variable = nil
|
952
|
+
query_role = nil
|
909
953
|
role_refs.zip(joined_roles||[]).each_with_index do |(role_ref, joined_role), i|
|
910
954
|
|
911
|
-
# Each role_ref is to an object joined via joined_role to
|
955
|
+
# Each role_ref is to an object joined via joined_role to variable (or which will be the variable)
|
912
956
|
|
913
|
-
# Create a
|
957
|
+
# Create a variable for the actual end-point (supertype of the constrained roles)
|
914
958
|
end_point = end_points[i]
|
915
959
|
unless end_point
|
916
|
-
raise "In #{constraint_type} #{name}, there is a faulty or non-translated
|
960
|
+
raise "In #{constraint_type} #{name}, there is a faulty or non-translated query"
|
917
961
|
end
|
918
|
-
debug :
|
919
|
-
end_node = @constellation.
|
962
|
+
debug :query, "Variable #{query.all_variable.size} is for #{end_point.name}"
|
963
|
+
end_node = @constellation.Variable(query, query.all_variable.size, :object_type => end_point)
|
920
964
|
|
921
965
|
# We're going to rewrite the constraint to constrain the supertype roles, but assume they're the same:
|
922
966
|
role_node = end_node
|
923
967
|
end_role = role_ref.role
|
924
968
|
|
925
|
-
# Create subtyping
|
926
|
-
|
927
|
-
|
969
|
+
# Create subtyping steps at the end-point, if needed:
|
970
|
+
projecting_play = nil
|
971
|
+
constrained_play = nil
|
928
972
|
if (subtype = role_ref.role.object_type) != end_point
|
929
|
-
debug :
|
973
|
+
debug :query, "Making subtyping steps from #{subtype.name} to #{end_point.name}" do
|
930
974
|
# There may be more than one supertyping level. Make the steps:
|
931
|
-
subtyping_steps =
|
932
|
-
|
933
|
-
|
975
|
+
subtyping_steps = subtype_steps(query, subtype, end_point)
|
976
|
+
step = subtyping_steps[0]
|
977
|
+
constrained_play = subtyping_steps[-1].input_play
|
934
978
|
|
935
979
|
# Replace the constrained role and node with the supertype ones:
|
936
|
-
end_node =
|
937
|
-
|
938
|
-
end_role =
|
939
|
-
role_node =
|
980
|
+
end_node = query.all_variable.detect{|jn| jn.object_type == end_point }
|
981
|
+
projecting_play = step.output_play
|
982
|
+
end_role = step.fact_type.all_role.detect{|r| r.object_type == end_point }
|
983
|
+
role_node = query.all_variable.detect{|jn| jn.object_type == role_ref.role.object_type }
|
940
984
|
end
|
941
985
|
end
|
942
986
|
|
943
|
-
raise "Internal error in #{constraint_type} #{name}: making illegal reference to
|
987
|
+
raise "Internal error in #{constraint_type} #{name}: making illegal reference to variable, end role mismatch" if end_role.object_type != end_node.object_type
|
944
988
|
rr = @constellation.RoleRef(replacement_rs, replacement_rs.all_role_ref.size, :role => end_role)
|
945
|
-
|
946
|
-
|
989
|
+
projecting_play ||= (constrained_play = @constellation.Play(end_node, end_role))
|
990
|
+
projecting_play.role_ref = rr # Project this RoleRef
|
991
|
+
# projecting_play.variable.projection = rr.role # REVISIT: The variable should project a role, not the Play a RoleRef
|
947
992
|
|
948
993
|
if join_over
|
949
|
-
if !
|
950
|
-
debug :
|
951
|
-
|
994
|
+
if !variable # Create the Variable when processing the first role
|
995
|
+
debug :query, "Variable #{query.all_variable.size} is over #{join_over.name}"
|
996
|
+
variable = @constellation.Variable(query, query.all_variable.size, :object_type => join_over)
|
952
997
|
end
|
953
|
-
debug :
|
998
|
+
debug :query, "Making step from #{end_point.name} to #{join_over.name}" do
|
954
999
|
rs = @constellation.RoleSequence(:new)
|
955
|
-
# Detect the fact type over which we're
|
956
|
-
raise "Internal error in #{constraint_type} #{name}: making illegal reference to
|
1000
|
+
# Detect the fact type over which we're stepping (may involve objectification)
|
1001
|
+
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
|
957
1002
|
@constellation.RoleRef(rs, 0, :role => role_ref.role)
|
958
|
-
|
959
|
-
raise "Internal error in #{constraint_type} #{name}: making illegal reference to
|
1003
|
+
role_play = @constellation.Play(role_node, role_ref.role)
|
1004
|
+
raise "Internal error in #{constraint_type} #{name}: making illegal reference to variable, joined_role mismatch" if joined_role.object_type != variable.object_type
|
960
1005
|
@constellation.RoleRef(rs, 1, :role => joined_role)
|
961
|
-
|
1006
|
+
join_play = @constellation.Play(variable, joined_role)
|
962
1007
|
|
963
|
-
|
964
|
-
debug :
|
1008
|
+
step = @constellation.Step(role_play, join_play, :fact_type => joined_role.fact_type)
|
1009
|
+
debug :query, "New step #{step.describe}"
|
965
1010
|
end
|
966
1011
|
else
|
967
|
-
debug :
|
1012
|
+
debug :query, "Need step for non-join_over role #{end_point.name} #{role_ref.describe} in #{role_ref.role.fact_type.default_reading}"
|
968
1013
|
if (roles = role_ref.role.fact_type.all_role.to_a).size > 1
|
969
1014
|
# Here we have an end join (step already created) but no sequence join
|
970
|
-
if
|
971
|
-
raise "Internal error in #{constraint_type} #{name}: making illegal
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
roles -= [
|
1015
|
+
if variable
|
1016
|
+
raise "Internal error in #{constraint_type} #{name}: making illegal step" if role_ref.role.object_type != role_node.object_type
|
1017
|
+
join_play = @constellation.Play(variable, query_role)
|
1018
|
+
role_play = @constellation.Play(role_node, role_ref.role)
|
1019
|
+
step = @constellation.Step(join_play, role_play, :fact_type => role_ref.role.fact_type)
|
1020
|
+
roles -= [query_role, role_ref.role]
|
976
1021
|
roles.each do |incidental_role|
|
977
|
-
jn = @constellation.
|
978
|
-
|
1022
|
+
jn = @constellation.Variable(query, query.all_variable.size, :object_type => incidental_role.object_type)
|
1023
|
+
play = @constellation.Play(jn, incidental_role, :step => step)
|
979
1024
|
end
|
980
1025
|
else
|
981
1026
|
if role_sequence.all_role_ref.size > 1
|
982
|
-
|
983
|
-
|
1027
|
+
variable = role_node
|
1028
|
+
query_role = role_ref.role
|
984
1029
|
else
|
985
|
-
# There's no
|
1030
|
+
# There's no query in this role sequence, so we'd drop off the bottom without doing the right things. Why?
|
986
1031
|
# Without this case, Supervision.orm omits "that runs Company" from the exclusion constraint, and I'm not sure why.
|
987
1032
|
# I think the "then" code causes it to drop out the bottom without making the step (which is otherwise made in every case, see CompanyDirectorEmployee for example)
|
988
|
-
|
989
|
-
|
1033
|
+
role_play = @constellation.Play(role_node, role_ref.role)
|
1034
|
+
step = nil
|
990
1035
|
role_ref.role.fact_type.all_role.each do |role|
|
991
|
-
next if role ==
|
1036
|
+
next if role == role_play.role
|
992
1037
|
next if role_sequence.all_role_ref.detect{|rr| rr.role == role}
|
993
|
-
jn = @constellation.
|
994
|
-
|
995
|
-
if
|
996
|
-
|
1038
|
+
jn = @constellation.Variable(query, query.all_variable.size, :object_type => role.object_type)
|
1039
|
+
play = @constellation.Play(jn, role)
|
1040
|
+
if step
|
1041
|
+
play.step = step # Incidental role
|
997
1042
|
else
|
998
|
-
|
1043
|
+
step = @constellation.Step(role_play, play, :fact_type => role_ref.role.fact_type)
|
999
1044
|
end
|
1000
1045
|
end
|
1001
1046
|
end
|
1002
1047
|
end
|
1003
1048
|
else
|
1004
|
-
# Unary fact type, make a
|
1005
|
-
|
1006
|
-
|
1049
|
+
# Unary fact type, make a Step from and to the constrained_play
|
1050
|
+
play = @constellation.Play(constrained_play.variable, role_ref.role)
|
1051
|
+
step = @constellation.Step(play, play, :fact_type => role_ref.role.fact_type)
|
1007
1052
|
end
|
1008
1053
|
end
|
1009
1054
|
end
|
1010
1055
|
|
1011
|
-
# Thoroughly check that this is a valid
|
1012
|
-
|
1013
|
-
debug :
|
1056
|
+
# Thoroughly check that this is a valid query
|
1057
|
+
query.validate
|
1058
|
+
debug :query, "Query has projected nodes #{replacement_rs.describe}"
|
1014
1059
|
|
1015
|
-
# Constrain the replacement role sequence, which has the attached
|
1060
|
+
# Constrain the replacement role sequence, which has the attached query:
|
1016
1061
|
role_sequences[role_sequences.index(role_sequence)] = replacement_rs
|
1017
1062
|
end
|
1018
1063
|
return true
|
1019
1064
|
end
|
1020
1065
|
rescue => e
|
1021
|
-
|
1066
|
+
debugger if debug :debug
|
1067
|
+
$stderr.puts "// #{e.to_s}: #{e.backtrace[0]}"
|
1022
1068
|
return false
|
1023
1069
|
end
|
1024
1070
|
|
@@ -1050,9 +1096,9 @@ module ActiveFacts
|
|
1050
1096
|
|
1051
1097
|
next if role_sequences.compact.size != role_sequences.size # Role sequence missing; includes a derived fact type role
|
1052
1098
|
|
1053
|
-
next unless
|
1099
|
+
next unless make_queries('exclusion', name+(x_mandatory ? '/'+x_mandatory['Name'] : ''), role_sequences)
|
1054
1100
|
|
1055
|
-
ec = @constellation.SetExclusionConstraint(
|
1101
|
+
ec = @constellation.SetExclusionConstraint(id_of(x))
|
1056
1102
|
ec.vocabulary = @vocabulary
|
1057
1103
|
ec.name = name
|
1058
1104
|
# ec.enforcement =
|
@@ -1085,9 +1131,9 @@ module ActiveFacts
|
|
1085
1131
|
# Role sequence missing; includes a derived fact type role
|
1086
1132
|
next if role_sequences.compact.size != role_sequences.size
|
1087
1133
|
|
1088
|
-
next unless
|
1134
|
+
next unless make_queries('equality', name, role_sequences)
|
1089
1135
|
|
1090
|
-
ec = @constellation.SetEqualityConstraint(
|
1136
|
+
ec = @constellation.SetEqualityConstraint(id_of(x))
|
1091
1137
|
ec.vocabulary = @vocabulary
|
1092
1138
|
ec.name = name
|
1093
1139
|
# ec.enforcement =
|
@@ -1115,9 +1161,9 @@ module ActiveFacts
|
|
1115
1161
|
)
|
1116
1162
|
}
|
1117
1163
|
next if role_sequences.compact.size != role_sequences.size # Role sequence missing; includes a derived fact type role
|
1118
|
-
next unless
|
1164
|
+
next unless make_queries('subset', name, role_sequences)
|
1119
1165
|
|
1120
|
-
ec = @constellation.SubsetConstraint(
|
1166
|
+
ec = @constellation.SubsetConstraint(id_of(x))
|
1121
1167
|
ec.vocabulary = @vocabulary
|
1122
1168
|
ec.name = name
|
1123
1169
|
# ec.enforcement =
|
@@ -1143,11 +1189,11 @@ module ActiveFacts
|
|
1143
1189
|
end
|
1144
1190
|
next unless from && to # Roles missing; covers a derived fact type
|
1145
1191
|
if from.object_type != to.object_type
|
1146
|
-
join_over, = *ActiveFacts::Metamodel.
|
1192
|
+
join_over, = *ActiveFacts::Metamodel.plays_over([from, to], :counterpart)
|
1147
1193
|
raise "Ring constraint has incompatible players #{from.object_type.name}, #{to.object_type.name}" if !join_over
|
1148
|
-
debug :
|
1194
|
+
debug :query, "join ring constraint over #{join_over.name}"
|
1149
1195
|
end
|
1150
|
-
rc = @constellation.RingConstraint(
|
1196
|
+
rc = @constellation.RingConstraint(id_of(x))
|
1151
1197
|
rc.vocabulary = @vocabulary
|
1152
1198
|
rc.name = name
|
1153
1199
|
# rc.enforcement =
|
@@ -1175,7 +1221,7 @@ module ActiveFacts
|
|
1175
1221
|
next unless role # Role missing; belongs to a derived fact type
|
1176
1222
|
debug :orm, "FrequencyConstraint(min #{min_frequency.inspect} max #{max_frequency.inspect} over #{role.fact_type.describe(role)} #{id} role ref = #{x_roles[0]["ref"]}"
|
1177
1223
|
@by_id[id] = @constellation.PresenceConstraint(
|
1178
|
-
|
1224
|
+
id_of(x_frequency_constraint),
|
1179
1225
|
:vocabulary => @vocabulary,
|
1180
1226
|
:name => name = x_frequency_constraint["Name"] || '',
|
1181
1227
|
:role_sequence => role_sequence,
|
@@ -1208,7 +1254,7 @@ module ActiveFacts
|
|
1208
1254
|
vt = @by_id[vt_id]
|
1209
1255
|
throw "ValueType #{vtname} not found" unless vt
|
1210
1256
|
|
1211
|
-
i = @constellation.Instance(
|
1257
|
+
i = @constellation.Instance(id_of(v.parent), :population => population, :object_type => vt, :value => [v.text, is_literal_string(v.text), nil])
|
1212
1258
|
@by_id[id] = i
|
1213
1259
|
# show_xmlobj(v)
|
1214
1260
|
}
|
@@ -1237,14 +1283,15 @@ module ActiveFacts
|
|
1237
1283
|
throw "EntityType #{etname} not found" unless et
|
1238
1284
|
end
|
1239
1285
|
|
1240
|
-
instance = @constellation.Instance(
|
1286
|
+
instance = @constellation.Instance(id_of(v), :population => population, :object_type => et, :value => nil)
|
1241
1287
|
@by_id[id] = instance
|
1242
1288
|
debug :orm, "Made new EntityType #{etname}"
|
1243
1289
|
}
|
1244
1290
|
end
|
1245
1291
|
|
1246
1292
|
# The EntityType instances have implicit facts for the PI facts.
|
1247
|
-
|
1293
|
+
# These are in the ORM file, but instead of using those,
|
1294
|
+
# We create implicit PI facts after all the instances.
|
1248
1295
|
entity_count = 0
|
1249
1296
|
pi_fact_count = 0
|
1250
1297
|
debug :orm, "Creating identifying facts for entities" do
|
@@ -1294,6 +1341,7 @@ module ActiveFacts
|
|
1294
1341
|
# Use the "ref" attribute of FactTypeRoleInstance:
|
1295
1342
|
x_fact_roles = @x_model.xpath("orm:Facts/orm:Fact/orm:Instances/orm:FactTypeInstance/orm:RoleInstances/orm:FactTypeRoleInstance")
|
1296
1343
|
|
1344
|
+
# REVISIT: This presumably duplicates the identifying fact instances for the above entities. Hmmm.
|
1297
1345
|
last_id = nil
|
1298
1346
|
fact = nil
|
1299
1347
|
fact_roles = []
|
@@ -1329,7 +1377,7 @@ module ActiveFacts
|
|
1329
1377
|
debug :orm, "Reading diagrams" do
|
1330
1378
|
x_diagrams.each do |x|
|
1331
1379
|
name = (x["Name"] || '').strip
|
1332
|
-
diagram = @constellation.
|
1380
|
+
diagram = @constellation.ORMDiagram(@vocabulary, name)
|
1333
1381
|
debug :diagram, "Starting to read diagram #{name}"
|
1334
1382
|
shapes = x.xpath("ormDiagram:Shapes/*")
|
1335
1383
|
debug :orm, "Reading shapes" do
|
@@ -1346,28 +1394,28 @@ module ActiveFacts
|
|
1346
1394
|
end
|
1347
1395
|
when 'ExternalConstraintShape', 'FrequencyConstraintShape'
|
1348
1396
|
# REVISIT: The offset might depend on the constraint type. This is right for subset and other round ones.
|
1349
|
-
|
1397
|
+
location = convert_location(bounds, Gravity::C)
|
1350
1398
|
shape = @constellation.ConstraintShape(
|
1351
|
-
:
|
1399
|
+
:guid => id_of(x_shape), :orm_diagram => diagram, :location => location, :is_expanded => is_expanded,
|
1352
1400
|
:constraint => subject
|
1353
1401
|
)
|
1354
1402
|
when 'RingConstraintShape'
|
1355
1403
|
# REVISIT: The offset might depend on the ring constraint type. This is right for basic round ones.
|
1356
|
-
|
1404
|
+
location = convert_location(bounds, Gravity::C)
|
1357
1405
|
shape = @constellation.RingConstraintShape(
|
1358
|
-
:
|
1406
|
+
:guid => id_of(x_shape), :orm_diagram => diagram, :location => location, :is_expanded => is_expanded,
|
1359
1407
|
:constraint => subject
|
1360
1408
|
)
|
1361
1409
|
shape.fact_type = subject.role.fact_type
|
1362
1410
|
when 'ModelNoteShape'
|
1363
1411
|
# REVISIT: Add model notes
|
1364
1412
|
when 'ObjectTypeShape'
|
1365
|
-
|
1366
|
-
# $stderr.puts "#{subject.name}: bounds=#{bounds} ->
|
1413
|
+
location = convert_location(bounds, Gravity::C)
|
1414
|
+
# $stderr.puts "#{subject.name}: bounds=#{bounds} -> location = (#{location.x}, #{location.y})"
|
1367
1415
|
shape = @constellation.ObjectTypeShape(
|
1368
|
-
:
|
1416
|
+
:guid => id_of(x_shape), :orm_diagram => diagram, :location => location, :is_expanded => is_expanded,
|
1369
1417
|
:object_type => subject,
|
1370
|
-
:
|
1418
|
+
:location => location
|
1371
1419
|
)
|
1372
1420
|
else
|
1373
1421
|
raise "Unknown shape #{x_shape.name}"
|
@@ -1392,7 +1440,7 @@ module ActiveFacts
|
|
1392
1440
|
else nil
|
1393
1441
|
end
|
1394
1442
|
|
1395
|
-
#
|
1443
|
+
# Location of a fact type is the centre of the row of role boxes
|
1396
1444
|
offs_x = 11
|
1397
1445
|
offs_y = -12
|
1398
1446
|
if fact_type.entity_type
|
@@ -1400,17 +1448,17 @@ module ActiveFacts
|
|
1400
1448
|
offs_y -= 9 if !fact_type.entity_type.is_implied_by_objectification
|
1401
1449
|
end
|
1402
1450
|
|
1403
|
-
|
1451
|
+
location = convert_location(bounds, Gravity::S, offs_x, offs_y)
|
1404
1452
|
|
1405
|
-
# $stderr.puts "#{fact_type.describe}: bounds=#{bounds} ->
|
1453
|
+
# $stderr.puts "#{fact_type.describe}: bounds=#{bounds} -> location = (#{location.x}, #{location.y})"
|
1406
1454
|
|
1407
1455
|
debug :orm, "REVISIT: Can't place rotated fact type correctly on diagram yet" if rotation_setting
|
1408
1456
|
|
1409
|
-
debug :orm, "fact type at #{
|
1457
|
+
debug :orm, "fact type at #{location.x},#{location.y} has display_role_names_setting=#{display_role_names_setting.inspect}, rotation_setting=#{rotation_setting.inspect}"
|
1410
1458
|
shape = @constellation.FactTypeShape(
|
1411
|
-
:
|
1412
|
-
:
|
1413
|
-
:
|
1459
|
+
:guid => id_of(x_shape),
|
1460
|
+
:orm_diagram => diagram,
|
1461
|
+
:location => location,
|
1414
1462
|
:is_expanded => is_expanded,
|
1415
1463
|
:display_role_names_setting => display_role_names_setting,
|
1416
1464
|
:rotation_setting => rotation_setting,
|
@@ -1433,18 +1481,23 @@ module ActiveFacts
|
|
1433
1481
|
|
1434
1482
|
relative_shapes = x_shape.xpath('ormDiagram:RelativeShapes/*')
|
1435
1483
|
relative_shapes.each do |xr_shape|
|
1436
|
-
|
1484
|
+
location = convert_location(xr_shape['AbsoluteBounds'])
|
1437
1485
|
case xr_shape.name
|
1438
1486
|
when 'ObjectifiedFactTypeNameShape'
|
1439
|
-
@constellation.ObjectifiedFactTypeNameShape(
|
1487
|
+
@constellation.ObjectifiedFactTypeNameShape(:guid => id_of(xr_shape), :fact_type_shape => shape, :orm_diagram => diagram, :location => location, :is_expanded => false)
|
1440
1488
|
when 'ReadingShape'
|
1441
|
-
|
1489
|
+
begin
|
1490
|
+
@constellation.ReadingShape(:guid => id_of(xr_shape), :fact_type_shape => shape, :orm_diagram => diagram, :location => location, :is_expanded => false, :reading => fact_type.preferred_reading)
|
1491
|
+
rescue =>e
|
1492
|
+
debugger
|
1493
|
+
@constellation.ReadingShape(:guid => id_of(xr_shape), :fact_type_shape => shape, :orm_diagram => diagram, :location => location, :is_expanded => false, :reading => fact_type.preferred_reading)
|
1494
|
+
end
|
1442
1495
|
when 'RoleNameShape'
|
1443
1496
|
role = @by_id[xr_shape.xpath("ormDiagram:Subject")[0]['ref']]
|
1444
1497
|
role_display = role_display_for_role(shape, x_role_display, role)
|
1445
1498
|
debug :orm, "Fact type '#{fact_type.preferred_reading.expand}' has #{xr_shape.name}"
|
1446
1499
|
@constellation.RoleNameShape(
|
1447
|
-
:
|
1500
|
+
:guid => id_of(xr_shape), :orm_diagram => diagram, :location => location, :is_expanded => false,
|
1448
1501
|
:role_display => role_display
|
1449
1502
|
)
|
1450
1503
|
when 'ValueConstraintShape'
|
@@ -1455,7 +1508,7 @@ module ActiveFacts
|
|
1455
1508
|
role_display = role_display_for_role(shape, x_role_display, constraint.role)
|
1456
1509
|
debug :orm, "ValueConstraintShape is on #{role_display.ordinal}'th role (by #{x_role_display.size > 0 ? 'role_display' : 'fact roles'})"
|
1457
1510
|
@constellation.ValueConstraintShape(
|
1458
|
-
:
|
1511
|
+
:guid => id_of(xr_shape), :orm_diagram => diagram, :location => location, :is_expanded => false,
|
1459
1512
|
:constraint => constraint,
|
1460
1513
|
:object_type_shape => nil, # This constraint is relative to a Fact Type, so must be on a role
|
1461
1514
|
:role_display => role_display
|
@@ -1480,7 +1533,7 @@ module ActiveFacts
|
|
1480
1533
|
end
|
1481
1534
|
|
1482
1535
|
DIAGRAM_SCALE = 96*1.5
|
1483
|
-
def
|
1536
|
+
def convert_location(bounds, gravity = Gravity::C, xoffs = 0, yoffs = 0)
|
1484
1537
|
return nil unless bounds
|
1485
1538
|
# Bounds is top, left, width, height in inches
|
1486
1539
|
bf = bounds.split(/, /).map{|b|b.to_f}
|
@@ -1492,11 +1545,11 @@ module ActiveFacts
|
|
1492
1545
|
|
1493
1546
|
x = (DIAGRAM_SCALE * (bf[0]+bf[2]*sizefrax[gravity][0]/2)).round + xoffs
|
1494
1547
|
y = (DIAGRAM_SCALE * (bf[1]+bf[3]*sizefrax[gravity][1]/2)).round + yoffs
|
1495
|
-
@constellation.
|
1548
|
+
@constellation.Location(x, y)
|
1496
1549
|
end
|
1497
1550
|
|
1498
1551
|
# Detect numeric data and denote it as a string:
|
1499
|
-
def
|
1552
|
+
def is_literal_string(value)
|
1500
1553
|
value =~ /[^ \d.]/
|
1501
1554
|
end
|
1502
1555
|
|