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,457 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler < ActiveFacts::CQL::Parser
4
-
5
- class ReferenceMode
6
- attr_reader :name, :value_constraint, :parameters
7
-
8
- def initialize name, value_constraint, parameters
9
- @name = name
10
- @value_constraint = value_constraint
11
- @parameters = parameters
12
- end
13
-
14
- def to_s
15
- "identified by its #{name}" +
16
- ((p = @parameters).size > 0 ? '('+p*', '+')' : '') +
17
- ((v = @value_constraint) ? v.to_s : '')
18
- end
19
- end
20
-
21
- class EntityType < ObjectType
22
- def initialize name, supertypes, identification, pragmas, clauses, context_note
23
- super name
24
- @supertypes = supertypes
25
- @identification = identification
26
- @pragmas = pragmas
27
- @clauses = clauses || []
28
- @context_note = context_note
29
- end
30
-
31
- def compile
32
- @entity_type = @vocabulary.valid_entity_type_name(@name) ||
33
- @constellation.EntityType(@vocabulary, @name, :concept => :new)
34
- @entity_type.is_independent = true if @pragmas.delete('independent')
35
-
36
- # REVISIT: CQL needs a way to indicate whether subtype migration can occur.
37
- # For example by saying "Xyz is a role of Abc".
38
- @supertypes.each_with_index do |supertype_name, i|
39
- add_supertype(supertype_name, @identification || i > 0)
40
- end
41
- @pragmas.each do |p|
42
- @constellation.ConceptAnnotation(:concept => @entity_type.concept, :mapping_annotation => p)
43
- end if @pragmas
44
-
45
- context = CompilationContext.new(@vocabulary)
46
-
47
- # Identification may be via a mode (create it) or by forward-referenced entity types (allow those):
48
- prepare_identifier context
49
-
50
- context.bind @clauses, @identification.is_a?(Array) ? @identification : []
51
-
52
- # Create the fact types that define the identifying roles:
53
- fact_types = create_identifying_fact_types context
54
-
55
- # At this point, @identification is an array of References and/or Clauses (for unary fact types)
56
- # Have to do this after creating the necessary fact types
57
- complete_reference_mode_fact_type fact_types
58
-
59
- # Find the roles to use if we have to create an identifying uniqueness constraint:
60
- identifying_roles = bind_identifying_roles context
61
-
62
- make_preferred_identifier_over_roles identifying_roles
63
-
64
- if @context_note
65
- @context_note.compile(@constellation, @entity_type)
66
- end
67
-
68
- @clauses.each do |clause|
69
- next unless clause.context_note
70
- clause.context_note.compile(@constellation, @entity_type)
71
- end
72
-
73
- @entity_type
74
- end
75
-
76
- def prepare_identifier context
77
- # Figure out the identification mode or roles, if any:
78
- if @identification
79
- if @identification.is_a? ReferenceMode
80
- make_entity_type_refmode_valuetypes(name, @identification.name, @identification.parameters)
81
- vt_name = @reference_mode_value_type.name
82
- @identification = [Compiler::Reference.new(vt_name, nil, nil, nil, nil, nil, @identification.value_constraint, nil)]
83
- else
84
- context.allowed_forward_terms = legal_forward_references(@identification)
85
- end
86
- end
87
- end
88
-
89
- # Names used in the identifying roles list may be forward referenced:
90
- def legal_forward_references(identification_phrases)
91
- identification_phrases.map do |phrase|
92
- phrase.is_a?(Reference) ? phrase.term : nil
93
- end.compact.uniq
94
- end
95
-
96
- def bind_identifying_roles context
97
- return unless @identification
98
- @identification.map do |id|
99
- if id.is_a?(Reference)
100
- binding = id.binding
101
- roles = binding.refs.map{|r|r.role || (rr=r.role_ref and rr.role)}.compact.uniq
102
- raise "Looking for an occurrence of identifying role #{id.inspect}, but found #{roles.size == 0 ? "none" : roles.size}" if roles.size != 1
103
- roles[0]
104
- else
105
- # id is a clause of a unary fact type.
106
- id.identify_other_players context
107
- id.bind context
108
- matching_clause =
109
- @clauses.detect { |clause| clause.phrases_match id.phrases }
110
- raise "Unary identifying role '#{id.inspect}' is not found in the defined fact types" unless matching_clause
111
- matching_clause.fact_type.all_role.single
112
- end
113
- end
114
- end
115
-
116
- def make_preferred_identifier_over_roles identifying_roles
117
- return unless identifying_roles && identifying_roles.size > 0
118
- role_sequence = @constellation.RoleSequence(:new)
119
- identifying_roles.each_with_index do |identifying_role, index|
120
- @constellation.RoleRef(role_sequence, index, :role => identifying_role)
121
- end
122
-
123
- # Find a uniqueness constraint as PI, or make one
124
- pc = find_pc_over_roles(identifying_roles)
125
- if (pc)
126
- pc.is_preferred_identifier = true
127
- pc.name = "#{@entity_type.name}PK" unless pc.name
128
- trace :constraint, "Existing PC #{pc.verbalise} is now PK for #{@entity_type.name}"
129
- else
130
- # Add a unique constraint over all identifying roles
131
- pc = @constellation.PresenceConstraint(
132
- :new,
133
- :vocabulary => @vocabulary,
134
- :name => "#{@entity_type.name}PK", # Is this a useful name?
135
- :role_sequence => role_sequence,
136
- :is_preferred_identifier => true,
137
- :max_frequency => 1 # Unique
138
- #:is_mandatory => true,
139
- #:min_frequency => 1,
140
- )
141
- trace :constraint, "Made new preferred PC GUID=#{pc.concept.guid} min=nil max=1 over #{role_sequence.describe}"
142
- end
143
- end
144
-
145
- def find_pc_over_roles(roles)
146
- return nil if roles.size == 0 # Safeguard; this would chuck an exception otherwise
147
- roles[0].all_role_ref.each do |role_ref|
148
- next if role_ref.role_sequence.all_role_ref.map(&:role) != roles
149
- pc = role_ref.role_sequence.all_presence_constraint.single # Will return nil if there's more than one.
150
- #puts "Existing PresenceConstraint matches those roles!" if pc
151
- return pc if pc
152
- end
153
- nil
154
- end
155
-
156
- def create_identifying_fact_types context
157
- fact_types = []
158
- # Categorise the clauses into fact types according to the roles they play.
159
- @clauses.inject({}) do |hash, clause|
160
- players_key = clause.refs.map{|vr| vr.key.compact}.sort
161
- (hash[players_key] ||= []) << clause
162
- hash
163
- end.each do |players_key, clauses|
164
- # REVISIT: Loose binding goes here; it might merge some Compiler#Roles
165
-
166
- fact_type = create_identifying_fact_type(context, clauses)
167
- fact_types << fact_type if fact_type
168
- unless fact_type.all_role.detect{|r| r.object_type == @entity_type}
169
- objectify_existing_fact_type(fact_type)
170
- end
171
- end
172
- fact_types
173
- end
174
-
175
- def create_identifying_fact_type context, clauses
176
- # See if any fact type already exists (this ET cannot be a player, but might objectify it)
177
- existing_clauses = clauses.select{ |clause| clause.match_existing_fact_type context }
178
- if negation = existing_clauses.detect{|c| c.certainty == false }
179
- raise "#{@name} cannot be identified by negated fact type #{negation.inspect}"
180
- end
181
- any_matched = existing_clauses.size > 0
182
-
183
- operation = any_matched ? 'Objectifying' : 'Creating'
184
- player_names = clauses[0].refs.map{|vr| vr.key.compact*'-'}
185
- trace :matching, "#{operation} fact type for #{clauses.size} clauses over (#{player_names*', '})" do
186
- if any_matched # There's an existing fact type we must be objectifying
187
- fact_type = objectify_existing_fact_type(existing_clauses[0].fact_type)
188
- end
189
-
190
- unless fact_type
191
- fact_type = clauses[0].make_fact_type(@vocabulary)
192
- clauses[0].make_reading(@vocabulary, fact_type)
193
- clauses[0].make_embedded_constraints vocabulary
194
- existing_clauses = [clauses[0]]
195
- end
196
-
197
- (clauses - existing_clauses).each do |clause|
198
- clause.make_reading(@vocabulary, fact_type)
199
- clause.make_embedded_constraints vocabulary
200
- end
201
-
202
- fact_type
203
- end
204
- end
205
-
206
- def objectify_existing_fact_type fact_type
207
- raise "#{@name} cannot objectify fact type '#{fact_type.entity_type.name}' that's already objectified" if fact_type.entity_type
208
- if @fact_type
209
- raise "#{@name} cannot objectify '#{fact_type.default_reading}', it already objectifies '#{@fact_type.default_reading}'"
210
- end
211
-
212
- if fact_type.internal_presence_constraints.select{|pc| pc.max_frequency == 1}.size == 0
213
- # If there's no existing uniqueness constraint over this fact type, make a spanning one.
214
- pc = @constellation.PresenceConstraint(
215
- :new,
216
- :vocabulary => @vocabulary,
217
- :name => @entity_type.name+"UQ",
218
- :role_sequence => fact_type.preferred_reading.role_sequence,
219
- :is_preferred_identifier => false, # We only get here when there is a reference mode on the entity type
220
- :max_frequency => 1
221
- )
222
- trace :constraint, "Made new objectification PC GUID=#{pc.concept.guid} min=nil max=1 over #{fact_type.preferred_reading.role_sequence.describe}"
223
- end
224
-
225
- @fact_type = @entity_type.fact_type = fact_type
226
- @entity_type.create_implicit_fact_types # REVISIT: Could there be readings for the implicit fact types here?
227
- @fact_type
228
- end
229
-
230
- def add_supertype(supertype_name, not_identifying)
231
- trace :supertype, "Adding #{not_identifying ? '' : 'identifying '}supertype #{supertype_name} to #{@entity_type.name}" do
232
- supertype = @vocabulary.valid_entity_type_name(supertype_name) ||
233
- @constellation.EntityType(@vocabulary, supertype_name, :concept => :new) # Should always already exist
234
-
235
- # Did we already know about this supertyping?
236
- return if @entity_type.all_type_inheritance_as_subtype.detect{|ti| ti.supertype == supertype}
237
-
238
- # By default, the first supertype identifies this entity type
239
- is_identifying_supertype = !not_identifying && @entity_type.all_type_inheritance_as_subtype.size == 0
240
-
241
- inheritance_fact = @constellation.TypeInheritance(@entity_type, supertype, :concept => :new)
242
-
243
- assimilation_pragmas = ['absorbed', 'separate', 'partitioned']
244
- assimilations = @pragmas.select { |p| assimilation_pragmas.include? p}
245
- @pragmas -= assimilation_pragmas
246
- raise "Conflicting assimilation pragmas #{assimilations*', '}" if assimilations.size > 1
247
- inheritance_fact.assimilation = assimilations[0]
248
-
249
- # Create a reading:
250
- sub_role = @constellation.Role(inheritance_fact, 0, :object_type => @entity_type, :concept => :new)
251
- super_role = @constellation.Role(inheritance_fact, 1, :object_type => supertype, :concept => :new)
252
-
253
- rs = @constellation.RoleSequence(:new)
254
- @constellation.RoleRef(rs, 0, :role => sub_role)
255
- @constellation.RoleRef(rs, 1, :role => super_role)
256
- @constellation.Reading(inheritance_fact, 0, :role_sequence => rs, :text => "{0} is a kind of {1}", :is_negative => false)
257
-
258
- rs2 = @constellation.RoleSequence(:new)
259
- @constellation.RoleRef(rs2, 0, :role => super_role)
260
- @constellation.RoleRef(rs2, 1, :role => sub_role)
261
- # Decide in which order to include is a/is an. Provide both, but in order.
262
- n = 'aeioh'.include?(sub_role.object_type.name.downcase[0]) ? 'n' : ''
263
- @constellation.Reading(inheritance_fact, 2, :role_sequence => rs2, :text => "{0} is a#{n} {1}", :is_negative => false)
264
-
265
- if is_identifying_supertype
266
- inheritance_fact.provides_identification = true
267
- end
268
-
269
- # Create uniqueness constraints over the subtyping fact type.
270
- p1rs = @constellation.RoleSequence(:new)
271
- @constellation.RoleRef(p1rs, 0).role = sub_role
272
- pc1 = @constellation.PresenceConstraint(:new, :vocabulary => @vocabulary)
273
- pc1.name = "#{@entity_type.name}MustHaveSupertype#{supertype.name}"
274
- pc1.role_sequence = p1rs
275
- pc1.is_mandatory = true # A subtype instance must have a supertype instance
276
- pc1.min_frequency = 1
277
- pc1.max_frequency = 1
278
- pc1.is_preferred_identifier = false
279
- trace :constraint, "Made new subtype PC GUID=#{pc1.concept.guid} min=1 max=1 over #{p1rs.describe}"
280
-
281
- p2rs = @constellation.RoleSequence(:new)
282
- constellation.RoleRef(p2rs, 0).role = super_role
283
- pc2 = constellation.PresenceConstraint(:new, :vocabulary => @vocabulary)
284
- pc2.name = "#{supertype.name}MayBeA#{@entity_type.name}"
285
- pc2.role_sequence = p2rs
286
- pc2.is_mandatory = false
287
- pc2.min_frequency = 0
288
- pc2.max_frequency = 1
289
- # The supertype role often identifies the subtype:
290
- pc2.is_preferred_identifier = inheritance_fact.provides_identification
291
- trace :supertype, "identification of #{@entity_type.name} via supertype #{supertype.name} was #{inheritance_fact.provides_identification ? '' : 'not '}added"
292
- trace :constraint, "Made new supertype PC GUID=#{pc2.concept.guid} min=1 max=1 over #{p2rs.describe}"
293
- end
294
- end
295
-
296
- def make_entity_type_refmode_valuetypes(name, mode, parameters)
297
- vt_name = "#{name}#{mode}"
298
- vt = nil
299
- trace :entity, "Preparing value type #{vt_name} for reference mode" do
300
- # Find an existing ValueType called 'vt_name' or 'name vtname'
301
- # or find/create the supertype '#{mode}' and the subtype
302
- unless vt = @vocabulary.valid_object_type_name(vt_name) or
303
- vt = @vocabulary.valid_object_type_name(vt_name = "#{name} #{mode}")
304
- base_vt = @vocabulary.valid_value_type_name(mode) ||
305
- @constellation.ValueType(@vocabulary, mode, :concept => :new)
306
- vt = @constellation.ValueType(@vocabulary, vt_name, :supertype => base_vt, :concept => :new)
307
- if parameters
308
- length, scale = *parameters
309
- vt.length = length if length
310
- vt.scale = scale if scale
311
- end
312
- else
313
- trace :entity, "Value type #{vt_name} already exists"
314
- end
315
- end
316
-
317
- # REVISIT: If we do this, it gets emitted twice when we generate CQL.
318
- # The generator should detect that the value_constraint is the same and not emit it.
319
- #if (ranges = identification[:value_constraint])
320
- # vt.value_constraint = value_constraint(ranges, identification[:enforcement])
321
- #end
322
- @reference_mode_value_type = vt
323
- end
324
-
325
- def complete_reference_mode_fact_type(fact_types)
326
- return unless identifying_type = @reference_mode_value_type
327
-
328
- # Find an existing fact type, if any:
329
- entity_role = identifying_role = nil
330
- fact_type = fact_types.detect do |ft|
331
- identifying_role = ft.all_role.detect{|r| r.object_type == identifying_type } and
332
- entity_role = ft.all_role.detect{|r| r.object_type == @entity_type }
333
- end
334
-
335
- # Create an identifying fact type if needed:
336
- unless fact_type
337
- fact_type = @constellation.FactType(:new)
338
- fact_types << fact_type
339
- entity_role = @constellation.Role(fact_type, 0, :object_type => @entity_type, :concept => :new)
340
- identifying_role = @constellation.Role(fact_type, 1, :object_type => identifying_type, :concept => :new)
341
- end
342
- @identification[0].role = identifying_role
343
-
344
- if (value_constraint = @identification[0].value_constraint)
345
- # The value_constraint applies only to the value role, not to the underlying value type
346
- # Decide whether this puts the value_constraint in the right place:
347
- value_constraint.constellation = fact_type.constellation
348
- identifying_role.role_value_constraint = value_constraint.compile
349
- end
350
-
351
- # Find all role sequences over the fact type's two roles
352
- rss = entity_role.all_role_ref.select do |rr|
353
- rr.role_sequence.all_role_ref.size == 2 &&
354
- (rr.role_sequence.all_role_ref.to_a-[rr])[0].role == identifying_role
355
- end.map{|rr| rr.role_sequence}
356
-
357
- # Make a forward reading, if there is none already:
358
- # Find or create RoleSequences for the forward and reverse readings:
359
- rs01 = rss.select{|rs| rs.all_role_ref.sort_by{|rr| rr.ordinal}.map(&:role) == [entity_role, identifying_role] }[0]
360
- if !rs01
361
- rs01 = @constellation.RoleSequence(:new)
362
- @constellation.RoleRef(rs01, 0, :role => entity_role)
363
- @constellation.RoleRef(rs01, 1, :role => identifying_role)
364
- end
365
- if rs01.all_reading.empty?
366
- @constellation.Reading(fact_type, fact_type.all_reading.size, :role_sequence => rs01, :text => "{0} has {1}", :is_negative => false)
367
- trace :mode, "Creating new forward reading '#{entity_role.object_type.name} has #{identifying_type.name}'"
368
- else
369
- trace :mode, "Using existing forward reading"
370
- end
371
-
372
- # Make a reverse reading if none exists
373
- rs10 = rss.select{|rs| rs.all_role_ref.sort_by{|rr| rr.ordinal}.map(&:role) == [identifying_role, entity_role] }[0]
374
- if !rs10
375
- rs10 = @constellation.RoleSequence(:new)
376
- @constellation.RoleRef(rs10, 0, :role => identifying_role)
377
- @constellation.RoleRef(rs10, 1, :role => entity_role)
378
- end
379
- if rs10.all_reading.empty?
380
- @constellation.Reading(fact_type, fact_type.all_reading.size, :role_sequence => rs10, :text => "{0} is of {1}", :is_negative => false)
381
- trace :mode, "Creating new reverse reading '#{identifying_type.name} is of #{entity_role.object_type.name}'"
382
- else
383
- trace :mode, "Using existing reverse reading"
384
- end
385
-
386
- # Entity must have one identifying instance. Find or create the role sequence, then create a PC if necessary
387
- rs0 = entity_role.all_role_ref.select{|rr| rr.role_sequence.all_role_ref.size == 1}[0]
388
- if rs0
389
- rs0 = rs0.role_sequence
390
- trace :mode, "Using existing EntityType role sequence"
391
- else
392
- rs0 = @constellation.RoleSequence(:new)
393
- @constellation.RoleRef(rs0, 0, :role => entity_role)
394
- trace :mode, "Creating new EntityType role sequence"
395
- end
396
- if (rs0.all_presence_constraint.size == 0)
397
- constraint = @constellation.PresenceConstraint(
398
- :new,
399
- :name => '',
400
- :vocabulary => @vocabulary,
401
- :role_sequence => rs0,
402
- :min_frequency => 1,
403
- :max_frequency => 1,
404
- :is_preferred_identifier => false,
405
- :is_mandatory => true
406
- )
407
- trace :constraint, "Made new refmode PC GUID=#{constraint.concept.guid} min=1 max=1 over #{rs0.describe}"
408
- else
409
- trace :mode, "Using existing EntityType PresenceConstraint"
410
- end
411
-
412
- # Value Type must have a value type. Find or create the role sequence, then create a PC if necessary
413
- trace :mode, "identifying_role has #{identifying_role.all_role_ref.size} attached sequences"
414
- trace :mode, "identifying_role has #{identifying_role.all_role_ref.select{|rr| rr.role_sequence.all_role_ref.size == 1}.size} unary sequences"
415
- rs1 = identifying_role.all_role_ref.select{|rr| rr.role_sequence.all_role_ref.size == 1 ? rr.role_sequence : nil }.compact[0]
416
- if (!rs1)
417
- rs1 = @constellation.RoleSequence(:new)
418
- @constellation.RoleRef(rs1, 0, :role => identifying_role)
419
- trace :mode, "Creating new ValueType role sequence"
420
- else
421
- rs1 = rs1.role_sequence
422
- trace :mode, "Using existing ValueType role sequence"
423
- end
424
- if (rs1.all_presence_constraint.size == 0)
425
- constraint = @constellation.PresenceConstraint(
426
- :new,
427
- :name => '',
428
- :vocabulary => @vocabulary,
429
- :role_sequence => rs1,
430
- :min_frequency => 0,
431
- :max_frequency => 1,
432
- :is_preferred_identifier => true,
433
- :is_mandatory => false
434
- )
435
- trace :constraint, "Made new refmode ValueType PC GUID=#{constraint.concept.guid} min=0 max=1 over #{rs1.describe}"
436
- else
437
- trace :mode, "Marking existing ValueType PresenceConstraint as preferred"
438
- rs1.all_presence_constraint.single.is_preferred_identifier = true
439
- end
440
- end
441
-
442
- def to_s
443
- "EntityType: #{super} #{
444
- @supertypes.size > 0 ? "< #{@supertypes*','} " : ''
445
- }#{
446
- @identification.is_a?(ReferenceMode) ? @identification.to_s : @identification.inspect
447
- }#{
448
- @clauses.size > 0 ? " where #{@clauses.inspect}" : ''
449
- }#{
450
- @pragmas.size > 0 ? ", pragmas [#{@pragmas*','}]" : ''
451
- };"
452
- end
453
- end
454
-
455
- end
456
- end
457
- end