async function createView()

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] };
    }
}