Esempio n. 1
0
    async def _set_table_counters(self, table_name: str):
        """
        Filling table max pk and count of records
        """
        async with self._src_database.connection_pool.acquire() as connection:
            table = self._dst_database.tables[table_name]

            try:
                count_table_records_sql = (
                    SQLRepository.get_count_table_records(
                        primary_key=table.primary_key, ))
            except AttributeError as e:
                logger.warning(f'{str(e)} --- _set_table_counters {"-"*10} - '
                               f"{table.name}")
                raise AttributeError
            except UndefinedFunctionError:
                raise UndefinedFunctionError

            res = await connection.fetchrow(count_table_records_sql)

            if res and res[0] and res[1]:
                logger.debug(f"table {table_name} with full count {res[0]}, "
                             f"max pk - {res[1]}")

                table.full_count = int(res[0])

                table.max_pk = (int(res[1]) if isinstance(res[1], int) else
                                table.full_count + 100000)

            del count_table_records_sql
Esempio n. 2
0
    async def _get_table_column_values_part(
        self,
        table_column_values_sql: str,
        table_column_values: List[Union[str, int]],
    ):
        if table_column_values_sql:
            logger.debug(table_column_values_sql)

            async with self._src_database.connection_pool.acquire(
            ) as connection:  # noqa
                try:
                    table_column_values_part = await connection.fetch(
                        table_column_values_sql)  # noqa
                except (asyncpg.PostgresSyntaxError,
                        asyncpg.UndefinedColumnError) as e:
                    logger.warning(
                        f"{str(e)} --- {table_column_values_sql} --- "
                        f"_get_table_column_values_part")
                    table_column_values_part = []

                filtered_table_column_values_part = [
                    record[0] for record in table_column_values_part
                    if record[0] is not None
                ]

                table_column_values.extend(filtered_table_column_values_part)

                del table_column_values_part
                del table_column_values_sql
Esempio n. 3
0
    async def _direct_recursively_preparing_table_chunk(
        self,
        table: DBTable,
        need_transfer_pks_chunk: List[int],
        stack_tables: Optional[Set[DBTable]] = None,
    ):
        """
        Recursively preparing table
        """

        logger.debug(make_str_from_iterable([t.name for t in stack_tables]))

        coroutines = [
            asyncio.create_task(
                self._direct_recursively_preparing_foreign_table(
                    table=table,
                    column=column,
                    need_transfer_pks=need_transfer_pks_chunk,
                    stack_tables=stack_tables,
                )) for column in table.not_self_fk_columns
            if not (column.constraint_table.with_key_column
                    or column.constraint_table in stack_tables)
        ]

        if coroutines:
            await asyncio.wait(coroutines)

        del need_transfer_pks_chunk
Esempio n. 4
0
    async def _direct_recursively_preparing_foreign_table_chunk(
        self,
        table: DBTable,
        column: DBColumn,
        need_transfer_pks_chunk: Iterable[int],
        stack_tables: Set[DBTable],
    ):
        """
        Direct recursively preparing foreign table chunk
        """
        foreign_table = column.constraint_table
        foreign_table.is_checked = True

        # Если таблица с key_column, то нет необходимости пробрасывать
        # идентификаторы записей
        if table.with_key_column:
            foreign_table_pks = await self._get_table_column_values(
                table=table,
                column=column,
            )
        else:
            need_transfer_pks = (need_transfer_pks_chunk
                                 if not table.is_full_prepared else ())

            foreign_table_pks = await self._get_table_column_values(
                table=table,
                column=column,
                primary_key_values=need_transfer_pks,
            )

        # если найдены значения внешних ключей отличающиеся от null, то
        # записи из внешней талицы с этими идентификаторами должны быть
        # импортированы
        if foreign_table_pks:
            logger.debug(
                f"table - {table.name}, column - {column.name} - reversed "
                f"collecting of fk_ids ----- {foreign_table.name}")

            foreign_table_pks_difference = foreign_table_pks.difference(
                foreign_table.need_transfer_pks)

            # если есть разница между предполагаемыми записями для импорта
            # и уже выбранными ранее, то разницу нужно импортировать
            if foreign_table_pks_difference:
                foreign_table.update_need_transfer_pks(
                    need_transfer_pks=foreign_table_pks_difference, )

                await asyncio.wait([
                    asyncio.create_task(
                        self._direct_recursively_preparing_table(
                            table=foreign_table,
                            need_transfer_pks=foreign_table_pks_difference,
                            stack_tables=stack_tables,
                        )),
                ])

            del foreign_table_pks_difference

        del foreign_table_pks
        del need_transfer_pks_chunk
Esempio n. 5
0
    def is_full_prepared(self):
        logger.debug(
            f'table - {self.name} -- count table records {self.full_count} and '
            f'need transfer pks {len(self.need_transfer_pks)}')

        if len(self.need_transfer_pks
               ) >= self.full_count - self.inaccuracy_count:  # noqa
            logger.info(f'table {self.name} full transferred')

            return True
Esempio n. 6
0
    async def collect(self):
        logger.info('start preparing tables sorted by dependency..')

        not_transferred_tables = list(
            filter(
                lambda t: (not t.is_ready_for_transferring and t.name not in
                           TABLES_WITH_GENERIC_FOREIGN_KEY),
                self._dst_database.tables.values(),
            ))
        logger.debug(
            f'tables not transferring {str(len(not_transferred_tables))}')

        dependencies_between_models = []
        for table in self._dst_database.tables_without_generics:
            for fk_column in table.not_self_fk_columns:
                dependencies_between_models.append(
                    (table.name, fk_column.constraint_table.name))

        sorted_dependencies_result = topological_sort(
            dependency_pairs=dependencies_between_models, )
        sorted_dependencies_result.cyclic.reverse()
        sorted_dependencies_result.sorted.reverse()

        sorted_tables_by_dependency = (sorted_dependencies_result.cyclic +
                                       sorted_dependencies_result.sorted)

        without_relatives = list({
            table.name
            for table in self._dst_database.tables_without_generics
        }.difference(sorted_tables_by_dependency))

        sorted_tables_by_dependency = without_relatives + sorted_tables_by_dependency

        # Явно ломаю асинхронность, т.к. порядок импорта таблиц важен
        for table_name in sorted_tables_by_dependency:
            table = self._dst_database.tables[table_name]

            if not table.is_ready_for_transferring:
                await self._prepare_unready_table(table=table, )

        logger.info('preparing tables sorted by dependency finished.')
Esempio n. 7
0
    async def _prepare_content_type_generic_data(
        self,
        target_table: DBTable,
        rel_table_name: str,
    ):
        if not rel_table_name:
            logger.debug('not send rel_table_name')
            return

        rel_table = self._dst_database.tables.get(rel_table_name)

        if not rel_table:
            logger.debug(f'table {rel_table_name} not found')
            return

        object_id_column = await target_table.get_column_by_name('object_id')

        if rel_table.primary_key.data_type != object_id_column.data_type:
            logger.debug(
                f'pk of table {rel_table_name} has an incompatible data type')
            return

        logger.info('prepare content type generic data')

        where_conditions = {
            'object_id': rel_table.need_transfer_pks,
            'content_type_id': [self.content_type_table[rel_table.name]],
        }

        need_transfer_pks = await self._get_table_column_values(
            table=target_table,
            column=target_table.primary_key,
            where_conditions_columns=where_conditions,
        )

        logger.info(
            f'{target_table.name} need transfer pks {len(need_transfer_pks)}')

        target_table.update_need_transfer_pks(
            need_transfer_pks=need_transfer_pks, )

        del where_conditions
        del need_transfer_pks
Esempio n. 8
0
    async def _prepare_unready_table(
        self,
        table: DBTable,
    ):
        """
        Preparing table records for transferring
        """
        logger.info(f'start preparing table "{table.name}"')
        # обход таблиц связанных через внешние ключи
        where_conditions_columns = {}

        fk_columns = table.highest_priority_fk_columns

        with_full_transferred_table = False

        for fk_column in fk_columns:
            logger.debug(f'prepare column {fk_column.name}')
            fk_table = self._dst_database.tables[
                fk_column.constraint_table.name]

            if fk_table.need_transfer_pks:
                if not fk_table.is_full_prepared:
                    where_conditions_columns[fk_column.name] = (
                        fk_table.need_transfer_pks)
                else:
                    with_full_transferred_table = True

        if (fk_columns and not where_conditions_columns
                and not with_full_transferred_table):
            return

        table_pks = await self._get_table_column_values(
            table=table,
            column=table.primary_key,
            where_conditions_columns=where_conditions_columns,
        )

        if (fk_columns and where_conditions_columns and not table_pks):
            return

        table.update_need_transfer_pks(need_transfer_pks=table_pks, )

        logger.debug(f'table "{table.name}" need transfer pks - '
                     f'{len(table.need_transfer_pks)}')

        del table_pks

        # обход таблиц ссылающихся на текущую таблицу
        logger.debug('prepare revert tables')

        coroutines = [
            asyncio.create_task(
                self._prepare_revert_table(
                    table=table,
                    revert_table=revert_table,
                    revert_columns=revert_columns,
                )) for revert_table, revert_columns in
            table.revert_foreign_tables.items()  # noqa
        ]

        if coroutines:
            await asyncio.wait(coroutines)

        if not table.need_transfer_pks:
            all_records = await self._get_table_column_values(
                table=table,
                column=table.primary_key,
            )

            table.update_need_transfer_pks(need_transfer_pks=all_records, )

            del all_records

        table.is_ready_for_transferring = True

        logger.info(f'finished collecting records ids of table "{table.name}"')