Project

athens

0.03
Low commit activity in last 3 years
A long-lived project that still receives updates
Allows you to easily access AWS Athena databases and run queries
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 1.17
~> 13.0
~> 3.2

Runtime

 Project Readme

Athens

Athens is a wrapper around the standard AWS athena sdk, with a much simpler interface for executing queries and processing results.

Installation

Add this line to your application's Gemfile:

gem 'athens'

And then execute:

$ bundle

Or install it yourself as:

$ gem install athens

Usage

Quickstart

There are two main classes for Athens, the Connection and the Query. First "open" a connection to the database:

conn = Athens::Connection.new(database: 'sample')

Then start a query:

query = conn.execute("SELECT * FROM mytable")

That kicks off an Athena query in the background. If you want you can just wait for it to finish:

query.wait
# or
query.wait(5) # Wait 5 seconds at most

When your query is done, grab the results as an array:

results = query.to_a
# [
#   ['column_1', 'column_2', 'column_3'],
#   [15, 'data', true],
#   [20, 'foo', false],
#   ...
# ]

Or as a hash (which is really an array where each row is a hash):

results = query.to_h
# [
#   {'column_1': 15, 'column_2': 'data', 'column_3': true},
#   {'column_1': 20, 'column_2': 'foo', 'column_3': false},
#   ...
# ]

Results are also available as unbuffered enumerators of row arrays:

query.rows.each {|row| ...}
# ['column_1', 'column_2', 'column_3']
# [15, 'data', true]
# [20, 'foo', false],
# ...

Or hashes:

query.records.each {|record| ...}
# {'column_1': 15, 'column_2': 'data', 'column_3': true}
# {'column_1': 20, 'column_2': 'foo', 'column_3': false}
# ...

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.

Configuration

Configure your AWS settings in an Athens.configure block (in rails put this in config/initializers/athens.rb):

Athens.configure do |config|
  config.output_location = "s3://my-bucket/my-folder/athena/results/"  # Required
  config.aws_access_key      = 'access'     # Optional
  config.aws_secret_key      = 'secret'     # Optional
  config.aws_profile         = 'myprofile'  # Optional
  config.aws_region          = 'us-east-1'  # Optional
  config.wait_polling_period = 0.25         # Optional - What period should we poll for the complete query?
  config.result_encryption   = nil          # Optional, see below
end

The aws parameters are all "optional", in that you can omit those in favor of any of the standard AWS configuration options (i.e. IAM Roles, environment variables, .aws/credentials files).

You can also override the AWS client configuration on a per-connection basis:

conn = Athens::Connection.new(aws_client_override: {})

Unlike the gem's credential names, the override option accepts the same parameter names as the core AWS SDK, namely access_key_id and secret_access_key. Below is an example of using the assumed role to generate temporary credentials and using the override.

credentials = Aws::AssumeRoleCredentials.new(
  role_arn: "arn:aws:iam::ACCOUNT:role/ROLE",
  role_session_name: "AssumeRoleSession"
).credentials
conn = Athens::Connection.new(
  aws_client_override: {
    access_key_id: credentials.access_key_id,
    secret_access_key: credentials.secret_access_key,
    session_token: credentials.session_token
  }
)

Take a look at the AWS Athena SDK for a list of all the available options.

The result_encryption option controls how the Athens results will be encrypted at the output_location. By default it's set to use the Amazon SSE encryption if you don't set it at all:

{ encryption_option: "SSE_S3" }

If you set it to nil, it'll default to the bucket encryption settings. You can also use a customer kms key, see https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Athena/Types/EncryptionConfiguration.html for the correct format.

Advanced Usage

Providing a database name to the connection is optional, if you omit the name you'll have to specify it in your query:

conn = Athens::Connection.new(database 'sample')
query = conn.execute("SELECT * FROM mytable")

# or

conn = Athens::Connection.new
query = conn.execute("SELECT * FROM sample.mytable")

While waiting for a query to finish, you could get one of two exceptions:

conn = Athens::Connection.new(database 'sample')
query = conn.execute("SELECT * FROM mytable")

begin
  query.wait()
rescue Athens::QueryFailedError => qfe
  # Query returned a failure message, qfe.message has details
rescue Athens::QueryCancelledError => qce
  # Query was canceled (usually by the user), qce.message has details
end

When a query is running you can do a few things:

conn = Athens::Connection.new(database: 'sample')
query = conn.execute("SELECT * FROM mytable")

query.state  # Returns one of QUEUED, RUNNING, SUCCEEDED, FAILED, or CANCELLED (https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Athena/Types/QueryExecutionStatus.html#state-instance_method)
query.state_reason  # Further details from AWS about the state
query.query_execution_id  # The id of the query returned from AWS
query.cancel   # Attempts to cancel an in-progress query, returns true or false (if the query has already finished this will return false)

query.to_a(header_row: false)  # If you want your query results returned without a header row of column names

The execute method also optionally supports the request_token and work_group parameters:

conn = Athens::Connection.new(database: 'sample')
query = conn.execute("SELECT * FROM mytable", request_token: single_use_token, work_group: my_work_group)

Development

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.

If you want you can use Vagrant instead, there's already a Vagrantfile so a simple vagrant up should get you setup.

If you want to use Docker, grab a ruby image and boot into the console. Then install git and bash and you can run the bin/setup script from there:

docker run --rm -it -v $(pwd):/app -w /app ruby:2.7-alpine /bin/sh -c 'apk add bash git;/bin/bash'

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/getletterpress/athens. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the WTFPL License.

Code of Conduct

Everyone interacting in the Athens project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.