google-cloud-bigquery 1.11.2 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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