google-cloud-bigquery 1.24.0 → 1.29.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -215,6 +215,17 @@ module Google
215
215
  @gapi.statistics.parent_job_id
216
216
  end
217
217
 
218
+ ##
219
+ # An array containing the job resource usage breakdown by reservation, if present. Reservation usage statistics
220
+ # are only reported for jobs that are executed within reservations. On-demand jobs do not report this data.
221
+ #
222
+ # @return [Array<Google::Cloud::Bigquery::Job::ReservationUsage>, nil] The reservation usage, if present.
223
+ #
224
+ def reservation_usage
225
+ return nil unless @gapi.statistics.reservation_usage
226
+ Array(@gapi.statistics.reservation_usage).map { |g| ReservationUsage.from_gapi g }
227
+ end
228
+
218
229
  ##
219
230
  # The statistics including stack frames for a child job of a script.
220
231
  #
@@ -489,6 +500,30 @@ module Google
489
500
  end
490
501
  end
491
502
 
503
+ ##
504
+ # Represents Job resource usage breakdown by reservation.
505
+ #
506
+ # @attr_reader [String] name The reservation name or "unreserved" for on-demand resources usage.
507
+ # @attr_reader [Fixnum] slot_ms The slot-milliseconds the job spent in the given reservation.
508
+ #
509
+ class ReservationUsage
510
+ attr_reader :name
511
+ attr_reader :slot_ms
512
+
513
+ ##
514
+ # @private Creates a new ReservationUsage instance.
515
+ def initialize name, slot_ms
516
+ @name = name
517
+ @slot_ms = slot_ms
518
+ end
519
+
520
+ ##
521
+ # @private New ReservationUsage from a statistics.reservation_usage value.
522
+ def self.from_gapi gapi
523
+ new gapi.name, gapi.slot_ms
524
+ end
525
+ end
526
+
492
527
  ##
493
528
  # Represents statistics for a child job of a script.
494
529
  #
@@ -537,7 +572,8 @@ module Google
537
572
  # end
538
573
  #
539
574
  class ScriptStatistics
540
- attr_reader :evaluation_kind, :stack_frames
575
+ attr_reader :evaluation_kind
576
+ attr_reader :stack_frames
541
577
 
542
578
  ##
543
579
  # @private Creates a new ScriptStatistics instance.
@@ -547,7 +583,7 @@ module Google
547
583
  end
548
584
 
549
585
  ##
550
- # @private New ScriptStatistics from a statistics.script_statistics object.
586
+ # @private New ScriptStatistics from a statistics.script_statistics value.
551
587
  def self.from_gapi gapi
552
588
  frames = Array(gapi.stack_frames).map { |g| ScriptStackFrame.from_gapi g }
553
589
  new gapi.evaluation_kind, frames
@@ -602,7 +638,11 @@ module Google
602
638
  # end
603
639
  #
604
640
  class ScriptStackFrame
605
- attr_reader :start_line, :start_column, :end_line, :end_column, :text
641
+ attr_reader :start_line
642
+ attr_reader :start_column
643
+ attr_reader :end_line
644
+ attr_reader :end_column
645
+ attr_reader :text
606
646
 
607
647
  ##
608
648
  # @private Creates a new ScriptStackFrame instance.
@@ -72,8 +72,8 @@ module Google
72
72
  return nil unless next?
73
73
  ensure_service!
74
74
  next_kwargs = @kwargs.merge token: token
75
- next_gapi = @service.list_jobs next_kwargs
76
- self.class.from_gapi next_gapi, @service, next_kwargs
75
+ next_gapi = @service.list_jobs(**next_kwargs)
76
+ self.class.from_gapi next_gapi, @service, **next_kwargs
77
77
  end
78
78
 
79
79
  ##
@@ -121,12 +121,12 @@ module Google
121
121
  # puts job.state
122
122
  # end
123
123
  #
124
- def all request_limit: nil
124
+ def all request_limit: nil, &block
125
125
  request_limit = request_limit.to_i if request_limit
126
126
  return enum_for :all, request_limit: request_limit unless block_given?
127
127
  results = self
128
128
  loop do
129
- results.each { |r| yield r }
129
+ results.each(&block)
130
130
  if request_limit
131
131
  request_limit -= 1
132
132
  break if request_limit.negative?
@@ -37,8 +37,8 @@ module Google
37
37
  # bigquery = Google::Cloud::Bigquery.new
38
38
  # dataset = bigquery.dataset "my_dataset"
39
39
  #
40
- # gs_url = "gs://my-bucket/file-name.csv"
41
- # load_job = dataset.load_job "my_new_table", gs_url do |schema|
40
+ # gcs_uri = "gs://my-bucket/file-name.csv"
41
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |schema|
42
42
  # schema.string "first_name", mode: :required
43
43
  # schema.record "cities_lived", mode: :repeated do |nested_schema|
44
44
  # nested_schema.string "place", mode: :required
@@ -112,8 +112,7 @@ module Google
112
112
  # `false` otherwise.
113
113
  #
114
114
  def iso8859_1?
115
- val = @gapi.configuration.load.encoding
116
- val == "ISO-8859-1"
115
+ @gapi.configuration.load.encoding == "ISO-8859-1"
117
116
  end
118
117
 
119
118
  ##
@@ -195,8 +194,7 @@ module Google
195
194
  # `NEWLINE_DELIMITED_JSON`, `false` otherwise.
196
195
  #
197
196
  def json?
198
- val = @gapi.configuration.load.source_format
199
- val == "NEWLINE_DELIMITED_JSON"
197
+ @gapi.configuration.load.source_format == "NEWLINE_DELIMITED_JSON"
200
198
  end
201
199
 
202
200
  ##
@@ -218,8 +216,27 @@ module Google
218
216
  # `false` otherwise.
219
217
  #
220
218
  def backup?
221
- val = @gapi.configuration.load.source_format
222
- val == "DATASTORE_BACKUP"
219
+ @gapi.configuration.load.source_format == "DATASTORE_BACKUP"
220
+ end
221
+
222
+ ##
223
+ # Checks if the source format is ORC.
224
+ #
225
+ # @return [Boolean] `true` when the source format is `ORC`,
226
+ # `false` otherwise.
227
+ #
228
+ def orc?
229
+ @gapi.configuration.load.source_format == "ORC"
230
+ end
231
+
232
+ ##
233
+ # Checks if the source format is Parquet.
234
+ #
235
+ # @return [Boolean] `true` when the source format is `PARQUET`,
236
+ # `false` otherwise.
237
+ #
238
+ def parquet?
239
+ @gapi.configuration.load.source_format == "PARQUET"
223
240
  end
224
241
 
225
242
  ##
@@ -347,6 +364,58 @@ module Google
347
364
  nil
348
365
  end
349
366
 
367
+ ###
368
+ # Checks if hive partitioning options are set.
369
+ #
370
+ # @see https://cloud.google.com/bigquery/docs/hive-partitioned-loads-gcs Loading externally partitioned data
371
+ #
372
+ # @return [Boolean] `true` when hive partitioning options are set, or `false` otherwise.
373
+ #
374
+ # @!group Attributes
375
+ #
376
+ def hive_partitioning?
377
+ !@gapi.configuration.load.hive_partitioning_options.nil?
378
+ end
379
+
380
+ ###
381
+ # The mode of hive partitioning to use when reading data. The following modes are supported:
382
+ #
383
+ # 1. `AUTO`: automatically infer partition key name(s) and type(s).
384
+ # 2. `STRINGS`: automatically infer partition key name(s). All types are interpreted as strings.
385
+ # 3. `CUSTOM`: partition key schema is encoded in the source URI prefix.
386
+ #
387
+ # @see https://cloud.google.com/bigquery/docs/hive-partitioned-loads-gcs Loading externally partitioned data
388
+ #
389
+ # @return [String, nil] The mode of hive partitioning, or `nil` if not set.
390
+ #
391
+ # @!group Attributes
392
+ #
393
+ def hive_partitioning_mode
394
+ @gapi.configuration.load.hive_partitioning_options.mode if hive_partitioning?
395
+ end
396
+
397
+ ###
398
+ # The common prefix for all source uris when hive partition detection is requested. The prefix must end
399
+ # immediately before the partition key encoding begins. For example, consider files following this data layout:
400
+ #
401
+ # ```
402
+ # gs://bucket/path_to_table/dt=2019-01-01/country=BR/id=7/file.avro
403
+ # gs://bucket/path_to_table/dt=2018-12-31/country=CA/id=3/file.avro
404
+ # ```
405
+ #
406
+ # When hive partitioning is requested with either `AUTO` or `STRINGS` mode, the common prefix can be either of
407
+ # `gs://bucket/path_to_table` or `gs://bucket/path_to_table/` (trailing slash does not matter).
408
+ #
409
+ # @see https://cloud.google.com/bigquery/docs/hive-partitioned-loads-gcs Loading externally partitioned data
410
+ #
411
+ # @return [String, nil] The common prefix for all source uris, or `nil` if not set.
412
+ #
413
+ # @!group Attributes
414
+ #
415
+ def hive_partitioning_source_uri_prefix
416
+ @gapi.configuration.load.hive_partitioning_options.source_uri_prefix if hive_partitioning?
417
+ end
418
+
350
419
  ###
351
420
  # Checks if the destination table will be range partitioned. See [Creating and using integer range partitioned
352
421
  # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
@@ -537,6 +606,7 @@ module Google
537
606
  ##
538
607
  # @private Create an Updater object.
539
608
  def initialize gapi
609
+ super()
540
610
  @updates = []
541
611
  @gapi = gapi
542
612
  @schema = nil
@@ -1326,6 +1396,89 @@ module Google
1326
1396
  @gapi.configuration.update! labels: val
1327
1397
  end
1328
1398
 
1399
+ ##
1400
+ # Sets the mode of hive partitioning to use when reading data. The following modes are supported:
1401
+ #
1402
+ # 1. `auto`: automatically infer partition key name(s) and type(s).
1403
+ # 2. `strings`: automatically infer partition key name(s). All types are interpreted as strings.
1404
+ # 3. `custom`: partition key schema is encoded in the source URI prefix.
1405
+ #
1406
+ # Not all storage formats support hive partitioning. Requesting hive partitioning on an unsupported format
1407
+ # will lead to an error. Currently supported types include: `avro`, `csv`, `json`, `orc` and `parquet`.
1408
+ #
1409
+ # See {#format=} and {#hive_partitioning_source_uri_prefix=}.
1410
+ #
1411
+ # @see https://cloud.google.com/bigquery/docs/hive-partitioned-loads-gcs Loading externally partitioned data
1412
+ #
1413
+ # @param [String, Symbol] mode The mode of hive partitioning to use when reading data.
1414
+ #
1415
+ # @example
1416
+ # require "google/cloud/bigquery"
1417
+ #
1418
+ # bigquery = Google::Cloud::Bigquery.new
1419
+ # dataset = bigquery.dataset "my_dataset"
1420
+ #
1421
+ # gcs_uri = "gs://cloud-samples-data/bigquery/hive-partitioning-samples/autolayout/*"
1422
+ # source_uri_prefix = "gs://cloud-samples-data/bigquery/hive-partitioning-samples/autolayout/"
1423
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1424
+ # job.format = :parquet
1425
+ # job.hive_partitioning_mode = :auto
1426
+ # job.hive_partitioning_source_uri_prefix = source_uri_prefix
1427
+ # end
1428
+ #
1429
+ # load_job.wait_until_done!
1430
+ # load_job.done? #=> true
1431
+ #
1432
+ # @!group Attributes
1433
+ #
1434
+ def hive_partitioning_mode= mode
1435
+ @gapi.configuration.load.hive_partitioning_options ||= Google::Apis::BigqueryV2::HivePartitioningOptions.new
1436
+ @gapi.configuration.load.hive_partitioning_options.mode = mode.to_s.upcase
1437
+ end
1438
+
1439
+ ##
1440
+ # Sets the common prefix for all source uris when hive partition detection is requested. The prefix must end
1441
+ # immediately before the partition key encoding begins. For example, consider files following this data
1442
+ # layout:
1443
+ #
1444
+ # ```
1445
+ # gs://bucket/path_to_table/dt=2019-01-01/country=BR/id=7/file.avro
1446
+ # gs://bucket/path_to_table/dt=2018-12-31/country=CA/id=3/file.avro
1447
+ # ```
1448
+ #
1449
+ # When hive partitioning is requested with either `AUTO` or `STRINGS` mode, the common prefix can be either of
1450
+ # `gs://bucket/path_to_table` or `gs://bucket/path_to_table/` (trailing slash does not matter).
1451
+ #
1452
+ # See {#hive_partitioning_mode=}.
1453
+ #
1454
+ # @see https://cloud.google.com/bigquery/docs/hive-partitioned-loads-gcs Loading externally partitioned data
1455
+ #
1456
+ # @param [String] source_uri_prefix The common prefix for all source uris.
1457
+ #
1458
+ # @example
1459
+ # require "google/cloud/bigquery"
1460
+ #
1461
+ # bigquery = Google::Cloud::Bigquery.new
1462
+ # dataset = bigquery.dataset "my_dataset"
1463
+ #
1464
+ # gcs_uri = "gs://cloud-samples-data/bigquery/hive-partitioning-samples/autolayout/*"
1465
+ # source_uri_prefix = "gs://cloud-samples-data/bigquery/hive-partitioning-samples/autolayout/"
1466
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1467
+ # job.format = :parquet
1468
+ # job.hive_partitioning_mode = :auto
1469
+ # job.hive_partitioning_source_uri_prefix = source_uri_prefix
1470
+ # end
1471
+ #
1472
+ # load_job.wait_until_done!
1473
+ # load_job.done? #=> true
1474
+ #
1475
+ # @!group Attributes
1476
+ #
1477
+ def hive_partitioning_source_uri_prefix= source_uri_prefix
1478
+ @gapi.configuration.load.hive_partitioning_options ||= Google::Apis::BigqueryV2::HivePartitioningOptions.new
1479
+ @gapi.configuration.load.hive_partitioning_options.source_uri_prefix = source_uri_prefix
1480
+ end
1481
+
1329
1482
  ##
1330
1483
  # Sets the field on which to range partition the table. See [Creating and using integer range partitioned
1331
1484
  # tables](https://cloud.google.com/bigquery/docs/creating-integer-range-partitions).
@@ -1345,8 +1498,8 @@ module Google
1345
1498
  # bigquery = Google::Cloud::Bigquery.new
1346
1499
  # dataset = bigquery.dataset "my_dataset"
1347
1500
  #
1348
- # gs_url = "gs://my-bucket/file-name.csv"
1349
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1501
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1502
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1350
1503
  # job.schema do |schema|
1351
1504
  # schema.integer "my_table_id", mode: :required
1352
1505
  # schema.string "my_table_data", mode: :required
@@ -1386,8 +1539,8 @@ module Google
1386
1539
  # bigquery = Google::Cloud::Bigquery.new
1387
1540
  # dataset = bigquery.dataset "my_dataset"
1388
1541
  #
1389
- # gs_url = "gs://my-bucket/file-name.csv"
1390
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1542
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1543
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1391
1544
  # job.schema do |schema|
1392
1545
  # schema.integer "my_table_id", mode: :required
1393
1546
  # schema.string "my_table_data", mode: :required
@@ -1427,8 +1580,8 @@ module Google
1427
1580
  # bigquery = Google::Cloud::Bigquery.new
1428
1581
  # dataset = bigquery.dataset "my_dataset"
1429
1582
  #
1430
- # gs_url = "gs://my-bucket/file-name.csv"
1431
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1583
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1584
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1432
1585
  # job.schema do |schema|
1433
1586
  # schema.integer "my_table_id", mode: :required
1434
1587
  # schema.string "my_table_data", mode: :required
@@ -1468,8 +1621,8 @@ module Google
1468
1621
  # bigquery = Google::Cloud::Bigquery.new
1469
1622
  # dataset = bigquery.dataset "my_dataset"
1470
1623
  #
1471
- # gs_url = "gs://my-bucket/file-name.csv"
1472
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1624
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1625
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1473
1626
  # job.schema do |schema|
1474
1627
  # schema.integer "my_table_id", mode: :required
1475
1628
  # schema.string "my_table_data", mode: :required
@@ -1510,8 +1663,8 @@ module Google
1510
1663
  # bigquery = Google::Cloud::Bigquery.new
1511
1664
  # dataset = bigquery.dataset "my_dataset"
1512
1665
  #
1513
- # gs_url = "gs://my-bucket/file-name.csv"
1514
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1666
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1667
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1515
1668
  # job.time_partitioning_type = "DAY"
1516
1669
  # end
1517
1670
  #
@@ -1549,8 +1702,8 @@ module Google
1549
1702
  # bigquery = Google::Cloud::Bigquery.new
1550
1703
  # dataset = bigquery.dataset "my_dataset"
1551
1704
  #
1552
- # gs_url = "gs://my-bucket/file-name.csv"
1553
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1705
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1706
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1554
1707
  # job.time_partitioning_type = "DAY"
1555
1708
  # job.time_partitioning_field = "dob"
1556
1709
  # job.schema do |schema|
@@ -1585,8 +1738,8 @@ module Google
1585
1738
  # bigquery = Google::Cloud::Bigquery.new
1586
1739
  # dataset = bigquery.dataset "my_dataset"
1587
1740
  #
1588
- # gs_url = "gs://my-bucket/file-name.csv"
1589
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1741
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1742
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1590
1743
  # job.time_partitioning_type = "DAY"
1591
1744
  # job.time_partitioning_expiration = 86_400
1592
1745
  # end
@@ -1645,8 +1798,8 @@ module Google
1645
1798
  # bigquery = Google::Cloud::Bigquery.new
1646
1799
  # dataset = bigquery.dataset "my_dataset"
1647
1800
  #
1648
- # gs_url = "gs://my-bucket/file-name.csv"
1649
- # load_job = dataset.load_job "my_new_table", gs_url do |job|
1801
+ # gcs_uri = "gs://my-bucket/file-name.csv"
1802
+ # load_job = dataset.load_job "my_new_table", gcs_uri do |job|
1650
1803
  # job.time_partitioning_type = "DAY"
1651
1804
  # job.time_partitioning_field = "dob"
1652
1805
  # job.schema do |schema|
@@ -124,12 +124,12 @@ module Google
124
124
  # puts model.model_id
125
125
  # end
126
126
  #
127
- def all request_limit: nil
127
+ def all request_limit: nil, &block
128
128
  request_limit = request_limit.to_i if request_limit
129
129
  return enum_for :all, request_limit: request_limit unless block_given?
130
130
  results = self
131
131
  loop do
132
- results.each { |r| yield r }
132
+ results.each(&block)
133
133
  if request_limit
134
134
  request_limit -= 1
135
135
  break if request_limit.negative?
@@ -0,0 +1,432 @@
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/apis/bigquery_v2"
17
+
18
+ module Google
19
+ module Cloud
20
+ module Bigquery
21
+ ##
22
+ # # Policy
23
+ #
24
+ # Represents a Cloud IAM Policy for BigQuery resources.
25
+ #
26
+ # A Policy is a collection of bindings. A {Policy::Binding} binds one or more members to a single role. Member
27
+ # strings can describe user accounts, service accounts, Google groups, and domains. A role string represents a
28
+ # named list of permissions; each role can be an IAM predefined role or a user-created custom role.
29
+ #
30
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing Policies
31
+ # @see https://cloud.google.com/bigquery/docs/table-access-controls-intro Controlling access to tables
32
+ #
33
+ # @attr [String] etag Used to check if the policy has changed since the last request. When you make a request with
34
+ # an `etag` value, Cloud IAM compares the `etag` value in the request with the existing `etag` value associated
35
+ # with the policy. It writes the policy only if the `etag` values match.
36
+ # @attr [Array<Binding>] bindings The bindings in the policy, which may be mutable or frozen depending on the
37
+ # context. See [Understanding Roles](https://cloud.google.com/iam/docs/understanding-roles) for a list of
38
+ # primitive and curated roles. See [BigQuery Table ACL
39
+ # permissions](https://cloud.google.com/bigquery/docs/table-access-controls-intro#permissions) for a list of
40
+ # values and patterns for members.
41
+ #
42
+ # @example
43
+ # require "google/cloud/bigquery"
44
+ #
45
+ # bigquery = Google::Cloud::Bigquery.new
46
+ # dataset = bigquery.dataset "my_dataset"
47
+ # table = dataset.table "my_table"
48
+ # policy = table.policy
49
+ #
50
+ # policy.frozen? #=> true
51
+ # binding_owner = policy.bindings.find { |b| b.role == "roles/owner" }
52
+ #
53
+ # binding_owner.role #=> "roles/owner"
54
+ # binding_owner.members #=> ["user:owner@example.com"]
55
+ # binding_owner.frozen? #=> true
56
+ # binding_owner.members.frozen? #=> true
57
+ #
58
+ # @example Update mutable bindings in the policy.
59
+ # require "google/cloud/bigquery"
60
+ #
61
+ # bigquery = Google::Cloud::Bigquery.new
62
+ # dataset = bigquery.dataset "my_dataset"
63
+ # table = dataset.table "my_table"
64
+ #
65
+ # table.update_policy do |p|
66
+ # p.grant role: "roles/viewer", members: "user:viewer@example.com"
67
+ # p.revoke role: "roles/editor", members: "user:editor@example.com"
68
+ # p.revoke role: "roles/owner"
69
+ # end
70
+ #
71
+ # @example Iterate over frozen bindings.
72
+ # require "google/cloud/bigquery"
73
+ #
74
+ # bigquery = Google::Cloud::Bigquery.new
75
+ # dataset = bigquery.dataset "my_dataset"
76
+ # table = dataset.table "my_table"
77
+ # policy = table.policy
78
+ #
79
+ # policy.frozen? #=> true
80
+ # policy.bindings.each do |b|
81
+ # puts b.role
82
+ # puts b.members
83
+ # end
84
+ #
85
+ # @example Update mutable bindings.
86
+ # require "google/cloud/bigquery"
87
+ #
88
+ # bigquery = Google::Cloud::Bigquery.new
89
+ # dataset = bigquery.dataset "my_dataset"
90
+ # table = dataset.table "my_table"
91
+ #
92
+ # table.update_policy do |p|
93
+ # p.bindings.each do |b|
94
+ # b.members.delete_if { |m| m.include? "@example.com" }
95
+ # end
96
+ # end
97
+ #
98
+ class Policy
99
+ attr_reader :etag
100
+ attr_reader :bindings
101
+
102
+ # @private
103
+ def initialize etag, bindings
104
+ @etag = etag.freeze
105
+ @bindings = bindings
106
+ end
107
+
108
+ ##
109
+ # Convenience method adding or updating a binding in the policy. See [Understanding
110
+ # Roles](https://cloud.google.com/iam/docs/understanding-roles) for a list of primitive and curated roles. See
111
+ # [BigQuery Table ACL
112
+ # permissions](https://cloud.google.com/bigquery/docs/table-access-controls-intro#permissions) for a list of
113
+ # values and patterns for members.
114
+ #
115
+ # @param [String] role The role that is bound to members in the binding. For example, `roles/viewer`,
116
+ # `roles/editor`, or `roles/owner`. Required.
117
+ # @param [String, Array<String>] members Specifies the identities requesting access for a Cloud Platform
118
+ # resource. `members` can have the following values. Required.
119
+ #
120
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
121
+ # account.
122
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
123
+ # account or a service account.
124
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
125
+ # `alice@example.com`.
126
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
127
+ # `my-other-app@appspot.gserviceaccount.com`.
128
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
129
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
130
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
131
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
132
+ # binding.
133
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing
134
+ # a service account that has been recently deleted. For example,
135
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted,
136
+ # this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains the role in
137
+ # the binding.
138
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a Google
139
+ # group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the
140
+ # group is recovered, this value reverts to `group:<emailid>` and the recovered group retains the role in
141
+ # the binding.
142
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For example,
143
+ # `google.com` or `example.com`.
144
+ #
145
+ # @return [nil]
146
+ #
147
+ # @example Grant a role to a member.
148
+ # require "google/cloud/bigquery"
149
+ #
150
+ # bigquery = Google::Cloud::Bigquery.new
151
+ # dataset = bigquery.dataset "my_dataset"
152
+ # table = dataset.table "my_table"
153
+ #
154
+ # table.update_policy do |p|
155
+ # p.grant role: "roles/viewer", members: "user:viewer@example.com"
156
+ # end
157
+ #
158
+ def grant role:, members:
159
+ existing_binding = bindings.find { |b| b.role == role }
160
+ if existing_binding
161
+ existing_binding.members.concat Array(members)
162
+ existing_binding.members.uniq!
163
+ else
164
+ bindings << Binding.new(role, members)
165
+ end
166
+ nil
167
+ end
168
+
169
+ ##
170
+ # Convenience method for removing a binding or bindings from the policy. See
171
+ # [Understanding Roles](https://cloud.google.com/iam/docs/understanding-roles) for a list of primitive and
172
+ # curated roles. See [BigQuery Table ACL
173
+ # permissions](https://cloud.google.com/bigquery/docs/table-access-controls-intro#permissions) for a list of
174
+ # values and patterns for members.
175
+ #
176
+ # @param [String] role A role that is bound to members in the policy. For example, `roles/viewer`,
177
+ # `roles/editor`, or `roles/owner`. Optional.
178
+ # @param [String, Array<String>] members Specifies the identities receiving access for a Cloud Platform
179
+ # resource. `members` can have the following values. Optional.
180
+ #
181
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
182
+ # account.
183
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
184
+ # account or a service account.
185
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
186
+ # `alice@example.com`.
187
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
188
+ # `my-other-app@appspot.gserviceaccount.com`.
189
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
190
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
191
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
192
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
193
+ # binding.
194
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing
195
+ # a service account that has been recently deleted. For example,
196
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted,
197
+ # this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains the role in
198
+ # the binding.
199
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a Google
200
+ # group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the
201
+ # group is recovered, this value reverts to `group:<emailid>` and the recovered group retains the role in
202
+ # the binding.
203
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For example,
204
+ # `google.com` or `example.com`.
205
+ #
206
+ # @return [nil]
207
+ #
208
+ # @example Revoke a role for a member or members.
209
+ # require "google/cloud/bigquery"
210
+ #
211
+ # bigquery = Google::Cloud::Bigquery.new
212
+ # dataset = bigquery.dataset "my_dataset"
213
+ # table = dataset.table "my_table"
214
+ #
215
+ # table.update_policy do |p|
216
+ # p.revoke role: "roles/viewer", members: "user:viewer@example.com"
217
+ # end
218
+ #
219
+ # @example Revoke a role for all members.
220
+ # require "google/cloud/bigquery"
221
+ #
222
+ # bigquery = Google::Cloud::Bigquery.new
223
+ # dataset = bigquery.dataset "my_dataset"
224
+ # table = dataset.table "my_table"
225
+ #
226
+ # table.update_policy do |p|
227
+ # p.revoke role: "roles/viewer"
228
+ # end
229
+ #
230
+ # @example Revoke all roles for a member or members.
231
+ # require "google/cloud/bigquery"
232
+ #
233
+ # bigquery = Google::Cloud::Bigquery.new
234
+ # dataset = bigquery.dataset "my_dataset"
235
+ # table = dataset.table "my_table"
236
+ #
237
+ # table.update_policy do |p|
238
+ # p.revoke members: ["user:viewer@example.com", "user:editor@example.com"]
239
+ # end
240
+ #
241
+ def revoke role: nil, members: nil
242
+ bindings_for_role = role ? bindings.select { |b| b.role == role } : bindings
243
+ bindings_for_role.each do |b|
244
+ if members
245
+ b.members -= Array(members)
246
+ bindings.delete b if b.members.empty?
247
+ else
248
+ bindings.delete b
249
+ end
250
+ end
251
+ nil
252
+ end
253
+
254
+ ##
255
+ # @private Convert the Policy to a Google::Apis::BigqueryV2::Policy.
256
+ def to_gapi
257
+ Google::Apis::BigqueryV2::Policy.new(
258
+ bindings: bindings_to_gapi,
259
+ etag: etag,
260
+ version: 1
261
+ )
262
+ end
263
+
264
+ ##
265
+ # @private Deep freeze the policy including its bindings.
266
+ def freeze
267
+ super
268
+ @bindings.each(&:freeze)
269
+ @bindings.freeze
270
+ self
271
+ end
272
+
273
+ ##
274
+ # @private New Policy from a Google::Apis::BigqueryV2::Policy object.
275
+ def self.from_gapi gapi
276
+ bindings = Array(gapi.bindings).map do |binding|
277
+ Binding.new binding.role, binding.members.to_a
278
+ end
279
+ new gapi.etag, bindings
280
+ end
281
+
282
+ ##
283
+ # # Policy::Binding
284
+ #
285
+ # Represents a Cloud IAM Binding for BigQuery resources within the context of a {Policy}.
286
+ #
287
+ # A binding binds one or more members to a single role. Member strings can describe user accounts, service
288
+ # accounts, Google groups, and domains. A role is a named list of permissions; each role can be an IAM
289
+ # predefined role or a user-created custom role.
290
+ #
291
+ # @see https://cloud.google.com/bigquery/docs/table-access-controls-intro Controlling access to tables
292
+ #
293
+ # @attr [String] role The role that is assigned to `members`. For example, `roles/viewer`, `roles/editor`, or
294
+ # `roles/owner`. Required.
295
+ # @attr [Array<String>] members Specifies the identities requesting access for a Cloud Platform resource.
296
+ # `members` can have the following values. Required.
297
+ #
298
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
299
+ # account.
300
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
301
+ # account or a service account.
302
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
303
+ # `alice@example.com`.
304
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
305
+ # `my-other-app@appspot.gserviceaccount.com`.
306
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
307
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
308
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
309
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
310
+ # binding.
311
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing
312
+ # a service account that has been recently deleted. For example,
313
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is undeleted,
314
+ # this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains the role in
315
+ # the binding.
316
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a Google
317
+ # group that has been recently deleted. For example, `admins@example.com?uid=123456789012345678901`. If the
318
+ # group is recovered, this value reverts to `group:<emailid>` and the recovered group retains the role in
319
+ # the binding.
320
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For example,
321
+ # `google.com` or `example.com`.
322
+ #
323
+ # @example
324
+ # require "google/cloud/bigquery"
325
+ #
326
+ # bigquery = Google::Cloud::Bigquery.new
327
+ # dataset = bigquery.dataset "my_dataset"
328
+ # table = dataset.table "my_table"
329
+ #
330
+ # policy = table.policy
331
+ # binding_owner = policy.bindings.find { |b| b.role == "roles/owner" }
332
+ #
333
+ # binding_owner.role #=> "roles/owner"
334
+ # binding_owner.members #=> ["user:owner@example.com"]
335
+ #
336
+ # binding_owner.frozen? #=> true
337
+ # binding_owner.members.frozen? #=> true
338
+ #
339
+ # @example Update mutable bindings.
340
+ # require "google/cloud/bigquery"
341
+ #
342
+ # bigquery = Google::Cloud::Bigquery.new
343
+ # dataset = bigquery.dataset "my_dataset"
344
+ # table = dataset.table "my_table"
345
+ #
346
+ # table.update_policy do |p|
347
+ # binding_owner = p.bindings.find { |b| b.role == "roles/owner" }
348
+ # binding_owner.members.delete_if { |m| m.include? "@example.com" }
349
+ # end
350
+ #
351
+ class Binding
352
+ attr_accessor :role
353
+ attr_reader :members
354
+
355
+ # @private
356
+ def initialize role, members
357
+ members = Array(members).uniq
358
+ raise ArgumentError, "members cannot be empty" if members.empty?
359
+ @role = role
360
+ @members = members
361
+ end
362
+
363
+ ##
364
+ # Sets the binding members.
365
+ #
366
+ # @param [Array<String>] new_members Specifies the identities requesting access for a Cloud Platform resource.
367
+ # `new_members` can have the following values. Required.
368
+ #
369
+ # * `allUsers`: A special identifier that represents anyone who is on the internet; with or without a Google
370
+ # account.
371
+ # * `allAuthenticatedUsers`: A special identifier that represents anyone who is authenticated with a Google
372
+ # account or a service account.
373
+ # * `user:<emailid>`: An email address that represents a specific Google account. For example,
374
+ # `alice@example.com`.
375
+ # * `serviceAccount:<emailid>`: An email address that represents a service account. For example,
376
+ # `my-other-app@appspot.gserviceaccount.com`.
377
+ # * `group:<emailid>`: An email address that represents a Google group. For example, `admins@example.com`.
378
+ # * `deleted:user:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a user
379
+ # that has been recently deleted. For example, `alice@example.com?uid=123456789012345678901`. If the user
380
+ # is recovered, this value reverts to `user:<emailid>` and the recovered user retains the role in the
381
+ # binding.
382
+ # * `deleted: serviceAccount:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier)
383
+ # representing a service account that has been recently deleted. For example,
384
+ # `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. If the service account is
385
+ # undeleted, this value reverts to `serviceAccount:<emailid>` and the undeleted service account retains
386
+ # the role in the binding.
387
+ # * `deleted:group:<emailid>?uid=<uniqueid>`: An email address (plus unique identifier) representing a
388
+ # Google group that has been recently deleted. For example,
389
+ # `admins@example.com?uid=123456789012345678901`. If the group is recovered, this value reverts to
390
+ # `group:<emailid>` and the recovered group retains the role in the binding.
391
+ # * `domain:<domain>`: The G Suite domain (primary) that represents all the users of that domain. For
392
+ # example, `google.com` or `example.com`.
393
+ #
394
+ def members= new_members
395
+ @members = Array(new_members).uniq
396
+ end
397
+
398
+ ##
399
+ # @private Convert the Binding to a Google::Apis::BigqueryV2::Binding.
400
+ def to_gapi
401
+ Google::Apis::BigqueryV2::Binding.new role: role, members: members
402
+ end
403
+
404
+ ##
405
+ # @private Deep freeze the policy including its members.
406
+ def freeze
407
+ super
408
+ role.freeze
409
+ members.each(&:freeze)
410
+ members.freeze
411
+ self
412
+ end
413
+
414
+ ##
415
+ # @private New Binding from a Google::Apis::BigqueryV2::Binding object.
416
+ def self.from_gapi gapi
417
+ new gapi.etag, gapi.members.to_a
418
+ end
419
+ end
420
+
421
+ protected
422
+
423
+ def bindings_to_gapi
424
+ @bindings.compact.uniq.map do |b|
425
+ next if b.members.empty?
426
+ b.to_gapi
427
+ end
428
+ end
429
+ end
430
+ end
431
+ end
432
+ end