Closed liamwh closed 8 months ago
In this instance a custom query should be used to lookup the view_id
(in this example, the email) in another query and then use that value to make the appropriate view change. This could be composed of a ViewRepository
to do the lookup and a GenericQuery
to make the change.
Example:
struct MyCompoundQuery {
email_lookup: EmailViewLookup,
base_query: GenericQuery<...>
}
#[async_trait]
impl Query<BankAccount> for MyCompoundQuery {
async fn dispatch(&self, aggregate_id: &str, events: &[EventEnvelope<BankAccount>]) {
let email_id = self.email_lookup.load(aggregate_id).await.unwrap().email_id;
self.base_query.dispatch(email_id, events).await;
}
}
Note: I've updated the name of the EmailViewLookup
component due to my previous choice being confusing.
Thank you for helping. I'm sorry for my ignorance here. It is still not entirely clear to me.
Here is my user struct:
pub struct User {
pub id: Uuid, (view_id)
pub email: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub token_salt: Uuid,
}
So I we should agree that we don't necessarily want another aggregate for an email right? I would expect a user to be the aggregate in this case.
If we say that the user is the aggregate, I should have a User Repository, and a User View, right? The problem is, the User View only allows looking up by the id (uuid).
In your suggestion, are you suggesting I make another aggregate for the email so I can have an EmailViewRepository? Or can you please help me understand how the compound query helps me here?
Thanks very much in advance, I'm very grateful for you help 🙏
Thank you for the clarification, I think I see part of the issue.
The GenericQuery
is a little misleading because it's sort of set up as a single source lookup. This is meant to simplify the initial build-out of a service. In real systems looking up the correct view may be done from a variety of sources.
One solution is to extend the GenericQuery
and add additional lookup methods rather than just using the UserId
(in this case, via an email).
The solution I recommended is adding a EmailViewLookup
that contains only two fields, UserId
and Email
. The backing database should set the email
field as an index. This can be updated using a GenericQuery
but you'll need build a custom tool to retrieve the UserId
based on that secondary index.
This could be extended to use any number of fields that you might need to use to lookup the ViewId
in question.
Generally a modified GenericQuery
is faster as it reduces the database calls needed to update each view. The latter option is simpler (so a bit easier to maintain) and, if extended, may be used as a lookup for multiple different views with widely differing view ids (just make sure it gets updated from all aggregate sources).
Hope that helps, let me know if I'm still not getting to the root of your problem.
My understanding is that the only way to use the load functionality with a View Repository is by supplying the view ID, which must be used because of the necessity to implement the ViewRepository trait (below) required by the GenericQuery struct.
But what if the view_id is not known upfront? For example, if I have a table
user_query
, where across all rows, theemail
field in the payload must be unique, how should I check ifuser_query
table contains a row where the payload'semail
value does not match a provided input?Am I meant to create a
user service
and add such methods to that service?