ROM 0.6.0 Released

We're happy to announce the final release of ROM 0.6.0! This version brings a lot of improvements and simplifies the internal architecture of ROM. There are over 700 commits between 0.5.0 and this release which is a result of fantastic feedback that we've received from early adopters and many contributions from new people.

This release includes updates of the following gems:

The following new adapters have been released too:

Class-based setup

The biggest change in this release is the ability to define your own relation, mapper and command subclasses that ROM will instantiate for you and expose through its registry. The DSL-based setup is still available but using classes turned out to be a better approach in bigger contexts like web-applications.

Here's a simple Relation subclass definition:

class Users < ROM::Relation[:memory]
  def by_name(name)
    restrict(name: name)
  end
end

Lazy-relations with data-pipelining

Previous version of ROM had the concept of Reader which turned out to be confusing. After lots of discussions it was replaced by a new interface for accessing relations. This change makes mapping relations explicit as you need to provide the name of mapper(s) that you want to use when loading a relation.

Lazy relations can be used with any object that implements mapper interface but the simplest way to levarage this feature is to register ROM mappers for quick access:

ROM.setup(:memory)

class Users < ROM::Relation[:memory]
  def by_name(name)
    restrict(name: name)
  end
end

class UserMapper < ROM::Mapper
  relation :users
  register_as :entity

  model User

  attribute :name
end

rom = ROM.finalize.env

user_entites = rom.relation(:users).as(:entity)
user_entities.by_name('Jane')

Thanks to data-pipelining feature you can send a relation through multiple mapping objects. This turned out to be very useful for decorating data:

class UserPresenterMapper < ROM::Mapper
  relation :users
  register_as :presenter

  model UserPresenter
end

user_presenter = rom.relation(:users).as(:entity, :presenter).by_name('Jane').first

On top of that there's also an experimental partial-application feature where you can grab a reference to a relation with partially applied arguments:

users_by_name = rom.relation(:users).as(:entity).by_name

users_by_name['Jane'].first

Improved and simplified command interface

Commands are now composable and you can access them directly and call them. This makes it more obvious what's going on. We are still working on a generalized error/success handling that will be based on a 3rd party dependency since this is really out of ROM's scope.

You can define your commands using class interfaces too:

ROM.setup(:memory)

class CreateUser < ROM::Commands::Create[:memory]
  relation :users
  register_as :create
  result :one
end

rom = ROM.finalize.env

create_user = rom.command(:users).create

rom.command(:users).try { create_user.call(name: 'Jane') }

Command API is growing quickly and more database-specific features will be implemented soon on top of existing functionality.

Improved adapter infrastructure

Adapter infrastructure has been simplified so now an adapter can provide its Repository and Relation subclasses and register itself under specific identifier. It means that a ROM adapter is just a couple of extensions that allow you to use ROM with various data sources. If the adapter can work in full read/write mode it can also provide its own Command subclasses.

Setting up an adapter is now simpler too - ROM doesn't make any assumptions about repository instantiation and you can also instaniate it yourself and pass the instance to ROM.setup. This feature is already used by rom-rails where you can configure your repositories in an initializer if you don't want ROM to infer configuration from database.yml.

Another nice addition is a set of Lint tests that are useful for adapter creators. We even made the effort to make it work with both MiniTest and RSpec. Here are a couple of linters from the new CSV adapter:

require 'rom/lint/spec'

describe ROM::CSV::Dataset do
  let(:data) { [{ id: 1 }, { id: 2 }] }
  let(:dataset) { ROM::CSV::Dataset.new(data) }

  it_behaves_like "a rom enumerable dataset"
end

describe ROM::CSV::Repository do
  let(:repository) { ROM::CSV::Repository }
  let(:uri) { File.expand_path('./spec/fixtures/users.csv') }

  it_behaves_like "a rom repository" do
    let(:identifier) { :csv }
  end
end

ROM's adapter ecosystem is growing fast - we have Redis, Neo4j and InfluxDB in the works already and more are planned.

Form objects for Rails

This release also includes updates to rom-rails - the most notable change is the addition of ROM::Model::Form which allows you to define form objects that work nicely with ROM. It is using Virtus for params handling and ActiveModel::Validations for validations.

Our Rails tutorial was updated too and explains how to use form objects in ROM. Here's an example of a simple form object definition:

class NewUserForm < ROM::Model::Form
  commands users: :create

  input do
    attribute :name, String

    timestamps
  end

  validations do
    validates :name, presence: true, uniqueness: true
  end

  def commit!
    users.try { users.create.call(attributes) }
  end
end

Upgrading from 0.5.0

The setup DSL works the same but you probably want to switch to class-based setup as it's easier to organize your code that way.

Please let us know if you have any trouble with the upgrade on our zulip channel or submit an issue describing problems you're having.

About 1.0.0

This has been amazing couple of months for ROM. The community is growing, we're seeing more and more people contributing to the project and geting great feedback from the real world usage.

Even though initially we planned to release 1.0.0 as soon as ROM proves itself on production, based on feedback from the community and discussing the release process we decided to give it few more months to push the first stable release.

We prefer to polish the interfaces and implement a bunch of important missing features that will make ROM simpler to use. In addition to features it's also important to provide great documentation and user guides, which is one of the priorities of 1.0.0 release.

Thank you!

Thank you to all the early adopters and new contributors. This release would not be possible without your help! It's amazing to see how the project evolves thanks to you.

We have more great news, so stay tuned and watch this space :)


ROM 0.5.0 Released

Today we're happy to announce the release of ROM version 0.5.0. It is the culmination of months of hard work from a growing team of contributors.

It's exciting to end the year with such a large and meaningful release.

How We Got Here

There were some twists and turns along the way, not the least of which was a reboot of the project with all new internals in November. The reboot was a turning point that has allowed us to accelerate development while cementing the core of ROM and surrounding libraries.

Version 0.5.0

The emphasis thus far has been on powerful mapping features and speed. This has resulted in an interface that looks lower-level than the other projects people use daily. We believe the higher-level and more convenient interfaces will emerge with more real world use.

Many of the features and much of the polishing found in this release happened as a direct result of ROM being used in production projects. In fact, one of the larger realizations over the last several months has been that ROM is not an ORM. I know. We were as surprised as you. Take some time to use it and you'll see what we mean. The Rails Tutorial outlined below is a great place to start.

There were so many things added, improved, replaced, refactored, and considered both in the core of ROM and in libraries like rom-rails and rom-sql that we can't cover them all here. See the changelog section below for an overview of the changes and a link to the changelogs for each project.

rom-rb.org

If you're reading this, it's because of the work we've done updating the website. Alongside the obvious layout and style changes we've also spent time on introductions and tutorials.

Introductions

The introductions are here to help you get accustomed to the terms and concepts used throughout ROM. You'll also find a brief article on Why ROM and a short comparision with ActiveRecord.

Tutorials

We've put together a fairly thorough tutorial for getting started with ROM and Rails and have several more planned. Even if you don't use Rails, this tutorial can help you understand how many of the ideas in ROM come together to create powerful ways of working with data.

There will be more tutorials in the coming weeks.

[rom] v0.5.0 Changelog summary:

  • Major milestone of putting together relation and mapping layers is done. ROM runs on a pluggable data mapping backends now. The first one is built-in and is based on a new library called transproc. More will come soon as the need arises.

  • Mapping is much more powerful now, support for prefixing keys, symbolizing keys, wrapping, grouping, embeddeding and coercions was added. In addition to that wrap, group and embedded can be nested which allows you to build very rich aggregate objects

  • Reading can only be used with defined relations now, which adheres to one of the core concepts in rom that data access should be restricted and encapsulated in the relation layer.

  • Adapter interface was improved and extended with extra options that can be used to build powerful adapters setup interface was improved and now accepts a simple URI string or a database.yml-complaint hash, makes it easier to use rom standalone and/or integrate with other libs and frameworks.

  • Relations that are not used by readers don't have to be defined now, it will be done automatically based on schema. This simplifies setup process every relation has access to all other relations (previously those were "raw" datasets from adapters). This allows you to reuse your relations inside. Well, relations.

  • Lots of internal improvements that should make using rom a nicer experience.

  • It remains very fast. Still lots of opportunities to tune it but not a big priority right now.

Full changelog

[rom-rails] v0.2.0 Changelog summary:

  • We have now generators for relations, mappers and commands!

  • Convenient validation and params processing extensions were added to make it easier to switch from AR to ROM in rails apps.

  • Support for hot-reloading in development env (works with spring!)

  • Support for more connection options (as a result of the general improvements in adapter interface)

Full changelog

[rom-demo] Updated:

  • Was updated to work with the latest ROM. You can see a GitHub adapter with some advanced mapping.

Latest rom-demo

[rom-sql] v0.3.1 Changelog summary:

  • Support for changes to ROM options and Rails reloading.

Full changelog

New adapters:

As mentioned before there are a couple of small adapters in the works: rom-yaml and rom-csv with more planned.

Onward towards ROM 1.0.0

Version 0.5.0 is a milestone on the journey to 1.0.0. There's nothing magical about a one-dot-oh but wouldn't it be nice?

For 1.0.0 there are no major changes planned. We will focus on polishing and new features like transactions in rom-sql and an extended command interface. There will be lots of internal small refactorings, improvements in the spec suite to bring a more unit-based approach now that interfaces are stabilizing, features based on feedback, and fixes for any bugs that come our way.

You can help

Yes, you can! As with all projects "many hands make light work". You don't have to jump in and tackle core issues, of course you can, but there are many ways you can help us out:

Try it out

Take it for a test drive. Drop it in to an existing project or create a new special little place just for ROM to live. The only requirement is that you come back and tell us what you think. Like. Dislike. We want to hear it all.

Tell us how you're using ROM

You may already be building things with ROM and we'd love to hear about it. What are you making? How is it working for you? What interfaces have you created to make common work easier? This feedback can greatly improve the project for everyone.

Documentation

[dramatic pause] We all love it when it's written but who writes it? We do. When you're trying out ROM and you find something doesn't make sense -- just create an issue on the repo. You could even assign it to yourself and make it better. (Imagine the satisfaction...)

Tutorials

Follow a tutorial. Well, since there is only one at the time of this announcement perhaps we should say "follow THE tutorial". Go through it and see what you make of it. If you find yourself using ROM differently, like in another framework, create a short tutorial about it. We can even help with the writing if you need it.

Write adapters

There are a couple of simple adapters in progress. Both rom-yaml and rom-csv are about as easy as they get. Maybe you could write rom-json or rom-NEWDB. We can help with this as well. Get it started and we'll all chip in.

Find your own way

We truly believe there are as many ways to help as there people. Take a look around, chat with us on Zulip and get to it.

Thanks for reading and here's to a great 2015!


  • 9 of 9