def index_loans(request: Request,
                id: int = 0,
                after_time: int = 0,
                before_time: int = 0,
                borrower_id: int = 0,
                lender_id: int = 0,
                includes_user_id: int = 0,
                borrower_name: str = '',
                lender_name: str = '',
                includes_user_name: str = '',
                principal_cents: int = 0,
                principal_repayment_cents: int = -1,
                unpaid: int = -1,
                repaid: int = -1,
                format: int = 2,
                limit: int = 10):
    id = _zero_to_none(id)
    after_time = _zero_to_none(after_time)
    before_time = _zero_to_none(before_time)
    borrower_id = _zero_to_none(borrower_id)
    lender_id = _zero_to_none(lender_id)
    includes_user_id = _zero_to_none(includes_user_id)
    borrower_name = _blank_to_none(borrower_name)
    lender_name = _blank_to_none(lender_name)
    includes_user_name = _blank_to_none(includes_user_name)
    principal_cents = _zero_to_none(principal_cents)
    principal_repayment_cents = _neg1_to_none(principal_repayment_cents)
    unpaid = _neg1_to_none(unpaid)
    repaid = _neg1_to_none(repaid)
    limit = _zero_to_none(limit)

    attempt_request_cost = 5
    headers = {'x-request-cost': str(attempt_request_cost)}
    with LazyItgs() as itgs:
        auth = find_bearer_token(request)
        user_id, _, perms = users.helper.get_permissions_from_header(
            itgs, auth, ratelimit_helper.RATELIMIT_PERMISSIONS)
        resp = try_handle_deprecated_call(itgs, request, SLUG, user_id=user_id)

        if resp is not None:
            return resp

        if not ratelimit_helper.check_ratelimit(itgs, user_id, perms,
                                                attempt_request_cost):
            return JSONResponse(content=RATELIMIT_RESPONSE.dict(),
                                status_code=429,
                                headers=headers)

        if limit is not None and (limit < 0 or limit >= 1000):
            return JSONResponse(content=PHPErrorResponse(errors=[
                PHPError(
                    error_type='INVALID_PARAMETER',
                    error_message=(
                        'Limit must be 0 or a positive integer less than 1000'
                    ))
            ]).dict(),
                                status_code=400)

        if limit is None and user_id is None:
            headers[
                'x-limit-warning'] = 'unauthed requests limit=0 replaced with limit=100'
            limit = 100

        if format not in (0, 1, 2, 3):
            return JSONResponse(content=PHPErrorResponse(errors=[
                PHPError(error_type='INVALID_PARAMETER',
                         error_message=('Format must be 0, 1, 2, or 3'))
            ]).dict(),
                                status_code=400)

        loans = Table('loans')
        if limit is None:
            real_request_cost = 100
        else:
            real_request_cost = min(100, limit)

        if format == 0:
            real_request_cost = math.ceil(math.log(real_request_cost + 1))
        elif format < 3:
            # Cost needs to be greater than loans show
            real_request_cost = 25 + real_request_cost * 2
        else:
            # We need to ensure the cost is greater than using the /users show
            # endpoint for getting usernames
            real_request_cost = 25 + math.ceil(real_request_cost * 4.1)

        headers['x-request-cost'] = str(attempt_request_cost +
                                        real_request_cost)
        if not ratelimit_helper.check_ratelimit(itgs, user_id, perms,
                                                real_request_cost):
            return JSONResponse(content=RATELIMIT_RESPONSE.dict(),
                                status_code=429,
                                headers=headers)

        moneys = Table('moneys')
        principals = moneys.as_('principals')
        principal_repayments = moneys.as_('principal_repayments')

        usrs = Table('users')
        lenders = usrs.as_('lenders')
        borrowers = usrs.as_('borrowers')

        query = (Query.from_(loans).where(loans.deleted_at.isnull()).orderby(
            loans.id, order=Order.desc))
        params = []
        joins = set()

        def _add_param(val):
            params.append(val)
            return Parameter(f'${len(params)}')

        def _ensure_principals():
            nonlocal query
            if 'principals' in joins:
                return
            joins.add('principals')
            query = (query.join(principals).on(
                principals.id == loans.principal_id))

        def _ensure_principal_repayments():
            nonlocal query
            if 'principal_repayments' in joins:
                return
            joins.add('principal_repayments')
            query = (query.join(principal_repayments).on(
                principal_repayments.id == loans.principal_repayment_id))

        def _ensure_lenders():
            nonlocal query
            if 'lenders' in joins:
                return
            joins.add('lenders')
            query = (query.join(lenders).on(lenders.id == loans.lender_id))

        def _ensure_borrowers():
            nonlocal query
            if 'borrowers' in joins:
                return
            joins.add('borrowers')
            query = (query.join(borrowers).on(
                borrowers.id == loans.borrower_id))

        if id is not None:
            query = query.where(loans.id == _add_param(id))

        if after_time is not None:
            query = (query.where(loans.created_at > _add_param(
                datetime.fromtimestamp(after_time / 1000.0))))

        if before_time is not None:
            query = (query.where(loans.created_at < _add_param(
                datetime.fromtimestamp(before_time / 1000.0))))

        if principal_cents is not None:
            _ensure_principals()
            query = (query.where(
                principals.amount_usd_cents == _add_param(principal_cents)))

        if principal_repayment_cents is not None:
            _ensure_principal_repayments()
            query = (query.where(principal_repayments.amount_usd_cents ==
                                 _add_param(principal_repayment_cents)))

        if borrower_id is not None:
            query = (query.where(loans.borrower_id == _add_param(borrower_id)))

        if lender_id is not None:
            query = (query.where(loans.lender_id == _add_param(lender_id)))

        if includes_user_id is not None:
            prm = _add_param(includes_user_id)
            query = (query.where((loans.borrower_id == prm)
                                 | (loans.lender_id == prm)))

        if borrower_name is not None:
            _ensure_borrowers()
            query = (query.where(
                borrowers.username == _add_param(borrower_name.lower())))

        if lender_name is not None:
            _ensure_lenders()
            query = (query.where(
                lenders.username == _add_param(lender_name.lower())))

        if includes_user_name is not None:
            _ensure_lenders()
            _ensure_borrowers()
            prm = _add_param(includes_user_name)
            query = (query.where((lenders.username == prm)
                                 | (borrowers.username == prm)))

        if unpaid is not None:
            if unpaid:
                query = query.where(loans.unpaid_at.notnull())
            else:
                query = query.where(loans.unpaid_at.isnull())

        if repaid is not None:
            if repaid:
                query = query.where(loans.repaid_at.notnull())
            else:
                query = query.where(loans.repaid_at.isnull())

        if limit is not None:
            query = query.limit(limit)

        query = query.select(loans.id)
        if format > 0:
            _ensure_principals()
            _ensure_principal_repayments()
            event_tables = (Table('loan_repayment_events'),
                            Table('loan_unpaid_events'),
                            Table('loan_admin_events'))
            latest_events = Table('latest_events')
            query = (query.with_(
                Query.from_(loans).select(
                    loans.id.as_('loan_id'),
                    Greatest(loans.created_at,
                             *(tbl.created_at for tbl in event_tables
                               )).as_('latest_event_at')).groupby(loans.id),
                'latest_events').left_join(latest_events).on(
                    latest_events.loan_id == loans.id).select(
                        loans.lender_id, loans.borrower_id,
                        principals.amount_usd_cents,
                        principal_repayments.amount_usd_cents, (Case().when(
                            loans.unpaid_at.isnull(), 'false').else_('true')),
                        Cast(
                            Extract('epoch', loans.created_at) * 1000,
                            'bigint'),
                        Cast(
                            Extract('epoch', latest_events.latest_event_at) *
                            1000, 'bigint')))

            if format == 3:
                creation_infos = Table('loan_creation_infos')
                _ensure_borrowers()
                _ensure_lenders()
                query = (query.join(creation_infos).on(
                    creation_infos.loan_id == loans.id).select(
                        Function('SUBSTRING', creation_infos.parent_fullname,
                                 4),
                        Function('SUBSTRING', creation_infos.comment_fullname,
                                 4), lenders.username, borrowers.username))

        sql, args = convert_numbered_args(query.get_sql(), params)
        headers['Cache-Control'] = 'public, max-age=600'
        if format == 0:
            return _UltraCompactResponse((sql, args), headers,
                                         'LOANS_ULTRACOMPACT')
        elif format == 1:
            return _CompactResponse((sql, args), headers, 'LOANS_COMPACT')
        elif format == 2:
            return _StandardResponse((sql, args), headers, 'LOANS_STANDARD')
        else:
            return _ExtendedResponse((sql, args), headers, 'LOANS_EXTENDED')
def extract_microsecond_equal(field: Term, value: int) -> Criterion:
    return Extract(DatePart.microsecond, field).eq(value)
def extract_minute_equal(field: Term, value: int) -> Criterion:
    return Extract(DatePart.minute, field).eq(value)
def extract_hour_equal(field: Term, value: int) -> Criterion:
    return Extract(DatePart.hour, field).eq(value)
def extract_day_equal(field: Term, value: int) -> Criterion:
    return Extract(DatePart.day, field).eq(value)
def extract_week_equal(field: Term, value: int) -> Criterion:
    return Extract(DatePart.week, field).eq(value)