rom-repository 1.1.0 released
Today we've released a new version of rom-repository which ships with new features and a couple of bug fixes. This release focused on improving auto-mapping capabilities and making it more flexible when you want to use custom mappers.
Adjusting relation nodes when loading aggregates
It's now possible to adjust individual relation nodes when you're loading aggregates or composing relations manually. This feature allows you to apply additional restrictions, or use custom views, or even set custom mappers on-the-fly.
Let's say we want to load users with their priority tasks:
aggregate(:tasks).
node(:tasks) { |tasks| tasks.where { priority < 3 }
This also works with deeply nested nodes:
aggregate(orders: :lines).
node(orders: :lines) { |lines| lines.where(id: line_ids) }
Disabling auto-mapping to structs
By default all repositories map plain hashes to ROM::Struct
objects, you can now disable this feature. This is useful in situations like mapping to JSON where intermediate objects are simply not needed, or when you want to use custom mappers that require hashes rather than structs.
You can disable mapping to structs using a repo class option:
class UserRepo < ROM::Repository[:users]
auto_struct(false)
end
user_repo = UserRepo.new(rom)
user_repo.users.to_a
# [{:id=>1, :name=>"Jane"}]
or when instantiating a repo object:
user_repo = UserRepo.new(rom, auto_struct: false)
or at run-time per individual relation:
class UserRepo < ROM::Repository[:users]
def user_hashes
users.with(auto_struct: false).to_a
end
end
user_repo = UserRepo.new(rom)
user_repo.user_hashes
# [{:id=>1, :name=>"Jane"}]
Improved support for wrapping
Just like combine
, wrap
now accepts association names. This simplifies loading nested data structures via joins. Here's a simple example:
class Tasks < ROM::Relation[:sql]
schema(infer: true) do
associations do
belongs_to :user
end
end
end
class TaskRepo < ROM::Repository[:tasks]
def with_user(id)
tasks.wrap(:user).by_pk(id).one
end
end
task_repo = TaskRepo.new(rom)
task_repo.with_user(id)
# #<ROM::Struct[Task] id=1 user_id=1 title="A task" user=#<ROM::Struct[User] id=1 name="Jane">>
Using custom mappers along with auto-mapping
You can now use auto_map
option in map_with
method which will apply auto-mapping before applying your own mappers. This is useful in cases where you want to use custom mappers and you want auto-mapping to handle complex structural transformations like merging multiple data sets into nested structures (which is what happens when you compose relations using aggregate
or combine
).
To enable auto-mapping with custom mappers, simply pass auto_map: true
option, this way you don't have to worry about handling aggregates manually, as your mappers will be applied to already transformed data:
class UserRepo < ROM::Repository[:users]
relations :tasks
def custom_mapping
aggregate(:tasks).
map_with(:my_custom_mapper, auto_map: true)
end
end
Release Details
This is a backward compatible upgrade, for more information check out the CHANGELOG. If you found any issues, or have trouble upgrading, please report it.