empire-client 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/empire.rb +178 -0
  3. data/lib/walkthrough.rb +101 -0
  4. metadata +104 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 528dc8d235093675e0f22b738a0f16d8e7134e09
4
+ data.tar.gz: c6b479ff28bef1e9f7ad0a9d219923b3e3a4078b
5
+ SHA512:
6
+ metadata.gz: 0534ce3f0f14d9525eecbd921a7f6e9d1b51e378d6ffc39f5f67b0f841b1c376cb130116928a0ab41843c97da7aab69b2f69e080cce88502fca147029c2ff498
7
+ data.tar.gz: 5948cc3f5ee664f930b4586a9cd21231ffc2e1806a5c0e4ea084c8c2835c0792371493b574c1f750b65794960e719c5afa012261ec818fd7485990b21f689854
data/lib/empire.rb ADDED
@@ -0,0 +1,178 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'date'
4
+
5
+ require 'httpclient'
6
+ require 'irb-pager'
7
+
8
+ require_relative 'walkthrough.rb'
9
+
10
+ class Empire
11
+ attr_reader :base_url
12
+
13
+ # app_key is your Empire application key, and is necessary for using the API
14
+ # opts can include any of:
15
+ # * :api_server => the server to connect to (default: api.empiredata.com)
16
+ # * :end_user => a string identifying the end user, required for any operations on views (default: nil)
17
+ # * :secrets_yaml => the path to a YAML file generated by https://login.empiredata.co (default: nil)
18
+ def initialize(app_key = nil, opts = {})
19
+ api_server = opts[:api_server] || 'api.empiredata.co'
20
+
21
+ @app_key = app_key
22
+ @end_user = opts[:end_user]
23
+ @session_key = nil
24
+
25
+ @http_client = HTTPClient.new
26
+
27
+ protocol = api_server.start_with?('localhost') ? 'http' : 'https'
28
+ @base_url = "#{protocol}://#{api_server}/empire/"
29
+
30
+ @service_secrets = nil
31
+ if opts[:secrets_yaml]
32
+ @service_secrets = YAML.load_file opts[:secrets_yaml]
33
+ end
34
+ end
35
+
36
+ # Connect to specific service
37
+ # service: service name
38
+ # secrets: hash with service secrets (optional if the Empire instance was initialized with a secrets_yaml)
39
+ def connect(service, secrets = nil)
40
+ path = "services/#{service}/connect"
41
+ unless secrets
42
+ unless @service_secrets
43
+ raise "secrets must be provided on connect command,
44
+ or secrets_yaml file must be given when constructing this instance"
45
+ end
46
+
47
+ secrets = {}
48
+ @service_secrets[service]['option'].each{|k, v| secrets[k] = v['value']}
49
+ end
50
+ request path, :post, {}, secrets
51
+ end
52
+
53
+ # Describe all services, all tables within a given service, or a given table
54
+ def describe(service = nil, table = nil)
55
+ path = 'services'
56
+ if service and table
57
+ path += "/#{service}/#{table}"
58
+ elsif service and !table
59
+ path += "/#{service}"
60
+ elsif !service and table
61
+ raise "Service must be specified if table is specified"
62
+ end
63
+
64
+ request path
65
+ end
66
+
67
+ # Paginated printing of an SQL query
68
+ def print_query(sql)
69
+ IRB::Pager.pager {
70
+ query(sql) do |l|
71
+ puts l
72
+ end
73
+ }
74
+ end
75
+
76
+ # Issue a SQL query, yielding each row
77
+ def query(sql)
78
+ path = 'query'
79
+ io = request path, :post, {}, {query: sql}, stream: true
80
+ io.each do |l|
81
+ yield l
82
+ end
83
+ end
84
+
85
+ # Insert a new row into this service table. The row should be a hash of {column: value}
86
+ def insert(service, table, row)
87
+ path = "services/#{service}/#{table}"
88
+ request path, :post, {}, row
89
+ end
90
+
91
+ # Materialize a SQL query as a view. This creates or updates a view.
92
+ def materialize_view(name, sql)
93
+ unless @end_user
94
+ raise "Cannot use materialized view within a session initiated without an enduser"
95
+ end
96
+ path = "view/#{name}"
97
+ data = {'query' => sql}
98
+ request path, :put, {}, data
99
+ end
100
+
101
+ # Delete a materialized view of SQL query
102
+ def drop_view(name)
103
+ unless @end_user
104
+ raise "Cannot use materialized view within a session initiated without an enduser"
105
+ end
106
+ path = "view/#{name}"
107
+ request path, :delete
108
+ end
109
+
110
+ # Boolean check if a materialized view is ready for querying.
111
+ # @note The user is expected to check view_ready? before querying a view with query()
112
+ def view_ready?(name)
113
+ status = view_status(name)
114
+
115
+ case status['viewStatus']
116
+ when 'ready' then true
117
+ when 'pending' then false
118
+ else
119
+ raise "Unknown view status: #{response['viewStatus']}"
120
+ end
121
+ end
122
+
123
+ # Datetime that this view was materialized at.
124
+ # nil if the materialization is currently pending.
125
+ def view_materialized_at(name)
126
+ status = view_status(name)
127
+ Date.parse(status['materializedAt']) rescue nil
128
+ end
129
+
130
+ # emulate default Object#inspect method but only display the object_id, not the properties
131
+ # to make things cleaner and more similar to Python client
132
+ def inspect
133
+ "#<Empire:#{(object_id << 1).to_s(16)}>"
134
+ end
135
+
136
+ private
137
+
138
+ def view_status(name)
139
+ unless @end_user
140
+ raise "Cannot use materialized view within a session initiated without an enduser"
141
+ end
142
+ path = "view/#{name}/status"
143
+ request path, :get
144
+ end
145
+
146
+ def request(path, method = :get, headers = {}, data = {}, opts = {})
147
+ create_session unless @sessionkey
148
+ headers_with_session = headers.merge({'Authorization' => "Empire sessionkey=\"#{@sessionkey}\""})
149
+ do_request path, method, headers_with_session, data, opts
150
+ end
151
+
152
+ def create_session
153
+ headers = {'Authorization' => "Empire appkey=\"#{@app_key}\""}
154
+ session_url = "session/create"
155
+ if @end_user
156
+ session_url = session_url + "?enduser=#{@end_user}"
157
+ end
158
+ data = do_request session_url, :post, headers
159
+ @sessionkey = data['sessionkey']
160
+ end
161
+
162
+ def do_request(path, method = :get, headers = {}, data = {}, opts = {})
163
+ url = @base_url + path
164
+ headers.merge!({'Content-Type' => 'application/json', 'Accept' => '*/*'})
165
+ if opts[:stream]
166
+ # return an IO object representing the streamed content
167
+ conn = @http_client.request_async method, url, nil, data.to_json, headers
168
+ conn.pop.content
169
+ else
170
+ # return the response body
171
+ response = @http_client.request method, url, body: data.to_json, header: headers
172
+ if response.status == HTTP::Status::INTERNAL
173
+ raise "Internal Server Error"
174
+ end
175
+ JSON.parse(response.body)
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,101 @@
1
+
2
+ class Empire
3
+
4
+ # Run automatic test of all services from YAML
5
+ def walkthrough
6
+ @last_service = nil
7
+ @last_table = nil
8
+
9
+ unless @service_secrets
10
+ puts "Please connect some services in https://login.empiredata.co, and download the new yaml file"
11
+ return
12
+ end
13
+
14
+ @service_secrets.each do |secret|
15
+ service = secret[0]
16
+ walkthrough_service(service)
17
+ end
18
+
19
+ walkthrough_materialized_view(@last_service, @last_table)
20
+
21
+ nil
22
+ end
23
+
24
+ private
25
+
26
+ def walkthrough_service(service)
27
+ puts "empire.connect '#{service}'"
28
+ begin
29
+ connect service
30
+ rescue
31
+ puts "Problem connecting to #{service}"
32
+ return
33
+ end
34
+
35
+ tables = describe service
36
+
37
+ unless tables and tables['service'] and tables['service']['tables']
38
+ puts "Can't find tables belonging to #{service}"
39
+ return
40
+ end
41
+
42
+ tables['service']['tables'].each do |table_data|
43
+ table = table_data['table']
44
+ walkthrough_table(service, table)
45
+ end
46
+
47
+ @last_service = service
48
+ end
49
+
50
+ def walkthrough_table(service, table)
51
+ if service == "mailchimp"
52
+ # These mailchimp tables can only be queried when filtering by a particular list.
53
+ if ["list_member", "campaign", "campaign_sent_to", "campaign_opened"].include? table
54
+ return
55
+ end
56
+ end
57
+
58
+ begin
59
+ sql = "SELECT * FROM #{service}.#{table} LIMIT 5"
60
+ puts "empire.query '#{sql}'"
61
+ query(sql) do |row|
62
+ print_row(row, 75)
63
+ end
64
+ rescue Exception => e
65
+ puts "Problem with #{service}.#{table}"
66
+ end
67
+
68
+ @last_table = table
69
+ end
70
+
71
+ def walkthrough_materialized_view(service, table)
72
+ unless @end_user
73
+ puts "Please specify an end_user parameter when instantiating the client, so that you can try materialized views"
74
+ return
75
+ end
76
+
77
+ puts "empire.materialize_view('view_name', 'SELECT * FROM #{service}.#{table} LIMIT 5')"
78
+ materialize_view('view_name', "SELECT * FROM #{service}.#{table} LIMIT 5")
79
+
80
+ puts "until empire.view_ready? 'view_name'\n sleep 0.1\nend"
81
+ until view_ready? 'view_name'
82
+ sleep 0.01
83
+ end
84
+
85
+ puts "empire.query 'SELECT * FROM view_name'"
86
+ query('SELECT * FROM view_name') do |row|
87
+ print_row(row, 75)
88
+ end
89
+
90
+ puts "empire.drop_view 'view_name'"
91
+ drop_view 'view_name'
92
+ end
93
+
94
+ def print_row(row, max_length)
95
+ fragment = row.slice(0, max_length)
96
+ if fragment.length == max_length
97
+ fragment = fragment + "..."
98
+ end
99
+ puts " #{fragment}"
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: empire-client
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ platform: ruby
6
+ authors:
7
+ - UPSHOT Data, Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpclient
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: irb-pager
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.18'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.18'
69
+ description: Empire is an API for accessing enterprise SaaS services such as Salesforce,
70
+ Zendesk, Google Apps, etc. It provides a uniform, database-like interface to every
71
+ service that it supports. Empire makes it easy to integrate data from multiple enterprise
72
+ services into your own enterprise app.
73
+ email: hello@empiredata.co
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - lib/empire.rb
79
+ - lib/walkthrough.rb
80
+ homepage: http://empiredata.co
81
+ licenses:
82
+ - Apache License, Version 2.0
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.9.3
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.3.0
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Ruby client for the Empire API
104
+ test_files: []