activefacts 0.8.9 → 0.8.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/Manifest.txt +28 -33
- data/Rakefile +11 -12
- data/bin/cql +90 -46
- data/examples/CQL/Blog.cql +2 -1
- data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
- data/examples/CQL/Death.cql +1 -1
- data/examples/CQL/Diplomacy.cql +9 -9
- data/examples/CQL/Genealogy.cql +3 -2
- data/examples/CQL/Insurance.cql +10 -7
- data/examples/CQL/JoinEquality.cql +2 -2
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +73 -53
- data/examples/CQL/MetamodelNext.cql +89 -67
- data/examples/CQL/OneToOnes.cql +2 -2
- data/examples/CQL/ServiceDirector.cql +10 -5
- data/examples/CQL/Supervision.cql +3 -3
- data/examples/CQL/Tests.Test5.Load.cql +1 -1
- data/examples/CQL/Warehousing.cql +4 -2
- data/lib/activefacts/cql/CQLParser.treetop +26 -60
- data/lib/activefacts/cql/Context.treetop +12 -2
- data/lib/activefacts/cql/Expressions.treetop +14 -30
- data/lib/activefacts/cql/FactTypes.treetop +165 -110
- data/lib/activefacts/cql/Language/English.treetop +167 -54
- data/lib/activefacts/cql/LexicalRules.treetop +16 -2
- data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
- data/lib/activefacts/cql/Terms.treetop +57 -27
- data/lib/activefacts/cql/ValueTypes.treetop +39 -13
- data/lib/activefacts/cql/compiler.rb +5 -3
- data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
- data/lib/activefacts/cql/compiler/constraint.rb +178 -275
- data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
- data/lib/activefacts/cql/compiler/expression.rb +418 -0
- data/lib/activefacts/cql/compiler/fact.rb +146 -145
- data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
- data/lib/activefacts/cql/compiler/join.rb +159 -0
- data/lib/activefacts/cql/compiler/shared.rb +51 -23
- data/lib/activefacts/cql/compiler/value_type.rb +56 -2
- data/lib/activefacts/cql/parser.rb +15 -4
- data/lib/activefacts/generate/absorption.rb +7 -7
- data/lib/activefacts/generate/cql.rb +100 -37
- data/lib/activefacts/generate/oo.rb +28 -51
- data/lib/activefacts/generate/ordered.rb +60 -36
- data/lib/activefacts/generate/ruby.rb +6 -6
- data/lib/activefacts/generate/sql/server.rb +4 -4
- data/lib/activefacts/input/orm.rb +71 -53
- data/lib/activefacts/persistence.rb +1 -1
- data/lib/activefacts/persistence/columns.rb +27 -23
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +17 -17
- data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
- data/lib/activefacts/persistence/reference.rb +61 -36
- data/lib/activefacts/persistence/tables.rb +61 -59
- data/lib/activefacts/support.rb +54 -29
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +99 -54
- data/lib/activefacts/vocabulary/metamodel.rb +43 -37
- data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
- data/spec/absorption_spec.rb +8 -8
- data/spec/cql/comparison_spec.rb +91 -0
- data/spec/cql/contractions_spec.rb +251 -0
- data/spec/cql/entity_type_spec.rb +319 -0
- data/spec/cql/expressions_spec.rb +63 -0
- data/spec/cql/fact_type_matching_spec.rb +283 -0
- data/spec/cql/french_spec.rb +21 -0
- data/spec/cql/parser/bad_literals_spec.rb +86 -0
- data/spec/cql/parser/constraints_spec.rb +19 -0
- data/spec/cql/parser/entity_types_spec.rb +106 -0
- data/spec/cql/parser/expressions_spec.rb +179 -0
- data/spec/cql/parser/fact_types_spec.rb +41 -0
- data/spec/cql/parser/literals_spec.rb +312 -0
- data/spec/cql/parser/pragmas_spec.rb +89 -0
- data/spec/cql/parser/value_types_spec.rb +42 -0
- data/spec/cql/role_matching_spec.rb +147 -0
- data/spec/cql/samples_spec.rb +9 -9
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/cql_dm_spec.rb +116 -0
- data/spec/cql_mysql_spec.rb +1 -1
- data/spec/cql_ruby_spec.rb +1 -1
- data/spec/cql_sql_spec.rb +3 -3
- data/spec/cql_symbol_tables_spec.rb +30 -30
- data/spec/cqldump_spec.rb +4 -4
- data/spec/helpers/array_matcher.rb +32 -27
- data/spec/helpers/diff_matcher.rb +6 -26
- data/spec/helpers/file_matcher.rb +41 -32
- data/spec/helpers/parse_to_ast_matcher.rb +76 -0
- data/spec/helpers/string_matcher.rb +32 -31
- data/spec/norma_cql_spec.rb +1 -1
- data/spec/norma_ruby_spec.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +1 -1
- data/spec/norma_sql_spec.rb +3 -1
- data/spec/norma_tables_spec.rb +1 -1
- data/spec/ruby_api_spec.rb +23 -0
- data/spec/spec_helper.rb +5 -4
- metadata +66 -66
- data/examples/CQL/OrienteeringER.cql +0 -58
- data/lib/activefacts/api.rb +0 -44
- data/lib/activefacts/api/concept.rb +0 -410
- data/lib/activefacts/api/constellation.rb +0 -128
- data/lib/activefacts/api/entity.rb +0 -256
- data/lib/activefacts/api/instance.rb +0 -60
- data/lib/activefacts/api/instance_index.rb +0 -80
- data/lib/activefacts/api/numeric.rb +0 -167
- data/lib/activefacts/api/role.rb +0 -80
- data/lib/activefacts/api/role_proxy.rb +0 -70
- data/lib/activefacts/api/role_values.rb +0 -117
- data/lib/activefacts/api/standard_types.rb +0 -87
- data/lib/activefacts/api/support.rb +0 -65
- data/lib/activefacts/api/value.rb +0 -135
- data/lib/activefacts/api/vocabulary.rb +0 -82
- data/spec/api/autocounter.rb +0 -82
- data/spec/api/constellation.rb +0 -130
- data/spec/api/entity_type.rb +0 -103
- data/spec/api/instance.rb +0 -461
- data/spec/api/roles.rb +0 -124
- data/spec/api/value_type.rb +0 -112
- data/spec/api_spec.rb +0 -13
- data/spec/cql/matching_spec.rb +0 -517
- data/spec/cql/unit_spec.rb +0 -394
- data/spec/spec.opts +0 -1
@@ -177,6 +177,8 @@ module ActiveFacts
|
|
177
177
|
name = (x['Name'] || "").gsub(/\s+/,' ').gsub(/-/,'_').strip
|
178
178
|
name = nil if name.size == 0
|
179
179
|
|
180
|
+
next if x['IsImplicitBooleanValue']
|
181
|
+
|
180
182
|
cdt = x.xpath('orm:ConceptualDataType')[0]
|
181
183
|
scale = cdt['Scale']
|
182
184
|
scale = scale != "" && scale.to_i
|
@@ -244,6 +246,7 @@ module ActiveFacts
|
|
244
246
|
name = "<unnamed>" if !name
|
245
247
|
name = "" if !name || name.size == 0
|
246
248
|
# Note that the new metamodel doesn't have a name for a facttype unless it's objectified
|
249
|
+
next if x.xpath("orm:DerivationRule").size > 0
|
247
250
|
|
248
251
|
debug :orm, "FactType #{name || id}"
|
249
252
|
facts << @by_id[id] = fact_type = @constellation.FactType(:new)
|
@@ -284,8 +287,7 @@ module ActiveFacts
|
|
284
287
|
throw "For Subtype fact #{name}, the subtype #{subtype_id} was not found" if !subtype
|
285
288
|
debug :orm, "#{subtype.name} is a subtype of #{supertype.name}"
|
286
289
|
|
287
|
-
inheritance_fact = @constellation.TypeInheritance(subtype, supertype)
|
288
|
-
inheritance_fact.fact_type_id = :new
|
290
|
+
inheritance_fact = @constellation.TypeInheritance(subtype, supertype, :fact_type_id => :new)
|
289
291
|
if x["IsPrimary"] == "true" or # Old way
|
290
292
|
x["PreferredIdentificationPath"] == "true" # Newer
|
291
293
|
debug :orm, "#{supertype.name} is primary supertype of #{subtype.name}"
|
@@ -297,8 +299,8 @@ module ActiveFacts
|
|
297
299
|
facts << @by_id[id] = inheritance_fact
|
298
300
|
|
299
301
|
# Create the new Roles so we can find constraints on them:
|
300
|
-
subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :
|
301
|
-
supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :
|
302
|
+
subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :object_type => subtype)
|
303
|
+
supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :object_type => supertype)
|
302
304
|
|
303
305
|
# Create readings, so constraints can be verbalised for example:
|
304
306
|
rs = @constellation.RoleSequence(:new)
|
@@ -310,7 +312,7 @@ module ActiveFacts
|
|
310
312
|
rs2 = @constellation.RoleSequence(:new)
|
311
313
|
@constellation.RoleRef(rs2, 0, :role => supertype_role)
|
312
314
|
@constellation.RoleRef(rs2, 1, :role => subtype_role)
|
313
|
-
n = 'aeiouh'.include?(subtype_role.
|
315
|
+
n = 'aeiouh'.include?(subtype_role.object_type.name.downcase[0]) ? 1 : 0
|
314
316
|
@constellation.Reading(inheritance_fact, 2+n, :role_sequence => rs2, :text => "{0} is a {1}")
|
315
317
|
@constellation.Reading(inheritance_fact, 3-n, :role_sequence => rs2, :text => "{0} is an {1}")
|
316
318
|
}
|
@@ -334,6 +336,7 @@ module ActiveFacts
|
|
334
336
|
|
335
337
|
fact_id = x_fact_type['ref']
|
336
338
|
fact_type = @by_id[fact_id]
|
339
|
+
next if x.xpath("orm:DerivationRule").size > 0
|
337
340
|
throw "Nested fact #{fact_id} not found" if !fact_type
|
338
341
|
|
339
342
|
#if is_implied
|
@@ -345,6 +348,8 @@ module ActiveFacts
|
|
345
348
|
@nested_types <<
|
346
349
|
@by_id[id] =
|
347
350
|
nested_type = @constellation.EntityType(@vocabulary, name)
|
351
|
+
independent = x['IsIndependent']
|
352
|
+
nested_type.is_independent = true if independent && independent == 'true' && !is_implied
|
348
353
|
nested_type.fact_type = fact_type
|
349
354
|
end
|
350
355
|
}
|
@@ -364,6 +369,7 @@ module ActiveFacts
|
|
364
369
|
debug :orm, "Reading roles and readings" do
|
365
370
|
@x_facts.each{|x|
|
366
371
|
id = x['id']
|
372
|
+
next if x.xpath("orm:DerivationRule").size > 0
|
367
373
|
fact_type = @by_id[id]
|
368
374
|
fact_name = x['Name'] || x['_Name'] || ''
|
369
375
|
#fact_name.gsub!(/\s/,'')
|
@@ -385,9 +391,8 @@ module ActiveFacts
|
|
385
391
|
raise "Invalid ORM file; fact has missing player (RolePlayer id=#{id})" unless rp
|
386
392
|
ref = rp['ref']
|
387
393
|
|
388
|
-
# Find the
|
389
|
-
|
390
|
-
throw "RolePlayer for '#{name}' #{ref} was not found" if !concept
|
394
|
+
# Find the object_type that plays the role:
|
395
|
+
object_type = @by_id[ref]
|
391
396
|
|
392
397
|
# Skip implicit roles added by NORMA to make unaries into binaries.
|
393
398
|
# This would make constraints over the deleted roles impossible,
|
@@ -406,19 +411,19 @@ module ActiveFacts
|
|
406
411
|
role_name = x['Name']
|
407
412
|
other_role.role_name = role_name if role_name && role_name != ''
|
408
413
|
|
409
|
-
concept.retract # Delete our object for the implicit boolean ValueType
|
410
414
|
@by_id.delete(ref) # and de-index it from our list
|
411
415
|
next
|
412
416
|
end
|
417
|
+
throw "RolePlayer for '#{name}' #{ref} was not found" if !object_type
|
413
418
|
|
414
|
-
debug :orm, "#{@vocabulary.name}, RoleName=#{x['Name'].inspect} played by
|
415
|
-
throw "Role is played by #{
|
419
|
+
debug :orm, "#{@vocabulary.name}, RoleName=#{x['Name'].inspect} played by object_type=#{object_type.name}"
|
420
|
+
throw "Role is played by #{object_type.class} not ObjectType" if !(@constellation.vocabulary.object_type(:ObjectType) === object_type)
|
416
421
|
|
417
|
-
debug :orm, "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.fact_type_id} played by #{
|
422
|
+
debug :orm, "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.fact_type_id} played by #{object_type.name}"
|
418
423
|
|
419
|
-
role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :
|
420
|
-
role.role_name = name if name && name !=
|
421
|
-
debug :orm, "Fact #{fact_name} (id #{fact_type.fact_type_id.object_id}) role #{x['Name']} is played by #{
|
424
|
+
role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :object_type => object_type)
|
425
|
+
role.role_name = name if name && name != object_type.name
|
426
|
+
debug :orm, "Fact #{fact_name} (id #{fact_type.fact_type_id.object_id}) role #{x['Name']} is played by #{object_type.name}, role is #{role.object_id}"
|
422
427
|
|
423
428
|
x_vr = x.xpath("orm:ValueRestriction/orm:RoleValueConstraint")
|
424
429
|
x_vr.each{|vr|
|
@@ -431,7 +436,7 @@ module ActiveFacts
|
|
431
436
|
}
|
432
437
|
}
|
433
438
|
|
434
|
-
debug :orm, "Adding Role #{role.role_name || role.
|
439
|
+
debug :orm, "Adding Role #{role.role_name || role.object_type.name} to #{fact_type.describe}"
|
435
440
|
#fact_type.add_role(role)
|
436
441
|
debug :orm, "Role #{role} is #{id}"
|
437
442
|
}
|
@@ -482,7 +487,7 @@ module ActiveFacts
|
|
482
487
|
#puts "text=#{text.inspect}, la=#{$1.inspect}, ta=#{$2.inspect}" if $1 || $2
|
483
488
|
la = ($1||'').gsub(/\s+/,' ').sub(/-/,'').strip
|
484
489
|
ta = ($2||'').gsub(/\s+/,' ').sub(/-/,'').strip
|
485
|
-
#puts "Setting leading adj #{la.inspect} from #{text.inspect} for #{role_ref.role.
|
490
|
+
#puts "Setting leading adj #{la.inspect} from #{text.inspect} for #{role_ref.role.object_type.name}" if la != ""
|
486
491
|
# REVISIT: Dunno what's up here, but removing the "if" test makes this chuck exceptions:
|
487
492
|
role_ref.leading_adjective = la if la != ""
|
488
493
|
role_ref.trailing_adjective = ta if ta != ""
|
@@ -502,7 +507,7 @@ module ActiveFacts
|
|
502
507
|
if RESERVED_WORDS.include?(w)
|
503
508
|
$stderr.puts "Masking reserved word '#{w}' in reading '#{text}'"
|
504
509
|
next "_#{w}"
|
505
|
-
elsif @constellation.
|
510
|
+
elsif @constellation.ObjectType[[[@vocabulary.name], w]]
|
506
511
|
$stderr.puts "Masking object type name '#{w}' in reading '#{text}'"
|
507
512
|
next "_#{w}"
|
508
513
|
elsif all_role_refs.detect{|rr| rr.role.role_name == w}
|
@@ -519,17 +524,17 @@ module ActiveFacts
|
|
519
524
|
next ''
|
520
525
|
end
|
521
526
|
end
|
522
|
-
$stderr.puts "Elided illegal characters '#{elided}' from reading" unless elided.empty?
|
527
|
+
$stderr.puts "Elided illegal characters '#{elided}' from reading #{text.inspect}" unless elided.empty?
|
523
528
|
text
|
524
529
|
end
|
525
530
|
|
526
531
|
def get_role_sequence(role_array)
|
527
|
-
# puts "Getting RoleSequence [#{role_array.map{|r| "#{r.
|
532
|
+
# puts "Getting RoleSequence [#{role_array.map{|r| "#{r.object_type.name} (role #{r.object_id})" }*", "}]"
|
528
533
|
|
529
534
|
# Look for an existing RoleSequence
|
530
535
|
# REVISIT: This searches all role sequences. Perhaps we could narrow it down first instead?
|
531
536
|
role_sequence = @constellation.RoleSequence.values.detect{|c|
|
532
|
-
#puts "Checking RoleSequence [#{c.all_role_ref.map{|rr| rr.role.
|
537
|
+
#puts "Checking RoleSequence [#{c.all_role_ref.map{|rr| rr.role.object_type.name}*", "}]"
|
533
538
|
role_array == c.all_role_ref.sort_by{|rr| rr.ordinal}.map{|rr| rr.role }
|
534
539
|
}
|
535
540
|
# puts "Found matching RoleSequence!" if role_sequence
|
@@ -558,12 +563,15 @@ module ActiveFacts
|
|
558
563
|
if (x_object.name.to_s == 'ObjectifiedType')
|
559
564
|
x_nests = x_object.xpath('orm:NestedPredicate')[0]
|
560
565
|
implied = x_nests['IsImplied']
|
566
|
+
# x_fact is the fact of which the role player is an objectification, not the fact this role belongs to
|
561
567
|
x_fact = @x_by_id[x_nests['ref']]
|
562
568
|
end
|
563
569
|
|
564
570
|
# This might have been a role of an ImpliedFact, which makes it safe to ignore.
|
565
571
|
next if 'ImpliedFact' == x_role.parent.parent.name
|
566
572
|
|
573
|
+
next if x_role.parent.parent.xpath('orm:DerivationRule').size > 0
|
574
|
+
|
567
575
|
# Talk about why this wasn't found - this shouldn't happen.
|
568
576
|
if (!x_nests || !implied)
|
569
577
|
#puts "="*60
|
@@ -629,7 +637,7 @@ module ActiveFacts
|
|
629
637
|
name = nil if name.size == 0
|
630
638
|
#puts "Residual Mandatory #{name}: #{role_sequence.to_s}"
|
631
639
|
|
632
|
-
if (players = role_sequence.all_role_ref.map{|rr| rr.role.
|
640
|
+
if (players = role_sequence.all_role_ref.map{|rr| rr.role.object_type}).uniq.size > 1
|
633
641
|
join_over, = *ActiveFacts::Metamodel.join_roles_over(role_sequence.all_role_ref.map{|rr| rr.role}, :proximate)
|
634
642
|
raise "Mandatory join constraint #{name} has incompatible players #{players.map{|o| o.name}.inspect}" unless join_over
|
635
643
|
if players.detect{|p| p != join_over}
|
@@ -666,7 +674,7 @@ module ActiveFacts
|
|
666
674
|
x_pi = x.xpath("orm:PreferredIdentifierFor")[0]
|
667
675
|
pi = x_pi ? @by_id[eref = x_pi['ref']] : nil
|
668
676
|
|
669
|
-
# Skip uniqueness constraints on implied
|
677
|
+
# Skip uniqueness constraints on implied object_types
|
670
678
|
next if x_pi && !pi
|
671
679
|
|
672
680
|
# Get the RoleSequence:
|
@@ -680,7 +688,7 @@ module ActiveFacts
|
|
680
688
|
if (fact_types = role_sequence.all_role_ref.map{|rr| rr.role.fact_type}).uniq.size > 1
|
681
689
|
join_over, = *ActiveFacts::Metamodel.join_roles_over(role_sequence.all_role_ref.map{|rr| rr.role}, :counterpart)
|
682
690
|
|
683
|
-
players = role_sequence.all_role_ref.map{|rr| rr.role.
|
691
|
+
players = role_sequence.all_role_ref.map{|rr| rr.role.object_type.name}.uniq
|
684
692
|
raise "Uniqueness join constraint #{name} has incompatible players #{players.inspect}" unless join_over
|
685
693
|
subtyping = players.size > 1 ? 'subtyping ' : ''
|
686
694
|
# REVISIT: Create the Join, the JoinNode for join_over, and steps from each role_ref to join_over
|
@@ -724,7 +732,7 @@ module ActiveFacts
|
|
724
732
|
(role = rr.role) &&
|
725
733
|
(fact_type = role.fact_type) &&
|
726
734
|
fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) &&
|
727
|
-
role.
|
735
|
+
role.object_type == fact_type.supertype &&
|
728
736
|
fact_type.provides_identification
|
729
737
|
|
730
738
|
pc = @constellation.PresenceConstraint(:new)
|
@@ -747,10 +755,10 @@ module ActiveFacts
|
|
747
755
|
end
|
748
756
|
|
749
757
|
def subtype_join_step(join, ti)
|
750
|
-
subtype_node = join.all_join_node.detect{|jn| jn.
|
751
|
-
@constellation.JoinNode(join, join.all_join_node.size, :
|
752
|
-
supertype_node = join.all_join_node.detect{|jn| jn.
|
753
|
-
@constellation.JoinNode(join, join.all_join_node.size, :
|
758
|
+
subtype_node = join.all_join_node.detect{|jn| jn.object_type == ti.subtype } ||
|
759
|
+
@constellation.JoinNode(join, join.all_join_node.size, :object_type => ti.subtype)
|
760
|
+
supertype_node = join.all_join_node.detect{|jn| jn.object_type == ti.supertype } ||
|
761
|
+
@constellation.JoinNode(join, join.all_join_node.size, :object_type => ti.supertype)
|
754
762
|
rs = @constellation.RoleSequence(:new)
|
755
763
|
@constellation.RoleRef(rs, 0, :role => ti.subtype_role)
|
756
764
|
sub_jr = @constellation.JoinRole(subtype_node, ti.subtype_role)
|
@@ -793,8 +801,11 @@ module ActiveFacts
|
|
793
801
|
end_joins = [] # An array of booleans indicating whether any role_sequence requires a subtyping join
|
794
802
|
role_sequences[0].all_role_ref.size.times do |i|
|
795
803
|
role_refs = role_sequences.map{|rs| rs.all_role_ref.detect{|rr| rr.ordinal == i}}
|
796
|
-
|
797
|
-
|
804
|
+
if (fact_types = role_refs.map{|rr| rr.role.fact_type}).uniq.size == 1
|
805
|
+
raise "In #{constraint_type} #{name}, there is a faulty join"
|
806
|
+
next
|
807
|
+
end
|
808
|
+
if (players = role_refs.map{|rr| rr.role.object_type}).uniq.size == 1
|
798
809
|
end_point = players[0]
|
799
810
|
end_joins[i] = false
|
800
811
|
else
|
@@ -805,7 +816,7 @@ module ActiveFacts
|
|
805
816
|
end
|
806
817
|
end_point = common_supertypes[0]
|
807
818
|
|
808
|
-
raise "constrained roles of #{constraint_type} constraint #{name} are incompatible (#{
|
819
|
+
raise "constrained roles of #{constraint_type} constraint #{name} are incompatible (#{players.map(&:name)*', '})" if common_supertypes.size == 0
|
809
820
|
end_joins[i] = true
|
810
821
|
end
|
811
822
|
end_points[i] = end_point
|
@@ -849,7 +860,7 @@ module ActiveFacts
|
|
849
860
|
role_sequences.zip(sequence_join_over||[], sequence_joined_roles||[]).map do |role_sequence, join_over, joined_roles|
|
850
861
|
# Skip if there's no join here (sequence join nor end-point subset join)
|
851
862
|
role_refs = role_sequence.all_role_ref_in_order
|
852
|
-
if !join_over and !role_refs.detect{|rr| rr.role.
|
863
|
+
if !join_over and !role_refs.detect{|rr| rr.role.object_type != end_points[rr.ordinal]}
|
853
864
|
# No sequence join nor end_point join here
|
854
865
|
next
|
855
866
|
end
|
@@ -866,8 +877,9 @@ module ActiveFacts
|
|
866
877
|
|
867
878
|
# Create a join node for the actual end-point (supertype of the constrained roles)
|
868
879
|
end_point = end_points[i]
|
880
|
+
raise "In #{constraint_type} #{name}, there is a faulty join" unless end_point
|
869
881
|
debug :join, "Join Node #{join.all_join_node.size} is for #{end_point.name}"
|
870
|
-
end_node = @constellation.JoinNode(join, join.all_join_node.size, :
|
882
|
+
end_node = @constellation.JoinNode(join, join.all_join_node.size, :object_type => end_point)
|
871
883
|
|
872
884
|
# We're going to rewrite the constraint to constrain the supertype roles, but assume they're the same:
|
873
885
|
role_node = end_node
|
@@ -876,7 +888,7 @@ module ActiveFacts
|
|
876
888
|
# Create subtyping join steps at the end-point, if needed:
|
877
889
|
projecting_jr = nil
|
878
890
|
constrained_join_role = nil
|
879
|
-
if (subtype = role_ref.role.
|
891
|
+
if (subtype = role_ref.role.object_type) != end_point
|
880
892
|
debug :join, "Making subtyping join steps from #{subtype.name} to #{end_point.name}" do
|
881
893
|
# There may be more than one supertyping level. Make the steps:
|
882
894
|
subtyping_steps = subtype_join_steps(join, subtype, end_point)
|
@@ -884,14 +896,14 @@ module ActiveFacts
|
|
884
896
|
constrained_join_role = subtyping_steps[-1].input_join_role
|
885
897
|
|
886
898
|
# Replace the constrained role and node with the supertype ones:
|
887
|
-
end_node = join.all_join_node.detect{|jn| jn.
|
899
|
+
end_node = join.all_join_node.detect{|jn| jn.object_type == end_point }
|
888
900
|
projecting_jr = js.output_join_role
|
889
|
-
end_role = js.fact_type.all_role.detect{|r| r.
|
890
|
-
role_node = join.all_join_node.detect{|jn| jn.
|
901
|
+
end_role = js.fact_type.all_role.detect{|r| r.object_type == end_point }
|
902
|
+
role_node = join.all_join_node.detect{|jn| jn.object_type == role_ref.role.object_type }
|
891
903
|
end
|
892
904
|
end
|
893
905
|
|
894
|
-
raise "Internal error: making illegal reference to join node" if end_role.
|
906
|
+
raise "Internal error: making illegal reference to join node" if end_role.object_type != end_node.object_type
|
895
907
|
rr = @constellation.RoleRef(replacement_rs, replacement_rs.all_role_ref.size, :role => end_role)
|
896
908
|
projecting_jr ||= (constrained_join_role = @constellation.JoinRole(end_node, end_role))
|
897
909
|
projecting_jr.role_ref = rr # Project this RoleRef
|
@@ -899,15 +911,15 @@ module ActiveFacts
|
|
899
911
|
if join_over
|
900
912
|
if !join_node # Create the JoinNode when processing the first role
|
901
913
|
debug :join, "Join Node #{join.all_join_node.size} is over #{join_over.name}"
|
902
|
-
join_node = @constellation.JoinNode(join, join.all_join_node.size, :
|
914
|
+
join_node = @constellation.JoinNode(join, join.all_join_node.size, :object_type => join_over)
|
903
915
|
end
|
904
916
|
debug :join, "Making join step from #{end_point.name} to #{join_over.name}" do
|
905
917
|
rs = @constellation.RoleSequence(:new)
|
906
918
|
# Detect the fact type over which we're joining (may involve objectification)
|
907
|
-
raise "Internal error: making illegal reference to join node" if role_ref.role.
|
919
|
+
raise "Internal error: making illegal reference to join node" if role_ref.role.object_type != role_node.object_type
|
908
920
|
@constellation.RoleRef(rs, 0, :role => role_ref.role)
|
909
921
|
role_jr = @constellation.JoinRole(role_node, role_ref.role)
|
910
|
-
raise "Internal error: making illegal reference to join node" if joined_role.
|
922
|
+
raise "Internal error: making illegal reference to join node" if joined_role.object_type != join_node.object_type
|
911
923
|
@constellation.RoleRef(rs, 1, :role => joined_role)
|
912
924
|
join_jr = @constellation.JoinRole(join_node, joined_role)
|
913
925
|
|
@@ -919,13 +931,13 @@ module ActiveFacts
|
|
919
931
|
if (roles = role_ref.role.fact_type.all_role.to_a).size > 1
|
920
932
|
# Here we have an end join (step already created) but no sequence join
|
921
933
|
if join_node
|
922
|
-
raise "Internal error: making illegal join step" if role_ref.role.
|
934
|
+
raise "Internal error: making illegal join step" if role_ref.role.object_type != role_node.object_type
|
923
935
|
join_jr = @constellation.JoinRole(join_node, join_role)
|
924
936
|
role_jr = @constellation.JoinRole(role_node, role_ref.role)
|
925
937
|
js = @constellation.JoinStep(join_jr, role_jr, :fact_type => role_ref.role.fact_type)
|
926
938
|
roles -= [join_role, role_ref.role]
|
927
939
|
roles.each do |incidental_role|
|
928
|
-
jn = @constellation.JoinNode(join, join.all_join_node.size, :
|
940
|
+
jn = @constellation.JoinNode(join, join.all_join_node.size, :object_type => incidental_role.object_type)
|
929
941
|
jr = @constellation.JoinRole(jn, incidental_role, :join_step => js)
|
930
942
|
end
|
931
943
|
else
|
@@ -941,7 +953,7 @@ module ActiveFacts
|
|
941
953
|
role_ref.role.fact_type.all_role.each do |role|
|
942
954
|
next if role == role_jr.role
|
943
955
|
next if role_sequence.all_role_ref.detect{|rr| rr.role == role}
|
944
|
-
jn = @constellation.JoinNode(join, join.all_join_node.size, :
|
956
|
+
jn = @constellation.JoinNode(join, join.all_join_node.size, :object_type => role.object_type)
|
945
957
|
jr = @constellation.JoinRole(jn, role)
|
946
958
|
if js
|
947
959
|
jr.join_step = js # Incidental role
|
@@ -994,6 +1006,8 @@ module ActiveFacts
|
|
994
1006
|
@mandatory_constraints_by_rs.delete(mc_rs)
|
995
1007
|
end
|
996
1008
|
|
1009
|
+
next if role_sequences.compact.size != role_sequences.size # Role sequence missing; includes a derived fact type role
|
1010
|
+
|
997
1011
|
make_joins('exclusion', name+(x_mandatory ? '/'+x_mandatory['Name'] : ''), role_sequences)
|
998
1012
|
|
999
1013
|
ec = @constellation.SetExclusionConstraint(:new)
|
@@ -1026,6 +1040,7 @@ module ActiveFacts
|
|
1026
1040
|
)
|
1027
1041
|
}
|
1028
1042
|
|
1043
|
+
next if role_sequences.compact.size != role_sequences.size # Role sequence missing; includes a derived fact type role
|
1029
1044
|
make_joins('equality', name, role_sequences)
|
1030
1045
|
|
1031
1046
|
ec = @constellation.SetEqualityConstraint(:new)
|
@@ -1055,6 +1070,7 @@ module ActiveFacts
|
|
1055
1070
|
"equality constraint #{name}"
|
1056
1071
|
)
|
1057
1072
|
}
|
1073
|
+
next if role_sequences.compact.size != role_sequences.size # Role sequence missing; includes a derived fact type role
|
1058
1074
|
make_joins('subset', name, role_sequences)
|
1059
1075
|
|
1060
1076
|
ec = @constellation.SubsetConstraint(:new)
|
@@ -1081,9 +1097,10 @@ module ActiveFacts
|
|
1081
1097
|
map do |xr|
|
1082
1098
|
@by_id[xr['ref']]
|
1083
1099
|
end
|
1084
|
-
|
1100
|
+
next unless from && to # Roles missing; covers a derived fact type
|
1101
|
+
if from.object_type != to.object_type
|
1085
1102
|
join_over, = *ActiveFacts::Metamodel.join_roles_over([from, to], :counterpart)
|
1086
|
-
raise "Ring constraint has incompatible players #{from.
|
1103
|
+
raise "Ring constraint has incompatible players #{from.object_type.name}, #{to.object_type.name}" if !join_over
|
1087
1104
|
debug :join, "join ring constraint over #{join_over.name}"
|
1088
1105
|
end
|
1089
1106
|
rc = @constellation.RingConstraint(:new)
|
@@ -1111,6 +1128,7 @@ module ActiveFacts
|
|
1111
1128
|
role = @by_id[x_roles[0]["ref"]]
|
1112
1129
|
role_sequence = @constellation.RoleSequence(:new)
|
1113
1130
|
role_ref = @constellation.RoleRef(role_sequence, 0, :role => role)
|
1131
|
+
next unless role # Role missing; belongs to a derived fact type
|
1114
1132
|
debug :orm, "FrequencyConstraint(min #{min_frequency.inspect} max #{max_frequency.inspect} over #{role.fact_type.describe(role)} #{id} role ref = #{x_roles[0]["ref"]}"
|
1115
1133
|
@by_id[id] = @constellation.PresenceConstraint(
|
1116
1134
|
:new,
|
@@ -1146,7 +1164,7 @@ module ActiveFacts
|
|
1146
1164
|
vt = @by_id[vt_id]
|
1147
1165
|
throw "ValueType #{vtname} not found" unless vt
|
1148
1166
|
|
1149
|
-
i = @constellation.Instance(:new, :population => population, :
|
1167
|
+
i = @constellation.Instance(:new, :population => population, :object_type => vt, :value => [v.text, is_a_string(v.text), nil])
|
1150
1168
|
@by_id[id] = i
|
1151
1169
|
# show_xmlobj(v)
|
1152
1170
|
}
|
@@ -1175,7 +1193,7 @@ module ActiveFacts
|
|
1175
1193
|
throw "EntityType #{etname} not found" unless et
|
1176
1194
|
end
|
1177
1195
|
|
1178
|
-
instance = @constellation.Instance(:new, :population => population, :
|
1196
|
+
instance = @constellation.Instance(:new, :population => population, :object_type => et, :value => nil)
|
1179
1197
|
@by_id[id] = instance
|
1180
1198
|
debug :orm, "Made new EntityType #{etname}"
|
1181
1199
|
}
|
@@ -1212,7 +1230,7 @@ module ActiveFacts
|
|
1212
1230
|
debug :orm, "For FactType #{ft}" do
|
1213
1231
|
fact = @constellation.Fact(:new, :population => population, :fact_type => ft)
|
1214
1232
|
fact_roles = ft.all_role.map do |role|
|
1215
|
-
if role.
|
1233
|
+
if role.object_type == et
|
1216
1234
|
object = instance
|
1217
1235
|
else
|
1218
1236
|
object = role_instances[role]
|
@@ -1299,7 +1317,7 @@ module ActiveFacts
|
|
1299
1317
|
when 'ObjectTypeShape'
|
1300
1318
|
shape = @constellation.ObjectTypeShape(
|
1301
1319
|
:new, :diagram => diagram, :position => position, :is_expanded => is_expanded,
|
1302
|
-
:
|
1320
|
+
:object_type => subject,
|
1303
1321
|
:has_expanded_reference_mode => false # REVISIT
|
1304
1322
|
)
|
1305
1323
|
else
|
@@ -1350,9 +1368,9 @@ module ActiveFacts
|
|
1350
1368
|
)
|
1351
1369
|
# Create RoleDisplay objects if necessary
|
1352
1370
|
x_role_display = x_shape.xpath("ormDiagram:RoleDisplayOrder/ormDiagram:Role")
|
1353
|
-
# print "Fact type '#{fact_type.preferred_reading.expand}' (#{fact_type.all_role.map{|r|r.
|
1371
|
+
# print "Fact type '#{fact_type.preferred_reading.expand}' (#{fact_type.all_role.map{|r|r.object_type.name}*' '})"
|
1354
1372
|
if x_role_display.size > 0
|
1355
|
-
debug :orm, " has roleDisplay (#{x_role_display.map{|rd| @by_id[rd['ref']].
|
1373
|
+
debug :orm, " has roleDisplay (#{x_role_display.map{|rd| @by_id[rd['ref']].object_type.name}*','})'"
|
1356
1374
|
x_role_display.each_with_index do |rd, ordinal|
|
1357
1375
|
role_display = @constellation.RoleDisplay(shape, ordinal, :role => @by_id[rd['ref']])
|
1358
1376
|
end
|
@@ -4,12 +4,12 @@
|
|
4
4
|
#
|
5
5
|
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
6
|
#
|
7
|
-
# Each Reference from a
|
7
|
+
# Each Reference from a ObjectType creates one or more Columns.
|
8
8
|
# A reference to a simple valuetype creates a single column, as
|
9
9
|
# does a reference to a table entity identified by a single value.
|
10
10
|
#
|
11
|
-
# When referring to a
|
12
|
-
# all references from that
|
11
|
+
# When referring to a object_type that doesn't have its own table,
|
12
|
+
# all references from that object_type are absorbed into this one.
|
13
13
|
#
|
14
14
|
# When multiple values identify an entity that does have its own
|
15
15
|
# table, a reference to that entity creates multiple columns,
|
@@ -63,12 +63,16 @@ module ActiveFacts
|
|
63
63
|
# * If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication
|
64
64
|
# * If we have retained the name of an entity, and this reference is the sole identifying role of an entity, and the identifying object has a name that is prefixed by the name of the object it identifies, remove the prefix and use just the suffix.
|
65
65
|
def name(joiner = "")
|
66
|
+
self.class.name(@references, joiner)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.name(refs, joiner = "")
|
66
70
|
last_names = []
|
67
|
-
names =
|
71
|
+
names = refs.
|
68
72
|
inject([]) do |a, ref|
|
69
73
|
|
70
74
|
# Skip any object after the first which is identified by this reference
|
71
|
-
if ref !=
|
75
|
+
if ref != refs[0] and
|
72
76
|
!ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and
|
73
77
|
ref.to and
|
74
78
|
ref.to.is_a?(ActiveFacts::Metamodel::EntityType) and
|
@@ -99,8 +103,8 @@ module ActiveFacts
|
|
99
103
|
names.shift
|
100
104
|
end
|
101
105
|
|
102
|
-
# If the reference is to the single identifying role of the
|
103
|
-
# strip the
|
106
|
+
# If the reference is to the single identifying role of the object_type making the reference,
|
107
|
+
# strip the object_type name from the start of the reference role
|
104
108
|
if a.size > 0 and
|
105
109
|
(et = ref.from).is_a?(ActiveFacts::Metamodel::EntityType) and
|
106
110
|
# This instead of the next 2 would apply to all identifying roles, but breaks some examples:
|
@@ -209,10 +213,10 @@ module ActiveFacts
|
|
209
213
|
end
|
210
214
|
|
211
215
|
module Metamodel #:nodoc:
|
212
|
-
# The
|
216
|
+
# The ObjectType class is defined in the metamodel; full documentation is not generated.
|
213
217
|
# This section shows the features relevant to relational Persistence.
|
214
|
-
class
|
215
|
-
# The array of columns for this
|
218
|
+
class ObjectType
|
219
|
+
# The array of columns for this ObjectType's table
|
216
220
|
def columns
|
217
221
|
@columns
|
218
222
|
end
|
@@ -225,7 +229,7 @@ module ActiveFacts
|
|
225
229
|
|
226
230
|
# The ValueType class is defined in the metamodel; full documentation is not generated.
|
227
231
|
# This section shows the features relevant to relational Persistence.
|
228
|
-
class ValueType <
|
232
|
+
class ValueType < ObjectType
|
229
233
|
# The identifier_columns for a ValueType can only ever be the self-value role that was injected
|
230
234
|
def identifier_columns
|
231
235
|
debug :columns, "Identifier Columns for #{name}" do
|
@@ -274,7 +278,7 @@ module ActiveFacts
|
|
274
278
|
|
275
279
|
# The EntityType class is defined in the metamodel; full documentation is not generated.
|
276
280
|
# This section shows the features relevant to relational Persistence.
|
277
|
-
class EntityType <
|
281
|
+
class EntityType < ObjectType
|
278
282
|
# The identifier_columns for an EntityType are the columns that result from the identifying roles
|
279
283
|
def identifier_columns
|
280
284
|
debug :columns, "Identifier Columns for #{name}" do
|
@@ -303,7 +307,7 @@ module ActiveFacts
|
|
303
307
|
(all_type_inheritance_as_subtype.size == 0 ||
|
304
308
|
all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
|
305
309
|
rc = absorbed_via.from.reference_columns(excluded_supertypes)
|
306
|
-
# The absorbed_via reference gets skipped here, ans also in
|
310
|
+
# The absorbed_via reference gets skipped here, ans also in object_type.rb
|
307
311
|
debug :columns, "Skipping #{absorbed_via}"
|
308
312
|
#rc.each{|col| col.prepend(absorbed_via)}
|
309
313
|
return rc
|
@@ -363,8 +367,8 @@ module ActiveFacts
|
|
363
367
|
# Make schema transformations like adding ValueType self-value columns (and later, Rails-friendly ID fields).
|
364
368
|
# Override this method to change the transformations
|
365
369
|
def finish_schema
|
366
|
-
|
367
|
-
|
370
|
+
all_object_type.each do |object_type|
|
371
|
+
object_type.self_value_reference if object_type.is_a?(ActiveFacts::Metamodel::ValueType) && object_type.is_table
|
368
372
|
end
|
369
373
|
end
|
370
374
|
|
@@ -373,18 +377,18 @@ module ActiveFacts
|
|
373
377
|
finish_schema
|
374
378
|
|
375
379
|
debug :columns, "Populating all columns" do
|
376
|
-
|
377
|
-
next if !
|
378
|
-
debug :columns, "Populating columns for table #{
|
379
|
-
|
380
|
+
all_object_type.each do |object_type|
|
381
|
+
next if !object_type.is_table
|
382
|
+
debug :columns, "Populating columns for table #{object_type.name}" do
|
383
|
+
object_type.populate_columns
|
380
384
|
end
|
381
385
|
end
|
382
386
|
end
|
383
387
|
debug :columns, "Finished columns" do
|
384
|
-
|
385
|
-
next if !
|
386
|
-
debug :columns, "Finished columns for table #{
|
387
|
-
|
388
|
+
all_object_type.each do |object_type|
|
389
|
+
next if !object_type.is_table
|
390
|
+
debug :columns, "Finished columns for table #{object_type.name}" do
|
391
|
+
object_type.columns.each do |column|
|
388
392
|
debug :columns, "#{column}"
|
389
393
|
end
|
390
394
|
end
|