Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Introduce association component#646

Merged
solnic merged 1 commit intomasterfrom
association-components
Jul 3, 2021
Merged

Introduce association component#646
solnic merged 1 commit intomasterfrom
association-components

Conversation

@solnic
Copy link
Member

@solnic solnic commented Jul 3, 2021

This is the first step towards schema<=>association decoupling.
Associations are now lazy-loaded via components and relations use their
own association resolver rather than relying on schema.

SchemaDSL still provides association definitions but this can be easily
improved so that Relation class can define its associations outside of
the schema block.

Associations are scoped to relations but it's possible to store them as
first-class components like the rest. I haven't done that though because
I'm not sure if this will be useful.

Here's a practical outcome of this change:

# here we get a relation object but its associations are NOT loaded yet
rom.relations[:users]
#<ROM::Relation[Users] name=ROM::Relation::Name(users) dataset=#<Sequel::Postgres::Dataset: "SELECT \"users\".\"id\", \"users\".\"name\" FROM \"users\" ORDER BY \"users\".\"id\"">>

# we can inspect the association resolver though and it still doesn't load associations
rom.relations[:users].associations.keys
["associations.users.posts", "associations.users.aliased_posts", "associations.users.labels", "associations.users.books"]

# once something asks for a specific association, it will be lazy-loaded
rom.relations[:users].associations[:labels]
#<ROM::SQL::Associations::ManyToMany definition=#<ROM::Associations::Definitions::ManyToMany source=ROM::Relation::Name(users) target=ROM::Relation::Name(labels) result=:many> source=#<ROM::Relation[Users] name=ROM::Relation::Name(users) dataset=#<Sequel::Postgres::Dataset: "SELECT \"users\".\"id\", \"users\".\"name\" FROM \"users\" ORDER BY \"users\".\"id\"">> target=#<ROM::Relation[Labels] name=ROM::Relation::Name(labels) dataset=#<Sequel::Postgres::Dataset: "SELECT \"labels\".\"id\", \"labels\".\"name\" FROM \"labels\" ORDER BY \"labels\".\"id\"">>>

There are various improvements that should be made eventually. Probably
the most important one is adding Association#inverse_of(another) so
that resolving "another side" can be done in a more robust way.
For example if you have "users.has_many(:posts)" but on the other side you
have "posts.belongs_to(:user, as: :author)" then it's tricky to figure it
out without a proper abstraction. Luckily, we have all the information
in the right place to implement it.

This is the first step towards schema<=>association decoupling.
Associations are now lazy-loaded via components and relations use their
own association resolver rather than relying on schema.

SchemaDSL still provides association definitions but this can be easily
improved so that Relation class can define its associations outside of
the schema block.

Associations are scoped to relations but it's possible to store them as
first-class components like the rest. I haven't done that though because
I'm not sure if this will be useful.

Here's a practical outcome of this change:

```ruby
\# here we get a relation object but its associations are NOT loaded yet
rom.relations[:users]
\#<ROM::Relation[Users] name=ROM::Relation::Name(users) dataset=#<Sequel::Postgres::Dataset: "SELECT \"users\".\"id\", \"users\".\"name\" FROM \"users\" ORDER BY \"users\".\"id\"">>

\# we can inspect the association resolver though and it still doesn't load associations
rom.relations[:users].associations.keys
["associations.users.posts", "associations.users.aliased_posts", "associations.users.labels", "associations.users.books"]

\# once something asks for a specific association, it will be lazy-loaded
rom.relations[:users].associations[:labels]
\#<ROM::SQL::Associations::ManyToMany definition=#<ROM::Associations::Definitions::ManyToMany source=ROM::Relation::Name(users) target=ROM::Relation::Name(labels) result=:many> source=#<ROM::Relation[Users] name=ROM::Relation::Name(users) dataset=#<Sequel::Postgres::Dataset: "SELECT \"users\".\"id\", \"users\".\"name\" FROM \"users\" ORDER BY \"users\".\"id\"">> target=#<ROM::Relation[Labels] name=ROM::Relation::Name(labels) dataset=#<Sequel::Postgres::Dataset: "SELECT \"labels\".\"id\", \"labels\".\"name\" FROM \"labels\" ORDER BY \"labels\".\"id\"">>>
```

There are various improvements that should be made eventually. Probably
the most important one is adding `Association#inverse_of(another)` so
that resolving "another side" can be done in a more robust way.
For example if you have "users.has_many(:posts)" but on the other side you
have "posts.belongs_to(:user, as: :author)" then it's tricky to figure it
out without a proper abstraction. Luckily, we have all the information
in the right place to implement it.
@solnic solnic force-pushed the association-components branch from 872a78f to 0689803 Compare July 3, 2021 13:19
@solnic solnic merged commit a16001e into master Jul 3, 2021
@solnic solnic deleted the association-components branch July 3, 2021 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant