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.
- 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
|