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,98 @@
|
|
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
|
+
# = CopyJob
|
20
|
+
#
|
21
|
+
# A Job subclass representing a copy operation that may be performed on a
|
22
|
+
# Table. A CopyJob instance is created when you call Table#copy.
|
23
|
+
#
|
24
|
+
# See {Copying an Existing
|
25
|
+
# Table}[https://cloud.google.com/bigquery/docs/tables#copyingtable]
|
26
|
+
# and the {Jobs API
|
27
|
+
# reference}[https://cloud.google.com/bigquery/docs/reference/v2/jobs]
|
28
|
+
# for details.
|
29
|
+
#
|
30
|
+
class CopyJob < Job
|
31
|
+
##
|
32
|
+
# The table from which data is copied. This is the table on
|
33
|
+
# which Table#copy was called. Returns a Table instance.
|
34
|
+
def source
|
35
|
+
table = config["copy"]["sourceTable"]
|
36
|
+
return nil unless table
|
37
|
+
retrieve_table table["projectId"],
|
38
|
+
table["datasetId"],
|
39
|
+
table["tableId"]
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# The table to which data is copied. Returns a Table instance.
|
44
|
+
def destination
|
45
|
+
table = config["copy"]["destinationTable"]
|
46
|
+
return nil unless table
|
47
|
+
retrieve_table table["projectId"],
|
48
|
+
table["datasetId"],
|
49
|
+
table["tableId"]
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Checks if the create disposition for the job is +CREATE_IF_NEEDED+,
|
54
|
+
# which provides the following behavior: If the table does not exist,
|
55
|
+
# the copy operation creates the table. This is the default.
|
56
|
+
def create_if_needed?
|
57
|
+
disp = config["copy"]["createDisposition"]
|
58
|
+
disp == "CREATE_IF_NEEDED"
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Checks if the create disposition for the job is +CREATE_NEVER+, which
|
63
|
+
# provides the following behavior: The table must already exist; if it
|
64
|
+
# does not, an error is returned in the job result.
|
65
|
+
def create_never?
|
66
|
+
disp = config["copy"]["createDisposition"]
|
67
|
+
disp == "CREATE_NEVER"
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Checks if the write disposition for the job is +WRITE_TRUNCATE+, which
|
72
|
+
# provides the following behavior: If the table already exists, the copy
|
73
|
+
# operation overwrites the table data.
|
74
|
+
def write_truncate?
|
75
|
+
disp = config["copy"]["writeDisposition"]
|
76
|
+
disp == "WRITE_TRUNCATE"
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Checks if the write disposition for the job is +WRITE_APPEND+, which
|
81
|
+
# provides the following behavior: If the table already exists, the copy
|
82
|
+
# operation appends the data to the table.
|
83
|
+
def write_append?
|
84
|
+
disp = config["copy"]["writeDisposition"]
|
85
|
+
disp == "WRITE_APPEND"
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Checks if the write disposition for the job is +WRITE_EMPTY+, which
|
90
|
+
# provides the following behavior: If the table already exists and
|
91
|
+
# contains data, the job will have an error. This is the default.
|
92
|
+
def write_empty?
|
93
|
+
disp = config["copy"]["writeDisposition"]
|
94
|
+
disp == "WRITE_EMPTY"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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/credentials"
|
17
|
+
|
18
|
+
module Gcloud
|
19
|
+
module Bigquery
|
20
|
+
##
|
21
|
+
# Represents the Oauth2 signing logic for Bigquery.
|
22
|
+
class Credentials < Gcloud::Credentials #:nodoc:
|
23
|
+
SCOPE = ["https://www.googleapis.com/auth/bigquery"]
|
24
|
+
PATH_ENV_VARS = %w(BIGQUERY_KEYFILE GCLOUD_KEYFILE GOOGLE_CLOUD_KEYFILE)
|
25
|
+
JSON_ENV_VARS = %w(BIGQUERY_KEYFILE_JSON GCLOUD_KEYFILE_JSON
|
26
|
+
GOOGLE_CLOUD_KEYFILE_JSON)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,134 @@
|
|
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
|
+
# = Data
|
20
|
+
#
|
21
|
+
# Represents Table Data as a list of name/value pairs.
|
22
|
+
# Also contains metadata such as +etag+ and +total+.
|
23
|
+
class Data < DelegateClass(::Array)
|
24
|
+
##
|
25
|
+
# The Table object the data belongs to.
|
26
|
+
attr_accessor :table #:nodoc:
|
27
|
+
|
28
|
+
##
|
29
|
+
# The Google API Client object.
|
30
|
+
attr_accessor :gapi #:nodoc:
|
31
|
+
|
32
|
+
def initialize arr = [] #:nodoc:
|
33
|
+
@table = nil
|
34
|
+
@gapi = {}
|
35
|
+
super arr
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# The resource type of the API response.
|
40
|
+
def kind
|
41
|
+
@gapi["kind"]
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# A token used for paging results.
|
46
|
+
def token
|
47
|
+
@gapi["pageToken"]
|
48
|
+
end
|
49
|
+
|
50
|
+
# A hash of this page of results.
|
51
|
+
def etag
|
52
|
+
@gapi["etag"]
|
53
|
+
end
|
54
|
+
|
55
|
+
# The total number of rows in the complete table.
|
56
|
+
def total
|
57
|
+
@gapi["totalRows"]
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Is there a next page of data?
|
62
|
+
def next?
|
63
|
+
!token.nil?
|
64
|
+
end
|
65
|
+
|
66
|
+
def next
|
67
|
+
return nil unless next?
|
68
|
+
ensure_table!
|
69
|
+
table.data token: token
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Represents Table Data as a list of positional values (array of arrays).
|
74
|
+
# No type conversion is made, e.g. numbers are formatted as strings.
|
75
|
+
def raw
|
76
|
+
Array(gapi["rows"]).map { |row| row["f"].map { |f| f["v"] } }
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# New Data from a response object.
|
81
|
+
def self.from_response resp, table #:nodoc:
|
82
|
+
formatted_rows = format_rows resp.data["rows"], table.fields
|
83
|
+
|
84
|
+
data = new formatted_rows
|
85
|
+
data.table = table
|
86
|
+
data.gapi = resp.data
|
87
|
+
data
|
88
|
+
end
|
89
|
+
|
90
|
+
# rubocop:disable all
|
91
|
+
# Disabled rubocop because this implementation will not last.
|
92
|
+
|
93
|
+
def self.format_rows rows, fields
|
94
|
+
headers = fields.map { |f| f["name"] }
|
95
|
+
field_types = fields.map { |f| f["type"] }
|
96
|
+
|
97
|
+
Array(rows).map do |row|
|
98
|
+
values = row["f"].map { |f| f["v"] }
|
99
|
+
formatted_values = format_values field_types, values
|
100
|
+
Hash[headers.zip formatted_values]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.format_values field_types, values
|
105
|
+
field_types.zip(values).map do |type, value|
|
106
|
+
begin
|
107
|
+
if value.nil?
|
108
|
+
nil
|
109
|
+
elsif type == "INTEGER"
|
110
|
+
Integer value
|
111
|
+
elsif type == "FLOAT"
|
112
|
+
Float value
|
113
|
+
elsif type == "BOOLEAN"
|
114
|
+
(value == "true" ? true : (value == "false" ? false : nil))
|
115
|
+
else
|
116
|
+
value
|
117
|
+
end
|
118
|
+
rescue
|
119
|
+
value
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
# rubocop:enable all
|
124
|
+
|
125
|
+
protected
|
126
|
+
|
127
|
+
##
|
128
|
+
# Raise an error unless an active connection is available.
|
129
|
+
def ensure_table!
|
130
|
+
fail "Must have active connection" unless table
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,662 @@
|
|
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 "json"
|
17
|
+
require "gcloud/bigquery/errors"
|
18
|
+
require "gcloud/bigquery/table"
|
19
|
+
require "gcloud/bigquery/dataset/list"
|
20
|
+
|
21
|
+
module Gcloud
|
22
|
+
module Bigquery
|
23
|
+
##
|
24
|
+
# = Dataset
|
25
|
+
#
|
26
|
+
# Represents a Dataset. A dataset is a grouping mechanism that holds zero or
|
27
|
+
# more tables. Datasets are the lowest level unit of access control; you
|
28
|
+
# cannot control access at the table level. A dataset is contained within a
|
29
|
+
# specific project.
|
30
|
+
#
|
31
|
+
# require "gcloud"
|
32
|
+
#
|
33
|
+
# gcloud = Gcloud.new
|
34
|
+
# bigquery = gcloud.bigquery
|
35
|
+
#
|
36
|
+
# dataset = bigquery.create_dataset "my_dataset",
|
37
|
+
# name: "My Dataset"
|
38
|
+
# description: "This is my Dataset"
|
39
|
+
#
|
40
|
+
class Dataset
|
41
|
+
##
|
42
|
+
# The Connection object.
|
43
|
+
attr_accessor :connection #:nodoc:
|
44
|
+
|
45
|
+
##
|
46
|
+
# The Google API Client object.
|
47
|
+
attr_accessor :gapi #:nodoc:
|
48
|
+
|
49
|
+
##
|
50
|
+
# Create an empty Dataset object.
|
51
|
+
def initialize #:nodoc:
|
52
|
+
@connection = nil
|
53
|
+
@gapi = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# A unique ID for this dataset, without the project name.
|
58
|
+
# The ID must contain only letters (a-z, A-Z), numbers (0-9),
|
59
|
+
# or underscores (_). The maximum length is 1,024 characters.
|
60
|
+
#
|
61
|
+
# :category: Attributes
|
62
|
+
#
|
63
|
+
def dataset_id
|
64
|
+
@gapi["datasetReference"]["datasetId"]
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# The ID of the project containing this dataset.
|
69
|
+
#
|
70
|
+
# :category: Attributes
|
71
|
+
#
|
72
|
+
def project_id
|
73
|
+
@gapi["datasetReference"]["projectId"]
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# A descriptive name for the dataset.
|
78
|
+
#
|
79
|
+
# :category: Attributes
|
80
|
+
#
|
81
|
+
def name
|
82
|
+
@gapi["friendlyName"]
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Updates the descriptive name for the dataset.
|
87
|
+
#
|
88
|
+
# :category: Attributes
|
89
|
+
#
|
90
|
+
def name= new_name
|
91
|
+
patch_gapi! name: new_name
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# A string hash of the dataset.
|
96
|
+
#
|
97
|
+
# :category: Attributes
|
98
|
+
#
|
99
|
+
def etag
|
100
|
+
ensure_full_data!
|
101
|
+
@gapi["etag"]
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# A URL that can be used to access the dataset using the REST API.
|
106
|
+
#
|
107
|
+
# :category: Attributes
|
108
|
+
#
|
109
|
+
def url
|
110
|
+
ensure_full_data!
|
111
|
+
@gapi["selfLink"]
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# A user-friendly description of the dataset.
|
116
|
+
#
|
117
|
+
# :category: Attributes
|
118
|
+
#
|
119
|
+
def description
|
120
|
+
ensure_full_data!
|
121
|
+
@gapi["description"]
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Updates the user-friendly description of the dataset.
|
126
|
+
#
|
127
|
+
# :category: Attributes
|
128
|
+
#
|
129
|
+
def description= new_description
|
130
|
+
patch_gapi! description: new_description
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# The default lifetime of all tables in the dataset, in milliseconds.
|
135
|
+
#
|
136
|
+
# :category: Attributes
|
137
|
+
#
|
138
|
+
def default_expiration
|
139
|
+
ensure_full_data!
|
140
|
+
@gapi["defaultTableExpirationMs"]
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Updates the default lifetime of all tables in the dataset, in
|
145
|
+
# milliseconds.
|
146
|
+
#
|
147
|
+
# :category: Attributes
|
148
|
+
#
|
149
|
+
def default_expiration= new_default_expiration
|
150
|
+
patch_gapi! default_expiration: new_default_expiration
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# The time when this dataset was created.
|
155
|
+
#
|
156
|
+
# :category: Attributes
|
157
|
+
#
|
158
|
+
def created_at
|
159
|
+
ensure_full_data!
|
160
|
+
Time.at(@gapi["creationTime"] / 1000.0)
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# The date when this dataset or any of its tables was last modified.
|
165
|
+
#
|
166
|
+
# :category: Attributes
|
167
|
+
#
|
168
|
+
def modified_at
|
169
|
+
ensure_full_data!
|
170
|
+
Time.at(@gapi["lastModifiedTime"] / 1000.0)
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# The geographic location where the dataset should reside. Possible
|
175
|
+
# values include EU and US. The default value is US.
|
176
|
+
#
|
177
|
+
# :category: Attributes
|
178
|
+
#
|
179
|
+
def location
|
180
|
+
ensure_full_data!
|
181
|
+
@gapi["location"]
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# Permanently deletes the dataset. The dataset must be empty before it can
|
186
|
+
# be deleted unless the +force+ option is set to +true+.
|
187
|
+
#
|
188
|
+
# === Parameters
|
189
|
+
#
|
190
|
+
# +options+::
|
191
|
+
# An optional Hash for controlling additional behavior. (+Hash+)
|
192
|
+
# <code>options[:force]</code>::
|
193
|
+
# If +true+, delete all the tables in the dataset. If +false+ and the
|
194
|
+
# dataset contains tables, the request will fail. Default is +false+.
|
195
|
+
# (+Boolean+)
|
196
|
+
#
|
197
|
+
# === Returns
|
198
|
+
#
|
199
|
+
# +true+ if the dataset was deleted.
|
200
|
+
#
|
201
|
+
# === Example
|
202
|
+
#
|
203
|
+
# require "gcloud"
|
204
|
+
#
|
205
|
+
# gcloud = Gcloud.new
|
206
|
+
# bigquery = gcloud.bigquery
|
207
|
+
#
|
208
|
+
# dataset = bigquery.dataset "my_dataset"
|
209
|
+
# dataset.delete
|
210
|
+
#
|
211
|
+
# :category: Lifecycle
|
212
|
+
#
|
213
|
+
def delete options = {}
|
214
|
+
ensure_connection!
|
215
|
+
resp = connection.delete_dataset dataset_id, options
|
216
|
+
if resp.success?
|
217
|
+
true
|
218
|
+
else
|
219
|
+
fail ApiError.from_response(resp)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
##
|
224
|
+
# Creates a new table.
|
225
|
+
#
|
226
|
+
# === Parameters
|
227
|
+
#
|
228
|
+
# +table_id+::
|
229
|
+
# The ID of the table. The ID must contain only letters (a-z, A-Z),
|
230
|
+
# numbers (0-9), or underscores (_). The maximum length is 1,024
|
231
|
+
# characters. (+String+)
|
232
|
+
# +options+::
|
233
|
+
# An optional Hash for controlling additional behavior. (+Hash+)
|
234
|
+
# <code>options[:name]</code>::
|
235
|
+
# A descriptive name for the table. (+String+)
|
236
|
+
# <code>options[:description]</code>::
|
237
|
+
# A user-friendly description of the table. (+String+)
|
238
|
+
# <code>options[:schema]</code>::
|
239
|
+
# A schema specifying fields and data types for the table. See the
|
240
|
+
# {Tables resource
|
241
|
+
# }[https://cloud.google.com/bigquery/docs/reference/v2/tables#resource]
|
242
|
+
# for more information. (+Hash+)
|
243
|
+
#
|
244
|
+
# === Returns
|
245
|
+
#
|
246
|
+
# Gcloud::Bigquery::Table
|
247
|
+
#
|
248
|
+
# === Examples
|
249
|
+
#
|
250
|
+
# require "gcloud"
|
251
|
+
#
|
252
|
+
# gcloud = Gcloud.new
|
253
|
+
# bigquery = gcloud.bigquery
|
254
|
+
# dataset = bigquery.dataset "my_dataset"
|
255
|
+
# table = dataset.create_table "my_table"
|
256
|
+
#
|
257
|
+
# A name and description can be provided:
|
258
|
+
#
|
259
|
+
# require "gcloud"
|
260
|
+
#
|
261
|
+
# gcloud = Gcloud.new
|
262
|
+
# bigquery = gcloud.bigquery
|
263
|
+
# dataset = bigquery.dataset "my_dataset"
|
264
|
+
#
|
265
|
+
# schema = {
|
266
|
+
# "fields" => [
|
267
|
+
# {
|
268
|
+
# "name" => "first_name",
|
269
|
+
# "type" => "STRING",
|
270
|
+
# "mode" => "REQUIRED"
|
271
|
+
# },
|
272
|
+
# {
|
273
|
+
# "name" => "cities_lived",
|
274
|
+
# "type" => "RECORD",
|
275
|
+
# "mode" => "REPEATED",
|
276
|
+
# "fields" => [
|
277
|
+
# {
|
278
|
+
# "name" => "place",
|
279
|
+
# "type" => "STRING",
|
280
|
+
# "mode" => "REQUIRED"
|
281
|
+
# },
|
282
|
+
# {
|
283
|
+
# "name" => "number_of_years",
|
284
|
+
# "type" => "INTEGER",
|
285
|
+
# "mode" => "REQUIRED"
|
286
|
+
# }
|
287
|
+
# ]
|
288
|
+
# }
|
289
|
+
# ]
|
290
|
+
# }
|
291
|
+
# table = dataset.create_table "my_table",
|
292
|
+
# name: "My Table",
|
293
|
+
# schema: schema
|
294
|
+
#
|
295
|
+
# :category: Table
|
296
|
+
#
|
297
|
+
def create_table table_id, options = {}
|
298
|
+
ensure_connection!
|
299
|
+
resp = connection.insert_table dataset_id, table_id, options
|
300
|
+
if resp.success?
|
301
|
+
Table.from_gapi resp.data, connection
|
302
|
+
else
|
303
|
+
fail ApiError.from_response(resp)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
##
|
308
|
+
# Creates a new view table from the given query.
|
309
|
+
#
|
310
|
+
# === Parameters
|
311
|
+
#
|
312
|
+
# +table_id+::
|
313
|
+
# The ID of the view table. The ID must contain only letters (a-z, A-Z),
|
314
|
+
# numbers (0-9), or underscores (_). The maximum length is 1,024
|
315
|
+
# characters. (+String+)
|
316
|
+
# +query+::
|
317
|
+
# The query that BigQuery executes when the view is referenced.
|
318
|
+
# (+String+)
|
319
|
+
# +options+::
|
320
|
+
# An optional Hash for controlling additional behavior. (+Hash+)
|
321
|
+
# <code>options[:name]</code>::
|
322
|
+
# A descriptive name for the table. (+String+)
|
323
|
+
# <code>options[:description]</code>::
|
324
|
+
# A user-friendly description of the table. (+String+)
|
325
|
+
#
|
326
|
+
# === Returns
|
327
|
+
#
|
328
|
+
# Gcloud::Bigquery::View
|
329
|
+
#
|
330
|
+
# === Examples
|
331
|
+
#
|
332
|
+
# require "gcloud"
|
333
|
+
#
|
334
|
+
# gcloud = Gcloud.new
|
335
|
+
# bigquery = gcloud.bigquery
|
336
|
+
# dataset = bigquery.dataset "my_dataset"
|
337
|
+
# view = dataset.create_view "my_view",
|
338
|
+
# "SELECT name, age FROM [proj:dataset.users]"
|
339
|
+
#
|
340
|
+
# A name and description can be provided:
|
341
|
+
#
|
342
|
+
# require "gcloud"
|
343
|
+
#
|
344
|
+
# gcloud = Gcloud.new
|
345
|
+
# bigquery = gcloud.bigquery
|
346
|
+
# dataset = bigquery.dataset "my_dataset"
|
347
|
+
# view = dataset.create_view "my_view",
|
348
|
+
# "SELECT name, age FROM [proj:dataset.users]",
|
349
|
+
# name: "My View", description: "This is my view"
|
350
|
+
#
|
351
|
+
# :category: Table
|
352
|
+
#
|
353
|
+
def create_view table_id, query, options = {}
|
354
|
+
options[:query] = query
|
355
|
+
create_table table_id, options
|
356
|
+
end
|
357
|
+
|
358
|
+
##
|
359
|
+
# Retrieves an existing table by ID.
|
360
|
+
#
|
361
|
+
# === Parameters
|
362
|
+
#
|
363
|
+
# +table_id+::
|
364
|
+
# The ID of a table. (+String+)
|
365
|
+
#
|
366
|
+
# === Returns
|
367
|
+
#
|
368
|
+
# Gcloud::Bigquery::Table or Gcloud::Bigquery::View or nil if the table
|
369
|
+
# does not exist
|
370
|
+
#
|
371
|
+
# === Example
|
372
|
+
#
|
373
|
+
# require "gcloud"
|
374
|
+
#
|
375
|
+
# gcloud = Gcloud.new
|
376
|
+
# bigquery = gcloud.bigquery
|
377
|
+
# dataset = bigquery.dataset "my_dataset"
|
378
|
+
# table = dataset.table "my_table"
|
379
|
+
# puts table.name
|
380
|
+
#
|
381
|
+
# :category: Table
|
382
|
+
#
|
383
|
+
def table table_id
|
384
|
+
ensure_connection!
|
385
|
+
resp = connection.get_table dataset_id, table_id
|
386
|
+
if resp.success?
|
387
|
+
Table.from_gapi resp.data, connection
|
388
|
+
else
|
389
|
+
nil
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
##
|
394
|
+
# Retrieves the list of tables belonging to the dataset.
|
395
|
+
#
|
396
|
+
# === Parameters
|
397
|
+
#
|
398
|
+
# +options+::
|
399
|
+
# An optional Hash for controlling additional behavior. (+Hash+)
|
400
|
+
# <code>options[:token]</code>::
|
401
|
+
# A previously-returned page token representing part of the larger set
|
402
|
+
# of results to view. (+String+)
|
403
|
+
# <code>options[:max]</code>::
|
404
|
+
# Maximum number of tables to return. (+Integer+)
|
405
|
+
#
|
406
|
+
# === Returns
|
407
|
+
#
|
408
|
+
# Array of Gcloud::Bigquery::Table or Gcloud::Bigquery::View
|
409
|
+
# (Gcloud::Bigquery::Table::List)
|
410
|
+
#
|
411
|
+
# === Examples
|
412
|
+
#
|
413
|
+
# require "gcloud"
|
414
|
+
#
|
415
|
+
# gcloud = Gcloud.new
|
416
|
+
# bigquery = gcloud.bigquery
|
417
|
+
# dataset = bigquery.dataset "my_dataset"
|
418
|
+
# tables = dataset.tables
|
419
|
+
# tables.each do |table|
|
420
|
+
# puts table.name
|
421
|
+
# end
|
422
|
+
#
|
423
|
+
# If you have a significant number of tables, you may need to paginate
|
424
|
+
# through them: (See Dataset::List#token)
|
425
|
+
#
|
426
|
+
# require "gcloud"
|
427
|
+
#
|
428
|
+
# gcloud = Gcloud.new
|
429
|
+
# bigquery = gcloud.bigquery
|
430
|
+
# dataset = bigquery.dataset "my_dataset"
|
431
|
+
#
|
432
|
+
# all_tables = []
|
433
|
+
# tmp_tables = dataset.tables
|
434
|
+
# while tmp_tables.any? do
|
435
|
+
# tmp_tables.each do |table|
|
436
|
+
# all_tables << table
|
437
|
+
# end
|
438
|
+
# # break loop if no more tables available
|
439
|
+
# break if tmp_tables.token.nil?
|
440
|
+
# # get the next group of tables
|
441
|
+
# tmp_tables = dataset.tables token: tmp_tables.token
|
442
|
+
# end
|
443
|
+
#
|
444
|
+
# :category: Table
|
445
|
+
#
|
446
|
+
def tables options = {}
|
447
|
+
ensure_connection!
|
448
|
+
resp = connection.list_tables dataset_id, options
|
449
|
+
if resp.success?
|
450
|
+
Table::List.from_resp resp, connection
|
451
|
+
else
|
452
|
+
fail ApiError.from_response(resp)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
##
|
457
|
+
# Queries data using the {asynchronous
|
458
|
+
# method}[https://cloud.google.com/bigquery/querying-data].
|
459
|
+
#
|
460
|
+
# Sets the current dataset as the default dataset in the query. Useful for
|
461
|
+
# using unqualified table names.
|
462
|
+
#
|
463
|
+
# === Parameters
|
464
|
+
#
|
465
|
+
# +query+::
|
466
|
+
# A query string, following the BigQuery {query
|
467
|
+
# syntax}[https://cloud.google.com/bigquery/query-reference], of the
|
468
|
+
# query to execute. Example: "SELECT count(f1) FROM
|
469
|
+
# [myProjectId:myDatasetId.myTableId]". (+String+)
|
470
|
+
# <code>options[:priority]</code>::
|
471
|
+
# Specifies a priority for the query. Possible values include
|
472
|
+
# +INTERACTIVE+ and +BATCH+. The default value is +INTERACTIVE+.
|
473
|
+
# (+String+)
|
474
|
+
# <code>options[:cache]</code>::
|
475
|
+
# Whether to look for the result in the query cache. The query cache is
|
476
|
+
# a best-effort cache that will be flushed whenever tables in the query
|
477
|
+
# are modified. The default value is +true+. (+Boolean+)
|
478
|
+
# <code>options[:table]</code>::
|
479
|
+
# The destination table where the query results should be stored. If not
|
480
|
+
# present, a new table will be created to store the results. (+Table+)
|
481
|
+
# <code>options[:create]</code>::
|
482
|
+
# Specifies whether the job is allowed to create new tables. (+String+)
|
483
|
+
#
|
484
|
+
# The following values are supported:
|
485
|
+
# * +needed+ - Create the table if it does not exist.
|
486
|
+
# * +never+ - The table must already exist. A 'notFound' error is
|
487
|
+
# raised if the table does not exist.
|
488
|
+
# <code>options[:write]</code>::
|
489
|
+
# Specifies the action that occurs if the destination table already
|
490
|
+
# exists. (+String+)
|
491
|
+
#
|
492
|
+
# The following values are supported:
|
493
|
+
# * +truncate+ - BigQuery overwrites the table data.
|
494
|
+
# * +append+ - BigQuery appends the data to the table.
|
495
|
+
# * +empty+ - A 'duplicate' error is returned in the job result if the
|
496
|
+
# table exists and contains data.
|
497
|
+
# <code>options[:large_results]</code>::
|
498
|
+
# If +true+, allows the query to produce arbitrarily large result tables
|
499
|
+
# at a slight cost in performance. Requires <code>options[:table]</code>
|
500
|
+
# to be set. (+Boolean+)
|
501
|
+
# <code>options[:flatten]</code>::
|
502
|
+
# Flattens all nested and repeated fields in the query results. The
|
503
|
+
# default value is +true+. <code>options[:large_results]</code> must be
|
504
|
+
# +true+ if this is set to +false+. (+Boolean+)
|
505
|
+
#
|
506
|
+
# === Returns
|
507
|
+
#
|
508
|
+
# Gcloud::Bigquery::QueryJob
|
509
|
+
#
|
510
|
+
# === Example
|
511
|
+
#
|
512
|
+
# require "gcloud"
|
513
|
+
#
|
514
|
+
# gcloud = Gcloud.new
|
515
|
+
# bigquery = gcloud.bigquery
|
516
|
+
#
|
517
|
+
# job = bigquery.query_job "SELECT name FROM my_table"
|
518
|
+
#
|
519
|
+
# loop do
|
520
|
+
# break if job.done?
|
521
|
+
# sleep 1
|
522
|
+
# job.refresh!
|
523
|
+
# end
|
524
|
+
# if !job.failed?
|
525
|
+
# job.query_results.each do |row|
|
526
|
+
# puts row["name"]
|
527
|
+
# end
|
528
|
+
# end
|
529
|
+
#
|
530
|
+
# :category: Data
|
531
|
+
#
|
532
|
+
def query_job query, options = {}
|
533
|
+
options[:dataset] ||= self
|
534
|
+
ensure_connection!
|
535
|
+
resp = connection.query_job query, options
|
536
|
+
if resp.success?
|
537
|
+
Job.from_gapi resp.data, connection
|
538
|
+
else
|
539
|
+
fail ApiError.from_response(resp)
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
##
|
544
|
+
# Queries data using the {synchronous
|
545
|
+
# method}[https://cloud.google.com/bigquery/querying-data].
|
546
|
+
#
|
547
|
+
# Sets the current dataset as the default dataset in the query. Useful for
|
548
|
+
# using unqualified table names.
|
549
|
+
#
|
550
|
+
# === Parameters
|
551
|
+
#
|
552
|
+
# +query+::
|
553
|
+
# A query string, following the BigQuery {query
|
554
|
+
# syntax}[https://cloud.google.com/bigquery/query-reference], of the
|
555
|
+
# query to execute. Example: "SELECT count(f1) FROM
|
556
|
+
# [myProjectId:myDatasetId.myTableId]". (+String+)
|
557
|
+
# <code>options[:max]</code>::
|
558
|
+
# The maximum number of rows of data to return per page of results.
|
559
|
+
# Setting this flag to a small value such as 1000 and then paging
|
560
|
+
# through results might improve reliability when the query result set is
|
561
|
+
# large. In addition to this limit, responses are also limited to 10 MB.
|
562
|
+
# By default, there is no maximum row count, and only the byte limit
|
563
|
+
# applies. (+Integer+)
|
564
|
+
# <code>options[:timeout]</code>::
|
565
|
+
# How long to wait for the query to complete, in milliseconds, before
|
566
|
+
# the request times out and returns. Note that this is only a timeout
|
567
|
+
# for the request, not the query. If the query takes longer to run than
|
568
|
+
# the timeout value, the call returns without any results and with
|
569
|
+
# QueryData#complete? set to false. The default value is 10000
|
570
|
+
# milliseconds (10 seconds). (+Integer+)
|
571
|
+
# <code>options[:dryrun]</code>::
|
572
|
+
# If set to +true+, BigQuery doesn't run the job. Instead, if the query
|
573
|
+
# is valid, BigQuery returns statistics about the job such as how many
|
574
|
+
# bytes would be processed. If the query is invalid, an error returns.
|
575
|
+
# The default value is +false+. (+Boolean+)
|
576
|
+
# <code>options[:cache]</code>::
|
577
|
+
# Whether to look for the result in the query cache. The query cache is
|
578
|
+
# a best-effort cache that will be flushed whenever tables in the query
|
579
|
+
# are modified. The default value is true. For more information, see
|
580
|
+
# {query caching}[https://developers.google.com/bigquery/querying-data].
|
581
|
+
# (+Boolean+)
|
582
|
+
#
|
583
|
+
# === Returns
|
584
|
+
#
|
585
|
+
# Gcloud::Bigquery::QueryData
|
586
|
+
#
|
587
|
+
# === Example
|
588
|
+
#
|
589
|
+
# require "gcloud"
|
590
|
+
#
|
591
|
+
# gcloud = Gcloud.new
|
592
|
+
# bigquery = gcloud.bigquery
|
593
|
+
#
|
594
|
+
# data = bigquery.query "SELECT name FROM my_table"
|
595
|
+
# data.each do |row|
|
596
|
+
# puts row["name"]
|
597
|
+
# end
|
598
|
+
#
|
599
|
+
# :category: Data
|
600
|
+
#
|
601
|
+
def query query, options = {}
|
602
|
+
options[:dataset] ||= dataset_id
|
603
|
+
options[:project] ||= project_id
|
604
|
+
ensure_connection!
|
605
|
+
resp = connection.query query, options
|
606
|
+
if resp.success?
|
607
|
+
QueryData.from_gapi resp.data, connection
|
608
|
+
else
|
609
|
+
fail ApiError.from_response(resp)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
##
|
614
|
+
# New Dataset from a Google API Client object.
|
615
|
+
def self.from_gapi gapi, conn #:nodoc:
|
616
|
+
new.tap do |f|
|
617
|
+
f.gapi = gapi
|
618
|
+
f.connection = conn
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
protected
|
623
|
+
|
624
|
+
##
|
625
|
+
# Raise an error unless an active connection is available.
|
626
|
+
def ensure_connection!
|
627
|
+
fail "Must have active connection" unless connection
|
628
|
+
end
|
629
|
+
|
630
|
+
def patch_gapi! options = {}
|
631
|
+
ensure_connection!
|
632
|
+
resp = connection.patch_dataset dataset_id, options
|
633
|
+
if resp.success?
|
634
|
+
@gapi = resp.data
|
635
|
+
else
|
636
|
+
fail ApiError.from_response(resp)
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
##
|
641
|
+
# Load the complete representation of the dataset if it has been
|
642
|
+
# only partially loaded by a request to the API list method.
|
643
|
+
def ensure_full_data!
|
644
|
+
reload_gapi! unless data_complete?
|
645
|
+
end
|
646
|
+
|
647
|
+
def reload_gapi!
|
648
|
+
ensure_connection!
|
649
|
+
resp = connection.get_dataset dataset_id
|
650
|
+
if resp.success?
|
651
|
+
@gapi = resp.data
|
652
|
+
else
|
653
|
+
fail ApiError.from_response(resp)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
def data_complete?
|
658
|
+
!@gapi["creationTime"].nil?
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
end
|