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