class Empire

Attributes

base_url[R]

Public Class Methods

new(app_key = nil, opts = {}) click to toggle source

app_key is your Empire application key, and is necessary for using the API opts can include any of:

* :api_server => the server to connect to (default: api.empiredata.com)
* :enduser => a string identifying the end user, required for any operations on views (default: nil)
* :secrets_yaml => the path to a YAML file generated by https://login.empiredata.co (default: nil)
# File lib/empire.rb, line 19
def initialize(app_key = nil, opts = {})
  api_server = opts[:api_server] || 'api.empiredata.co'

  @app_key = app_key
  @enduser = opts[:enduser]
  @session_key = nil

  @http_client = HTTPClient.new

  protocol = api_server.start_with?('localhost') ? 'http' : 'https'
  @base_url = "#{protocol}://#{api_server}/empire/"

  @service_secrets = nil
  if opts[:secrets_yaml]
    @service_secrets = YAML.load_file opts[:secrets_yaml]
  end
end

Public Instance Methods

connect(service, secrets = nil) click to toggle source

Connect to specific service service: service name secrets: hash with service secrets (optional if the Empire instance was initialized with a secrets_yaml)

# File lib/empire.rb, line 40
def connect(service, secrets = nil)
  path = "services/#{service}/connect"

  unless secrets
    unless @service_secrets
      raise Empire::MissingSecretsError.new
    end

    secrets = {}
    @service_secrets[service]['option'].each{|k, v| 
      secrets[k] = v['value']
    }
  end

  request path, :post, {}, secrets
end
describe(service = nil, table = nil) click to toggle source

Describe all services, all tables within a given service, or a given table

# File lib/empire.rb, line 58
def describe(service = nil, table = nil)
  path = 'services'
  if service and table
    path += "/#{service}/#{table}"
  elsif service and !table
    path += "/#{service}"
  elsif !service and table
    raise Empire::MissingServiceError.new("Service must be specified if table is specified")
  end

  request path
end
drop_view(name) click to toggle source

Delete a materialized view of SQL query

# File lib/empire.rb, line 106
def drop_view(name)
  unless @enduser
    raise Empire::MissingEnduserError.new
  end
  path = "view/#{name}"
  request path, :delete
end
insert(service, table, row) click to toggle source

Insert a new row into this service table. The row should be a hash of {column: value}

# File lib/empire.rb, line 90
def insert(service, table, row)
  path = "services/#{service}/#{table}"
  request path, :post, {}, row
end
inspect() click to toggle source

emulate default Object#inspect method but only display the object_id, not the properties to make things cleaner and more similar to Python client

# File lib/empire.rb, line 136
def inspect
  "#<Empire:#{(object_id << 1).to_s(16)}>"
end
materialize_view(name, sql) click to toggle source

Materialize a SQL query as a view. This creates or updates a view.

# File lib/empire.rb, line 96
def materialize_view(name, sql)
  unless @enduser
    raise Empire::MissingEnduserError.new
  end
  path = "view/#{name}"
  data = {'query' => sql}
  request path, :put, {}, data
end
print_query(sql) click to toggle source

Paginated printing of an SQL query

query(sql) { |l| ... } click to toggle source

Issue a SQL query, yielding each row

# File lib/empire.rb, line 81
def query(sql)
  path = 'query'
  io = request path, :post, {}, {query: sql}, stream: true
  io.each do |l|
    yield l
  end
end
view_materialized_at(name) click to toggle source

Datetime that this view was materialized at. nil if the materialization is currently pending.

# File lib/empire.rb, line 129
def view_materialized_at(name)
  status = view_status(name)
  Date.parse(status['materializedAt']) rescue nil
end
view_ready?(name) click to toggle source

Boolean check if a materialized view is ready for querying. @note The user is expected to check view_ready? before querying a view with query()

# File lib/empire.rb, line 116
def view_ready?(name)
  status = view_status(name)

  case status['viewStatus']
  when 'ready' then true
  when 'pending' then false
  else
    raise APIError.new("Unknown view status: #{response['viewStatus']}")
  end
end
walkthrough() click to toggle source

Run automatic test of all services from YAML

# File lib/walkthrough.rb, line 5
def walkthrough
  @last_service = nil
  @last_table = nil

  unless @service_secrets
    puts "Please connect some services in https://login.empiredata.co, and download the new yaml file"
    return 
  end

  @service_secrets.each do |secret|
    service = secret[0]
    walkthrough_service(service)
  end

  walkthrough_materialized_view(@last_service, @last_table)

  nil
end

Private Instance Methods

create_session() click to toggle source
# File lib/empire.rb, line 156
def create_session
  headers = {'Authorization' => "Empire appkey=\"#{@app_key}\""}
  session_url = "session/create"
  if @enduser
    session_url = session_url + "?enduser=#{@enduser}"
  end
  data = do_request session_url, :post, headers
  @sessionkey = data['sessionkey']
end
do_request(path, method = :get, headers = {}, data = {}, opts = {}) click to toggle source
# File lib/empire.rb, line 166
def do_request(path, method = :get, headers = {}, data = {}, opts = {})
  url = @base_url + path
  headers.merge!({'Content-Type' => 'application/json', 'Accept' => '*/*'})
  if opts[:stream]
    # return an IO object representing the streamed content
    conn = @http_client.request_async method, url, nil, data.to_json, headers
    conn.pop.content
  else
    # return the response body, parsed as JSON
    
    response = @http_client.request method, url, body: data.to_json, header: headers

    begin
      json = JSON.parse(response.body)
    rescue => e 
      raise Empire::APIError.new("#{e} #{response.body}")
    end

    if json["status"] != "OK"
      raise Empire::APIError.new(json["error"])
    end
    json
  end
end
print_row(row, max_length = 70) click to toggle source
request(path, method = :get, headers = {}, data = {}, opts = {}) click to toggle source
# File lib/empire.rb, line 150
def request(path, method = :get, headers = {}, data = {}, opts = {})
  create_session unless @sessionkey
  headers_with_session = headers.merge({'Authorization' => "Empire sessionkey=\"#{@sessionkey}\""})
  do_request path, method, headers_with_session, data, opts
end
view_status(name) click to toggle source
# File lib/empire.rb, line 142
def view_status(name)
  unless @enduser
    raise Empire::MissingEnduserError.new
  end
  path = "view/#{name}/status"
  request path, :get
end
walkthrough_materialized_view(service, table) click to toggle source
# File lib/walkthrough.rb, line 71
def walkthrough_materialized_view(service, table)
  unless @enduser
    puts "Please specify an enduser parameter when instantiating the client, so that you can try materialized views"
    return
  end

  puts "empire.materialize_view('view_name', 'SELECT * FROM #{service}.#{table} LIMIT 5')"
  materialize_view('view_name', "SELECT * FROM #{service}.#{table} LIMIT 5")

  puts "until empire.view_ready? 'view_name'\n  sleep 0.01\nend"
  until view_ready? 'view_name'
    sleep 0.01
  end

  puts "empire.query 'SELECT * FROM view_name'"
  query('SELECT * FROM view_name') do |row|
    print_row(row)
  end

  puts "empire.drop_view 'view_name'"
  drop_view 'view_name'
end
walkthrough_service(service) click to toggle source
# File lib/walkthrough.rb, line 26
def walkthrough_service(service)
  puts "empire.connect '#{service}'"
  begin
    connect service
  rescue
    puts "Problem connecting to #{service}"
    return
  end

  tables = describe service

  unless tables and tables['service'] and tables['service']['tables']
    puts "Can't find tables belonging to #{service}"
    return
  end

  tables['service']['tables'].each do |table_data|
    table = table_data['table']
    walkthrough_table(service, table)
  end

  @last_service = service
end
walkthrough_table(service, table) click to toggle source
# File lib/walkthrough.rb, line 50
def walkthrough_table(service, table)
  if service == "mailchimp"
    # These mailchimp tables can only be queried when filtering by a particular list.
    if ["list_member", "campaign", "campaign_sent_to", "campaign_opened"].include? table
      return
    end
  end

  begin
    sql = "SELECT * FROM #{service}.#{table} LIMIT 5"
    puts "empire.query '#{sql}'"
    query(sql) do |row|
      print_row(row)
    end
  rescue Exception => e
    puts "Problem with #{service}.#{table}"
  end

  @last_table = table
end