Class: Twb::DataSource

Inherits:
Object
  • Object
show all
Defined in:
lib/twb/datasource.rb

Constant Summary collapse

@@hasher =
Digest::SHA256.new
@@connGNodeParamsJSON =
%q(
{ "csv"           : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "CSV"        },
  "excel"         : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "Excel"      },
  "dataengine"    : { "label" : ["dbname"  ], "id" : ["directory","filename"], "type" : "TDE"        },
  "msaccess"      : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "MS Access"  },
  "oracle"        : { "label" : ["server"  ], "id" : [            "server"  ], "type" : "Oracle"     },
  "postgres"      : { "label" : ["server"  ], "id" : [            "server"  ], "type" : "PostgreSQL" },
  "textscan"      : { "label" : ["filename"], "id" : ["directory","filename"], "type" : "CSV / TSV"  },
  "excel-direct"  : { "label" : ["filename"], "id" : [            "filename"], "type" : "Excel"      },
  "salesforce"    : { "label" : ["server"  ], "id" : [            "server"  ], "type" : "Salesforce" }
}
)
@@cgNodeParams =
JSON.parse @@connGNodeParamsJSON

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dataSourceNode, workbook) ⇒ DataSource

Returns a new instance of DataSource.



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/twb/datasource.rb', line 58

def initialize dataSourceNode, workbook
  @node     = dataSourceNode
  @workbook = workbook 
  @name     = @node.attr('name')
  @caption  = @node.attr('caption')
  @uiname   = @caption.nil? ? @name : @caption
  processConnection
  processFilters
  loadTableFields
  return self
end

Instance Attribute Details

#allFieldsObject (readonly)

Returns the value of attribute allFields.



54
55
56
# File 'lib/twb/datasource.rb', line 54

def allFields
  @allFields
end

#calculatedField(name) ⇒ Object (readonly)

Returns the value of attribute calculatedField.



53
54
55
# File 'lib/twb/datasource.rb', line 53

def calculatedField
  @calculatedField
end

#calculatedFieldNamesObject (readonly)

Returns the value of attribute calculatedFieldNames.



53
54
55
# File 'lib/twb/datasource.rb', line 53

def calculatedFieldNames
  @calculatedFieldNames
end

#calculatedFieldNamesMapObject (readonly)

Returns the value of attribute calculatedFieldNamesMap.



53
54
55
# File 'lib/twb/datasource.rb', line 53

def calculatedFieldNamesMap
  @calculatedFieldNamesMap
end

#calculatedFieldsObject (readonly)

Returns the value of attribute calculatedFields.



53
54
55
# File 'lib/twb/datasource.rb', line 53

def calculatedFields
  @calculatedFields
end

#captionObject (readonly)

Returns the value of attribute caption.



42
43
44
# File 'lib/twb/datasource.rb', line 42

def caption
  @caption
end

#columnFieldsObject (readonly)

Returns the value of attribute columnFields.



47
48
49
# File 'lib/twb/datasource.rb', line 47

def columnFields
  @columnFields
end

#connectionObject (readonly)

Returns the value of attribute connection.



44
45
46
# File 'lib/twb/datasource.rb', line 44

def connection
  @connection
end

#connHashObject (readonly)

Returns the value of attribute connHash.



44
45
46
# File 'lib/twb/datasource.rb', line 44

def connHash
  @connHash
end

#dbFieldsObject (readonly)

Returns the value of attribute dbFields.



49
50
51
# File 'lib/twb/datasource.rb', line 49

def dbFields
  @dbFields
end

#dsclassObject (readonly)

Returns the value of attribute dsclass.



43
44
45
# File 'lib/twb/datasource.rb', line 43

def dsclass
  @dsclass
end

#fieldUINamesObject (readonly)

Returns the value of attribute fieldUINames.



52
53
54
# File 'lib/twb/datasource.rb', line 52

def fieldUINames
  @fieldUINames
end

#filtersObject (readonly)

Returns the value of attribute filters.



55
56
57
# File 'lib/twb/datasource.rb', line 55

def filters
  @filters
end

#hasFieldObject (readonly)

Returns the value of attribute hasField.



46
47
48
# File 'lib/twb/datasource.rb', line 46

def hasField
  @hasField
end

#isExtractObject (readonly)

Returns the value of attribute isExtract.



43
44
45
# File 'lib/twb/datasource.rb', line 43

def isExtract
  @isExtract
end

#joinPairsObject (readonly)

Returns the value of attribute joinPairs.



45
46
47
# File 'lib/twb/datasource.rb', line 45

def joinPairs
  @joinPairs
end

#localFieldObject (readonly)

Returns the value of attribute localField.



46
47
48
# File 'lib/twb/datasource.rb', line 46

def localField
  @localField
end

#localFieldNamesObject (readonly)

Returns the value of attribute localFieldNames.



46
47
48
# File 'lib/twb/datasource.rb', line 46

def localFieldNames
  @localFieldNames
end

#localFieldsObject (readonly)

Returns the value of attribute localFields.



46
47
48
# File 'lib/twb/datasource.rb', line 46

def localFields
  @localFields
end

#mappedFieldsObject (readonly)

Returns the value of attribute mappedFields.



50
51
52
# File 'lib/twb/datasource.rb', line 50

def mappedFields
  @mappedFields
end

#metadataFieldsObject (readonly)

Returns the value of attribute metadataFields.



48
49
50
# File 'lib/twb/datasource.rb', line 48

def metadataFields
  @metadataFields
end

#nameObject (readonly)

Returns the value of attribute name.



42
43
44
# File 'lib/twb/datasource.rb', line 42

def name
  @name
end

#nodeObject (readonly)

Returns the value of attribute node.



56
57
58
# File 'lib/twb/datasource.rb', line 56

def node
  @node
end

#tableFieldsMapObject (readonly)

Returns the value of attribute tableFieldsMap.



51
52
53
# File 'lib/twb/datasource.rb', line 51

def tableFieldsMap
  @tableFieldsMap
end

#tablesObject (readonly)

Returns the value of attribute tables.



45
46
47
# File 'lib/twb/datasource.rb', line 45

def tables
  @tables
end

#uinameObject (readonly)

Returns the value of attribute uiname.



42
43
44
# File 'lib/twb/datasource.rb', line 42

def uiname
  @uiname
end

#workbookObject (readonly)

Returns the value of attribute workbook.



41
42
43
# File 'lib/twb/datasource.rb', line 41

def workbook
  @workbook
end

Instance Method Details

#calculatedFieldsMapObject



283
284
285
# File 'lib/twb/datasource.rb', line 283

def calculatedFieldsMap
  @calculatedFieldsMap ||= loadCalculatedFields
end

#columnFieldsMapObject



162
163
164
165
# File 'lib/twb/datasource.rb', line 162

def columnFieldsMap
  loadColumnFields if @columnFieldsMap.nil?
  return @columnFieldsMap
end

#dbFieldsMapObject



265
266
267
# File 'lib/twb/datasource.rb', line 265

def dbFieldsMap
  @tableFieldsMap
end

#fieldTable(fieldName) ⇒ Object



324
325
326
327
328
# File 'lib/twb/datasource.rb', line 324

def fieldTable fieldName
  loadTableFields if @tableFieldsMap.nil?
  dbField = @tableFieldsMap[fieldName]
  return dbField.nil? ? nil : dbField.dbtable
end

#fieldUIName(fieldName) ⇒ Object



233
234
235
236
# File 'lib/twb/datasource.rb', line 233

def fieldUIName fieldName
  loadFieldUINames if @fieldUINames.nil?
  @fieldUINames[fieldName]
end

#has_field?(fieldName) ⇒ Boolean

Returns:

  • (Boolean)


320
321
322
# File 'lib/twb/datasource.rb', line 320

def has_field? fieldName
  dbFieldsMap.has_key? fieldName
end

#joinTreeObject



130
131
132
# File 'lib/twb/datasource.rb', line 130

def joinTree
  @joinTree ||= loadJoinTree
end

#loadCalculatedFieldsObject



302
303
304
305
306
307
308
309
310
# File 'lib/twb/datasource.rb', line 302

def loadCalculatedFields
  @calculatedFieldsMap = {}
  cfnodes = @node.xpath("./column[calculation]")
  cfnodes.each do |node|
    calcField = Twb::CalculatedField.new node, self
    @calculatedFieldsMap[calcField.uiname] = calcField
  end
  return @calculatedFieldsMap
end

#loadColumnFieldsObject



167
168
169
170
171
172
173
174
175
176
177
# File 'lib/twb/datasource.rb', line 167

def loadColumnFields
  @columnFields    = Set.new
  @columnFieldsMap = {}
  nodes = @node.xpath('./column')
  nodes.each do |n|
    field = Twb::ColumnField.new n, self
    @columnFields << field
    @columnFieldsMap[field.uiname] = field
  end
  return @columnFields
end

#loadFieldUINamesObject



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/twb/datasource.rb', line 243

def loadFieldUINames
  @fieldUINames = {}
  metadataFields.each do |fld|
    unless fld.localName.nil?
      @fieldUINames[fld.localName] = fld.uiname
      @fieldUINames[fld.uiname]    = fld.uiname
    end
  end
  calculatedFields.each do |fld| 
    @fieldUINames[fld.name]   = fld.uiname
    @fieldUINames[fld.uiname] = fld.uiname
  end
  localFields.each do |fld| 
    @fieldUINames[fld.name]   = fld.uiname
    @fieldUINames[fld.uiname] = fld.uiname
  end
end

#loadJoinPairsObject



119
120
121
122
123
124
125
126
127
128
# File 'lib/twb/datasource.rb', line 119

def loadJoinPairs
  @joinPairs = Set.new
  mainJoin   = @node.xpath("./connection/relation[@type='join']")
  clauses    = @node.xpath(".//relation[@type='join']/clause") 
  clauses.each do |clause|
    leafs = clause.xpath('.//expression[not(node())]')
    @joinPairs << [ pullTable(leafs[0]) , pullTable(leafs[1]) ]
  end
  return @joinPairs
end

#loadJoinTreeObject



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/twb/datasource.rb', line 134

def loadJoinTree
  loadJoinPairs if @joinPairs.nil?
  # puts "LJT::#{@uiname}::joinPairs:: #{@joinPairs.inspect}"
  # @joinPairs.each { |jp| puts "JP::#{jp}" }
  @joinTree = JoinTree.new(@name)
  @joinPairs.each do |from,to|
    # puts "from:#{from} -> to:#{to}"
    tableFrom = JoinTable.new(from)
    tableTo   = JoinTable.new(to)
    @joinTree.add(tableFrom, tableTo)
  end
  # puts '---'
  return @joinTree
end

#loadLocalFieldsObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/twb/datasource.rb', line 184

def loadLocalFields
  @localFields = Set.new
  unless @connection.nil?  # Parameters has no connection node, & no local fields
    connClass    = @node.at_xpath('./connection').attribute('class').text
    fxpath       = case connClass
                   when 'dataengine' then './column'
                   when 'sqlserver'  then './column'
                   else                   './connection/relation/columns/column'
                   end
    nodes = @node.xpath(fxpath)
    nodes.each do |node|
      field = Twb::LocalField.new(node)
      @localFields << field
    end
  end
  return @localFields
end

#loadMetadataFieldsObject



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/twb/datasource.rb', line 206

def loadMetadataFields
  @metadataFields = Set.new
  unless @connection.nil?  # Parameters has no connection node, & no metadata fields
    # nodes = @node.xpath(".//metadata-record[@class='column']")
    # # note: there are other nodes "<metadata-record class='capability'>" whose nature is unclear
    # #       these nodes have no value for their <name node, so are not loaded
    nodes = @node.xpath("./connection//metadata-record[@class='column']")
    nodes.each do |node|
      field = Twb::MetadataField.new(node)
      field.source = :db
      @metadataFields << field
    end
    nodes = @node.xpath('./extract//metadata-record')
    nodes.each do |node|
      field = Twb::MetadataField.new(node)
      field.source = :extract
      @metadataFields << field
    end
  end
  return @metadataFields
end

#loadTableFieldsObject

fields are unique in the data source by UI name



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/twb/datasource.rb', line 331

def loadTableFields
  # puts "DATA SOURCE FIELD TABLE LOAD"
  @tableFieldsMap = {}
  fieldNodes = @node.xpath('./connection/cols/map')
  fieldNodes.each do |fn|
    dbField = Twb::DbField.new(@uiname, fn, :map)
    @tableFieldsMap[dbField.uiname] = dbField
  end
  relTableNodes = @node.xpath('.//relation[@table]')
  relTableNodes.each do |relNode|
    table = relNode.attribute('name').text
    cols  = relNode.xpath('./columns/column')
    cols.each do |col|
      dbField = Twb::DbField.new(@uiname, col, :tableColumn, table)
      fldName = col.attribute('name')
      @tableFieldsMap[dbField.uiname] = dbField
    end
  end
end

#loadTables(connection) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/twb/datasource.rb', line 107

def loadTables connection
  @tables = {}
  nodes = connection.xpath(".//relation[@type='table']")
  nodes.each do |node|
    @tables[node.attr('name')] = node.attr('table')
  end
end

#mappedFieldsMapObject



273
274
275
276
# File 'lib/twb/datasource.rb', line 273

def mappedFieldsMap
  loadTableFields if @tableFieldsMap.nil?
  return @tableFieldsMap
end

#Parameters?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/twb/datasource.rb', line 154

def Parameters?
  'Parameters'.eql? @name 
end

#processConnectionObject



78
79
80
81
82
83
84
85
86
87
# File 'lib/twb/datasource.rb', line 78

def processConnection
  @connection  = @node.at_xpath('./connection')
  @dsclass     = @name  # handles 'Parameters' data source, which has no connection element (& others if so)  
  unless @connection.nil?
    @dsclass = @connection.attribute('class').text
    # note: must use "dsclass" as "class" would override Rubys ".class" Kernel method
    setConnectionHash
    loadTables @connection
  end
end

#processFiltersObject



351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/twb/datasource.rb', line 351

def processFilters
  if @filters.nil?
    @filters = {}
    fnodes = @node.xpath('./filter')
    fnodes.each do |fn|
      columnN = fn.attribute('column')
      unless columnN.nil?
        memberNodes = fn.xpath('.//groupfilter/@member')
        unless memberNodes.nil?
          members = []
          memberNodes.each do |m|
            members.push m.text
          end
          @filters[columnN.text] = members
        end
      end 
    end
  end
end

#pullTable(xml) ⇒ Object



149
150
151
152
# File 'lib/twb/datasource.rb', line 149

def pullTable xml
    code =xml.attribute('op').text
    table = code.split('].[')[0][1..-1]
end

#setConnectionHashObject

Notes:

- TODO: need to determine which, if any, of the connection attributes should be
        included in the hash in order to identify it unambiguously - without
        local values that obscure the data source's 'real' identity
- attributes with value '' don't contribute to the hash


94
95
96
97
98
99
100
101
# File 'lib/twb/datasource.rb', line 94

def setConnectionHash
  dsAttributes = @node.xpath('./connection/@*')
  dsConnStr    = ''
  dsAttributes.each do |attr|
    dsConnStr += attr.text
  end
  @connHash = Digest::MD5.hexdigest(dsConnStr)
end

#tableauVersionObject



70
71
72
# File 'lib/twb/datasource.rb', line 70

def tableauVersion tabVersion
  @tableauVersion = tabVersion
end

#tableFieldsObject



261
262
263
# File 'lib/twb/datasource.rb', line 261

def tableFields
  @tableFieldsMap.values
end

#updateTimeObject



228
229
230
231
# File 'lib/twb/datasource.rb', line 228

def updateTime
  attr = @node.xpath('.//@update-time').first
  @updateTime = attr.nil? ? nil : attr.value
end