activefacts 0.8.9 → 0.8.10

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.
Files changed (120) hide show
  1. data/.gemtest +0 -0
  2. data/Manifest.txt +28 -33
  3. data/Rakefile +11 -12
  4. data/bin/cql +90 -46
  5. data/examples/CQL/Blog.cql +2 -1
  6. data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
  7. data/examples/CQL/Death.cql +1 -1
  8. data/examples/CQL/Diplomacy.cql +9 -9
  9. data/examples/CQL/Genealogy.cql +3 -2
  10. data/examples/CQL/Insurance.cql +10 -7
  11. data/examples/CQL/JoinEquality.cql +2 -2
  12. data/examples/CQL/Marriage.cql +1 -1
  13. data/examples/CQL/Metamodel.cql +73 -53
  14. data/examples/CQL/MetamodelNext.cql +89 -67
  15. data/examples/CQL/OneToOnes.cql +2 -2
  16. data/examples/CQL/ServiceDirector.cql +10 -5
  17. data/examples/CQL/Supervision.cql +3 -3
  18. data/examples/CQL/Tests.Test5.Load.cql +1 -1
  19. data/examples/CQL/Warehousing.cql +4 -2
  20. data/lib/activefacts/cql/CQLParser.treetop +26 -60
  21. data/lib/activefacts/cql/Context.treetop +12 -2
  22. data/lib/activefacts/cql/Expressions.treetop +14 -30
  23. data/lib/activefacts/cql/FactTypes.treetop +165 -110
  24. data/lib/activefacts/cql/Language/English.treetop +167 -54
  25. data/lib/activefacts/cql/LexicalRules.treetop +16 -2
  26. data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
  27. data/lib/activefacts/cql/Terms.treetop +57 -27
  28. data/lib/activefacts/cql/ValueTypes.treetop +39 -13
  29. data/lib/activefacts/cql/compiler.rb +5 -3
  30. data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
  31. data/lib/activefacts/cql/compiler/constraint.rb +178 -275
  32. data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
  33. data/lib/activefacts/cql/compiler/expression.rb +418 -0
  34. data/lib/activefacts/cql/compiler/fact.rb +146 -145
  35. data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
  36. data/lib/activefacts/cql/compiler/join.rb +159 -0
  37. data/lib/activefacts/cql/compiler/shared.rb +51 -23
  38. data/lib/activefacts/cql/compiler/value_type.rb +56 -2
  39. data/lib/activefacts/cql/parser.rb +15 -4
  40. data/lib/activefacts/generate/absorption.rb +7 -7
  41. data/lib/activefacts/generate/cql.rb +100 -37
  42. data/lib/activefacts/generate/oo.rb +28 -51
  43. data/lib/activefacts/generate/ordered.rb +60 -36
  44. data/lib/activefacts/generate/ruby.rb +6 -6
  45. data/lib/activefacts/generate/sql/server.rb +4 -4
  46. data/lib/activefacts/input/orm.rb +71 -53
  47. data/lib/activefacts/persistence.rb +1 -1
  48. data/lib/activefacts/persistence/columns.rb +27 -23
  49. data/lib/activefacts/persistence/foreignkey.rb +6 -6
  50. data/lib/activefacts/persistence/index.rb +17 -17
  51. data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
  52. data/lib/activefacts/persistence/reference.rb +61 -36
  53. data/lib/activefacts/persistence/tables.rb +61 -59
  54. data/lib/activefacts/support.rb +54 -29
  55. data/lib/activefacts/version.rb +1 -1
  56. data/lib/activefacts/vocabulary/extensions.rb +99 -54
  57. data/lib/activefacts/vocabulary/metamodel.rb +43 -37
  58. data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
  59. data/spec/absorption_spec.rb +8 -8
  60. data/spec/cql/comparison_spec.rb +91 -0
  61. data/spec/cql/contractions_spec.rb +251 -0
  62. data/spec/cql/entity_type_spec.rb +319 -0
  63. data/spec/cql/expressions_spec.rb +63 -0
  64. data/spec/cql/fact_type_matching_spec.rb +283 -0
  65. data/spec/cql/french_spec.rb +21 -0
  66. data/spec/cql/parser/bad_literals_spec.rb +86 -0
  67. data/spec/cql/parser/constraints_spec.rb +19 -0
  68. data/spec/cql/parser/entity_types_spec.rb +106 -0
  69. data/spec/cql/parser/expressions_spec.rb +179 -0
  70. data/spec/cql/parser/fact_types_spec.rb +41 -0
  71. data/spec/cql/parser/literals_spec.rb +312 -0
  72. data/spec/cql/parser/pragmas_spec.rb +89 -0
  73. data/spec/cql/parser/value_types_spec.rb +42 -0
  74. data/spec/cql/role_matching_spec.rb +147 -0
  75. data/spec/cql/samples_spec.rb +9 -9
  76. data/spec/cql_cql_spec.rb +1 -1
  77. data/spec/cql_dm_spec.rb +116 -0
  78. data/spec/cql_mysql_spec.rb +1 -1
  79. data/spec/cql_ruby_spec.rb +1 -1
  80. data/spec/cql_sql_spec.rb +3 -3
  81. data/spec/cql_symbol_tables_spec.rb +30 -30
  82. data/spec/cqldump_spec.rb +4 -4
  83. data/spec/helpers/array_matcher.rb +32 -27
  84. data/spec/helpers/diff_matcher.rb +6 -26
  85. data/spec/helpers/file_matcher.rb +41 -32
  86. data/spec/helpers/parse_to_ast_matcher.rb +76 -0
  87. data/spec/helpers/string_matcher.rb +32 -31
  88. data/spec/norma_cql_spec.rb +1 -1
  89. data/spec/norma_ruby_spec.rb +1 -1
  90. data/spec/norma_ruby_sql_spec.rb +1 -1
  91. data/spec/norma_sql_spec.rb +3 -1
  92. data/spec/norma_tables_spec.rb +1 -1
  93. data/spec/ruby_api_spec.rb +23 -0
  94. data/spec/spec_helper.rb +5 -4
  95. metadata +66 -66
  96. data/examples/CQL/OrienteeringER.cql +0 -58
  97. data/lib/activefacts/api.rb +0 -44
  98. data/lib/activefacts/api/concept.rb +0 -410
  99. data/lib/activefacts/api/constellation.rb +0 -128
  100. data/lib/activefacts/api/entity.rb +0 -256
  101. data/lib/activefacts/api/instance.rb +0 -60
  102. data/lib/activefacts/api/instance_index.rb +0 -80
  103. data/lib/activefacts/api/numeric.rb +0 -167
  104. data/lib/activefacts/api/role.rb +0 -80
  105. data/lib/activefacts/api/role_proxy.rb +0 -70
  106. data/lib/activefacts/api/role_values.rb +0 -117
  107. data/lib/activefacts/api/standard_types.rb +0 -87
  108. data/lib/activefacts/api/support.rb +0 -65
  109. data/lib/activefacts/api/value.rb +0 -135
  110. data/lib/activefacts/api/vocabulary.rb +0 -82
  111. data/spec/api/autocounter.rb +0 -82
  112. data/spec/api/constellation.rb +0 -130
  113. data/spec/api/entity_type.rb +0 -103
  114. data/spec/api/instance.rb +0 -461
  115. data/spec/api/roles.rb +0 -124
  116. data/spec/api/value_type.rb +0 -112
  117. data/spec/api_spec.rb +0 -13
  118. data/spec/cql/matching_spec.rb +0 -517
  119. data/spec/cql/unit_spec.rb +0 -394
  120. 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, :concept => subtype)
301
- supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :concept => supertype)
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.concept.name.downcase[0]) ? 1 : 0
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 concept that plays the role:
389
- concept = @by_id[ref]
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 concept=#{concept.name}"
415
- throw "Role is played by #{concept.class} not Concept" if !(@constellation.vocabulary.concept(:Concept) === concept)
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 #{concept.name}"
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, :concept => concept)
420
- role.role_name = name if name && name != concept.name
421
- debug :orm, "Fact #{fact_name} (id #{fact_type.fact_type_id.object_id}) role #{x['Name']} is played by #{concept.name}, role is #{role.object_id}"
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.concept.name} to #{fact_type.describe}"
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.concept.name}" if la != ""
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.Concept[[[@vocabulary.name], w]]
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.concept.name} (role #{r.object_id})" }*", "}]"
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.concept.name}*", "}]"
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.concept}).uniq.size > 1
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 concepts
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.concept.name}.uniq
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.concept == fact_type.supertype &&
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.concept == ti.subtype } ||
751
- @constellation.JoinNode(join, join.all_join_node.size, :concept => ti.subtype)
752
- supertype_node = join.all_join_node.detect{|jn| jn.concept == ti.supertype } ||
753
- @constellation.JoinNode(join, join.all_join_node.size, :concept => ti.supertype)
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
- next if (fact_types = role_refs.map{|rr| rr.role.fact_type}).uniq.size == 1
797
- if (players = role_refs.map{|rr| rr.role.concept}).uniq.size == 1
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 (#{names*', '})" if common_supertypes.size == 0
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.concept != end_points[rr.ordinal]}
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, :concept => end_point)
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.concept) != end_point
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.concept == end_point }
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.concept == end_point }
890
- role_node = join.all_join_node.detect{|jn| jn.concept == role_ref.role.concept }
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.concept != end_node.concept
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, :concept => join_over)
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.concept != role_node.concept
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.concept != join_node.concept
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.concept != role_node.concept
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, :concept => incidental_role.concept)
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, :concept => role.concept)
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
- if from.concept != to.concept
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.concept.name}, #{to.concept.name}" if !join_over
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, :concept => vt, :value => [v.text, is_a_string(v.text), nil])
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, :concept => et, :value => nil)
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.concept == et
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
- :concept => subject,
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.concept.name}*' '})"
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']].concept.name}*','})'"
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
@@ -12,4 +12,4 @@ require 'activefacts/persistence/foreignkey'
12
12
  require 'activefacts/persistence/index'
13
13
 
14
14
  # These extend the API classes with relational awareness:
15
- require 'activefacts/persistence/concept'
15
+ require 'activefacts/persistence/object_type'
@@ -4,12 +4,12 @@
4
4
  #
5
5
  # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
6
  #
7
- # Each Reference from a Concept creates one or more Columns.
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 concept that doesn't have its own table,
12
- # all references from that concept are absorbed into this one.
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 = @references.
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 != @references[0] and
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 concept making the reference,
103
- # strip the concept name from the start of the reference role
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 Concept class is defined in the metamodel; full documentation is not generated.
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 Concept
215
- # The array of columns for this Concept's table
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 < Concept
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 < Concept
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 concept.rb
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
- all_concept.each do |concept|
367
- concept.self_value_reference if concept.is_a?(ActiveFacts::Metamodel::ValueType) && concept.is_table
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
- all_concept.each do |concept|
377
- next if !concept.is_table
378
- debug :columns, "Populating columns for table #{concept.name}" do
379
- concept.populate_columns
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
- all_concept.each do |concept|
385
- next if !concept.is_table
386
- debug :columns, "Finished columns for table #{concept.name}" do
387
- concept.columns.each do |column|
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