athens 0.1.0 → 0.3.3

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: '02197372c02d45a05efd88997b4cd8c01d66c869eafd6ca867f86da791ffe7b4'
4
- data.tar.gz: 1753f4f6986c4fedf82f09d9a6d9ebe0b9fb630d59261011fc3c0667108e4ed0
3
+ metadata.gz: fa391fbff6c5016740bc28cfb0692fcc79ee2e1361d31541a635691e6cbbc8a7
4
+ data.tar.gz: ef1fbb6307221f616576e844ced0ed9398ff9e6db436fde0142e58c89be8c9f5
5
5
  SHA512:
6
- metadata.gz: facc871951901270b2b61410ae471cd6d62fcb33d2a914da76855e41fbccfb5039ee4e0d086deced77bcf39bf8c07fe865c635d6659093a2acac181291c78c2a
7
- data.tar.gz: feca9c73d6145784b74dc4ce5442c2b764efda51719ff58e5fa6896d8dfd89186224d7aaa4f9ae282d58043bf5aa4f0e3576998d40ec0d9983c51d917d6d8022
6
+ metadata.gz: e37d29e7d93b1aa61d6266b5feccc3789087f697c1751830893adc4c795761f587bafdaa44f34de6b5786712d8983e66511d3d0f10fa1b0922ec6921e4201e66
7
+ data.tar.gz: 0ccaf8bbb67bceb9136806a93da4447ace996ab9709e82d8f6861249e6a62246680c3a618a1479481b931127e568e966038569da2d1814540ef64b7ab3dd155e
@@ -1,3 +1,26 @@
1
+ ## 0.3.3 / 2021-01-12
2
+
3
+ * Added support for Ruby 3.0 (thanks [blackjiro](https://github.com/blackjiro))
4
+
5
+ ## 0.3.2 / 2020-11-24
6
+
7
+ * Added optional `request_token` and `work_group` parameters to the query execute method (thanks [mediafinger](https://github.com/mediafinger))
8
+
9
+ ## 0.3.1 / 2020-07-20
10
+
11
+ * Bumped development rake version from 0.10 to 0.13 for security fixes
12
+ * Fixed warning about string defaulting to string (#2)
13
+
14
+ ## 0.3.0 / 2019-07-02
15
+
16
+ * Added enumerator-based result access methods: `#rows` and `#records`
17
+ * Fixed bug dropping headers from memoized rows across `#to_h` and `#to_a(header_row: true)`
18
+
19
+ ## 0.2.0 / 2019-03-20
20
+
21
+ * Added support for NULL values. Columns with a nullable status of "NULLABLE" or "UNKNOWN" will return nil for NULL values
22
+ * If a NOT_NULL column returns a nil value an InvalidNullError will be raised
23
+
1
24
  ## 0.1.0 / 2019-03-01
2
25
 
3
26
  * Initial release!
@@ -1,33 +1,36 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- athens (0.1.0)
4
+ athens (0.3.3)
5
5
  aws-sdk-athena (~> 1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- aws-eventstream (1.0.1)
11
- aws-partitions (1.136.0)
12
- aws-sdk-athena (1.7.0)
13
- aws-sdk-core (~> 3, >= 3.39.0)
14
- aws-sigv4 (~> 1.0)
15
- aws-sdk-core (3.46.0)
16
- aws-eventstream (~> 1.0)
17
- aws-partitions (~> 1.0)
18
- aws-sigv4 (~> 1.0)
10
+ aws-eventstream (1.1.0)
11
+ aws-partitions (1.416.0)
12
+ aws-sdk-athena (1.33.0)
13
+ aws-sdk-core (~> 3, >= 3.109.0)
14
+ aws-sigv4 (~> 1.1)
15
+ aws-sdk-core (3.111.0)
16
+ aws-eventstream (~> 1, >= 1.0.2)
17
+ aws-partitions (~> 1, >= 1.239.0)
18
+ aws-sigv4 (~> 1.1)
19
19
  jmespath (~> 1.0)
20
- aws-sigv4 (1.0.3)
20
+ aws-sigv4 (1.2.2)
21
+ aws-eventstream (~> 1, >= 1.0.2)
21
22
  jmespath (1.4.0)
22
- rake (10.5.0)
23
+ rake (13.0.1)
24
+ rexml (3.2.4)
23
25
 
24
26
  PLATFORMS
25
27
  ruby
26
28
 
27
29
  DEPENDENCIES
28
30
  athens!
29
- bundler (~> 1.17)
30
- rake (~> 10.0)
31
+ bundler (>= 1.17)
32
+ rake (~> 13.0)
33
+ rexml (~> 3.2)
31
34
 
32
35
  BUNDLED WITH
33
- 1.17.2
36
+ 2.2.5
data/README.md CHANGED
@@ -61,6 +61,23 @@ results = query.to_h
61
61
  # ]
62
62
  ```
63
63
 
64
+ Results are also available as unbuffered enumerators of row arrays:
65
+ ```ruby
66
+ query.rows.each {|row| ...}
67
+ # ['column_1', 'column_2', 'column_3']
68
+ # [15, 'data', true]
69
+ # [20, 'foo', false],
70
+ # ...
71
+ ```
72
+
73
+ Or hashes:
74
+ ```ruby
75
+ query.records.each {|record| ...}
76
+ # {'column_1': 15, 'column_2': 'data', 'column_3': true}
77
+ # {'column_1': 20, 'column_2': 'foo', 'column_3': false}
78
+ # ...
79
+ ```
80
+
64
81
  Athens attempts to parse the sql data types into their ruby equivalents, although there's currently no support for the more complex Array/Map types.
65
82
 
66
83
  ### Configuration
@@ -129,6 +146,13 @@ query.cancel # Attempts to cancel an in-progress query, returns true or false
129
146
  query.to_a(header_row: false) # If you want your query results returned without a header row of column names
130
147
  ```
131
148
 
149
+ The execute method also optionally supports the `request_token` and `work_group` [parameters](https://docs.aws.amazon.com/athena/latest/APIReference/API_StartQueryExecution.html#API_StartQueryExecution_RequestSyntax):
150
+
151
+ ```ruby
152
+ conn = Athens::Connection.new(database: 'sample')
153
+ query = conn.execute("SELECT * FROM mytable", request_token: single_use_token, work_group: my_work_group)
154
+ ```
155
+
132
156
  ## Development
133
157
 
134
158
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,2 +1 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
@@ -32,10 +32,11 @@ Gem::Specification.new do |spec|
32
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
33
  spec.require_paths = ["lib"]
34
34
 
35
- spec.required_ruby_version = '~> 2.4'
35
+ spec.required_ruby_version = '>= 2.4'
36
36
 
37
37
  spec.add_dependency "aws-sdk-athena", "~> 1"
38
38
 
39
- spec.add_development_dependency "bundler", "~> 1.17"
40
- spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "bundler", ">= 1.17"
40
+ spec.add_development_dependency "rake", "~> 13.0"
41
+ spec.add_development_dependency "rexml", "~> 3.2"
41
42
  end
@@ -8,7 +8,7 @@ module Athens
8
8
  def initialize(database: nil, aws_client_override: {})
9
9
  @database_name = database
10
10
 
11
- client_config = {
11
+ client_config = {
12
12
  access_key_id: Athens.configuration.aws_access_key,
13
13
  secret_access_key: Athens.configuration.aws_secret_key,
14
14
  region: Athens.configuration.aws_region
@@ -19,26 +19,28 @@ module Athens
19
19
 
20
20
  # Runs a query against Athena, returning an Athens::Query object
21
21
  # that you can use to wait for it to finish or get the results
22
- def execute(query)
22
+ def execute(query, request_token: nil, work_group: nil)
23
23
  if @database_name
24
24
  resp = @client.start_query_execution(
25
25
  query_string: query,
26
26
  query_execution_context: context,
27
- result_configuration: result_config
27
+ result_configuration: result_config,
28
+ client_request_token: request_token,
29
+ work_group: work_group
28
30
  )
29
31
  else
30
32
  resp = @client.start_query_execution(
31
33
  query_string: query,
32
34
  result_configuration: result_config
33
35
  )
34
- end
36
+ end
35
37
 
36
38
  return Athens::Query.new(self, resp.query_execution_id)
37
39
  end
38
40
 
39
41
  private
40
42
 
41
- def context
43
+ def context
42
44
  Aws::Athena::Types::QueryExecutionContext.new(database: @database_name)
43
45
  end
44
46
 
@@ -4,5 +4,6 @@ module Athens
4
4
  class QueryFailedError < Error; end
5
5
  class QueryCancelledError < Error; end
6
6
  class InvalidRequestError < Error; end
7
+ class InvalidNullError < Error; end
7
8
 
8
9
  end
@@ -69,12 +69,10 @@ module Athens
69
69
  end
70
70
  end
71
71
 
72
- def to_a(header_row: true)
72
+ def rows
73
73
  raise InvalidRequestError.new("Query must be in SUCCEEDED state to return results") unless @state == 'SUCCEEDED'
74
74
 
75
- if @results.nil?
76
- # Need to load and map all of the rows from the original result
77
- @results = []
75
+ Enumerator.new do |y|
78
76
  result = @connection.client.get_query_results({query_execution_id: @query_execution_id})
79
77
 
80
78
  metadata = result.result_set.result_set_metadata
@@ -85,53 +83,43 @@ module Athens
85
83
  break if rows.empty?
86
84
 
87
85
  if first
88
- @results << rows.shift.data.map {|col| col.var_char_value}
86
+ y << rows.shift.data.map {|col| col.var_char_value}
89
87
  first = false
90
88
  end
91
89
 
92
- rows.each do |row|
93
- @results << map_types(metadata, row)
94
- end
90
+ rows.each {|row| y << map_types(metadata, row)}
95
91
 
96
- if result.next_token
97
- result = @connection.client.get_query_results({
98
- query_execution_id: @query_execution_id,
99
- next_token: result.next_token
100
- })
101
- else
102
- # No more rows, break out and return our mapped data
103
- break
104
- end
105
- end
106
- end
92
+ break unless result.next_token
107
93
 
108
- if header_row
109
- return @results
110
- else
111
- return @results[1, @results.size]
94
+ result = @connection.client.get_query_results({
95
+ query_execution_id: @query_execution_id,
96
+ next_token: result.next_token
97
+ })
98
+ end
112
99
  end
113
100
  end
114
101
 
115
- def to_h
116
- if @hash_results.nil?
117
- all_rows = self.to_a(header_row: true)
118
-
119
- headers = all_rows.shift
120
-
121
- @hash_results = []
102
+ def records
103
+ Enumerator.new do |y|
104
+ headers = nil
122
105
 
123
- unless headers.nil?
124
- all_rows.each do |row|
125
- map = {}
126
- headers.each_with_index do |header, index|
127
- map[header] = row[index]
128
- end
129
- @hash_results << map
106
+ rows.each_with_index do |row|
107
+ if headers.nil?
108
+ headers = row
109
+ next
130
110
  end
111
+
112
+ y << Hash[headers.zip(row)]
131
113
  end
132
114
  end
115
+ end
116
+
117
+ def to_a(header_row: true)
118
+ (@results ||= rows.to_a).drop(header_row ? 0 : 1)
119
+ end
133
120
 
134
- return @hash_results
121
+ def to_h
122
+ @hash_results ||= records.to_a
135
123
  end
136
124
 
137
125
  private
@@ -151,29 +139,36 @@ module Athens
151
139
 
152
140
  metadata.column_info.each_with_index do |col, index|
153
141
  data = row.data[index].var_char_value
142
+ nullable = ["UNKNOWN", "NULLABLE"].include?(col.nullable)
154
143
 
155
- case col.type
156
- when 'tinyint', 'smallint', 'int', 'integer', 'bigint'
157
- mapped << data.to_i
158
- when 'timestamp'
159
- mapped << Time.parse(data)
160
- when 'varchar'
144
+ if nullable && data.nil?
161
145
  mapped << data
162
- when 'float', 'double'
163
- mapped << data.to_f
164
- when 'decimal'
165
- if @decimal_without_new
166
- mapped << BigDecimal(data)
146
+ elsif !nullable && data.nil?
147
+ raise InvalidNullError.new("Got null data from a non-null field (#{col.name})")
148
+ else
149
+ case col.type
150
+ when 'tinyint', 'smallint', 'int', 'integer', 'bigint'
151
+ mapped << data.to_i
152
+ when 'timestamp'
153
+ mapped << Time.parse(data)
154
+ when 'varchar', 'string'
155
+ mapped << data
156
+ when 'float', 'double'
157
+ mapped << data.to_f
158
+ when 'decimal'
159
+ if @decimal_without_new
160
+ mapped << BigDecimal(data)
161
+ else
162
+ mapped << BigDecimal.new(data)
163
+ end
164
+ when 'date'
165
+ mapped << Date.parse(data)
166
+ when 'boolean'
167
+ mapped << (data == "true")
167
168
  else
168
- mapped << BigDecimal.new(data)
169
+ puts "WARNING: Unsupported type: #{col.type}, defaulting to string"
170
+ mapped << data
169
171
  end
170
- when 'date'
171
- mapped << Date.parse(data)
172
- when 'boolean'
173
- mapped << (data == "true")
174
- else
175
- puts "WARNING: Unsupported type: #{col.type}, defaulting to string"
176
- mapped << data
177
172
  end
178
173
  end
179
174
 
@@ -1,3 +1,3 @@
1
1
  module Athens
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: athens
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Schulte
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-01 00:00:00.000000000 Z
11
+ date: 2021-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-athena
@@ -28,14 +28,14 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.17'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.17'
41
41
  - !ruby/object:Gem::Dependency
@@ -44,14 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rexml
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '3.2'
55
69
  description: Allows you to easily access AWS Athena databases and run queries
56
70
  email:
57
71
  - chris@oceanbreezesoftware.com
@@ -84,13 +98,13 @@ metadata:
84
98
  homepage_uri: https://github.com/getletterpress/athens
85
99
  source_code_uri: https://github.com/getletterpress/athens
86
100
  changelog_uri: https://github.com/getletterpress/athens/CHANGELOG.md
87
- post_install_message:
101
+ post_install_message:
88
102
  rdoc_options: []
89
103
  require_paths:
90
104
  - lib
91
105
  required_ruby_version: !ruby/object:Gem::Requirement
92
106
  requirements:
93
- - - "~>"
107
+ - - ">="
94
108
  - !ruby/object:Gem::Version
95
109
  version: '2.4'
96
110
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -99,9 +113,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
113
  - !ruby/object:Gem::Version
100
114
  version: '0'
101
115
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.7.8
104
- signing_key:
116
+ rubygems_version: 3.1.4
117
+ signing_key:
105
118
  specification_version: 4
106
119
  summary: Run simple SQL queries in AWS Athena
107
120
  test_files: []