I have the following situation: I have a database with objects, and tags. They are related in a many-to-many way, that is, each object might be tagged with any number of tags, and tags may be applied to any number of objects. This is modeled with
- an
objecttable, which has anobject_idprimary key - a
tagtable, which has atag_idprimary key - an
object_tagtable, which has two columns:object_idandtag_id, both, being foreign keys, and(object_id, tag_id)being the primary key.
I would like the user to be able to filter for objects in my database that have all of the tags the user provides. To do this with a single tag, I would:
- inner join
objectandobject_tagonobject_id(which is implicit, thanks to thejoinable!macro) - select only the
objectpart of the table
This operation starts with a table whose schema is the same as object, and ends with a table whose schema is the same as object, so I assumed that I could just iterate this operation for every tag that the user has provided.
However, this doesn't work: diesel complains, with very ugly type errors. I assume the issue is that somehow I haven't done things in the right way, and so Diesel doesn't see that applying this operation is supposed to leave the schema unchanged.
So, I have tried another approach (which seems to more less efficient, but idk how the database manager optimizes this kind of things so I wouldn't bet on it):
- for every tag, I generate a query on
object_tagthat filters only rows whosetag_idmatches the tag - for every such query, I then select only the
object_id - I intersect all of them
the code is roughly the following:
tags.iter().copied().map(|id_of_tag| {
use schema::object_tag::dsl::*;
object_tag
.select(object_id)
.filter(tag_id.eq(id_of_tag))
}).reduce(|l, r| l.intersect(r))
this doesn't work either, though. I've tried throwing a couple of .into_boxed() to see if that would help, but I still can't get it to work.
How am I supposed to make this work?