"A Reaction product"
type Product {
  "Product ID"
  _id: ID!

  "The date and time at which this product was created"
  createdAt: DateTime!

  "Hash to compare with publishedProductHash, to see if this product has changed since it was last published"
  currentProductHash: String

  "The full product description, which may have newline characters in it"
  description: String

  "True if this product has been deleted. Typically, deleted products are not returned in queries."
  isDeleted: Boolean!

  "True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries."
  isVisible: Boolean!

  "All media for a product"
  media(
    "Determines whether variant media should be included in the product or not"
    shouldIncludeVariantMedia: Boolean = true
    ): [ImageInfo]

  "The product description to use for page `description` meta element in HTML"
  metaDescription: String

  "Arbitrary additional metadata about this product"
  metafields: [Metafield]!

  "The country of origin"
  originCountry: String

  "Subtitle"
  pageTitle: String

  "An arbitrary product type value, such as from an external system"
  productType: String

  "The date and time at which this product was last published. If `null`, it has never been published."
  publishedAt: DateTime

  "Hash to compare with currentProductHash, to see if this product has changed since it was last published"
  publishedProductHash: String

  "The shop to which this product belongs"
  shop: Shop!

  "Whether this product will be shown in the generated sitemap"
  shouldAppearInSitemap: Boolean

  "A URL-safe and human-readable string that uniquely identifies this product"
  slug: String

  "Holds metadata specific to a specific social network service"
  socialMetadata: [SocialMetadata]

  "When a shopper purchases this product, what types of fulfillment can they choose from?"
  supportedFulfillmentTypes: [FulfillmentType]!

  "The list of tag IDs that have been applied to this product"
  tagIds: [ID]

  "The list of tags that have been applied to this product"
  tags(
    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int,

    "Return results sorted in this order"
    sortOrder: SortOrder = asc,

    "By default, tags are sorted by ID. Set this to sort by one of the other allowed fields"
    sortBy: TagSortByField = _id
  ): TagConnection

  "Product title"
  title: String

  "The date and time at which this product was last updated"
  updatedAt: DateTime

  "A list of all variants for this product"
  variants(
    "Include hidden variants"
    shouldIncludeHidden: Boolean = true,

    "Include archived variants"
    shouldIncludeArchived: Boolean = false
  ): [ProductVariant]!

  "The product vendor or manufacturer, for display"
  vendor: String
}

"A Reaction product variant or option"
type ProductVariant {
  "Variant ID"
  _id: ID!

  """
  The attribute label describes the category of variant, for example, `Color` or `Size`.
  In most cases this will be the same for all variants at the same level.
  """
  attributeLabel: String

  "The product variant barcode value, if it has one"
  barcode: String

  "The date and time at which this variant was created"
  createdAt: DateTime

  "The height of the product variant, if it has physical dimensions"
  height: Float

  "The position of this variant among other variants at the same level of the product-variant-option hierarchy"
  index: Int

  "True if this variant was deleted. Deleted variants are not published to the catalog."
  isDeleted: Boolean!

  "True if this variant is visible. Hidden variants are not published to the catalog."
  isVisible: Boolean!

  "The length of the product, if it has physical dimensions"
  length: Float

  "All media for a variant"
  media: [ImageInfo]

  "Arbitrary additional metadata about this product"
  metafields: [Metafield]!

  "The minimum quantity that must be added to a cart"
  minOrderQuantity: Int

  "A short title to use for product detail select lists"
  optionTitle: String

  "Child variants, if any"
  options(
    "Include hidden variants"
    shouldIncludeHidden: Boolean = true,

    "Include archived variants"
    shouldIncludeArchived: Boolean = false
  ): [ProductVariant]!

  "The country of origin"
  originCountry: String

  "The shop to which this product variant belongs"
  shop: Shop!

  "SKU of variant"
  sku: String

  """
  The full variant title for use on cart, checkout, and order summaries and on invoices.
  This fully describes the configured variant. For example, if this is an option with
  `optionTitle` "Large", its parent variant has `optionTitle` `Red`, and the product
  `title` is "Fancy T-Shirt", then this `title` will be something like `Fancy T-Shirt - Red - Large`.
  """
  title: String

  "The date and time at which this product was last updated"
  updatedAt: DateTime

  "The weight of the product on Earth, if it has physical dimensions"
  weight: Float

  "The width of the product, if it has physical dimensions"
  width: Float
}

"Response payload of `archiveProducts` mutation"
type ArchiveProductsPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "Array of newly archived products"
  products: [Product]!
}

"Response payload of `archiveProductVariants` mutation"
type ArchiveProductVariantsPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "Array of newly archived variants"
  variants: [ProductVariant]!
}

"Response payload for `updateProductsVisibility` mutation"
type UpdateProductsVisibilityPayload {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "The number of products that were updated successfully"
  updatedCount: Int
}

"Response payload of `createProduct` mutation"
type CreateProductPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "The created product"
  product: Product!
}

"Response payload of `createProductVariant` mutation"
type CreateProductVariantPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "The created product variant"
  variant: ProductVariant!
}

"Response payload of `cloneProducts` mutation"
type CloneProductsPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "Array of newly cloned products"
  products: [Product]!
}

"Response payload of `cloneProductVariants` mutation"
type CloneProductVariantsPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "Array of newly cloned product variants"
  variants: [ProductVariant]!
}

"Response payload of `updateProduct` mutation"
type UpdateProductPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "Updated product"
  product: Product!
}

"Response payload of `updateProductVariantField` mutation"
type UpdateProductVariantPayload  {
  "The same string you sent with the mutation params, for matching mutation calls with their responses"
  clientMutationId: String

  "Updated variant"
  variant: ProductVariant!
}

"A connection edge in which each node is a `Product` object"
type ProductEdge {
  "The cursor that represents this node in the paginated results"
  cursor: ConnectionCursor!

  "The product"
  node: Product
}

"""
Wraps a list of Products`s, providing pagination cursors and information.

For information about what Relay-compatible connections are and how to use them, see the following articles:
- [Relay Connection Documentation](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections)
- [Relay Connection Specification](https://facebook.github.io/relay/graphql/connections.htm)
- [Using Relay-style Connections With Apollo Client](https://www.apollographql.com/docs/react/recipes/pagination.html)
"""
type ProductConnection {
  "The list of nodes that match the query, wrapped in an edge to provide a cursor string for each"
  edges: [ProductEdge]

  """
  You can request the `nodes` directly to avoid the extra wrapping that `NodeEdge` has,
  if you know you will not need to paginate the results.
  """
  nodes: [Product]

  "Information to help a client request the next or previous page"
  pageInfo: PageInfo!

  "The total number of nodes that match your query"
  totalCount: Int!
}

"Input for the `archiveProducts` mutation"
input ArchiveProductsInput  {
  "Array of IDs of products to archive"
  productIds: [ID]!

  "ID of shop that owns all products you are archiving"
  shopId: ID!
}

"Input for the `archiveProducts` mutation"
input ArchiveProductVariantsInput  {
  "ID of shop that owns all variants you are archiving"
  shopId: ID!

  "Array of IDs of variants to archive"
  variantIds: [ID]!
}

"Input for the `updateProductsVisibility` mutation"
input UpdateProductsVisibilityInput {
  "The desired visibility"
  isVisible: Boolean!

  "Array of product ids to update"
  productIds: [ID]!

  "ID of shop the products belong to"
  shopId: ID!
}

"Input for the `createProduct` mutation"
input CreateProductInput {
  "Product input"
  product: ProductInput

  "ID of shop product will belong to"
  shopId: ID!

  "Set to false if you do not want to auto-create the first variant of the product"
  shouldCreateFirstVariant: Boolean = true
}

"Input for the `createProductVariant` mutation"
input CreateProductVariantInput {
  "ID of product variant belongs to"
  productId: ID!

  "ID of shop product variant will belong to"
  shopId: ID!

  "Variant input"
  variant: ProductVariantInput
}

"Input for the `cloneProducts` mutation"
input CloneProductsInput  {
  "Array of IDs of products to clone"
  productIds: [ID]!

  "ID of shop that owns all products you are cloning"
  shopId: ID!
}

"Input for the `cloneProductVariants` mutation"
input CloneProductVariantsInput  {
  "ID of shop that owns all product variants you want to clone"
  shopId: ID!

  "Array of IDs of variants to clone"
  variantIds: [ID]!
}

"Input for the `updateProduct` mutation"
input UpdateProductInput {
  "Product input"
  product: ProductInput!

  "ID of product to update"
  productId: ID!

  "ID of shop that owns the product to update"
  shopId: ID!
}

"Mutation input for a product"
input ProductInput {
  """
  Any string to use as the internal ID for a new product. Do not prefix or base64 encode this ID.
  This field is allowed only when creating a product. If you include an ID for an update, you
  will get an error. The string must also be different from any existing product, variant, or
  option internal ID or you will get a duplicate ID error. If you do not include this when creating
  a product, a random unique string is generated for you.
  """
  _id: String

  "The full product description, which may have newline characters in it"
  description: String

  "Facebook message"
  facebookMsg: String

  "Google message"
  googleplusMsg: String

  "True if this product has been deleted. Typically, deleted products are not returned in queries."
  isDeleted: Boolean

  "True if this product should be shown to shoppers. Typically, non-visible products are not returned in queries."
  isVisible: Boolean

  "The product description to use for page `description` meta element in HTML"
  metaDescription: String

  "Arbitrary additional metadata about this product"
  metafields: [MetafieldInput]

  "The country of origin"
  originCountry: String

  "Subtitle"
  pageTitle: String

  "Pinterest message"
  pinterestMsg: String

  "An arbitrary product type value, such as from an external system"
  productType: String

  "Whether this product will be shown in the generated sitemap"
  shouldAppearInSitemap: Boolean

  "A URL-safe and human-readable string that uniquely identifies this product"
  slug: String

  "When a shopper purchases this product, what types of fulfillment can they choose from?"
  supportedFulfillmentTypes: [FulfillmentType]

  "The list of tag IDs that have been applied to this product"
  tagIds: [ID]

  "Product title"
  title: String

  "Twitter message"
  twitterMsg: String

  "The product vendor or manufacturer, for display"
  vendor: String
}

"Mutation input for a product variant or option"
input ProductVariantInput {
  """
  Any string to use as the internal ID for a new variant. Do not prefix or base64 encode this ID.
  This field is allowed only when creating a variant. If you include an ID for an update, you
  will get an error. The string must also be different from any existing product, variant, or
  option internal ID or you will get a duplicate ID error. If you do not include this when creating
  a variant, a random unique string is generated for you.
  """
  _id: String

  """
  The attribute label describes the category of variant, for example, `Color` or `Size`.
  In most cases this will be the same for all variants at the same level.
  """
  attributeLabel: String

  "The product variant barcode value, if it has one"
  barcode: String

  "The height of the product variant, if it has physical dimensions"
  height: Float

  "The position of this variant among other variants at the same level of the product-variant-option hierarchy"
  index: Int

  "True if this variant was deleted. Deleted variants are not published to the catalog."
  isDeleted: Boolean

  "True if this variant is visible. Hidden variants are not published to the catalog."
  isVisible: Boolean

  "The length of the product, if it has physical dimensions"
  length: Float

  "Arbitrary additional metadata about this product"
  metafields: [MetafieldInput]

  "The minimum quantity that must be added to a cart"
  minOrderQuantity: Int

  "A short title to use for product detail select lists"
  optionTitle: String

  "The country of origin"
  originCountry: String

  "SKU of variant"
  sku: String

  """
  The full variant title for use on cart, checkout, and order summaries and on invoices.
  This fully describes the configured variant. For example, if this is an option with
  `optionTitle` `Large`, its parent variant has `optionTitle` `Red`, and the product
  `title` is `Fancy T-Shirt`, then this `title` will be something like `Fancy T-Shirt - Red - Large`.
  """
  title: String

  "The weight of the product on Earth, if it has physical dimensions"
  weight: Float

  "The width of the product, if it has physical dimensions"
  width: Float
}

"Input for the `updateProductVariantField` mutation"
input UpdateProductVariantInput  {
  "ID of shop that owns the variant to update"
  shopId: ID!

  "Variant input"
  variant: ProductVariantInput!

  "ID of variant to update"
  variantId: ID!
}


"The fields by which you are allowed to sort any query that returns a `ProductConnection`"
enum ProductSortByField {
  "Product ID"
  _id

  "Date and time the product was created"
  createdAt

  "Product title"
  title

  "Date and time the product was last updated"
  updatedAt
}

"Range operator for DateTime fields"
input ProductDateRange {
  "The start of the date range"
  start: DateTime!

  "The end of the date range"
  end: DateTime!
}

"Operators for filtering on a DateTime field"
input ProductDateOperators {
  "The value must be equal to the given value"
  eq: DateTime

  "The value must be greater than the given value"
  before: DateTime

  "The value must be greater than or equal to the given value"
  after: DateTime

  "The value must be between the given values"
  between: ProductDateRange
}

extend type Mutation {
  "Archive products"
  archiveProducts(
    "Mutation input"
    input: ArchiveProductsInput!
  ): ArchiveProductsPayload!

  "Archive product variants"
  archiveProductVariants(
    "Mutation input"
    input: ArchiveProductVariantsInput!
  ): ArchiveProductVariantsPayload!

  "Update the isVisible property of an array of products"
  updateProductsVisibility(
    "Mutation input"
    input: UpdateProductsVisibilityInput!
  ): UpdateProductsVisibilityPayload!

  "Create a new product"
  createProduct(
    "Mutation input"
    input: CreateProductInput!
  ): CreateProductPayload!

  "Create a new product variant"
  createProductVariant(
    "Mutation input"
    input: CreateProductVariantInput!
  ): CreateProductVariantPayload!

  "Clone an existing product"
  cloneProducts(
    "Mutation input"
    input: CloneProductsInput!
  ): CloneProductsPayload!

  "Clone an existing product variant"
  cloneProductVariants(
    "Mutation input"
    input: CloneProductVariantsInput!
  ): CloneProductVariantsPayload!

  "Update an existing product"
  updateProduct(
    "Mutation input"
    input: UpdateProductInput!
  ): UpdateProductPayload!

  "Update an existing product variant"
  updateProductVariant(
    "Mutation input"
    input: UpdateProductVariantInput!
  ): UpdateProductVariantPayload!
}

extend type Query {
  "Query to get a filtered list of Products"
  filterProducts(
    "Shop ID"
    shopId: ID!,

    "Input Conditions for fliter (use either 'any' or 'all' not both)"
    conditions: FilterConditionsInput,

    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int

    "Return results sorted in this order"
    sortOrder: SortOrder = desc,

    "By default, products are sorted by createdAt. Set this to sort by one of the other allowed fields"
    sortBy: ProductSortByField = createdAt
  ): ProductConnection
  
  "Query for a single Product"
  product(
    "Product ID"
    productId: ID!,

    "Shop ID"
    shopId: ID!

  ): Product

  "Query for a list of Products"
  products(
    "Filter by created timestamp"
    createdAt: ProductDateOperators

    "Filter by updated at timestamp"
    updatedAt: ProductDateOperators

    "Filter by archived"
    isArchived: Boolean

    "Filter by visibility"
    isVisible: Boolean

    "Flag to set metafields search method. Default value false, performs a fuzzy search. Explicitly set it to true to perform exact match."
    isExactMatch: Boolean = false

    "Filter by metafield key using `regex` match. To get specific searches send the argument as a regex pattern"
    metafieldKey: String

    "Filter by metafield value using `regex` match. To get specific searches send the argument as a regex pattern"
    metafieldValue: String

    "Filter by price range maximum value"
    priceMax: Float

    "Filter by price range minimum value"
    priceMin: Float

    "List of product IDs to filter by"
    productIds: [ID]

    "Regex metch query string"
    query: String

    "List of shop IDs to filter by"
    shopIds: [ID]!

    "List of tag ids to filter by"
    tagIds: [ID]

    "Return only results that come after this cursor. Use this with `first` to specify the number of results to return."
    after: ConnectionCursor,

    "Return only results that come before this cursor. Use this with `last` to specify the number of results to return."
    before: ConnectionCursor,

    "Return at most this many results. This parameter may be used with either `after` or `offset` parameters."
    first: ConnectionLimitInt,

    "Return at most this many results. This parameter may be used with the `before` parameter."
    last: ConnectionLimitInt,

    "Return only results that come after the Nth result. This parameter may be used with the `first` parameter."
    offset: Int,

    "Return results sorted in this order"
    sortOrder: SortOrder = desc,

    "By default, products are sorted by createdAt. Set this to sort by one of the other allowed fields"
    sortBy: ProductSortByField = createdAt
  ): ProductConnection
}
