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,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