def merge_enrollments(db, uuid, organization):
    """Merge overlapping enrollments.

    This function merges those enrollments, related to the given 'uuid' and
    'organization', that have overlapping dates. Default start and end dates
    (1900-01-01 and 2100-01-01) are considered range limits and will be
    removed when a set of ranges overlap. For example:

     * [(1900-01-01, 2010-01-01), (2008-01-01, 2100-01-01)]
           --> (2008-01-01, 2010-01-01)
     * [(1900-01-01, 2010-01-01), (2008-01-01, 2010-01-01), (2010-01-02, 2100-01-01)]
           --> (2008-01-01, 2010-01-01),(2010-01-02, 2100-01-01)
     * [(1900-01-01, 2010-01-01), (2010-01-02, 2100-01-01)]
           --> (1900-01-01, 2010-01-01), (2010-01-02, 2100-01-01)

    It may raise a InvalidValueError when any date is out of bounds. In other words, when
    any date < 1900-01-01 or date > 2100-01-01.

    :param db: database manager
    :param uuid: unique identifier
    :param organization: name of the organization

    :raises NotFoundError: when either 'uuid' or 'organization' are not
        found in the registry. It is also raised when there are not enrollments
        related to 'uuid' and 'organization'
    :raises InvalidValueError: when any date is out of bounds
    """
    # Merge enrollments
    with db.connect() as session:
        uidentity = find_unique_identity(session, uuid)

        if not uidentity:
            raise NotFoundError(entity=uuid)

        org = find_organization(session, organization)

        if not org:
            raise NotFoundError(entity=organization)

        disjoint = session.query(Enrollment).\
            filter(Enrollment.uidentity == uidentity,
                   Enrollment.organization == org).all()

        if not disjoint:
            entity = '-'.join((uuid, organization))
            raise NotFoundError(entity=entity)

        dates = [(enr.start, enr.end) for enr in disjoint]

        for st, en in utils.merge_date_ranges(dates):
            # We prefer this method to find duplicates
            # to avoid integrity exceptions when creating
            # enrollments that are already in the database
            is_dup = lambda x, st, en: x.start == st and x.end == en

            filtered = [x for x in disjoint if not is_dup(x, st, en)]

            if len(filtered) != len(disjoint):
                disjoint = filtered
                continue

            # This means no dups where found so we need to add a
            # new enrollment
            try:
                enroll_db(session, uidentity, org,
                          from_date=st, to_date=en)
            except ValueError as e:
                raise InvalidValueError(e)

        # Remove disjoint enrollments from the registry
        for enr in disjoint:
            delete_enrollment_db(session, enr)
def merge_enrollments ( db , uuid , organization ) : with db . connect ( ) as session : uidentity = find_unique_identity ( session , uuid ) if not uidentity : raise NotFoundError ( entity = uuid ) org = find_organization ( session , organization ) if not org : raise NotFoundError ( entity = organization ) disjoint = session . query ( Enrollment ) . filter ( Enrollment . uidentity == uidentity , Enrollment . organization == org ) . all ( ) if not disjoint : entity = '-' . join ( ( uuid , organization ) ) raise NotFoundError ( entity = entity ) dates = [ ( enr . start , enr . end ) for enr in disjoint ] for st , en in utils . merge_date_ranges ( dates ) : is_dup = lambda x , st , en : x . start == st and x . end == en filtered = [ x for x in disjoint if not is_dup ( x , st , en ) ] if len ( filtered ) != len ( disjoint ) : disjoint = filtered continue try : enroll_db ( session , uidentity , org , from_date = st , to_date = en ) except ValueError as e : raise InvalidValueError ( e ) for enr in disjoint : delete_enrollment_db ( session , enr )
Merge overlapping enrollments.

    This function merges those enrollments, related to the given 'uuid' and
    'organization', that have overlapping dates. Default start and end dates
    (1900-01-01 and 2100-01-01) are considered range limits and will be
    removed when a set of ranges overlap. For example:

     * [(1900-01-01, 2010-01-01), (2008-01-01, 2100-01-01)]
           --> (2008-01-01, 2010-01-01)
     * [(1900-01-01, 2010-01-01), (2008-01-01, 2010-01-01), (2010-01-02, 2100-01-01)]
           --> (2008-01-01, 2010-01-01),(2010-01-02, 2100-01-01)
     * [(1900-01-01, 2010-01-01), (2010-01-02, 2100-01-01)]
           --> (1900-01-01, 2010-01-01), (2010-01-02, 2100-01-01)

    It may raise a InvalidValueError when any date is out of bounds. In other words, when
    any date < 1900-01-01 or date > 2100-01-01.

    :param db: database manager
    :param uuid: unique identifier
    :param organization: name of the organization

    :raises NotFoundError: when either 'uuid' or 'organization' are not
        found in the registry. It is also raised when there are not enrollments
        related to 'uuid' and 'organization'
    :raises InvalidValueError: when any date is out of bounds