kaspth / oaken

A fresh blended alternative to Fixtures & FactoryBot for dev and test data.
MIT License
201 stars 6 forks source link

Group Fixtures converter output around root model e.g. Account #65

Closed kaspth closed 1 year ago

kaspth commented 1 year ago

Right now our converter can take a structure like this:

# test/fixtures/accounts.yml
demo:
  name: Demonstrable Inc.

kaspers_donuts:
  name: Kasper's Donuts

# test/fixtures/users.yml
kasper:
  name: Kasper
  accounts: kaspers_donuts

coworker:
  name: Coworker
  accounts: kaspers_donuts

super_supporter:
  name: Super Supporter

# test/fixtures/menus.yml
donuts:
  account: kaspers_donuts

# test/fixtures/menu/items.yml
plain_donut:
  menu: donuts
  name: Plain
  price_cents: 10_00

sprinkled_donut:
  menu: donuts
  name: Sprinkled
  price_cents: 10_10

And then when run with bin/rails g oaken:convert:fixtures --root-model=Account --no-keeps build:

# db/seeds.rb
Oaken.prepare do
  register Menu::Item

  seed :accounts, :data
end

# db/seeds/test/accounts/demo.rb
demo = accounts.create :demo, name: "Demonstrable Inc."
menus.create :donuts, account: kaspers_donuts # Not sure why it puts this here

# db/seeds/test/accounts/kaspers_donuts.rb
kaspers_donuts = accounts.create :kaspers_donuts, name: "Kasper's Donuts"
menus.create :donuts, account: kaspers_donuts
users.create :kasper, name: "Kasper", accounts: kaspers_donuts
users.create :coworker, name: "Coworker", accounts: kaspers_donuts

So we can recognize anything that references the account directly and put it into the right file.

We don't recognize second-level connections, e.g. menu/items.yml should be in accounts/kaspers_donuts.rb and I'm wondering if we should even bother. If we just generate the Oaken syntax and put everything into a file like db/seeds/test/FIXTURES_TO_ASSOCIATE.rb that looks like:

# test/fixtures/menu/items.yml
plain_donut = menu_items.create :plain_donut, menu: donuts, price_cents: 10_00
sprinkled_donut = menu_items.create :sprinkled_donut, menu: donuts, price_cents: 10_10

# Other files here…

Then people can copy paste into the right file by matching the variable name, e.g. find which account file has the donuts variable from menu: donuts.

kaspth commented 1 year ago

I got it working recursively!

So now we generate this:

# db/seeds.rb
Oaken.prepare do
  register Menu::Item

  seed :accounts, :data
end

# db/seeds/test/accounts/demo.rb
accounts.create :demo, name: "Demonstrable Inc."

# There's an extra newline in this file when there's no dependents, but that's a rare case so we probably don't see that live.

# db/seeds/test/accounts/kaspers_donuts.rb
kaspers_donuts = accounts.create :kaspers_donuts, name: "Kasper's Donuts"

donuts = menus.create :donuts, account: kaspers_donuts
menu_items.create :plain_donut, menu: donuts, name: "Plain", price_cents: 1000
menu_items.create :sprinkled_donut, menu: donuts, name: "Sprinkled", price_cents: 1010

users.create :kasper, name: "Kasper", accounts: [kaspers_donuts]
users.create :coworker, name: "Coworker", accounts: [kaspers_donuts]
kaspth commented 1 year ago

Ok, now we're also generating data seed files for any unreferenced data segmented by table.

So these:

# test/fixtures/plans.yml
test_premium:
  title: Test Premium
  price_cents: 20_00

# test/fixtures/users.yml
super_supporter:
  name: Super Supporter

Will generate:

# db/seeds/test/data/plans.rb
plans.create :test_premium, title: "Test Premium", price_cents: 2000 # Note we can't preserve the `_`

# db/seeds/test/data/users.rb
users.create :super_supporter, name: "Super Supporter"
kaspth commented 1 year ago

There's some strange newlines generated somewhere, but that'll be for tomorrow.