private static CursorPageSlice <TEntity> PostProcessResultsIntoCursorPageSlice <TEntity>(
            List <CursorResult <TEntity> > results,
            SqlQuerySliceInfo sqlQuerySliceInfo,
            int?totalCount
            ) where TEntity : class
        {
            bool hasPreviousPage = false;
            bool hasNextPage     = false;

            if (sqlQuerySliceInfo.IsPreviousPagePossible)
            {
                var firstCursor = results.FirstOrDefault();
                hasPreviousPage = firstCursor?.CursorIndex > 1; //Cursor Index is 1 Based; 0 would be the Cursor before the First
            }

            if (sqlQuerySliceInfo.IsNextPagePossible)
            {
                //GENERALLY This should Always Be True as we always increment the EndIndex if there is the Possibility that there might
                //  be a NEXT Page, and the ExpectedCount is always a value that should satisfy the processing
                //  (e.g. ExpectedCount might be int.MaxValue which would ensure our Take is always successful to get ALL Results).
                if (sqlQuerySliceInfo.IsEndIndexOverFetchedForNextPageCheck && sqlQuerySliceInfo.ExpectedCount < int.MaxValue)
                {
                    hasNextPage = results.Count > sqlQuerySliceInfo.ExpectedCount;
                    if (hasNextPage)
                    {
                        results.RemoveAt(results.Count - 1);
                    }
                }
            }

            //Return a CursorPagedResult decorator for the results along with the Total Count!
            var cursorPage = new CursorPageSlice <TEntity>(results, totalCount, hasPreviousPage, hasNextPage);

            return(cursorPage);
        }
 /// <summary>
 /// Helper method for converting Cursor Slice to OffsetPageResults for easier processing by calling code.
 /// </summary>
 /// <typeparam name="TEntity"></typeparam>
 /// <param name="cursorPageSlice"></param>
 /// <returns></returns>
 public static OffsetPageResults <TEntity> ToOffsetPageResults <TEntity>(this CursorPageSlice <TEntity> cursorPageSlice)
 //ALL entities retrieved and Mapped for Cursor Pagination must support IHaveCursor interface.
     where TEntity : class
 {
     return(new OffsetPageResults <TEntity>(
                cursorPageSlice.Results,
                cursorPageSlice.HasNextPage,
                cursorPageSlice.HasPreviousPage,
                cursorPageSlice.TotalCount
                ));
 }
        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);
        }