def _get_violations(self, query, record):
        """Reverse-engineer the query to figure out why a record was selected.

        :param query: MongoDB query
        :type query: MongQuery
        :param record: Record in question
        :type record: dict
        :return: Reasons why bad
        :rtype: list(ConstraintViolation)
        """
        # special case, when no constraints are given
        if len(query.all_clauses) == 0:
            return [NullConstraintViolation()]
        # normal case, check all the constraints
        reasons = []
        for clause in query.all_clauses:
            var_name = None
            key = clause.constraint.field.name
            op = clause.constraint.op
            fval = mongo_get(record, key)
            if fval is None:
                expected = clause.constraint.value
                reasons.append(ConstraintViolation(clause.constraint, 'missing', expected))
                continue
            if op.is_variable():
                # retrieve value for variable
                var_name = clause.constraint.value
                value = mongo_get(record, var_name, default=None)
                if value is None:
                    reasons.append(ConstraintViolation(clause.constraint, 'missing', var_name))
                    continue
                clause.constraint.value = value         # swap out value, temporarily
            # take length for size
            if op.is_size():
                if isinstance(fval, str) or not hasattr(fval, '__len__'):
                    reasons.append(ConstraintViolation(clause.constraint, type(fval), 'sequence'))
                    if op.is_variable():
                        clause.constraint.value = var_name      # put original value back
                    continue
                fval = len(fval)
            ok, expected = clause.constraint.passes(fval)
            if not ok:
                reasons.append(ConstraintViolation(clause.constraint, fval, expected))
            if op.is_variable():
                clause.constraint.value = var_name      # put original value back
        return reasons
Reverse-engineer the query to figure out why a record was selected.

        :param query: MongoDB query
        :type query: MongQuery
        :param record: Record in question
        :type record: dict
        :return: Reasons why bad
        :rtype: list(ConstraintViolation)