twb 1.0.5 → 1.9.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/twb.rb +10 -6
- data/lib/twb/analysis/CalculatedFields/CSVEmitter.rb +154 -0
- data/lib/twb/analysis/CalculatedFields/CalculatedFieldsAnalyzer.rb +527 -0
- data/lib/twb/analysis/CalculatedFields/MarkdownEmitter.rb +71 -0
- data/lib/twb/analysis/DataSources/DataSourceTableFieldsCSVEmitter.rb +117 -0
- data/lib/twb/analysis/Sheets/WorksheetDataStructureCSVEmitter.rb +192 -0
- data/lib/twb/calculatedfield.rb +47 -0
- data/lib/twb/columnfield.rb +94 -0
- data/lib/twb/dashboard.rb +1 -1
- data/lib/twb/datasource.rb +368 -121
- data/lib/twb/fieldcalculation.rb +157 -81
- data/lib/twb/localfield.rb +32 -29
- data/lib/twb/metadatafield.rb +57 -15
- data/lib/twb/util/ftpPublisher.rb +48 -0
- data/lib/twb/util/joinUtilities.rb +52 -0
- data/lib/twb/workbook.rb +27 -10
- data/lib/twb/worksheet.rb +146 -53
- metadata +11 -5
- data/lib/twb/analysis/calculatedfieldsanalyzer.rb +0 -508
- data/lib/twb/apps/X-Ray Dashboards.rb +0 -80
- data/lib/twb/countNodes.rb +0 -98
data/lib/twb/dashboard.rb
CHANGED
@@ -65,7 +65,7 @@ module Twb
|
|
65
65
|
@minheight = size.attr('minheight')
|
66
66
|
@minwidth = size.attr('minwidth')
|
67
67
|
@rangesize = size.attr('rangesize')
|
68
|
-
@dimensions = @minwidth.to_s
|
68
|
+
@dimensions = "%s:%s:%s:%s" % [@minwidth.to_s, @minheight.to_s, @maxwidth.to_s, @maxheight.to_s]
|
69
69
|
end
|
70
70
|
|
71
71
|
end
|
data/lib/twb/datasource.rb
CHANGED
@@ -20,36 +20,47 @@ require 'json'
|
|
20
20
|
module Twb
|
21
21
|
|
22
22
|
class DataSource
|
23
|
-
|
23
|
+
|
24
24
|
@@hasher = Digest::SHA256.new
|
25
25
|
|
26
26
|
@@connGNodeParamsJSON = %q(
|
27
|
-
{ "csv" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "
|
28
|
-
"excel" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "
|
29
|
-
"dataengine" : { "label" : ["dbname" ], "id" : ["directory","filename"], "type" : "
|
30
|
-
"msaccess" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "
|
31
|
-
"
|
32
|
-
"
|
33
|
-
"
|
27
|
+
{ "csv" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "CSV" },
|
28
|
+
"excel" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "Excel" },
|
29
|
+
"dataengine" : { "label" : ["dbname" ], "id" : ["directory","filename"], "type" : "TDE" },
|
30
|
+
"msaccess" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "MS Access" },
|
31
|
+
"oracle" : { "label" : ["server" ], "id" : [ "server" ], "type" : "Oracle" },
|
32
|
+
"postgres" : { "label" : ["server" ], "id" : [ "server" ], "type" : "PostgreSQL" },
|
33
|
+
"textscan" : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "CSV / TSV" },
|
34
|
+
"excel-direct" : { "label" : ["filename"], "id" : [ "filename"], "type" : "Excel" },
|
35
|
+
"salesforce" : { "label" : ["server" ], "id" : [ "server" ], "type" : "Salesforce" }
|
34
36
|
}
|
35
37
|
)
|
36
38
|
@@cgNodeParams = JSON.parse @@connGNodeParamsJSON
|
37
39
|
|
38
40
|
|
39
|
-
attr_reader :
|
40
|
-
attr_reader :
|
41
|
-
attr_reader :
|
42
|
-
attr_reader :
|
41
|
+
attr_reader :workbook
|
42
|
+
attr_reader :name, :caption, :uiname
|
43
|
+
attr_reader :dsclass, :isExtract
|
44
|
+
attr_reader :connection, :connHash
|
45
|
+
attr_reader :tables, :joinPairs
|
46
|
+
attr_reader :localFields, :localFieldNames, :localField, :hasField
|
47
|
+
attr_reader :columnFields
|
48
|
+
attr_reader :metadataFields
|
49
|
+
attr_reader :dbFields
|
50
|
+
attr_reader :mappedFields
|
51
|
+
attr_reader :fieldUINames
|
52
|
+
attr_reader :calculatedFields, :calculatedFieldNamesMap, :calculatedFieldNames, :calculatedField
|
53
|
+
attr_reader :allFields
|
43
54
|
attr_reader :filters
|
44
55
|
attr_reader :node
|
45
56
|
|
46
|
-
def initialize dataSourceNode
|
47
|
-
@node
|
48
|
-
@
|
49
|
-
@
|
50
|
-
@
|
57
|
+
def initialize dataSourceNode, workbook
|
58
|
+
@node = dataSourceNode
|
59
|
+
@workbook = workbook
|
60
|
+
@name = @node.attr('name')
|
61
|
+
@caption = @node.attr('caption')
|
62
|
+
@uiname = if @caption.nil? || @caption == '' then @name else @caption end
|
51
63
|
processConnection
|
52
|
-
processFields
|
53
64
|
processFilters
|
54
65
|
loadTableFields
|
55
66
|
return self
|
@@ -88,6 +99,10 @@ module Twb
|
|
88
99
|
@connHash = Digest::MD5.hexdigest(dsConnStr)
|
89
100
|
end
|
90
101
|
|
102
|
+
def isExtract
|
103
|
+
@isExtract ||= @isExtract = !@node.at_xpath('./extract').nil?
|
104
|
+
end
|
105
|
+
|
91
106
|
def loadTables connection
|
92
107
|
@tables = {}
|
93
108
|
nodes = connection.xpath(".//relation[@type='table']")
|
@@ -96,43 +111,115 @@ module Twb
|
|
96
111
|
end
|
97
112
|
end
|
98
113
|
|
114
|
+
def joinPairs
|
115
|
+
@joinPairs ||= loadJoinPairs
|
116
|
+
end
|
117
|
+
|
118
|
+
def loadJoinPairs
|
119
|
+
@joinPairs = Set.new
|
120
|
+
mainJoin = @node.xpath("./connection/relation[@type='join']")
|
121
|
+
clauses = @node.xpath(".//relation[@type='join']/clause")
|
122
|
+
clauses.each do |clause|
|
123
|
+
leafs = clause.xpath('.//expression[not(node())]')
|
124
|
+
@joinPairs << [ pullTable(leafs[0]) , pullTable(leafs[1]) ]
|
125
|
+
end
|
126
|
+
return @joinPairs
|
127
|
+
end
|
128
|
+
|
129
|
+
def joinTree
|
130
|
+
@joinTree ||= loadJoinTree
|
131
|
+
end
|
132
|
+
|
133
|
+
def loadJoinTree
|
134
|
+
loadJoinPairs if @joinPairs.nil?
|
135
|
+
# puts "LJT::#{@uiname}::joinPairs:: #{@joinPairs.inspect}"
|
136
|
+
# @joinPairs.each { |jp| puts "JP::#{jp}" }
|
137
|
+
@joinTree = JoinTree.new(@name)
|
138
|
+
@joinPairs.each do |from,to|
|
139
|
+
# puts "from:#{from} -> to:#{to}"
|
140
|
+
tableFrom = JoinTable.new(from)
|
141
|
+
tableTo = JoinTable.new(to)
|
142
|
+
@joinTree.add(tableFrom, tableTo)
|
143
|
+
end
|
144
|
+
# puts '---'
|
145
|
+
return @joinTree
|
146
|
+
end
|
147
|
+
|
148
|
+
def pullTable xml
|
149
|
+
code =xml.attribute('op').text
|
150
|
+
table = code.split('].[')[0][1..-1]
|
151
|
+
end
|
152
|
+
|
153
|
+
|
99
154
|
def Parameters?
|
100
155
|
'Parameters'.eql? @name
|
101
156
|
end
|
102
157
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
when 'sqlserver' then './column'
|
114
|
-
else './connection/relation/columns/column'
|
115
|
-
end
|
116
|
-
nodes = @node.xpath(fxpath)
|
117
|
-
# puts "DATASOURCE ::=>> @node: connClass: '#{connClass.class}' ::: #{connClass.eql?('dataengine')} fxpath: #{fxpath} :: #{nodes.length}"
|
118
|
-
nodes.each do |node|
|
119
|
-
field = Twb::LocalField.new(node)
|
120
|
-
@localfields[field.dbname] = field
|
158
|
+
def columnFields
|
159
|
+
@columnFields ||= loadColumnFields
|
160
|
+
end
|
161
|
+
|
162
|
+
def loadColumnFields
|
163
|
+
@columnFields = Set.new
|
164
|
+
nodes = @node.xpath('./column')
|
165
|
+
nodes.each do |n|
|
166
|
+
field = Twb::ColumnField.new n
|
167
|
+
@columnFields << field
|
121
168
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
169
|
+
return @columnFields
|
170
|
+
end
|
171
|
+
|
172
|
+
def localFields
|
173
|
+
@localFields ||= loadLocalFields
|
174
|
+
end
|
175
|
+
|
176
|
+
def loadLocalFields
|
177
|
+
@localFields = {}
|
178
|
+
unless @connection.nil? # Parameters has no connection node, & no local fields
|
179
|
+
connClass = @node.at_xpath('./connection').attribute('class').text
|
180
|
+
fxpath = case connClass
|
181
|
+
when 'dataengine' then './column'
|
182
|
+
when 'sqlserver' then './column'
|
183
|
+
else './connection/relation/columns/column'
|
184
|
+
end
|
185
|
+
nodes = @node.xpath(fxpath)
|
186
|
+
nodes.each do |node|
|
187
|
+
field = Twb::LocalField.new(node)
|
188
|
+
@localFields[field.name] = field
|
189
|
+
end
|
129
190
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
191
|
+
return @localFields
|
192
|
+
end
|
193
|
+
|
194
|
+
def metadataFields
|
195
|
+
@metadataFields ||= loadMetadataFields
|
196
|
+
end
|
197
|
+
|
198
|
+
def loadMetadataFields
|
199
|
+
@metadataFields = Set.new
|
200
|
+
unless @connection.nil? # Parameters has no connection node, & no metadata fields
|
201
|
+
# nodes = @node.xpath(".//metadata-record[@class='column']")
|
202
|
+
# # note: there are other nodes "<metadata-record class='capability'>" whose nature is unclear
|
203
|
+
# # these nodes have no value for their <name node, so are not loaded
|
204
|
+
nodes = @node.xpath('./connection//metadata-record')
|
205
|
+
nodes.each do |node|
|
206
|
+
field = Twb::MetadataField.new(node)
|
207
|
+
field.source = :db
|
208
|
+
@metadataFields << field
|
209
|
+
end
|
210
|
+
nodes = @node.xpath('./extract//metadata-record')
|
211
|
+
nodes.each do |node|
|
212
|
+
field = Twb::MetadataField.new(node)
|
213
|
+
field.source = :extract
|
214
|
+
@metadataFields << field
|
215
|
+
end
|
216
|
+
end
|
217
|
+
return @metadataFields
|
218
|
+
end
|
219
|
+
|
220
|
+
def updateTime
|
221
|
+
attr = @node.xpath('.//@update-time').first
|
222
|
+
@updateTime = attr.nil? ? nil : attr.value
|
136
223
|
end
|
137
224
|
|
138
225
|
def fieldUIName fieldName
|
@@ -163,12 +250,58 @@ module Twb
|
|
163
250
|
end
|
164
251
|
end
|
165
252
|
|
166
|
-
def
|
253
|
+
def dbFields
|
167
254
|
return @mappedFields unless @mappedFields.nil?
|
168
255
|
loadTableFields
|
169
256
|
return @mappedFields
|
170
257
|
end
|
171
258
|
|
259
|
+
def mappedFields
|
260
|
+
loadTableFields if @mappedFields.nil?
|
261
|
+
return @mappedFields
|
262
|
+
end
|
263
|
+
|
264
|
+
# NOTE: Calculated Fields are mapped by their UI name
|
265
|
+
def calculatedFieldsMap
|
266
|
+
@calculatedFieldsMap ||= loadCalculatedFields
|
267
|
+
end
|
268
|
+
|
269
|
+
def calculatedFields
|
270
|
+
loadCalculatedFields if @calculatedFieldsMap.nil?
|
271
|
+
return @calculatedFieldsMap.values
|
272
|
+
end
|
273
|
+
|
274
|
+
def calculatedFieldNames
|
275
|
+
loadCalculatedFields if @calculatedFieldsMap.nil?
|
276
|
+
return @calculatedFieldsMap.keys
|
277
|
+
end
|
278
|
+
|
279
|
+
def calculatedField(name)
|
280
|
+
loadCalculatedFields if @calculatedFieldsMap.nil?
|
281
|
+
return @calculatedFieldsMap[name]
|
282
|
+
end
|
283
|
+
|
284
|
+
def loadCalculatedFields
|
285
|
+
@calculatedFieldsMap = {}
|
286
|
+
cfnodes = @node.xpath("./column[calculation]")
|
287
|
+
cfnodes.each do |node|
|
288
|
+
calcField = Twb::CalculatedField.new node, self
|
289
|
+
@calculatedFieldsMap[calcField.uiname] = calcField
|
290
|
+
end
|
291
|
+
return @calculatedFieldsMap
|
292
|
+
end
|
293
|
+
|
294
|
+
def allFields
|
295
|
+
return @allFields unless @allFields.nil?
|
296
|
+
@allFields = SortedSet.new
|
297
|
+
dbf = dbFields
|
298
|
+
@allFields << dbf.keys
|
299
|
+
end
|
300
|
+
|
301
|
+
def has_field? fieldName
|
302
|
+
dbFields.has_key? fieldName
|
303
|
+
end
|
304
|
+
|
172
305
|
def fieldTable fieldName
|
173
306
|
loadTableFields if @mappedFields.nil?
|
174
307
|
tf = @mappedFields[fieldName]
|
@@ -200,11 +333,11 @@ module Twb
|
|
200
333
|
end
|
201
334
|
end
|
202
335
|
|
203
|
-
=begin
|
204
|
-
<filter class='categorical' column='[enforcement_type]' filter-group='2'>
|
205
|
-
<groupfilter function='member' level='[enforcement_type]' member='"towing"' user:ui-domain='database' user:ui-enumeration='inclusive' user:ui-marker='enumerate' />
|
206
|
-
</filter>
|
207
|
-
|
336
|
+
# =begin
|
337
|
+
# <filter class='categorical' column='[enforcement_type]' filter-group='2'>
|
338
|
+
# <groupfilter function='member' level='[enforcement_type]' member='"towing"' user:ui-domain='database' user:ui-enumeration='inclusive' user:ui-marker='enumerate' />
|
339
|
+
# </filter>
|
340
|
+
# end
|
208
341
|
def processFilters
|
209
342
|
if @filters.nil?
|
210
343
|
@filters = {}
|
@@ -224,69 +357,183 @@ module Twb
|
|
224
357
|
end
|
225
358
|
end
|
226
359
|
end
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
#
|
231
|
-
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
360
|
+
|
361
|
+
end # class DataSource
|
362
|
+
|
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
|
+
|
428
|
+
class JoinTablePair
|
429
|
+
attr_reader :from, :to
|
430
|
+
def initialize(from, to)
|
431
|
+
raise ParamaterException.new("'From' cannot be nil.") if from.nil?
|
432
|
+
raise ParamaterException.new("'To' cannot be nil.") if to.nil?
|
433
|
+
@from = from
|
434
|
+
@to = to
|
435
|
+
end
|
436
|
+
def to_s
|
437
|
+
"#{@from} -> #{@to}"
|
438
|
+
end
|
439
|
+
end # class JoinTablePair
|
440
|
+
|
441
|
+
|
442
|
+
class JoinTable
|
443
|
+
include Comparable
|
444
|
+
|
445
|
+
attr_reader :name, :datasource #, :str
|
446
|
+
attr_accessor :children, :depth
|
447
|
+
|
448
|
+
def initialize(name, datasource=nil)
|
449
|
+
@name = name
|
450
|
+
@datasource = datasource
|
451
|
+
# @str = nil
|
452
|
+
@children = {}
|
453
|
+
@depth = 0
|
454
|
+
end
|
455
|
+
|
456
|
+
def to_s
|
457
|
+
str = "[#{@datasource}].[#{@name}] :: (#{@depth}) :: #{@children.length} :: "
|
458
|
+
@children.each { |n,c| str << "#{n}, " }
|
459
|
+
return str
|
460
|
+
end
|
461
|
+
|
462
|
+
def <=>(anOther)
|
463
|
+
@str <=> anOther.str
|
464
|
+
end
|
465
|
+
|
466
|
+
def addChild child
|
467
|
+
# puts "#{@name}.addChild(#{child.name})"
|
468
|
+
# puts "children: #{@children}"
|
469
|
+
@children[child.name] = child if @children[child.name].nil?
|
470
|
+
# puts "children: #{@children}"
|
471
|
+
end
|
472
|
+
|
473
|
+
def child name
|
474
|
+
@children[name]
|
475
|
+
end
|
476
|
+
|
477
|
+
end # class JoinTable
|
478
|
+
|
479
|
+
|
480
|
+
class JoinTree
|
481
|
+
|
482
|
+
attr_reader :datasource, :root, :maxdepth, :tables
|
483
|
+
|
484
|
+
def initialize datasource
|
485
|
+
@datasource = datasource
|
486
|
+
@root = nil
|
487
|
+
@maxdepth = 0
|
488
|
+
@tables = {}
|
489
|
+
end
|
490
|
+
|
491
|
+
def add host, dest
|
492
|
+
# puts "\nJT add() host: #{host}"
|
493
|
+
# puts " dest: #{dest}"
|
494
|
+
from = @tables[host.name].nil? ? host : @tables[host.name]
|
495
|
+
to = @tables[dest.name].nil? ? dest : @tables[dest.name]
|
496
|
+
from.addChild(to)
|
497
|
+
@tables[from.name] = from
|
498
|
+
@tables[to.name] = to
|
499
|
+
if @root.nil? || @root.name.eql?(to.name)
|
500
|
+
@root = from
|
501
|
+
end
|
502
|
+
setDepth(@root,1)
|
503
|
+
end
|
504
|
+
|
505
|
+
def table tableName
|
506
|
+
@tables[tableName]
|
507
|
+
end
|
508
|
+
|
509
|
+
def setDepth table, depth
|
510
|
+
# puts "-- setDepth(#{table.class}[#{table.name}] \t, #{depth})"
|
511
|
+
@tables[table.name].depth = depth
|
512
|
+
childrenDepth = depth+1
|
513
|
+
table.children.each { |n,c| setDepth(c,childrenDepth)}
|
514
|
+
end
|
515
|
+
|
516
|
+
def tableDepth tableName
|
517
|
+
@tables[tableName].nil? ? 0 : @tables[tableName].depth
|
518
|
+
end
|
519
|
+
|
520
|
+
def disp table
|
521
|
+
puts "%s %s %s (%d)" % [' ' * table.depth, '-' * table.depth, table.name, table.depth]
|
522
|
+
table.children.each { |n,c| disp c}
|
523
|
+
end
|
524
|
+
|
525
|
+
def iterate
|
526
|
+
disp @root
|
527
|
+
end
|
528
|
+
|
529
|
+
def to_s
|
530
|
+
str = "root: #{@root}\ntables"
|
531
|
+
@tables.each do |t|
|
532
|
+
str << " tbl:: #{t}"
|
533
|
+
end
|
534
|
+
return str
|
535
|
+
end
|
536
|
+
|
537
|
+
end # class JoinTree
|
538
|
+
|
539
|
+
end # module Twb
|