twb 1.9.1 → 2.2.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.
@@ -0,0 +1,208 @@
1
+ # DocumentedFieldsCSVEmitter.rb - this Ruby script Copyright 2017 Christopher Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'twb'
17
+ require 'csv'
18
+
19
+ module Twb
20
+ module Analysis
21
+
22
+ class DocumentedFieldsCSVEmitter
23
+
24
+ attr_reader :csvFileName, :csvRecords
25
+ attr_reader :dsCount, :fieldsCount
26
+
27
+ @@csvHeader = ['Record #',
28
+ 'Workbook',
29
+ 'Workbook Dir',
30
+ 'Data Source',
31
+ 'Field',
32
+ 'Doc Type',
33
+ 'Doc Line #'
34
+ 'Doc Line'
35
+ ]
36
+ @@csvFileType = 'TwbAnnotatedFields'
37
+ @@csvFileName = @@csvFileType + '.csv'
38
+
39
+ def initialize
40
+ @csvFile = CSV.open(@@csvFileName,'w')
41
+ @csvFile << @@csvHeader
42
+ @csvRecords = Set.new
43
+ puts "Opened: #{!@csvFile.nil?} - #{@@csvFileName}"
44
+ # --
45
+ @recNum = 0
46
+ @dsCount = 0
47
+ @fieldsCount = 0
48
+ end
49
+
50
+ def self.csvHeader
51
+ @@csvHeader
52
+ end
53
+
54
+ def self.csvFileType
55
+ @@csvFileType
56
+ end
57
+
58
+ def self.csvFileNaame
59
+ @@csvFileName
60
+ end
61
+
62
+ def processTwb twb
63
+ @twb = nil
64
+ @twb = twb if twb.instance_of? Twb::Workbook
65
+ @twb = Twb::Workbook.new(twb) if twb.instance_of? String
66
+ raise ArgumentError.new("ERROR in Workbok processing: '#{twb}' must be a Workbook (class) or the name of a Workbook (String), is a #{twb.class} \n ") unless @twb.is_a? Twb::Workbook
67
+ # --
68
+ dss = @twb.datasources
69
+ dss.each do |ds|
70
+ @dsname = ds.uiname
71
+ # puts "\n -- #{ds.uiname} "
72
+ # tables = Set.new
73
+ fields = {}
74
+ @dsCount += 1
75
+ fclasses = Set.new
76
+ ds.localFields.each do |field|
77
+ recordFieldFull field, :local
78
+ # recordField( fields, field, {:type=>:local,:columnField=>true,:hidden=>field.hidden} )
79
+ # emitTech( ds, field.uiname, 'Local', field.properties)
80
+ # recordTech( field, 'LocalA')
81
+ end
82
+ ds.columnFields.each do |field|
83
+ recordFieldFull field, :column
84
+ # recordField( fields, field, {:type=>'column',:columnField=>true,:hidden=>field.hidden} )
85
+ # emitTech( ds, field.uiname, 'Column', field.properties)
86
+ # recordTech( field, 'ColumnA')
87
+ end
88
+ ds.calculatedFields.each do |field|
89
+ recordFieldFull field, :calc
90
+ # puts "WWW #{field.class} :: #{field} ::prop:: #{field.properties.class} :: #{field.properties}"
91
+ # recordField( fields, field, {:type=>'calc',:calculatedField=>true,:hidden=>field.hidden} )
92
+ # emitTech( ds, field.uiname, 'Calculated', field.properties)
93
+ # recordTech( field, 'CalcA')
94
+ end
95
+ ds.metadataFields.each do |field|
96
+ recordFieldFull field, :metadata
97
+ # recordField( fields, field, {:type=>'metadata',:metadataField=>true} )
98
+ # emitTech( ds, field.uiname, 'MetaData', field.properties)
99
+ # recordTech( field, 'MetadataA')
100
+ end
101
+ ds.dbFields.each do |field|
102
+ recordFieldFull field, :db
103
+ # recordField( fields, field, {:type=>'database',:dbField=>true} )
104
+ # emitTech( ds, field.uiname, 'Db', field.properties)
105
+ # recordTech( field, 'DbA')
106
+ end
107
+ ds.mappedFields.each do |field|
108
+ recordFieldFull field, :mapped
109
+ # recordField( fields, field, {:type=>'mapped',:mappedField=>true} )
110
+ # emitTech( ds, field.uiname, 'Mapped', field.properties)
111
+ # recordTech( field, 'MappedA')
112
+ end
113
+ emitFields(fields)
114
+ end
115
+ end # def processTwb twb
116
+
117
+ def recordFieldFull field, source
118
+ # print field.properties.nil? ? '-' : ":#{field.properties.length}"
119
+ # puts field.properties
120
+ @recNum+=1
121
+ field.properties.each do |name,value|
122
+ # print name
123
+ @csvFileFull << [ @recNum,
124
+ @twb.name,
125
+ @twb.dir,
126
+ @dsname,
127
+ field.uiname,
128
+ source,
129
+ field.class,
130
+ field.node.path.to_s.gsub(/[0-9]/,'').gsub('[]',''),
131
+ name,
132
+ value
133
+ ]
134
+ # @csvFileFull << csvRec
135
+ end
136
+ end
137
+
138
+ def recordField fields, field, props
139
+ # puts "%-65s :: %s " % [fieldName,props]
140
+ return if field.uiname.nil?
141
+ if fields.has_key? field.uiname
142
+ fields[field.uiname].merge! field.properties
143
+ else
144
+ fields[field.uiname] = field.properties
145
+ end
146
+ end
147
+
148
+ def emitFields fields
149
+ fields.each do |fieldName,props|
150
+ # puts "FIELD:: %-40s :: %s" % [fieldName,props.inspect]
151
+ # class = props[]
152
+ csvRec = [ @recNum+=1,
153
+ @twb.name,
154
+ @twb.dir,
155
+ @dsname,
156
+ fieldName,
157
+ props[:type],
158
+ props['hidden'],
159
+ props[:columnField],
160
+ props[:calculatedField],
161
+ props[:dbField],
162
+ props[:mappedField],
163
+ props[:metadataField]
164
+ ]
165
+ @csvFile << csvRec
166
+ @csvRecords.add csvRec
167
+ end
168
+ end
169
+
170
+ def recordTech field, type
171
+ @recNum+=1
172
+ field.properties.each do |name,value|
173
+ @csvFileTech << [ @recNum,
174
+ @twb.name,
175
+ @twb.dir,
176
+ @dsname,
177
+ field.uiname,
178
+ type,
179
+ name,
180
+ value
181
+ ]
182
+ end
183
+ end
184
+
185
+ def emitTech dataSource, fieldName, type, properties
186
+ # puts "XX #{dataSource.uiname} :: #{fieldName} #{} :: #{type} :: #{properties}"
187
+ @recNum+=1
188
+ properties.each do |name,value|
189
+ @csvFileTech << [ @recNum,
190
+ @twb.name,
191
+ @twb.dir,
192
+ dataSource.uiname,
193
+ fieldName,
194
+ type,
195
+ name,
196
+ value
197
+ ]
198
+ end
199
+ end
200
+
201
+ def cleanup
202
+ @csvFile.close unless @csvFile.nil?
203
+ end
204
+
205
+ end # class DocumentedFieldsCSVEmitter
206
+
207
+ end # module Analysis
208
+ end # module Twb
@@ -0,0 +1,77 @@
1
+ # calculatedfieldsanalyzer.rb - this Ruby script Copyright 2017 Christopher Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'twb'
17
+
18
+ module Twb
19
+ module Analysis
20
+
21
+ class DocumentedFieldsMarkdownEmitter
22
+
23
+ attr_reader :docFileName
24
+
25
+ def initialize
26
+ # puts ""
27
+ end
28
+
29
+ def processTwb twbName
30
+ @twb = Twb::Workbook.new twbName
31
+ @docFileName = @twb.name + '.DocumentedFields.md'
32
+ @docFile = File.open(@docFileName,'w')
33
+ @docFile.puts "## #{@twb.name}"
34
+ dss = @twb.datasources
35
+ @docFile.puts "#{dss.length} Data Source#{(dss.length>1) ? 's' : ''}"
36
+ @docFile.puts " "
37
+ dss.each do |ds|
38
+ @docFile.puts "- #{ds.uiname}"
39
+ end
40
+ @docFile.puts " "
41
+ dss.each do |ds|
42
+ @docFile.puts "### #{ds.uiname}"
43
+ columnFields = ds.columnFields #.sort_by { |fldName,calc| fldName }
44
+ columnFields.each do |field|
45
+ commentLines = field.comment
46
+ calculation = field.calcField
47
+ # puts "\n#{field.uiname}"
48
+ # puts "Comment? #{commentLines}"
49
+ # puts "Calc ? #{calculation}"
50
+ @docFile.puts "\n##### #{field.uiname} "
51
+ unless commentLines.nil?
52
+ commentLines.each do |line|
53
+ @docFile.puts "###### #{line}"
54
+ end
55
+ end
56
+ unless calculation.nil?
57
+ @docFile.puts "```"
58
+ @docFile.puts calculation.formulaResolved
59
+ @docFile.puts "\n -- Fields --" unless calculation.calcFields.empty?
60
+ refFields = SortedSet.new
61
+ calculation.calcFields.each do |cf|
62
+ fds = if cf.dataSourceRef == :remote then "<<#{cf.dataSource}>>" else '' end
63
+ refFields.add "#{cf.uiName} \t #{fds}"
64
+ end
65
+ refFields.each do |rf|
66
+ @docFile.puts " #{rf}"
67
+ end
68
+ @docFile.puts "```"
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ end # class MarkdownEmitter
75
+
76
+ end # module Analysis
77
+ end # module Twb
@@ -19,14 +19,16 @@ module Twb
19
19
 
20
20
  class CalculatedField
21
21
 
22
- attr_reader :node, :dataSource
22
+ attr_reader :dataSource
23
+ attr_reader :node, :properties
23
24
  attr_reader :caption, :name, :uiname
24
25
  attr_reader :datatype, :role, :type
25
- attr_reader :calculation
26
+ attr_reader :calculation, :calcFields
27
+ attr_reader :hidden
26
28
 
27
29
  def initialize(calcNode, datasource=nil)
28
- @dataSource = datasource
29
30
  @node = calcNode
31
+ @dataSource = datasource
30
32
  # --
31
33
  @caption = calcNode.attribute('caption').text if calcNode.has_attribute?('caption')
32
34
  @name = calcNode.attribute('name').text.gsub(/^\[/,'').gsub(/\]$/,'')
@@ -37,6 +39,37 @@ module Twb
37
39
  @type = @node.attribute('type').text
38
40
  # --
39
41
  @calculation = Twb::FieldCalculation.new(self, datasource)
42
+ # --
43
+ @hidden = true if calcNode.has_attribute?('caption')
44
+ end
45
+
46
+ def properties
47
+ @properties ||= loadProperties
48
+ end
49
+
50
+ def calcLines
51
+ @calculation.calcFields
52
+ end
53
+
54
+ def formulaLines
55
+ @calculation.formulaLines
56
+ end
57
+
58
+ def formulaResolvedLines
59
+ @calculation.formulaResolvedLines
60
+ end
61
+
62
+ def formulaResolved
63
+ @calculation.formulaResolved
64
+ end
65
+
66
+ def loadProperties
67
+ @properties= {}
68
+ @node.attributes.each do |name,attr|
69
+ @properties[name] = attr.value
70
+ end
71
+ @properties[:uiname] = @uiname
72
+ return @properties
40
73
  end
41
74
 
42
75
  def to_s
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014, 2015 Chris Gerrard
1
+ # Copyright (C) 2014, 2018 Chris Gerrard
2
2
  #
3
3
  # This program is free software: you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -47,15 +47,18 @@ module Twb
47
47
  # value
48
48
  # visual-totals
49
49
 
50
- attr_reader :node
50
+ attr_reader :node, :properties
51
51
  attr_reader :name, :caption, :uiname
52
52
  attr_reader :dataType, :defaultFormat, :paramDomainType
53
53
  attr_reader :role, :type, :value
54
54
  attr_reader :alias, :semanticRole, :aggregation
55
55
  attr_reader :autoColumn, :hidden, :datatypeCustomized
56
+ attr_reader :calcField
56
57
 
57
58
 
58
- def initialize fieldNode
59
+ def initialize(fieldNode, datasource=nil)
60
+
61
+ @datasource = datasource
59
62
  @node = fieldNode
60
63
  @name = load 'name'
61
64
  @caption = load 'caption'
@@ -73,6 +76,7 @@ module Twb
73
76
  @autoColumn = load 'auto-column'
74
77
  @hidden = load 'hidden'
75
78
  @datatypeCustomized = load 'datatype-customized'
79
+ @calcField = loadCalcField
76
80
  end
77
81
 
78
82
  def load nodeName
@@ -81,6 +85,69 @@ module Twb
81
85
  return val
82
86
  end
83
87
 
88
+ def calcField
89
+ @calcField ||= loadCalcField
90
+ end
91
+
92
+ def loadCalcField
93
+ if !@node.at_xpath('./calculation').nil?
94
+ @calcField = Twb::CalculatedField.new @node, @datasource
95
+ else
96
+ @calcField = nil
97
+ end
98
+ end
99
+
100
+ def comment
101
+ @commentLines ||= loadComment
102
+ end
103
+
104
+ # COMMENTED FIELDS
105
+ # --------------------------------------
106
+ # <column caption='Calculation1' datatype='real' name='[Calculation_821344020759588865]' role='measure' type='quantitative'>
107
+ # <calculation class='tableau' formula='[Formula Length] * 1.1' />
108
+ # <desc>
109
+ # <formatted-text>
110
+ # <run>THIS IS A COMMENT</run>
111
+ # </formatted-text>
112
+ # </desc>
113
+ # </column>
114
+ # <column datatype='string' name='[Data Source Name (tech) (CalculatedFieldsReferencedFields.csv)]' role='dimension' type='nominal'>
115
+ # <desc>
116
+ # <formatted-text>
117
+ # <run>THIS IS A COMMENT</run>
118
+ # </formatted-text>
119
+ # </desc>
120
+ # </column>
121
+ def loadComment
122
+ @commentLines = []
123
+ runs = @node.xpath('./desc/formatted-text/run')
124
+ runs.each do |run|
125
+ lines = run.text.split(/\n/)
126
+ lines.each do |line|
127
+ @commentLines << line
128
+ end
129
+ end
130
+ return @commentLines
131
+ end
132
+
133
+ def hasComment?
134
+ loadComment if @commentLines.nil?
135
+ @commentLines.empty?
136
+ end
137
+
138
+ def properties
139
+ @properties ||= loadProperties
140
+ end
141
+
142
+ def loadProperties
143
+ @properties= {}
144
+ @node.attributes.each do |name,attr|
145
+ @properties[name] = attr.value
146
+ end
147
+ @properties[:uiname] = @name
148
+ return @properties
149
+ end
150
+
84
151
  def to_s
85
152
  @name
86
153
  end
@@ -48,6 +48,7 @@ module Twb
48
48
  attr_reader :metadataFields
49
49
  attr_reader :dbFields
50
50
  attr_reader :mappedFields
51
+ attr_reader :tableFieldsMap
51
52
  attr_reader :fieldUINames
52
53
  attr_reader :calculatedFields, :calculatedFieldNamesMap, :calculatedFieldNames, :calculatedField
53
54
  attr_reader :allFields
@@ -59,7 +60,7 @@ module Twb
59
60
  @workbook = workbook
60
61
  @name = @node.attr('name')
61
62
  @caption = @node.attr('caption')
62
- @uiname = if @caption.nil? || @caption == '' then @name else @caption end
63
+ @uiname = @caption.nil? ? @name : @caption
63
64
  processConnection
64
65
  processFilters
65
66
  loadTableFields
@@ -150,7 +151,6 @@ module Twb
150
151
  table = code.split('].[')[0][1..-1]
151
152
  end
152
153
 
153
-
154
154
  def Parameters?
155
155
  'Parameters'.eql? @name
156
156
  end
@@ -159,22 +159,30 @@ module Twb
159
159
  @columnFields ||= loadColumnFields
160
160
  end
161
161
 
162
+ def columnFieldsMap
163
+ loadColumnFields if @columnFieldsMap.nil?
164
+ return @columnFieldsMap
165
+ end
166
+
162
167
  def loadColumnFields
163
- @columnFields = Set.new
168
+ @columnFields = Set.new
169
+ @columnFieldsMap = {}
164
170
  nodes = @node.xpath('./column')
165
171
  nodes.each do |n|
166
- field = Twb::ColumnField.new n
172
+ field = Twb::ColumnField.new n, self
167
173
  @columnFields << field
174
+ @columnFieldsMap[field.uiname] = field
168
175
  end
169
176
  return @columnFields
170
177
  end
171
178
 
179
+
172
180
  def localFields
173
181
  @localFields ||= loadLocalFields
174
182
  end
175
183
 
176
184
  def loadLocalFields
177
- @localFields = {}
185
+ @localFields = Set.new
178
186
  unless @connection.nil? # Parameters has no connection node, & no local fields
179
187
  connClass = @node.at_xpath('./connection').attribute('class').text
180
188
  fxpath = case connClass
@@ -185,7 +193,7 @@ module Twb
185
193
  nodes = @node.xpath(fxpath)
186
194
  nodes.each do |node|
187
195
  field = Twb::LocalField.new(node)
188
- @localFields[field.name] = field
196
+ @localFields << field
189
197
  end
190
198
  end
191
199
  return @localFields
@@ -201,7 +209,7 @@ module Twb
201
209
  # nodes = @node.xpath(".//metadata-record[@class='column']")
202
210
  # # note: there are other nodes "<metadata-record class='capability'>" whose nature is unclear
203
211
  # # these nodes have no value for their <name node, so are not loaded
204
- nodes = @node.xpath('./connection//metadata-record')
212
+ nodes = @node.xpath("./connection//metadata-record[@class='column']")
205
213
  nodes.each do |node|
206
214
  field = Twb::MetadataField.new(node)
207
215
  field.source = :db
@@ -234,34 +242,44 @@ module Twb
234
242
 
235
243
  def loadFieldUINames
236
244
  @fieldUINames = {}
237
- columnNodes = @node.xpath('./column')
238
- columnNodes.each do |cn|
239
- name = cn.attribute('name').text.gsub(/^\[|\]$/,'')
240
- caption = cn.attribute('caption')
241
- uiName = caption.nil? ? name : caption.text
242
- @fieldUINames[name] = uiName
243
- @fieldUINames[caption.text] = caption.text unless caption.nil? # in case of unintended usage: lookup by Caption name
245
+ metadataFields.each do |fld|
246
+ unless fld.localName.nil?
247
+ @fieldUINames[fld.localName] = fld.uiname
248
+ @fieldUINames[fld.uiname] = fld.uiname
249
+ end
250
+ end
251
+ calculatedFields.each do |fld|
252
+ @fieldUINames[fld.name] = fld.uiname
253
+ @fieldUINames[fld.uiname] = fld.uiname
244
254
  end
245
- mappedFields.each do |fname,fmap|
246
- dbTable = fmap['table']
247
- dbName = fmap['dbName']
248
- @fieldUINames[dbName] = fname unless @fieldUINames.include?(dbName)
249
- @fieldUINames[fname] = fname unless @fieldUINames.include?(fname)
255
+ localFields.each do |fld|
256
+ @fieldUINames[fld.name] = fld.uiname
257
+ @fieldUINames[fld.uiname] = fld.uiname
250
258
  end
251
259
  end
252
260
 
261
+ def tableFields
262
+ @tableFieldsMap.values
263
+ end
264
+
265
+ def dbFieldsMap
266
+ @tableFieldsMap
267
+ end
268
+
253
269
  def dbFields
254
- return @mappedFields unless @mappedFields.nil?
255
- loadTableFields
256
- return @mappedFields
270
+ @tableFieldsMap.values
271
+ end
272
+
273
+ def mappedFieldsMap
274
+ loadTableFields if @tableFieldsMap.nil?
275
+ return @tableFieldsMap
257
276
  end
258
277
 
259
278
  def mappedFields
260
- loadTableFields if @mappedFields.nil?
261
- return @mappedFields
279
+ loadTableFields if @tableFieldsMap.nil?
280
+ return @tableFieldsMap.values
262
281
  end
263
282
 
264
- # NOTE: Calculated Fields are mapped by their UI name
265
283
  def calculatedFieldsMap
266
284
  @calculatedFieldsMap ||= loadCalculatedFields
267
285
  end
@@ -296,48 +314,40 @@ module Twb
296
314
  @allFields = SortedSet.new
297
315
  dbf = dbFields
298
316
  @allFields << dbf.keys
317
+ @allFields << calculatedFieldNames
299
318
  end
300
319
 
301
320
  def has_field? fieldName
302
- dbFields.has_key? fieldName
321
+ dbFieldsMap.has_key? fieldName
303
322
  end
304
323
 
305
324
  def fieldTable fieldName
306
- loadTableFields if @mappedFields.nil?
307
- tf = @mappedFields[fieldName]
308
- return tf.nil? ? nil : tf['table']
325
+ loadTableFields if @tableFieldsMap.nil?
326
+ dbField = @tableFieldsMap[fieldName]
327
+ return dbField.nil? ? nil : dbField.dbtable
309
328
  end
310
329
 
311
330
  # fields are unique in the data source by UI name
312
331
  def loadTableFields
313
332
  # puts "DATA SOURCE FIELD TABLE LOAD"
314
- @mappedFields = {}
333
+ @tableFieldsMap = {}
315
334
  fieldNodes = @node.xpath('./connection/cols/map')
316
335
  fieldNodes.each do |fn|
317
- uiName = fn.attribute('key').text.gsub(/^\[|\]$/,'')
318
- fldRef = fn.attribute('value').text.gsub(/^\[|\]$/,'')
319
- parts = fldRef.split('].[')
320
- table = parts[0]
321
- dbName = parts[1]
322
- @mappedFields[uiName] = {'table' => table, 'dbName' => dbName}
323
- # puts "=== #{uiName} :: T=#{@mappedFields[uiName]['table']} DBN=#{@mappedFields[uiName]['dbName']} "
336
+ dbField = Twb::DbField.new(@uiname, fn, :map)
337
+ @tableFieldsMap[dbField.uiname] = dbField
324
338
  end
325
339
  relTableNodes = @node.xpath('.//relation[@table]')
326
340
  relTableNodes.each do |relNode|
327
341
  table = relNode.attribute('name').text
328
- cols = relNode.xpath('./columns/column')
342
+ cols = relNode.xpath('./columns/column')
329
343
  cols.each do |col|
344
+ dbField = Twb::DbField.new(@uiname, col, :tableColumn, table)
330
345
  fldName = col.attribute('name')
331
- @mappedFields[fldName.text] = {'table' => table, 'dbName' => @uiname} unless fldName.nil?
346
+ @tableFieldsMap[dbField.uiname] = dbField
332
347
  end
333
348
  end
334
349
  end
335
350
 
336
- # =begin
337
- # <filter class='categorical' column='[enforcement_type]' filter-group='2'>
338
- # <groupfilter function='member' level='[enforcement_type]' member='&quot;towing&quot;' user:ui-domain='database' user:ui-enumeration='inclusive' user:ui-marker='enumerate' />
339
- # </filter>
340
- # end
341
351
  def processFilters
342
352
  if @filters.nil?
343
353
  @filters = {}
@@ -360,70 +370,6 @@ module Twb
360
370
 
361
371
  end # class DataSource
362
372
 
363
- # DataSource Utilities
364
-
365
- # # Generates and returns a set of graph node-edge-node triplets.
366
- # # The intention is to create a graph that can be standalone used as a subgraph by the function's caller.
367
- # # The initial implementation only considers a linear list of node names as input, resulting in
368
- # # the creation of a single-path structure, e.g.
369
- # # [inNode] -> node1 -> node2 -> ... -> nodeN
370
- # # this may manifest as a tree when there are siblings at any level, e.g.
371
- # # [inNode] -> node1 -> node11 -> ... -> nodeX
372
- # # -> node22 -> ... -> nodeY
373
- # # -> node2 -> node21 -> ... -> nodeZ
374
- # # Params:
375
- # # +inNodes+:: the node(s) to which this function's generated graph is to be linked, may be nil:
376
- # # + , or multiple)
377
- # # +nodesList+:: list of node types by name to be built and linked together, in the order named
378
- # def graphNodes nodesList
379
- # graph = Twb::Util::Graphedges.new()
380
- # nodesList.each do |nName|
381
- # end
382
- # case @dsclass
383
- # when 'federated'
384
- # graph = processFederatedSource nodesList
385
- # end
386
- # return graph
387
- # end
388
-
389
- # def processFederatedSource nodesList
390
- # emit false, " (federated) #{dataSource.uiname}"
391
- # dsGNode = Twb::Util::Graphnode.new(name: @uiname, id: @name, type: 'Data Connection')
392
- # graph = Twb::Util::Graphedges.new(dsGNode)
393
- # edges = []
394
- # dsNode = dataSource.node
395
- # connections = dsNode.xpath('./connection/named-connections/named-connection/connection')
396
- # connections.each do |conn|
397
- # connClass = conn.attribute('class').text
398
- # emit true, "CONN CLASS: #{connClass}"
399
- # # -- Generating Source Node
400
- # cgParams = @@cgNodeParams[connClass]
401
- # # emit true, "cgparams : #{cgParams}"
402
- # cLabel = buildConnGraphPart( conn, cgParams['label'])
403
- # cID = buildConnGraphPart( conn, cgParams['id'])
404
- # cType = cgParams['type']
405
- # # emit true, " label : #{cLabel}"
406
- # # emit true, " id : #{cID}"
407
- # # emit true, " type : #{cType}"
408
- # srcNode = Twb::Util::Graphnode.new(name: cLabel, id: cID, type: 'Data Source')
409
- # graphEdge = Twb::Util::Graphedge.new(from: dsGNode, to: srcNode, relationship: 'is located at')
410
- # graph.edges << graphEdge
411
- # end
412
- # return graph
413
- # end
414
-
415
- # def buildConnGraphPart connNode, attributes
416
- # return connNode.attribute(attributes) if attributes.is_a? String
417
- # emit false, "ATTRIBUTES :: #{attributes}"
418
- # str = ''
419
- # attributes.each do |attName|
420
- # attrib = connNode.attribute(attName)
421
- # emit false, " -#{attName}\t-> #{attrib}"
422
- # str += attrib.text unless attrib.nil?
423
- # end
424
- # return str
425
- # end
426
-
427
373
 
428
374
  class JoinTablePair
429
375
  attr_reader :from, :to