Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions bigquery/cloud-client/grantAccessToDataset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

/**
* Grants access to a BigQuery dataset for a specified entity.
*
* @param {string} datasetId ID of the dataset to grant access to.
* @param {string} entityId ID of the entity to grant access to.
* @param {string} role Role to grant.
* @returns {Promise<Array>} Array of access entries.
*/
async function grantAccessToDataset(datasetId, entityId, role) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we typically write the Node samples so that there is an inner function and an outer function, where the outer function exposes arguments that are passed through to the inner function.

// [START bigquery_grant_access_to_dataset]
const {BigQuery} = require('@google-cloud/bigquery');

// Define enum for HTTP codes.
const HTTP_STATUS = {
PRECONDITION_FAILED: 412,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: can we use a library here instead of defining our own constant? Maybe something from the gRPC library for Node?

};

// TODO(developer): Update and un-comment below lines.
Comment thread
telpirion marked this conversation as resolved.
Outdated

// ID of the dataset to revoke access to.
// datasetId = "my_project_id.my_dataset_name";

// ID of the user or group from whom you are adding access.
// Alternatively, the JSON REST API representation of the entity,
// such as a view's table reference.
// entityId = "user-or-group-to-add@example.com";

// One of the "Basic roles for datasets" described here:
// https://cloud.google.com/bigquery/docs/access-control-basic-roles#dataset-basic-roles
// role = "READER";

// Type of entity you are granting access to.
// Find allowed allowed entity type names here:
// https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets#resource:-dataset
// In this case, we're using groupByEmail
const entityType = 'groupByEmail';

// Instantiate a client.
const client = new BigQuery();

try {
// Get a reference to the dataset.
const [dataset] = await client.dataset(datasetId).get();

// The 'access entries' array is immutable. Create a copy for modifications.
const entries = Array.isArray(dataset.metadata.access)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: don't use ternary conditions in samples, as they are harder to read.

The condition that we're testing is "is dataset.metadata.access an array?" I think we can assume that it is an array, since it is returned by the API service.

? [...dataset.metadata.access]
: [];

// Append an AccessEntry to grant the role to a dataset.
// Find more details about the AccessEntry object in the BigQuery documentation:
// https://cloud.google.com/python/docs/reference/bigquery/latest/google.cloud.bigquery.dataset.AccessEntry
entries.push({
role: role,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can shorten this operation to just

entries.push({
    role,
    [entityType]: entityId,
})

[entityType]: entityId,
});

// Assign the array of AccessEntries back to the dataset.
const metadata = {
access: entries,
};

// Update will only succeed if the dataset
// has not been modified externally since retrieval.
//
// See the BigQuery client library documentation for more details on metadata updates:
// https://cloud.google.com/nodejs/docs/reference/bigquery/latest

// Update just the 'access entries' property of the dataset.
const [updatedDataset] = await client
.dataset(datasetId)
.setMetadata(metadata);

// Show a success message.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: cut this comment, as it doesn't add any significant new information to what the code does.

console.log(
`Role '${role}' granted for entity '${entityId}' in dataset '${datasetId}'.`
);

return updatedDataset.access;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: process results from the method call in the sample.

See: https://googlecloudplatform.github.io/samples-style-guide/#result

} catch (error) {
if (error.code === HTTP_STATUS.PRECONDITION_FAILED) {
console.error(
`Dataset '${datasetId}' was modified remotely before this update. ` +
'Fetch the latest version and retry.'
);
Comment thread
telpirion marked this conversation as resolved.
Outdated
} else {
throw error;
}
}
// [END bigquery_grant_access_to_dataset]
}

module.exports = {
grantAccessToDataset,
};
95 changes: 95 additions & 0 deletions bigquery/cloud-client/grantAccessToTableOrView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

/**
* Grants access to a BigQuery table or view for a specified principal.
*
* @param {string} projectId Google Cloud Platform project ID.
* @param {string} datasetId Dataset where the table or view is.
* @param {string} resourceName Table or view name to get the access policy.
* @param {string} principalId The principal requesting access to the table or view.
* @param {string} role Role to assign to the member.
* @returns {Promise<object[]>} The updated policy bindings.
*/
async function grantAccessToTableOrView(
projectId,
datasetId,
resourceName,
principalId,
role
) {
// [START bigquery_grant_access_to_table_or_view]
const {BigQuery} = require('@google-cloud/bigquery');

// TODO(developer): Update and un-comment below lines.
Comment thread
telpirion marked this conversation as resolved.
Outdated

// Google Cloud Platform project.
// projectId = "my_project_id"

// Dataset where the table or view is.
// datasetId = "my_dataset_id"

// Table or view name to get the access policy.
// resourceName = "my_table_id"

// The principal requesting access to the table or view.
// Find more details about principal identifiers here:
// https://cloud.google.com/iam/docs/principal-identifiers
// principalId = "user:bob@example.com"

// Role to assign to the member.
// role = "roles/bigquery.dataViewer"

// Instantiate a client.
const client = new BigQuery();

// Get a reference to the dataset by datasetId.
const dataset = client.dataset(datasetId);
// Get a reference to the table by tableName.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: insert space between getting the dataset and the comment about getting the table.

In fact, I think you can remove both comments, as the intention of the code is clear.

See https://googlecloudplatform.github.io/samples-style-guide/#comments

const table = dataset.table(resourceName);

// Get the IAM access policy for the table or view.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: include a link to the IAM policies for tables, for example https://cloud.google.com/bigquery/docs/access-control.

const [policy] = await table.getIamPolicy();

// Initialize bindings array.
if (!policy.bindings) {
policy.bindings = [];
}

// To grant access to a table or view
// add bindings to the Table or View policy.
//
// Find more details about Policy and Binding objects here:
// https://cloud.google.com/security-command-center/docs/reference/rest/Shared.Types/Policy
// https://cloud.google.com/security-command-center/docs/reference/rest/Shared.Types/Binding
const binding = {
role: role,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: as above, you can use shorthand property name here.

members: [principalId],
};
policy.bindings.push(binding);

// Set the IAM access policy with updated bindings.
const [updatedPolicy] = await table.setIamPolicy(policy);

// Show a success message.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: remove comment.

console.log(
`Role '${role}' granted for principal '${principalId}' on resource '${datasetId}.${resourceName}'.`
);
// [END bigquery_grant_access_to_table_or_view]
return updatedPolicy.bindings;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: same as above -- samples shouldn't return a result.

}

module.exports = {grantAccessToTableOrView};
26 changes: 26 additions & 0 deletions bigquery/cloud-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "bigquery-cloud-client",
"description": "Big Query Cloud Client Node.js samples",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google LLC",
"engines": {
"node": "20.x"
},
"scripts": {
"deploy": "gcloud app deploy",
"start": "node app.js",
"unit-test": "c8 mocha -p -j 2 test/ --timeout=10000 --exit",
"test": "npm run unit-test"
},
"dependencies": {
"@google-cloud/bigquery": "7.9.2"
},
"devDependencies": {
"c8": "^10.0.0",
"chai": "^4.5.0",
"mocha": "^10.0.0",
"sinon": "^18.0.0"
}
}
Loading