activefacts 0.8.16 → 0.8.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +15 -0
  2. data/Manifest.txt +10 -4
  3. data/bin/afgen +26 -20
  4. data/bin/cql +1 -1
  5. data/css/orm2.css +89 -9
  6. data/examples/CQL/CompanyDirectorEmployee.cql +4 -4
  7. data/examples/CQL/Genealogy.cql +5 -5
  8. data/examples/CQL/Metamodel.cql +121 -91
  9. data/examples/CQL/MonthInSeason.cql +2 -6
  10. data/examples/CQL/SeparateSubtype.cql +11 -9
  11. data/examples/CQL/ServiceDirector.cql +21 -33
  12. data/examples/CQL/Supervision.cql +0 -3
  13. data/examples/CQL/WindowInRoomInBldg.cql +10 -4
  14. data/examples/CQL/unit.cql +1 -1
  15. data/lib/activefacts.rb +1 -0
  16. data/lib/activefacts/cql/CQLParser.treetop +5 -1
  17. data/lib/activefacts/cql/Context.treetop +2 -7
  18. data/lib/activefacts/cql/Expressions.treetop +2 -2
  19. data/lib/activefacts/cql/FactTypes.treetop +37 -31
  20. data/lib/activefacts/cql/Language/English.treetop +21 -4
  21. data/lib/activefacts/cql/LexicalRules.treetop +59 -1
  22. data/lib/activefacts/cql/ObjectTypes.treetop +22 -12
  23. data/lib/activefacts/cql/Terms.treetop +13 -9
  24. data/lib/activefacts/cql/ValueTypes.treetop +30 -11
  25. data/lib/activefacts/cql/compiler.rb +34 -5
  26. data/lib/activefacts/cql/compiler/clause.rb +207 -116
  27. data/lib/activefacts/cql/compiler/constraint.rb +129 -105
  28. data/lib/activefacts/cql/compiler/entity_type.rb +49 -27
  29. data/lib/activefacts/cql/compiler/expression.rb +71 -42
  30. data/lib/activefacts/cql/compiler/fact.rb +70 -64
  31. data/lib/activefacts/cql/compiler/fact_type.rb +108 -57
  32. data/lib/activefacts/cql/compiler/query.rb +178 -0
  33. data/lib/activefacts/cql/compiler/shared.rb +13 -12
  34. data/lib/activefacts/cql/compiler/value_type.rb +10 -4
  35. data/lib/activefacts/cql/nodes.rb +1 -1
  36. data/lib/activefacts/cql/parser.rb +6 -2
  37. data/lib/activefacts/generate/absorption.rb +6 -3
  38. data/lib/activefacts/generate/cql.rb +140 -84
  39. data/lib/activefacts/generate/dm.rb +12 -6
  40. data/lib/activefacts/generate/help.rb +25 -6
  41. data/lib/activefacts/generate/helpers/oo.rb +195 -0
  42. data/lib/activefacts/generate/helpers/ordered.rb +589 -0
  43. data/lib/activefacts/generate/helpers/rails.rb +57 -0
  44. data/lib/activefacts/generate/html/glossary.rb +274 -54
  45. data/lib/activefacts/generate/json.rb +25 -22
  46. data/lib/activefacts/generate/null.rb +1 -0
  47. data/lib/activefacts/generate/rails/models.rb +244 -0
  48. data/lib/activefacts/generate/rails/schema.rb +185 -0
  49. data/lib/activefacts/generate/records.rb +1 -0
  50. data/lib/activefacts/generate/ruby.rb +51 -30
  51. data/lib/activefacts/generate/sql/mysql.rb +5 -3
  52. data/lib/activefacts/generate/sql/server.rb +8 -4
  53. data/lib/activefacts/generate/text.rb +1 -0
  54. data/lib/activefacts/generate/transform/surrogate.rb +209 -0
  55. data/lib/activefacts/generate/version.rb +1 -0
  56. data/lib/activefacts/input/orm.rb +234 -181
  57. data/lib/activefacts/mapping/rails.rb +122 -0
  58. data/lib/activefacts/persistence/columns.rb +34 -18
  59. data/lib/activefacts/persistence/foreignkey.rb +129 -71
  60. data/lib/activefacts/persistence/index.rb +42 -12
  61. data/lib/activefacts/persistence/reference.rb +37 -23
  62. data/lib/activefacts/persistence/tables.rb +53 -19
  63. data/lib/activefacts/registry.rb +11 -0
  64. data/lib/activefacts/support.rb +28 -10
  65. data/lib/activefacts/version.rb +1 -1
  66. data/lib/activefacts/vocabulary/extensions.rb +246 -117
  67. data/lib/activefacts/vocabulary/metamodel.rb +105 -65
  68. data/lib/activefacts/vocabulary/verbaliser.rb +226 -194
  69. data/spec/absorption_spec.rb +1 -0
  70. data/spec/cql/comparison_spec.rb +8 -8
  71. data/spec/cql/contractions_spec.rb +16 -43
  72. data/spec/cql/entity_type_spec.rb +2 -1
  73. data/spec/cql/expressions_spec.rb +2 -2
  74. data/spec/cql/fact_type_matching_spec.rb +4 -1
  75. data/spec/cql/parser/bad_literals_spec.rb +30 -30
  76. data/spec/cql/parser/entity_types_spec.rb +6 -6
  77. data/spec/cql/parser/expressions_spec.rb +25 -19
  78. data/spec/cql/samples_spec.rb +5 -4
  79. data/spec/cql_cql_spec.rb +2 -1
  80. data/spec/cql_dm_spec.rb +4 -0
  81. data/spec/cql_mysql_spec.rb +4 -0
  82. data/spec/cql_parse_spec.rb +2 -0
  83. data/spec/cql_ruby_spec.rb +4 -0
  84. data/spec/cql_sql_spec.rb +4 -0
  85. data/spec/cqldump_spec.rb +7 -4
  86. data/spec/helpers/parse_to_ast_matcher.rb +7 -3
  87. data/spec/helpers/test_parser.rb +2 -0
  88. data/spec/norma_cql_spec.rb +5 -2
  89. data/spec/norma_ruby_spec.rb +4 -1
  90. data/spec/norma_ruby_sql_spec.rb +4 -1
  91. data/spec/norma_sql_spec.rb +4 -1
  92. data/spec/norma_tables_spec.rb +2 -2
  93. data/spec/ruby_api_spec.rb +1 -1
  94. data/spec/spec_helper.rb +2 -0
  95. data/spec/transform_surrogate_spec.rb +59 -0
  96. metadata +70 -60
  97. data/TODO +0 -308
  98. data/lib/activefacts/cql/compiler/join.rb +0 -162
  99. data/lib/activefacts/generate/oo.rb +0 -176
  100. data/lib/activefacts/generate/ordered.rb +0 -602
data/TODO DELETED
@@ -1,308 +0,0 @@
1
- ActiveFacts ToDo list
2
-
3
- Metamodel
4
- ALWAYS Integrate Metamodel changes through lib/activefacts/vocabulary/metamodel.rb
5
- SOON Add Terms for Object Types
6
- using Words? (which include adjectives/rolenames)
7
- Notes (Extend context notes)
8
- comments in CQL?
9
- Derivation notes?
10
- HelpText?
11
- FBM Standards Metamodel
12
- Migrate towards standard terminology
13
- Make ORM model emit good CQL
14
- Use UUIDs
15
- Renamed from ("Person (was called User) ...")
16
- Multiple revisions?
17
- Extensions (new vocabularies?) for Metamodel
18
- security
19
- processes
20
- discussion/conversation
21
- Implement abstract supertypes?
22
- Allow Object naming "Paris means City 'Paris'"
23
- Use subtype extension in Metamodel (based on abstract SBVR supertypes as shown?)
24
- Meaning
25
- Concept
26
- NounConcept
27
- ObjectType
28
- RolePlaying
29
- FactType
30
- Fact
31
- Value
32
- Query
33
- Lexeme (language/locale sensitive text)
34
- Term
35
- Reading (template text, adjectives)
36
- Value (literal)
37
- Or just have per-locale syntax parser/generator to/from canonical form?
38
- Role names
39
- need to attach to RoleRefs instead of Roles
40
- Refactor RoleRef and RoleSequence so RoleSequence isn't re-used out of context
41
- Index/access-path/ordering pragmas
42
- Temporal literals (expressions using current time)
43
- Temporal: e.g. Date/Time {{/not} {after/before}} Date/Time
44
- SOON Refactor Derived Fact Types (Queries) using new terminology
45
-
46
- CQL
47
- Object Types
48
- ValueTypes
49
- Change so Data Types are not inherited
50
- Implement named parameters
51
- Autogenerated
52
- On assert (UUID)
53
- On save (ID, Timestamp, etc)
54
- Partial auto-counters (Role, *Ordinal*)
55
- Implement base VTs
56
- SOON "vt is written;" syntax
57
- Entity Types
58
- SOON "Et is identified;" forward-reference syntax
59
- Allow other possessive pronouns "Ship is identified by her Name"
60
- Allow shorthand for multi-part identification
61
- "Person is identified by his given-Name and family-Name;"
62
- Subtypes
63
- Support Role subtypes as distinct (subtype migration allowed)
64
- Subtyping fact type role names?
65
- Object Names
66
- "Paris means City 'Paris'"
67
-
68
- Joins
69
- SOON Anti-joins (no, none, negation, "it is not the case that", etc)
70
- SOON Double-contraction "Person who came to Party and was not invited to"
71
- SOON Outer joins ("maybe")
72
- SOON Compile Value join nodes
73
- STARTED, DIFFICULT Implement comparison operators as derived fact types (<, etc)
74
- Automatically detect type conversion joins
75
-
76
- Queries
77
- Expression clauses
78
- Redo grammar as normal clause (A < B -> A rel B)
79
- User-defined expression operators/clauses?
80
- Fact Type Negation (A rel no B, no A rel B)
81
- "returning" clause
82
- Invoke queries using defined role names:
83
- Company has young Person (as Director) where ...
84
- (invoke as "Company has young Director")
85
- Temporal terms and phrases
86
- "now" "4 year ago", "3 minutes from now"
87
- Temporal ValueType to act as a Universal fact type over the domain
88
- e.g. Time.hour -> all possible hours
89
- Figure out what base constraints propagate to the result set
90
- Allow "which" to project roles from a query "which Person gatecrashed Party?"
91
- Value range restrictions (in {1,2,4}) instead of (restricted to {...})
92
-
93
- Linguistic aspects
94
- UTF-8 Support
95
- Other languages
96
- Define syntax for and handle Gender
97
- French
98
- Spanish
99
- Use filename to select (Bar.fr.cql or Bar.cql.fr?)
100
- Use metamodel predicates instead of pragmas
101
- e.g. for "Object type is independent", say "Object Type 'Foo' is independent";
102
- How to handle Fact Type names in the above syntax? Objectify? But need ring constraint roles.
103
- Vocabulary name is implicit here...
104
- SOON Allow more than one Business Context Note per item
105
- Fact type binding
106
- Use non-local role names in fact type matching?
107
- Check that subscripts are being tested properly
108
- Implement some/that binding
109
- subscripts not necessary where "that" is unambiguous.
110
- which/that: "which Person likes that Person?"
111
- Double-hyphen for hyphenated adjectives
112
-
113
- Constraints
114
- SOON Implement "maybe" to make min-frequency non-mandatory
115
- Value Literal syntax constraints
116
- Regexp: "vt is written to match /xyz/"
117
- Regexp for role values
118
- subtype of Value Constraint
119
- PEG Grammars for literals? (extend CQL grammar)
120
- Ring constraints
121
- how to handle ambiguous rings, e.g. in ternaries?
122
- how to handle multiple rings in one FT?
123
- Think about syntax to allow this
124
- Populate Ring Types in metamodel (five unaries?)
125
- Constraint names (esp Presence Constraints, they become index names)
126
- Temporal Modeling ([at most] one at a time)
127
- single table mapping
128
- two tables mappings (current/history)
129
- Add Exclusion constraint syntax using negative clause:
130
- Person is ceo if and only if no Manager manages (that?) Person
131
- Similar case exists for subset constraint?
132
- A rel B only if no B rel C - think through
133
- Delay creation of default identifying constraints for objectified fact types
134
- Perhaps before relational/object mapping?
135
- Or don't create them at all - handle missing PI for OFTs instead
136
- Asserted instances
137
- "including {'foo', 'bar', ...}" akin to "restricted to"...
138
-
139
- Importing vocabularies
140
- Distinguish "import" from "use"?
141
- Bind to imported ValueTypes (and other object types?)
142
- Base vocabularies for SQL
143
- Multiple SQL base vocabs, using db pref to choose between.
144
-
145
- CQL Verbaliser
146
- SOON Detect new fact types that would be interpreted as an existing (only adjectives differ), and use single reading (before double-reading) e.g. other-Role of RingConstraint
147
- Implement some/that binding
148
- use some/that where "that" is unambiguous
149
- Don't emit some/that until binding will use it properly
150
- Instance data verbalisation
151
- Emit objectification joins
152
- Contractions (use Verbaliser!)
153
- Emit example fact from ORM2009 presentation
154
- Output clustering
155
- Emit Value Types just before first use
156
- Emit Constraints as soon as possible
157
- Choose "focus" items with most 1st and 2nd generation dependencies, and do all precursors/followers before choosing another
158
- Left-contraction of joins "Xyz is ... and is ...;"
159
-
160
- Units
161
- SOON Store sample data with specified unit
162
- Handle storing numeric Instance values (noted to be in the lexical form; but strings aren't!)
163
- SOON Save Units on ValueTypes
164
- Generate conversion formula to fundamental types
165
-
166
- CQL Shell
167
- Save definitions, including instances
168
- /sql; generate the SQL for this vocabulary
169
- /valid; check all metamodel constraints over the vocabulary, and/or vocabulary constraints over the population
170
- Queries
171
- /population {open, check, create} database_name
172
- /ruby
173
- /cql
174
-
175
- NORMA reader
176
- NORMA Joins
177
- Detect and store implicit joins in presence constraints (if needed???)
178
- Convert all NORMA Join paths
179
- NORMA input: Warn when preferred reading role order doesn't match the preferred identifier for objectified FTs
180
- Import instance data for objectified fact types
181
- Double-hyphen for hyphenated adjectives
182
-
183
- Generators
184
- Ruby generator
185
- Emit a module method for each example population
186
-
187
- Relational Composition
188
- Subtype Mapping
189
- extension (subtype in separate table)
190
- partition (separate and include all supertype roles)
191
- Make sure all test scenarios are covered
192
- Transforms
193
- Rails ID injection
194
- Subtype discriminator injection where no mandatory role on subtype
195
- Don't introduce additional discriminator for sub-sub-type
196
- Detect non-exclusive subtypes and discriminate combinations
197
- Column name generation
198
- Provide alternative generation pattern(s) (snake-case)
199
- Duplicate column names (detect, handle)
200
- SQL Generation
201
- Auto-generated column types
202
- IDentity fields
203
- GUIDs
204
- partial auto-counters (Ordinal)
205
- Timestamps
206
- other auto-counters?
207
- Foreign Key fields
208
- Index both ends
209
- Determine cascading based on mandatory-ness
210
- Emit triggers where PK is in a subtype (and view was generated)
211
- Existing database/vocabulary
212
- Minimal impact vs refactor and migrate
213
-
214
- Runtime API
215
- Autogenerated Data Types
216
- GUID, Ordinal
217
- Entity
218
- Save identifying roles as Role objects not symbols
219
- SOON Propagate retract() properly (replace delete?)
220
- Subtype migration
221
- Replace instance by instance of different class, de-/re-assign all roles?
222
- Re-use same role proxy/ies?
223
- Role value array proxy class
224
- Handle sorting by residual fields in counterpart's key
225
- Detect & preserve adds/deletes
226
- Correctly handle values across multiple constellations or in no constellation
227
- Verbalisation
228
- SOON Add readings to API
229
- Redo all verbalisation to use readings
230
- Use existing verbalise for to_s
231
- Ensure that all objects and classes verbalise and to_s
232
- SOON verbalise Role Value Array
233
- verbalise takes optional "verbalisation context" object
234
- Which objects have already been verbalised
235
- What role names and/or subscripts have been assigned
236
- Possible to implement as a single-pass process?
237
- Queries
238
- Query DSL/API in Ruby?
239
- CQL Query conversion to SQL (via Ruby?)
240
- Constellation boundaries
241
- Record unpopulated roles and object types during query execution (nil != mu)
242
- Hard vs soft boundary (Auto-fetch vs exception)
243
- RDBMS Platform Support
244
- DataObjects (SQL Server, MySQL, PostgreSQL, Oracle, DB2)
245
- Enumerate tables instead of needing "table" keyword
246
- Log changes to allow update
247
-
248
- Database reverse engineering
249
- Read Linda Bird's PhD thesis
250
- Extract raw schema info
251
- Tables
252
- Columns & types
253
- Null constraints
254
- Unique & primary keys
255
- Foreign keys
256
- Check constraints
257
- Naming Heuristics
258
- Rails
259
- Intuition (FK naming)
260
- Load Rails models
261
- Detect pluralisation
262
- intuit common reference modes (e.g. thing_ID)
263
- Examine data for likely FKs
264
- count, min, max, median, distinct, count(NULL)
265
- Check non-violation of possible FKs:
266
- select count(*) where not exists ...
267
- Decompose to elementary form
268
- Schema transform by manual selection (GUI?)
269
- Deabsorb (incl to use existing type)
270
- Alias name
271
- Project subclass using discriminator
272
- ... other transforms
273
-
274
- Test stubs/mocks
275
- Quality/usage metrics
276
- Mock API
277
- Mock data
278
- Use sample population as test data
279
- incorporate Faker, Machinist, etc
280
-
281
- Packaging and documentation
282
- Split into multiple gems?
283
-
284
- Example models
285
- Convert microformat RDF: http://microformats.org/about, http://www.data-vocabulary.org/
286
-
287
- APRIMO
288
- Overall design
289
- Subscription, list/search models, friends
290
- Diagram view
291
- CQL view
292
- Object type browser
293
- Object Types
294
- Fact Types
295
- Constraints
296
- Instance data
297
- Query builder
298
- AJAX
299
- Design JSON API
300
- Server
301
- Stand-alone???
302
- Metamodel Diagrams
303
- Convert from metamodel to JSON
304
- Database
305
- Derived Fact Types
306
- Constellation declarations
307
- Process models
308
- Units
@@ -1,162 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler < ActiveFacts::CQL::Parser
4
- class Definition
5
- # Make a JoinNode for every variable present in these clauses
6
- def build_join_nodes(clauses_list)
7
- debug :join, "Building join nodes" do
8
- join = @constellation.Join(:new)
9
- all_variables_in_clauses(clauses_list).
10
- each do |variable|
11
- debug :join, "Creating join node #{join.all_join_node.size} for #{variable.inspect}"
12
- variable.join_node = @constellation.JoinNode(join, join.all_join_node.size, :object_type => variable.player)
13
- if literal = variable.refs.detect{|r| r.literal}
14
- if literal.kind_of?(ActiveFacts::CQL::Compiler::VarRef)
15
- literal = literal.literal
16
- end
17
- unit = @constellation.Unit.detect{|k, v| [v.name, v.plural_name].include? literal.unit} if literal.unit
18
- variable.join_node.value = [literal.literal.to_s, literal.is_a?(String), unit]
19
- end
20
- end
21
- join
22
- end
23
- end
24
-
25
- def build_all_join_steps(clauses_list)
26
- roles_by_variable = {}
27
- debug :join, "Building join steps" do
28
- clauses_list.each do |clause|
29
- next if clause.is_naked_object_type
30
- build_join_steps(clause, roles_by_variable)
31
- end
32
- end
33
- roles_by_variable
34
- end
35
-
36
- def build_join_steps clause, roles_by_variable = {}, objectification_node = nil
37
- join_roles = []
38
- incidental_roles = []
39
- debug :join, "Creating join Role Sequence for #{clause.inspect} with #{clause.var_refs.size} role refs" do
40
- objectification_step = nil
41
- clause.var_refs.each do |var_ref|
42
- # These var_refs are the Compiler::VarRefs, which have associated Metamodel::RoleRefs,
43
- # but we need to create JoinRoles for those roles.
44
- # REVISIT: JoinRoles may need to save residual_adjectives
45
- variable = var_ref.variable
46
- role = (var_ref && var_ref.role) || (var_ref.role_ref && var_ref.role_ref.role)
47
- join_role = nil
48
-
49
- debugger unless clause.fact_type
50
- if (clause.fact_type.entity_type)
51
- # This clause is of an objectified fact type.
52
- # We need a join step from this role to the phantom role, but not
53
- # for a role that has only one var_ref (this one) in their variable.
54
- # Create the JoinNode and JoinRole in any case though.
55
- refs_count = variable.refs.size
56
- objectification_ref_count = 0
57
- if var_ref.nested_clauses
58
- var_ref.nested_clauses.each do |ojc|
59
- objectification_ref_count += ojc.var_refs.select{|var_ref| var_ref.variable.refs.size > 1}.size
60
- end
61
- end
62
- refs_count += objectification_ref_count
63
-
64
- debug :join, "Creating Join Node #{var_ref.inspect} (counts #{refs_count}/#{objectification_ref_count}) and objectification Join Step for #{var_ref.inspect}" do
65
-
66
- raise "Internal error: Trying to add role of #{role.object_type.name} to join node for #{variable.join_node.object_type.name}" unless variable.join_node.object_type == role.object_type
67
- join_role = @constellation.JoinRole(variable.join_node, role)
68
-
69
- if (refs_count <= 1) # Our work here is done if there are no other refs
70
- if objectification_step
71
- join_role.join_step = objectification_step
72
- else
73
- incidental_roles << join_role
74
- end
75
- next
76
- end
77
-
78
- join_roles << join_role
79
- unless objectification_node
80
- # This is an implicit objectification, just the FT clause, not ET(where ...clause...)
81
- # We need to create a JoinNode for this object, even though it has no VarRefs
82
- join = variable.join_node.join
83
- debug :join, "Creating JN#{join.all_join_node.size} for #{clause.fact_type.entity_type.name} in objectification"
84
- objectification_node = @constellation.JoinNode(join, join.all_join_node.size, :object_type => clause.fact_type.entity_type)
85
- end
86
- raise "Internal error: Trying to add role of #{role.implicit_fact_type.all_role.single.object_type.name} to join node for #{objectification_node.object_type.name}" unless objectification_node.object_type == role.implicit_fact_type.all_role.single.object_type
87
-
88
- irole = role.implicit_fact_type.all_role.single
89
- raise "Internal error: Trying to add role of #{irole.object_type.name} to join node for #{objectification_node.object_type.name}" unless objectification_node.object_type == irole.object_type
90
- objectification_role = @constellation.JoinRole(objectification_node, role.implicit_fact_type.all_role.single)
91
- objectification_step = @constellation.JoinStep(objectification_role, join_role, :fact_type => role.implicit_fact_type)
92
- debug :join, "New #{objectification_step.describe}"
93
- debug :join, "Associating #{incidental_roles.map(&:describe)*', '} incidental roles with #{objectification_step.describe}" if incidental_roles.size > 0
94
- incidental_roles.each { |jr| jr.join_step = objectification_step }
95
- incidental_roles = []
96
- join_roles = []
97
- end
98
- else
99
- debug :join, "Creating VarRef for #{var_ref.inspect}" do
100
- # REVISIT: If there's an implicit subtyping join here, create it; then always raise the error here.
101
- # I don't want to do this for now because the verbaliser will always verbalise all join steps.
102
- if variable.join_node.object_type != role.object_type and
103
- 0 == (variable.join_node.object_type.supertypes_transitive & role.object_type.supertypes_transitive).size
104
- raise "Internal error: Trying to add role of #{role.object_type.name} to join node #{variable.join_node.ordinal} for #{variable.join_node.object_type.name} in '#{clause.fact_type.default_reading}'"
105
- end
106
- raise "Internal error: Trying to add role of #{role.object_type.name} to join node #{variable.join_node.ordinal} for #{variable.join_node.object_type.name}" unless variable.join_node.object_type == role.object_type
107
- begin
108
- join_role = @constellation.JoinRole(variable.join_node, role)
109
- rescue ArgumentError => e
110
- join_role = @constellation.JoinRole(variable.join_node, role)
111
- end
112
- join_roles << join_role
113
- end
114
- end
115
-
116
- if var_ref.nested_clauses
117
- # We are looking at a role whose player is an objectification of a fact type,
118
- # which will have ImplicitFactTypes for each role.
119
- # Each of these ImplicitFactTypes has a single phantom role played by the objectifying entity type
120
- # One of these phantom roles is likely to be the subject of an objectification join step.
121
- var_ref.nested_clauses.each do |r|
122
- debug :join, "Building objectification join for #{var_ref.nested_clauses.inspect}" do
123
- build_join_steps r, roles_by_variable, variable.join_node
124
- end
125
- end
126
- end
127
- roles_by_variable[variable] = [role, join_role]
128
- end
129
- end
130
-
131
- if join_roles.size > 0
132
- end_node = join_roles[-1].join_node
133
- if !clause.fact_type.entity_type and role = clause.fact_type.all_role.single
134
- # Don't give the ImplicitBoolean a join_node. We can live without one, for now.
135
- # The Join Step will have a duplicate node, and the fact type will tell us what's happening
136
- join_roles << join_roles[0]
137
- end
138
- # We aren't talking about objectification here, so there must be exactly two roles.
139
- raise "REVISIT: Internal error constructing join for #{clause.inspect}" if join_roles.size != 2
140
- js = @constellation.JoinStep(join_roles[0], join_roles[1], :fact_type => clause.fact_type)
141
- debug :join, "New Join Step #{js.describe}"
142
- debug :join, "Associating #{incidental_roles.map(&:describe)*', '} incidental roles with #{js.describe}" if incidental_roles.size > 0
143
- incidental_roles.each { |jr| jr.join_step = js }
144
- end
145
- roles_by_variable
146
- end
147
-
148
- # Return the unique array of all variables in these clauses, including in objectification joins
149
- def all_variables_in_clauses clauses
150
- clauses.map do |clause|
151
- clause.var_refs.map do |var_ref|
152
- raise "Variable reference #{var_ref.inspect} is not bound to a variable" unless var_ref.variable
153
- [var_ref.variable] + (var_ref.nested_clauses ? all_variables_in_clauses(var_ref.nested_clauses) : [])
154
- end
155
- end.
156
- flatten.
157
- uniq
158
- end
159
- end
160
- end
161
- end
162
- end