activefacts 0.8.16 → 0.8.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Manifest.txt +10 -4
- data/bin/afgen +26 -20
- data/bin/cql +1 -1
- data/css/orm2.css +89 -9
- data/examples/CQL/CompanyDirectorEmployee.cql +4 -4
- data/examples/CQL/Genealogy.cql +5 -5
- data/examples/CQL/Metamodel.cql +121 -91
- data/examples/CQL/MonthInSeason.cql +2 -6
- data/examples/CQL/SeparateSubtype.cql +11 -9
- data/examples/CQL/ServiceDirector.cql +21 -33
- data/examples/CQL/Supervision.cql +0 -3
- data/examples/CQL/WindowInRoomInBldg.cql +10 -4
- data/examples/CQL/unit.cql +1 -1
- data/lib/activefacts.rb +1 -0
- data/lib/activefacts/cql/CQLParser.treetop +5 -1
- data/lib/activefacts/cql/Context.treetop +2 -7
- data/lib/activefacts/cql/Expressions.treetop +2 -2
- data/lib/activefacts/cql/FactTypes.treetop +37 -31
- data/lib/activefacts/cql/Language/English.treetop +21 -4
- data/lib/activefacts/cql/LexicalRules.treetop +59 -1
- data/lib/activefacts/cql/ObjectTypes.treetop +22 -12
- data/lib/activefacts/cql/Terms.treetop +13 -9
- data/lib/activefacts/cql/ValueTypes.treetop +30 -11
- data/lib/activefacts/cql/compiler.rb +34 -5
- data/lib/activefacts/cql/compiler/clause.rb +207 -116
- data/lib/activefacts/cql/compiler/constraint.rb +129 -105
- data/lib/activefacts/cql/compiler/entity_type.rb +49 -27
- data/lib/activefacts/cql/compiler/expression.rb +71 -42
- data/lib/activefacts/cql/compiler/fact.rb +70 -64
- data/lib/activefacts/cql/compiler/fact_type.rb +108 -57
- data/lib/activefacts/cql/compiler/query.rb +178 -0
- data/lib/activefacts/cql/compiler/shared.rb +13 -12
- data/lib/activefacts/cql/compiler/value_type.rb +10 -4
- data/lib/activefacts/cql/nodes.rb +1 -1
- data/lib/activefacts/cql/parser.rb +6 -2
- data/lib/activefacts/generate/absorption.rb +6 -3
- data/lib/activefacts/generate/cql.rb +140 -84
- data/lib/activefacts/generate/dm.rb +12 -6
- data/lib/activefacts/generate/help.rb +25 -6
- data/lib/activefacts/generate/helpers/oo.rb +195 -0
- data/lib/activefacts/generate/helpers/ordered.rb +589 -0
- data/lib/activefacts/generate/helpers/rails.rb +57 -0
- data/lib/activefacts/generate/html/glossary.rb +274 -54
- data/lib/activefacts/generate/json.rb +25 -22
- data/lib/activefacts/generate/null.rb +1 -0
- data/lib/activefacts/generate/rails/models.rb +244 -0
- data/lib/activefacts/generate/rails/schema.rb +185 -0
- data/lib/activefacts/generate/records.rb +1 -0
- data/lib/activefacts/generate/ruby.rb +51 -30
- data/lib/activefacts/generate/sql/mysql.rb +5 -3
- data/lib/activefacts/generate/sql/server.rb +8 -4
- data/lib/activefacts/generate/text.rb +1 -0
- data/lib/activefacts/generate/transform/surrogate.rb +209 -0
- data/lib/activefacts/generate/version.rb +1 -0
- data/lib/activefacts/input/orm.rb +234 -181
- data/lib/activefacts/mapping/rails.rb +122 -0
- data/lib/activefacts/persistence/columns.rb +34 -18
- data/lib/activefacts/persistence/foreignkey.rb +129 -71
- data/lib/activefacts/persistence/index.rb +42 -12
- data/lib/activefacts/persistence/reference.rb +37 -23
- data/lib/activefacts/persistence/tables.rb +53 -19
- data/lib/activefacts/registry.rb +11 -0
- data/lib/activefacts/support.rb +28 -10
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +246 -117
- data/lib/activefacts/vocabulary/metamodel.rb +105 -65
- data/lib/activefacts/vocabulary/verbaliser.rb +226 -194
- data/spec/absorption_spec.rb +1 -0
- data/spec/cql/comparison_spec.rb +8 -8
- data/spec/cql/contractions_spec.rb +16 -43
- data/spec/cql/entity_type_spec.rb +2 -1
- data/spec/cql/expressions_spec.rb +2 -2
- data/spec/cql/fact_type_matching_spec.rb +4 -1
- data/spec/cql/parser/bad_literals_spec.rb +30 -30
- data/spec/cql/parser/entity_types_spec.rb +6 -6
- data/spec/cql/parser/expressions_spec.rb +25 -19
- data/spec/cql/samples_spec.rb +5 -4
- data/spec/cql_cql_spec.rb +2 -1
- data/spec/cql_dm_spec.rb +4 -0
- data/spec/cql_mysql_spec.rb +4 -0
- data/spec/cql_parse_spec.rb +2 -0
- data/spec/cql_ruby_spec.rb +4 -0
- data/spec/cql_sql_spec.rb +4 -0
- data/spec/cqldump_spec.rb +7 -4
- data/spec/helpers/parse_to_ast_matcher.rb +7 -3
- data/spec/helpers/test_parser.rb +2 -0
- data/spec/norma_cql_spec.rb +5 -2
- data/spec/norma_ruby_spec.rb +4 -1
- data/spec/norma_ruby_sql_spec.rb +4 -1
- data/spec/norma_sql_spec.rb +4 -1
- data/spec/norma_tables_spec.rb +2 -2
- data/spec/ruby_api_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/transform_surrogate_spec.rb +59 -0
- metadata +70 -60
- data/TODO +0 -308
- data/lib/activefacts/cql/compiler/join.rb +0 -162
- data/lib/activefacts/generate/oo.rb +0 -176
- data/lib/activefacts/generate/ordered.rb +0 -602
@@ -54,13 +54,13 @@ module ActiveFacts
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# An array of the names of the columns this index covers
|
57
|
-
def column_names(
|
58
|
-
columns.map{|column| column.name(
|
57
|
+
def column_names(separator = "")
|
58
|
+
columns.map{|column| column.name(separator)}
|
59
59
|
end
|
60
60
|
|
61
61
|
# An array of the names of the columns this index covers, with some lexical truncations.
|
62
|
-
def abbreviated_column_names(
|
63
|
-
columns.map{|column| column.name(
|
62
|
+
def abbreviated_column_names(separator = "")
|
63
|
+
columns.map{|column| column.name(separator).sub(/^#{over.name}/,'')}
|
64
64
|
end
|
65
65
|
|
66
66
|
# The name of a view that can be created to enforce uniqueness over non-null key values
|
@@ -69,18 +69,43 @@ module ActiveFacts
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def to_s #:nodoc:
|
72
|
-
|
72
|
+
if @uniqueness_constraint
|
73
|
+
name = @uniqueness_constraint.name
|
74
|
+
preferred = @uniqueness_constraint.is_preferred_identifier ? " (preferred)" : ""
|
75
|
+
else
|
76
|
+
name = "#{@on.name}IsUnique"
|
77
|
+
preferred = !@on.injected_surrogate_role ? " (preferred)" : ""
|
78
|
+
end
|
73
79
|
colnames = @columns.map(&:name)*", "
|
74
|
-
preferred = @uniqueness_constraint.is_preferred_identifier ? " (preferred)" : ""
|
75
80
|
"Index #{name} on #{@on.name} over #{@over.name}(#{colnames})#{preferred}"
|
76
81
|
end
|
77
82
|
end
|
78
83
|
end
|
79
84
|
|
80
85
|
module Metamodel #:nodoc:
|
86
|
+
class EntityType
|
87
|
+
def self_index
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class ValueType
|
93
|
+
def self_index
|
94
|
+
ActiveFacts::Persistence::Index.new(
|
95
|
+
nil, # The implied uniqueness constraint is not created
|
96
|
+
self, # ValueType being indexed
|
97
|
+
self, # Absorbed object being indexed
|
98
|
+
columns.select{|c| c.references[0].is_self_value},
|
99
|
+
injected_surrogate_role ? false : true
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
81
104
|
class ObjectType
|
82
105
|
# An array of each Index for this table
|
83
|
-
def indices
|
106
|
+
def indices
|
107
|
+
@indices || populate_indices
|
108
|
+
end
|
84
109
|
|
85
110
|
def clear_indices #:nodoc:
|
86
111
|
# Clear any previous indices
|
@@ -100,7 +125,7 @@ module ActiveFacts
|
|
100
125
|
# order of the columns, not the same as the columns in the PK for which they might be an FK.
|
101
126
|
all_column_by_ref_path =
|
102
127
|
debug :index2, "Indexing columns by ref_path" do
|
103
|
-
|
128
|
+
columns.inject({}) do |hash, column|
|
104
129
|
debug :index2, "References in column #{name}.#{column.name}" do
|
105
130
|
ref_path = column.absorption_references
|
106
131
|
raise "No absorption_references for #{column.name} from #{column.references.map(&:to_s)*" and "}" if !ref_path || ref_path.empty?
|
@@ -118,10 +143,10 @@ module ActiveFacts
|
|
118
143
|
inject({}) do |hash, ref_path|
|
119
144
|
ref_path.each do |ref|
|
120
145
|
next unless ref.to_role
|
121
|
-
#debug :index2, "Considering #{ref_path.map(&:to_s)*" and "} yielding columns #{all_column_by_ref_path[ref_path].map{|c| c.name(
|
146
|
+
# debug :index2, "Considering #{ref_path.map(&:to_s)*" and "} yielding columns #{all_column_by_ref_path[ref_path].map{|c| c.name('.')}*", "}"
|
122
147
|
ref.to_role.all_role_ref.each do |role_ref|
|
123
148
|
all_pcs = role_ref.role_sequence.all_presence_constraint
|
124
|
-
|
149
|
+
# puts "pcs over #{ref_path.map{|r| r.to_names}.flatten*'.'}: #{role_ref.role_sequence.all_presence_constraint.map(&:describe)*"; "}" if all_pcs.size > 0
|
125
150
|
pcs = all_pcs.
|
126
151
|
reject do |pc|
|
127
152
|
!pc.max_frequency or # No maximum freq; cannot be a uniqueness constraint
|
@@ -148,16 +173,18 @@ module ActiveFacts
|
|
148
173
|
|
149
174
|
debug :index, "All Indices in #{name}:" do
|
150
175
|
@indices = columns_by_unique_constraint.map do |uc, columns_with_ordinal|
|
151
|
-
|
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})"
|
152
177
|
columns = columns_with_ordinal.sort_by{|ca| [ca[0,2], ca[2].name]}.map{|ca| ca[2]}
|
153
178
|
absorption_level = columns.map(&:absorption_level).min
|
154
179
|
over = columns[0].references[absorption_level].from
|
155
180
|
|
156
181
|
# Absorption through a one-to-one forms a UC that we don't need to enforce using an index:
|
157
|
-
|
182
|
+
if over != self and
|
158
183
|
over.absorbed_via == columns[0].references[absorption_level-1] and
|
159
184
|
(rr = uc.role_sequence.all_role_ref.single) and
|
160
185
|
over.absorbed_via.fact_type.all_role.include?(rr.role)
|
186
|
+
next nil
|
187
|
+
end
|
161
188
|
|
162
189
|
index = ActiveFacts::Persistence::Index.new(
|
163
190
|
uc,
|
@@ -175,6 +202,9 @@ module ActiveFacts
|
|
175
202
|
index.columns.map(&:name)+['', index.over.name]
|
176
203
|
end
|
177
204
|
end
|
205
|
+
si = self_index
|
206
|
+
@indices.unshift(si) if si
|
207
|
+
@indices
|
178
208
|
end
|
179
209
|
|
180
210
|
end
|
@@ -39,9 +39,11 @@ module ActiveFacts
|
|
39
39
|
attr_reader :from, :to # A "from" instance is related to one "to" instance
|
40
40
|
attr_reader :from_role, :to_role # For objectified facts, one role will be nil (a phantom)
|
41
41
|
attr_reader :fact_type
|
42
|
+
attr_accessor :fk_jump # True if this reference links a table to another in an FK (between absorbed references)
|
42
43
|
|
43
44
|
# A Reference is created from a object_type in regard to a role it plays
|
44
45
|
def initialize(from, role)
|
46
|
+
@fk_jump = false
|
45
47
|
@from = from
|
46
48
|
return unless role # All done if it's a self-value reference for a ValueType
|
47
49
|
@fact_type = role.fact_type
|
@@ -73,7 +75,6 @@ module ActiveFacts
|
|
73
75
|
# Is this Reference covered by a mandatory constraint (implicitly or explicitly)
|
74
76
|
def is_mandatory
|
75
77
|
!@from_role || # All phantom roles of fact types are mandatory
|
76
|
-
is_unary || # Unary fact types become booleans, which must be true or false
|
77
78
|
@from_role.is_mandatory
|
78
79
|
end
|
79
80
|
|
@@ -111,10 +112,10 @@ module ActiveFacts
|
|
111
112
|
end
|
112
113
|
|
113
114
|
# Return the array of names for the (perhaps implicit) *to_role* of this Reference
|
114
|
-
def to_names
|
115
|
+
def to_names(is_prefix = true)
|
115
116
|
case
|
116
117
|
when is_unary
|
117
|
-
if @to && @to.fact_type
|
118
|
+
if @to && @to.fact_type && is_prefix
|
118
119
|
@to.name.camelwords
|
119
120
|
else
|
120
121
|
@to_role.fact_type.preferred_reading.text.gsub(/\{[0-9]\}/,'').strip.camelwords
|
@@ -134,14 +135,14 @@ module ActiveFacts
|
|
134
135
|
# Return the array of names for the (perhaps implicit) *from_role* of this Reference
|
135
136
|
def from_names
|
136
137
|
case
|
138
|
+
when @from && !@from_role # @from is an objectified fact type so @from_role is a phantom
|
139
|
+
@from.name.camelwords
|
137
140
|
when is_unary
|
138
141
|
if @from && @from.fact_type
|
139
142
|
@from.name.camelwords
|
140
143
|
else
|
141
144
|
@from_role.fact_type.preferred_reading.text.gsub(/\{[0-9]\}/,'').strip.camelwords
|
142
145
|
end
|
143
|
-
when @from && !@from_role # @from is an objectified fact type so @from_role is a phantom
|
144
|
-
@from.name.camelwords
|
145
146
|
when !@from_role # Self-value role of an independent ValueType
|
146
147
|
@from.name.camelwords + ["Value"]
|
147
148
|
when @from_role.role_name # Named role
|
@@ -152,12 +153,21 @@ module ActiveFacts
|
|
152
153
|
end
|
153
154
|
end
|
154
155
|
|
156
|
+
def is_one_to_one
|
157
|
+
[:one_one, :subtype, :supertype].include?(role_type)
|
158
|
+
end
|
159
|
+
|
155
160
|
# For a one-to-one (or a subtyping fact type), reverse the direction.
|
156
161
|
def flip #:nodoc:
|
157
|
-
raise "Illegal flip of #{self}" unless @to and
|
162
|
+
raise "Illegal flip of #{self}" unless @to and is_one_to_one
|
158
163
|
|
159
164
|
detabulate
|
165
|
+
mirror
|
166
|
+
tabulate
|
167
|
+
end
|
160
168
|
|
169
|
+
# Create a (non-tabulated) flipped version of this Reference. Careful not to tabulate it!
|
170
|
+
def mirror
|
161
171
|
if @to.absorbed_via == self
|
162
172
|
@to.absorbed_via = nil
|
163
173
|
@from.absorbed_via = self
|
@@ -166,8 +176,11 @@ module ActiveFacts
|
|
166
176
|
# Flip the reference
|
167
177
|
@to, @from = @from, @to
|
168
178
|
@to_role, @from_role = @from_role, @to_role
|
179
|
+
self
|
180
|
+
end
|
169
181
|
|
170
|
-
|
182
|
+
def reversed
|
183
|
+
clone.mirror
|
171
184
|
end
|
172
185
|
|
173
186
|
def tabulate #:nodoc:
|
@@ -188,7 +201,8 @@ module ActiveFacts
|
|
188
201
|
end
|
189
202
|
|
190
203
|
def to_s #:nodoc:
|
191
|
-
|
204
|
+
ref_type = fk_jump ? "jumping to" : (is_absorbing ? "absorbing" : "to")
|
205
|
+
"reference from #{@from.name}#{@to ? " #{ref_type} #{@to.name}" : ""}" + (@fact_type ? " in '#{@fact_type.default_reading}'" : "")
|
192
206
|
end
|
193
207
|
|
194
208
|
# The reading for the fact type underlying this Reference
|
@@ -258,8 +272,8 @@ module ActiveFacts
|
|
258
272
|
def populate_references #:nodoc:
|
259
273
|
all_role.each do |role|
|
260
274
|
# It's possible that this role is in an implicit or derived fact type. Skip it if so.
|
261
|
-
next if role.fact_type.is_a?(
|
262
|
-
role.fact_type.preferred_reading.role_sequence.all_role_ref.to_a[0].
|
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
|
263
277
|
|
264
278
|
populate_reference role
|
265
279
|
end
|
@@ -296,7 +310,6 @@ module ActiveFacts
|
|
296
310
|
end
|
297
311
|
|
298
312
|
when :subtype # This object is a supertype, which can absorb the subtype unless that's independent
|
299
|
-
raise hell unless role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
300
313
|
if role.fact_type.assimilation
|
301
314
|
ActiveFacts::Persistence::Reference.new(self, role).tabulate
|
302
315
|
# If partitioned, the supertype is absorbed into *each* subtype; a reference to the supertype needs to know which
|
@@ -351,7 +364,7 @@ module ActiveFacts
|
|
351
364
|
end
|
352
365
|
end
|
353
366
|
|
354
|
-
class EntityType <
|
367
|
+
class EntityType < DomainObjectType
|
355
368
|
def populate_references #:nodoc:
|
356
369
|
if fact_type && fact_type.all_role.size > 1
|
357
370
|
# NOT: fact_type.all_role.each do |role| # Place roles in the preferred order instead:
|
@@ -366,23 +379,24 @@ module ActiveFacts
|
|
366
379
|
class Vocabulary
|
367
380
|
def populate_all_references #:nodoc:
|
368
381
|
debug :references, "Populating all object_type references" do
|
369
|
-
all_object_type.each do |object_type|
|
370
|
-
object_type.clear_references
|
371
|
-
object_type.is_table = nil # Undecided; force an attempt to decide
|
372
|
-
object_type.tentative = true # Uncertain
|
373
|
-
end
|
374
382
|
all_object_type.each do |object_type|
|
375
383
|
debug :references, "Populating references for #{object_type.name}" do
|
376
384
|
object_type.populate_references
|
377
385
|
end
|
378
386
|
end
|
379
387
|
end
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
388
|
+
show_all_references
|
389
|
+
end
|
390
|
+
|
391
|
+
def show_all_references
|
392
|
+
if debug :references
|
393
|
+
debug :references, "Finished object_type references" do
|
394
|
+
all_object_type.each do |object_type|
|
395
|
+
next unless object_type.references_from.size > 0
|
396
|
+
debug :references, "#{object_type.name}:" do
|
397
|
+
object_type.references_from.each do |ref|
|
398
|
+
debug :references, "#{ref}"
|
399
|
+
end
|
386
400
|
end
|
387
401
|
end
|
388
402
|
end
|
@@ -17,7 +17,7 @@ require 'activefacts/persistence/reference'
|
|
17
17
|
module ActiveFacts
|
18
18
|
module Metamodel
|
19
19
|
|
20
|
-
class ValueType <
|
20
|
+
class ValueType < DomainObjectType
|
21
21
|
def absorbed_via #:nodoc:
|
22
22
|
# ValueTypes aren't absorbed in the way EntityTypes are
|
23
23
|
nil
|
@@ -35,7 +35,7 @@ module ActiveFacts
|
|
35
35
|
end
|
36
36
|
|
37
37
|
# Only a table if it has references (to another ValueType)
|
38
|
-
if !references_from.empty?
|
38
|
+
if !references_from.empty? && !is_auto_assigned
|
39
39
|
debug :absorption, "#{name} is a table because it has #{references_from.size} references to it"
|
40
40
|
@is_table = true
|
41
41
|
else
|
@@ -55,7 +55,7 @@ module ActiveFacts
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
class EntityType <
|
58
|
+
class EntityType < DomainObjectType
|
59
59
|
# A Reference from an entity type that fully absorbs this one
|
60
60
|
def absorbed_via; @absorbed_via; end
|
61
61
|
def absorbed_via=(r) #:nodoc:
|
@@ -85,12 +85,25 @@ module ActiveFacts
|
|
85
85
|
return @is_table = true
|
86
86
|
end
|
87
87
|
|
88
|
-
# Subtypes
|
89
|
-
#
|
88
|
+
# Subtypes may be partitioned or separate, in which case they're definitely tables.
|
89
|
+
# Otherwise, if their identification is inherited from a supertype, they're definitely absorbed.
|
90
|
+
# If theey have separate identification, it might absorb them.
|
90
91
|
if (!supertypes.empty?)
|
91
92
|
as_ti = all_supertype_inheritance.detect{|ti| ti.assimilation}
|
92
|
-
|
93
|
-
|
93
|
+
@is_table = as_ti != nil
|
94
|
+
if @is_table
|
95
|
+
debug :absorption, "EntityType #{name} is #{as_ti.assimilation} from supertype #{as_ti.supertype}"
|
96
|
+
else
|
97
|
+
identifying_fact_type = preferred_identifier.role_sequence.all_role_ref.to_a[0].role.fact_type
|
98
|
+
if identifying_fact_type.is_a?(TypeInheritance)
|
99
|
+
debug :absorption, "EntityType #{name} is absorbed into supertype #{supertypes[0].name}"
|
100
|
+
@is_table = false
|
101
|
+
else
|
102
|
+
# Possibly absorbed, we'll have to see how that pans out
|
103
|
+
@tentative = true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return @is_table
|
94
107
|
end
|
95
108
|
|
96
109
|
# If the preferred_identifier includes an auto_assigned ValueType
|
@@ -168,12 +181,20 @@ module ActiveFacts
|
|
168
181
|
end
|
169
182
|
|
170
183
|
def self.relational_transform &block
|
171
|
-
# Add this block to the additional transformations which
|
184
|
+
# Add this block to the additional transformations which will be applied
|
172
185
|
# to the relational schema after the initial absorption.
|
173
186
|
# For example, to perform injection of surrogate keys to replace composite keys...
|
174
187
|
@@relational_transforms << block
|
175
188
|
end
|
176
189
|
|
190
|
+
def wipe_existing_mapping
|
191
|
+
all_object_type.each do |object_type|
|
192
|
+
object_type.clear_references
|
193
|
+
object_type.is_table = nil # Undecided; force an attempt to decide
|
194
|
+
object_type.tentative = true # Uncertain
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
177
198
|
def decide_tables #:nodoc:
|
178
199
|
# Strategy:
|
179
200
|
# 1) Populate references for all ObjectTypes
|
@@ -181,7 +202,7 @@ module ActiveFacts
|
|
181
202
|
# a. ObjectTypes labelled is_independent are tables (See the is_table methods above)
|
182
203
|
# b. Entity types having no references to them must be tables
|
183
204
|
# c. subtypes are not tables unless marked with assimilation = separate or partitioned
|
184
|
-
# d. ValueTypes are never tables unless they can have references (to other ValueTypes)
|
205
|
+
# d. ValueTypes are never tables unless they independent or can have references (to other ValueTypes)
|
185
206
|
# e. An EntityType having an identifying AutoInc field must be a table unless it has exactly one reference
|
186
207
|
# f. An EntityType whose only reference is through its single preferred_identifier role gets absorbed
|
187
208
|
# g. An EntityType that must has references other than its PI must be a table (unless it has exactly one reference to it)
|
@@ -190,6 +211,8 @@ module ActiveFacts
|
|
190
211
|
# - subtype extension where supertype has only PI roles and no AutoInc
|
191
212
|
# 3) any ValueType that has references from it must become a table if not already
|
192
213
|
|
214
|
+
wipe_existing_mapping
|
215
|
+
|
193
216
|
populate_all_references
|
194
217
|
|
195
218
|
debug :absorption, "Calculating relational composition" do
|
@@ -218,7 +241,7 @@ module ActiveFacts
|
|
218
241
|
undecided.select do |object_type|
|
219
242
|
debug :absorption, "Considering #{object_type.name}:" do
|
220
243
|
debug :absorption, "refs to #{object_type.name} are from #{object_type.references_to.map{|ref| ref.from.name}*", "}" if object_type.references_to.size > 0
|
221
|
-
debug :absorption, "refs from #{object_type.name} are to #{object_type.references_from.map{|ref| ref.to.name
|
244
|
+
debug :absorption, "refs from #{object_type.name} are to #{object_type.references_from.map{|ref| ref.to ? ref.to.name : ref.fact_type.default_reading}*", "}" if object_type.references_from.size > 0
|
222
245
|
|
223
246
|
# Always absorb an objectified unary into its role player:
|
224
247
|
if object_type.fact_type && object_type.fact_type.all_role.size == 1
|
@@ -247,11 +270,21 @@ module ActiveFacts
|
|
247
270
|
}
|
248
271
|
debug :absorption, "#{object_type.name} has #{non_identifying_refs_from.size} non-identifying functional roles"
|
249
272
|
|
273
|
+
=begin
|
274
|
+
# This is kinda arbitrary. We need a policy for evaluating optional flips, so we can decide if they "improve" things.
|
275
|
+
# The flipping that occurs below always eliminates a table by absorption, but this doesn't.
|
276
|
+
|
250
277
|
# If all non-identifying functional roles are one-to-ones that can be flipped, do that:
|
251
278
|
if non_identifying_refs_from.all? { |ref| ref.role_type == :one_one && (ref.to.is_table || ref.to.tentative) }
|
252
|
-
|
279
|
+
debug :absorption, "Flipping references from #{object_type.name}" do
|
280
|
+
non_identifying_refs_from.each do |ref|
|
281
|
+
debug :absorption, "Flipping #{ref}"
|
282
|
+
ref.flip
|
283
|
+
end
|
284
|
+
end
|
253
285
|
non_identifying_refs_from = []
|
254
286
|
end
|
287
|
+
=end
|
255
288
|
|
256
289
|
if object_type.references_to.size > 1 and
|
257
290
|
non_identifying_refs_from.size > 0
|
@@ -266,8 +299,7 @@ module ActiveFacts
|
|
266
299
|
!ref.to or ref.to.absorbed_via == ref
|
267
300
|
end+object_type.references_to
|
268
301
|
).reject do |ref|
|
269
|
-
next true if !ref.to.is_table or
|
270
|
-
![:one_one, :supertype, :subtype].include?(ref.role_type)
|
302
|
+
next true if !ref.to.is_table or !ref.is_one_to_one
|
271
303
|
|
272
304
|
# Don't absorb an object along a non-mandatory role (otherwise if it doesn't play that role, it can't exist either)
|
273
305
|
from_is_mandatory = !!ref.is_mandatory
|
@@ -282,7 +314,7 @@ module ActiveFacts
|
|
282
314
|
if absorption_paths.size > 0
|
283
315
|
debug :absorption, "#{object_type.name} is fully absorbed through #{absorption_paths.inspect}"
|
284
316
|
absorption_paths.each do |ref|
|
285
|
-
debug :absorption, "
|
317
|
+
debug :absorption, "Flipping #{ref} so #{object_type.name} can be absorbed"
|
286
318
|
ref.flip if object_type == ref.from
|
287
319
|
end
|
288
320
|
object_type.definitely_not_table
|
@@ -310,8 +342,13 @@ module ActiveFacts
|
|
310
342
|
# unless it should absorb something else (another ValueType is all it could be):
|
311
343
|
all_object_type.each do |object_type|
|
312
344
|
if (!object_type.is_table and object_type.references_to.size == 0 and object_type.references_from.size > 0)
|
313
|
-
|
314
|
-
|
345
|
+
if !object_type.references_from.detect{|r| !r.is_one_to_one || !r.to.is_table}
|
346
|
+
debug :absorption, "Flipping references from #{object_type.name}; they're all to tables"
|
347
|
+
object_type.references_from.map(&:flip)
|
348
|
+
else
|
349
|
+
debug :absorption, "Making #{object_type.name} a table; it has nowhere else to go and needs to absorb things"
|
350
|
+
object_type.probably_table
|
351
|
+
end
|
315
352
|
end
|
316
353
|
end
|
317
354
|
|
@@ -324,9 +361,6 @@ module ActiveFacts
|
|
324
361
|
end
|
325
362
|
end
|
326
363
|
|
327
|
-
populate_all_columns
|
328
|
-
populate_all_indices
|
329
|
-
|
330
364
|
@tables =
|
331
365
|
all_object_type.
|
332
366
|
select { |f| f.is_table }.
|