Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Top-level associations DSL #656

Merged
merged 3 commits into from
Jul 21, 2021
Merged

Conversation

solnic
Copy link
Member

@solnic solnic commented Jul 21, 2021

Originally, you could only define associations within schema blocks. This is no longer needed due to automatic resolution of runtime objects, including schemas and their attributes. So now we can define associations anywhere, the most obvious place is a relation itself of course.

To make this possible I had to port schema and associations DSLs to the new component-based DSL. Backward-compatibility is maintained via rom/compat.

Bonus: improved plugins

This refactoring introduced additional challenge because of the way how schema DSL plugins worked. To make things better and easier to manage, plugins are now created per component with their own configurations. This is actually a pretty significant improvement because it allows you to write plugins for any component type and you have an isolated context with plugin's options and its target component configuration available to you.

This means that for example the customized Schema DSL in rom-sql can now be turned into a tiny plugin rather than having a full-blown Schema::DSL subclass and having to deal with it during setup.

Example

require "rom"
require "rom/core"
require "rom/types"
require "rom/compat"
require "rom/sql"
require "rom-changeset"

require "dry-monitor"

module Types
  include ROM::Types
end

rom = ROM::Runtime.new(:sql, "sqlite::memory") do |runtime|
  runtime.relation(:users) do
    schema do
      attribute :id, Types::Integer, primary_key: true
      attribute :name, Types::String
    end

    associations do
      has_many :tasks
    end
  end

  runtime.relation(:tasks) do
    schema do
      attribute :id, Types::Integer, primary_key: true
      attribute :user_id, Types.ForeignKey(:users)
      attribute :title, Types::String
    end

    associations do
      belongs_to :user
    end
  end
end

rom, time = Dry::Monitor::CLOCK.measure { ROM.runtime(rom) }

puts "rom loaded in #{time}ms"
# rom loaded in 0ms :D

rom.gateways[:default].auto_migrate!(rom, inline: true)

users = rom.relations[:users]
tasks = rom.relations[:tasks]

user = users.changeset(:create, name: "Jane").commit
# {:id=>1, :name=>"Jane"}

task = tasks.changeset(:create, title: "Do Something").associate(user, :user).commit
# {:id=>1, :user_id=>1, :title=>"Do Something"}

solnic added 3 commits July 20, 2021 13:37
- `associations` is now a top-level DSL powered by components API
- Schemas can still define associations to keep backward compatiblity
- *Relations* can now define their associations as a new feature

Bonus: plugins are now enabled and applied on a per target basis. This
means that the plugin API is now simpler and more powerful.
@solnic solnic force-pushed the rework-schema-and-association-dsls branch from 268a7ca to e79828e Compare July 21, 2021 09:02
@solnic solnic marked this pull request as ready for review July 21, 2021 09:02
@solnic solnic merged commit e1f19e6 into master Jul 21, 2021
@solnic solnic deleted the rework-schema-and-association-dsls branch July 21, 2021 09:29
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