コード例 #1
0
    private static CursorPagingRange SliceRange(
        CursorPagingArguments arguments,
        int maxElementCount)
    {
        // [SPEC] if after is set then remove all elements of edges before and including
        // afterEdge.
        //
        // The cursor is increased by one so that the index points to the element after
        var startIndex = arguments.After is { } a
            ? IndexEdge <TEntity> .DeserializeCursor(a) + 1
            : 0;

        // [SPEC] if before is set then remove all elements of edges before and including
        // beforeEdge.
        var before = arguments.Before is { } b
            ? IndexEdge <TEntity> .DeserializeCursor(b)
            : maxElementCount;

        // if after is negative we have know how much of the offset was in the negative range.
        // The amount of positions that are in the negative range, have to be subtracted from
        // the take or we will fetch too many items.
        var startOffsetCorrection = 0;

        if (startIndex < 0)
        {
            startOffsetCorrection = Math.Abs(startIndex);
            startIndex            = 0;
        }

        CursorPagingRange range = new(startIndex, before);

        //[SPEC] If first is less than 0 throw an error
        ValidateFirst(arguments, out var first);

        if (first is not null)
        {
            first -= startOffsetCorrection;
            if (first < 0)
            {
                first = 0;
            }
        }

        //[SPEC] Slice edges to be of length first by removing edges from the end of edges.
        range.Take(first);

        //[SPEC] if last is less than 0 throw an error
        ValidateLast(arguments, out var last);

        //[SPEC] Slice edges to be of length last by removing edges from the start of edges.
        range.TakeLast(last);

        return(range);
    }
        public static ICursorPageSlice <T> SliceAsCursorPage <T>(this IEnumerable <T> items, string?after, int?first, string?before, int?last)
            where T : class
        {
            //Do nothing if there are no results...
            if (!items.Any())
            {
                return(new CursorPageSlice <T>(Enumerable.Empty <ICursorResult <T> >(), 0, false, false));
            }

            var afterIndex = after != null
                ? IndexEdge <string> .DeserializeCursor(after)
                : 0;

            var beforeIndex = before != null
                ? IndexEdge <string> .DeserializeCursor(before)
                : 0;

            //FIRST log the index of all items in the list BEFORE slicing, as these indexes are
            //  the Cursor Indexes for paging up/down the entire list, & ICursorResult is the Decorator
            //  around the Entity Models.

            //NOTE: We MUST materialize this after applying index values to prevent ongoing increments...
            int index = 0;
            IEnumerable <ICursorResult <T> > slice = items
                                                     .Select(c => new CursorResult <T>(c, ++index))
                                                     .ToList();

            int totalCount = slice.Count();

            //If After specified, remove all before After (or skip past After)
            if (afterIndex > 0 && slice.Last().CursorIndex > afterIndex)
            {
                slice = slice.Skip(afterIndex);
            }

            //If Before is specified, remove all after Before (Skip Until Before is reached)
            if (beforeIndex > 0 && slice.Last().CursorIndex > beforeIndex)
            {
                slice = slice.SkipWhile(c => c.CursorIndex < beforeIndex);
            }

            //If First is specified, then take the first/top rows from the current Slice!
            if (first.HasValue && first > 0 && slice.Count() > first)
            {
                slice = slice.Take(first.Value);
            }

            //If First is specified, then take the first/top rows from the current Slice!
            if (last.HasValue && last > 0 && slice.Count() > last)
            {
                slice = slice.TakeLast(last.Value);
            }

            //Wrap all results into a PagedCursor Slice result wit Total Count...
            //NOTE: to ensure our pagination is complete, we materialize the Results!
            var results     = slice.ToList();
            var firstCursor = results.FirstOrDefault();
            var lastCursor  = results.LastOrDefault();

            var cursorPageSlice = new CursorPageSlice <T>(
                results,
                totalCount,
                hasPreviousPage: firstCursor?.CursorIndex > 1,
                hasNextPage: lastCursor?.CursorIndex < totalCount
                );

            return(cursorPageSlice);
        }