private async Task <object> ResolveConnection(ResolveConnectionContext <object> context, IQueryBuilder <Person> personQueryBuilder) { _personRepository.Context = context; var first = context.First; var afterCursor = Cursor.FromCursor <DateTime?>(context.After); var last = context.Last; var beforeCursor = Cursor.FromCursor <DateTime?>(context.Before); var cancellationToken = context.CancellationToken; var getPersonTask = GetPeople(first, afterCursor, last, beforeCursor, cancellationToken); var getHasNextPageTask = GetHasNextPage(first, afterCursor, cancellationToken); var getHasPreviousPageTask = GetHasPreviousPage(last, beforeCursor, cancellationToken); var totalCountTask = _personRepository.GetTotalCount(cancellationToken); await Task.WhenAll(getPersonTask, getHasNextPageTask, getHasPreviousPageTask, totalCountTask); var people = getPersonTask.Result; var hasNextPage = getHasNextPageTask.Result; var hasPreviousPage = getHasPreviousPageTask.Result; var totalCount = totalCountTask.Result; var(firstCursor, lastCursor) = Cursor.GetFirstAndLastCursor(people, x => x.CreateDate); return(new Connection <Person>() { Edges = people .Select(x => new Edge <Person>() { Cursor = Cursor.ToCursor(x.CreateDate), Node = x }) .ToList(), PageInfo = new PageInfo() { HasNextPage = hasNextPage, HasPreviousPage = hasPreviousPage, StartCursor = firstCursor, EndCursor = lastCursor, }, TotalCount = totalCount, }); }
private async static Task <object> ResolveCountriesConnection( ICountryRepository countryRepository, ResolveConnectionContext <object> context) { var first = context.First; var afterCode = Cursor.FromCursor <string>(context.After); var last = context.Last; var beforeCode = Cursor.FromCursor <string>(context.Before); var cancellationToken = context.CancellationToken; var getCountriesTask = GetCountries(countryRepository, first, afterCode, last, afterCode, cancellationToken); var getHasNextPageTask = GetHasNextPage(countryRepository, first, afterCode, cancellationToken); var getHasPreviousPageTask = GetHasPreviousPage(countryRepository, last, beforeCode, cancellationToken); var totalCountTask = countryRepository.GetTotalCount(cancellationToken); await Task.WhenAll(getCountriesTask, getHasNextPageTask, getHasPreviousPageTask, totalCountTask); var countries = getCountriesTask.Result; var hasNextPage = getHasNextPageTask.Result; var hasPreviousPage = getHasPreviousPageTask.Result; var totalCount = totalCountTask.Result; var(firstCursor, lastCursor) = Cursor.GetFirstAndLastCursor(countries, x => x.Code); return(new Connection <Country> { Edges = countries .Select(x => new Edge <Country> { Cursor = Cursor.ToCursor(x.Code), Node = x }) .ToList(), PageInfo = new PageInfo { HasNextPage = hasNextPage, HasPreviousPage = hasPreviousPage, StartCursor = firstCursor, EndCursor = lastCursor }, TotalCount = totalCount }); }
/// <summary> /// Gets Connection. /// </summary> /// <typeparam name="T">T item.</typeparam> /// <param name="context">Connection context.</param> /// <param name="enumerable">An IEnumerable of T items.</param> /// <param name="defaultPageLimit">Default page limit.</param> /// <returns></returns> public static async Task <Connection <T> > GetConnectionAsync <T>(this ResolveConnectionContext <object> context, IEnumerable <T> enumerable, int defaultPageLimit = 10) { // Ref: https://graphql.org/learn/pagination/ var list = enumerable.ToList(); var total = list.Count; int skip = 0; int take = defaultPageLimit; var edges = list.Select(TransformToEdge).ToList(); if (!string.IsNullOrEmpty(context.After)) { skip = GetIndex(context.After) + 1; } if (context.First.HasValue) { take = context.First.Value; } var hasNextPage = total > skip + take; var filtered = edges.Skip(skip).Take(take).ToList(); var first = filtered.FirstOrDefault().GetCursor(); var connection = new Connection <T> { TotalCount = total, Edges = filtered, PageInfo = new PageInfo { StartCursor = first, EndCursor = filtered.LastOrDefault().GetCursor(), HasNextPage = hasNextPage, HasPreviousPage = GetIndex(first) > 0 } }; return(await Task.FromResult(connection)); }
public static Connection <TSource> ToConnection <TSource, TParent>( IEnumerable <TSource> slice, ResolveConnectionContext <TParent> context, int sliceStartIndex, int totalCount, bool strictCheck = true ) { var sliceList = slice as IList <TSource> ?? slice.ToList(); var metrics = ArraySliceMetrics.Create( sliceList, context, sliceStartIndex, totalCount, strictCheck ); var edges = metrics.Slice.Select((item, i) => new Edge <TSource> { Node = item, Cursor = OffsetToCursor(metrics.StartOffset + i) }) .ToList(); var firstEdge = edges.FirstOrDefault(); var lastEdge = edges.LastOrDefault(); return(new Connection <TSource> { Edges = edges, TotalCount = totalCount, PageInfo = new PageInfo { StartCursor = firstEdge?.Cursor, EndCursor = lastEdge?.Cursor, HasPreviousPage = metrics.HasPrevious, HasNextPage = metrics.HasNext, } }); }
public static Connection <TSource> ToConnection <TSource, TParent>(this IEnumerable <TSource> source, ResolveConnectionContext <TParent> context, int totalCount) { // TODO: Implement paging logic var items = source.Select(x => new Edge <TSource> { Node = x }).ToList(); var after = context.After; var before = context.Before; var first = context.First; var last = context.Last; return(new Connection <TSource> { Edges = items, PageInfo = new PageInfo { } }); }
public static async Task <Connection <T> > ToConnection <T, TSource>( this Query query, ResolveConnectionContext <TSource> context, Func <T, string> cursorSelector) where T : class where TSource : class { var xQuery = query as XQuery; if (xQuery == null) { throw new ArgumentException("Make sure the query object is instantiated from a queryFactory", nameof(query)); } if (!xQuery.Clauses.Any(q => q.Component == "select")) { xQuery.Select("*"); } var statement = xQuery.Compiler.Compile( xQuery.Slice( context.After?.FromCursor().ToString(), context.First.GetValueOrDefault(0), context.Before?.FromCursor().ToString(), context.Last.GetValueOrDefault(0))); // Some custom mapping logic. Until the `RowNumber` field is found, all fields are considered // to be part of `T`. This methodology works because the last field selected is in fact the // `RowNumber` field (through the Slice function). var totalCount = 0; var dictionary = xQuery.Connection.Query( sql: statement.Sql, param: statement.NamedBindings, map: (T t, (long rowNumber, long rowCount)meta) => { totalCount = (int)meta.rowCount; return(new KeyValuePair <long, T>(meta.rowNumber, t)); },
public ScopedContextBase() { _scopedServiceProviderMock = new Mock <IServiceProvider>(MockBehavior.Strict); _scopedServiceProvider = _scopedServiceProviderMock.Object; _scopedServiceScopeMock = new Mock <IServiceScope>(MockBehavior.Strict); _scopedServiceScopeMock.Setup(x => x.ServiceProvider).Returns(_scopedServiceProvider).Verifiable(); _scopedServiceScopeMock.Setup(x => x.Dispose()).Verifiable(); var scopedServiceScope = _scopedServiceScopeMock.Object; _serviceScopeFactoryMock = new Mock <IServiceScopeFactory>(MockBehavior.Strict); _serviceScopeFactoryMock.Setup(x => x.CreateScope()).Returns(scopedServiceScope).Verifiable(); var serviceScopeFactory = _serviceScopeFactoryMock.Object; _requestServicesMock = new Mock <IServiceProvider>(MockBehavior.Strict); _requestServicesMock.Setup(x => x.GetService(It.Is <Type>(t => t == typeof(IServiceScopeFactory)))).Returns(serviceScopeFactory).Verifiable(); var requestServices = _requestServicesMock.Object; _scopedContext = new ResolveFieldContext { RequestServices = requestServices }; _scopedConnectionContext = new ResolveConnectionContext <object>(_scopedContext, false, default); }
public Connection <IContent> CreateIContentConnection( ResolveConnectionContext <IContent> context, LoaderOptions loaderOptions, int defaultPageSize) { int first = context.PageSize ?? defaultPageSize; int.TryParse(context.After, out int after); var items = GetChildren( context.Source.ContentLink, loaderOptions, after, first, out bool hasNextPage ); var pageInfo = CreatePageInfo(first, after, hasNextPage); int endCursor = int.Parse(pageInfo.EndCursor); var edges = new List <Edge <IContent> >(); for (int i = 0; i < items.Count(); i++) { edges.Add(new Edge <IContent> { Node = items.ElementAt(i), Cursor = ((endCursor - first) + i + 1).ToString() }); } return(new Connection <IContent> { TotalCount = items.Count(), Edges = edges, PageInfo = pageInfo }); }
public static Connection <TSource> ToConnection <TSource, TParent>( IEnumerable <TSource> items, ResolveConnectionContext <TParent> context) { return(ToConnection(items, context, 0, items.Count())); }
/* * This is just a mock extension. Modify to suit your own needs. */ public static async Task <Connection <TResult> > ToConnection <TResult, TSource>( this IEnumerable <TResult> enumerable, ResolveConnectionContext <TSource> context) where TResult : IId where TSource : class { await Task.Delay(8); // Again, we have some network activity going on here :) IList <TResult> resultset; // In this if else tree we select the pages we want if (!string.IsNullOrWhiteSpace(context.After)) { resultset = enumerable .SkipWhile(q => q.Id != context.After.FromCursor()) .Skip(1) // We skip an additional one because other the 'after' cursor would be included in the results. .Take(context.First.GetValueOrDefault(context.PageSize ?? 10)) .ToList(); } else if (!string.IsNullOrWhiteSpace(context.Before)) { throw new NotImplementedException(); } else if (context.First != null) { resultset = enumerable .Take(context.First.Value) .ToList(); } else if (context.Last != null) { throw new NotImplementedException(); } else { // We're out of options. Return a default selection resultset = enumerable .Take(context.PageSize ?? 10) .ToList(); } // The rest of this method is used to construct the connection we're returning var edges = resultset.Select((item, i) => new Edge <TResult> { Node = item, Cursor = item?.Id.ToCursor() }) .ToList(); var connection = new Connection <TResult> { Edges = edges, TotalCount = enumerable.Count(), PageInfo = new PageInfo { StartCursor = edges.FirstOrDefault()?.Cursor, EndCursor = edges.LastOrDefault()?.Cursor, HasPreviousPage = true, HasNextPage = true, } }; return(connection); }
public ArraySliceMetrics( IList <TSource> slice, ResolveConnectionContext <TParent> context) : this(slice, context, 0, slice.Count) { }