예제 #1
0
    def handle (self, *args, **options):
        session.bind.echo = options['debug']
        filepath = options['filepath']

        model_info = {}

        with open(filepath, 'r') as data_file:
            content = ''.join(line.split('//')[0] for line in data_file)
            full_data = json.loads(content, object_pairs_hook = OrderedDict)

        for data_block in full_data:
            Model = get_model(data_block['application'], data_block['Model'])
            unique_indexes = {}

            # Prepare indeces of unique-constraints.
            for table in Model.__mapper__.tables:
                for constraint in table.constraints:
                    if isinstance(constraint, UniqueConstraint):
                        unique_indexes[constraint] = set()

            for datum in data_block['data']:
                datum = prepare(session, Model, datum)
                update_target = None

                for constraint, index in unique_indexes.items():
                    # Look for item in index.
                    key = key_from_constraint(constraint, datum)
                    if key in index:
                        self.stderr.write("ERROR: Second import of '{}' " +
                            "record with unique constraint:".format(Model))
                        for column, value in zip(constraint.columns, key):
                            self.stderr.write("       {} = {}".format(
                                column, value))
                        return

                    # Look for item in database.
                    target = session.query(Model).filter(
                        *filter_from_constraint(constraint, datum)).scalar()
                    if update_target and update_target != target:
                        self.stderr.write('ERROR: Second unique-index match does not yield the same model.')
                        self.stderr.write("       Model: {}".format(Model))
                        self.stderr.write("       constraint: {}".format(constraint))
                        self.stderr.write("       data: {}".format(datum))
                        return
                    update_target = target

                if update_target:
                    updated = False
                    for field, value in datum.items():
                        if getattr(update_target, field) != value:
                            updated = True
                            setattr(update_target, field, value)
                    if updated:
                        self.stdout.write("updating {}".format(update_target))
                else:
                    model = Model(**datum)
                    session.add(model)
                    self.stdout.write("adding {}".format(model))

            session.flush()

        session.commit()
예제 #2
0
def update_character_summary (request, id):
    character = session.query(Character).get(int(id))

    response = storyteller_or_editing_owner(request, character, 'edit')
    if response:
        return response

    chronicle_ids = [c.id for c in character.chronicle.all_chronicles]
    affected_traits = set()
    data = json.loads(request.body.decode('ascii'))

    for key, value in data.items():
        column = Character.__table__.columns[key]

        if len(column.foreign_keys) == 0:
            old_value = getattr(character, key)
            new_value = value

            # TODO (Emery): Check rules for character_summary attributes. (Name, last_edited, ...)

        else:
            TraitType = get_referenced_model(column)

            key = key[:-3]  # assumes key in format "<key>_id"
            old_value = getattr(character, key)
            new_value = None if value is None else session.query(TraitType).get(value)

            if old_value:
                changing_trait_ids = (old_value.id,)
            else:
                changing_trait_ids = tuple()
            if new_value:
                changing_trait_ids += (new_value.id,)

            # Rule: character-has-trait
            for rule in session.query(CharacterHasTrait).filter(
                CharacterHasTrait.chronicle_id.in_(chronicle_ids),
                CharacterHasTrait.other_trait_id.in_(changing_trait_ids)
            ):
                affected_traits.add(rule.trait)

            # Rule: character-does-not-have-trait
            for rule in session.query(CharacterDoesNotHaveTrait).filter(
                CharacterDoesNotHaveTrait.chronicle_id.in_(chronicle_ids),
                CharacterDoesNotHaveTrait.other_trait_id.in_(changing_trait_ids)
            ):
                affected_traits.add(rule.trait)

        # Set attribute on character.
        setattr(character, key, new_value)

    session.flush()

    # Recalculate availabilities for affected traits.
    availabilities = calculate_availabilities(character, affected_traits)

    return JsonResponse(
        {
            'character': character,
            'availabilities': availabilities,
        },
        encoder = ModelEncoder
    )