Hi there!
I’ve been going through commands guide, but I can’t find a any info on how to build a generic command that can be registered on a repository similarly to built-in create, update, and delete commands. Is it possible to do?
Another semi-related question - is there a way to provide a base class for all repository classes? Let’s say I’d like to have methods defined on all my repositories without using mixins or monkey-patching ROM::Repository::Root class. Is that possible?
Thank you in advance for answering my questions.
PS. Sorry if they might trivial but I’ve just stared looking into ROM.rb, and still finding my ways around docs, and guides.
Yes it is possible although it’s a bit weird because the name of the method must match the command identifier. So, in case of the built-in commands you have commands :create that translates to a corresponding :create command.
This means that if you register a custom command and name it, let’s say, :upsert, then you should be able to do commands :create, :upsert and both command and upsert methods should become available in your repository.
Yes, you actually should have an abstract repository class that inherits from Root and use that in your repo classes. Here’s how it looks in one of my projects:
module Devtools
class Repository < ROM::Repository::Root
include Deps[container: "persistence.rom"]
struct_namespace Structs
end
end
Then I have my repos that inherit from it, ie:
require "devtools/repository"
module Devtools
class PullRequestRepo < Repository[:pull_requests]
# stuff
end
end
Hope this helps. Lemme know if I should explain it better
@solnic thanks for the reply. Base class for repository works fine!
I have a problem with custom command though. Can you provide a working example for ROM.rb with rails?
I’ve tried something like this (registered with commands :build on the repo):
class BuildCommand < ROM::SQL::Commands::Create
relation :projects
register_as :build
def execute(tuple)
# do whatever you need
end
end
but it throws error when I try to use it:
ArgumentError: wrong number of arguments (given 1, expected 2+)
from vendor/bundle/ruby/2.7.0/gems/rom-core-5.2.5/lib/rom/command.rb:475:in `apply_hooks'
PS. It also does not work without relation :projects so it’s not generic.
@solnic it works fine. However ProjectRepository.new(ROM.env).root.mapper.model gives me the correct entity class, while relation.mapper in the ROM.env.relations[:projects].command(:build).call(some_data) returns false.
To give you more context, I was following Exploding Rails book and I wanted to have a custom build command that creates an empty entity that I can use with Rails form helpers.
If I define build method on the base repo class like this:
def build(attributes = {})
root.mapper.model.new(attributes)
end
It all works fine. However I wanted to inject to the repo via custom build commands like this: commands :build, :create, update: :by_pk, delete: :by_pk.
This is because repository relations are configured to use auto-struct mapping. You need to give me more context (code-wise) so that I can tell you what to do. ie how your command is defined.
@lowski oh I see now what you’re after - I don’t recommend doing this at the command level. Commands are meant to be used for db-specific stuff. Model instantiation should be handled by repositories. I’ll be adding some convenient APIs for that in 6.0.0. Probably something like RootRepository#build would make sense.