google-cloud-bigquery 1.12.0 → 1.38.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHENTICATION.md +9 -28
  3. data/CHANGELOG.md +372 -1
  4. data/CONTRIBUTING.md +328 -116
  5. data/LOGGING.md +2 -2
  6. data/OVERVIEW.md +21 -20
  7. data/TROUBLESHOOTING.md +2 -8
  8. data/lib/google/cloud/bigquery/argument.rb +197 -0
  9. data/lib/google/cloud/bigquery/convert.rb +154 -170
  10. data/lib/google/cloud/bigquery/copy_job.rb +40 -23
  11. data/lib/google/cloud/bigquery/credentials.rb +5 -12
  12. data/lib/google/cloud/bigquery/data.rb +109 -18
  13. data/lib/google/cloud/bigquery/dataset/access.rb +322 -51
  14. data/lib/google/cloud/bigquery/dataset/list.rb +7 -13
  15. data/lib/google/cloud/bigquery/dataset.rb +960 -279
  16. data/lib/google/cloud/bigquery/external/avro_source.rb +107 -0
  17. data/lib/google/cloud/bigquery/external/bigtable_source/column.rb +404 -0
  18. data/lib/google/cloud/bigquery/external/bigtable_source/column_family.rb +945 -0
  19. data/lib/google/cloud/bigquery/external/bigtable_source.rb +230 -0
  20. data/lib/google/cloud/bigquery/external/csv_source.rb +481 -0
  21. data/lib/google/cloud/bigquery/external/data_source.rb +771 -0
  22. data/lib/google/cloud/bigquery/external/json_source.rb +170 -0
  23. data/lib/google/cloud/bigquery/external/parquet_source.rb +148 -0
  24. data/lib/google/cloud/bigquery/external/sheets_source.rb +166 -0
  25. data/lib/google/cloud/bigquery/external.rb +50 -2256
  26. data/lib/google/cloud/bigquery/extract_job.rb +217 -58
  27. data/lib/google/cloud/bigquery/insert_response.rb +1 -3
  28. data/lib/google/cloud/bigquery/job/list.rb +13 -20
  29. data/lib/google/cloud/bigquery/job.rb +286 -11
  30. data/lib/google/cloud/bigquery/load_job.rb +801 -133
  31. data/lib/google/cloud/bigquery/model/list.rb +5 -9
  32. data/lib/google/cloud/bigquery/model.rb +247 -16
  33. data/lib/google/cloud/bigquery/policy.rb +432 -0
  34. data/lib/google/cloud/bigquery/project/list.rb +6 -11
  35. data/lib/google/cloud/bigquery/project.rb +526 -243
  36. data/lib/google/cloud/bigquery/query_job.rb +584 -125
  37. data/lib/google/cloud/bigquery/routine/list.rb +165 -0
  38. data/lib/google/cloud/bigquery/routine.rb +1227 -0
  39. data/lib/google/cloud/bigquery/schema/field.rb +413 -63
  40. data/lib/google/cloud/bigquery/schema.rb +221 -48
  41. data/lib/google/cloud/bigquery/service.rb +186 -109
  42. data/lib/google/cloud/bigquery/standard_sql.rb +269 -53
  43. data/lib/google/cloud/bigquery/table/async_inserter.rb +86 -42
  44. data/lib/google/cloud/bigquery/table/list.rb +6 -11
  45. data/lib/google/cloud/bigquery/table.rb +1188 -326
  46. data/lib/google/cloud/bigquery/time.rb +6 -0
  47. data/lib/google/cloud/bigquery/version.rb +1 -1
  48. data/lib/google/cloud/bigquery.rb +18 -8
  49. data/lib/google-cloud-bigquery.rb +15 -13
  50. metadata +67 -40
@@ -0,0 +1,197 @@
1
+ # Copyright 2020 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 "google/cloud/bigquery/standard_sql"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Bigquery
21
+ ##
22
+ # # Argument
23
+ #
24
+ # Input/output argument of a function or a stored procedure. See {Routine}.
25
+ #
26
+ # @example
27
+ # require "google/cloud/bigquery"
28
+ #
29
+ # bigquery = Google::Cloud::Bigquery.new
30
+ # dataset = bigquery.dataset "my_dataset"
31
+ # routine = dataset.create_routine "my_routine" do |r|
32
+ # r.routine_type = "SCALAR_FUNCTION"
33
+ # r.language = :SQL
34
+ # r.body = "(SELECT SUM(IF(elem.name = \"foo\",elem.val,null)) FROM UNNEST(arr) AS elem)"
35
+ # r.arguments = [
36
+ # Google::Cloud::Bigquery::Argument.new(
37
+ # name: "arr",
38
+ # argument_kind: "FIXED_TYPE",
39
+ # data_type: Google::Cloud::Bigquery::StandardSql::DataType.new(
40
+ # type_kind: "ARRAY",
41
+ # array_element_type: Google::Cloud::Bigquery::StandardSql::DataType.new(
42
+ # type_kind: "STRUCT",
43
+ # struct_type: Google::Cloud::Bigquery::StandardSql::StructType.new(
44
+ # fields: [
45
+ # Google::Cloud::Bigquery::StandardSql::Field.new(
46
+ # name: "name",
47
+ # type: Google::Cloud::Bigquery::StandardSql::DataType.new(type_kind: "STRING")
48
+ # ),
49
+ # Google::Cloud::Bigquery::StandardSql::Field.new(
50
+ # name: "val",
51
+ # type: Google::Cloud::Bigquery::StandardSql::DataType.new(type_kind: "INT64")
52
+ # )
53
+ # ]
54
+ # )
55
+ # )
56
+ # )
57
+ # )
58
+ # ]
59
+ # end
60
+ #
61
+ class Argument
62
+ ##
63
+ # Creates a new, immutable Argument object.
64
+ #
65
+ # @overload initialize(data_type, kind, mode, name)
66
+ # @param [StandardSql::DataType, String] data_type The data type of the argument. Required unless
67
+ # {#argument_kind} is `ANY_TYPE`.
68
+ # @param [String] argument_kind The kind of argument. Optional. Defaults to `FIXED_TYPE`.
69
+ #
70
+ # * `FIXED_TYPE` - The argument is a variable with fully specified type, which can be a struct or an array,
71
+ # but not a table.
72
+ # * `ANY_TYPE` - The argument is any type, including struct or array, but not a table.
73
+ #
74
+ # To be added: `FIXED_TABLE`, `ANY_TABLE`.
75
+ # @param [String] mode Specifies whether the argument is input or output. Optional. Can be set for procedures
76
+ # only.
77
+ #
78
+ # * IN - The argument is input-only.
79
+ # * OUT - The argument is output-only.
80
+ # * INOUT - The argument is both an input and an output.
81
+ # @param [String] name The name of the argument. Optional. Can be absent for a function return argument.
82
+ #
83
+ def initialize **kwargs
84
+ kwargs[:data_type] = StandardSql::DataType.gapi_from_string_or_data_type kwargs[:data_type]
85
+ @gapi = Google::Apis::BigqueryV2::Argument.new(**kwargs)
86
+ end
87
+
88
+ ##
89
+ # The data type of the argument. Required unless {#argument_kind} is `ANY_TYPE`.
90
+ #
91
+ # @return [StandardSql::DataType] The data type.
92
+ #
93
+ def data_type
94
+ StandardSql::DataType.from_gapi @gapi.data_type
95
+ end
96
+
97
+ ##
98
+ # The kind of argument. Optional. Defaults to `FIXED_TYPE`.
99
+ #
100
+ # * `FIXED_TYPE` - The argument is a variable with fully specified type, which can be a struct or an array, but
101
+ # not a table.
102
+ # * `ANY_TYPE` - The argument is any type, including struct or array, but not a table.
103
+ #
104
+ # To be added: `FIXED_TABLE`, `ANY_TABLE`.
105
+ #
106
+ # @return [String] The upper case kind of argument.
107
+ #
108
+ def argument_kind
109
+ @gapi.argument_kind
110
+ end
111
+
112
+ ##
113
+ # Checks if the value of {#argument_kind} is `FIXED_TYPE`. The default is `true`.
114
+ #
115
+ # @return [Boolean] `true` when `FIXED_TYPE`, `false` otherwise.
116
+ #
117
+ def fixed_type?
118
+ return true if @gapi.argument_kind.nil?
119
+ @gapi.argument_kind == "FIXED_TYPE"
120
+ end
121
+
122
+ ##
123
+ # Checks if the value of {#argument_kind} is `ANY_TYPE`. The default is `false`.
124
+ #
125
+ # @return [Boolean] `true` when `ANY_TYPE`, `false` otherwise.
126
+ #
127
+ def any_type?
128
+ @gapi.argument_kind == "ANY_TYPE"
129
+ end
130
+
131
+ ##
132
+ # Specifies whether the argument is input or output. Optional. Can be set for procedures only.
133
+ #
134
+ # * IN - The argument is input-only.
135
+ # * OUT - The argument is output-only.
136
+ # * INOUT - The argument is both an input and an output.
137
+ #
138
+ # @return [String] The upper case input/output mode of the argument.
139
+ #
140
+ def mode
141
+ @gapi.mode
142
+ end
143
+
144
+ ##
145
+ # Checks if the value of {#mode} is `IN`. Can be set for procedures only. The default is `false`.
146
+ #
147
+ # @return [Boolean] `true` when `IN`, `false` otherwise.
148
+ #
149
+ def in?
150
+ @gapi.mode == "IN"
151
+ end
152
+
153
+ ##
154
+ # Checks if the value of {#mode} is `OUT`. Can be set for procedures only. The default is `false`.
155
+ #
156
+ # @return [Boolean] `true` when `OUT`, `false` otherwise.
157
+ #
158
+ def out?
159
+ @gapi.mode == "OUT"
160
+ end
161
+
162
+ ##
163
+ # Checks if the value of {#mode} is `INOUT`. Can be set for procedures only. The default is `false`.
164
+ #
165
+ # @return [Boolean] `true` when `INOUT`, `false` otherwise.
166
+ #
167
+ def inout?
168
+ @gapi.mode == "INOUT"
169
+ end
170
+
171
+ ##
172
+ #
173
+ # The name of the argument. Optional. Can be absent for a function return argument.
174
+ #
175
+ # @return [String] The name of the argument.
176
+ #
177
+ def name
178
+ @gapi.name
179
+ end
180
+
181
+ ##
182
+ # @private
183
+ def to_gapi
184
+ @gapi
185
+ end
186
+
187
+ ##
188
+ # @private New Argument from a Google API Client object.
189
+ def self.from_gapi gapi
190
+ new.tap do |a|
191
+ a.instance_variable_set :@gapi, gapi
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -23,30 +23,29 @@ require "date"
23
23
  module Google
24
24
  module Cloud
25
25
  module Bigquery
26
- # rubocop:disable Metrics/ModuleLength
27
-
28
26
  ##
29
27
  # @private
30
28
  #
31
- # Internal conversion of raw data values to/from Bigquery values
29
+ # Internal conversion of raw data values to/from BigQuery values
30
+ #
31
+ # | BigQuery | Ruby | Notes |
32
+ # |--------------|--------------------------------------|----------------------------------------------------|
33
+ # | `BOOL` | `true`/`false` | |
34
+ # | `INT64` | `Integer` | |
35
+ # | `FLOAT64` | `Float` | |
36
+ # | `NUMERIC` | `BigDecimal` | `BigDecimal` values will be rounded to scale 9. |
37
+ # | `BIGNUMERIC` | converted to `BigDecimal` | Pass data as `String`; map query params in `types`.|
38
+ # | `STRING` | `String` | |
39
+ # | `DATETIME` | `DateTime` | `DATETIME` does not support time zone. |
40
+ # | `DATE` | `Date` | |
41
+ # | `GEOGRAPHY` | `String` | |
42
+ # | `TIMESTAMP` | `Time` | |
43
+ # | `TIME` | `Google::Cloud::BigQuery::Time` | |
44
+ # | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
45
+ # | `ARRAY` | `Array` | Nested arrays, `nil` values are not supported. |
46
+ # | `STRUCT` | `Hash` | Hash keys may be strings or symbols. |
32
47
  #
33
- # | BigQuery | Ruby | Notes |
34
- # |-------------|----------------|---|
35
- # | `BOOL` | `true`/`false` | |
36
- # | `INT64` | `Integer` | |
37
- # | `FLOAT64` | `Float` | |
38
- # | `NUMERIC` | `BigDecimal` | Will be rounded to 9 decimal places |
39
- # | `STRING` | `String` | |
40
- # | `DATETIME` | `DateTime` | `DATETIME` does not support time zone. |
41
- # | `DATE` | `Date` | |
42
- # | `TIMESTAMP` | `Time` | |
43
- # | `TIME` | `Google::Cloud::BigQuery::Time` | |
44
- # | `BYTES` | `File`, `IO`, `StringIO`, or similar | |
45
- # | `ARRAY` | `Array` | Nested arrays, `nil` values are not supported. |
46
- # | `STRUCT` | `Hash` | Hash keys may be strings or symbols. |
47
48
  module Convert
48
- ##
49
- # @private
50
49
  def self.format_rows rows, fields
51
50
  Array(rows).map do |row|
52
51
  # convert TableRow to hash to handle nested TableCell values
@@ -54,8 +53,6 @@ module Google
54
53
  end
55
54
  end
56
55
 
57
- ##
58
- # @private
59
56
  def self.format_row row, fields
60
57
  row_pairs = fields.zip(row[:f]).map do |f, v|
61
58
  [f.name.to_sym, format_value(v, f)]
@@ -75,11 +72,7 @@ module Google
75
72
  elsif Array === value[:v]
76
73
  value[:v].map { |v| format_value v, field }
77
74
  elsif Hash === value[:v]
78
- if value[:v].empty?
79
- nil
80
- else
81
- format_row value[:v], field.fields
82
- end
75
+ format_row value[:v], field.fields
83
76
  elsif field.type == "STRING"
84
77
  String value[:v]
85
78
  elsif field.type == "INTEGER"
@@ -96,6 +89,8 @@ module Google
96
89
  end
97
90
  elsif field.type == "NUMERIC"
98
91
  BigDecimal value[:v]
92
+ elsif field.type == "BIGNUMERIC"
93
+ BigDecimal value[:v]
99
94
  elsif field.type == "BOOLEAN"
100
95
  (value[:v] == "true" ? true : (value[:v] == "false" ? false : nil))
101
96
  elsif field.type == "BYTES"
@@ -108,135 +103,119 @@ module Google
108
103
  ::Time.parse("#{value[:v]} UTC").to_datetime
109
104
  elsif field.type == "DATE"
110
105
  Date.parse value[:v]
106
+ elsif field.type == "GEOGRAPHY"
107
+ String value[:v]
111
108
  else
112
109
  value[:v]
113
110
  end
114
111
  end
115
112
 
116
- ##
117
- # @private
118
- def self.to_query_param value
119
- if TrueClass === value
120
- return Google::Apis::BigqueryV2::QueryParameter.new(
121
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
122
- type: "BOOL"),
123
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
124
- value: true)
125
- )
126
- elsif FalseClass === value
127
- return Google::Apis::BigqueryV2::QueryParameter.new(
128
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
129
- type: "BOOL"),
130
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
131
- value: false)
132
- )
133
- elsif Integer === value
134
- return Google::Apis::BigqueryV2::QueryParameter.new(
135
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
136
- type: "INT64"),
137
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
138
- value: value)
139
- )
140
- elsif Float === value
141
- return Google::Apis::BigqueryV2::QueryParameter.new(
142
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
143
- type: "FLOAT64"),
144
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
145
- value: value)
146
- )
147
- elsif BigDecimal === value
148
- # Round to precision of 9
149
- value_str = value.finite? ? value.round(9).to_s("F") : value.to_s
150
- return Google::Apis::BigqueryV2::QueryParameter.new(
151
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
152
- type: "NUMERIC"),
153
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
154
- value: value_str)
155
- )
156
- elsif String === value
157
- return Google::Apis::BigqueryV2::QueryParameter.new(
158
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
159
- type: "STRING"),
160
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
161
- value: value)
162
- )
163
- elsif DateTime === value
164
- return Google::Apis::BigqueryV2::QueryParameter.new(
165
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
166
- type: "DATETIME"),
167
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
168
- value: value.strftime("%Y-%m-%d %H:%M:%S.%6N"))
169
- )
170
- elsif Date === value
171
- return Google::Apis::BigqueryV2::QueryParameter.new(
172
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
173
- type: "DATE"),
174
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
175
- value: value.to_s)
176
- )
177
- elsif ::Time === value
178
- return Google::Apis::BigqueryV2::QueryParameter.new(
179
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
180
- type: "TIMESTAMP"),
181
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
182
- value: value.strftime("%Y-%m-%d %H:%M:%S.%6N%:z"))
183
- )
184
- elsif Bigquery::Time === value
185
- return Google::Apis::BigqueryV2::QueryParameter.new(
186
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
187
- type: "TIME"),
188
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
189
- value: value.value)
190
- )
191
- elsif value.respond_to?(:read) && value.respond_to?(:rewind)
192
- value.rewind
193
- return Google::Apis::BigqueryV2::QueryParameter.new(
194
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
195
- type: "BYTES"),
196
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
197
- value: Base64.strict_encode64(
198
- value.read.force_encoding("ASCII-8BIT")))
199
- )
200
- elsif Array === value
201
- array_params = value.map { |param| Convert.to_query_param param }
202
- return Google::Apis::BigqueryV2::QueryParameter.new(
203
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
204
- type: "ARRAY",
205
- array_type: array_params.first.parameter_type
206
- ),
207
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
208
- array_values: array_params.map(&:parameter_value)
209
- )
210
- )
211
- elsif Hash === value
212
- struct_pairs = value.map do |name, param|
213
- struct_param = Convert.to_query_param param
214
- [Google::Apis::BigqueryV2::QueryParameterType::StructType.new(
215
- name: String(name),
216
- type: struct_param.parameter_type
217
- ), struct_param.parameter_value]
113
+ # rubocop:enable all
114
+
115
+ def self.to_query_param_value value, type = nil
116
+ return Google::Apis::BigqueryV2::QueryParameterValue.new value: nil if value.nil?
117
+
118
+ json_value = to_json_value value, type
119
+
120
+ case json_value
121
+ when Array
122
+ type = extract_array_type type
123
+ array_values = json_value.map { |v| to_query_param_value v, type }
124
+ Google::Apis::BigqueryV2::QueryParameterValue.new array_values: array_values
125
+ when Hash
126
+ struct_pairs = json_value.map do |k, v|
127
+ [String(k), to_query_param_value(v, type)]
218
128
  end
219
- struct_values = Hash[struct_pairs.map do |type, value|
220
- [type.name.to_sym, value]
221
- end]
129
+ struct_values = Hash[struct_pairs]
130
+ Google::Apis::BigqueryV2::QueryParameterValue.new struct_values: struct_values
131
+ else
132
+ # Everything else is converted to a string, per the API expectations.
133
+ Google::Apis::BigqueryV2::QueryParameterValue.new value: json_value.to_s
134
+ end
135
+ end
222
136
 
223
- return Google::Apis::BigqueryV2::QueryParameter.new(
224
- parameter_type: Google::Apis::BigqueryV2::QueryParameterType.new(
225
- type: "STRUCT",
226
- struct_types: struct_pairs.map(&:first)
227
- ),
228
- parameter_value: Google::Apis::BigqueryV2::QueryParameterValue.new(
229
- struct_values: struct_values
230
- )
137
+ def self.to_query_param_type type
138
+ case type
139
+ when Array
140
+ Google::Apis::BigqueryV2::QueryParameterType.new(
141
+ type: "ARRAY".freeze,
142
+ array_type: to_query_param_type(type.first)
143
+ )
144
+ when Hash
145
+ Google::Apis::BigqueryV2::QueryParameterType.new(
146
+ type: "STRUCT".freeze,
147
+ struct_types: type.map do |key, val|
148
+ Google::Apis::BigqueryV2::QueryParameterType::StructType.new(
149
+ name: String(key),
150
+ type: to_query_param_type(val)
151
+ )
152
+ end
231
153
  )
232
154
  else
233
- raise "A query parameter of type #{value.class} is not supported."
155
+ Google::Apis::BigqueryV2::QueryParameterType.new type: type.to_s.freeze
234
156
  end
235
157
  end
236
158
 
237
- ##
238
- # @private
239
- def self.to_json_value value
159
+ # rubocop:disable Lint/DuplicateBranch
160
+ # rubocop:disable Metrics/CyclomaticComplexity
161
+ # rubocop:disable Style/GuardClause
162
+
163
+ def self.default_query_param_type_for param
164
+ raise ArgumentError, "nil params are not supported, must assign optional type" if param.nil?
165
+
166
+ case param
167
+ when String
168
+ :STRING
169
+ when Symbol
170
+ :STRING
171
+ when TrueClass
172
+ :BOOL
173
+ when FalseClass
174
+ :BOOL
175
+ when Integer
176
+ :INT64
177
+ when BigDecimal
178
+ :NUMERIC
179
+ when Numeric
180
+ :FLOAT64
181
+ when ::Time
182
+ :TIMESTAMP
183
+ when Bigquery::Time
184
+ :TIME
185
+ when DateTime
186
+ :DATETIME
187
+ when Date
188
+ :DATE
189
+ when Array
190
+ if param.empty?
191
+ raise ArgumentError, "Cannot determine type for empty array values"
192
+ end
193
+ non_nil_values = param.compact.map { |p| default_query_param_type_for p }.compact
194
+ if non_nil_values.empty?
195
+ raise ArgumentError, "Cannot determine type for array of nil values"
196
+ end
197
+ if non_nil_values.uniq.count > 1
198
+ raise ArgumentError, "Cannot determine type for array of different types of values"
199
+ end
200
+ [non_nil_values.first]
201
+ when Hash
202
+ param.transform_values do |value|
203
+ default_query_param_type_for value
204
+ end
205
+ else
206
+ if param.respond_to?(:read) && param.respond_to?(:rewind)
207
+ :BYTES
208
+ else
209
+ raise "A query parameter of type #{param.class} is not supported"
210
+ end
211
+ end
212
+ end
213
+
214
+ # rubocop:enable Lint/DuplicateBranch
215
+ # rubocop:enable Metrics/CyclomaticComplexity
216
+ # rubocop:enable Style/GuardClause
217
+
218
+ def self.to_json_value value, type = nil
240
219
  if DateTime === value
241
220
  value.strftime "%Y-%m-%d %H:%M:%S.%6N"
242
221
  elsif Date === value
@@ -245,28 +224,47 @@ module Google
245
224
  value.strftime "%Y-%m-%d %H:%M:%S.%6N%:z"
246
225
  elsif Bigquery::Time === value
247
226
  value.value
227
+ elsif BigDecimal === value
228
+ if value.finite?
229
+ # Round to precision of 9 unless explicit `BIGNUMERIC`
230
+ bigdecimal = type == :BIGNUMERIC ? value : value.round(9)
231
+ bigdecimal.to_s "F"
232
+ else
233
+ value.to_s
234
+ end
248
235
  elsif value.respond_to?(:read) && value.respond_to?(:rewind)
249
236
  value.rewind
250
- Base64.strict_encode64(value.read.force_encoding("ASCII-8BIT"))
237
+ Base64.strict_encode64 value.read.force_encoding("ASCII-8BIT")
251
238
  elsif Array === value
252
- value.map { |v| to_json_value v }
239
+ type = extract_array_type type
240
+ value.map { |x| to_json_value x, type }
253
241
  elsif Hash === value
254
- Hash[value.map { |k, v| [k.to_s, to_json_value(v)] }]
242
+ Hash[value.map { |k, v| [k.to_s, to_json_value(v, type)] }]
255
243
  else
256
244
  value
257
245
  end
258
246
  end
259
247
 
260
- # rubocop:enable all
248
+ def self.to_query_param param, type = nil
249
+ type ||= default_query_param_type_for param
261
250
 
262
- ##
263
- # @private
264
- def self.to_json_rows rows
265
- rows.map { |row| to_json_row row }
251
+ Google::Apis::BigqueryV2::QueryParameter.new(
252
+ parameter_type: to_query_param_type(type),
253
+ parameter_value: to_query_param_value(param, type)
254
+ )
266
255
  end
267
256
 
268
257
  ##
269
- # @private
258
+ # Lists are specified by providing the type code in an array. For example, an array of integers are specified as
259
+ # `[:INT64]`. Extracts the symbol.
260
+ def self.extract_array_type type
261
+ return nil if type.nil?
262
+ unless type.is_a?(Array) && type.count == 1 && type.first.is_a?(Symbol)
263
+ raise ArgumentError, "types Array #{type.inspect} should include only a single symbol element."
264
+ end
265
+ type.first
266
+ end
267
+
270
268
  def self.to_json_row row
271
269
  Hash[row.map { |k, v| [k.to_s, to_json_value(v)] }]
272
270
  end
@@ -278,8 +276,6 @@ module Google
278
276
  end
279
277
 
280
278
  ##
281
- # @private
282
- #
283
279
  # Converts create disposition strings to API values.
284
280
  #
285
281
  # @return [String] API representation of create disposition.
@@ -298,8 +294,6 @@ module Google
298
294
  end
299
295
 
300
296
  ##
301
- # @private
302
- #
303
297
  # Converts write disposition strings to API values.
304
298
  #
305
299
  # @return [String] API representation of write disposition.
@@ -320,8 +314,6 @@ module Google
320
314
  end
321
315
 
322
316
  ##
323
- # @private
324
- #
325
317
  # Converts source format strings to API values.
326
318
  #
327
319
  # @return [String] API representation of source format.
@@ -335,15 +327,15 @@ module Google
335
327
  "parquet" => "PARQUET",
336
328
  "datastore" => "DATASTORE_BACKUP",
337
329
  "backup" => "DATASTORE_BACKUP",
338
- "datastore_backup" => "DATASTORE_BACKUP"
330
+ "datastore_backup" => "DATASTORE_BACKUP",
331
+ "ml_tf_saved_model" => "ML_TF_SAVED_MODEL",
332
+ "ml_xgboost_booster" => "ML_XGBOOST_BOOSTER"
339
333
  }[format.to_s.downcase]
340
334
  return val unless val.nil?
341
335
  format
342
336
  end
343
337
 
344
338
  ##
345
- # @private
346
- #
347
339
  # Converts file paths into source format by extension.
348
340
  #
349
341
  # @return [String] API representation of source format.
@@ -354,8 +346,6 @@ module Google
354
346
  end
355
347
 
356
348
  ##
357
- # @private
358
- #
359
349
  # Converts file path into source format by extension.
360
350
  #
361
351
  # @return [String] API representation of source format.
@@ -370,8 +360,6 @@ module Google
370
360
  end
371
361
 
372
362
  ##
373
- # @private
374
- #
375
363
  # Converts a primitive time value in milliseconds to a Ruby Time object.
376
364
  #
377
365
  # @return [Time, nil] The Ruby Time object, or nil if the given argument
@@ -382,19 +370,15 @@ module Google
382
370
  end
383
371
 
384
372
  ##
385
- # @private
386
- #
387
373
  # Converts a Ruby Time object to a primitive time value in milliseconds.
388
374
  #
389
375
  # @return [Integer, nil] The primitive time value in milliseconds, or
390
376
  # nil if the given argument is nil.
391
377
  def self.time_to_millis time_obj
392
378
  return nil unless time_obj
393
- (time_obj.to_i * 1000) + (time_obj.nsec / 1000000)
379
+ (time_obj.to_i * 1000) + (time_obj.nsec / 1_000_000)
394
380
  end
395
381
  end
396
-
397
- # rubocop:enable Metrics/ModuleLength
398
382
  end
399
383
  end
400
384
  end