Open cllns opened 2 months ago
This just got me again.
My workaround for this not working was adding a default value in the struct with attribute :favorites_count, Types::Integer.default(0)
instead of in the factory definition.
It can properly create a struct, and it even fills in this favorites_count = 0
.
Then, I use a Repo to find that record I just created, and I get it back, with favorites_count also = 0 in this case.
But then I get article_repo.find_by_id(123) == factory_article
as false, even though article_repo.find_by_id(123).to_h == factory_article.to_h
is true. This is very surprising because they both appear to have the same class but they don't (see rom-rb/rom#610), when looking at their object_id's, one can see they're different. I looked into ROM::StructCompiler and indeed, the first time it's compiled (from the factory), it's missing the favorites_count, so it's a different Struct class than the one that does have favorites_count.
Factories are defined based on relation schemas, not struct schemas. If we wanted to support projected attributes we'd need a way of telling the factory that they exist. This can be done by defining your projected schema using view
DSL in relations. They are not supported by factory but we could make them work.
What if the definitions are still based on the relation, but the actual Factory object creation would allow values that exist on the Struct that's associated with the factory?
e.g. Factory[:article, favorites_count: 123]
Right now that raises this error: Unknown attributes: favorites_count (ROM::Factory::UnknownFactoryAttributes)
I'm not sure if that's simpler to implement.
Or, alternately, what if there were a syntax in defining the Factories that would let users define arbitrary attributes? After all, users can select_append
arbitrary tuples that get mapped to the struct, they're already "open" structs.
e.g.
MyFactory.define(:article, struct_namespace: Structs) do |f|
f.title "Title"
f.open do |o|
o.favorites_count(123) # which exists on the schema for the associated struct
o.promoted(false) # which doesn't need to exist on the schema for the associated struct
end
end
We could have a DSL for defining factories for custom structs too, like MyFactory.define(Article) do ...
Describe the bug
I have a custom struct for Article that holds the number of favorites attached to it (as
favorites_count
). This is computed via a join with the favorites relation.When trying to create a Factory for Article that has a
favorites_count
specified, I get an error onROM::Factory::DSL
saying the favorites_count is not defined.To Reproduce
Expected behavior
I would expect that I could define the factory as above. Then be able to use it with
MyFactory[:article]
andMyFactory.structs[:article]
where theStruct::Article
would have a favorites_count of 123.I think I would expect rom-factory to infer the attributes from the relation, but then also look at the associated struct (in the struct_namespace) to see if there are any other attributes there and allow those to be declared in the factory as well.
This may not be the proper way of doing this, so I'm open to feedback on the approach, and workarounds.
My environment