def get_individuals_by_variant(variant_id):
    """
    Return variants that have been called in an individual
    """
    db_session = orm.get_session()

    try:
        var = db_session.query(orm.models.Variant)\
            .filter(orm.models.Variant.id == variant_id)\
            .one_or_none()
    except orm.ORMException as e:
        err = _report_search_failed('variant', e, variant_id=variant_id)
        return err, 500

    if not var:
        err = Error(message="No variant found: "+str(variant_id), code=404)
        return err, 404

    try:
        individuals = [call.individual for call in var.calls
                       if call.individual is not None]
    except orm.ORMException as e:
        err = _report_search_failed('individuals', e, by_variant_id=variant_id)
        return err, 500

    return [orm.dump(i) for i in individuals], 200
def put_individual(individual_id, individual):
    """
    Update a single individual by individual id (in URL)
    and new api.models.Invididual object (passed in body)
    """
    db_session = orm.get_session()
    try:
        q = db_session.query(Individual).get(individual_id)
    except orm.ORMException as e:
        err = _report_search_failed('individual', e, ind_id=str(individual_id))
        return err, 500

    if not q:
        err = Error(message="No individual found: "+str(individual_id), code=404)
        return err, 404

    if 'id' in individual:
        del individual['id']
    if 'created' in individual:
        del individual['created']

    individual['updated'] = datetime.datetime.utcnow()

    try:
        row = db_session.query(Individual).filter(Individual.id == individual_id).first()
        for key in individual:
            setattr(row, key, individual[key])
        db_session.commit()
    except orm.ORMException as e:
        err = _report_update_failed('individual', e, ind_id=str(individual_id))
        return err, 500

    return None, 204, {'Location': BASEPATH+'/individuals/'+str(individual_id)}
def get_variants_by_individual(individual_id):
    """
    Return variants that have been called in an individual
    """
    db_session = orm.get_session()
    ind_id = individual_id

    try:
        ind = db_session.query(orm.models.Individual)\
            .filter(orm.models.Individual.id == ind_id)\
            .one_or_none()
    except orm.ORMException as e:
        err = _report_search_failed('individual', e, individual_id=individual_id)
        return err, 500

    if not ind:
        err = Error(message="No individual found: "+str(ind_id), code=404)
        return err, 404

    try:
        variants = [call.variant for call in ind.calls if call.variant]
    except orm.ORMException as e:
        err = _report_search_failed('variants', e, by_individual_id=individual_id)
        return err, 500

    return [orm.dump(v) for v in variants], 200
def put_call(call_id, call):
    """
    Update a single individual by call id (in URL)
    and new Call api dict (passed in body)
    """
    db_session = orm.get_session()
    try:
        q = db_session.query(Call).get(call_id)
    except orm.ORMException as e:
        err = _report_search_failed('call', e, call_id=str(call_id))
        return err, 500

    if not q:
        err = Error(message="No call found: "+str(call_id), code=404)
        return err, 404

    if 'id' in call:
        del call['id']
    if 'created' in call:
        del call['created']

    call['updated'] = datetime.datetime.utcnow()

    try:
        row = db_session.query(Individual).filter(Call.id == call_id).first()
        for key in call:
            setattr(row, key, call[key])
        db_session.commit()
    except orm.ORMException as e:
        err = _report_update_failed('call', e, call_id=str(call_id))
        return err, 500

    return None, 204, {'Location': '/calls/'+str(call_id)}
def put_variant(variant_id, variant):
    """
    Update a single variant by variant id (in URL)
    and new Variant dict object (passed in body)
    """
    db_session = orm.get_session()
    try:
        q = db_session.query(Variant).get(variant_id)
    except orm.ORMException as e:
        err = _report_search_failed('variant', e, var_id=str(variant_id))
        return err, 500

    if not q:
        err = Error(message="No variant found: "+str(variant_id), code=404)
        return err, 404

    if 'id' in variant:
        del variant['id']
    if 'created' in variant:
        del variant['created']

    variant['updated'] = datetime.datetime.utcnow()

    try:
        row = db_session.query(Variant).filter(Variant.id == variant_id).first()
        for key in variant:
            setattr(row, key, variant[key])
        db_session.commit()
    except orm.ORMException as e:
        err = _report_update_failed('variant', e, var_id=str(variant_id))
        return err, 500

    return None, 204, {'Location': BASEPATH+'/individuals/'+str(variant_id)}
def _report_object_exists(typename, **kwargs):
    """
    Generate standard log message + request error for warning:
    Trying to POST an object that already exists

    :param typename: name of type involved
    :param **kwargs: arbitrary keyword parameters
    :return: Connexion Error() type to return
    """
    report = typename + ': Attempt to modify with a POST'
    message = 'Attempt to modify '+typename+' with a POST'
    logger().warning(struct_log(action=report, **kwargs))
    return Error(message=message, code=405)
def _report_conversion_error(typename, exception, **kwargs):
    """
    Generate standard log message + request error for warning:
    Trying to POST an object that already exists

    :param typename: name of type involved
    :param exception: exception thrown by ORM
    :param **kwargs: arbitrary keyword parameters
    :return: Connexion Error() type to return
    """
    report = 'Could not convert '+typename+' to ORM model'
    message = typename + ': failed validation - could not convert to internal representation'
    logger().error(struct_log(action=report, exception=str(exception), **kwargs))
    return Error(message=message, code=400)
def _report_update_failed(typename, exception, **kwargs):
    """
    Generate standard log message + request error for error:
    Internal error performing update (PUT)

    :param typename: name of type involved
    :param exception: exception thrown by ORM
    :param **kwargs: arbitrary keyword parameters
    :return: Connexion Error() type to return
    """
    report = typename + ' updated failed'
    message = 'Internal error updating '+typename+'s'
    logger().error(struct_log(action=report, exception=str(exception), **kwargs))
    return Error(message=message, code=500)
def _report_write_error(typename, exception, **kwargs):
    """
    Generate standard log message + request error for error:
    Error writing to DB

    :param typename: name of type involved
    :param exception: exception thrown by ORM
    :param **kwargs: arbitrary keyword parameters
    :return: Connexion Error() type to return
    """
    report = 'Internal error writing '+typename+' to DB'
    message = typename + ': internal error saving ORM object to DB'
    logger().error(struct_log(action=report, exception=str(exception), **kwargs))
    err = Error(message=message, code=500)
    return err
def get_one_call(call_id):
    """
    Return single call object
    """
    try:
        q = Call().query.get(call_id)
    except Error as e:
        err = _report_search_failed('call', e, call_id=str(call_id))
        return err, 500

    if not q:
        err = Error(message="No call found: "+str(call_id), code=404)
        return err, 404

    return orm.dump(q), 200
def get_one_individual(individual_id):
    """
    Return single individual object
    """
    try:
        q = Individual().query.get(individual_id)
    except orm.ORMException as e:
        err = _report_search_failed('individual', e, ind_id=str(individual_id))
        return err, 500

    if not q:
        err = Error(message="No individual found: "+str(individual_id), code=404)
        return err, 404

    return orm.dump(q), 200
def get_one_variant(variant_id):
    """
    Return single variant object
    """
    db_session = orm.get_session()
    try:
        q = db_session.query(models.Variant).get(variant_id)
    except orm.ORMException as e:
        err = _report_search_failed('variant', e, var_id=str(variant_id))
        return err, 500

    if not q:
        err = Error(message="No variant found: "+str(variant_id), code=404)
        return err, 404

    return orm.dump(q), 200
def delete_call(call_id):
    """
    Delete a single call by call id (in URL)
    """
    db_session = orm.get_session()
    try:
        q = db_session.query(Call).get(call_id)
    except orm.ORMException as e:
        err = _report_search_failed('call', e, call_id=str(call_id))
        return err, 500

    if not q:
        err = Error(message="No call found: "+str(call_id), code=404)
        return err, 404

    try:
        row = db_session.query(Call).filter(Call.id == call_id).first()
        db_session.delete(row)
        db_session.commit()
    except orm.ORMException as e:
        err = _report_update_failed('call', e, call_id=str(call_id))
        return err, 500

    return None, 204, {'Location': BASEPATH+'/calls/'+str(call_id)}
def delete_individual(individual_id):
    """
    Delete a single individual by individual id (in URL)
    """
    db_session = orm.get_session()
    try:
        q = db_session.query(Individual).get(individual_id)
    except orm.ORMException as e:
        err = _report_search_failed('individual', e, ind_id=str(individual_id))
        return err, 500

    if not q:
        err = Error(message="No individual found: "+str(individual_id), code=404)
        return err, 404

    try:
        row = db_session.query(Individual).filter(Individual.id == individual_id).first()
        db_session.delete(row)
        db_session.commit()
    except orm.ORMException as e:
        err = _report_update_failed('individual', e, ind_id=str(individual_id))
        return err, 500

    return None, 204, {'Location': BASEPATH+'/individuals/'+str(individual_id)}