@@ -59,6 +59,10 @@ class Data < DelegateClass(::Array)
5959 # @private The Google API Client object in JSON Hash.
6060 attr_accessor :gapi_json
6161
62+ ##
63+ # @private The query Job gapi object, or nil if from Table#data.
64+ attr_accessor :job_gapi
65+
6266 # @private
6367 def initialize arr = [ ]
6468 @service = nil
@@ -195,6 +199,130 @@ def headers
195199 schema . headers
196200 end
197201
202+ ##
203+ # The type of query statement, if valid. Possible values (new values
204+ # might be added in the future):
205+ #
206+ # * "CREATE_MODEL": DDL statement, see [Using Data Definition Language
207+ # Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
208+ # * "CREATE_TABLE": DDL statement, see [Using Data Definition Language
209+ # Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
210+ # * "CREATE_TABLE_AS_SELECT": DDL statement, see [Using Data Definition
211+ # Language Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
212+ # * "CREATE_VIEW": DDL statement, see [Using Data Definition Language
213+ # Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
214+ # * "DELETE": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
215+ # * "DROP_MODEL": DDL statement, see [Using Data Definition Language
216+ # Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
217+ # * "DROP_TABLE": DDL statement, see [Using Data Definition Language
218+ # Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
219+ # * "DROP_VIEW": DDL statement, see [Using Data Definition Language
220+ # Statements](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language)
221+ # * "INSERT": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
222+ # * "MERGE": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
223+ # * "SELECT": SQL query, see [Standard SQL Query Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax)
224+ # * "UPDATE": DML statement, see [Data Manipulation Language Syntax](https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax)
225+ #
226+ # @return [String, nil] The type of query statement.
227+ #
228+ def statement_type
229+ return nil unless job_gapi && job_gapi . statistics . query
230+ job_gapi . statistics . query . statement_type
231+ end
232+
233+ ##
234+ # Whether the query that created this data was a DDL statement.
235+ #
236+ # @see https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language
237+ # Using Data Definition Language Statements
238+ #
239+ # @return [Boolean]
240+ #
241+ # @example
242+ # require "google/cloud/bigquery"
243+ #
244+ # bigquery = Google::Cloud::Bigquery.new
245+ # data = bigquery.query "CREATE TABLE my_table (x INT64)"
246+ #
247+ # data.statement_type #=> "CREATE_TABLE"
248+ # data.ddl? #=> true
249+ #
250+ def ddl?
251+ %w[ CREATE_MODEL CREATE_TABLE CREATE_TABLE_AS_SELECT CREATE_VIEW \
252+ DROP_MODEL DROP_TABLE DROP_VIEW ] . include? statement_type
253+ end
254+
255+ ##
256+ # Whether the query that created this data was a DML statement.
257+ #
258+ # @see https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax
259+ # Data Manipulation Language Syntax
260+ #
261+ # @return [Boolean]
262+ #
263+ # @example
264+ # require "google/cloud/bigquery"
265+ #
266+ # bigquery = Google::Cloud::Bigquery.new
267+ # data = bigquery.query "UPDATE my_table " \
268+ # "SET x = x + 1 " \
269+ # "WHERE x IS NOT NULL"
270+ #
271+ # data.statement_type #=> "UPDATE"
272+ # data.dml? #=> true
273+ #
274+ def dml?
275+ %w[ INSERT UPDATE MERGE DELETE ] . include? statement_type
276+ end
277+
278+ ##
279+ # The DDL operation performed, possibly dependent on the pre-existence
280+ # of the DDL target. (See {#ddl_target_table}.) Possible values (new
281+ # values might be added in the future):
282+ #
283+ # * "CREATE": The query created the DDL target.
284+ # * "SKIP": No-op. Example cases: the query is
285+ # `CREATE TABLE IF NOT EXISTS` while the table already exists, or the
286+ # query is `DROP TABLE IF EXISTS` while the table does not exist.
287+ # * "REPLACE": The query replaced the DDL target. Example case: the
288+ # query is `CREATE OR REPLACE TABLE`, and the table already exists.
289+ # * "DROP": The query deleted the DDL target.
290+ #
291+ # @return [String, nil] The DDL operation performed.
292+ #
293+ def ddl_operation_performed
294+ return nil unless job_gapi && job_gapi . statistics . query
295+ job_gapi . statistics . query . ddl_operation_performed
296+ end
297+
298+ ##
299+ # The DDL target table, in reference state. (See {Table#reference?}.)
300+ # Present only for `CREATE/DROP TABLE/VIEW` queries. (See
301+ # {#statement_type}.)
302+ #
303+ # @return [Google::Cloud::Bigquery::Table, nil] The DDL target table, in
304+ # reference state.
305+ #
306+ def ddl_target_table
307+ return nil unless job_gapi && job_gapi . statistics . query
308+ ensure_service!
309+ table = job_gapi . statistics . query . ddl_target_table
310+ return nil unless table
311+ Google ::Cloud ::Bigquery ::Table . new_reference_from_gapi table , service
312+ end
313+
314+ ##
315+ # The number of rows affected by a DML statement. Present only for DML
316+ # statements `INSERT`, `UPDATE` or `DELETE`. (See {#statement_type}.)
317+ #
318+ # @return [Integer, nil] The number of rows affected by a DML statement,
319+ # or `nil` if the query is not a DML statement.
320+ #
321+ def num_dml_affected_rows
322+ return nil unless job_gapi && job_gapi . statistics . query
323+ job_gapi . statistics . query . num_dml_affected_rows
324+ end
325+
198326 ##
199327 # Whether there is a next page of data.
200328 #
@@ -252,7 +380,7 @@ def next
252380 @table_gapi . table_reference . dataset_id ,
253381 @table_gapi . table_reference . table_id ,
254382 token : token
255- self . class . from_gapi_json data_json , @table_gapi , @service
383+ self . class . from_gapi_json data_json , @table_gapi , job_gapi , @service
256384 end
257385
258386 ##
@@ -327,13 +455,16 @@ def all request_limit: nil
327455
328456 ##
329457 # @private New Data from a response object.
330- def self . from_gapi_json gapi_json , table_gapi , service
331- formatted_rows = Convert . format_rows ( gapi_json [ :rows ] ,
332- table_gapi . schema . fields )
458+ def self . from_gapi_json gapi_json , table_gapi , job_gapi , service
459+ rows = gapi_json [ :rows ] || [ ]
460+ unless rows . empty?
461+ rows = Convert . format_rows rows , table_gapi . schema . fields
462+ end
333463
334- data = new formatted_rows
464+ data = new rows
335465 data . table_gapi = table_gapi
336466 data . gapi_json = gapi_json
467+ data . job_gapi = job_gapi
337468 data . service = service
338469 data
339470 end
0 commit comments