in api/v1/src/datasets/dataManager.js [509:607]
async function createView(view, overrideSql) {
let viewSql = overrideSql;
try {
if (!viewSql) {
viewSql = await sqlBuilder.generateSql(view);
}
const bigqueryUtil = new BigQueryUtil(view.projectId);
let metadataResult = await bigqueryUtil.getTableMetadata(view.datasetId, view.name);
let viewMetadata = metadataResult.metadata;
const viewExists = metadataResult.exists;
let createViewResult;
let configuredExpirationTime = view.expiration && view.expiration.delete === true ? view.expiration.time : null;
let viewDescription = `This view was generated by ${cfg.productName}. ${view.description}`;
let labels = {
[cfg.cdsManagedLabelKey]: true,
[cfg.googPackagedSolutionKey] : cfg.googPackagedSolutionValue
};
const viewOptions = {
description: viewDescription,
labels: labels,
expirationTime: configuredExpirationTime
};
if (viewExists === true) {
console.log("View '%s' already exists, checking if it's up to date", view.name);
const viewDefinition = viewMetadata.view.query;
if (viewSql.replace("\n", "") === viewDefinition.replace("\n", "")) {
console.log("SQL text is identitical");
}
else {
console.log(`SQL text is different, need to re-create view\nView Definition:\n${viewDefinition}\n\nConfig SQL:\n${viewSql}`);
createViewResult = await bigqueryUtil.createView(view.datasetId, view.name, viewSql, viewOptions, true);
if (createViewResult.success === false) {
console.log("Failed to create view, skipping to next view");
return { isValid: false, success: false };
}
else {
// If view is deleted and recreated we need to refresh metadata
viewMetadata = createViewResult.metadata;
}
}
const currentExpiryTime = viewMetadata.expirationTime;
console.log(`configuredExpirationTime is ${configuredExpirationTime}, expirationTime for view '${view.name}' is ${currentExpiryTime}`);
// Update expirationTime for view
// Deleting the property doesn't remove it from metadata, setting it to null removes it
if (configuredExpirationTime != currentExpiryTime) {
console.log(`Configured expirationTime is different than the value for view '${view.name}'`);
viewMetadata.expirationTime = configuredExpirationTime;
await bigqueryUtil.setTableMetadata(view.datasetId, view.name, viewMetadata);
}
}
else {
createViewResult = await bigqueryUtil.createView(view.datasetId, view.name, viewSql, viewOptions, true);
}
let viewCreated = createViewResult && createViewResult.success;
console.log("Authorizing view objects for access from other datasets");
// https://github.com/GoogleCloudPlatform/datashare-toolkit/issues/655
if (view.accessControl && view.accessControl.enabled === true && cfg.cdsDatasetId !== view.datasetId) {
await bigqueryUtil.shareAuthorizeView(cfg.cdsDatasetId, view.projectId, view.datasetId, view.name, viewCreated);
}
if (Object.prototype.hasOwnProperty.call(view, 'source') && view.source !== null) {
let source = view.source;
// https://github.com/GoogleCloudPlatform/datashare-toolkit/pull/409
// Before table-level access was allowed, it wasn't valid to authorize a view within the same dataset, as if you have
// access to a dataset, you would have access to all of its objects.
// Now that table-level access is available, there are cases where a user does not have dataset-level access,
// but have access to one or more tables or views, in which case authorizing views at the dataset level is required
// if and when selecting data from another object within the same dataset for which a user does not have direct permission.
await bigqueryUtil.shareAuthorizeView(source.datasetId, view.projectId, view.datasetId, view.name, viewCreated);
}
else if (Object.prototype.hasOwnProperty.call(view, 'custom') && view.custom !== null) {
// Custom sql
let custom = view.custom;
if (custom.authorizeFromDatasetIds && custom.authorizeFromDatasetIds.length > 0) {
for (const d of view.custom.authorizeFromDatasetIds) {
await bigqueryUtil.shareAuthorizeView(d, view.projectId, view.datasetId, view.name, viewCreated);
}
}
}
return { success: true, data: {} };
}
catch (err) {
console.error(`Failed to create view: ${JSON.stringify(view)} - ${JSON.stringify(err)}`);
return { success: false, code: 500, errors: [err.message] };
}
}