td 0.7.0 → 0.7.1

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.
data/ChangeLog CHANGED
@@ -1,9 +1,19 @@
1
1
 
2
+ == 2011-08-15 version 0.7.1
3
+
4
+ * Validate name of a database/table on create-database/create-log-table
5
+ subcommands
6
+ * Uses /v3/job/result?format=msgpack API to get result of a job
7
+ * -d, --database DB_NAME option is now required on query subcommand
8
+ * API server can be changed using TD_API_SERVER=HOST:PORT environment variable
9
+
10
+
2
11
  == 2011-08-06 version 0.7.0
3
12
 
4
13
  * import subcommand accepts UNIX time integer value on --json and --msgpack format
5
14
  * Renamed command name (trd -> td)
6
15
 
16
+
7
17
  == 2011-07-18 version 0.6.3
8
18
 
9
19
  * show-jobs: shows elapsed time
data/lib/td/api.rb CHANGED
@@ -99,7 +99,7 @@ class API
99
99
  end
100
100
 
101
101
  # => Job
102
- def query(q, db_name=nil)
102
+ def query(db_name, q)
103
103
  job_id = @iface.hive_query(q, db_name)
104
104
  Job.new(self, job_id, :hive, q) # TODO url
105
105
  end
@@ -108,27 +108,54 @@ class API
108
108
  def jobs(from=nil, to=nil)
109
109
  js = @iface.list_jobs(from, to)
110
110
  js.map {|job_id,type,status,query,start_at,end_at|
111
- Job.new(self, job_id, type, query, status, nil, nil, nil, start_at, end_at)
111
+ Job.new(self, job_id, type, query, status, nil, nil, start_at, end_at)
112
112
  }
113
113
  end
114
114
 
115
115
  # => Job
116
116
  def job(job_id)
117
117
  job_id = job_id.to_s
118
- type, query, status, result, url, debug, start_at, end_at = @iface.show_job(job_id)
119
- Job.new(self, job_id, type, query, status, url, result, debug, start_at, end_at)
118
+ type, query, status, url, debug, start_at, end_at = @iface.show_job(job_id)
119
+ Job.new(self, job_id, type, query, status, url, debug, start_at, end_at)
120
120
  end
121
121
 
122
- # => type:Symbol, result:String, url:String
122
+ # => type:Symbol, url:String
123
123
  def job_status(job_id)
124
- type, query, status, result, url, debug, start_at, end_at = @iface.show_job(job_id)
125
- return query, status, result, url, debug, start_at, end_at
124
+ type, query, status, url, debug, start_at, end_at = @iface.show_job(job_id)
125
+ return query, status, url, debug, start_at, end_at
126
+ end
127
+
128
+ # => result:[{column:String=>value:Object]
129
+ def job_result(job_id)
130
+ @iface.job_result(job_id)
131
+ end
132
+
133
+ # => nil
134
+ def job_result_each(job_id, &block)
135
+ @iface.job_result_each(job_id, &block)
126
136
  end
127
137
 
128
138
  # => time:Flaot
129
139
  def import(db_name, table_name, format, stream, stream_size=stream.lstat.size)
130
140
  @iface.import(db_name, table_name, format, stream, stream_size)
131
141
  end
142
+
143
+ def self.validate_database_name(name)
144
+ name = name.to_s
145
+ if name.empty?
146
+ raise "Empty name is not allowed"
147
+ end
148
+ if name.length < 3 || 32 < name.length
149
+ raise "Name must be 3 to 32 characters, got #{name.length} characters."
150
+ end
151
+ unless name =~ /^([a-z0-9_]+)$/
152
+ raise "Name must consist only of alphabets, numbers, '_'."
153
+ end
154
+ end
155
+
156
+ def self.validate_table_name(name)
157
+ validate_database_name(name)
158
+ end
132
159
  end
133
160
 
134
161
  end
@@ -216,17 +243,17 @@ class Table < APIObject
216
243
  end
217
244
 
218
245
  class Job < APIObject
219
- def initialize(api, job_id, type, query, status=nil, url=nil, result=nil, debug=nil, start_at=nil, end_at=nil)
246
+ def initialize(api, job_id, type, query, status=nil, url=nil, debug=nil, start_at=nil, end_at=nil, result=nil)
220
247
  super(api)
221
248
  @job_id = job_id
222
249
  @type = type
223
250
  @url = url
224
251
  @query = query
225
252
  @status = status
226
- @result = result
227
253
  @debug = debug
228
254
  @start_at = start_at
229
255
  @end_at = end_at
256
+ @result = result
230
257
  end
231
258
 
232
259
  attr_reader :job_id, :type
@@ -266,12 +293,20 @@ class Job < APIObject
266
293
  end
267
294
 
268
295
  def result
269
- return nil unless finished?
270
- update_status! unless @result
271
- @result.split("\n").map {|line|
272
- # TODO format of the result is TSV for now
273
- line.split("\t")
274
- }
296
+ unless @result
297
+ return nil unless finished?
298
+ @result = @api.job_result(@job_id)
299
+ end
300
+ @result
301
+ end
302
+
303
+ def result_each(&block)
304
+ if @result
305
+ @result.each(&block)
306
+ else
307
+ @api.job_result_each(&block)
308
+ end
309
+ nil
275
310
  end
276
311
 
277
312
  def finished?
@@ -287,11 +322,18 @@ class Job < APIObject
287
322
  !finished?
288
323
  end
289
324
 
325
+ def success?
326
+ @status == "success"
327
+ end
328
+
329
+ def error?
330
+ @status == "error"
331
+ end
332
+
290
333
  def update_status!
291
- query, status, result, url, debug, start_at, end_at = @api.job_status(@job_id)
334
+ query, status, url, debug, start_at, end_at = @api.job_status(@job_id)
292
335
  @query = query
293
336
  @status = status
294
- @result = result
295
337
  @url = url
296
338
  @debug = debug
297
339
  @start_at = start_at
data/lib/td/api_iface.rb CHANGED
@@ -141,12 +141,46 @@ class APIInterface
141
141
  type = (js['type'] || '?').to_sym # TODO
142
142
  query = js['query']
143
143
  status = js['status']
144
- result = js['result']
145
144
  debug = js['debug']
146
145
  url = js['url']
147
146
  start_at = js['start_at']
148
147
  end_at = js['end_at']
149
- return [type, query, status, result, url, debug, start_at, end_at]
148
+ return [type, query, status, url, debug, start_at, end_at]
149
+ end
150
+
151
+ def job_result(job_id)
152
+ require 'msgpack'
153
+ code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'})
154
+ if code != "200"
155
+ raise_error("Get job result failed", res)
156
+ end
157
+ result = []
158
+ MessagePack::Unpacker.new.feed_each(body) {|row|
159
+ result << row
160
+ }
161
+ return result
162
+ end
163
+
164
+ def job_result_each(job_id, &block)
165
+ # TODO chunked encoding
166
+ require 'msgpack'
167
+ code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>'msgpack'})
168
+ if code != "200"
169
+ raise_error("Get job result failed", res)
170
+ end
171
+ result = []
172
+ MessagePack::Unpacker.new.feed_each(body) {|row|
173
+ yield row
174
+ }
175
+ nil
176
+ end
177
+
178
+ def job_result_raw(job_id, format)
179
+ code, body, res = get("/v3/job/result/#{e job_id}", {'format'=>format})
180
+ if code != "200"
181
+ raise_error("Get job result failed", res)
182
+ end
183
+ return body
150
184
  end
151
185
 
152
186
  # => jobId:String
@@ -211,8 +245,16 @@ class APIInterface
211
245
  end
212
246
 
213
247
  private
214
- HOST = ENV['TD_API_SERVER'] || 'api.treasure-data.com'
215
- PORT = 80
248
+ host = 'api.treasure-data.com'
249
+ port = 80
250
+ if e = ENV['TD_API_SERVER']
251
+ host, port_ = e.split(':',2)
252
+ port_ = port_.to_i
253
+ port = port_ if port_ != 0
254
+ end
255
+
256
+ HOST = host
257
+ PORT = port
216
258
  USE_SSL = false
217
259
  BASE_URL = ''
218
260
 
@@ -9,6 +9,8 @@ module Command
9
9
  conf = cmd_config
10
10
  api = cmd_api(conf)
11
11
 
12
+ API.validate_database_name(db_name)
13
+
12
14
  begin
13
15
  api.create_database(db_name)
14
16
  rescue AlreadyExistsError
@@ -76,7 +78,6 @@ module Command
76
78
  alias show_dbs show_databases
77
79
  alias create_db create_database
78
80
  alias drop_db drop_database
79
-
80
81
  end
81
82
  end
82
83
 
@@ -8,7 +8,7 @@ module Command
8
8
  op.banner << "\noptions:\n"
9
9
 
10
10
  db_name = nil
11
- op.on('-d', '--database DB_NAME', 'use the database') {|s|
11
+ op.on('-d', '--database DB_NAME', 'use the database (required)') {|s|
12
12
  db_name = s
13
13
  }
14
14
 
@@ -22,11 +22,14 @@ module Command
22
22
  conf = cmd_config
23
23
  api = cmd_api(conf)
24
24
 
25
- if db_name
26
- find_database(api, db_name)
25
+ unless db_name
26
+ $stderr.puts "-d, --database DB_NAME option is required."
27
+ exit 1
27
28
  end
28
29
 
29
- job = api.query(sql, db_name)
30
+ find_database(api, db_name)
31
+
32
+ job = api.query(db_name, sql)
30
33
 
31
34
  $stderr.puts "Job #{job.job_id} is started."
32
35
  $stderr.puts "Use '#{$prog} job #{job.job_id}' to show the status."
@@ -36,7 +39,7 @@ module Command
36
39
  wait_job(job)
37
40
  puts "Status : #{job.status}"
38
41
  puts "Result :"
39
- puts cmd_render_table(job.result, :max_width=>10000)
42
+ puts render_result(job.result)
40
43
  end
41
44
  end
42
45
 
@@ -116,12 +119,12 @@ module Command
116
119
  if wait && !job.finished?
117
120
  wait_job(job)
118
121
  puts "Result :"
119
- puts cmd_render_table(job.result, :max_width=>10000)
122
+ puts render_result(job.result)
120
123
 
121
124
  else
122
125
  if job.finished?
123
126
  puts "Result :"
124
- puts cmd_render_table(job.result, :max_width=>10000)
127
+ puts render_result(job.result)
125
128
  end
126
129
 
127
130
  if verbose
@@ -162,6 +165,20 @@ module Command
162
165
  stderr_lines += stderr.size
163
166
  end
164
167
  end
168
+
169
+ def render_result(result)
170
+ require 'json'
171
+ rows = result.map {|row|
172
+ row.map {|v|
173
+ if v.is_a?(String)
174
+ v.to_s
175
+ else
176
+ v.to_json
177
+ end
178
+ }
179
+ }
180
+ puts cmd_render_table(rows, :max_width=>10000)
181
+ end
165
182
  end
166
183
  end
167
184
 
@@ -6,6 +6,8 @@ module Command
6
6
  conf = cmd_config
7
7
  api = cmd_api(conf)
8
8
 
9
+ API.validate_table_name(table_name)
10
+
9
11
  begin
10
12
  api.create_table(db_name, table_name, type)
11
13
  rescue NotFoundError
data/lib/td/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module TD
2
2
 
3
- VERSION = '0.7.0'
3
+ VERSION = '0.7.1'
4
4
 
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: td
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 1
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 0
10
- version: 0.7.0
9
+ - 1
10
+ version: 0.7.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sadayuki Furuhashi
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-06 00:00:00 +09:00
18
+ date: 2011-08-15 00:00:00 +09:00
19
19
  default_executable: td
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency