gcloud 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/AUTHENTICATION.md +3 -3
- data/CHANGELOG.md +12 -0
- data/OVERVIEW.md +30 -0
- data/lib/gcloud.rb +126 -9
- data/lib/gcloud/bigquery.rb +399 -0
- data/lib/gcloud/bigquery/connection.rb +592 -0
- data/lib/gcloud/bigquery/copy_job.rb +98 -0
- data/lib/gcloud/bigquery/credentials.rb +29 -0
- data/lib/gcloud/bigquery/data.rb +134 -0
- data/lib/gcloud/bigquery/dataset.rb +662 -0
- data/lib/gcloud/bigquery/dataset/list.rb +51 -0
- data/lib/gcloud/bigquery/errors.rb +62 -0
- data/lib/gcloud/bigquery/extract_job.rb +117 -0
- data/lib/gcloud/bigquery/insert_response.rb +80 -0
- data/lib/gcloud/bigquery/job.rb +283 -0
- data/lib/gcloud/bigquery/job/list.rb +55 -0
- data/lib/gcloud/bigquery/load_job.rb +199 -0
- data/lib/gcloud/bigquery/project.rb +512 -0
- data/lib/gcloud/bigquery/query_data.rb +135 -0
- data/lib/gcloud/bigquery/query_job.rb +151 -0
- data/lib/gcloud/bigquery/table.rb +827 -0
- data/lib/gcloud/bigquery/table/list.rb +55 -0
- data/lib/gcloud/bigquery/view.rb +419 -0
- data/lib/gcloud/credentials.rb +3 -3
- data/lib/gcloud/datastore.rb +15 -3
- data/lib/gcloud/datastore/credentials.rb +3 -2
- data/lib/gcloud/datastore/dataset.rb +5 -1
- data/lib/gcloud/datastore/transaction.rb +1 -1
- data/lib/gcloud/pubsub.rb +14 -3
- data/lib/gcloud/pubsub/credentials.rb +4 -4
- data/lib/gcloud/pubsub/project.rb +5 -1
- data/lib/gcloud/pubsub/topic.rb +5 -0
- data/lib/gcloud/storage.rb +14 -24
- data/lib/gcloud/storage/bucket.rb +10 -4
- data/lib/gcloud/storage/credentials.rb +3 -2
- data/lib/gcloud/storage/file.rb +8 -1
- data/lib/gcloud/storage/project.rb +5 -1
- data/lib/gcloud/upload.rb +54 -0
- data/lib/gcloud/version.rb +1 -1
- metadata +78 -2
@@ -0,0 +1,51 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Gcloud
|
17
|
+
module Bigquery
|
18
|
+
class Dataset
|
19
|
+
##
|
20
|
+
# Dataset::List is a special case Array with additional values.
|
21
|
+
class List < DelegateClass(::Array)
|
22
|
+
##
|
23
|
+
# If not empty, indicates that there are more records that match
|
24
|
+
# the request and this value should be passed to continue.
|
25
|
+
attr_accessor :token
|
26
|
+
|
27
|
+
# A hash of this page of results.
|
28
|
+
attr_accessor :etag
|
29
|
+
|
30
|
+
##
|
31
|
+
# Create a new Dataset::List with an array of datasets.
|
32
|
+
def initialize arr = []
|
33
|
+
super arr
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# New Dataset::List from a response object.
|
38
|
+
def self.from_resp resp, conn #:nodoc:
|
39
|
+
datasets = List.new(Array(resp.data["datasets"]).map do |gapi_object|
|
40
|
+
Dataset.from_gapi gapi_object, conn
|
41
|
+
end)
|
42
|
+
datasets.instance_eval do
|
43
|
+
@token = resp.data["nextPageToken"]
|
44
|
+
@etag = resp.data["etag"]
|
45
|
+
end
|
46
|
+
datasets
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Gcloud
|
17
|
+
module Bigquery
|
18
|
+
##
|
19
|
+
# Base BigQuery exception class.
|
20
|
+
class Error < Gcloud::Error
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Raised when an API call is not successful.
|
25
|
+
class ApiError < Error
|
26
|
+
##
|
27
|
+
# The code of the error.
|
28
|
+
attr_reader :code
|
29
|
+
|
30
|
+
##
|
31
|
+
# The errors encountered.
|
32
|
+
attr_reader :errors
|
33
|
+
|
34
|
+
def initialize message, code, errors = [] #:nodoc:
|
35
|
+
super message
|
36
|
+
@code = code
|
37
|
+
@errors = errors
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_response resp #:nodoc:
|
41
|
+
if resp.data? && resp.data["error"]
|
42
|
+
from_response_data resp.data["error"]
|
43
|
+
else
|
44
|
+
from_response_status resp
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.from_response_data error #:nodoc:
|
49
|
+
new error["message"], error["code"], error["errors"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.from_response_status resp #:nodoc:
|
53
|
+
if resp.status == 404
|
54
|
+
new "#{resp.error_message}: #{resp.request.uri.request_uri}",
|
55
|
+
resp.status
|
56
|
+
else
|
57
|
+
new resp.error_message, resp.status
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Gcloud
|
17
|
+
module Bigquery
|
18
|
+
##
|
19
|
+
# = ExtractJob
|
20
|
+
#
|
21
|
+
# A Job subclass representing an export operation that may be performed
|
22
|
+
# on a Table. A ExtractJob instance is created when you call Table#extract.
|
23
|
+
#
|
24
|
+
# See {Exporting Data From
|
25
|
+
# BigQuery}[https://cloud.google.com/bigquery/exporting-data-from-bigquery]
|
26
|
+
# and the {Jobs API
|
27
|
+
# reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs]
|
28
|
+
# for details.
|
29
|
+
#
|
30
|
+
class ExtractJob < Job
|
31
|
+
##
|
32
|
+
# The URI or URIs representing the Google Cloud Storage files to which
|
33
|
+
# the data is exported.
|
34
|
+
def destinations
|
35
|
+
Array config["extract"]["destinationUris"]
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# The table from which the data is exported. This is the table upon
|
40
|
+
# which Table#extract was called. Returns a Table instance.
|
41
|
+
def source
|
42
|
+
table = config["extract"]["sourceTable"]
|
43
|
+
return nil unless table
|
44
|
+
retrieve_table table["projectId"],
|
45
|
+
table["datasetId"],
|
46
|
+
table["tableId"]
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Checks if the export operation compresses the data using gzip. The
|
51
|
+
# default is +false+.
|
52
|
+
def compression?
|
53
|
+
val = config["extract"]["compression"]
|
54
|
+
val == "GZIP"
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Checks if the destination format for the data is {newline-delimited
|
59
|
+
# JSON}[http://jsonlines.org/]. The default is +false+.
|
60
|
+
def json?
|
61
|
+
val = config["extract"]["destinationFormat"]
|
62
|
+
val == "NEWLINE_DELIMITED_JSON"
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Checks if the destination format for the data is CSV. Tables with nested
|
67
|
+
# or repeated fields cannot be exported as CSV. The default is +true+.
|
68
|
+
def csv?
|
69
|
+
val = config["extract"]["destinationFormat"]
|
70
|
+
return true if val.nil?
|
71
|
+
val == "CSV"
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Checks if the destination format for the data is
|
76
|
+
# {Avro}[http://avro.apache.org/]. The default is +false+.
|
77
|
+
def avro?
|
78
|
+
val = config["extract"]["destinationFormat"]
|
79
|
+
val == "AVRO"
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# The symbol the operation uses to delimit fields in the exported data.
|
84
|
+
# The default is a comma (,).
|
85
|
+
def delimiter
|
86
|
+
val = config["extract"]["fieldDelimiter"]
|
87
|
+
val = "," if val.nil?
|
88
|
+
val
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Checks if the exported data contains a header row. The default is
|
93
|
+
# +true+.
|
94
|
+
def print_header?
|
95
|
+
val = config["extract"]["printHeader"]
|
96
|
+
val = true if val.nil?
|
97
|
+
val
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# The count of files per destination URI or URI pattern specified in
|
102
|
+
# #destinations. Returns an Array of values in the same order as the URI
|
103
|
+
# patterns.
|
104
|
+
def destinations_file_counts
|
105
|
+
Array stats["extract"]["destinationUriFileCounts"]
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# The count of files per destination URI or URI pattern specified in
|
110
|
+
# #destinations. Returns a Hash with the URI patterns as keys and the
|
111
|
+
# counts as values.
|
112
|
+
def destinations_counts
|
113
|
+
Hash[destinations.zip destinations_file_counts]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Gcloud
|
17
|
+
module Bigquery
|
18
|
+
##
|
19
|
+
# InsertResponse
|
20
|
+
class InsertResponse
|
21
|
+
def initialize rows, gapi #:nodoc:
|
22
|
+
@rows = rows
|
23
|
+
@gapi = gapi
|
24
|
+
end
|
25
|
+
|
26
|
+
def success?
|
27
|
+
error_count.zero?
|
28
|
+
end
|
29
|
+
|
30
|
+
def insert_count
|
31
|
+
@insert_count ||= @rows.count - error_count
|
32
|
+
end
|
33
|
+
|
34
|
+
def error_count
|
35
|
+
@error_count ||= Array(@gapi["insertErrors"]).count
|
36
|
+
end
|
37
|
+
|
38
|
+
def insert_errors
|
39
|
+
@insert_errors ||= begin
|
40
|
+
Array(@gapi["insertErrors"]).map do |ie|
|
41
|
+
row = @rows[ie["index"]]
|
42
|
+
errors = ie["errors"]
|
43
|
+
InsertError.new row, errors
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def error_rows
|
49
|
+
@error_rows ||= begin
|
50
|
+
Array(@gapi["insertErrors"]).map do |ie|
|
51
|
+
@rows[ie["index"]]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def errors_for row
|
57
|
+
ie = insert_errors.detect { |e| e.row == row }
|
58
|
+
return ie.errors if ie
|
59
|
+
[]
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.from_gapi rows, gapi #:nodoc:
|
63
|
+
gapi = gapi.to_hash if gapi.respond_to? :to_hash
|
64
|
+
new rows, gapi
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# InsertError
|
69
|
+
class InsertError
|
70
|
+
attr_reader :row
|
71
|
+
attr_reader :errors
|
72
|
+
|
73
|
+
def initialize row, errors #:nodoc:
|
74
|
+
@row = row
|
75
|
+
@errors = errors
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2015 Google Inc. All rights reserved.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require "gcloud/bigquery/query_data"
|
17
|
+
require "gcloud/bigquery/job/list"
|
18
|
+
require "gcloud/bigquery/errors"
|
19
|
+
|
20
|
+
module Gcloud
|
21
|
+
module Bigquery
|
22
|
+
##
|
23
|
+
# = Job
|
24
|
+
#
|
25
|
+
# Represents a generic Job that may be performed on a Table.
|
26
|
+
#
|
27
|
+
# See {Managing Jobs, Datasets, and Projects
|
28
|
+
# }[https://cloud.google.com/bigquery/docs/managing_jobs_datasets_projects]
|
29
|
+
# for an overview of BigQuery jobs, and the {Jobs API
|
30
|
+
# reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs]
|
31
|
+
# for details.
|
32
|
+
#
|
33
|
+
# The subclasses of Job represent the specific BigQuery job types: CopyJob,
|
34
|
+
# ExtractJob, LoadJob, and QueryJob.
|
35
|
+
#
|
36
|
+
# A job instance is created when you call Project#query_job,
|
37
|
+
# Dataset#query_job, Table#copy, Table#extract, Table#load, or View#data.
|
38
|
+
#
|
39
|
+
# require "gcloud"
|
40
|
+
#
|
41
|
+
# gcloud = Gcloud.new
|
42
|
+
# bigquery = gcloud.bigquery
|
43
|
+
#
|
44
|
+
# q = "SELECT COUNT(word) as count FROM publicdata:samples.shakespeare"
|
45
|
+
# job = bigquery.query_job q
|
46
|
+
#
|
47
|
+
# loop do
|
48
|
+
# break if job.done?
|
49
|
+
# sleep 1
|
50
|
+
# job.refresh!
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# if job.failed?
|
54
|
+
# puts job.error
|
55
|
+
# else
|
56
|
+
# puts job.query_results.first
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
class Job
|
60
|
+
##
|
61
|
+
# The Connection object.
|
62
|
+
attr_accessor :connection #:nodoc:
|
63
|
+
|
64
|
+
##
|
65
|
+
# The Google API Client object.
|
66
|
+
attr_accessor :gapi #:nodoc:
|
67
|
+
|
68
|
+
##
|
69
|
+
# Create an empty Job object.
|
70
|
+
def initialize #:nodoc:
|
71
|
+
@connection = nil
|
72
|
+
@gapi = {}
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# The ID of the job.
|
77
|
+
def job_id
|
78
|
+
@gapi["jobReference"]["jobId"]
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# The ID of the project containing the job.
|
83
|
+
def project_id
|
84
|
+
@gapi["jobReference"]["projectId"]
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# The current state of the job. The possible values are +PENDING+,
|
89
|
+
# +RUNNING+, and +DONE+. A +DONE+ state does not mean that the job
|
90
|
+
# completed successfully. Use #failed? to discover if an error occurred
|
91
|
+
# or if the job was successful.
|
92
|
+
def state
|
93
|
+
return nil if @gapi["status"].nil?
|
94
|
+
@gapi["status"]["state"]
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Checks if the job's state is +RUNNING+.
|
99
|
+
def running?
|
100
|
+
return false if state.nil?
|
101
|
+
"running".casecmp(state).zero?
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Checks if the job's state is +PENDING+.
|
106
|
+
def pending?
|
107
|
+
return false if state.nil?
|
108
|
+
"pending".casecmp(state).zero?
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Checks if the job's state is +DONE+. When +true+, the job has stopped
|
113
|
+
# running. However, a +DONE+ state does not mean that the job completed
|
114
|
+
# successfully. Use #failed? to detect if an error occurred or if the
|
115
|
+
# job was successful.
|
116
|
+
def done?
|
117
|
+
return false if state.nil?
|
118
|
+
"done".casecmp(state).zero?
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Checks if an error is present.
|
123
|
+
def failed?
|
124
|
+
!error.nil?
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# The time when the job was created.
|
129
|
+
def created_at
|
130
|
+
return nil if @gapi["statistics"].nil?
|
131
|
+
return nil if @gapi["statistics"]["creationTime"].nil?
|
132
|
+
Time.at(@gapi["statistics"]["creationTime"] / 1000.0)
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# The time when the job was started.
|
137
|
+
# This field is present after the job's state changes from +PENDING+
|
138
|
+
# to either +RUNNING+ or +DONE+.
|
139
|
+
def started_at
|
140
|
+
return nil if @gapi["statistics"].nil?
|
141
|
+
return nil if @gapi["statistics"]["startTime"].nil?
|
142
|
+
Time.at(@gapi["statistics"]["startTime"] / 1000.0)
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# The time when the job ended.
|
147
|
+
# This field is present when the job's state is +DONE+.
|
148
|
+
def ended_at
|
149
|
+
return nil if @gapi["statistics"].nil?
|
150
|
+
return nil if @gapi["statistics"]["endTime"].nil?
|
151
|
+
Time.at(@gapi["statistics"]["endTime"] / 1000.0)
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# The configuration for the job. Returns a hash. See the {Jobs API
|
156
|
+
# reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs].
|
157
|
+
def configuration
|
158
|
+
hash = @gapi["configuration"] || {}
|
159
|
+
hash = hash.to_hash if hash.respond_to? :to_hash
|
160
|
+
hash
|
161
|
+
end
|
162
|
+
alias_method :config, :configuration
|
163
|
+
|
164
|
+
##
|
165
|
+
# The statistics for the job. Returns a hash. See the {Jobs API
|
166
|
+
# reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs].
|
167
|
+
def statistics
|
168
|
+
hash = @gapi["statistics"] || {}
|
169
|
+
hash = hash.to_hash if hash.respond_to? :to_hash
|
170
|
+
hash
|
171
|
+
end
|
172
|
+
alias_method :stats, :statistics
|
173
|
+
|
174
|
+
##
|
175
|
+
# The job's status. Returns a hash. The values contained in the hash are
|
176
|
+
# also exposed by #state, #error, and #errors.
|
177
|
+
def status
|
178
|
+
hash = @gapi["status"] || {}
|
179
|
+
hash = hash.to_hash if hash.respond_to? :to_hash
|
180
|
+
hash
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# The last error for the job, if any errors have occurred. Returns a
|
185
|
+
# hash. See the {Jobs API
|
186
|
+
# reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs].
|
187
|
+
#
|
188
|
+
# === Returns
|
189
|
+
#
|
190
|
+
# +Hash+
|
191
|
+
#
|
192
|
+
# {
|
193
|
+
# "reason"=>"notFound",
|
194
|
+
# "message"=>"Not found: Table publicdata:samples.BAD_ID"
|
195
|
+
# }
|
196
|
+
#
|
197
|
+
def error
|
198
|
+
status["errorResult"]
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# The errors for the job, if any errors have occurred. Returns an array
|
203
|
+
# of hash objects. See #error.
|
204
|
+
def errors
|
205
|
+
Array status["errors"]
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Created a new job with the current configuration.
|
210
|
+
def rerun!
|
211
|
+
ensure_connection!
|
212
|
+
resp = connection.insert_job configuration
|
213
|
+
if resp.success?
|
214
|
+
Job.from_gapi resp.data, connection
|
215
|
+
else
|
216
|
+
fail ApiError.from_response(resp)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Reloads the job with current data from the BigQuery service.
|
222
|
+
def refresh!
|
223
|
+
ensure_connection!
|
224
|
+
resp = connection.get_job job_id
|
225
|
+
if resp.success?
|
226
|
+
@gapi = resp.data
|
227
|
+
else
|
228
|
+
fail ApiError.from_response(resp)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# New Job from a Google API Client object.
|
234
|
+
def self.from_gapi gapi, conn #:nodoc:
|
235
|
+
klass = klass_for gapi
|
236
|
+
klass.new.tap do |f|
|
237
|
+
f.gapi = gapi
|
238
|
+
f.connection = conn
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
protected
|
243
|
+
|
244
|
+
##
|
245
|
+
# Raise an error unless an active connection is available.
|
246
|
+
def ensure_connection!
|
247
|
+
fail "Must have active connection" unless connection
|
248
|
+
end
|
249
|
+
|
250
|
+
##
|
251
|
+
# Get the subclass for a job type
|
252
|
+
def self.klass_for gapi
|
253
|
+
if gapi["configuration"]["copy"]
|
254
|
+
return CopyJob
|
255
|
+
elsif gapi["configuration"]["extract"]
|
256
|
+
return ExtractJob
|
257
|
+
elsif gapi["configuration"]["load"]
|
258
|
+
return LoadJob
|
259
|
+
elsif gapi["configuration"]["query"]
|
260
|
+
return QueryJob
|
261
|
+
end
|
262
|
+
Job
|
263
|
+
end
|
264
|
+
|
265
|
+
def retrieve_table project_id, dataset_id, table_id
|
266
|
+
ensure_connection!
|
267
|
+
resp = connection.get_project_table project_id, dataset_id, table_id
|
268
|
+
if resp.success?
|
269
|
+
Table.from_gapi resp.data, connection
|
270
|
+
else
|
271
|
+
return nil if resp.status == 404
|
272
|
+
fail ApiError.from_response(resp)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# We need Job to be defined before loading these.
|
280
|
+
require "gcloud/bigquery/copy_job"
|
281
|
+
require "gcloud/bigquery/extract_job"
|
282
|
+
require "gcloud/bigquery/load_job"
|
283
|
+
require "gcloud/bigquery/query_job"
|