rom icon indicating copy to clipboard operation
rom copied to clipboard

Add support for virtual attributes at the relation definition level

Open waiting-for-dev opened this issue 5 years ago • 2 comments

In the same vein that you can define virtual columns in a database, maybe it could be convenient to have something similar for rom attributes at the relation definition level.

In rom-sql, you can already do something like:

relation.order(relation[:attr_1] - relation[:attr_2])

However, the idea would be to have them declared at the relation definition level, together with a new method which could transparently fetch an actual or a virtual attribute.

I think it would be better not to overload .schema and #[] relation methods for this functionality in order to have a clear separation of concerns. In the same way, defined virtual attributes would not be part of the default dataset (at least by default).

Examples

class Relation < ROM::Relation[:sql]
  schema :users  do
    attribute :attr_1, Types::Integer
    attribute :attr_2, Types::Integer
  end

  virtual do |schema|
    attribute(:diff) { |schema| schema[:attr_1] - schema[:attr_2] }
  end
end

# ...

relation.where(relation.fetch(:attr_1) > 2).order(relation.fetch(:diff))

Sure we could find a better name than fetch....

Of course, I could try it myself once I clean a little my stack of pending PRs...

waiting-for-dev avatar Feb 07 '19 18:02 waiting-for-dev

Why not just define a method:

class Relation < ROM::Relation[:sql]
  schema :users  do
    attribute :attr_1, Types::Integer
    attribute :attr_2, Types::Integer
  end

  def diff
    self[:attr_1] - self[:attr_2]
  end
end

# ...

relation.where(relation.fetch(:attr_1) > 2).order(relation.diff)

???

solnic avatar Apr 27 '19 09:04 solnic

Well, the whole point here is to be able to use them transparently. It would make rom's schemas closer to what we have at the database level. I mean, in SQL we can use an actual field or a dynamic field in the same way: SELECT attr1, attr1 - attr2 FROM...

It is related to the cross-layer convenient coupling I said in https://github.com/rom-rb/rom/issues/524#issuecomment-486095896:

Then there is also some cross-layer coupling I have been using because sometimes it is too convenient to avoid. For example, say you are rendering an HTML table containing data from a relation and this table have links to be ordered by any of the columns, where each column represents a relation attribute. Currently I'm using the attribute name to build the link, and it is travelling unmodified from the view layer bottom to the relation layer, where it finishes its voyage within #[].

Say in the example you have :attr1, :attr2 and :diff columns. It would be convenient to be able to treat them in the same way and just let the schema resolve the actual difference.

But I'm not 100% sure about it, because at the end one of the reasons I want it is because a coupling, which is convenient, but a coupling anyway. Also, having the relation or schema layer closer to the database layer doesn't have to be a good thing necessarily. But I think it is good to bring this discussion and give it some thoughts, because at first sight I see some benefits to the feature.

waiting-for-dev avatar Apr 29 '19 10:04 waiting-for-dev