def METHOD_NAME(self) -> Iterator[Dict[str, Any]]:
    response = self.execute_query()
    workbooks_data = [workbook for workbook in response['workbooks']
                      if workbook['projectName'] not in
                      self._conf.get_list(TableauGraphQLDashboardTableExtractor.EXCLUDED_PROJECTS, [])]
    for workbook in workbooks_data:
        if None in (workbook['projectName'], workbook['name']):
            LOGGER.warning(f'Ignoring workbook (ID:{workbook["vizportalUrlId"]}) ' +
                           f'in project (ID:{workbook["projectVizportalUrlId"]}) because of a lack of permission')
            continue
        data = {
            'dashboard_group_id': workbook['projectName'],
            'dashboard_id': TableauDashboardUtils.sanitize_workbook_name(workbook['name']),
            'cluster': self._conf.get_string(TableauGraphQLDashboardTableExtractor.CLUSTER),
            'table_ids': []
        }
        for table in workbook['upstreamTables']:
            if table['name'] is None:
                LOGGER.warning(f'Ignoring a table in workbook (ID:{workbook["name"]}) ' +
                               f'in project (ID:{workbook["projectName"]}) because of a lack of permission')
                continue
            # external tables have no schema, so they must be parsed differently
            # see TableauExternalTableExtractor for more specifics
            if table['schema'] != '':
                cluster = self._conf.get_string(TableauGraphQLDashboardTableExtractor.CLUSTER)
                database = self._conf.get_string(TableauGraphQLDashboardTableExtractor.DATABASE)
                # Tableau sometimes incorrectly assigns the "schema" value
                # based on how the datasource connection is used in a workbook.
                # It will hide the real schema inside the table name, like "real_schema.real_table",
                # and set the "schema" value to "wrong_schema". In every case discovered so far, the schema
                # key is incorrect, so the "inner" schema from the table name is used instead.
                if '.' in table['name']:
                    parts = table['name'].split('.')
                    if len(parts) == 2:
                        schema, name = parts
                    else:
                        database = '.'.join(parts[:-2])
                        schema, name = parts[-2:]
                else:
                    schema, name = table['schema'], table['name']
                schema = TableauDashboardUtils.sanitize_schema_name(schema)
                name = TableauDashboardUtils.sanitize_table_name(name)
            else:
                cluster = self._conf.get_string(TableauGraphQLDashboardTableExtractor.EXTERNAL_CLUSTER_NAME)
                database = TableauDashboardUtils.sanitize_database_name(
                    table['database']['connectionType']
                )
                schema = TableauDashboardUtils.sanitize_schema_name(table['database']['name'])
                name = TableauDashboardUtils.sanitize_table_name(table['name'])
            table_id = TableMetadata.TABLE_KEY_FORMAT.format(
                db=database,
                cluster=cluster,
                schema=schema,
                tbl=name,
            )
            data['table_ids'].append(table_id)
        yield data