Why not `ctx.db.query("table").withIndex(vectorIndex)`?
This is just out of curiosity, why not
ctx.db.query("table").withIndex(vectorIndex)
but instead ctx.vectorSearch()
? Is it because we don't want to expose ctx.db
in actions?
In fact, why is there no ctx.db.query()
in actions? Is there a reason for not allowing querying dB in actions? Seems to me like it should be fine since unlike mutations, determinism (or non-determinism) of the calling function (an action in this case) doesn't affect anything.
Concerning the first question, we can just use Typescript to narrow down the indexes in the withIndex()
of queries and mutations to non-vector indexes, while allowing all indexes in actions.5 Replies
This gives a more unified API.
Also, why not
ctx.runFunction
or ctx.runFn
in actions, instead of ctx.runQuery/runMutation
in actions? I guess there's some reason for this, but I can't figure it out. Unifying everything looks like it'll be better.1. it's not
ctx.db.query(tbl).withIndex(vectorIndex)
because people would think ctx.db.query(tbl).withIndex(dbIndex)
should work, but it doesn't.
2. ctx.db.query(tbl)
doesn't exist in actions because then people would do multiple db.queries in the same action, which loses the atomicity that you want and would get if it's in a query or mutation. We've considered something like ctx.runTransaction((ctx) => { inline mutation })
but there are some difficulties with variable binding.
3. Mutations and queries have different properties -- mutations can write to the db and get retried on conflicts, while queries can be cached. Since they're semantically different, they are called differentlyThanks for the response.
1. Shouldn't TS be able to solve that alongside a clear section about it in the docs?
ctx.vectorSearch
makes it look like it's very far away from a DB operation, which is not the case. ctx.db.vectorSearch
would be better IMO.
2. Could you please provide a simple example of a problem that can arise from this, and how it is solved by the current implementation? I'm unable to come up with one.
3. Yeah, I know they're different. Is this in addition to the existence of queries in action, or is it related to the ctx.runFunction
suggestion? Regarding their different properties, isn't that the same case with mutations and actions, while both are still usable with the same ctx.scheduler.runAfter()
API?1. Different TS types could be used, but then you've got very different DB types for the same variable name that don't even overlap; it gets confusing to have db work so differently when e.g. writing functions that take these types are arguments. I see your point about it not being obvious that vectorSearch is related to the DB, agree that's a tradeoff. Clearly it's possible,
db
has a different type in mutations vs queries! But since one is a subset of the other this felt less confusing.
2. Query a list of users in a channel from an action, then a list of messages in that channel. But in between those two queries, a new user joined the channel and send a message. (maybe it's a welcome message that happens automatically when they join) Now you have a message without the corresponding user!
In a query function this can't happen, every db.query takes place at the same logical timestamp to protect from race conditions like this. If we provided a db
that worked this differently then helper functions that accepted db as an argument might work correctly when used in queries and mutations but incorrectly when used in actions.
3. Yeah it's possible to have a ctx.runFunction
, you can write one yourself; but it's nice to see the difference in code between these without needing to hover over the type or cmd-click to find out if something is a query or mutation.
@Abdulramon Jemil Great questions! For some of these API ideas you might try them out in your own apps; you can write function wrappers to change what's in ctx or use your own object to produce the API you like, and when a library like this looks useful or becomes popular we absolutely look at it for thinking through future APIs!Thanks for the response. Happy to see how these APIs evolve with time.
As for
2
, the statement "db.query takes place at the same logical timestamp to protect from race conditions" was exactly what I was looking for. While I did guess it, I couldn't find it in the docs (Saw the part written for mutations tho.)