public StorefrontGraphQuery( IDataLoaderContextAccessor dataLoaderContextAccessor, ILanguageProvider languageProvider, ICurrencyProvider currencyProvider, IContentPageServiceProvider contentPageServiceProvider, INavigationServiceProvider navigationServiceProvider, ICategoryServiceProvider categoryServiceProvider, IProductServiceProvider productServiceProvider, IContentPageService contentPageService, IContentPageLookupService contentPageLookupService, INavigationLookupService navigationLookupService, ICategoryService categoryService, ICategoryLookupService categoryLookupService, IProductService productService, IProductLookupService productLookupService) { Name = "Query"; #region Languages Field <ListGraphType <LanguageGraphType>, IList <string> >() .Name("Languages") .Description("The languages supported") .Resolve(ctx => languageProvider.Languages); #endregion Languages #region Currencies Field <ListGraphType <CurrencyGraphType>, IList <NodaMoney.Currency> >() .Name("Currencies") .Description("The currencies supported") .Resolve(ctx => currencyProvider.Currencies .Select(NodaMoney.Currency.FromCode) .ToList()); #endregion Currencies #region Content Pages Field <ContentPageGraphType, ContentPage>() .Name("ContentPage") .Argument <StringGraphType>("id", "Id of the content page") .Argument <StringGraphType>("handle", "Handle of the content page") .ResolveAsync(ctx => { if (!contentPageServiceProvider.IsEnabled) { throw new ExecutionError("Content pages not supported."); } if (ctx.HasArgument("id")) { var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, ContentPage>("ContentPage.LookupByIdAsync", contentPageLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.GetArgument <string>("id"))); } if (ctx.HasArgument("handle")) { var userContext = (StorefrontGraphUserContext)ctx.UserContext; var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, ContentPage>("ContentPage.LookupByHandleAsync", handles => contentPageLookupService.LookupByHandleAsync(handles, userContext.LanguageCode)); return(loader.LoadAsync(ctx.GetArgument <string>("handle"))); } return(null); }); Connection <ContentPageGraphType>() .Name("ContentPages") .Unidirectional() .Argument <StringGraphType>("query", "The search query to filter results by") .Argument <ContentPageSortKeyGraphType>("sortKey", "The key to sort the underlying list by") .Argument <StringGraphType>("reverse", "Reverse the order of the underlying list") .ResolveAsync(async ctx => { if (!contentPageServiceProvider.IsEnabled) { throw new ExecutionError("Content pages not supported."); } var userContext = (StorefrontGraphUserContext)ctx.UserContext; var result = await contentPageService.GetBySearchAsync( ctx.GetArgument <string>("query"), userContext.LanguageCode, null, ctx.GetArgument <string>("after"), ctx.GetArgument <int>("first", 24), ctx.GetArgument <ContentPageSortKey>("sortKey"), ctx.GetArgument <bool>("reverse")); return(result.ToGraphConnection()); }); #endregion Content Pages #region Navigations Field <NavigationGraphType, Navigation>() .Name("Navigation") .Argument <StringGraphType>("id", "Id of the navigation") .Argument <StringGraphType>("handle", "Handle of the navigation") .ResolveAsync(ctx => { if (!navigationServiceProvider.IsEnabled) { throw new ExecutionError("Navigations not supported."); } if (ctx.HasArgument("id")) { var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Navigation>("Navigation.LookupByIdAsync", navigationLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.GetArgument <string>("id"))); } if (ctx.HasArgument("handle")) { var userContext = (StorefrontGraphUserContext)ctx.UserContext; var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Navigation>("Navigation.LookupByHandleAsync", handles => navigationLookupService.LookupByHandleAsync(handles, userContext.LanguageCode)); return(loader.LoadAsync(ctx.GetArgument <string>("handle"))); } return(null); }); #endregion Navigations #region Categories Field <CategoryGraphType, Category>() .Name("Category") .Argument <StringGraphType>("id", "Id of the category") .Argument <StringGraphType>("handle", "Handle of the category") .ResolveAsync(ctx => { if (!categoryServiceProvider.IsEnabled) { throw new ExecutionError("Categories not supported."); } if (ctx.HasArgument("id")) { var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Category>("Category.LookupByIdAsync", categoryLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.GetArgument <string>("id"))); } if (ctx.HasArgument("handle")) { var userContext = (StorefrontGraphUserContext)ctx.UserContext; var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Category>("Category.LookupByHandleAsync", handles => categoryLookupService.LookupByHandleAsync(handles, userContext.LanguageCode)); return(loader.LoadAsync(ctx.GetArgument <string>("handle"))); } return(null); }); Connection <CategoryGraphType>() .Name("Categories") .Unidirectional() .Argument <StringGraphType>("query", "The search query to filter results by") .Argument <CategorySortKeyGraphType>("sortKey", "The key to sort the underlying list by") .Argument <StringGraphType>("reverse", "Reverse the order of the underlying list") .ResolveAsync(async ctx => { if (!categoryServiceProvider.IsEnabled) { throw new ExecutionError("Categories not supported."); } var userContext = (StorefrontGraphUserContext)ctx.UserContext; var result = await categoryService.GetBySearchAsync( ctx.GetArgument <string>("query"), userContext.LanguageCode, null, ctx.GetArgument <string>("after"), ctx.GetArgument <int>("first", 24), ctx.GetArgument <CategorySortKey>("sortKey"), ctx.GetArgument <bool>("reverse")); return(result.ToGraphConnection()); }); #endregion Categories #region Products Field <ProductGraphType, Product>() .Name("Product") .Argument <StringGraphType>("id", "Id of the category") .Argument <StringGraphType>("handle", "Handle of the category") .ResolveAsync(ctx => { if (!productServiceProvider.IsEnabled) { throw new ExecutionError("Products not supported."); } if (ctx.HasArgument("id")) { var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Product>("Product.LookupByIdAsync", productLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.GetArgument <string>("id"))); } if (ctx.HasArgument("handle")) { var userContext = (StorefrontGraphUserContext)ctx.UserContext; var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Product>("Product.LookupByHandleAsync", handles => productLookupService.LookupByHandleAsync(handles, userContext.LanguageCode)); return(loader.LoadAsync(ctx.GetArgument <string>("handle"))); } return(null); }); Connection <ProductGraphType>() .Name("Products") .Unidirectional() .Argument <StringGraphType>("query", "The search query to filter results by") .Argument <ProductSortKeyGraphType>("sortKey", "The key to sort the underlying list by") .Argument <StringGraphType>("reverse", "Reverse the order of the underlying list") .ResolveAsync(async ctx => { if (!productServiceProvider.IsEnabled) { throw new ExecutionError("Products not supported."); } var userContext = (StorefrontGraphUserContext)ctx.UserContext; var result = await productService.GetBySearchAsync( ctx.GetArgument <string>("query"), userContext.LanguageCode, null, ctx.GetArgument <string>("after"), ctx.GetArgument <int>("first", 24), ctx.GetArgument <ProductSortKey>("sortKey"), ctx.GetArgument <bool>("reverse"), userContext.CurrencyCode); return(result.ToGraphConnection()); }); #endregion Products }
public ProductGraphType( IDataLoaderContextAccessor dataLoaderContextAccessor, IMetaFieldServiceProvider metaFieldServiceProvider, IMetaFieldService metaFieldService, IMetaFieldLookupService metaFieldLookupService, ICategoryServiceProvider categoryServiceProvider, ICategoryLookupService categoryLookupService, IMappingService mappingService ) { Name = "Product"; Field <StringGraphType, string>() .Name("Id") .Description("Globally unique identifier, eg: gid://Product/1000") .Resolve(ctx => ctx.Source.Id); Field <StringGraphType, string>() .Name("ParentId") .Description("Globally unique identifier of parent, 'gid://' if none") .Resolve(ctx => ctx.Source.ParentId); Field <StringGraphType, string>() .Name("Handle") .Description("A human-friendly unique string for the product") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Handles .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <StringGraphType, string>() .Name("Title") .Description("The title of the product") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Titles .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <StringGraphType, string>() .Name("Url") .Description("The url of the product") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Urls .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <StringGraphType, string>() .Name("Type") .Description("The type of the product") .Resolve(ctx => ctx.Source.Type); Field <StringGraphType, string>() .Name("Description") .Description("The description of the product") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Descriptions .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <DateTimeGraphType, DateTime>() .Name("CreatedAt") .Description("The timestamp of product creation") .Resolve(ctx => ctx.Source.CreatedAt.ToDateTime()); Field <DateTimeGraphType, DateTime>() .Name("UpdatedAt") .Description("The timestamp of the latest product update") .Resolve(ctx => ctx.Source.UpdatedAt.ToDateTime()); Field <StringGraphType, string>() .Name("PrimaryCategoryId") .Description("Globally unique identifier of the primary category the product belong to") .Resolve(ctx => ctx.Source.PrimaryCategoryId); Field <ListGraphType <StringGraphType>, IList <string> >() .Name("CategoryIds") .Description("Globally unique identifiers of categories the product belong to") .Resolve(ctx => ctx.Source.CategoryIds); Field <ListGraphType <ProductVariantGraphType>, IList <ProductVariant> >() .Name("Variants") .Description("The variants of the product") .Resolve(ctx => ctx.Source.Variants .OrderBy(x => x.SortOrder) .ToList()); Field <ListGraphType <ImageGraphType>, IList <Image> >() .Name("Images") .Description("The images of the product") .Resolve(ctx => ctx.Source.Images); Field <ImageGraphType, Image>() .Name("PrimaryImage") .Description("The primary image of the product") .Resolve(ctx => { if (ctx.Source.Images.Any()) { // First image of product return(ctx.Source.Images.First()); } foreach (var productVariant in ctx.Source.Variants) { if (productVariant.Images.Any()) { // First image of product product return(ctx.Source.Images.First()); } } // No images return(null); }); Field <MoneyGraphType, NodaMoney.Money>() .Name("UnitPriceFrom") .Description("The unit price of the cheapest variant") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; // Join unit prices for currency code and map to NodaMoney, return smallest return(mappingService .Map <Proto.Types.Money, NodaMoney.Money>( ctx.Source.Variants .SelectMany(x => x.UnitPrices.Where(p => p.CurrencyCode == userContext.CurrencyCode))) .Min()); }); #region Meta-fields Field <MetaFieldGraphType, MetaField>() .Name("MetaField") .Description("Connection to a specific meta-field") .Argument <NonNullGraphType <StringGraphType> >("namespace", "Namespace of the meta-field") .Argument <NonNullGraphType <StringGraphType> >("name", "Name of the meta-field") .ResolveAsync(async ctx => { if (!metaFieldServiceProvider.IsEnabled) { throw new ExecutionError("Meta-fields not supported."); } var result = await metaFieldService.GetBySearchAsync( ctx.Source.Id, ctx.GetArgument <string>("namespace"), ctx.GetArgument <string>("name")); return(result.FirstOrDefault()); }); Field <ListGraphType <MetaFieldGraphType>, IList <MetaField> >() .Name("MetaFields") .Description("Connection to a all meta-fields") .ResolveAsync(ctx => { if (!metaFieldServiceProvider.IsEnabled) { throw new ExecutionError("Meta-fields not supported."); } var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, IList <MetaField> >("MetaField.LookupByParentIdsAsync", metaFieldLookupService.LookupByParentIdsAsync); return(loader.LoadAsync(ctx.Source.Id)); }); #endregion Meta-fields #region Categories Field <CategoryGraphType, Category>() .Name("PrimaryCategory") .ResolveAsync(ctx => { if (!categoryServiceProvider.IsEnabled) { throw new ExecutionError("Categories not supported."); } var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Category>("Category.LookupByIdAsync", categoryLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.Source.PrimaryCategoryId)); }); Field <ListGraphType <CategoryGraphType>, Category[]>() .Name("Categories") .ResolveAsync(ctx => { if (!categoryServiceProvider.IsEnabled) { throw new ExecutionError("Categories not supported."); } var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Category>("Category.LookupByIdAsync", categoryLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.Source.CategoryIds)); }); #endregion Categories }
public CategoryGraphType( IDataLoaderContextAccessor dataLoaderContextAccessor, IMetaFieldServiceProvider metaFieldServiceProvider, IMetaFieldService metaFieldService, IMetaFieldLookupService metaFieldLookupService, IProductServiceProvider productServiceProvider, IProductService productService, ICategoryService categoryService, ICategoryLookupService categoryLookupService ) { Name = "Category"; Field <StringGraphType, string>() .Name("Id") .Description("Globally unique identifier, eg: gid://Category/1000") .Resolve(ctx => ctx.Source.Id); Field <StringGraphType, string>() .Name("ParentId") .Description("Globally unique identifier of parent, 'gid://' if none") .Resolve(ctx => ctx.Source.ParentId); Field <StringGraphType, string>() .Name("Handle") .Description("A human-friendly unique string for the category") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Handles .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <StringGraphType, string>() .Name("Title") .Description("The title of the category") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Titles .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <StringGraphType, string>() .Name("Url") .Description("The url of the category") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Urls .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <StringGraphType, string>() .Name("Type") .Description("The type of the category") .Resolve(ctx => ctx.Source.Type); Field <StringGraphType, string>() .Name("Description") .Description("The description of the category") .Resolve(ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; return(ctx.Source.Descriptions .FirstOrDefault(x => x.LanguageCode == userContext.LanguageCode) ?.Value); }); Field <DateTimeGraphType, DateTime>() .Name("CreatedAt") .Description("The timestamp of category creation") .Resolve(ctx => ctx.Source.CreatedAt.ToDateTime()); Field <DateTimeGraphType, DateTime>() .Name("UpdatedAt") .Description("The timestamp of the latest category update") .Resolve(ctx => ctx.Source.UpdatedAt.ToDateTime()); Field <ImageGraphType, Image>() .Name("PrimaryImage") .Description("The primary image of the category") .Resolve(ctx => ctx.Source.PrimaryImage); #region Meta-fields Field <MetaFieldGraphType, MetaField>() .Name("MetaField") .Description("Connection to a specific meta-field") .Argument <NonNullGraphType <StringGraphType> >("namespace", "Namespace of the meta-field") .Argument <NonNullGraphType <StringGraphType> >("name", "Name of the meta-field") .ResolveAsync(async ctx => { if (!metaFieldServiceProvider.IsEnabled) { throw new ExecutionError("Meta-fields not supported."); } var result = await metaFieldService.GetBySearchAsync( ctx.Source.Id, ctx.GetArgument <string>("namespace"), ctx.GetArgument <string>("name")); return(result.FirstOrDefault()); }); Field <ListGraphType <MetaFieldGraphType>, IList <MetaField> >() .Name("MetaFields") .Description("Connection to a all meta-fields") .ResolveAsync(ctx => { if (!metaFieldServiceProvider.IsEnabled) { throw new ExecutionError("Meta-fields not supported."); } var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, IList <MetaField> >("MetaField.LookupByParentIdsAsync", metaFieldLookupService.LookupByParentIdsAsync); return(loader.LoadAsync(ctx.Source.Id)); }); #endregion #region Categories Field <CategoryGraphType, Category>() .Name("Parent") .ResolveAsync(ctx => { if (string.IsNullOrEmpty(ctx.Source.ParentId)) { return(null); } var loader = dataLoaderContextAccessor.Context .GetOrAddBatchLoader <string, Category>("Category.LookupByIdAsync", categoryLookupService.LookupByIdAsync); return(loader.LoadAsync(ctx.Source.ParentId)); }); Connection <CategoryGraphType>() .Name("Children") .Unidirectional() .Argument <StringGraphType>("query", "The search query to filter children by") .Argument <CategorySortKeyGraphType>("sortKey", "The key to sort the underlying list by") .Argument <StringGraphType>("reverse", "Reverse the order of the underlying list") .ResolveAsync(async ctx => { var userContext = (StorefrontGraphUserContext)ctx.UserContext; var result = await categoryService.GetBySearchAsync( ctx.GetArgument <string>("query"), userContext.LanguageCode, ctx.Source.Id, ctx.GetArgument <string>("after"), ctx.GetArgument <int>("first", 24), ctx.GetArgument <CategorySortKey>("sortKey"), ctx.GetArgument <bool>("reverse")); return(result.ToGraphConnection()); }); #endregion Categories #region Products Connection <ProductGraphType>() .Name("Products") .Unidirectional() .Argument <StringGraphType>("query", "The search query to filter products by") .Argument <ProductSortKeyGraphType>("sortKey", "The key to sort the underlying list by") .Argument <StringGraphType>("reverse", "Reverse the order of the underlying list") .ResolveAsync(async ctx => { if (!productServiceProvider.IsEnabled) { throw new ExecutionError("Products not supported."); } var userContext = (StorefrontGraphUserContext)ctx.UserContext; var result = await productService.GetBySearchAsync( ctx.GetArgument <string>("query"), userContext.LanguageCode, ctx.Source.Id, ctx.GetArgument <string>("after"), ctx.GetArgument <int>("first", 24), ctx.GetArgument <ProductSortKey>("sortKey"), ctx.GetArgument <bool>("reverse"), userContext.CurrencyCode); return(result.ToGraphConnection()); }); #endregion Products }