Is it possible to fan out arguments passed with .bind() when doing a RELATE query (Rust SDK)

39 Views Asked by At

Creating a one-to-many relationship is no issue, i.e.:

let user = Thing::from(UserId(0));
let tracks: Vec<Thing> = vec![Thing::from(TrackId(0)), Thing::from(TrackId(1))];

db.query("RELATE $user->owns->$track")
    .bind(("user", user))
    .bind(("track", tracks))
    .await;

This creates a record between the user and each track -- e.g.:

user:0->owns->track:0 
user:0->owns->track:1

However, if I wanted to have multiple users -- e.g.:

let users: Vec<Thing> = vec![Thing::from(UserId(0)), Thing::from(UserId(1))];

I end up with each user having a record for each track:

user:0->owns->track:0 
user:0->owns->track:1
user:1->owns->track:0
user:1->owns->track:1 

when instead I would like to have:

user:0->owns->track:0 
user:1->owns->track:1

and this is further complicated by the need for adding record data (i.e. a SET statement), specifically I want to be able to also add a specific datetime for each of these relationship, e.g.

RELATE user:0->owns->track:0 SET purchase_date = 2022-07-03T07:18:52Z
RELATE user:1->owns->track:1 SET purchase_date = 2000-01-01T07:18:52Z

I can do these as separate queries -- but if there is a way to do it in one call to query it could be nice.

1

There are 1 best solutions below

0
MacLeod Dave On

Okay, looks like this can be some with a bit more SurrealQL that uses the transpose method to stitch the two together.

db.query(
"let $together = array::transpose([$users, $tracks]);
for $item in $together {
let $one = $item[0];
let $two = $item[1];
relate $one->owns->$two;
}")
.bind(("users", users))
.bind(("tracks", tracks))
.await?;

Note though that transpose won't short circuit if one array is shorter than the other, but if you know for sure that you have arrays of equal length that each match a user to a track then this should work.