activefacts 1.6.0 → 1.7.1

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.
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,132 +0,0 @@
1
- require 'activefacts/vocabulary'
2
- require 'activefacts/persistence'
3
- require 'active_support'
4
- require 'digest/sha1'
5
-
6
- module ActiveFacts
7
- module Persistence
8
- def self.rails_name_trunc name
9
- if name.length > 63
10
- hash = Digest::SHA1.hexdigest name
11
- name = name[0, 53] + '__' + hash[0, 8]
12
- end
13
- name
14
- end
15
-
16
- def self.rails_plural_name name
17
- # Crunch spaces and pluralise the first part, all in snake_case
18
- name.pop if name.is_a?(Array) and name.last == []
19
- name = name[0]*'_' if name.is_a?(Array) and name.size == 1
20
- if name.is_a?(Array)
21
- name = ActiveSupport::Inflector.tableize((name[0]*'_').gsub(/\s+/, '_')) +
22
- '_' +
23
- ActiveSupport::Inflector.underscore((name[1..-1].flatten*'_').gsub(/\s+/, '_'))
24
- else
25
- ActiveSupport::Inflector.tableize(name.gsub(/\s+/, '_'))
26
- end
27
- end
28
-
29
- def self.rails_singular_name name
30
- # Crunch spaces and convert to snake_case
31
- name = name.flatten*'_' if name.is_a?(Array)
32
- ActiveSupport::Inflector.underscore(name.gsub(/\s+/, '_'))
33
- end
34
-
35
- class Column
36
- def rails_name
37
- Persistence::rails_singular_name(name('_'))
38
- end
39
-
40
- def rails_type
41
- type_name, params, constraints = *type()
42
- rails_type = case type_name
43
- when /^Auto ?Counter$/i
44
- 'serial' # REVISIT: Need to detect surrogate ID fields and handle them correctly
45
-
46
- when /^[Ug]uid$/i
47
- 'uuid'
48
-
49
- when /^Unsigned ?Integer$/i,
50
- /^Integer$/i,
51
- /^Signed ?Integer$/i,
52
- /^Unsigned ?Small ?Integer$/i,
53
- /^Signed ?Small ?Integer$/i,
54
- /^Unsigned ?Tiny ?Integer$/i
55
- length = nil
56
- 'integer'
57
-
58
- when /^Decimal$/i
59
- 'decimal'
60
-
61
- when /^Float$/i, /^Double$/i, /^Real$/i
62
- 'float'
63
-
64
- when /^Fixed ?Length ?Text$/i, /^Char$/i
65
- 'string'
66
- when /^Variable ?Length ?Text$/i, /^String$/i
67
- 'string'
68
- when /^Large ?Length ?Text$/i, /^Text$/i
69
- 'text'
70
-
71
- when /^Date ?And ?Time$/i, /^Date ?Time$/i
72
- 'datetime'
73
- when /^Date$/i
74
- 'datetime'
75
- when /^Time$/i
76
- 'time'
77
- when /^Auto ?Time ?Stamp$/i
78
- 'timestamp'
79
-
80
- when /^Money$/i
81
- 'decimal'
82
- when /^Picture ?Raw ?Data$/i, /^Image$/i, /^Variable ?Length ?Raw ?Data$/i, /^Blob$/i
83
- 'binary'
84
- when /^BIT$/i, /^Boolean$/i
85
- 'boolean'
86
- else
87
- type_name # raise "ActiveRecord type unknown for standard type #{type}"
88
- end
89
- [rails_type, params[:length]]
90
- end
91
- end
92
-
93
- class Index
94
- def rails_name
95
- column_names = columns.map{|c| c.rails_name }
96
- index_name = "index_#{on.rails_name+'_on_'+column_names*'_'}"
97
- Persistence.rails_name_trunc index_name
98
- end
99
- end
100
-
101
- class ForeignKey
102
- def rails_from_association_name
103
- Persistence::rails_singular_name(to_name.join('_'))
104
- end
105
-
106
- def rails_to_association
107
- jump = jump_reference
108
- if jump.is_one_to_one
109
- [ "has_one", Persistence::rails_singular_name(from_name)]
110
- else
111
- [ "has_many", Persistence::rails_plural_name(from_name)]
112
- end
113
- end
114
- end
115
- end
116
-
117
- module Metamodel
118
- class ObjectType
119
- def rails_name
120
- Persistence::rails_plural_name(name)
121
- end
122
-
123
- def rails_singular_name
124
- Persistence::rails_singular_name(name)
125
- end
126
-
127
- def rails_class_name
128
- ActiveSupport::Inflector.camelize(name.gsub(/\s+/, '_'))
129
- end
130
- end
131
- end
132
- end
@@ -1,15 +0,0 @@
1
- #
2
- # ActiveFacts Relational mapping and persistence.
3
- #
4
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
5
- #
6
-
7
- # These files are concerned with calculating a relational schema for a vocabulary:
8
- require 'activefacts/persistence/reference'
9
- require 'activefacts/persistence/tables'
10
- require 'activefacts/persistence/columns'
11
- require 'activefacts/persistence/foreignkey'
12
- require 'activefacts/persistence/index'
13
-
14
- # These extend the API classes with relational awareness:
15
- require 'activefacts/persistence/object_type'
@@ -1,446 +0,0 @@
1
- #
2
- # ActiveFacts Relational mapping and persistence.
3
- # Columns in a relational table; each is derived from a sequence of References.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- # Each Reference from a ObjectType creates one or more Columns.
8
- # A reference to a simple valuetype creates a single column, as
9
- # does a reference to a table entity identified by a single value.
10
- #
11
- # When referring to a object_type that doesn't have its own table,
12
- # all references from that object_type are absorbed into this one.
13
- #
14
- # When multiple values identify an entity that does have its own
15
- # table, a reference to that entity creates multiple columns,
16
- # a multi-part foreign key.
17
- #
18
-
19
- module ActiveFacts
20
- module Persistence #:nodoc:
21
-
22
- class Column
23
- def initialize(reference = nil) #:nodoc:
24
- references << reference if reference
25
- end
26
-
27
- # A Column is created from a path through an array of References to a ValueType
28
- def references
29
- @references ||= []
30
- end
31
-
32
- # All references up to and including the first non-absorbing reference
33
- def absorption_references
34
- @references.inject([]) do |array, ref|
35
- array << ref
36
- # puts "Column #{name} spans #{ref}, #{ref.is_absorbing ? "" : "not "} absorbing (#{ref.to.name} absorbs via #{ref.to.absorbed_via.inspect})"
37
- break array unless ref.is_absorbing
38
- array
39
- end
40
- end
41
-
42
- # How many of the initial references are involved in full absorption of an EntityType into this column's table
43
- def absorption_level
44
- l = 0
45
- @references.detect do |ref|
46
- l += 1 if ref.is_absorbing
47
- false
48
- end
49
- l
50
- end
51
-
52
- def prepend reference #:nodoc:
53
- references.insert 0, reference
54
- self
55
- end
56
-
57
- # A Column name is a sequence of names (derived from the to_roles of the References)
58
- # appended by a separator string (pass nil to get the original array of names)
59
- # The names to use is derived from the to_names of each Reference,
60
- # modified by these rules:
61
- # * A reference after the first one which is not a TypeInheritance but where the _from_ object plays the sole role in the preferred identifier of the _to_ entity is ignored,
62
- # * A reference (after a name has been retained) which is a TypeInheritance retains the names of the subtype,
63
- # * If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication
64
- # * If we have retained the name of an entity, and this reference is the sole identifying role of an entity, and the identifying object has a name that is prefixed by the name of the object it identifies, remove the prefix and use just the suffix.
65
- def name(separator = "")
66
- self.class.name(@references, separator)
67
- end
68
-
69
- def self.name(refs, separator = "")
70
- last_names = []
71
- names = refs.
72
- inject([]) do |a, ref|
73
-
74
- # Skip any object after the first which is identified by this reference
75
- if ref != refs[0] and
76
- !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and
77
- ref.to and
78
- ref.to.is_a?(ActiveFacts::Metamodel::EntityType) and
79
- (role_ref = ref.to.preferred_identifier.role_sequence.all_role_ref.single) and
80
- role_ref.role == ref.from_role
81
- trace :columns, "Skipping #{ref}, identifies non-initial object"
82
- next a
83
- end
84
-
85
- names = ref.to_names(ref != refs.last)
86
-
87
- # When traversing type inheritances, keep the subtype name, not the supertype names as well:
88
- if a.size > 0 && ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
89
- if ref.to != ref.fact_type.subtype # Did we already have the subtype?
90
- trace :columns, "Skipping supertype #{ref}"
91
- next a
92
- end
93
- trace :columns, "Eliding supertype in #{ref}"
94
- last_names.size.times { a.pop } # Remove the last names added
95
- elsif last_names.last && last_names.last == names[0][0...last_names.last.size]
96
- # When Xyz is followed by XyzID, truncate that to just ID
97
- trace :columns, "truncating repeated #{last_names.last} in #{names[0]}"
98
- names[0] = names[0][last_names.last.size..-1]
99
- names.shift if names[0] == ''
100
- elsif last_names.last == names[0]
101
- # Same, but where an underscore split up the words
102
- trace :columns, "truncating repeated name in #{names.inspect}"
103
- names.shift
104
- end
105
-
106
- # If the reference is to the single identifying role of the object_type making the reference,
107
- # strip the object_type name from the start of the reference role
108
- if a.size > 0 and
109
- (et = ref.from).is_a?(ActiveFacts::Metamodel::EntityType) and
110
- # This instead of the next 2 would apply to all identifying roles, but breaks some examples:
111
- # (role_ref = et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role == ref.to_role}) and
112
- (role_ref = et.preferred_identifier.role_sequence.all_role_ref.single) and
113
- role_ref.role == ref.to_role and
114
- names[0][0...et.name.size].downcase == et.name.downcase
115
-
116
- trace :columns, "truncating transitive identifying role #{names.inspect}"
117
- names[0] = names[0][et.name.size..-1]
118
- names.shift if names[0] == ""
119
- end
120
-
121
- last_names = names
122
-
123
- a += names
124
- a
125
- end.elide_repeated_subsequences { |a, b|
126
- if a.is_a?(Array)
127
- a.map{|e| e.downcase} == b.map{|e| e.downcase}
128
- else
129
- a.downcase == b.downcase
130
- end
131
- }
132
-
133
- name_array = names.map{|n| n.sub(/^[a-z]/){|s| s.upcase}}
134
- separator ? name_array * separator : name_array
135
- end
136
-
137
- # Is this column mandatory or nullable?
138
- def is_mandatory
139
- # Uncomment the following line for CWA unaries (not nullable, just T/F)
140
- # @references[-1].is_unary ||
141
- !@references.detect{|ref| !ref.is_mandatory || ref.is_unary }
142
- end
143
-
144
- # This column is auto-assigned if it's an auto-assigned value type and is not a foreign key
145
- def is_auto_assigned
146
- last_table_ref = references.reverse.detect{|r| r.from && r.from.is_table}
147
- (to = references[-1].to) &&
148
- to.is_auto_assigned &&
149
- references[0].from.identifier_columns.size == 1 &&
150
- references[0].from == last_table_ref.from
151
- end
152
-
153
- # What's the underlying SQL data type of this column?
154
- def type
155
- params = {}
156
- constraints = []
157
- return ["BIT", params, constraints] if references[-1].is_unary # It's a unary
158
-
159
- # Add a role value constraint
160
- # REVISIT: Can add join-role-value-constraints here, if we ever provide a way to define them
161
- if references[-1].to_role && references[-1].to_role.role_value_constraint
162
- constraints << references[-1].to_role.role_value_constraint
163
- end
164
-
165
- vt = references[-1].is_self_value ? references[-1].from : references[-1].to
166
- begin
167
- params[:length] ||= vt.length if vt.length.to_i != 0
168
- params[:scale] ||= vt.scale if vt.scale.to_i != 0
169
- constraints << vt.value_constraint if vt.value_constraint
170
- last_vt = vt
171
- vt = vt.supertype
172
- end while vt
173
- params[:underlying_type] = last_vt
174
- return [last_vt.name, params, constraints]
175
- end
176
-
177
- # The comment is the readings from the References expressed as a series of steps (not a full verbalisation)
178
- def comment
179
- @references.map do |ref|
180
- ref.verbalised_path
181
- end.compact * " and "
182
- end
183
-
184
- def to_s #:nodoc:
185
- "#{@references[0].from.name} column #{name('.')}"
186
- end
187
- end
188
-
189
- class Reference
190
- def columns(excluded_supertypes) #:nodoc:
191
- kind = ""
192
- cols =
193
- if is_unary
194
- kind = "unary "
195
- objectified_unary_columns =
196
- ((@to && @to.fact_type) ? @to.all_columns(excluded_supertypes) : [])
197
-
198
- =begin
199
- # This code omits the unary if it's objectified and that plays a mandatory role
200
- first_mandatory_column = nil
201
- if (@to && @to.fact_type)
202
- trace :unary_col, "Deciding whether to skip unary column for #{inspect}" do
203
- first_mandatory_column =
204
- objectified_unary_columns.detect do |col| # Detect a mandatory column for the unary
205
- trace :unary_col, "checking column #{col.name}" do
206
- !col.references.detect do |ref|
207
- trace :unary_col, "#{ref} is mandatory=#{ref.is_mandatory.inspect}"
208
- !ref.is_mandatory
209
- end
210
- end
211
- end
212
- if is_from_objectified_fact && first_mandatory_column
213
- trace :unary_col, "Skipping unary column for #{inspect} because #{first_mandatory_column.name} is mandatory"
214
- end
215
- end
216
- end
217
-
218
- (is_from_objectified_fact && first_mandatory_column ? [] : [Column.new()]) + # The unary itself, unless its objectified
219
- =end
220
-
221
- [Column.new()] + # The unary itself
222
- objectified_unary_columns
223
- elsif is_self_value
224
- kind = "self-role "
225
- [Column.new()]
226
- elsif is_simple_reference
227
- @to.reference_columns(excluded_supertypes)
228
- else
229
- kind = "absorbing "
230
- @to.all_columns(excluded_supertypes)
231
- end
232
-
233
- cols.each do |c|
234
- c.prepend self
235
- end
236
-
237
- trace :columns, "Columns from #{kind}#{self}" do
238
- cols.each {|c|
239
- trace :columns, "#{c}"
240
- }
241
- end
242
- end
243
- end
244
- end
245
-
246
- module Metamodel #:nodoc:
247
- # The ObjectType class is defined in the metamodel; full documentation is not generated.
248
- # This section shows the features relevant to relational Persistence.
249
- class ObjectType
250
- # The array of columns for this ObjectType's table
251
- def columns
252
- @columns || populate_columns
253
- end
254
-
255
- def populate_columns #:nodoc:
256
- @columns =
257
- all_columns({})
258
- end
259
-
260
- def wipe_columns
261
- @columns = nil
262
- end
263
- end
264
-
265
- # The ValueType class is defined in the metamodel; full documentation is not generated.
266
- # This section shows the features relevant to relational Persistence.
267
- class ValueType < DomainObjectType
268
- # The identifier_columns for a ValueType can only ever be the self-value role that was injected
269
- def identifier_columns
270
- trace :columns, "Identifier Columns for #{name}" do
271
- raise "Illegal call to identifier_columns for absorbed ValueType #{name}" unless is_table
272
- if isr = injected_surrogate_role
273
- columns.select{|column| column.references[0].from_role == isr }
274
- else
275
- columns.select{|column| column.references[0] == self_value_reference}
276
- end
277
- end
278
- end
279
-
280
- # When creating a foreign key to this ValueType, what columns must we include?
281
- # This must be a fresh copy, because the columns will have References prepended
282
- def reference_columns(excluded_supertypes) #:nodoc:
283
- trace :columns, "Reference Columns for #{name}" do
284
- if is_table
285
- if isr = injected_surrogate_role
286
- ref_from = references_from.detect{|ref| ref.from_role == isr}
287
- [ActiveFacts::Persistence::Column.new(ref_from)]
288
- else
289
- [ActiveFacts::Persistence::Column.new(self_value_reference)]
290
- end
291
- else
292
- [ActiveFacts::Persistence::Column.new]
293
- end
294
- end
295
- end
296
-
297
- # When absorbing this ValueType, what columns must be absorbed?
298
- # This must be a fresh copy, because the columns will have References prepended.
299
- def all_columns(excluded_supertypes) #:nodoc:
300
- columns = []
301
- trace :columns, "All Columns for #{name}" do
302
- if is_table
303
- self_value_reference
304
- else
305
- columns << ActiveFacts::Persistence::Column.new
306
- end
307
- references_from.each do |ref|
308
- trace :columns, "Columns absorbed via #{ref}" do
309
- columns += ref.columns({})
310
- end
311
- end
312
- end
313
- columns
314
- end
315
-
316
- # If someone asks for this, it's because it's needed, so create it.
317
- def self_value_reference #:nodoc:
318
- # Make a reference for the self-value column
319
- @self_value_reference ||= ActiveFacts::Persistence::Reference.new(self, nil).tabulate
320
- end
321
- end
322
-
323
- # The EntityType class is defined in the metamodel; full documentation is not generated.
324
- # This section shows the features relevant to relational Persistence.
325
- class EntityType < DomainObjectType
326
- # The identifier_columns for an EntityType are the columns that result from the identifying roles
327
- def identifier_columns
328
- trace :columns, "Identifier Columns for #{name}" do
329
- if absorbed_via and
330
- # If this is a subtype that has its own identification, use that.
331
- (all_type_inheritance_as_subtype.size == 0 ||
332
- all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
333
- return absorbed_via.from.identifier_columns
334
- end
335
-
336
- preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
337
- ref = references_from.detect {|ref| ref.to_role == role_ref.role}
338
-
339
- columns.select{|column| column.references[0] == ref}
340
- end.flatten
341
- end
342
- end
343
-
344
- # When creating a foreign key to this EntityType, what columns must we include (the identifier columns)?
345
- # This must be a fresh copy, because the columns will have References prepended
346
- def reference_columns(excluded_supertypes) #:nodoc:
347
- trace :columns, "Reference Columns for #{name}" do
348
-
349
- if absorbed_via and
350
- # If this is not a subtype, or is a subtype that has its own identification, use the id.
351
- (all_type_inheritance_as_subtype.size == 0 ||
352
- all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
353
- rc = absorbed_via.from.reference_columns(excluded_supertypes)
354
- # The absorbed_via reference gets skipped here, and also in object_type.rb
355
- trace :columns, "Skipping #{absorbed_via}"
356
- absorbed_mirror ||= absorbed_via.reversed
357
- rc.each{|col| col.prepend(absorbed_mirror)}
358
- return rc
359
- end
360
-
361
- # REVISIT: Should have built preferred_identifier_references
362
- preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
363
- # REVISIT: Should index references by to_role:
364
- ref = references_from.detect {|ref| ref.to_role == role_ref.role}
365
-
366
- raise "reference for role #{role_ref.describe} not found on #{name} in #{references_from.size} references:\n\t#{references_from.map(&:to_s)*"\n\t"}" unless ref
367
-
368
- ref.columns({})
369
- end.flatten
370
- end
371
- end
372
-
373
- # When absorbing this EntityType, what columns must be absorbed?
374
- # This must be a fresh copy, because the columns will have References prepended.
375
- def all_columns(excluded_supertypes) #:nodoc:
376
- trace :columns, "All Columns for #{name}" do
377
- columns = []
378
- sups = supertypes
379
- pi_roles = preferred_identifier.role_sequence.all_role_ref.map{|rr| rr.role}
380
- references_from.sort_by do |ref|
381
- # Put supertypes first, in order, then PI roles, non-subtype references by name, then subtypes by name:
382
- next [0, p] if p = sups.index(ref.to)
383
- if !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
384
- next [1, p] if p = pi_roles.index(ref.to_role)
385
- next [2, ref.to_names]
386
- end
387
- [3, ref.to_names]
388
- end.each do |ref|
389
- trace :columns, "Columns absorbed via #{ref}" do
390
- if (ref.role_type == :supertype)
391
- if excluded_supertypes[ref.to]
392
- trace :columns, "Exclude #{ref.to.name}, we already inherited it"
393
- next
394
- end
395
-
396
- next if (ref.to.absorbed_via != ref)
397
- excluded_supertypes[ref.to] = true
398
- columns += ref.columns(excluded_supertypes)
399
- else
400
- columns += ref.columns({})
401
- end
402
- end
403
- end
404
- columns
405
- end
406
- end
407
- end
408
-
409
- # The Vocabulary class is defined in the metamodel; full documentation is not generated.
410
- # This section shows the features relevant to relational Persistence.
411
- class Vocabulary
412
- # Make schema transformations like adding ValueType self-value columns (and later, Rails-friendly ID fields).
413
- # Override this method to change the transformations
414
- def finish_schema
415
- all_object_type.each do |object_type|
416
- object_type.self_value_reference if object_type.is_a?(ActiveFacts::Metamodel::ValueType) && object_type.is_table
417
- end
418
- end
419
-
420
- def populate_all_columns #:nodoc:
421
- # REVISIT: Is now a good time to apply schema transforms or should this be more explicit?
422
- finish_schema
423
-
424
- trace :columns, "Populating all columns" do
425
- all_object_type.each do |object_type|
426
- next if !object_type.is_table
427
- trace :columns, "Populating columns for table #{object_type.name}" do
428
- object_type.populate_columns
429
- end
430
- end
431
- end
432
- trace :columns, "Finished columns" do
433
- all_object_type.each do |object_type|
434
- next if !object_type.is_table
435
- trace :columns, "Finished columns for table #{object_type.name}" do
436
- object_type.columns.each do |column|
437
- trace :columns, "#{column}"
438
- end
439
- end
440
- end
441
- end
442
- end
443
- end
444
-
445
- end
446
- end