Orchestrates batch migration of product images from external URLs to Storage module.
Provides functions to query migration status, queue migration jobs, and migrate individual products.
Usage
# Get migration statistics
stats = ImageMigration.migration_stats()
# => %{total: 100, migrated: 25, pending: 75, failed: 0}
# Queue all pending products for migration
{:ok, count} = ImageMigration.queue_all_migrations(user_id)
# => {:ok, 75}
# Migrate a single product synchronously
{:ok, product} = ImageMigration.migrate_product(product_id, user_id)
Summary
Functions
Cancels all pending migration jobs.
Migrates a single product synchronously.
Returns migration statistics.
Returns the count of products that have been migrated.
Returns products that need image migration.
Returns the count of products needing migration.
Queues migration jobs for all products needing migration.
Functions
@spec cancel_pending_migrations() :: {:ok, non_neg_integer()}
Cancels all pending migration jobs.
Returns
{:ok, count}- Number of jobs cancelled
@spec migrate_product(String.t(), String.t() | integer()) :: {:ok, PhoenixKit.Modules.Shop.Product.t()} | {:error, term()}
Migrates a single product synchronously.
Downloads all legacy images and updates the product with storage UUIDs.
Returns
{:ok, product}- Updated product with storage image IDs{:error, :already_migrated}- Product already has storage images{:error, :no_images}- Product has no legacy images to migrate{:error, reason}- Migration failed
Examples
iex> migrate_product(product_id, user_id)
{:ok, %Product{featured_image_id: "uuid-1", image_ids: ["uuid-1", "uuid-2"]}}
@spec migration_stats() :: map()
Returns migration statistics.
Returns
A map with the following keys:
:total- Total products with any images (legacy or storage):migrated- Products that have storage-based images:pending- Products with legacy images but no storage images:failed- Count of failed migration jobs (from Oban):in_progress- Count of currently running migration jobs
Examples
iex> migration_stats()
%{total: 100, migrated: 25, pending: 75, failed: 0, in_progress: 5}
@spec products_migrated_count() :: non_neg_integer()
Returns the count of products that have been migrated.
Examples
iex> products_migrated_count()
25
@spec products_needing_migration(keyword()) :: [PhoenixKit.Modules.Shop.Product.t()]
Returns products that need image migration.
A product needs migration if it has legacy image URLs but no Storage UUIDs.
Options
:limit- Maximum number of products to return (default: all):offset- Number of products to skip (default: 0)
Examples
iex> products_needing_migration()
[%Product{}, %Product{}, ...]
iex> products_needing_migration(limit: 10)
[%Product{}, ...]
@spec products_needing_migration_count() :: non_neg_integer()
Returns the count of products needing migration.
Examples
iex> products_needing_migration_count()
75
@spec queue_all_migrations( String.t() | integer(), keyword() ) :: {:ok, non_neg_integer()} | {:error, term()}
Queues migration jobs for all products needing migration.
Creates an Oban job for each product that has legacy images but no storage images.
Options
:limit- Maximum number of products to queue (default: all):priority- Oban job priority (default: 3)
Returns
{:ok, count}- Number of jobs queued{:error, reason}- If queuing failed
Examples
iex> queue_all_migrations(user_id)
{:ok, 75}
iex> queue_all_migrations(user_id, limit: 10)
{:ok, 10}