activefacts 0.8.18 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +8 -8
  2. data/Rakefile +0 -8
  3. data/examples/CQL/CompanyDirectorEmployee.cql +12 -8
  4. data/examples/CQL/Metamodel.cql +40 -24
  5. data/examples/CQL/OilSupply.cql +10 -8
  6. data/examples/CQL/unit.cql +52 -51
  7. data/lib/activefacts/cql/LexicalRules.treetop +1 -1
  8. data/lib/activefacts/cql/compiler.rb +1 -1
  9. data/lib/activefacts/cql/compiler/clause.rb +16 -24
  10. data/lib/activefacts/cql/compiler/constraint.rb +4 -4
  11. data/lib/activefacts/cql/compiler/entity_type.rb +16 -16
  12. data/lib/activefacts/cql/compiler/expression.rb +3 -3
  13. data/lib/activefacts/cql/compiler/fact.rb +1 -1
  14. data/lib/activefacts/cql/compiler/fact_type.rb +14 -4
  15. data/lib/activefacts/cql/compiler/shared.rb +1 -1
  16. data/lib/activefacts/cql/compiler/value_type.rb +2 -2
  17. data/lib/activefacts/generate/cql.rb +10 -34
  18. data/lib/activefacts/generate/helpers/oo.rb +10 -6
  19. data/lib/activefacts/generate/helpers/ordered.rb +32 -6
  20. data/lib/activefacts/generate/json.rb +2 -2
  21. data/lib/activefacts/generate/ruby.rb +7 -15
  22. data/lib/activefacts/generate/transform/surrogate.rb +7 -7
  23. data/lib/activefacts/input/orm.rb +23 -26
  24. data/lib/activefacts/persistence/index.rb +1 -1
  25. data/lib/activefacts/persistence/reference.rb +5 -2
  26. data/lib/activefacts/version.rb +3 -3
  27. data/lib/activefacts/vocabulary/extensions.rb +59 -19
  28. data/lib/activefacts/vocabulary/metamodel.rb +30 -14
  29. data/spec/cql/parser/bad_literals_spec.rb +1 -1
  30. data/spec/cql/parser/expressions_spec.rb +1 -1
  31. data/spec/cql_dm_spec.rb +15 -0
  32. data/spec/cql_mysql_spec.rb +1 -1
  33. data/spec/cqldump_spec.rb +12 -12
  34. data/spec/norma_cql_spec.rb +0 -1
  35. data/spec/norma_ruby_sql_spec.rb +3 -2
  36. data/spec/norma_tables_spec.rb +1 -1
  37. metadata +78 -127
  38. data/examples/CQL/JoinEquality.cql +0 -35
  39. data/examples/CQL/MonthInSeason.cql +0 -23
  40. data/examples/CQL/Moon.cql +0 -23
  41. data/examples/CQL/SubtypePI.cql +0 -31
  42. data/examples/CQL/Tests.Test5.Load.cql +0 -38
@@ -52,7 +52,7 @@ module ActiveFacts
52
52
  when ActiveFacts::Metamodel::PresenceConstraint
53
53
  fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq # All fact types spanned by this constraint
54
54
  if fact_types.size == 1 # There's only one, save it:
55
- # debug "Single-fact constraint on #{fact_types[0].guid}: #{c.name}"
55
+ # debug "Single-fact constraint on #{fact_types[0].concept.guid}: #{c.name}"
56
56
  (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
57
57
  end
58
58
  when ActiveFacts::Metamodel::RingConstraint
@@ -93,6 +93,26 @@ module ActiveFacts
93
93
  units_end if done_banner
94
94
  end
95
95
 
96
+ def value_type_fork(o)
97
+ if o.name == "_ImplicitBooleanValueType"
98
+ # do nothing
99
+ elsif
100
+ !o.supertype # No supertype, i.e. a base type
101
+ o.all_role.size == 0 && # No roles
102
+ !o.is_independent && # not independent
103
+ !o.value_constraint && # No value constraints
104
+ o.concept.all_context_note_as_relevant_concept.size == 0 && # No context notes
105
+ o.all_instance.size == 0 # No instances
106
+ data_type_dump(o)
107
+ else
108
+ super_type_name = o.supertype ? o.supertype.name : o.name
109
+ length = (l = o.length) && l > 0 ? "#{l}" : nil
110
+ scale = (s = o.scale) && s > 0 ? "#{s}" : nil
111
+ facets = { :length => length, :scale => scale }
112
+ value_type_dump(o, super_type_name, facets)
113
+ end
114
+ end
115
+
96
116
  def value_types_dump
97
117
  done_banner = false
98
118
  @value_type_dumped = {}
@@ -112,7 +132,7 @@ module ActiveFacts
112
132
  def value_type_chain_dump(o)
113
133
  return if @value_type_dumped[o]
114
134
  value_type_chain_dump(o.supertype) if (o.supertype && !@value_type_dumped[o.supertype])
115
- value_type_dump(o) if o.name != "_ImplicitBooleanValueType"
135
+ value_type_fork(o)
116
136
  @value_type_dumped[o] = true
117
137
  end
118
138
 
@@ -306,11 +326,13 @@ module ActiveFacts
306
326
  end
307
327
 
308
328
  def skip_fact_type(f)
329
+ return true if f.is_a?(ActiveFacts::Metamodel::TypeInheritance)
330
+ return false if f.entity_type && !@object_types_dumped[f.entity_type]
331
+
309
332
  # REVISIT: There might be constraints we have to merge into the nested entity or subtype.
310
333
  # These will come up as un-handled constraints:
334
+ # Dump this fact type only if it contains a presence constraint we've missed:
311
335
  pcs = @presence_constraints_by_fact[f]
312
- return true if f.is_a?(ActiveFacts::Metamodel::TypeInheritance)
313
- return false if f.entity_type && !@object_types_dumped[f.entity_type]
314
336
  pcs && pcs.size > 0 && !pcs.detect{|c| !@constraints_used[c] }
315
337
  end
316
338
 
@@ -334,7 +356,7 @@ module ActiveFacts
334
356
 
335
357
  # debug "for fact type #{fact_type.to_s}, considering\n\t#{fact_constraints.map(&:to_s)*",\n\t"}"
336
358
  # debug "#{fact_type.name} has readings:\n\t#{fact_type.readings.map(&:name)*"\n\t"}"
337
- # debug "Dumping #{fact_type.guid} as a fact type"
359
+ # debug "Dumping #{fact_type.concept.guid} as a fact type"
338
360
 
339
361
  # Fact types that aren't nested have no names
340
362
  name = fact_type.entity_type && fact_type.entity_type.name
@@ -531,7 +553,11 @@ module ActiveFacts
531
553
  debug "Should override value_type_end"
532
554
  end
533
555
 
534
- def value_type_dump(o)
556
+ def data_type_dump(o)
557
+ debug "Should override data_type_dump"
558
+ end
559
+
560
+ def value_type_dump(o, super_type_name, facets)
535
561
  debug "Should override value_type_dump"
536
562
  end
537
563
 
@@ -72,7 +72,7 @@ module ActiveFacts
72
72
  if o.fact_type
73
73
  uuid = (uuids[o.fact_type] ||= uuid_from_id(o.fact_type))
74
74
  j[:objectifies] = uuid
75
- j[:implicit] = true if o.is_implied_by_objectification
75
+ j[:implicit] = true if o.concept.implication_rule
76
76
  end
77
77
  if o.all_type_inheritance_as_subtype.size > 0
78
78
  j[:supertypes] = o.
@@ -248,7 +248,7 @@ module ActiveFacts
248
248
  if (c.enforcement)
249
249
  # REVISIT: Deontic constraint
250
250
  end
251
- if (c.all_context_note_as_relevant_concept.size > 0)
251
+ if (c.concept.all_context_note_as_relevant_concept.size > 0)
252
252
  # REVISIT: Context Notes
253
253
  end
254
254
 
@@ -59,25 +59,17 @@ module ActiveFacts
59
59
  end
60
60
  end
61
61
 
62
- def value_type_dump(o)
62
+ def data_type_dump(o)
63
+ value_type_dump(o, o.name, {}) if o.all_role.size > 0
64
+ end
65
+
66
+ def value_type_dump(o, super_type_name, facets)
63
67
  length = (l = o.length) && l > 0 ? ":length => #{l}" : nil
64
68
  scale = (s = o.scale) && s > 0 ? ":scale => #{s}" : nil
65
69
  params = [length,scale].compact * ", "
66
70
 
67
- return if
68
- !o.supertype && # No supertype, i.e. a base type
69
- o.all_role.size == 0 && # No roles
70
- !o.is_independent && # not independent
71
- o.all_instance.size == 0 # No instances
72
-
73
- name = o.name
74
- ruby_type_name =
75
- if o.supertype
76
- o.supertype.name.gsub(/ /,'')
77
- else
78
- o.name.gsub(/ /,'')
79
- end
80
- name = name.sub(/^[a-z]/) {|i| i.upcase}.gsub(/ /,'')
71
+ ruby_type_name = super_type_name.gsub(/ /,'')
72
+ name = o.name.sub(/^[a-z]/) {|i| i.upcase}.gsub(/ /,'')
81
73
  if ruby_type_name == name
82
74
  ruby_type_name = '::'+ruby_type_name
83
75
  end
@@ -14,18 +14,18 @@ module ActiveFacts
14
14
  def add_surrogate type_name = 'Auto Counter', suffix = 'ID'
15
15
  # Find or assert the surrogate value type
16
16
  auto_counter = vocabulary.valid_value_type_name(type_name) ||
17
- constellation.ValueType(:vocabulary => vocabulary, :name => type_name, :guid => :new)
17
+ constellation.ValueType(:vocabulary => vocabulary, :name => type_name, :concept => :new)
18
18
 
19
19
  # Create a subtype to identify this entity type:
20
20
  vt_name = self.name + ' '+suffix
21
21
  my_id = @vocabulary.valid_value_type_name(vt_name) ||
22
- constellation.ValueType(:vocabulary => vocabulary, :name => vt_name, :guid => :new, :supertype => auto_counter)
22
+ constellation.ValueType(:vocabulary => vocabulary, :name => vt_name, :concept => :new, :supertype => auto_counter)
23
23
 
24
24
  # Create a fact type
25
- identifying_fact_type = constellation.FactType(:guid => :new)
26
- my_role = constellation.Role(:guid => :new, :fact_type => identifying_fact_type, :ordinal => 0, :object_type => self)
25
+ identifying_fact_type = constellation.FactType(:concept => :new)
26
+ my_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 0, :object_type => self)
27
27
  @injected_surrogate_role = my_role
28
- id_role = constellation.Role(:guid => :new, :fact_type => identifying_fact_type, :ordinal => 1, :object_type => my_id)
28
+ id_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 1, :object_type => my_id)
29
29
 
30
30
  # Create a reading (which needs a RoleSequence)
31
31
  reading = constellation.Reading(
@@ -39,7 +39,7 @@ module ActiveFacts
39
39
 
40
40
  # Create two uniqueness constraints for the one-to-one. Each needs a RoleSequence (two RoleRefs)
41
41
  one_id = constellation.PresenceConstraint(
42
- :guid => :new,
42
+ :concept => :new,
43
43
  :vocabulary => vocabulary,
44
44
  :name => self.name+'HasOne'+suffix,
45
45
  :role_sequence => [:new],
@@ -51,7 +51,7 @@ module ActiveFacts
51
51
  @constellation.RoleRef(:role_sequence => one_id.role_sequence, :ordinal => 0, :role => my_role)
52
52
 
53
53
  one_me = constellation.PresenceConstraint(
54
- :guid => :new,
54
+ :concept => :new,
55
55
  :vocabulary => vocabulary,
56
56
  :name => self.name+suffix+'IsOfOne'+self.name,
57
57
  :role_sequence => [:new],
@@ -48,8 +48,8 @@ module ActiveFacts
48
48
  "UnsignedLargeIntegerNumeric" => "Unsigned Integer(64)",
49
49
  "AutoCounterNumeric" => "Auto Counter",
50
50
  "FloatingPointNumeric" => "Real(64)",
51
- "SinglePrecisionFloatingPointNumeric" => " Real(32)",
52
- "DoublePrecisionFloatingPointNumeric" => " Real(32)",
51
+ "SinglePrecisionFloatingPointNumeric" => "Real(32)",
52
+ "DoublePrecisionFloatingPointNumeric" => "Real(32)",
53
53
  "DecimalNumeric" => "Decimal",
54
54
  "MoneyNumeric" => "Money",
55
55
  "FixedLengthRawData" => "Blob",
@@ -160,7 +160,7 @@ module ActiveFacts
160
160
  @by_id[id] =
161
161
  debug :orm, "Asserting new EntityType #{name.inspect}" do
162
162
  @vocabulary.valid_entity_type_name(name) ||
163
- @constellation.EntityType(@vocabulary, name, :guid => id_of(x))
163
+ @constellation.EntityType(@vocabulary, name, :concept => id_of(x))
164
164
  end
165
165
  entity_types << entity_type
166
166
  independent = x['IsIndependent']
@@ -233,7 +233,7 @@ module ActiveFacts
233
233
  debug :orm, "Asserting new ValueType #{supertype_name.inspect} for supertype" do
234
234
  value_super_type =
235
235
  @vocabulary.valid_value_type_name(supertype_name) ||
236
- @constellation.ValueType(@vocabulary, supertype_name, :guid => id_of(x_supertype))
236
+ @constellation.ValueType(@vocabulary, supertype_name, :concept => id_of(x_supertype))
237
237
  end
238
238
  else
239
239
  # REVISIT: Need to handle standard types better here:
@@ -241,7 +241,7 @@ module ActiveFacts
241
241
  if type_name != name
242
242
  debug :orm, "Asserting new ValueType #{type_name.inspect} for supertype" do
243
243
  @vocabulary.valid_value_type_name(type_name) ||
244
- @constellation.ValueType(@vocabulary.identifying_role_values, type_name, :guid => :new)
244
+ @constellation.ValueType(@vocabulary.identifying_role_values, type_name, :concept => :new)
245
245
  end
246
246
  else
247
247
  nil
@@ -252,7 +252,7 @@ module ActiveFacts
252
252
  debug :orm, "Asserting new ValueType #{name.inspect}" do
253
253
  @by_id[id] =
254
254
  @vocabulary.valid_value_type_name(name) ||
255
- @constellation.ValueType(@vocabulary.identifying_role_values, name, :guid => id_of(x))
255
+ @constellation.ValueType(@vocabulary.identifying_role_values, name, :concept => id_of(x))
256
256
  end
257
257
  vt.supertype = value_super_type
258
258
  vt.length = length if length
@@ -305,7 +305,6 @@ module ActiveFacts
305
305
  name = "<unnamed>" if !name
306
306
  name = "" if !name || name.size == 0
307
307
  # Note that the new metamodel doesn't have a name for a facttype unless it's objectified
308
- next if x.xpath("orm:DerivationRule").size > 0
309
308
 
310
309
  debug :orm, "FactType #{name || id}"
311
310
  facts << @by_id[id] = fact_type = @constellation.FactType(id_of(x))
@@ -353,7 +352,7 @@ module ActiveFacts
353
352
  next if subtype.kind_of? ActiveFacts::Metamodel::ValueType or
354
353
  supertype.kind_of? ActiveFacts::Metamodel::ValueType
355
354
 
356
- inheritance_fact = @constellation.TypeInheritance(subtype, supertype, :guid => id_of(x))
355
+ inheritance_fact = @constellation.TypeInheritance(subtype, supertype, :concept => id_of(x))
357
356
  if x["IsPrimary"] == "true" or # Old way
358
357
  x["PreferredIdentificationPath"] == "true" # Newer
359
358
  debug :orm, "#{supertype.name} is primary supertype of #{subtype.name}"
@@ -365,8 +364,8 @@ module ActiveFacts
365
364
  facts << @by_id[id] = inheritance_fact
366
365
 
367
366
  # Create the new Roles so we can find constraints on them:
368
- subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :object_type => subtype, :guid => id_of(x_subtype_role))
369
- supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :object_type => supertype, :guid => id_of(x_supertype_role))
367
+ subtype_role = @by_id[subtype_role_id] = @constellation.Role(inheritance_fact, 0, :object_type => subtype, :concept => id_of(x_subtype_role))
368
+ supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :object_type => supertype, :concept => id_of(x_supertype_role))
370
369
 
371
370
  # Create readings, so constraints can be verbalised for example:
372
371
  rs = @constellation.RoleSequence(:new)
@@ -402,17 +401,16 @@ module ActiveFacts
402
401
 
403
402
  fact_id = x_fact_type['ref']
404
403
  fact_type = @by_id[fact_id]
405
- next if x.xpath("orm:DerivationRule").size > 0
406
404
  next unless fact_type # "Nested fact #{fact_id} not found; objectification of a derived fact type?"
407
405
 
408
- debug :orm, "NestedType #{name} is #{id}, nests #{fact_type.guid}"
406
+ debug :orm, "NestedType #{name} is #{id}, nests #{fact_type.concept.guid}"
409
407
  @nested_types <<
410
408
  @by_id[id] =
411
409
  nested_type = @vocabulary.valid_entity_type_name(name) ||
412
- @constellation.EntityType(@vocabulary, name, :guid => id_of(x))
410
+ @constellation.EntityType(@vocabulary, name, :concept => id_of(x))
413
411
  independent = x['IsIndependent']
414
412
  nested_type.is_independent = true if independent && independent == 'true' && !is_implied
415
- nested_type.is_implied_by_objectification = is_implied
413
+ nested_type.concept.implication_rule = 'objectification' if is_implied
416
414
  nested_type.fact_type = fact_type
417
415
  }
418
416
  end
@@ -431,7 +429,6 @@ module ActiveFacts
431
429
  debug :orm, "Reading roles and readings" do
432
430
  @x_facts.each{|x|
433
431
  id = x['id']
434
- next if x.xpath("orm:DerivationRule").size > 0
435
432
  fact_type = @by_id[id]
436
433
  fact_name = x['Name'] || x['_Name'] || ''
437
434
  #fact_name.gsub!(/\s/,'')
@@ -475,16 +472,18 @@ module ActiveFacts
475
472
  @by_id.delete(ref) # and de-index it from our list
476
473
  next
477
474
  end
478
- throw "RolePlayer for '#{name}' #{ref} in fact type #{x.parent.parent['_Name']} was not found" if !object_type
475
+ if !object_type
476
+ throw "RolePlayer for '#{name}' #{ref} in fact type #{x.parent.parent['_Name']} was not found"
477
+ end
479
478
 
480
479
  debug :orm, "#{@vocabulary.name}, RoleName=#{x['Name'].inspect} played by object_type=#{object_type.name}"
481
480
  throw "Role is played by #{object_type.class} not ObjectType" if !(@constellation.vocabulary.object_type(:ObjectType) === object_type)
482
481
 
483
- debug :orm, "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.guid} played by #{object_type.name}"
482
+ debug :orm, "Creating role #{name} nr#{fact_type.all_role.size} of #{fact_type.concept.guid} played by #{object_type.name}"
484
483
 
485
- role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :object_type => object_type, :guid => id_of(x))
484
+ role = @by_id[id] = @constellation.Role(fact_type, fact_type.all_role.size, :object_type => object_type, :concept => id_of(x))
486
485
  role.role_name = name if name && name != object_type.name
487
- debug :orm, "Fact #{fact_name} (id #{fact_type.guid.object_id}) role #{x['Name']} is played by #{object_type.name}, role is #{role.object_id}"
486
+ debug :orm, "Fact #{fact_name} (id #{fact_type.concept.guid}) role #{x['Name']} is played by #{object_type.name}, role is #{role.concept.guid}"
488
487
 
489
488
  x_vr = x.xpath("orm:ValueRestriction/orm:RoleValueConstraint")
490
489
  x_vr.each{|vr|
@@ -571,7 +570,7 @@ module ActiveFacts
571
570
  text.strip!
572
571
  text.downcase! # Check for reserved words and object type names *after* downcasing
573
572
  elided = ''
574
- text.gsub!(/( |-?\b[A-Za-z_][A-Za-z0-9_]*\b-?|\{\d\})|./) do |w|
573
+ text.gsub!(/( |[a-z]+(-[a-z]+)+|-?\b[A-Za-z_][A-Za-z0-9_]*\b-?|\{\d\})|./) do |w|
575
574
  case w
576
575
  when /[A-Za-z]/
577
576
  if RESERVED_WORDS.include?(w)
@@ -599,7 +598,7 @@ module ActiveFacts
599
598
  end
600
599
 
601
600
  def get_role_sequence(role_array)
602
- # puts "Getting RoleSequence [#{role_array.map{|r| "#{r.object_type.name} (role #{r.object_id})" }*", "}]"
601
+ # puts "Getting RoleSequence [#{role_array.map{|r| "#{r.object_type.name} (role #{r.concept.guid})" }*", "}]"
603
602
 
604
603
  # Look for an existing RoleSequence
605
604
  # REVISIT: This searches all role sequences. Perhaps we could narrow it down first instead?
@@ -640,8 +639,6 @@ module ActiveFacts
640
639
  # This might have been a role of an ImpliedFact, which makes it safe to ignore.
641
640
  next if 'ImpliedFact' == x_role.parent.parent.name
642
641
 
643
- next if x_role.parent.parent.xpath('orm:DerivationRule').size > 0
644
-
645
642
  # Talk about why this wasn't found - this shouldn't happen.
646
643
  if (!x_nests || !implied)
647
644
  #puts "="*60
@@ -1236,7 +1233,7 @@ module ActiveFacts
1236
1233
 
1237
1234
  def read_instances
1238
1235
  debug :orm, "Reading sample data" do
1239
- population = @constellation.Population(@vocabulary, "sample", :guid => :new)
1236
+ population = @constellation.Population(@vocabulary, "sample", :concept => :new)
1240
1237
 
1241
1238
  # Value instances first, then entities then facts:
1242
1239
 
@@ -1406,7 +1403,7 @@ module ActiveFacts
1406
1403
  :guid => id_of(x_shape), :orm_diagram => diagram, :location => location, :is_expanded => is_expanded,
1407
1404
  :constraint => subject
1408
1405
  )
1409
- shape.fact_type = subject.role.fact_type
1406
+ shape.fact_type_shape = subject.role.fact_type.all_fact_type_shape.to_a[0]
1410
1407
  when 'ModelNoteShape'
1411
1408
  # REVISIT: Add model notes
1412
1409
  when 'ObjectTypeShape'
@@ -1445,7 +1442,7 @@ module ActiveFacts
1445
1442
  offs_y = -12
1446
1443
  if fact_type.entity_type
1447
1444
  offs_x -= 12
1448
- offs_y -= 9 if !fact_type.entity_type.is_implied_by_objectification
1445
+ offs_y -= 9 if !fact_type.entity_type.concept.implication_rule # .implication_rule_name == 'objectification'
1449
1446
  end
1450
1447
 
1451
1448
  location = convert_location(bounds, Gravity::S, offs_x, offs_y)
@@ -173,7 +173,7 @@ module ActiveFacts
173
173
 
174
174
  debug :index, "All Indices in #{name}:" do
175
175
  @indices = columns_by_unique_constraint.map do |uc, columns_with_ordinal|
176
- debug :index, "Index due to uc #{uc.guid} on #{name} over (#{columns_with_ordinal.sort_by{|onc|onc[0]}.map{|ca| ca[2].name}.inspect})"
176
+ debug :index, "Index due to uc #{uc.concept.guid} on #{name} over (#{columns_with_ordinal.sort_by{|onc|onc[0]}.map{|ca| ca[2].name}.inspect})"
177
177
  columns = columns_with_ordinal.sort_by{|ca| [ca[0,2], ca[2].name]}.map{|ca| ca[2]}
178
178
  absorption_level = columns.map(&:absorption_level).min
179
179
  over = columns[0].references[absorption_level].from
@@ -217,7 +217,7 @@ module ActiveFacts
217
217
  end
218
218
 
219
219
  module Metamodel #:nodoc:
220
- class ObjectType < Concept
220
+ class ObjectType
221
221
  # Say whether the independence of this object is still under consideration
222
222
  # This is used in detecting dependency cycles, such as occurs in the Metamodel
223
223
  attr_accessor :tentative #:nodoc:
@@ -273,7 +273,10 @@ module ActiveFacts
273
273
  all_role.each do |role|
274
274
  # It's possible that this role is in an implicit or derived fact type. Skip it if so.
275
275
  next if role.fact_type.is_a?(LinkFactType) or
276
- role.fact_type.preferred_reading.role_sequence.all_role_ref.to_a[0].play
276
+ # REVISIT: dafuq? Is this looking for a constraint over a derivation? This looks wrong.
277
+ role.fact_type.preferred_reading.role_sequence.all_role_ref.to_a[0].play or
278
+ # This is not yet actually set, and wouldn't handle constraint derivations anyhow:
279
+ role.variable_as_projection
277
280
 
278
281
  populate_reference role
279
282
  end
@@ -6,9 +6,9 @@
6
6
  #
7
7
  module ActiveFacts
8
8
  module Version
9
- MAJOR = 0
10
- MINOR = 8
11
- PATCH = 18
9
+ MAJOR = 1
10
+ MINOR = 0
11
+ PATCH = 0
12
12
 
13
13
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
14
14
  end
@@ -88,6 +88,18 @@ module ActiveFacts
88
88
  preferred_reading.expand(frequency_constraints, define_role_names)
89
89
  end
90
90
 
91
+ # Does any role of this fact type participate in a preferred identifier?
92
+ def is_existential
93
+ return false if all_role.size > 2
94
+ all_role.detect do |role|
95
+ role.all_role_ref.detect do |rr|
96
+ rr.role_sequence.all_presence_constraint.detect do |pc|
97
+ pc.is_preferred_identifier
98
+ end
99
+ end
100
+ end
101
+ end
102
+
91
103
  def internal_presence_constraints
92
104
  all_role.map do |r|
93
105
  r.all_role_ref.map do |rr|
@@ -100,7 +112,7 @@ module ActiveFacts
100
112
 
101
113
  def implicit_boolean_type vocabulary
102
114
  @constellation.ImplicitBooleanValueType[[vocabulary.identifying_role_values, "_ImplicitBooleanValueType"]] ||
103
- @constellation.ImplicitBooleanValueType(vocabulary.identifying_role_values, "_ImplicitBooleanValueType", :guid => :new)
115
+ @constellation.ImplicitBooleanValueType(vocabulary.identifying_role_values, "_ImplicitBooleanValueType", :concept => :new)
104
116
  end
105
117
 
106
118
  # This entity type has just objectified a fact type. Create the necessary ImplicitFactTypes with phantom roles
@@ -111,7 +123,7 @@ module ActiveFacts
111
123
  # We only do it when the unary fact type is not objectified
112
124
  link_fact_type = @constellation.LinkFactType(:new, :implying_role => role)
113
125
  entity_type = @entity_type || implicit_boolean_type(role.object_type.vocabulary)
114
- phantom_role = @constellation.Role(link_fact_type, 0, :object_type => entity_type, :guid => :new)
126
+ phantom_role = @constellation.Role(link_fact_type, 0, :object_type => entity_type, :concept => :new)
115
127
  end
116
128
 
117
129
  def reading_preferably_starting_with_role role, negated = false
@@ -125,6 +137,16 @@ module ActiveFacts
125
137
  def all_role_in_order
126
138
  all_role.sort_by{|r| r.ordinal}
127
139
  end
140
+
141
+ def compatible_readings types_array
142
+ all_reading.select do |reading|
143
+ ok = true
144
+ reading.role_sequence.all_role_ref_in_order.each_with_index do |rr, i|
145
+ ok = false unless types_array[i].include?(rr.role.object_type)
146
+ end
147
+ ok
148
+ end
149
+ end
128
150
  end
129
151
 
130
152
  class Role
@@ -183,6 +205,7 @@ module ActiveFacts
183
205
  end
184
206
 
185
207
  def role_name(separator = "-")
208
+ return 'UNKNOWN' unless role
186
209
  name_array =
187
210
  if role.fact_type.all_role.size == 1
188
211
  if role.fact_type.is_a?(LinkFactType)
@@ -380,12 +403,15 @@ module ActiveFacts
380
403
  #pi = supertype.preferred_identifier
381
404
  #return nil
382
405
  elsif fact_type
406
+ possible_pi = nil
383
407
  fact_type.all_role.each{|role|
384
408
  role.all_role_ref.each{|role_ref|
385
409
  # Discount role sequences that contain roles not in this fact type:
386
410
  next if role_ref.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type != fact_type }
387
411
  role_ref.role_sequence.all_presence_constraint.each{|pc|
388
- next unless pc.is_preferred_identifier and pc.max_frequency == 1
412
+ next unless pc.max_frequency == 1
413
+ possible_pi = pc
414
+ next unless pc.is_preferred_identifier
389
415
  pi = pc
390
416
  break
391
417
  }
@@ -393,6 +419,10 @@ module ActiveFacts
393
419
  }
394
420
  break if pi
395
421
  }
422
+ if !pi && possible_pi
423
+ debug :pi, "Using existing PC as PI for #{name}"
424
+ pi = possible_pi
425
+ end
396
426
  else
397
427
  debug :pi, "No PI found for #{name}"
398
428
  end
@@ -450,7 +480,7 @@ module ActiveFacts
450
480
  fact_type.all_role.map do |role|
451
481
  next if role.link_fact_type # Already exists
452
482
  link_fact_type = @constellation.LinkFactType(:new, :implying_role => role)
453
- phantom_role = @constellation.Role(link_fact_type, 0, :object_type => self, :guid => :new)
483
+ phantom_role = @constellation.Role(link_fact_type, 0, :object_type => self, :concept => :new)
454
484
  # We could create a copy of the visible external role here, but there's no need yet...
455
485
  # Nor is there a need for a presence constraint, readings, etc.
456
486
  link_fact_type
@@ -482,26 +512,35 @@ module ActiveFacts
482
512
 
483
513
  expanded.gsub!(/\{#{i}\}/) do
484
514
  role_ref = role_refs[i]
485
- player = role_ref.role.object_type
486
- role_name = role.role_name
487
- role_name = nil if role_name == ""
488
- if role_name && define_role_names == false
489
- l_adj = t_adj = nil # When using role names, don't add adjectives
490
- end
491
- freq_con = frequency_constraints[i]
492
- freq_con = freq_con.frequency if freq_con && freq_con.is_a?(ActiveFacts::Metamodel::PresenceConstraint)
493
- if freq_con.is_a?(Array)
494
- freq_con, player_name = *freq_con
495
- else
496
- player_name = player.name
497
- end
515
+ if role_ref.role
516
+ player = role_ref.role.object_type
517
+ role_name = role.role_name
518
+ role_name = nil if role_name == ""
519
+ if role_name && define_role_names == false
520
+ l_adj = t_adj = nil # When using role names, don't add adjectives
521
+ end
522
+
523
+ freq_con = frequency_constraints[i]
524
+ freq_con = freq_con.frequency if freq_con && freq_con.is_a?(ActiveFacts::Metamodel::PresenceConstraint)
525
+ if freq_con.is_a?(Array)
526
+ freq_con, player_name = *freq_con
527
+ else
528
+ player_name = player.name
529
+ end
530
+ else
531
+ # We have an unknown role. The reading cannot be correctly expanded
532
+ player_name = "UNKNOWN"
533
+ role_name = nil
534
+ freq_con = nil
535
+ end
536
+
498
537
  literal = literals[i]
499
538
  words = [
500
539
  freq_con ? freq_con : nil,
501
540
  l_adj,
502
541
  define_role_names == false && role_name ? role_name : player_name,
503
542
  t_adj,
504
- define_role_names && role_name && player.name != role_name ? "(as #{role_name})" : nil,
543
+ define_role_names && role_name && player_name != role_name ? "(as #{role_name})" : nil,
505
544
  # Can't have both a literal and a value constraint, but we don't enforce that here:
506
545
  literal ? literal : nil
507
546
  ]
@@ -738,7 +777,7 @@ module ActiveFacts
738
777
  class Query
739
778
  def show
740
779
  steps_shown = {}
741
- debug :query, "Displaying full contents of Query #{guid}" do
780
+ debug :query, "Displaying full contents of Query #{concept.guid}" do
742
781
  all_variable.sort_by{|jn| jn.ordinal}.each do |variable|
743
782
  debug :query, "#{variable.describe}" do
744
783
  variable.all_step.
@@ -820,6 +859,7 @@ module ActiveFacts
820
859
  # This is only used for debugging, from RoleRef#describe
821
860
  class ImplicitReading
822
861
  attr_accessor :fact_type, :text
862
+ attr_reader :is_negative # Never true
823
863
 
824
864
  def initialize(fact_type, text)
825
865
  @fact_type = fact_type