Packages

phoenix_kit

1.7.76
1.7.210 1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib mix tasks phoenix_kit entities export.ex
Raw

lib/mix/tasks/phoenix_kit/entities/export.ex

defmodule Mix.Tasks.PhoenixKit.Entities.Export do
@shortdoc "Export entities and entity data to JSON files"
@moduledoc """
Mix task to export entity definitions and data to JSON files.
Each entity is exported as a single file containing both the definition
and all its data records.
Exports are stored in the configured mirror path (default: priv/entities/).
## Usage
# Export all entities (definitions + data if data mirroring enabled)
mix phoenix_kit.entities.export
# Export specific entity
mix phoenix_kit.entities.export --entity brand
# Export with data included (regardless of setting)
mix phoenix_kit.entities.export --with-data
# Export without data (regardless of setting)
mix phoenix_kit.entities.export --no-data
# Custom output path
mix phoenix_kit.entities.export --output /path/to/export
## Options
--entity NAME Export specific entity only
--with-data Include data records in export
--no-data Exclude data records from export
--output PATH Custom output directory (overrides settings)
--quiet Suppress output messages
## Output Structure
priv/entities/
brand.json # Contains definition + all data records
product.json # Contains definition + all data records
## JSON Format
{
"export_version": "1.0",
"exported_at": "2025-12-11T10:30:00Z",
"definition": {
"name": "brand",
"display_name": "Brand",
...
},
"data": [
{"title": "Acme Corp", "slug": "acme-corp", ...},
{"title": "Globex", "slug": "globex", ...}
]
}
## Examples
# Full export for version control backup
mix phoenix_kit.entities.export --with-data
# Export just the brand entity
mix phoenix_kit.entities.export --entity brand
# Export to a specific directory
mix phoenix_kit.entities.export --output ./backup/entities
"""
use Mix.Task
alias PhoenixKit.Modules.Entities
alias PhoenixKit.Modules.Entities.EntityData
alias PhoenixKit.Modules.Entities.Mirror.Storage
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Date, as: UtilsDate
@export_version "1.0"
@impl Mix.Task
def run(args) do
Mix.Task.run("app.start")
{options, _remaining} = parse_options(args)
# Override path if specified
if output_path = options[:output] do
Settings.update_setting("entities_mirror_path", output_path)
end
# Ensure directory exists
Storage.ensure_directory()
if options[:entity] do
export_single_entity(options[:entity], options)
else
export_all(options)
end
end
defp parse_options(args) do
{options, remaining, _errors} =
OptionParser.parse(args,
strict: [
entity: :string,
with_data: :boolean,
no_data: :boolean,
output: :string,
quiet: :boolean
],
aliases: [
e: :entity,
o: :output,
q: :quiet
]
)
{Enum.into(options, %{}), remaining}
end
defp include_data?(options) do
cond do
options[:with_data] -> true
options[:no_data] -> false
true -> Storage.data_enabled?()
end
end
defp export_single_entity(entity_name, options) do
case Entities.get_entity_by_name(entity_name) do
nil ->
Mix.shell().error("Entity '#{entity_name}' not found.")
exit({:shutdown, 1})
entity ->
include_data = include_data?(options)
data_records = if include_data, do: EntityData.list_data_by_entity(entity.uuid), else: []
content = build_export_content(entity, data_records)
result = Storage.write_entity(entity.name, content)
log_result(entity_name, length(data_records), result, options)
log_summary([result], options)
end
end
defp export_all(options) do
unless options[:quiet] do
Mix.shell().info("Exporting all entities...")
end
include_data = include_data?(options)
results =
Entities.list_entities()
|> Enum.map(fn entity ->
data_records = if include_data, do: EntityData.list_data_by_entity(entity.uuid), else: []
content = build_export_content(entity, data_records)
result = Storage.write_entity(entity.name, content)
log_result(entity.name, length(data_records), result, options)
result
end)
log_summary(results, options)
end
defp build_export_content(entity, data_records) do
%{
"export_version" => @export_version,
"exported_at" => UtilsDate.utc_now() |> DateTime.to_iso8601(),
"definition" => serialize_entity(entity),
"data" => Enum.map(data_records, &serialize_entity_data/1)
}
end
defp serialize_entity(entity) do
%{
"name" => entity.name,
"display_name" => entity.display_name,
"display_name_plural" => entity.display_name_plural,
"description" => entity.description,
"icon" => entity.icon,
"status" => to_string(entity.status),
"fields_definition" => entity.fields_definition,
"settings" => entity.settings,
"date_created" => format_datetime(entity.date_created),
"date_updated" => format_datetime(entity.date_updated)
}
end
defp serialize_entity_data(record) do
%{
"title" => record.title,
"slug" => record.slug,
"status" => to_string(record.status),
"data" => record.data,
"metadata" => record.metadata,
"date_created" => format_datetime(record.date_created),
"date_updated" => format_datetime(record.date_updated)
}
end
defp format_datetime(nil), do: nil
defp format_datetime(%DateTime{} = dt), do: DateTime.to_iso8601(dt)
defp format_datetime(%NaiveDateTime{} = ndt), do: NaiveDateTime.to_iso8601(ndt)
defp format_datetime(other), do: to_string(other)
defp log_result(_name, _data_count, _result, %{quiet: true}), do: :ok
defp log_result(name, data_count, {:ok, path}, _options) do
data_info = if data_count > 0, do: " (#{data_count} records)", else: ""
Mix.shell().info(" #{name}#{data_info} -> #{path}")
end
defp log_result(name, _data_count, {:error, reason}, _options) do
Mix.shell().error(" #{name} failed: #{inspect(reason)}")
end
defp log_summary(_results, %{quiet: true}), do: :ok
defp log_summary(results, _options) do
success_count = Enum.count(results, &match?({:ok, _}, &1))
error_count = Enum.count(results, &match?({:error, _}, &1))
Mix.shell().info("\n--- Summary ---")
Mix.shell().info("Exported: #{success_count} entities")
if error_count > 0 do
Mix.shell().error("Errors: #{error_count}")
end
Mix.shell().info("Output path: #{Storage.root_path()}")
end
end