# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.1] - 2026-03-11
### Fixed
- `build_params?: false` no longer raises when used on non-struct factories (or inherited from a
parent module). Non-struct factories always generate their `build_*` functions regardless of this
option. Previously, the compile-time validation predated barebones factories and incorrectly
rejected this combination.
## [0.4.0] - 2026-03-10
### Changed
- **Breaking:** Non-struct factories now generate `build_*/0,1` and `build_*_list/1,2` instead of
`build_*_params/0,1` and `build_*_params_list/1,2`. The `_params` suffix was misleading for
factories that can return any value. Struct factories are unchanged.
## [0.3.2] - 2026-03-10
### Added
- `params_for_*` and `string_params_for_*` functions for Ecto schema factories. These build a
struct then strip Ecto metadata (`__meta__`, autogenerated IDs, `NotLoaded` associations,
`belongs_to` structs), returning a clean map for changesets or controller tests. Foreign keys
are set automatically for persisted `belongs_to` associations.
- Unlike ExMachina's `params_for`, nil values are preserved (not silently dropped) and
`string_params_for` leaves struct values like `DateTime` untouched (not converted to maps).
## [0.3.1] - 2026-03-10
### Added
- Factory bodies can now return arbitrary values (strings, keyword lists, tuples, nil, etc.),
not just maps. Factories without `:struct` are no longer restricted to returning maps.
- Lazy evaluation now works in keyword lists — 0-arity and 1-arity function values are resolved
at build time, matching the existing behavior for maps and structs.
### Fixed
- `build_*_params_list/1` (single-arity convenience) now calls the factory with its actual default
argument instead of always passing `%{}`. Previously, factories with non-map defaults would crash
when using the list builder without explicit arguments.
## [0.3.0] - 2026-03-10
### Changed
- **Breaking:** Renamed `params?` option to `build_params?` for consistency with `build_struct?`
## [0.2.2] - 2026-03-10
### Added
- Duplicate option warnings: FactoryMan now emits a compile-time `Logger.warning` when a child
factory module or `deffactory` specifies an option that is already defined by the parent with
the same value. Helps catch redundant copy-pasted options.
- `suppress_duplicate_option_warning: true` option to silence the warning at module or factory
level when the duplication is intentional. This option does not propagate to child modules.
## [0.2.1] - 2026-03-09
### Added
- `:as` option for `defvariant` to customize the generated function name. By default, variant
functions are named `{variant}_{base}` (e.g. `build_admin_user_struct`). The `:as` option
overrides this combined name (e.g. `as: :mod` generates `build_mod_struct` instead of
`build_moderator_user_struct`).
## [0.2.0] - 2026-03-08
### Added
- `build_params?: false` option for `deffactory`. When set, the factory body returns a struct directly
instead of a params map. No `build_*_params` functions are generated. Useful for complex
factories that need full control over struct construction (e.g. resolving associations from
other factories, conditional logic). Can be set at module level or factory level.
- `defvariant` macro for defining variant factories that wrap a base factory. The variant body
is a preprocessor: it transforms caller params before delegating to the base factory. Generates
the full set of named functions (e.g. `build_admin_user_struct/0,1`, `insert_admin_user!/0,1,2`).
- Compile-time validation: `build_params?: false` without `struct:` raises `ArgumentError`
- Compile-time validation: `defvariant` referencing undefined base factory raises `ArgumentError`
### Fixed
- Flaky "circular sequence cycles through values" test that depended on test ordering. Added
`FactoryMan.Sequence.reset()` to ensure predictable starting position.
## [0.1.1] - 2026-03-07
### Fixed
- Factory-level hooks were being flattened into top-level options instead of staying nested under
the `:hooks` key. This caused `_factory_opts()` and `_<name>_factory_opts()` debug functions to
return a polluted keyword list with hook keys (e.g. `:after_insert`) mixed in alongside
configuration keys (e.g. `:repo`, `:struct`). Hooks now stay properly nested.
- Fixed several inaccurate examples in moduledoc and README (e.g. `build_api_payload()` corrected
to `build_api_payload_params()`, missing `Map.merge` calls in examples)
### Changed
- Replaced `List.pop_at` with `Enum.at` in `FactoryMan.Sequence` for list-based sequences
(avoids constructing an unused remainder list)
- Reorganized demo factory definitions into logical sections: core, lazy evaluation, sequences,
factory options, and parameter patterns
- Removed redundant demo factories (`params_only`, `with_custom_param_name`) and renamed
`with_after_build_params_hook` to `hooked`
- Refactored test suite: reorganized into `describe` blocks by feature, removed ~21 redundant
tests, fixed misleading test names and broken assertions. 69 tests remain (was 90), all
meaningful.
- Added Dialyzer configuration (`plt_add_apps: [:ex_unit]`). Zero warnings.
- Expanded hooks documentation with pipeline diagram, reference table, precedence rules, and
practical examples
- Added lazy evaluation ordering warning explaining that 1-arity lazy functions receive the
pre-evaluation map
- Rewrote AGENTS.md with usage rules, canonical patterns, and anti-patterns
## [0.1.0] - 2026-02-08
### Added
- Initial alpha release
- `deffactory` macro for defining factories
- Automatic struct building with `build_*_struct` functions
- Database insertion with `insert_*!` functions
- Params-only factories without database dependency (i.e. only has `build_*_params` and `build_*_params_list`)
- Sequence generation for unique values
- Lazy evaluation for computed attributes
- Factory inheritance via `:extends` option
- Hooks system for custom transformations
- List factories for bulk data creation (`*_list` variants)
- Support for embedded schemas (Build struct, but do not attempt to generate `insert_*` functions)