activefacts 0.8.18 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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