package graphql import ( "context" "fmt" "github.com/gshopify/service-wrapper/fun" "github.com/gshopify/service-wrapper/model" "github.com/gshopify/service-wrapper/server/middleware" "github.com/microcosm-cc/bluemonday" "gshopper.com/gshopify/products/graphql/generated" "gshopper.com/gshopify/products/graphql/helper" "strings" ) func (r *queryResolver) Product(ctx context.Context, handle *string, id *string) (*generated.Product, error) { var ( inContext *middleware.GShopifyContext err error ) if inContext, err = middleware.InContext(ctx); err != nil { return nil, err } if id == nil && handle == nil { return nil, fmt.Errorf("at least one argument must be specified") } if id != nil { if s, err := model.ParseId(model.GidProduct, *id); err != nil { return nil, err } else { *id = s } } return r.db.Product(inContext.Language, handle, id) } func (r *queryResolver) Products(ctx context.Context, after *string, before *string, first *int, last *int, query *string, reverse *bool, sort *generated.ProductSortKeys) (*generated.ProductConnection, error) { var ( inContext *middleware.GShopifyContext products []*generated.Product err error ) if inContext, err = middleware.InContext(ctx); err != nil { return nil, err } if products, err = r.db.Products(inContext.Language, nil); err != nil { return nil, err } products = helper.SortProducts(products, sort) return helper.NewProductConnection(products, after, before, first, last, reverse) } func (r *productResolver) Description(_ context.Context, product *generated.Product, truncateAt *int) (string, error) { return fun.TruncateAt( bluemonday.StrictPolicy().Sanitize(string(product.DescriptionHTML)), truncateAt) } // Products retrieves Product list by collection func (r *collectionResolver) Products(ctx context.Context, collection *generated.Collection, after *string, before *string, filters []*generated.ProductFilter, first *int, last *int, reverse *bool, sort *generated.ProductCollectionSortKeys) (*generated.ProductConnection, error) { var ( inContext *middleware.GShopifyContext products []*generated.Product err error ) if inContext, err = middleware.InContext(ctx); err != nil { return nil, err } rawId, err := model.ParseId(model.GidCollection, collection.ID) if err != nil { return nil, err } if products, err = r.db.Products(inContext.Language, &rawId); err != nil { return nil, err } products = helper.FilterProducts(products, filters) products = helper.SortProducts(products, sort) return helper.NewProductConnection(products, after, before, first, last, reverse) } func (r *productResolver) Options(ctx context.Context, product *generated.Product, first *int) ([]*generated.ProductOption, error) { var ( inContext *middleware.GShopifyContext options []*generated.ProductOption err error ) if inContext, err = middleware.InContext(ctx); err != nil { return nil, err } rawId, err := model.ParseId(model.GidProduct, product.ID) if err != nil { return nil, err } if options, err = r.db.ProductOptions(inContext.Language, rawId); err != nil { return nil, err } return fun.First(options, first), nil } func (r *productResolver) Variants(ctx context.Context, product *generated.Product, first *int, after *string, last *int, before *string, reverse *bool, sort *generated.ProductVariantSortKeys) (*generated.ProductVariantConnection, error) { var ( inContext *middleware.GShopifyContext variants []*generated.ProductVariant err error ) inContext, err = middleware.InContext(ctx) if err != nil { return nil, err } rawId, err := model.ParseId(model.GidProduct, product.ID) if err != nil { return nil, err } variants, err = r.db.ProductVariants(inContext, rawId) if err != nil { return nil, err } return helper.NewProductVariantConnection(variants, after, before, first, last, reverse, sort) } func (r *productResolver) VariantBySelectedOptions(ctx context.Context, product *generated.Product, input []*generated.SelectedOptionInput) (*generated.ProductVariant, error) { options, err := r.Options(ctx, product, nil) if err != nil { return nil, err } size := len(options) if size != len(input) { return nil, fmt.Errorf("illegal SelectedOptionInput") } type ext struct { id string index int } var selected = make([]ext, 0) for i := range input { for k := range options { if options[k].Name != input[i].Name { continue } for j, value := range options[k].Values { if value != input[i].Value { continue } selected = append(selected, ext{ id: options[k].ID, index: j + 1, }) break } } } if size != len(selected) { return nil, fmt.Errorf("illegal SelectedOptionInput") } variants, err := r.Variants(ctx, product, nil, nil, nil, nil, nil, nil) if err != nil { return nil, err } for _, node := range variants.Nodes { var i = 0 for _, e := range selected { for _, meta := range node.Metafields { if meta.Namespace != model.GidOption.String() { continue } if t := model.MetaFieldType(meta.Type); !t.IsValid() || model.MetaFieldTypeNumberInteger != t { continue } if e.id == meta.Key && fmt.Sprintf("%d", e.index) == meta.Value { i++ break } } } if i == size { return node, nil } } return nil, nil } func (r *productVariantResolver) Product(ctx context.Context, variant *generated.ProductVariant) (*generated.Product, error) { var ( inContext *middleware.GShopifyContext err error ) if inContext, err = middleware.InContext(ctx); err != nil { return nil, err } if variant.Product == nil { return nil, fmt.Errorf("unknown product.ID for variant: `%s`", variant.ID) } rawId, err := model.ParseId(model.GidProduct, variant.Product.ID) if err != nil { return nil, err } return r.db.Product(inContext.Language, nil, &rawId) } // StoreAvailability TODO: implement func (r *productVariantResolver) StoreAvailability(ctx context.Context, variant *generated.ProductVariant, first *int, after *string, last *int, before *string, reverse *bool) (*generated.StoreAvailabilityConnection, error) { panic("not implemented") } func (r *productVariantResolver) SelectedOptions(ctx context.Context, variant *generated.ProductVariant) ([]*generated.SelectedOption, error) { var ( inContext *middleware.GShopifyContext err error ) if inContext, err = middleware.InContext(ctx); err != nil { return nil, err } rawId, err := model.ParseId(model.GidVariant, variant.ID) if err != nil { return nil, fmt.Errorf("unknown ID for variant: `%s`", variant.ID) } return r.db.ProductVariantOptions(inContext.Language, rawId) } func (r *productVariantResolver) Title(ctx context.Context, variant *generated.ProductVariant) (string, error) { opts, err := r.SelectedOptions(ctx, variant) if err != nil { return "", err } s := make([]string, len(opts)) for i := range opts { s[i] = opts[i].Value } return strings.Join(s, " / "), nil } func (r *queryResolver) ProductTags(_ context.Context, first int) (*generated.StringConnection, error) { tags, err := r.db.ProductTags() if err != nil { return nil, err } return helper.NewStringConnection(tags, &first, nil, nil) } func (r *queryResolver) ProductTypes(_ context.Context, first int) (*generated.StringConnection, error) { types, err := r.db.ProductTypes() if err != nil { return nil, err } return helper.NewStringConnection(types, &first, nil, nil) } func (r *queryResolver) ProductRecommendations(ctx context.Context, productID string) ([]*generated.Product, error) { panic("not implemented") }