activefacts 1.6.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,187 +0,0 @@
1
- #
2
- # ActiveFacts Relational mapping and persistence.
3
- # A ForeignKey exists for every Reference from a ObjectType to another ObjectType that's a table.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- module ActiveFacts
8
- module Persistence
9
- class ForeignKey
10
- # What table (ObjectType) is the FK from?
11
- def from; @from; end
12
-
13
- # What table (ObjectType) is the FK to?
14
- def to; @to; end
15
-
16
- # What reference created the FK?
17
- def references; @references; end
18
-
19
- # What columns in the *from* table form the FK
20
- def from_columns; @from_columns; end
21
-
22
- # What columns in the *to* table form the identifier
23
- def to_columns; @to_columns; end
24
-
25
- def initialize(from, to, references, from_columns, to_columns) #:nodoc:
26
- @from, @to, @references, @from_columns, @to_columns =
27
- from, to, references, from_columns, to_columns
28
- end
29
-
30
- def describe
31
- "foreign key from #{from.name}(#{from_columns.map{|c| c.name}*', '}) to #{to.name}(#{to_columns.map{|c| c.name}*', '})"
32
- end
33
-
34
- def verbalised_path reverse = false
35
- # REVISIT: This should be a proper join path verbalisation:
36
- refs = reverse ? references.reverse : references
37
- refs.map do |r|
38
- r.verbalised_path reverse
39
- end * ' and '
40
- end
41
-
42
- # Which references are absorbed into the "from" table?
43
- def precursor_references
44
- fk_jump = @references.detect(&:fk_jump)
45
- jump_index = @references.index(fk_jump)
46
- @references[0, jump_index]
47
- end
48
-
49
- # Which references are absorbed into the "to" table?
50
- def following_references
51
- fk_jump = @references.detect(&:fk_jump)
52
- jump_index = @references.index(fk_jump)
53
- fk_jump != @references.last ? @references[jump_index+1..-1] : []
54
- end
55
-
56
- def jump_reference
57
- @references.detect(&:fk_jump)
58
- end
59
-
60
- def to_name
61
- p = precursor_references
62
- f = following_references
63
- j = jump_reference
64
-
65
- @references.last.to_names +
66
- (p.empty? && f.empty? ? [] : ['via'] + p.map{|r| r.to_names}.flatten + f.map{|r| r.from_names}.flatten)
67
- end
68
-
69
- # The from_name is the role name of the table with the FK, viewed from the other end
70
- # When there are no precursor_references or following_references, it's the jump_reference.from_names
71
- # REVISIT: I'm still working out what to do with precursor_references and following_references
72
- def from_name
73
- p = precursor_references
74
- f = following_references
75
- j = jump_reference
76
-
77
- # pluralise unless j.is_one_to_one
78
-
79
- # REVISIT: references[0].from_names is where the FK lives; but the object of interest may be an absorbed subclass which we should use here instead:
80
- # REVISIT: Should crunch superclasses in subtype traversals
81
- # REVISIT: Need to add "_as_rolename" where rolename is not to.name
82
-
83
- [
84
- @references[0].from_names,
85
- (p.empty? && f.empty? ? [] : ['via'] + p.map{|r| r.to_names}.flatten + f.map{|r| r.from_names}.flatten)
86
- ]
87
- end
88
-
89
- end
90
- end
91
-
92
- module Metamodel #:nodoc:
93
- class ObjectType
94
- # When an EntityType is fully absorbed, its foreign keys are too.
95
- # Return an Array of Reference paths for such absorbed FKs
96
- def all_absorbed_foreign_key_reference_path
97
- references_from.inject([]) do |array, ref|
98
- if ref.is_simple_reference
99
- if TypeInheritance === ref.fact_type
100
- # Ignore references to secondary supertypes, when absorption is through primary.
101
- next array if absorbed_via && TypeInheritance === absorbed_via.fact_type
102
- # Ignore the case where a subtype is absorbed elsewhere:
103
- # REVISIT: Disabled, as this should never happen.
104
- # next array if ref.to.absorbed_via != ref.fact_type
105
- end
106
- ref.fk_jump = true
107
- array << [ref]
108
- elsif ref.is_absorbing or (ref.to && !ref.to.is_table)
109
- trace :fk, "getting fks absorbed into #{name} via #{ref}" do
110
- ref.to.all_absorbed_foreign_key_reference_path.each do |aref|
111
- array << aref.insert(0, ref)
112
- end
113
- end
114
- end
115
- array
116
- end
117
- end
118
-
119
- def foreign_keys_to
120
- @foreign_keys_to ||= []
121
- end
122
-
123
- # Return an array of all the foreign keys from this table
124
- def foreign_keys
125
-
126
- # Get the ForeignKey object for each absorbed reference path
127
- @foreign_keys ||=
128
- begin
129
- fk_ref_paths = all_absorbed_foreign_key_reference_path
130
- fk_ref_paths.map do |fk_ref_path|
131
- trace :fk, "\nFK: " + fk_ref_path.map{|fk_ref| fk_ref.reading }*" and " do
132
-
133
- from_columns = (columns||all_columns({})).select{|column|
134
- column.references[0...fk_ref_path.size] == fk_ref_path
135
- }
136
- trace :fk, "from_columns = #{from_columns.map { |column| column.name }*", "}"
137
-
138
- # Figure out absorption on the target end:
139
- to = fk_ref_path.last.to
140
- if to.absorbed_via
141
- trace :fk, "Reference target #{fk_ref_path.last.to.name} is absorbed via:" do
142
- while (r = to.absorbed_via)
143
- m = r.reversed
144
- trace :fk, "#{m.reading}"
145
- fk_ref_path << m
146
- to = m.from == to ? m.to : m.from
147
- end
148
- trace :fk, "Absorption ends at #{to.name}"
149
- end
150
- end
151
-
152
- # REVISIT: This test may no longer be necessary
153
- raise "REVISIT: #{fk_ref_path.inspect} is bad" unless to and to.columns
154
-
155
- # REVISIT: This fails for absorbed subtypes having their own identification.
156
- # Check the CompanyDirectorEmployee model for example, EmployeeManagerNr -> Person (should reference EmployeeNr)
157
- # Need to use the absorbed identifier_columns of the subtype,
158
- # not the columns of the supertype that absorbs it.
159
- # But in general, that isn't going to work because in most DBMS
160
- # there's no suitable uniquen index on the subtype's identifier_columns
161
-
162
- to_columns = fk_ref_path[-1].to.identifier_columns
163
-
164
- # Put the column pairs in the correct order. They MUST be in the order they appear in the primary key
165
- froms, tos = from_columns.zip(to_columns).sort_by { |pair|
166
- to_columns.index(pair[1])
167
- }.transpose
168
-
169
- fk = ActiveFacts::Persistence::ForeignKey.new(self, to, fk_ref_path, froms, tos)
170
- to.foreign_keys_to << fk
171
- fk
172
- end
173
- end.
174
- sort_by do |fk|
175
- # Put the foreign keys in a defined order:
176
- # debugger if !fk.to_columns || fk.to_columns.include?(nil) || !fk.from_columns || fk.from_columns.include?(nil)
177
- [ fk.to.name,
178
- fk.to_columns.map{|col| col.name(nil).sort},
179
- fk.from_columns.map{|col| col.name(nil).sort}
180
- ]
181
- end
182
- end
183
-
184
- end
185
- end
186
- end
187
- end
@@ -1,240 +0,0 @@
1
- #
2
- # ActiveFacts Relational mapping and persistence.
3
- # An Index on a ObjectType is used to represent a unique constraint across roles absorbed
4
- # into that object_type's table.
5
- #
6
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
7
- #
8
-
9
- module ActiveFacts
10
- module Persistence
11
- class Index
12
- # The UniquenessConstraint that created this index
13
- def uniqueness_constraint; @uniqueness_constraint; end
14
-
15
- # The table that the index is on
16
- def on; @on; end
17
-
18
- # If a non-mandatory reference was absorbed, only the non-nil instances are unique.
19
- # Return the ObjectType that was absorbed, which might differ from this Index's table.
20
- def over; @over; end
21
-
22
- # Return the array of columns in this index
23
- def columns; @columns; end
24
-
25
- # Is this index the primary key for this table?
26
- def is_primary; @is_primary; end
27
-
28
- # Is this index unique?
29
- def is_unique; @is_unique; end
30
-
31
- # An Index arises from a uniqueness constraint and applies to a table,
32
- # but because the UC may actually be over an object absorbed into the table,
33
- # we must record that object also.
34
- # We record the columns it's over, whether it's primary (for 'over'),
35
- # and whether it's unique (always, at present)
36
- def initialize(uc, on, over, columns, is_primary, is_unique = true) #:nodoc:
37
- @uniqueness_constraint, @on, @over, @columns, @is_primary, @is_unique =
38
- uc, on, over, columns, is_primary, is_unique
39
- end
40
-
41
- # The name that was assigned (perhaps implicitly by NORMA)
42
- def real_name
43
- @uniqueness_constraint.name && @uniqueness_constraint.name != '' ? @uniqueness_constraint.name.gsub(' ','') : nil
44
- end
45
-
46
- # This name is either the name explicitly assigned (if any) or is constructed to form a unique index name.
47
- def name
48
- uc = @uniqueness_constraint
49
- r = real_name
50
- return r if r && r !~ /^(Ex|In)ternalUniquenessConstraint[0-9]+$/
51
- (uc.is_preferred_identifier ? "PK_" : "IX_") +
52
- view_name +
53
- (uc.is_preferred_identifier ? "" : "By"+column_names*"")
54
- end
55
-
56
- # An array of the names of the columns this index covers
57
- def column_names(separator = "")
58
- columns.map{|column| column.name(separator)}
59
- end
60
-
61
- # An array of the names of the columns this index covers, with some lexical truncations.
62
- def abbreviated_column_names(separator = "")
63
- columns.map{|column| column.name(separator).sub(/^#{over.name}/,'')}
64
- end
65
-
66
- # The name of a view that can be created to enforce uniqueness over non-null key values
67
- def view_name
68
- "#{over.name.gsub(' ','')}#{on == over ? "" : "In"+on.name.gsub(' ','')}"
69
- end
70
-
71
- def to_s #:nodoc:
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
79
- colnames = @columns.map(&:name)*", "
80
- "Index #{name} on #{@on.name} over #{@over.name}(#{colnames})#{preferred}"
81
- end
82
- end
83
- end
84
-
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
-
104
- class ObjectType
105
- # An array of each Index for this table
106
- def indices
107
- @indices || populate_indices
108
- end
109
-
110
- def clear_indices #:nodoc:
111
- # Clear any previous indices
112
- @indices = nil
113
- end
114
-
115
- def populate_indices #:nodoc:
116
- # The absorption path of a column indicates how it came to be in this table.
117
- # It might be a direct many:one valuetype relationship, or it might be in such
118
- # a relationship to an entity that was absorbed into this table (and so on).
119
- # The reference path is the set of absorption references and one past it.
120
- # Stopping here means we don't dig into the definitions of FK column counterparts.
121
- # Note that many columns of an object may have the same ref_path.
122
- #
123
- # REVISIT:
124
- # Note also that this produces columns ordered for each refpath the same as the
125
- # order of the columns, not the same as the columns in the PK for which they might be an FK.
126
- all_column_by_ref_path =
127
- trace :index2, "Indexing columns by ref_path" do
128
- columns.inject({}) do |hash, column|
129
- trace :index2, "References in column #{name}.#{column.name}" do
130
- ref_path = column.absorption_references
131
- raise "No absorption_references for #{column.name} from #{column.references.map(&:to_s)*" and "}" if !ref_path || ref_path.empty?
132
- (hash[ref_path] ||= []) << column
133
- trace :index2, "#{column.name} involves #{ref_path.map(&:to_s)*" and "}"
134
- end
135
- hash
136
- end
137
- end
138
-
139
- columns_by_unique_constraint = {}
140
- all_column_by_role_ref =
141
- all_column_by_ref_path.
142
- keys. # Go through all refpaths and find uniqueness constraints
143
- inject({}) do |hash, ref_path|
144
- ref_path.each do |ref|
145
- next unless ref.to_role
146
- # trace :index2, "Considering #{ref_path.map(&:to_s)*" and "} yielding columns #{all_column_by_ref_path[ref_path].map{|c| c.name('.')}*", "}"
147
- ref.to_role.all_role_ref.each do |role_ref|
148
- all_pcs = role_ref.role_sequence.all_presence_constraint
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
150
- pcs = all_pcs.
151
- reject do |pc|
152
- !pc.max_frequency or # No maximum freq; cannot be a uniqueness constraint
153
- pc.max_frequency != 1 or # maximum is not 1
154
- # Constraint is not over a unary fact type role (NORMA does this)
155
- pc.role_sequence.all_role_ref.size == 1 && ref_path[-1].to_role.fact_type.all_role.size == 1
156
- end
157
- next unless pcs.size > 0
158
- # The columns for this ref_path support the UCs in "pcs".
159
- pcs.each do |pc|
160
- ref_columns = all_column_by_ref_path[ref_path]
161
- ordinal = role_ref.ordinal # Position in priority order
162
- ref_columns.each_with_index do |column, index|
163
- #puts "Adding index column #{column.name} in rank[#{ordinal},#{index}]"
164
- # REVISIT: the "index" here might be a duplicate in some cases: change sort_by below to just sort and run the SeparateSubtypes CQL model for example.
165
- (columns_by_unique_constraint[pc] ||= []) << [ordinal, index, column]
166
- end
167
- end
168
- hash[role_ref] = all_column_by_ref_path[ref_path]
169
- end
170
- end
171
- hash
172
- end
173
-
174
- trace :index, "All Indices in #{name}:" do
175
- @indices = columns_by_unique_constraint.map do |uc, columns_with_ordinal|
176
- trace :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
- columns = columns_with_ordinal.sort_by{|ca| [ca[0,2], ca[2].name]}.map{|ca| ca[2]}
178
- absorption_level = columns.map(&:absorption_level).min
179
- over = columns[0].references[absorption_level].from
180
-
181
- # Absorption through a one-to-one forms a UC that we don't need to enforce using an index:
182
- if over != self and
183
- over.absorbed_via == columns[0].references[absorption_level-1] and
184
- (rr = uc.role_sequence.all_role_ref.single) and
185
- over.absorbed_via.fact_type.all_role.include?(rr.role)
186
- next nil
187
- end
188
-
189
- index = ActiveFacts::Persistence::Index.new(
190
- uc,
191
- self,
192
- over,
193
- columns,
194
- uc.is_preferred_identifier
195
- )
196
- trace :index, index
197
- index
198
- end.
199
- compact.
200
- sort_by do |index|
201
- # Put the indices in a defined order:
202
- index.columns.map(&:name)+['', index.over.name]
203
- end
204
- end
205
- si = self_index
206
- @indices.unshift(si) if si
207
- @indices
208
- end
209
-
210
- end
211
-
212
- class Vocabulary
213
- def populate_all_indices #:nodoc:
214
- trace :index, "Populating all object_type indices" do
215
- all_object_type.each do |object_type|
216
- object_type.clear_indices
217
- end
218
- all_object_type.each do |object_type|
219
- next unless object_type.is_table
220
- trace :index, "Populating indices for #{object_type.name}" do
221
- object_type.populate_indices
222
- end
223
- end
224
- end
225
- trace :index, "Finished object_type indices" do
226
- all_object_type.each do |object_type|
227
- next unless object_type.is_table
228
- next unless object_type.indices.size > 0
229
- trace :index, "#{object_type.name}:" do
230
- object_type.indices.each do |index|
231
- trace :index, index
232
- end
233
- end
234
- end
235
- end
236
- end
237
- end
238
-
239
- end
240
- end
@@ -1,198 +0,0 @@
1
- require 'activefacts/support'
2
-
3
- module ActiveFacts
4
- module API
5
- module ObjectType
6
- def table
7
- @is_table = true
8
- end
9
-
10
- def is_table
11
- @is_table
12
- end
13
-
14
- def columns
15
- raise "This method is no longer in use"
16
- =begin
17
- return @columns if @columns
18
- trace :persistence, "Calculating columns for #{basename}" do
19
- @columns = (
20
- if superclass.is_entity_type
21
- # REVISIT: Need keys to secondary supertypes as well, but no duplicates.
22
- trace :persistence, "Separate subtype has a foreign key to its supertype" do
23
- superclass.__absorb([[superclass.basename]], self)
24
- end
25
- else
26
- []
27
- end +
28
- # Then absorb all normal roles:
29
- roles.values.select do |role|
30
- role.unique && !role.counterpart_unary_has_precedence
31
- end.inject([]) do |columns, role|
32
- rn = role.name.to_s.split(/_/)
33
- trace :persistence, "Role #{rn*'.'}" do
34
- columns += role.counterpart_object_type.__absorb([rn], role.counterpart)
35
- end
36
- end +
37
- # And finally all absorbed subtypes:
38
- subtypes.
39
- select{|subtype| !subtype.is_table}. # Don't absorb separate subtypes
40
- inject([]) do |columns, subtype|
41
- # Pass self as 2nd param here, not a role, standing for the supertype role
42
- subtype_name = subtype.basename
43
- trace :persistence, "Absorbing subtype #{subtype_name}" do
44
- columns += subtype.__absorb([[subtype_name]], self)
45
- end
46
- end
47
- ).map do |col_names|
48
- last = nil
49
- col_names.flatten.map do |name|
50
- name.downcase.sub(/^[a-z]/){|c| c.upcase}
51
- end.
52
- reject do |n|
53
- # Remove sequential duplicates:
54
- dup = last == n
55
- last = n
56
- dup
57
- end*"."
58
- end
59
- end
60
- =end
61
- end
62
-
63
- # Return an array of the absorbed columns, using prefix for name truncation
64
- def __absorb(prefix, except_role = nil)
65
- # also considered a table if the superclass isn't excluded and is (transitively) a table
66
- if !@is_table && (except_role == superclass || !is_table_subtype)
67
- if is_entity_type
68
- if (role = fully_absorbed) && role != except_role
69
- # If this non-table is fully absorbed into another table (not our caller!)
70
- # (another table plays its single identifying role), then absorb that role only.
71
- # counterpart_object_type = role.counterpart_object_type
72
- # This omission matches the one in columns.rb, see EntityType#reference_columns
73
- # new_prefix = prefix + [role.name.to_s.split(/_/)]
74
- trace :persistence, "Reference to #{role.name} (absorbed elsewhere)" do
75
- role.counterpart_object_type.__absorb(prefix, role.counterpart)
76
- end
77
- else
78
- # Not a table -> all roles are absorbed
79
- roles.
80
- values.
81
- select do |role|
82
- role.unique && role != except_role && !role.counterpart_unary_has_precedence
83
- end.
84
- inject([]) do |columns, role|
85
- columns += __absorb_role(prefix, role)
86
- end +
87
- subtypes. # Absorb subtype roles too!
88
- select{|subtype| !subtype.is_table}. # Don't absorb separate subtypes
89
- inject([]) do |columns, subtype|
90
- # Pass self as 2nd param here, not a role, standing for the supertype role
91
- new_prefix = prefix[0..-2] + [[subtype.basename]]
92
- trace :persistence, "Absorbed subtype #{subtype.basename}" do
93
- columns += subtype.__absorb(new_prefix, self)
94
- end
95
- end
96
- end
97
- else
98
- [prefix]
99
- end
100
- else
101
- # Create a foreign key to the table
102
- if is_entity_type
103
- ir = identifying_role_names.map{|role_name| roles(role_name) }
104
- trace :persistence, "Reference to #{basename} with #{prefix.inspect}" do
105
- ic = identifying_role_names.map{|role_name| role_name.to_s.split(/_/)}
106
- ir.inject([]) do |columns, role|
107
- columns += __absorb_role(prefix, role)
108
- end
109
- end
110
- else
111
- # Reference to value type which is a table
112
- col = prefix.clone
113
- trace :persistence, "Self-value #{col[-1]}.Value"
114
- col[-1] += ["Value"]
115
- col
116
- end
117
- end
118
- end
119
-
120
- def __absorb_role(prefix, role)
121
- if prefix.size > 0 and
122
- (c = role.owner).is_entity_type and
123
- c.identifying_roles == [role] and
124
- (irn = c.identifying_role_names).size == 1 and
125
- (n = irn[0].to_s.split(/_/)).size > 1 and
126
- (owner = role.owner.basename.snakecase.split(/_/)) and
127
- n[0...owner.size] == owner
128
- trace :persistence, "truncating transitive identifying role #{n.inspect}"
129
- owner.size.times { n.shift }
130
- new_prefix = prefix + [n]
131
- elsif (c = role.counterpart_object_type).is_entity_type and
132
- (irn = c.identifying_role_names).size == 1 and
133
- #irn[0].to_s.split(/_/)[0] == role.owner.basename.downcase
134
- irn[0] == role.counterpart.name
135
- #trace :persistence, "=== #{irn[0].to_s.split(/_/)[0]} elided ==="
136
- new_prefix = prefix
137
- elsif (fa_role = fully_absorbed) && fa_role == role
138
- new_prefix = prefix
139
- else
140
- new_prefix = prefix + [role.name.to_s.split(/_/)]
141
- end
142
- #trace :persistence, "new_prefix is #{new_prefix*"."}"
143
-
144
- trace :persistence, "Absorbing role #{role.name} as #{new_prefix[prefix.size..-1]*"."}" do
145
- role.counterpart_object_type.__absorb(new_prefix, role.counterpart)
146
- end
147
- end
148
-
149
- def is_table_subtype
150
- return true if is_table
151
- klass = superclass
152
- while klass.is_entity_type
153
- return true if klass.is_table
154
- klass = klass.superclass
155
- end
156
- return false
157
- end
158
- end
159
-
160
- module Entity
161
- module ClassMethods
162
- def fully_absorbed
163
- return false unless (ir = identifying_role_names) && ir.size == 1
164
- role = roles(ir[0])
165
- return role if ((cp = role.counterpart_object_type).is_table ||
166
- (cp.is_entity_type && cp.fully_absorbed))
167
- return superclass if superclass.is_entity_type # Absorbed subtype
168
- nil
169
- end
170
- end
171
- end
172
-
173
- # A one-to-one can be absorbed into either table. We decide which by comparing
174
- # the names, just as happens in ObjectType.populate_reference (see reference.rb)
175
- class Role
176
- def counterpart_unary_has_precedence
177
- counterpart_object_type.is_table_subtype and
178
- counterpart.unique and
179
- owner.name.downcase < counterpart.owner.name.downcase
180
- end
181
- end
182
-
183
- end
184
- end
185
-
186
- class TrueClass
187
- def self.__absorb(prefix, except_role = nil)
188
- [prefix]
189
- end
190
-
191
- def self.is_table
192
- false
193
- end
194
-
195
- def self.is_table_subtype
196
- false
197
- end
198
- end