| defmodule Plausible.DataMigration.PrefixTrackerScriptConfigurationId do |
| @moduledoc """ |
| Migration to update tracker script configuration IDs to use the new prefixed format. |
| |
| This migration: |
| 1. Processes tracker configurations in batches to avoid memory issues |
| 2. Uses batch updates for better performance |
| 3. Handles the case where tracker configurations might not exist for all sites |
| 4. Provides progress logging |
| """ |
|
|
| import Ecto.Query |
| alias Plausible.Repo |
| alias Plausible.Site.TrackerScriptConfiguration |
|
|
| def run(batch_size \\ 100) do |
| total_configs = count_total_configurations() |
| IO.puts("Found #{total_configs} total tracker configurations to process") |
|
|
| process_batch(nil, total_configs, batch_size, 0) |
| end |
|
|
| defp count_total_configurations do |
| Repo.aggregate( |
| from(config in TrackerScriptConfiguration, |
| where: not like(config.id, "pa-%") |
| ), |
| :count, |
| :id |
| ) |
| end |
|
|
| defp process_batch(last_id, total_configs, batch_size, processed_count) do |
| configs = get_configurations_batch(last_id, batch_size) |
|
|
| if length(configs) > 0 do |
| batch_num = div(processed_count, batch_size) + 1 |
| start_pos = processed_count + 1 |
| end_pos = processed_count + length(configs) |
|
|
| IO.puts("Processing batch #{batch_num} (#{start_pos}-#{end_pos} of #{total_configs})") |
|
|
| process_configurations_batch(configs, batch_num) |
|
|
| process_batch( |
| List.last(configs).id, |
| total_configs, |
| batch_size, |
| processed_count + length(configs) |
| ) |
| else |
| IO.puts("Migration completed!") |
| end |
| end |
|
|
| defp get_configurations_batch(last_id, batch_size) do |
| query = |
| from(config in TrackerScriptConfiguration, |
| where: not like(config.id, "pa-%"), |
| order_by: [asc: config.id], |
| limit: ^batch_size, |
| select: %{ |
| id: config.id |
| } |
| ) |
|
|
| query = |
| if last_id do |
| from(config in query, where: config.id > ^last_id) |
| else |
| query |
| end |
|
|
| Repo.all(query) |
| end |
|
|
| defp process_configurations_batch(configs, batch_num) do |
| config_ids = Enum.map(configs, & &1.id) |
|
|
| case Repo.query( |
| "UPDATE tracker_script_configuration SET id = 'pa-' || id WHERE id = ANY($1)", |
| [config_ids] |
| ) do |
| {:ok, %{num_rows: updated_count}} -> |
| if updated_count != length(configs) do |
| IO.puts( |
| "Warning: Batch #{batch_num} - Expected to update #{length(configs)} configurations, but updated #{updated_count}" |
| ) |
| end |
|
|
| {:error, error} -> |
| IO.puts("Error updating batch #{batch_num}: #{inspect(error)}") |
| |
| end |
| end |
| end |
|
|