google-cloud-bigquery 1.11.2 → 1.12.0

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.
@@ -0,0 +1,168 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "delegate"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Bigquery
21
+ class Model
22
+ ##
23
+ # Model::List is a special case Array with additional values.
24
+ class List < DelegateClass(::Array)
25
+ ##
26
+ # If not empty, indicates that there are more records that match
27
+ # the request and this value should be passed to continue.
28
+ attr_accessor :token
29
+
30
+ ##
31
+ # @private Create a new Model::List with an array of models.
32
+ def initialize arr = []
33
+ super arr
34
+ end
35
+
36
+ ##
37
+ # Whether there is a next page of models.
38
+ #
39
+ # @return [Boolean]
40
+ #
41
+ # @example
42
+ # require "google/cloud/bigquery"
43
+ #
44
+ # bigquery = Google::Cloud::Bigquery.new
45
+ # dataset = bigquery.dataset "my_dataset"
46
+ #
47
+ # models = dataset.models
48
+ # if models.next?
49
+ # next_models = models.next
50
+ # end
51
+ #
52
+ def next?
53
+ !token.nil?
54
+ end
55
+
56
+ ##
57
+ # Retrieve the next page of models.
58
+ #
59
+ # @return [Model::List]
60
+ #
61
+ # @example
62
+ # require "google/cloud/bigquery"
63
+ #
64
+ # bigquery = Google::Cloud::Bigquery.new
65
+ # dataset = bigquery.dataset "my_dataset"
66
+ #
67
+ # models = dataset.models
68
+ # if models.next?
69
+ # next_models = models.next
70
+ # end
71
+ #
72
+ def next
73
+ return nil unless next?
74
+ ensure_service!
75
+ gapi = @service.list_models @dataset_id, token: token, max: @max
76
+ self.class.from_gapi gapi, @service, @dataset_id, @max
77
+ end
78
+
79
+ ##
80
+ # Retrieves remaining results by repeatedly invoking {#next} until
81
+ # {#next?} returns `false`. Calls the given block once for each
82
+ # result, which is passed as the argument to the block.
83
+ #
84
+ # An Enumerator is returned if no block is given.
85
+ #
86
+ # This method will make repeated API calls until all remaining results
87
+ # are retrieved. (Unlike `#each`, for example, which merely iterates
88
+ # over the results returned by a single API call.) Use with caution.
89
+ #
90
+ # @param [Integer] request_limit The upper limit of API requests to
91
+ # make to load all models. Default is no limit.
92
+ # @yield [model] The block for accessing each model.
93
+ # @yieldparam [Model] model The model object.
94
+ #
95
+ # @return [Enumerator]
96
+ #
97
+ # @example Iterating each result by passing a block:
98
+ # require "google/cloud/bigquery"
99
+ #
100
+ # bigquery = Google::Cloud::Bigquery.new
101
+ # dataset = bigquery.dataset "my_dataset"
102
+ #
103
+ # dataset.models.all do |model|
104
+ # puts model.model_id
105
+ # end
106
+ #
107
+ # @example Using the enumerator by not passing a block:
108
+ # require "google/cloud/bigquery"
109
+ #
110
+ # bigquery = Google::Cloud::Bigquery.new
111
+ # dataset = bigquery.dataset "my_dataset"
112
+ #
113
+ # all_names = dataset.models.all.map do |model|
114
+ # model.model_id
115
+ # end
116
+ #
117
+ # @example Limit the number of API requests made:
118
+ # require "google/cloud/bigquery"
119
+ #
120
+ # bigquery = Google::Cloud::Bigquery.new
121
+ # dataset = bigquery.dataset "my_dataset"
122
+ #
123
+ # dataset.models.all(request_limit: 10) do |model|
124
+ # puts model.model_id
125
+ # end
126
+ #
127
+ def all request_limit: nil
128
+ request_limit = request_limit.to_i if request_limit
129
+ unless block_given?
130
+ return enum_for :all, request_limit: request_limit
131
+ end
132
+ results = self
133
+ loop do
134
+ results.each { |r| yield r }
135
+ if request_limit
136
+ request_limit -= 1
137
+ break if request_limit < 0
138
+ end
139
+ break unless results.next?
140
+ results = results.next
141
+ end
142
+ end
143
+
144
+ ##
145
+ # @private New Model::List from a response object.
146
+ def self.from_gapi gapi_list, service, dataset_id = nil, max = nil
147
+ models = List.new(Array(gapi_list[:models]).map do |gapi_json|
148
+ Model.from_gapi_json gapi_json, service
149
+ end)
150
+ models.instance_variable_set :@token, gapi_list[:nextPageToken]
151
+ models.instance_variable_set :@service, service
152
+ models.instance_variable_set :@dataset_id, dataset_id
153
+ models.instance_variable_set :@max, max
154
+ models
155
+ end
156
+
157
+ protected
158
+
159
+ ##
160
+ # Raise an error unless an active service is available.
161
+ def ensure_service!
162
+ raise "Must have active connection" unless @service
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -238,6 +238,60 @@ module Google
238
238
  end
239
239
  end
240
240
 
241
+ ##
242
+ # Lists all models in the specified dataset.
243
+ # Requires the READER dataset role.
244
+ def list_models dataset_id, max: nil, token: nil
245
+ options = { skip_deserialization: true }
246
+ # The list operation is considered idempotent
247
+ execute backoff: true do
248
+ json_txt = service.list_models @project, dataset_id,
249
+ max_results: max,
250
+ page_token: token,
251
+ options: options
252
+ JSON.parse json_txt, symbolize_names: true
253
+ end
254
+ end
255
+
256
+ # Gets the specified model resource by model ID.
257
+ # This method does not return the data in the model,
258
+ # it only returns the model resource,
259
+ # which describes the structure of this model.
260
+ def get_model dataset_id, model_id
261
+ # The get operation is considered idempotent
262
+ execute backoff: true do
263
+ json_txt = service.get_model @project, dataset_id, model_id,
264
+ options: { skip_deserialization: true }
265
+ JSON.parse json_txt, symbolize_names: true
266
+ end
267
+ end
268
+
269
+ ##
270
+ # Updates information in an existing model, replacing fields that
271
+ # are provided in the submitted model resource.
272
+ def patch_model dataset_id, model_id, patched_model_gapi, etag = nil
273
+ patch_with_backoff = false
274
+ options = { skip_deserialization: true }
275
+ if etag
276
+ options[:header] = { "If-Match" => etag }
277
+ # The patch with etag operation is considered idempotent
278
+ patch_with_backoff = true
279
+ end
280
+ execute backoff: patch_with_backoff do
281
+ json_txt = service.patch_model @project, dataset_id, model_id,
282
+ patched_model_gapi,
283
+ options: options
284
+ JSON.parse json_txt, symbolize_names: true
285
+ end
286
+ end
287
+
288
+ ##
289
+ # Deletes the model specified by modelId from the dataset.
290
+ # If the model contains data, all the data will be deleted.
291
+ def delete_model dataset_id, model_id
292
+ execute { service.delete_model @project, dataset_id, model_id }
293
+ end
294
+
241
295
  ##
242
296
  # Lists all jobs in the specified project to which you have
243
297
  # been granted the READER job role.
@@ -0,0 +1,291 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Google
17
+ module Cloud
18
+ module Bigquery
19
+ ##
20
+ # BigQuery standard SQL is compliant with the SQL 2011 standard and has
21
+ # extensions that support querying nested and repeated data.
22
+ module StandardSql
23
+ ##
24
+ # A field or a column.
25
+ class Field
26
+ ##
27
+ # @private Create an empty StandardSql::Field object.
28
+ def initialize
29
+ @gapi_json = nil
30
+ end
31
+
32
+ ##
33
+ # The name of the field. (Can be absent for struct fields.)
34
+ #
35
+ # @return [String, nil]
36
+ #
37
+ def name
38
+ return nil if @gapi_json[:name] == "".freeze
39
+
40
+ @gapi_json[:name]
41
+ end
42
+
43
+ ##
44
+ # The type of the field.
45
+ #
46
+ # @return [DataType]
47
+ #
48
+ def type
49
+ DataType.from_gapi_json @gapi_json[:type]
50
+ end
51
+
52
+ ##
53
+ # @private New StandardSql::Field from a JSON object.
54
+ def self.from_gapi_json gapi_json
55
+ new.tap do |f|
56
+ f.instance_variable_set :@gapi_json, gapi_json
57
+ end
58
+ end
59
+ end
60
+
61
+ ##
62
+ # The type of a field or a column.
63
+ class DataType
64
+ ##
65
+ # @private Create an empty StandardSql::DataType object.
66
+ def initialize
67
+ @gapi_json = nil
68
+ end
69
+
70
+ ##
71
+ # The top level type of this field.
72
+ #
73
+ # Can be any standard SQL data type (e.g., "INT64", "DATE", "ARRAY").
74
+ #
75
+ # @see https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
76
+ # Standard SQL Data Types
77
+ #
78
+ # @return [String]
79
+ #
80
+ def type_kind
81
+ @gapi_json[:typeKind]
82
+ end
83
+
84
+ ##
85
+ # The type of a fields when DataType is an Array. (See #array?)
86
+ #
87
+ # @return [DataType, nil]
88
+ #
89
+ def array_element_type
90
+ return if @gapi_json[:arrayElementType].nil?
91
+
92
+ DataType.from_gapi_json @gapi_json[:arrayElementType]
93
+ end
94
+
95
+ ##
96
+ # The fields of the struct. (See #struct?)
97
+ #
98
+ # @return [StructType, nil]
99
+ #
100
+ def struct_type
101
+ return if @gapi_json[:structType].nil?
102
+
103
+ StructType.from_gapi_json @gapi_json[:structType]
104
+ end
105
+
106
+ ##
107
+ # Checks if the {#type_kind} of the field is `INT64`.
108
+ #
109
+ # @return [Boolean] `true` when `INT64`, `false` otherwise.
110
+ #
111
+ # @!group Helpers
112
+ #
113
+ def int?
114
+ type_kind == "INT64".freeze
115
+ end
116
+
117
+ ##
118
+ # Checks if the {#type_kind} of the field is `FLOAT64`.
119
+ #
120
+ # @return [Boolean] `true` when `FLOAT64`, `false` otherwise.
121
+ #
122
+ # @!group Helpers
123
+ #
124
+ def float?
125
+ type_kind == "FLOAT64".freeze
126
+ end
127
+
128
+ ##
129
+ # Checks if the {#type_kind} of the field is `NUMERIC`.
130
+ #
131
+ # @return [Boolean] `true` when `NUMERIC`, `false` otherwise.
132
+ #
133
+ # @!group Helpers
134
+ #
135
+ def numeric?
136
+ type_kind == "NUMERIC".freeze
137
+ end
138
+
139
+ ##
140
+ # Checks if the {#type_kind} of the field is `BOOL`.
141
+ #
142
+ # @return [Boolean] `true` when `BOOL`, `false` otherwise.
143
+ #
144
+ # @!group Helpers
145
+ #
146
+ def boolean?
147
+ type_kind == "BOOL".freeze
148
+ end
149
+
150
+ ##
151
+ # Checks if the {#type_kind} of the field is `STRING`.
152
+ #
153
+ # @return [Boolean] `true` when `STRING`, `false` otherwise.
154
+ #
155
+ # @!group Helpers
156
+ #
157
+ def string?
158
+ type_kind == "STRING".freeze
159
+ end
160
+
161
+ ##
162
+ # Checks if the {#type_kind} of the field is `BYTES`.
163
+ #
164
+ # @return [Boolean] `true` when `BYTES`, `false` otherwise.
165
+ #
166
+ # @!group Helpers
167
+ #
168
+ def bytes?
169
+ type_kind == "BYTES".freeze
170
+ end
171
+
172
+ ##
173
+ # Checks if the {#type_kind} of the field is `DATE`.
174
+ #
175
+ # @return [Boolean] `true` when `DATE`, `false` otherwise.
176
+ #
177
+ # @!group Helpers
178
+ #
179
+ def date?
180
+ type_kind == "DATE".freeze
181
+ end
182
+
183
+ ##
184
+ # Checks if the {#type_kind} of the field is `DATETIME`.
185
+ #
186
+ # @return [Boolean] `true` when `DATETIME`, `false` otherwise.
187
+ #
188
+ # @!group Helpers
189
+ #
190
+ def datetime?
191
+ type_kind == "DATETIME".freeze
192
+ end
193
+
194
+ ##
195
+ # Checks if the {#type_kind} of the field is `GEOGRAPHY`.
196
+ #
197
+ # @return [Boolean] `true` when `GEOGRAPHY`, `false` otherwise.
198
+ #
199
+ # @!group Helpers
200
+ #
201
+ def geography?
202
+ type_kind == "GEOGRAPHY".freeze
203
+ end
204
+
205
+ ##
206
+ # Checks if the {#type_kind} of the field is `TIME`.
207
+ #
208
+ # @return [Boolean] `true` when `TIME`, `false` otherwise.
209
+ #
210
+ # @!group Helpers
211
+ #
212
+ def time?
213
+ type_kind == "TIME".freeze
214
+ end
215
+
216
+ ##
217
+ # Checks if the {#type_kind} of the field is `TIMESTAMP`.
218
+ #
219
+ # @return [Boolean] `true` when `TIMESTAMP`, `false` otherwise.
220
+ #
221
+ # @!group Helpers
222
+ #
223
+ def timestamp?
224
+ type_kind == "TIMESTAMP".freeze
225
+ end
226
+
227
+ ##
228
+ # Checks if the {#type_kind} of the field is `ARRAY`.
229
+ #
230
+ # @return [Boolean] `true` when `ARRAY`, `false` otherwise.
231
+ #
232
+ # @!group Helpers
233
+ #
234
+ def array?
235
+ type_kind == "ARRAY".freeze
236
+ end
237
+
238
+ ##
239
+ # Checks if the {#type_kind} of the field is `STRUCT`.
240
+ #
241
+ # @return [Boolean] `true` when `STRUCT`, `false` otherwise.
242
+ #
243
+ # @!group Helpers
244
+ #
245
+ def struct?
246
+ type_kind == "STRUCT".freeze
247
+ end
248
+
249
+ ##
250
+ # @private New StandardSql::DataType from a JSON object.
251
+ def self.from_gapi_json gapi_json
252
+ new.tap do |dt|
253
+ dt.instance_variable_set :@gapi_json, gapi_json
254
+ end
255
+ end
256
+ end
257
+
258
+ ##
259
+ # The type of a `STRUCT` field or a column.
260
+ class StructType
261
+ ##
262
+ # @private Create an empty StandardSql::DataType object.
263
+ def initialize
264
+ @gapi_json = nil
265
+ end
266
+
267
+ ##
268
+ # The top level type of this field.
269
+ #
270
+ # Can be any standard SQL data type (e.g., "INT64", "DATE", "ARRAY").
271
+ #
272
+ # @return [Array<Field>]
273
+ #
274
+ def fields
275
+ Array(@gapi_json[:fields]).map do |field_gapi_json|
276
+ Field.from_gapi_json field_gapi_json
277
+ end
278
+ end
279
+
280
+ ##
281
+ # @private New StandardSql::StructType from a JSON object.
282
+ def self.from_gapi_json gapi_json
283
+ new.tap do |st|
284
+ st.instance_variable_set :@gapi_json, gapi_json
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end