Code Monkey home page Code Monkey logo

Comments (40)

solnic avatar solnic commented on May 26, 2024 4

hanami-model will provide more conventional usage than "plain rom" which comes with various conveniences like model inference, auto-timestamps, auto-field renaming etc. Pretty much what you would expect from a full-stack framework.

from model.

cllns avatar cllns commented on May 26, 2024 2

@Defman21 Yup. @jodosha is working on changing the backend of hanami-model to use Ruby Object Mapper (rom). He's started it on the new-engine branch, so you can check it out there, but it's in progress and the docs don't reflect the changes.

from model.

Defman21 avatar Defman21 commented on May 26, 2024 1

I'm happy to see that there's some work going on to solve this issue :)

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

@jodosha Why do you put [] in an 1-n association?

from model.

jdickey avatar jdickey commented on May 26, 2024

@AlfonsoUceda Because the target of the association (the comments in that case; the subject would be the related Article instance) is a collection instead of a single item, hence the array (collection) notation.

At least, that was my reading of it.

from model.

jodosha avatar jodosha commented on May 26, 2024

@AlfonsoUceda yes @jdickey is right. This is a convention that I've seen in other Ruby ORMs, we can stick with it, because it's already known.

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

Ok thanks @jodosha and @jdickey ;)

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

What do you think about the method association inject in atrributes set de foreign key?

from model.

pcriv avatar pcriv commented on May 26, 2024

I'm having a hard time understanding how associations would work with the entity.
If do something like article.comments
is CommentRepository.by_article(article) called behind the scenes?

from model.

jodosha avatar jodosha commented on May 26, 2024

@pablocrivella Sorry for the confusion.

I don't want to give entities this faculty. If you look at the example above, where ArticleRepository preloads the comments, it fetches and assign them to the article object.

Pseudo-code:

article = fetch_article_from_database
comments = fetch_comments_for(article)

article.comments = comments

This hypothetical code shouldn't be visible to you, but happen behind the scenes.

To recap: no real associations in entities, they are just an accessor who is fed by the repository.

from model.

pcriv avatar pcriv commented on May 26, 2024

Will it work with lazy loading? (sorry for the nagging, I'm just curious. I really like the approach you are following, I have tried the repository pattern before but with .Net and nhibernate Orm)

from model.

jodosha avatar jodosha commented on May 26, 2024

@pablocrivella Not a problem at all, feel free to ask and let me know if it makes sense for you.

It will be lazy by default, if you will omit the .preload(:comments) (see above), article.comments will return nil. This because Article#comments is just a dumb getter, so you have to be explicit and set that value via the repository.

from model.

carloslopes avatar carloslopes commented on May 26, 2024

@jodosha What do you think about a #load method? It will use the same logic that the #preload has but will serve to lazy load the associations.

from model.

jodosha avatar jodosha commented on May 26, 2024

@carloslopes Tell me more, please. Where do you see this #load mechanism? I'm not sure if I got your idea.

from model.

carloslopes avatar carloslopes commented on May 26, 2024

@jodosha sorry, sometimes I still think like AR. The #load method would stay on the model, but this will break that separation of concerns that we keep here (and this way is a lot better).

My bad! πŸ˜‰

from model.

 avatar commented on May 26, 2024

@jodosha So wat you mean is that, after serializing the result of the query to an array, preload loops over the result and fill the association attributes? isn't that super inefficient?

from model.

jodosha avatar jodosha commented on May 26, 2024

@coenert Why is that?

At the low level when we translate query results to domain objects (eg. Hash to Comment), we have those objects that we assign to the article. It's O(n), because we need to deserialize comments one by one, but that's common to all the ORMs. Am I missing something?

from model.

 avatar commented on May 26, 2024

@jodosha nevermind, i missed something. I know we have to deserialize all those records, but i thought that every time we deserialize 1 entitty we had to fetch all the associated objects with another query. But we can just make a query like:

where(article_id: [id1, id2, id3, .....])

And then assign the result to each article.

I would like to try this one!

from model.

 avatar commented on May 26, 2024

Ok, i faced a problem while making an test implementation, and i think we should discuss this problem.

When you define an association in the mapper: association :comments, [Comment] we find the first problem: because we need the Repository to retrieve the related objects we also need the collection in the same mapper, but we just don't what the collection is.

To get the collection i have 2 possible solutions:

  • collection name == Entity name in plurar form and provide api to give specifiy collection name, the rails way. Don't like this one(person -> people problem)
  • loop over collections(in the same adapter or given adapter) and use the first collection where Entity is given Entity. Seems the only reasonable way for me

(bold text is my opinion)

from model.

jodosha avatar jodosha commented on May 26, 2024

@coenert Suppose we have the following mapping:

collection :comments do
  entity Comment
  entity CommentRepository
  # ...
end

adapter :disqus do
  collection :comments do
    entity Comment
    entity RemoteCommentRepository
    # ...
  end
end

collection :articles do
  # ...
  association :comments, [Comment]
  #           [1]        [2]
end

The proposed solution has two arguments:

  1. The name of the association, we should use this name both to lookup for the homonym collection (the first :comments) and to set the attribute into the entity Article#comments. This should lookup the default adapter.
    1a. We want to use a collection that comes from a different adapter. We should allow to specify it (see example 1).
    1b. We want to have a different accessor to be filled into the entity (eg Article#my_comments). We should introduce another option too (see example 2).
    1c. The serialized objects are stored inside the entity. Think of MongoDB's embedded associations, where we don't have a top level :comments collection, but they are stored inside each single article. We should introduce :attribute (or :embedded), as source of this collection. We can use [Comment] to infer the entity`.
  2. The plural/singular form of the association, to distinguish between has one and has many form. Theoretically this could be replaced with an option like multiple: true. Please don't rely on this to lookup the repository.
    2a. If we replace this as shown at point 2, we should introduce a new API to infer the entity in case of embedded collection. See 1c.

Example 1

association :comments, [Comment], adapter: :disqus

Example 2

association :my_comments, [Comment], collection: :comments

Example 3

association :comments, [Comment], attribute: :comments

Now, suppose that we have the following signature:

def association(name, options = {})
  # the collection name should be computed by looking at the attribute `:collection`, or fallback to `name`.
  collection_name = options.fetch(:collection) { name }
end

We can ask to the mapper to retrieve that collection and, finally ask for the repository: mapper.collection(collection_name).repository.

There are two missing pieces in the just depicted solution:

  1. A Mapping::Collection doesn't have access to the mapper. Evaluate if this is needed by the development if this feature
  2. Mapper#collection should accept an adapter option: mapper.collection(collection_name, adapter: :disqus).

Does this clarify the intents?

from model.

 avatar commented on May 26, 2024

@jodosha thanks for your complete answer πŸ‘Œ, most of it is clear for me now.

that means that when we have an has one and we want to name it article instead of articles(name of collection) we have to define the association like this:

association :article, Article, collection: :articles

it is πŸ‘ for me, simple api.

About the missing things:

  1. In my test implementation i added mapper as an constructor argument, access to the mapper is mandatory to receive the collection object.
  2. true, i think i will make an seperate PR for this, is that ok?

from model.

carloslopes avatar carloslopes commented on May 26, 2024

@coenert for has one associations you should use:

association :article, Article

You use the brackets when the association is a collection

from model.

 avatar commented on May 26, 2024

@carloslopes youre right, but only need to remove the []. edited that

from model.

 avatar commented on May 26, 2024

@jodosha I have some concerns about the api, with the current api there is no difference between belongs_to and has_one, how do we know where the foreign_key is located. i thought about how we can change the api so that you can specify that. I came with the idea that an association also an attribute is, but than lazy loaded. what about this api:

Has Many

attribute :my_articles, has.many_of(Article) {
  collection :articles
  foreign_key :author_id
}

Has One

attribute :details, has.one_of(UserDetails) {
  collection :user_details
}

Belongs To

attribute :author, belongs_to(User) {
  collection :users
  foreign_key :author_id
}

But you can also specifiy the options inline:

attribute :author, belongs_to(User), collection: :users, foreign_key: :author_id

i think it is also simpeler to understand. what do you think about it?

from model.

Extazystas avatar Extazystas commented on May 26, 2024

Is it official part of lotus model?
If yes, why its not mentioned in Readme?

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

No, it isn't
El 30/03/2015 18:16, "Extazystas" [email protected] escribiΓ³:

Is it official part of lotus model?
If yes, why its not mentioned in Readme?

Reply to this email directly or view it on GitHub
#35 (comment).

from model.

pascalbetz avatar pascalbetz commented on May 26, 2024

How would associations work for the insert/remove workflow (adding a comment to/removing a comment from an article)? I guess there'd be no support from lotus/model as it's only a "stupid" ruby object?

About the syntax for declaring assocations:
Defining associations with/without []to indicate has many/ belongs to seems a bit limited (as @coenert already pointed out with the has one case (foreign key on the other end)). I'd prefer something more speaking, like the inline version from @coenert.

Sidenote:
I'm new to lotus and doing a lot of Rails currently

from model.

jodosha avatar jodosha commented on May 26, 2024

@pascalbetz Thank you for your opinion. The workflow for add/remove associated records is something under discussion. We're trying to apply a simple design here. πŸ˜„

from model.

pascalbetz avatar pascalbetz commented on May 26, 2024

@jodosha

If i understand correctly:

associations are just "stupid" getters/setters. So there is no syncing between the foreign key attribute and the association?

(pseudocode)

article = Article(id: 1, ....)
p article.user_id => nil

user = User(id: 10, ...)

article.user = user
p article.user_id => 10

I guess you don't want to autogenerate methods like

def user=(user)
  self.user_id= user.try(:id)
  @user = user
end

on the entity?

from model.

pascalbetz avatar pascalbetz commented on May 26, 2024

@coenert

Wouldn't the collection/fk/... options be arguments to belongs_to? (assuming belongs_to is a method which returns a type which represents the association)

attribute :author, belongs_to(User, collection: :users, foreign_key: :author_id)

from model.

 avatar commented on May 26, 2024

@pascalbetz Probably, but now after some time i think my suggested api isn't in any way simpeler to understand then the one @jodosha initially suggested. I think i missed the point of creating less magic DSL's to reduce complexity(still learning πŸ˜„)

from model.

pascalbetz avatar pascalbetz commented on May 26, 2024

@coenert

The proposed API by @jodosha might hit some limits though (has and belongs to many, has many through, has one).

How about

attribute :user_id, Integer...
belongs_to :user, User, foreign_key: :user_id, ...
has_many :comments, Comment

Pretty much like Rails does it. Just keep the associated class as the second argument.

from model.

kirantpatil avatar kirantpatil commented on May 26, 2024

Sir, Any updates on this issue ?

from model.

runlevel5 avatar runlevel5 commented on May 26, 2024

@kirantpatil we are in the cycle of improving model so please stay tuned.

from model.

Defman21 avatar Defman21 commented on May 26, 2024

Are you still in the cycle of improving Model? I'm missing any sort of relations between tables.

from model.

elliottmason avatar elliottmason commented on May 26, 2024

In lieu of hanami-model, what would be the downsides of just straight-up using rom? What will hanami-model provide that rom doesn't right now?

I've been wanting to start new projects in Hanami but the lack of model associations is a pretty big hurdle; pretty much the primary reason I still spin up new apps in Rails.

from model.

senei avatar senei commented on May 26, 2024

attribute :author, belongs_to(User, collection: :users, foreign_key: :author_id)

returns error uninitialized constant Book::User (NameError) -- why
in db it is working correctly

from model.

beauby avatar beauby commented on May 26, 2024

@senei Please open a separate issue.

from model.

jodosha avatar jodosha commented on May 26, 2024

@senei Where did you found that syntax? And where it is used?

from model.

jodosha avatar jodosha commented on May 26, 2024

I'm closing this in favor of future, smaller, focused, and actionable proposals.

from model.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.