Quick update: with those changes, doing the following...
vendors = Vendor
.where(:user_id => 1)
.eager(:last_edit)
.all
yields a query of:
INFO -- : (0.000693s) SELECT * FROM (SELECT * FROM `vendor_revisions` WHERE
(1 = `vendor_revisions`.`vendor_id`) ORDER BY `created_at` DESC LIMIT 1) AS
`t1` UNION ALL SELECT * FROM (SELECT * FROM `vendor_revisions` WHERE (2 =
`vendor_revisions`.`vendor_id`) ORDER BY `created_at` DESC LIMIT 1) AS `t1`
and it returns the correct values. Is that the expected behavior?
Thanks again,
Greg
On Thursday, December 29, 2016 at 8:43:54 PM UTC-5, Greg Gilbert wrote:
>
> Sorry about the Docker setup, thought it might be easier. I'll remember
> for next time.
>
> I see what you're saying about adding the :order. Doing that on the
> association is cleaner than the proc.
>
> I turned on debug to look at the queries, and it looks like doing it that
> way creates N+1 queries, i.e.:
>
> INFO -- : (0.000408s) SELECT * FROM `vendors` WHERE (`user_id` = 1)
> INFO -- : (0.000509s) SELECT * FROM `vendor_revisions` WHERE
> (`vendor_revisions`.`vendor_id` = 1) ORDER BY `created_at` DESC LIMIT 1
> INFO -- : (0.000356s) SELECT * FROM `vendor_revisions` WHERE
> (`vendor_revisions`.`vendor_id` = 2) ORDER BY `created_at` DESC LIMIT 1
>
> Isn't that less efficient than doing it all in one query and sorting it
> out?
>
> Thanks,
> greg
>
> On Thursday, December 29, 2016 at 2:14:00 AM UTC-5, Jeremy Evans wrote:
>>
>> On Wednesday, December 28, 2016 at 10:03:55 PM UTC-8, Greg Gilbert wrote:
>>>
>>> Hey,
>>>
>>> I put together a proof of concept using Docker:
>>> https://github.com/greggilbert/sequel-association-test
>>>
>>> If you look at doit.rb, you'll see two queries. The first one doesn't
>>> work (i.e. returns nil) but the second one does. I guess there's
>>> something about the eager_limit that's not right? And if you leave out
>>> the .eager line altogether, you get the first VendorRevision for each,
>>> not the last.
>>>
>>> Let me know if there's anything else I can clarify.
>>>
>>
>> In the future, please do not submit examples that use docker, or split
>> code between multiple files. Please combine all code in a single post to
>> this list. This saves me time as I wouldn't have to go through 4 separate
>> files to piece together a working example just to provide support. Below
>> is a self contained example I made from your repo that is runnable with
>> bin/sequel (e.g. ruby bin/sequel -E sqlite:/ filename.rb).
>>
>> In any case, :eager_limit should not be used for one_to_one associations,
>> and it doesn't make sense to use it as the limit should always be 1 anyway
>> (it can make sense for *_to_many associations). Using :eager_limit for
>> one_to_one associations is undefined behavior, so the fact that it breaks
>> something is not a bug.
>>
>> You'll notice in the code below that I commented out the :order option to
>> the last_edit association. From looking at your example, I would guess
>> that you would want to specify that option, and then you'll be able to use
>> the last block in the example, which doesn't use an eager callback. This
>> is best as it produces the most optimized query. It seems to me unlikely
>> that you'd ever want to use the last_edit association without a reverse
>> chronological order.
>>
>> Thanks,
>> Jeremy
>>
>> DB.instance_exec do
>> create_table(:users) do
>> primary_key :id
>> String :email, null: false
>> String :password_hash, null: false
>> DateTime :created_at, null: false, default:
>> Sequel::CURRENT_TIMESTAMP
>> DateTime :updated_at, null: false, default:
>> Sequel::CURRENT_TIMESTAMP
>> end
>>
>> create_table(:vendors) do
>> primary_key :id
>> foreign_key :user_id, :users
>> Boolean :is_verified, default: false
>> end
>>
>> create_table(:vendor_revisions) do
>> primary_key :id
>> foreign_key :vendor_id, :vendors, null: false, index: true
>> String :name, null: false, index: true
>> DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
>> DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
>> end
>>
>> alter_table(:vendors) do
>> add_foreign_key :latest_revision, :vendor_revisions, null: true
>> end
>> end
>>
>> class User < Sequel::Model
>> one_to_many :vendors
>> end
>>
>> class VendorRevision < Sequel::Model
>> many_to_one :vendor
>> end
>>
>> VendorRevision.plugin :timestamps, update_on_create: true
>>
>> class Vendor < Sequel::Model
>> one_to_many :vendor_revisions, class: VendorRevision
>> many_to_one :user
>> end
>>
>> Vendor.one_to_one :last_edit, :class => :VendorRevision#,
>> :order=>Sequel.desc(:created_at)
>>
>> u1 = User.create(:email => '[email protected]', password_hash: 'foo')
>> u2 = User.create(:email => '[email protected]', password_hash: 'foo')
>> v1 = Vendor.create(:user_id => u1.id)
>> v2 = Vendor.create(:user_id => u1.id)
>> v3 = Vendor.create(:user_id => u2.id)
>> vr1 = VendorRevision.create(:vendor_id => v1.id, :name => 'Test one')
>> vr3 = VendorRevision.create(:vendor_id => v2.id, :name => 'Test three')
>> vr2 = VendorRevision.create(:vendor_id => v1.id, :name => 'Test two')
>> vr4 = VendorRevision.create(:vendor_id => v2.id, :name => 'Test four')
>>
>> vendors = Vendor
>> .where(:user_id => 1)
>> .eager(:last_edit => proc {|ds|
>> ds.reverse_order(:created_at).clone(:eager_limit => 1) })
>> .all
>>
>> vendors.each do |v|
>> p v.last_edit
>> p '-'*50
>> end
>>
>> vendors = Vendor
>> .where(:user_id => 1)
>> .eager(:last_edit => proc {|ds|
>> ds.reverse_order(:created_at) })
>> .all
>>
>> vendors.each do |v|
>> p v.last_edit
>> p '-'*50
>> end
>>
>> vendors = Vendor
>> .where(:user_id => 1)
>> .eager(:last_edit)
>> .all
>>
>> vendors.each do |v|
>> p v.last_edit
>> p '-'*50
>> end
>>
>
--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.