Re: many_to_many associations with cloning and classes

2021-11-15 Thread Jeremy Evans
On Mon, Nov 15, 2021 at 1:01 PM Benjamin Hutton  wrote:

> thanks!
>
> FWIW, all my class names are actually passed around as strings
>

Yep, that's pretty common in most apps.  I guess it is very uncommon to
clone associations and use a different :class in a cloned association,
otherwise someone would have hit this before.  In any case, the problem has
been fixed:
https://github.com/jeremyevans/sequel/commit/64480baf60976bf2ba89985f592ef0a205413e99

Thanks,
Jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sequel-talk+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sequel-talk/CADGZSSeFW-zr0-O_N9JRt9zm6p-bjzohf6G8N7T_F9m7f3CuNQ%40mail.gmail.com.


Re: many_to_many associations with cloning and classes

2021-11-15 Thread Benjamin Hutton
thanks!

FWIW, all my class names are actually passed around as strings

On Monday, November 15, 2021 at 3:37:18 PM UTC-5 Jeremy Evans wrote:

> On Mon, Nov 15, 2021 at 11:50 AM Benjamin Hutton  
> wrote:
>
>> Hey Jeremy,
>>
>> I am seeing some strange behavior with many_to_many associations, 
>> association cloning, and classes.
>>
>> I am building a set of sequel models to interact with a legacy database 
>> that we are slowly migrating away from, and trying to untangle some 
>> polymorphism in the old database.
>>
>> I started with a bunch of associations like the following:
>>
>> many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table: 
>> :content_syndications, left_key: :contentable_id, right_key: :content_id 
>> do |ds|
>>ds.where(:contents[:type] => 'Contents::Audio')
>> end
>>
>> I then realized that I can do the following, in order to get rid of the 
>> block on the association:
>>
>> class Legacy::Models::SequelAudio < Legacy::Models::SequelContent
>>   set_dataset LEGACY_DB[:contents].where(type: 'Contents::Audio')
>> end
>>
>> Which leads to:
>>
>> many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table: 
>> :content_syndications, left_key: :contentable_id, right_key: :content_id
>>
>> At this point, I realize I am relying on something cool going on with the 
>> class argument.
>>
>> I then try to further DRY up my code by doing this:
>>
>> many_to_many :audios, clone: :contents, class: 
>> 'Legacy::Models::SequelAudio'
>>
>> Unfortunately, it seems like the class that I am specifying is no longer 
>> getting applied. The association returns records with the class that is 
>> on the cloned contents association, not the audios association. And it 
>> isn't using the correct dataset anymore.
>>
>> Is there something else that I need to be doing? Am I misunderstanding 
>> cloning?
>>
>
> I had trouble reproducing the example at first, using the following code:
>
>  A = Class.new(Sequel::Model)
> Content = Class.new(Sequel::Model(:contents))
> Audio = Class.new(Sequel::Model(DB[:contents].where(:type=>'audio') ))
> A.many_to_many :contents, :class=>Content, :join_table=>:x
> A.many_to_many :audios, :clone=>:contents, :class=>Audio
> DB.fetch = {:id=>2}
> p A.association_reflection(:contents).associated_class
> p A.association_reflection(:audios).associated_class
> p A.load(:id=>1).contents_dataset.sql
> p A.load(:id=>1).audios_dataset.sql
> p A.load(:id=>1).contents.first
> p A.load(:id=>1).audios.first
>
> The output from that is:
>
> Content
> Audio
> "SELECT contents.* FROM contents INNER JOIN x ON (x.content_id = 
> contents.id) WHERE (x.a_id = 1)"
> "SELECT contents.* FROM contents INNER JOIN x ON (x.audio_id = contents.id) 
> WHERE ((type = 'audio') AND (x.a_id = 1))"
> #2}>
> #2}>
>
> However, I was able to reproduce this when using a symbol to the :class 
> option:
>
> A.many_to_many :contents, :class=>:Content, :join_table=>:x
> A.many_to_many :audios, :clone=>:contents, :class=>:Audio
>
> With that change, the output is:
>
> Content
> Content
> "SELECT contents.* FROM contents INNER JOIN x ON (x.content_id = 
> contents.id) WHERE (x.a_id = 1)"
> "SELECT contents.* FROM contents INNER JOIN x ON (x.audio_id = contents.id) 
> WHERE (x.a_id = 1)"
> #2}>
> #2}>
>
> So this is definitely a bug, and it's related to the late binding of 
> classes by using a string or symbol, probably because the :class option is 
> renamed to :class_name in that case, but the cloning code doesn't handle 
> that.  I'll work on a fix for it shortly.
>
> Thanks,
> Jeremy
>

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sequel-talk+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sequel-talk/ce3834da-8adf-4438-b624-686c9f15d13en%40googlegroups.com.


Re: many_to_many associations with cloning and classes

2021-11-15 Thread Jeremy Evans
On Mon, Nov 15, 2021 at 11:50 AM Benjamin Hutton 
wrote:

> Hey Jeremy,
>
> I am seeing some strange behavior with many_to_many associations,
> association cloning, and classes.
>
> I am building a set of sequel models to interact with a legacy database
> that we are slowly migrating away from, and trying to untangle some
> polymorphism in the old database.
>
> I started with a bunch of associations like the following:
>
> many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table:
> :content_syndications, left_key: :contentable_id, right_key: :content_id
> do |ds|
>ds.where(:contents[:type] => 'Contents::Audio')
> end
>
> I then realized that I can do the following, in order to get rid of the
> block on the association:
>
> class Legacy::Models::SequelAudio < Legacy::Models::SequelContent
>   set_dataset LEGACY_DB[:contents].where(type: 'Contents::Audio')
> end
>
> Which leads to:
>
> many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table:
> :content_syndications, left_key: :contentable_id, right_key: :content_id
>
> At this point, I realize I am relying on something cool going on with the
> class argument.
>
> I then try to further DRY up my code by doing this:
>
> many_to_many :audios, clone: :contents, class:
> 'Legacy::Models::SequelAudio'
>
> Unfortunately, it seems like the class that I am specifying is no longer
> getting applied. The association returns records with the class that is
> on the cloned contents association, not the audios association. And it
> isn't using the correct dataset anymore.
>
> Is there something else that I need to be doing? Am I misunderstanding
> cloning?
>

I had trouble reproducing the example at first, using the following code:

 A = Class.new(Sequel::Model)
Content = Class.new(Sequel::Model(:contents))
Audio = Class.new(Sequel::Model(DB[:contents].where(:type=>'audio') ))
A.many_to_many :contents, :class=>Content, :join_table=>:x
A.many_to_many :audios, :clone=>:contents, :class=>Audio
DB.fetch = {:id=>2}
p A.association_reflection(:contents).associated_class
p A.association_reflection(:audios).associated_class
p A.load(:id=>1).contents_dataset.sql
p A.load(:id=>1).audios_dataset.sql
p A.load(:id=>1).contents.first
p A.load(:id=>1).audios.first

The output from that is:

Content
Audio
"SELECT contents.* FROM contents INNER JOIN x ON (x.content_id = contents.id)
WHERE (x.a_id = 1)"
"SELECT contents.* FROM contents INNER JOIN x ON (x.audio_id = contents.id)
WHERE ((type = 'audio') AND (x.a_id = 1))"
#2}>
#2}>

However, I was able to reproduce this when using a symbol to the :class
option:

A.many_to_many :contents, :class=>:Content, :join_table=>:x
A.many_to_many :audios, :clone=>:contents, :class=>:Audio

With that change, the output is:

Content
Content
"SELECT contents.* FROM contents INNER JOIN x ON (x.content_id = contents.id)
WHERE (x.a_id = 1)"
"SELECT contents.* FROM contents INNER JOIN x ON (x.audio_id = contents.id)
WHERE (x.a_id = 1)"
#2}>
#2}>

So this is definitely a bug, and it's related to the late binding of
classes by using a string or symbol, probably because the :class option is
renamed to :class_name in that case, but the cloning code doesn't handle
that.  I'll work on a fix for it shortly.

Thanks,
Jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sequel-talk+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sequel-talk/CADGZSSdC2q-qaSBa2B8Z6uZDcvwNnh3NX%2B0YghNksD0VLXBjiA%40mail.gmail.com.


many_to_many associations with cloning and classes

2021-11-15 Thread Benjamin Hutton
Hey Jeremy,

I am seeing some strange behavior with many_to_many associations, 
association cloning, and classes.

I am building a set of sequel models to interact with a legacy database 
that we are slowly migrating away from, and trying to untangle some 
polymorphism in the old database.

I started with a bunch of associations like the following:

many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table: 
:content_syndications, left_key: :contentable_id, right_key: :content_id do 
|ds|
   ds.where(:contents[:type] => 'Contents::Audio')
end

I then realized that I can do the following, in order to get rid of the 
block on the association:

class Legacy::Models::SequelAudio < Legacy::Models::SequelContent
  set_dataset LEGACY_DB[:contents].where(type: 'Contents::Audio')
end

Which leads to:

many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table: 
:content_syndications, left_key: :contentable_id, right_key: :content_id

At this point, I realize I am relying on something cool going on with the 
class argument.

I then try to further DRY up my code by doing this:

many_to_many :audios, clone: :contents, class: 'Legacy::Models::SequelAudio'

Unfortunately, it seems like the class that I am specifying is no longer 
getting applied. The association returns records with the class that is on 
the cloned contents association, not the audios association. And it isn't 
using the correct dataset anymore.

Is there something else that I need to be doing? Am I misunderstanding 
cloning?

-Ben

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sequel-talk+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sequel-talk/0d070dc1-abe1-4849-b979-25afef58a539n%40googlegroups.com.