Example #1
0
def rb_post():
    """
    Создание нового справочника
    :return:
    """
    j = flask.request.get_json()
    rb = RefBookRegistry.create(j)
    return rb.meta
Example #2
0
def migrate_from_v1():
    def blocks(iterable, max_size=2000):
        result = []
        i = 0
        for item in iterable:
            result.append(item)
            i += 1
            if i >= max_size:
                yield result
                result = []
                i = 0
        if result:
            yield result

    def get_field_codes(collection):
        codes = set()
        for row in collection.find():
            codes |= set(row.keys())
        codes.discard('_id')
        return codes

    parser = argparse.ArgumentParser()
    parser.add_argument('--all',
                        action='store_const',
                        const=True,
                        default=False)
    parser.add_argument('--host', default=None)
    parser.add_argument('--port', default=None)
    parser.add_argument('--from-db', default='vesta')
    parser.add_argument('--db', default=nvesta_db)

    args = parser.parse_args(sys.argv[1:])

    mongo = pymongo.MongoClient(
        host=args.host,
        port=args.port,
    )

    RefBookRegistry.bootstrap(mongo[args.db])

    db_vesta = mongo[args.from_db]
    RefBookRegistry.bootstrap(mongo[args.db])

    processed_dicts = {'dict_names'}
    processed_dicts.update(set(RefBookRegistry.names()))

    for v_description in db_vesta['dict_names'].find():
        code = v_description.get('code')
        if code in processed_dicts:
            continue
        v_collection = db_vesta[code]
        count = v_collection.count()

        print 'Transferring', str(count).rjust(6), code

        primary_link = None
        linked = v_description.get('linked')
        if linked:
            primary_link = {
                'left_field': linked['origin_field'],
                'right_field': linked['linked_field'],
                'right_rb': linked['collection']['code'],
            }

        rb = RefBookRegistry.create({
            'code':
            code,
            'name':
            v_description.get('name') or code,
            'description':
            v_description.get('description'),
            'oid':
            v_description.get('oid'),
            'fields': [{
                'key': fc,
                'mandatory': fc == 'code',
            } for fc in sorted(get_field_codes(v_collection))],
            'primary_link':
            primary_link,
            'version':
            safe_traverse(v_description, 'version', 'version', default=None)
        })

        for block in blocks(v_collection.find()):
            rb.save_bulk(rb.record_factory(raw) for raw in block)

        processed_dicts.add(code)

    for code in db_vesta.collection_names(False):
        if code in processed_dicts:
            continue

        v_collection = db_vesta[code]
        count = v_collection.count()

        print 'Transferring', str(count).rjust(6), code

        rb = RefBookRegistry.create({
            'code':
            code,
            'name':
            code,
            'description':
            '',
            'oid':
            '',
            'fields': [{
                'key': fc,
                'mandatory': fc == 'code',
            } for fc in sorted(get_field_codes(v_collection))],
            'primary_link':
            None,
        })

        for block in blocks(v_collection.find()):
            rb.save_bulk(rb.record_factory(raw) for raw in block)

    RefBookRegistry.bootstrap(mongo[args.db])
Example #3
0
def import_nsi_dict(nsi_dict, nsi_client):
    code = nsi_dict['code']
    name = nsi_dict['name']

    with log_context(['nsi', 'import']) as log:
        log.log(u'Импорт {0} ({1})'.format(name, code))
        log.tags.add(code)

        try:
            # Пытаемся понять, какая версия справочника нынче актуальна
            latest_version = prepare_dictionary(
                nsi_client.getVersionList(code)[-1])
            latest_version['date'] = datetime.strptime(latest_version['date'],
                                                       '%d.%m.%Y')
        except (IndexError, ValueError), e:
            # Не получилось. С позором ретируемся.
            log.tags.add('import error')
            log.error(u'Ошибка получения версии ({0}): {1}'.format(code, e))
            return

        try:
            # Есть два варианта: либо справочник есть...
            rb = RefBookRegistry.get(code)
        except KeyError:
            # ...либо его надо создать.
            rb = RefBookRegistry.create({
                'code':
                nsi_dict.get('code', nsi_dict.get('id')),
                'name':
                nsi_dict.get('name', nsi_dict.get('code', nsi_dict.get('id'))),
                'description':
                nsi_dict.get('description'),
                'oid':
                nsi_dict.get('oid'),
            })

        my_version = rb.meta.version
        their_version = latest_version['version']

        def dump_documents(docs):
            log.log(u'Начинаем обновление данных...')
            documents = map(prepare_dictionary, docs)
            log.log(u'Новых/изменённых записей: %s' % len(documents))
            # Сперва меняем (при необходимости) структуру справочника
            names = set()
            for doc in documents:
                names.update(set(doc.iterkeys()))
            own_names = set(field.key for field in rb.meta.fields)
            new_names = names - own_names
            all_names = names | own_names
            if new_names:
                # Новые столбцы появились, надо добавить
                log.log(u'Структура справочника изменилась. Решейпим...')
                for key in new_names:
                    rb.meta.fields.append(FieldMeta(key=key))
                rb.meta.reshape()

            key_names = (key
                         for key in ('identcode', 'code', 'id', 'recid', 'oid')
                         if key in all_names)
            for key in key_names:
                rb.collection.create_index(key, sparse=True)

            log.log(u'Добавляем/обновляем записи...')
            documents_to_save = []
            for doc in documents:
                existing = None
                for key in key_names:
                    if key in doc:
                        existing = rb.find_one({key: doc[key]})
                        if existing:  # Нечего по сто тыщ раз искать одно и то же
                            break
                if not existing:
                    existing = rb.record_factory()
                existing.update(doc)
                documents_to_save.append(existing)
            log.log(u'Сбрасываем записи в БД...')
            rb.save_bulk(documents_to_save)

        if not my_version:
            log.log(u'Локальный справочник не имеет версии, создаётся')
            parts_number = nsi_client.get_parts_number(code, their_version)
            log.log(u'Ответ получен. Всего частей: %s' % parts_number)
            for i in xrange(parts_number or 0):
                log.log(u'Запрашиваем часть %s / %s' % (i + 1, parts_number))
                request_result = nsi_client.get_parts_data(
                    code, their_version, i + 1)
                log.log(u'Ответ получен. Разбираем...')
                dump_documents(doc for doc in request_result if doc)
            log.log(u'Разобрано')
        elif my_version and my_version != their_version:
            log.log(u'Локальная версия справочника: {0}'.format(my_version))
            log.log(
                u'Актуальная версия справочника: {0}'.format(their_version))
            log.log(u'Версии не совпадают, обновляем diff...')
            request_result = nsi_client.getRefbookUpdate(
                code=code, user_version=my_version)
            log.log(u'Ответ получен. Разбираем...')
            dump_documents(doc for doc in request_result if doc)
            log.log(u'Разобрано')
        else:
            log.log(u'Локальная версия справочника: {0}'.format(my_version))
            log.log(
                u'Актуальная версия справочника: {0}'.format(their_version))
            log.log(u'Версии совпадают, не обновляем справочник')
            return