PhoenixKitEcommerce.ProductSource.Catalogue.Query (PhoenixKitEcommerce v0.5.0)

Copy Markdown View Source

Ecto queries over phoenix_kit_catalogue's Item/Category schemas, scoped to the one catalogue the shop reads (get_config("shop_catalogue"), default name "decor3dprint", resolved through Catalogue.list_catalogues/0).

Returns raw catalogue structs — PhoenixKitEcommerce.ProductSource.Catalogue turns them into view-structs via Catalogue.View. Nothing here is called unless ProductSource.current/0 already picked this adapter, which requires phoenix_kit_catalogue to be loaded; @compile {:no_warn_undefined, ...} only quietens the compiler's static xref check for hosts that don't declare the optional dependency.

Summary

Functions

Facet counts for one attribute SET's values (set_slug — the set's entities blueprint name, with or without the "catalogue_set_" prefix, same lookup filter_by_metadata/2 uses), scoped to storefront-visible items (active_visibility/1) in the shop catalogue.

The uuid of the one catalogue the shop reads, or nil when it can't be resolved (not yet bootstrapped, or the configured name matches none). Resolved by name on every call — the shop has one catalogue, so this is one small SELECT against a handful of rows, not a per-request bottleneck.

Count of items matching opts (no pagination applied).

Fetches one category by uuid, scoped to the shop catalogue.

Fetches one item by uuid, scoped to the shop catalogue. nil on a miss.

Lists the shop catalogue's categories.

Fetches categories by uuid, scoped to the shop catalogue. Missing uuids dropped.

Lists items matching opts, ordered by position, name.

Fetches items by uuid, order preserved, missing uuids dropped, scoped to the shop catalogue (same "one catalogue only" contract every other read in this module enforces) — mirrors PhoenixKitEcommerce.ProductSource.Legacy.list_products_by_ids/1.

list_items/1 plus the total count before pagination is applied.

Min/max base_price over active items, optionally scoped to a category.

Active-item counts grouped by category_uuid, "active" meaning item.status == "active" and COALESCE(shop_status, 'active') = 'active' (spec principle 7, same fallback as the listing) — items with no category are excluded, same as ProductSource.Legacy.product_counts_by_category/0.

Translated display names for a batch of attribute-set BLUEPRINTS, keyed by set uuid (AttributeSets.resolve_for_item/2's per-set :uuid field) — ProductSource.Catalogue swaps a resolved set's :name for this before handing sets to View.product_view/2 (which is pure and has no way to read settings["translations"] itself). One AttributeSets.get_set/2 call per DISTINCT set, never per item — a product page has a handful of attached sets, and a listing page's many items still share that same handful, so the count stays small; there is no batched-by-uuid-list entities read to reach for instead. A set that can't be resolved (deleted, or gated by get_set/2's own owner check) is simply absent from the result — callers keep the untranslated :name already on the resolved set for it.

Translated display name of one attribute set by its FILTER-CONFIG slug (set_slug — with or without the catalogue_set_ prefix, same lookup filter_by_metadata/2 uses), nil when the slug doesn't resolve to a set. The sidebar's attribute_set/metadata_option filter section reads this — a filter config only ever carries the slug, never the set's uuid.

Distinct vendor values (from data["ecommerce"]["vendor"]) over active items, with counts, optionally scoped to a category.

Functions

attribute_set_counts(set_slug, opts \\ [])

@spec attribute_set_counts(String.t(), keyword()) :: [
  %{slug: String.t(), label: String.t(), count: non_neg_integer()}
]

Facet counts for one attribute SET's values (set_slug — the set's entities blueprint name, with or without the "catalogue_set_" prefix, same lookup filter_by_metadata/2 uses), scoped to storefront-visible items (active_visibility/1) in the shop catalogue.

Options: :category_uuid (scope to one category), :exclude_hidden_categories (drop items whose category's shop_status is "hidden"), :language (prefer data[language]["_title"] over the value's bare title — the picker/sidebar's fuller per-language resolution is Block 5's remaining work; this covers the plain value label).

A value with no published EntityData row for the requested slug never appears — draft/archived values (Block 5's resolver creates unknown Shopify strings as draft) are excluded from storefront facets by construction, not by a separate filter.

Ordered by the value's position, then its resolved label.

catalogue_uuid()

@spec catalogue_uuid() :: Ecto.UUID.t() | nil

The uuid of the one catalogue the shop reads, or nil when it can't be resolved (not yet bootstrapped, or the configured name matches none). Resolved by name on every call — the shop has one catalogue, so this is one small SELECT against a handful of rows, not a per-request bottleneck.

count_items(opts \\ [])

@spec count_items(keyword()) :: non_neg_integer()

Count of items matching opts (no pagination applied).

get_category(uuid)

@spec get_category(String.t()) :: PhoenixKitCatalogue.Schemas.Category.t() | nil

Fetches one category by uuid, scoped to the shop catalogue.

get_item(uuid)

@spec get_item(String.t()) :: PhoenixKitCatalogue.Schemas.Item.t() | nil

Fetches one item by uuid, scoped to the shop catalogue. nil on a miss.

list_categories(opts \\ [])

@spec list_categories(keyword()) :: [PhoenixKitCatalogue.Schemas.Category.t()]

Lists the shop catalogue's categories.

list_categories_by_uuids(uuids)

@spec list_categories_by_uuids([String.t()]) :: [
  PhoenixKitCatalogue.Schemas.Category.t()
]

Fetches categories by uuid, scoped to the shop catalogue. Missing uuids dropped.

list_items(opts \\ [])

@spec list_items(keyword()) :: [PhoenixKitCatalogue.Schemas.Item.t()]

Lists items matching opts, ordered by position, name.

list_items_by_uuids(uuids)

@spec list_items_by_uuids([Ecto.UUID.t()]) :: [PhoenixKitCatalogue.Schemas.Item.t()]

Fetches items by uuid, order preserved, missing uuids dropped, scoped to the shop catalogue (same "one catalogue only" contract every other read in this module enforces) — mirrors PhoenixKitEcommerce.ProductSource.Legacy.list_products_by_ids/1.

list_items_with_count(opts \\ [])

@spec list_items_with_count(keyword()) ::
  {[PhoenixKitCatalogue.Schemas.Item.t()], non_neg_integer()}

list_items/1 plus the total count before pagination is applied.

price_range(opts \\ [])

@spec price_range(keyword()) :: {Decimal.t() | nil, Decimal.t() | nil}

Min/max base_price over active items, optionally scoped to a category.

product_counts_by_category()

@spec product_counts_by_category() :: %{required(String.t()) => non_neg_integer()}

Active-item counts grouped by category_uuid, "active" meaning item.status == "active" and COALESCE(shop_status, 'active') = 'active' (spec principle 7, same fallback as the listing) — items with no category are excluded, same as ProductSource.Legacy.product_counts_by_category/0.

set_display_names(set_uuids, language)

@spec set_display_names([Ecto.UUID.t()], String.t()) :: %{
  required(Ecto.UUID.t()) => String.t()
}

Translated display names for a batch of attribute-set BLUEPRINTS, keyed by set uuid (AttributeSets.resolve_for_item/2's per-set :uuid field) — ProductSource.Catalogue swaps a resolved set's :name for this before handing sets to View.product_view/2 (which is pure and has no way to read settings["translations"] itself). One AttributeSets.get_set/2 call per DISTINCT set, never per item — a product page has a handful of attached sets, and a listing page's many items still share that same handful, so the count stays small; there is no batched-by-uuid-list entities read to reach for instead. A set that can't be resolved (deleted, or gated by get_set/2's own owner check) is simply absent from the result — callers keep the untranslated :name already on the resolved set for it.

set_label(set_slug, language)

@spec set_label(String.t(), String.t()) :: String.t() | nil

Translated display name of one attribute set by its FILTER-CONFIG slug (set_slug — with or without the catalogue_set_ prefix, same lookup filter_by_metadata/2 uses), nil when the slug doesn't resolve to a set. The sidebar's attribute_set/metadata_option filter section reads this — a filter config only ever carries the slug, never the set's uuid.

vendor_counts(opts \\ [])

@spec vendor_counts(keyword()) :: [%{value: String.t(), count: non_neg_integer()}]

Distinct vendor values (from data["ecommerce"]["vendor"]) over active items, with counts, optionally scoped to a category.