rom-rb / rom-factory

Data generator with support for persistence backends
MIT License
83 stars 42 forks source link

Add support for one-to-one-though associations #61

Closed ianks closed 4 years ago

ianks commented 4 years ago

This PR makes it possible to have OneToOneThrough in factories. This is incredibly important since oftentimes, one-to-one-throughs are critical when refactoring coupled relations in a codebase.

Caveats

I cannot get factories.struct(:user) to work with this. There is some strange stuff happening where the schema inferencing from the model expects a user_id on addresses, despite it being a has_one. I don't know how to resolve that. I believe there is some strange schema merging going on, but I do not have enough context to debug it. @solnic can someone help me with this?

Click here to show the backtrace
  1) ROM::Factory.structs one-to-one-through when building a struct persists the relation properly without pre-existing assoc record
     Failure/Error: model.new(attributes)

     Dry::Struct::Error:
       [ROM::Struct::Address.new] :user_id is missing in Hash input
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:392:in `block in resolve_missing_keys'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:383:in `each'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:383:in `resolve_missing_keys'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:347:in `resolve_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:62:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/constructor.rb:59:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-struct-1.3.0/lib/dry/struct/class_interface.rb:265:in `new'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-struct-1.3.0/lib/dry/struct/class_interface.rb:260:in `new'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-struct-1.3.0/lib/dry/struct/class_interface.rb:285:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/sum.rb:83:in `block in call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/constrained.rb:56:in `call_safe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/sum.rb:83:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema/key.rb:49:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:336:in `block in resolve_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:330:in `each'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:330:in `resolve_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:62:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/constructor.rb:59:in `call_unsafe'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-struct-1.3.0/lib/dry/struct/class_interface.rb:265:in `new'
     # ./lib/rom/factory/tuple_evaluator.rb:63:in `struct'
     # ./lib/rom/factory/builder.rb:45:in `struct'
     # ./lib/rom/factory/factories.rb:45:in `[]'
     # ./spec/integration/rom/factory_spec.rb:144:in `block (5 levels) in '
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:257:in `instance_exec'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:257:in `block in run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:503:in `block in with_around_and_singleton_context_hooks'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:460:in `block in with_around_example_hooks'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/hooks.rb:472:in `block in run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/hooks.rb:610:in `run_around_example_hooks_for'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/hooks.rb:472:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:460:in `with_around_example_hooks'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:503:in `with_around_and_singleton_context_hooks'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example.rb:254:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:633:in `block in run_examples'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:629:in `map'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:629:in `run_examples'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:595:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `block in run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `map'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `block in run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `map'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `block in run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `map'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/example_group.rb:596:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:121:in `block (3 levels) in run_specs'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:121:in `map'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:121:in `block (2 levels) in run_specs'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/configuration.rb:2031:in `with_suite_hooks'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:116:in `block in run_specs'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/reporter.rb:74:in `report'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:115:in `run_specs'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:89:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:71:in `run'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/lib/rspec/core/runner.rb:45:in `invoke'
     # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/rspec-core-3.9.0/exe/rspec:4:in `'
     # /home/ianks/.asdf/installs/ruby/2.6.6/bin/rspec:23:in `load'
     # /home/ianks/.asdf/installs/ruby/2.6.6/bin/rspec:23:in `'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/cli/exec.rb:63:in `load'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/cli/exec.rb:63:in `kernel_load'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/cli/exec.rb:28:in `run'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/cli.rb:476:in `exec'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/cli.rb:30:in `dispatch'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/cli.rb:24:in `start'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/exe/bundle:46:in `block in '
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/lib/bundler/friendly_errors.rb:123:in `with_friendly_errors'
     # /home/ianks/.gem/ruby/2.6.0/gems/bundler-2.1.1/exe/bundle:34:in `'
     # /home/ianks/.asdf/installs/ruby/2.6.6/bin/bundle:23:in `load'
     # /home/ianks/.asdf/installs/ruby/2.6.6/bin/bundle:23:in `
' # ------------------ # --- Caused by: --- # Dry::Types::MissingKeyError: # :user_id is missing in Hash input # /home/ianks/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/dry-types-1.4.0/lib/dry/types/schema.rb:392:in `block in resolve_missing_keys'

Summary

Overall, I think this PR is ready to go even without structs for now, wdyt?

ianks commented 4 years ago

Thank you @solnic!!