activefacts 1.0.2 → 1.1.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 +5 -13
- data/Rakefile +2 -2
- data/bin/afgen +1 -1
- data/bin/cql +118 -27
- data/examples/CQL/Insurance.cql +2 -2
- data/examples/CQL/Metamodel.cql +3 -3
- data/examples/CQL/SchoolActivities.cql +1 -1
- data/examples/CQL/Warehousing.cql +5 -4
- data/lib/activefacts/cql.rb +1 -1
- data/lib/activefacts/cql/Language/English.treetop +2 -1
- data/lib/activefacts/cql/compiler.rb +6 -6
- data/lib/activefacts/cql/compiler/clause.rb +69 -46
- data/lib/activefacts/cql/compiler/constraint.rb +14 -14
- data/lib/activefacts/cql/compiler/entity_type.rb +24 -24
- data/lib/activefacts/cql/compiler/fact.rb +40 -27
- data/lib/activefacts/cql/compiler/fact_type.rb +16 -16
- data/lib/activefacts/cql/compiler/query.rb +12 -12
- data/lib/activefacts/cql/compiler/shared.rb +9 -0
- data/lib/activefacts/cql/compiler/value_type.rb +4 -4
- data/lib/activefacts/cql/parser.rb +9 -9
- data/lib/activefacts/generate/cql.rb +41 -20
- data/lib/activefacts/generate/helpers/oo.rb +33 -70
- data/lib/activefacts/generate/helpers/ordered.rb +61 -87
- data/lib/activefacts/generate/ruby.rb +12 -72
- data/lib/activefacts/generate/transform/surrogate.rb +13 -13
- data/lib/activefacts/input/orm.rb +72 -71
- data/lib/activefacts/persistence/columns.rb +66 -31
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +12 -12
- data/lib/activefacts/persistence/object_type.rb +15 -12
- data/lib/activefacts/persistence/reference.rb +20 -18
- data/lib/activefacts/persistence/tables.rb +40 -36
- data/lib/activefacts/support.rb +69 -123
- data/lib/activefacts/version.rb +2 -2
- data/lib/activefacts/vocabulary/extensions.rb +42 -39
- data/lib/activefacts/vocabulary/metamodel.rb +11 -1
- data/lib/activefacts/vocabulary/verbaliser.rb +28 -28
- data/spec/cql/contractions_spec.rb +1 -1
- data/spec/cql/entity_type_spec.rb +1 -1
- data/spec/cql/fact_type_matching_spec.rb +3 -3
- data/spec/cql/role_matching_spec.rb +4 -4
- data/spec/cql/samples_spec.rb +2 -2
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/helpers/array_matcher.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +2 -2
- data/spec/norma_tables_spec.rb +3 -2
- metadata +47 -68
@@ -105,13 +105,13 @@ module ActiveFacts
|
|
105
105
|
|
106
106
|
def loose_bind_wherever_possible
|
107
107
|
# Apply loose binding over applicable roles:
|
108
|
-
|
108
|
+
trace :binding, "Loose binding on #{self.class.name}" do
|
109
109
|
@clauses_lists.each do |clauses_list|
|
110
110
|
clauses_list.each do |clause|
|
111
111
|
clause.refs.each_with_index do |ref, i|
|
112
112
|
next if ref.binding.refs.size > 1
|
113
113
|
# if clause.side_effects && !clause.side_effects.role_side_effects[i].residual_adjectives
|
114
|
-
#
|
114
|
+
# trace :binding, "Discounting #{ref.inspect} as needing loose binding because it has no residual_adjectives"
|
115
115
|
# next
|
116
116
|
# end
|
117
117
|
# This ref didn't match any other ref. Have a scout around for a suitable partner
|
@@ -128,7 +128,7 @@ module ActiveFacts
|
|
128
128
|
}
|
129
129
|
end.map{|k,b| b}
|
130
130
|
next if candidates.size != 1 # Fail
|
131
|
-
|
131
|
+
trace :binding, "Loose binding #{ref.inspect} to #{candidates[0].inspect}"
|
132
132
|
ref.rebind_to(@context, candidates[0].refs[0])
|
133
133
|
end
|
134
134
|
end
|
@@ -138,15 +138,15 @@ module ActiveFacts
|
|
138
138
|
|
139
139
|
def loose_bind
|
140
140
|
# Apply loose binding over applicable @roles:
|
141
|
-
|
141
|
+
trace :binding, "Check for loose bindings on #{@roles.size} roles in #{self.class.name}" do
|
142
142
|
@roles.each do |ref|
|
143
143
|
if ref.binding.refs.size < @clauses_lists.size+1
|
144
|
-
|
144
|
+
trace :binding, "Insufficient bindings for #{ref.inspect} (#{ref.binding.refs.size}, expected #{@clauses_lists.size+1}), attempting loose binding" do
|
145
145
|
@clauses_lists.each do |clauses_list|
|
146
146
|
candidates = []
|
147
147
|
next if clauses_list.
|
148
148
|
detect do |clause|
|
149
|
-
|
149
|
+
trace :binding, "Checking #{clause.inspect}"
|
150
150
|
clause.refs.
|
151
151
|
detect do |vr|
|
152
152
|
already_bound = vr.binding == ref.binding
|
@@ -156,10 +156,10 @@ module ActiveFacts
|
|
156
156
|
already_bound
|
157
157
|
end
|
158
158
|
end
|
159
|
-
|
159
|
+
trace :binding, "Attempting loose binding for #{ref.inspect} in #{clauses_list.inspect}, from the following candidates: #{candidates.inspect}"
|
160
160
|
|
161
161
|
if candidates.size == 1
|
162
|
-
|
162
|
+
trace :binding, "Rebinding #{candidates[0].inspect} to #{ref.inspect}"
|
163
163
|
candidates[0].rebind_to(@context, ref)
|
164
164
|
end
|
165
165
|
end
|
@@ -226,7 +226,7 @@ module ActiveFacts
|
|
226
226
|
:is_mandatory => @quantifier.min && @quantifier.min > 0
|
227
227
|
)
|
228
228
|
@enforcement.compile(@constellation, @constraint) if @enforcement
|
229
|
-
|
229
|
+
trace :constraint, "Made new PC GUID=#{@constraint.concept.guid} min=#{@quantifier.min.inspect} max=#{@quantifier.max.inspect} over #{role_sequence.describe}"
|
230
230
|
super
|
231
231
|
end
|
232
232
|
|
@@ -244,7 +244,7 @@ module ActiveFacts
|
|
244
244
|
clause.refs.select{ |vr| vr.player == ref.player }
|
245
245
|
end.flatten
|
246
246
|
if candidates.size == 1
|
247
|
-
|
247
|
+
trace :binding, "Rebinding #{ref.inspect} to #{candidates[0].inspect} in presence constraint"
|
248
248
|
ref.rebind_to(@context, candidates[0])
|
249
249
|
end
|
250
250
|
end
|
@@ -276,8 +276,8 @@ module ActiveFacts
|
|
276
276
|
clause.includes_literals
|
277
277
|
end
|
278
278
|
|
279
|
-
|
280
|
-
|
279
|
+
trace :query, "Building query for #{clauses_list.inspect}" do
|
280
|
+
trace :query, "Constrained bindings are #{@common_bindings.inspect}"
|
281
281
|
# Every Binding in these clauses becomes a Variable,
|
282
282
|
# and every clause becomes a Step (and a RoleSequence).
|
283
283
|
# The returned RoleSequences contains the RoleRefs for the common_bindings.
|
@@ -301,7 +301,7 @@ module ActiveFacts
|
|
301
301
|
role_sequence = @constellation.RoleSequence(:new)
|
302
302
|
query_bindings = bindings-@common_bindings
|
303
303
|
unless query_bindings.empty? or ignore_trailing_steps && query_bindings.size <= 1
|
304
|
-
|
304
|
+
trace :constraint, "REVISIT: #{self.class}: Ignoring query from #{@common_bindings.inspect} to #{query_bindings.inspect} in #{clauses_list.inspect}"
|
305
305
|
end
|
306
306
|
@common_bindings.each do |binding|
|
307
307
|
roles = clauses_list.
|
@@ -483,7 +483,7 @@ module ActiveFacts
|
|
483
483
|
:ring_type => ring_type
|
484
484
|
)
|
485
485
|
|
486
|
-
|
486
|
+
trace :constraint, "Added #{@constraint.verbalise}"
|
487
487
|
super
|
488
488
|
end
|
489
489
|
|
@@ -122,7 +122,7 @@ module ActiveFacts
|
|
122
122
|
if (pc)
|
123
123
|
pc.is_preferred_identifier = true
|
124
124
|
pc.name = "#{@entity_type.name}PK" unless pc.name
|
125
|
-
|
125
|
+
trace "Existing PC #{pc.verbalise} is now PK for #{@entity_type.name}"
|
126
126
|
else
|
127
127
|
# Add a unique constraint over all identifying roles
|
128
128
|
pc = @constellation.PresenceConstraint(
|
@@ -135,7 +135,7 @@ module ActiveFacts
|
|
135
135
|
#:is_mandatory => true,
|
136
136
|
#:min_frequency => 1,
|
137
137
|
)
|
138
|
-
|
138
|
+
trace :constraint, "Made new preferred PC GUID=#{pc.concept.guid} min=nil max=1 over #{role_sequence.describe}"
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
@@ -183,7 +183,7 @@ module ActiveFacts
|
|
183
183
|
|
184
184
|
operation = any_matched ? 'Objectifying' : 'Creating'
|
185
185
|
player_names = clauses[0].refs.map{|vr| vr.key.compact*'-'}
|
186
|
-
|
186
|
+
trace :matching, "#{operation} fact type for #{clauses.size} clauses over (#{player_names*', '})" do
|
187
187
|
if any_matched # There's an existing fact type we must be objectifying
|
188
188
|
fact_type = objectify_existing_fact_type(existing_clauses[0].fact_type)
|
189
189
|
end
|
@@ -220,7 +220,7 @@ module ActiveFacts
|
|
220
220
|
:is_preferred_identifier => false, # We only get here when there is a reference mode on the entity type
|
221
221
|
:max_frequency => 1
|
222
222
|
)
|
223
|
-
|
223
|
+
trace :constraint, "Made new objectification PC GUID=#{pc.concept.guid} min=nil max=1 over #{fact_type.preferred_reading.role_sequence.describe}"
|
224
224
|
end
|
225
225
|
|
226
226
|
@fact_type = @entity_type.fact_type = fact_type
|
@@ -229,7 +229,7 @@ module ActiveFacts
|
|
229
229
|
end
|
230
230
|
|
231
231
|
def add_supertype(supertype_name, not_identifying)
|
232
|
-
|
232
|
+
trace :supertype, "Adding #{not_identifying ? '' : 'identifying '}supertype #{supertype_name} to #{@entity_type.name}" do
|
233
233
|
supertype = @vocabulary.valid_entity_type_name(supertype_name) ||
|
234
234
|
@constellation.EntityType(@vocabulary, supertype_name, :concept => :new) # Should always already exist
|
235
235
|
|
@@ -275,7 +275,7 @@ module ActiveFacts
|
|
275
275
|
pc1.min_frequency = 1
|
276
276
|
pc1.max_frequency = 1
|
277
277
|
pc1.is_preferred_identifier = false
|
278
|
-
|
278
|
+
trace :constraint, "Made new subtype PC GUID=#{pc1.concept.guid} min=1 max=1 over #{p1rs.describe}"
|
279
279
|
|
280
280
|
p2rs = @constellation.RoleSequence(:new)
|
281
281
|
constellation.RoleRef(p2rs, 0).role = super_role
|
@@ -287,15 +287,15 @@ module ActiveFacts
|
|
287
287
|
pc2.max_frequency = 1
|
288
288
|
# The supertype role often identifies the subtype:
|
289
289
|
pc2.is_preferred_identifier = inheritance_fact.provides_identification
|
290
|
-
|
291
|
-
|
290
|
+
trace :supertype, "identification of #{@entity_type.name} via supertype #{supertype.name} was #{inheritance_fact.provides_identification ? '' : 'not '}added"
|
291
|
+
trace :constraint, "Made new supertype PC GUID=#{pc2.concept.guid} min=1 max=1 over #{p2rs.describe}"
|
292
292
|
end
|
293
293
|
end
|
294
294
|
|
295
295
|
def make_entity_type_refmode_valuetypes(name, mode, parameters)
|
296
296
|
vt_name = "#{name}#{mode}"
|
297
297
|
vt = nil
|
298
|
-
|
298
|
+
trace :entity, "Preparing value type #{vt_name} for reference mode" do
|
299
299
|
# Find an existing ValueType called 'vt_name' or 'name vtname'
|
300
300
|
# or find/create the supertype '#{mode}' and the subtype
|
301
301
|
unless vt = @vocabulary.valid_object_type_name(vt_name) or
|
@@ -309,7 +309,7 @@ module ActiveFacts
|
|
309
309
|
vt.scale = scale if scale
|
310
310
|
end
|
311
311
|
else
|
312
|
-
|
312
|
+
trace :entity, "Value type #{vt_name} already exists"
|
313
313
|
end
|
314
314
|
end
|
315
315
|
|
@@ -363,9 +363,9 @@ module ActiveFacts
|
|
363
363
|
end
|
364
364
|
if rs01.all_reading.empty?
|
365
365
|
@constellation.Reading(fact_type, fact_type.all_reading.size, :role_sequence => rs01, :text => "{0} has {1}", :is_negative => false)
|
366
|
-
|
366
|
+
trace :mode, "Creating new forward reading '#{entity_role.object_type.name} has #{identifying_type.name}'"
|
367
367
|
else
|
368
|
-
|
368
|
+
trace :mode, "Using existing forward reading"
|
369
369
|
end
|
370
370
|
|
371
371
|
# Make a reverse reading if none exists
|
@@ -377,20 +377,20 @@ module ActiveFacts
|
|
377
377
|
end
|
378
378
|
if rs10.all_reading.empty?
|
379
379
|
@constellation.Reading(fact_type, fact_type.all_reading.size, :role_sequence => rs10, :text => "{0} is of {1}", :is_negative => false)
|
380
|
-
|
380
|
+
trace :mode, "Creating new reverse reading '#{identifying_type.name} is of #{entity_role.object_type.name}'"
|
381
381
|
else
|
382
|
-
|
382
|
+
trace :mode, "Using existing reverse reading"
|
383
383
|
end
|
384
384
|
|
385
385
|
# Entity must have one identifying instance. Find or create the role sequence, then create a PC if necessary
|
386
386
|
rs0 = entity_role.all_role_ref.select{|rr| rr.role_sequence.all_role_ref.size == 1}[0]
|
387
387
|
if rs0
|
388
388
|
rs0 = rs0.role_sequence
|
389
|
-
|
389
|
+
trace :mode, "Using existing EntityType role sequence"
|
390
390
|
else
|
391
391
|
rs0 = @constellation.RoleSequence(:new)
|
392
392
|
@constellation.RoleRef(rs0, 0, :role => entity_role)
|
393
|
-
|
393
|
+
trace :mode, "Creating new EntityType role sequence"
|
394
394
|
end
|
395
395
|
if (rs0.all_presence_constraint.size == 0)
|
396
396
|
constraint = @constellation.PresenceConstraint(
|
@@ -403,22 +403,22 @@ module ActiveFacts
|
|
403
403
|
:is_preferred_identifier => false,
|
404
404
|
:is_mandatory => true
|
405
405
|
)
|
406
|
-
|
406
|
+
trace :constraint, "Made new refmode PC GUID=#{constraint.concept.guid} min=1 max=1 over #{rs0.describe}"
|
407
407
|
else
|
408
|
-
|
408
|
+
trace :mode, "Using existing EntityType PresenceConstraint"
|
409
409
|
end
|
410
410
|
|
411
411
|
# Value Type must have a value type. Find or create the role sequence, then create a PC if necessary
|
412
|
-
|
413
|
-
|
412
|
+
trace :mode, "identifying_role has #{identifying_role.all_role_ref.size} attached sequences"
|
413
|
+
trace :mode, "identifying_role has #{identifying_role.all_role_ref.select{|rr| rr.role_sequence.all_role_ref.size == 1}.size} unary sequences"
|
414
414
|
rs1 = identifying_role.all_role_ref.select{|rr| rr.role_sequence.all_role_ref.size == 1 ? rr.role_sequence : nil }.compact[0]
|
415
415
|
if (!rs1)
|
416
416
|
rs1 = @constellation.RoleSequence(:new)
|
417
417
|
@constellation.RoleRef(rs1, 0, :role => identifying_role)
|
418
|
-
|
418
|
+
trace :mode, "Creating new ValueType role sequence"
|
419
419
|
else
|
420
420
|
rs1 = rs1.role_sequence
|
421
|
-
|
421
|
+
trace :mode, "Using existing ValueType role sequence"
|
422
422
|
end
|
423
423
|
if (rs1.all_presence_constraint.size == 0)
|
424
424
|
constraint = @constellation.PresenceConstraint(
|
@@ -431,9 +431,9 @@ module ActiveFacts
|
|
431
431
|
:is_preferred_identifier => true,
|
432
432
|
:is_mandatory => false
|
433
433
|
)
|
434
|
-
|
434
|
+
trace :constraint, "Made new refmode ValueType PC GUID=#{constraint.concept.guid} min=0 max=1 over #{rs1.describe}"
|
435
435
|
else
|
436
|
-
|
436
|
+
trace :mode, "Marking existing ValueType PresenceConstraint as preferred"
|
437
437
|
rs1.all_presence_constraint.single.is_preferred_identifier = true
|
438
438
|
end
|
439
439
|
end
|
@@ -53,7 +53,7 @@ module ActiveFacts
|
|
53
53
|
player = ref.binding.player
|
54
54
|
# raise "A literal may not be an objectification" if ref.role_ref.nested_clauses
|
55
55
|
# raise "Not processing facts involving nested clauses yet" if ref.role_ref
|
56
|
-
|
56
|
+
trace :instance, "Making #{player.class.basename} #{player.name} using #{l.inspect}" do
|
57
57
|
ref.binding.instance = instance_identified_by_literal(player, l)
|
58
58
|
end
|
59
59
|
ref
|
@@ -84,13 +84,15 @@ module ActiveFacts
|
|
84
84
|
# Find the roles of this clause that do not yet have an instance
|
85
85
|
bare_roles = clause.refs.
|
86
86
|
select do |ref|
|
87
|
-
|
88
|
-
next false if ref.literal and
|
87
|
+
if !ref.binding.instance and ref.literal
|
89
88
|
ref.binding.instance = instance_identified_by_literal(ref.binding.player, ref.literal)
|
89
|
+
end
|
90
|
+
|
91
|
+
next false if ref.binding.instance
|
90
92
|
true
|
91
93
|
end
|
92
94
|
|
93
|
-
|
95
|
+
trace :instance, "Considering '#{clause.display}' with "+
|
94
96
|
(bare_roles.empty? ? "no bare roles" : "bare roles: #{bare_roles.map{|ref| ref.player.name}*", "}") do
|
95
97
|
|
96
98
|
# If all the roles are in place, we can bind the rest of this clause:
|
@@ -107,7 +109,7 @@ module ActiveFacts
|
|
107
109
|
end
|
108
110
|
|
109
111
|
return true if progress
|
110
|
-
|
112
|
+
trace :instance, "Can't make progress on '#{clause.display}'"
|
111
113
|
nil
|
112
114
|
end
|
113
115
|
end
|
@@ -118,14 +120,14 @@ module ActiveFacts
|
|
118
120
|
@pass += 1
|
119
121
|
|
120
122
|
progress = false
|
121
|
-
|
123
|
+
trace :instance, "Pass #{@pass} with #{@unbound_clauses.size} clauses to consider" do
|
122
124
|
@unbound_clauses =
|
123
125
|
@unbound_clauses.select do |clause|
|
124
126
|
action = bind_clause(clause)
|
125
127
|
progress = true if action
|
126
128
|
!action
|
127
129
|
end
|
128
|
-
|
130
|
+
trace :instance, "end of pass, unbound clauses are #{@unbound_clauses.map(&:display)*', '}"
|
129
131
|
end # debug
|
130
132
|
progress
|
131
133
|
end
|
@@ -139,35 +141,39 @@ module ActiveFacts
|
|
139
141
|
|
140
142
|
def bind_complete_fact clause
|
141
143
|
return true unless clause.fact_type # An bare objectification
|
142
|
-
|
143
|
-
instances = clause.refs.map{|vr| vr.binding.instance}
|
144
|
-
|
144
|
+
trace :instance, "All bindings in '#{clause.display}' contain instances; assert the fact type"
|
145
|
+
instances = clause.refs.map{|vr| vr.binding.instance }
|
146
|
+
trace :instance, "Instances are #{instances.map{|i| "#{i.verbalise}"}*", "}"
|
145
147
|
|
146
148
|
if e = clause.fact_type.entity_type and
|
147
149
|
clause.refs[0].binding.instance.object_type == e
|
148
150
|
fact = clause.refs[0].binding.instance.fact
|
149
151
|
else
|
150
152
|
# Check that this fact doesn't already exist
|
153
|
+
trace :instance, "Searching for existing fact instance"
|
154
|
+
|
151
155
|
fact = clause.fact_type.all_fact.detect do |f|
|
156
|
+
|
152
157
|
# Get the role values of this fact in the order of the clause we just bound
|
153
158
|
role_values_in_clause_order = f.all_role_value.sort_by do |rv|
|
154
159
|
clause.reading.role_sequence.all_role_ref.detect{|rr| rr.role == rv.role}.ordinal
|
155
160
|
end
|
161
|
+
|
156
162
|
# If all this fact's role values are played by the bound instances, it's the same fact
|
157
163
|
!role_values_in_clause_order.zip(instances).detect{|rv, i| rv.instance != i }
|
158
164
|
end
|
159
165
|
end
|
160
166
|
if fact
|
161
167
|
clause.fact = fact
|
162
|
-
|
168
|
+
trace :instance, "Found existing fact"
|
163
169
|
else
|
170
|
+
trace :instance, "Creating new fact of type #{clause.fact_type.default_reading}"
|
164
171
|
fact =
|
165
172
|
clause.fact =
|
166
173
|
@constellation.Fact(:new, :fact_type => clause.fact_type, :population => @population)
|
167
174
|
@bound_facts << fact
|
168
|
-
|
169
175
|
clause.reading.role_sequence.all_role_ref_in_order.zip(instances).each do |rr, instance|
|
170
|
-
|
176
|
+
trace :instance, "Assigning fact role #{instance.object_type.name} to #{instance.value ? instance.value.inspect : instance.verbalise}"
|
171
177
|
# REVISIT: Any residual adjectives after the fact type matching are lost here.
|
172
178
|
@constellation.RoleValue(:fact => fact, :instance => instance, :role => rr.role, :population => @population)
|
173
179
|
end
|
@@ -176,7 +182,7 @@ module ActiveFacts
|
|
176
182
|
if !fact.instance && clause.fact_type.entity_type
|
177
183
|
# Objectified fact type; create the instance
|
178
184
|
# Create the instance that objectifies this fact. We don't have the binding to assign it to though; that'll happen in our caller
|
179
|
-
|
185
|
+
trace :instance, "Objectifying fact as #{clause.fact_type.entity_type.name}"
|
180
186
|
instance =
|
181
187
|
@constellation.Instance(:new, :object_type => clause.fact_type.entity_type, :fact => fact, :population => @population)
|
182
188
|
@bound_facts << instance
|
@@ -202,14 +208,14 @@ module ActiveFacts
|
|
202
208
|
identifying_instance = identifying_binding.instance
|
203
209
|
preferred_identifier = entity_type.preferred_identifier
|
204
210
|
|
205
|
-
|
211
|
+
trace :instance, "This clause associates a new #{binding.player.name} with a #{identifying_binding.player.name}#{identifying_instance ? " which exists" : ""}"
|
206
212
|
|
207
213
|
identifying_role_ref = preferred_identifier.role_sequence.all_role_ref.detect { |rr|
|
208
214
|
rr.role.fact_type == clause.fact_type && rr.role.object_type == identifying_binding.player
|
209
215
|
}
|
210
216
|
unless identifying_role_ref
|
211
217
|
# This shold never happen; we already bound all refs
|
212
|
-
|
218
|
+
trace :instance, "Failed to find a #{identifying_instance.object_type.name}"
|
213
219
|
return false # We can't do this yet
|
214
220
|
end
|
215
221
|
role_value = identifying_instance.all_role_value.detect do |rv|
|
@@ -217,7 +223,7 @@ module ActiveFacts
|
|
217
223
|
end
|
218
224
|
if role_value
|
219
225
|
instance = (role_value.fact.all_role_value.to_a-[role_value])[0].instance
|
220
|
-
|
226
|
+
trace :instance, "Found an existing instance (of #{instance.object_type.name}) from a previous definition"
|
221
227
|
binding.instance = instance
|
222
228
|
return true # Done with this clause
|
223
229
|
end
|
@@ -240,16 +246,17 @@ module ActiveFacts
|
|
240
246
|
[rr, identifying_clause, identifying_binding, identifying_instance]
|
241
247
|
end
|
242
248
|
if identifiers.detect{ |i| !i[3] } # Not all required facts are bound yet
|
243
|
-
|
249
|
+
trace :instance, "Can't go through with creating #{binding.player.name}; not all the identifying facts are in"
|
244
250
|
return false
|
245
251
|
end
|
246
252
|
|
247
|
-
|
253
|
+
trace :instance, "Creating Entity #{binding.player.name} using #{identifiers.size} roles" do
|
248
254
|
instance = @constellation.Instance(:new, :object_type => entity_type, :population => @population)
|
249
255
|
binding.instance = instance
|
250
256
|
@bound_facts << instance
|
251
257
|
identifiers.each do |rr, identifying_clause, identifying_binding, identifying_instance|
|
252
258
|
# This clause provides the identifying literal for the entity_type
|
259
|
+
trace :instance, "Creating existential fact #{rr.role.fact_type.default_reading} for value #{identifying_instance.value.inspect}"
|
253
260
|
id_fact =
|
254
261
|
identifying_clause.fact =
|
255
262
|
@constellation.Fact(:new, :fact_type => rr.role.fact_type, :population => @population)
|
@@ -267,21 +274,25 @@ module ActiveFacts
|
|
267
274
|
if object_type.is_a?(ActiveFacts::Metamodel::EntityType)
|
268
275
|
entity_identified_by_literal object_type, literal
|
269
276
|
else
|
270
|
-
|
271
|
-
|
277
|
+
trace :instance, "Assert Value #{object_type.name} #{literal.inspect}" do
|
272
278
|
is_literal_string = literal.literal.is_a?(String)
|
273
|
-
|
279
|
+
# REVISIT: Check for subtypes and supertypes also, and promote type if necessary
|
280
|
+
instance = object_type.all_instance.detect do |i|
|
281
|
+
#instance = @constellation.Instance.detect do |key, i|
|
274
282
|
# REVISIT: And same unit
|
283
|
+
trace :instance, "Comparing #{i.value.literal.inspect} to #{literal.literal.inspect}"
|
275
284
|
i.population == @population &&
|
276
285
|
i.value &&
|
277
|
-
i.value.literal == literal &&
|
286
|
+
i.value.literal.inspect == literal.literal.inspect &&
|
278
287
|
i.value.is_literal_string == is_literal_string
|
279
288
|
end
|
280
289
|
#instance = object_type.all_instance.detect { |instance|
|
281
290
|
# instance.population == @population && instance.value == literal
|
282
291
|
#}
|
283
|
-
|
284
|
-
|
292
|
+
if instance
|
293
|
+
trace :instance, "This #{object_type.name} value already exists"
|
294
|
+
else
|
295
|
+
trace :instance, "Creating Value #{object_type.name} #{literal.inspect} #{@population.name.size>0 ? " in "+@population.name.inspect : ''}"
|
285
296
|
instance = @constellation.Instance(:new)
|
286
297
|
instance.object_type = object_type
|
287
298
|
instance.population = @population
|
@@ -296,7 +307,7 @@ module ActiveFacts
|
|
296
307
|
def entity_identified_by_literal object_type, literal
|
297
308
|
# A literal that identifies an entity type means the entity type has only one identifying role
|
298
309
|
# That role is played either by a value type, or by another similarly single-identified entity type
|
299
|
-
|
310
|
+
trace :instance, "Assert Entity #{object_type.name} identified by '#{literal}'" do
|
300
311
|
identifying_role_refs = object_type.preferred_identifier.role_sequence.all_role_ref
|
301
312
|
raise "Single literal cannot satisfy multiple identifying roles for #{object_type.name}" if identifying_role_refs.size > 1
|
302
313
|
role = identifying_role_refs.single.role
|
@@ -312,13 +323,15 @@ module ActiveFacts
|
|
312
323
|
}
|
313
324
|
if instance_rv
|
314
325
|
instance = existing_instance
|
315
|
-
|
326
|
+
trace :instance, "This #{object_type.name} entity already exists"
|
316
327
|
else
|
317
328
|
# This fact has no clause.
|
329
|
+
trace :instance, "Creating implicit existential fact #{role.fact_type.default_reading}"
|
318
330
|
fact = @constellation.Fact(:new, :fact_type => role.fact_type, :population => @population)
|
319
331
|
@bound_facts << fact
|
320
332
|
# This instance will be associated with its binding by our caller
|
321
333
|
instance = @constellation.Instance(:new, :object_type => object_type, :population => @population)
|
334
|
+
trace :instance, "Creating Entity #{object_type.name} identified by '#{literal}' #{@population.name.size>0 ? " in "+@population.name.inspect : ''}"
|
322
335
|
@bound_facts << instance
|
323
336
|
# The identifying fact type has two roles; create both role instances:
|
324
337
|
@constellation.RoleValue(:instance => identifying_instance, :fact => fact, :population => @population, :role => role)
|