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.
- checksums.yaml +8 -8
- data/Rakefile +0 -8
- data/examples/CQL/CompanyDirectorEmployee.cql +12 -8
- data/examples/CQL/Metamodel.cql +40 -24
- data/examples/CQL/OilSupply.cql +10 -8
- data/examples/CQL/unit.cql +52 -51
- data/lib/activefacts/cql/LexicalRules.treetop +1 -1
- data/lib/activefacts/cql/compiler.rb +1 -1
- data/lib/activefacts/cql/compiler/clause.rb +16 -24
- data/lib/activefacts/cql/compiler/constraint.rb +4 -4
- data/lib/activefacts/cql/compiler/entity_type.rb +16 -16
- data/lib/activefacts/cql/compiler/expression.rb +3 -3
- data/lib/activefacts/cql/compiler/fact.rb +1 -1
- data/lib/activefacts/cql/compiler/fact_type.rb +14 -4
- data/lib/activefacts/cql/compiler/shared.rb +1 -1
- data/lib/activefacts/cql/compiler/value_type.rb +2 -2
- data/lib/activefacts/generate/cql.rb +10 -34
- data/lib/activefacts/generate/helpers/oo.rb +10 -6
- data/lib/activefacts/generate/helpers/ordered.rb +32 -6
- data/lib/activefacts/generate/json.rb +2 -2
- data/lib/activefacts/generate/ruby.rb +7 -15
- data/lib/activefacts/generate/transform/surrogate.rb +7 -7
- data/lib/activefacts/input/orm.rb +23 -26
- data/lib/activefacts/persistence/index.rb +1 -1
- data/lib/activefacts/persistence/reference.rb +5 -2
- data/lib/activefacts/version.rb +3 -3
- data/lib/activefacts/vocabulary/extensions.rb +59 -19
- data/lib/activefacts/vocabulary/metamodel.rb +30 -14
- data/spec/cql/parser/bad_literals_spec.rb +1 -1
- data/spec/cql/parser/expressions_spec.rb +1 -1
- data/spec/cql_dm_spec.rb +15 -0
- data/spec/cql_mysql_spec.rb +1 -1
- data/spec/cqldump_spec.rb +12 -12
- data/spec/norma_cql_spec.rb +0 -1
- data/spec/norma_ruby_sql_spec.rb +3 -2
- data/spec/norma_tables_spec.rb +1 -1
- metadata +78 -127
- data/examples/CQL/JoinEquality.cql +0 -35
- data/examples/CQL/MonthInSeason.cql +0 -23
- data/examples/CQL/Moon.cql +0 -23
- data/examples/CQL/SubtypePI.cql +0 -31
- 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
|
-
|
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
|
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.
|
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
|
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
|
-
|
68
|
-
|
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, :
|
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, :
|
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(:
|
26
|
-
my_role = constellation.Role(:
|
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(:
|
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
|
-
:
|
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
|
-
:
|
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" => "
|
52
|
-
"DoublePrecisionFloatingPointNumeric" => "
|
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, :
|
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, :
|
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, :
|
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, :
|
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, :
|
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, :
|
369
|
-
supertype_role = @by_id[supertype_role_id] = @constellation.Role(inheritance_fact, 1, :object_type => supertype, :
|
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, :
|
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.
|
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
|
-
|
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, :
|
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
|
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!(/(
|
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.
|
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", :
|
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.
|
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.
|
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
|
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
|
-
|
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
|
data/lib/activefacts/version.rb
CHANGED
@@ -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", :
|
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, :
|
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
|
-
|
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, :
|
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
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
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 &&
|
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
|