trino-client 2.0.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50686d406d4aedd29016b8b5cfee3024869e797791cc53e099dbf813f6a7d135
4
- data.tar.gz: d4d2e2762b8eba6ecaf6c2dd07c19f1db37eee5c8d1ebf4c995d88ec768fe62c
3
+ metadata.gz: a9ecbdf7d017c29ac4e645d54564a701538724367f8ae62551c5e5dce705f91f
4
+ data.tar.gz: 78f07db77b0c6231c563c4a39a74e07d186c93b0b0ad03327439c9781e5d577d
5
5
  SHA512:
6
- metadata.gz: 203db357ca5034c2000d836667ac1bb92d976300d7299663105af90f284657854eb061625b48756a4cba0d21a4d8342d5006c95a7b6eab7e37ca1abbe832c21d
7
- data.tar.gz: 5566882e00f6edac34ac3d863d78aea8f3358e829b86d7ffff9f51582b42315b7a2b87e0d71a7b22cfd98eea5ac0fb20ab28f1e219991f1ac62e28256cf914ec
6
+ metadata.gz: 2c6c3b16e146d2141df38a4bd10e873cedcb18d3a0f6cb8908122382ac2cc44b471a27a4c243981ff9783da450f497ef4219d6bf4a4cc1c4e94a7d2a6ab084f2
7
+ data.tar.gz: 71bf6ac5e65dada7e5f02f03f7abf13132a81849520720a41641acc2041ef2bfbd4f8000de476d968dfec3c5666cf94c6acff52ec2771aaabb924bfddd228d44
data/ChangeLog.md CHANGED
@@ -1,5 +1,12 @@
1
1
  trino-client-ruby
2
2
  ====
3
+ ## 2.2.0
4
+ - Add transform_row and scalar_parser documentation and make them easier to use ([#118](https://github.com/treasure-data/trino-client-ruby/issues/118)) [[41ffca7](https://github.com/treasure-data/trino-client-ruby/commit/41ffca7)]
5
+
6
+ ## 2.1.0
7
+ - Add utility for transforming Trino ROW type columns into Ruby hashes ([#117](https://github.com/treasure-data/trino-client-ruby/issues/117)) [[e14251c](https://github.com/treasure-data/trino-client-ruby/commit/e14251c)]
8
+ - Bump actions/checkout from 3 to 4 ([#116](https://github.com/treasure-data/trino-client-ruby/issues/116)) [[ebd9d9e](https://github.com/treasure-data/trino-client-ruby/commit/ebd9d9e)]
9
+
3
10
  ## 2.0.1
4
11
  - Reduce published gem size ([#113](https://github.com/treasure-data/trino-client-ruby/issues/113)) [[4e03819](https://github.com/treasure-data/trino-client-ruby/commit/4e03819)]
5
12
  - Update standard requirement from ~> 1.24.3 to ~> 1.30.1 ([#112](https://github.com/treasure-data/trino-client-ruby/issues/112)) [[b9f9c0c](https://github.com/treasure-data/trino-client-ruby/commit/b9f9c0c)]
data/README.md CHANGED
@@ -64,6 +64,19 @@ query = client.query("select * from sys.node")
64
64
  query_id = query.query_info.query_id
65
65
  query.each_row {|row| ... } # when a thread is processing the query,
66
66
  client.kill(query_id) # another thread / process can kill the query.
67
+
68
+ # Use Query#transform_row to parse Trino ROW types into Ruby Hashes.
69
+ # You can also set a scalar_parser to parse scalars how you'd like them.
70
+ scalar_parser = -> (data, type) { (type === 'json') ? JSON.parse(data) : data }
71
+ client.query("select * from sys.node") do |q|
72
+ q.scalar_parser = scalar_parser
73
+
74
+ # get query results. it feeds more rows until
75
+ # query execution finishes:
76
+ q.each_row {|row|
77
+ p q.transform_row(row)
78
+ }
79
+ end
67
80
  ```
68
81
 
69
82
  ## Build models
@@ -0,0 +1,115 @@
1
+ module Trino::Client
2
+ class ColumnValueParser
3
+ INSIDE_MATCHING_PARENS_REGEX = /\((?>[^)(]+|\g<0>)*\)/
4
+
5
+ attr_reader :name, :type, :scalar_parser
6
+
7
+ def initialize(column, scalar_parser = nil)
8
+ @name = column.name
9
+ @type = prepare_type_for_parsing(column.type)
10
+ @scalar_parser = scalar_parser
11
+ end
12
+
13
+ # Public: Parse the value of a row's field by using its column's Trino type.
14
+ # Trino types can be scalars like VARCHAR and TIMESTAMP or complex types
15
+ # like ARRAY and ROW. ROW types are treated as objects.
16
+ # An ARRAY column's type is an array of types as you'd expect. A ROW
17
+ # column's type is a comma-separated list of space-separated (name, type) tuples.
18
+ #
19
+ # data - The value of a row's field. Can be a string, number, an array of those,
20
+ # or an arrays of arrays, etc.
21
+ # dtype - The Trino type string of the column. See above explanation.
22
+ #
23
+ # Returns:
24
+ # - The given value for strings and numbers
25
+ # - A Time for timestamps
26
+ # - A Hash of { field1 => value1, field2 => value2, ...etc } for row types
27
+ # - An array of the above for array types
28
+ def value(data, dtype = type)
29
+ # Convert Trino ARRAY elements into Ruby Arrays
30
+ if starts_with?(dtype, 'array(')
31
+ return parse_array_element(data, dtype)
32
+
33
+ # Convert Trino ROW elements into Ruby Hashes
34
+ elsif starts_with?(dtype, 'row(')
35
+ return parse_row_element(data, dtype)
36
+
37
+ # If defined, use scalar_parser to convert scalar types
38
+ elsif !scalar_parser.nil?
39
+ return scalar_parser.call(data, dtype)
40
+ end
41
+
42
+ # Otherwise, values are returned unaltered
43
+ data
44
+ end
45
+
46
+ private
47
+
48
+ # Private: Remove quotation marks and handle recent versions of
49
+ # Trino having a 'with time zone' suffix on some fields that breaks
50
+ # out assumption that types don't have spaces in them.
51
+ #
52
+ # Returns a string.
53
+ def prepare_type_for_parsing(type)
54
+ type.gsub('"', '').gsub(' with time zone', '_with_time_zone')
55
+ end
56
+
57
+ def parse_array_element(data, dtype)
58
+ # If the element is empty, return an empty array
59
+ return [] if blank?(data)
60
+
61
+ # Inner data type will be the current dtype with `array(` and `)` chopped off
62
+ inner_dtype = dtype.match(INSIDE_MATCHING_PARENS_REGEX)[0][1..-2]
63
+
64
+ data.map { |inner_data| value(inner_data, inner_dtype) }
65
+ end
66
+
67
+ def parse_row_element(data, dtype)
68
+ # If the element is empty, return an empty object
69
+ return {} if blank?(data)
70
+
71
+ parsed_row_element = {}
72
+
73
+ inner_dtype = dtype.match(INSIDE_MATCHING_PARENS_REGEX)[0][1..-2]
74
+ elems = inner_dtype.split(' ')
75
+ num_elems_to_skip = 0
76
+ field_position = 0
77
+
78
+ # Iterate over each datatype of the row and mutate parsed_row_element
79
+ # to have a key of the field name and value for that field's value.
80
+ elems.each_with_index do |field, i|
81
+ # We detected an array or row and are skipping all of the elements within it
82
+ # since its conversion was handled by calling `value` recursively.
83
+ if num_elems_to_skip.positive?
84
+ num_elems_to_skip -= 1
85
+ next
86
+ end
87
+
88
+ # Field names never have these characters and are never the last element.
89
+ next if field.include?(',') || field.include?('(') || field.include?(')') || i == elems.length - 1
90
+
91
+ type = elems[(i + 1)..].join(' ')
92
+
93
+ # If this row has a nested array or row, the type of this field is that array or row's type.
94
+ if starts_with?(type, 'array(') || starts_with?(type, 'row(')
95
+ datatype = type.sub(/\(.*/, '')
96
+ type = "#{datatype}#{type.match(INSIDE_MATCHING_PARENS_REGEX)[0]}"
97
+ num_elems_to_skip = type.split(' ').length # see above comment about num_elems_to_skip
98
+ end
99
+
100
+ parsed_row_element[field] = value(data[field_position], type)
101
+ field_position += 1
102
+ end
103
+
104
+ parsed_row_element
105
+ end
106
+
107
+ def blank?(obj)
108
+ obj.respond_to?(:empty?) ? !!obj.empty? : !obj
109
+ end
110
+
111
+ def starts_with?(str, prefix)
112
+ prefix.respond_to?(:to_str) && str[0, prefix.length] == prefix
113
+ end
114
+ end
115
+ end
@@ -18,6 +18,7 @@ module Trino::Client
18
18
  require 'faraday'
19
19
  require 'faraday/gzip'
20
20
  require 'faraday/follow_redirects'
21
+ require 'trino/client/column_value_parser'
21
22
  require 'trino/client/models'
22
23
  require 'trino/client/errors'
23
24
  require 'trino/client/faraday_client'
@@ -44,6 +45,21 @@ module Trino::Client
44
45
  Trino::Client.faraday_client(options)
45
46
  end
46
47
 
48
+ def self.transform_row(column_value_parsers, row)
49
+ row_object = {}
50
+
51
+ row.each_with_index do |element, i|
52
+ column = column_value_parsers[i]
53
+ value = column.value(element)
54
+
55
+ row_object[column.name] = value
56
+ end
57
+
58
+ row_object
59
+ end
60
+
61
+ attr_accessor :scalar_parser
62
+
47
63
  def initialize(api)
48
64
  @api = api
49
65
  end
@@ -86,6 +102,21 @@ module Trino::Client
86
102
  return @api.current_results.columns
87
103
  end
88
104
 
105
+ def column_value_parsers
106
+ @column_value_parsers ||= {}
107
+ @column_value_parsers[scalar_parser] ||= columns.map {|column|
108
+ ColumnValueParser.new(column, scalar_parser)
109
+ }
110
+ end
111
+
112
+ def transform_rows
113
+ rows.map { |row| transform_row(row) }
114
+ end
115
+
116
+ def transform_row(row)
117
+ self.class.transform_row(column_value_parsers, row)
118
+ end
119
+
89
120
  def rows
90
121
  rows = []
91
122
  each_row_chunk {|chunk|
@@ -15,6 +15,6 @@
15
15
  #
16
16
  module Trino
17
17
  module Client
18
- VERSION = "2.0.1"
18
+ VERSION = "2.2.0"
19
19
  end
20
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trino-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-17 00:00:00.000000000 Z
11
+ date: 2023-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -190,6 +190,7 @@ files:
190
190
  - lib/trino-client.rb
191
191
  - lib/trino/client.rb
192
192
  - lib/trino/client/client.rb
193
+ - lib/trino/client/column_value_parser.rb
193
194
  - lib/trino/client/errors.rb
194
195
  - lib/trino/client/faraday_client.rb
195
196
  - lib/trino/client/model_versions/0.149.rb