Is there a way to explicitly type certain drizzle results as `Array<T | undefined>`?
For example, I am making a query which I know will sometimes return undefined, since I am accessing a row that may or may not be present. I'm not sure how to type this such that I have type safety through the rest of the code to ensure that I never access properties without undefined checks.
I'm aware of Typescript
noUncheckedIndexedAccess
but that will change the behavior of all arrays everywhere in my codebase, which I do not want. I just want the ability to indicate that a certain Drizzle select result will sometimes have no items returned.
e.g. const [maybeExistingEntity] = await drizzle.select(.....).limit(1)
now strongly types maybeExistingEntity
where I would like the type to be T | undefined
.31 Replies
my current solution is to wrap drizzle calls where this applies in:
But this seems silly. thoughts?
I can't think of anything other than
noUndeckedIndexedAccess
.
Other than that, type casting but it's just as sillyyeah, that tsconfig option makes a lot of patterns fail, e.g.
if a.length > 1 a[0].something...
since it could be a sparse array, theoretically, the compiler can't prove that accessing the first element is safe
using it isn't realistic, so I'll just use my funky function for now. Would be great to have a dot method on drizzle that just transforms the return type into undefined for these cases
(or maybe just... have it be undefined all the time? since any query can fail to return results, after all)
or actually, what would be very nice in drizzle, that won't break any existing queries, is to add a new function analogous to limit(1)
that returns either the element or undefined. Like fetchFirst()
or something
and instead of returning a Result[]
it can return Result | undefined
The problem with
Array<T | undefined>
is that now ALL the elements of the array are literally T or undefined, so even if you .map()
you'll have to type cast it or something like this, which is just not correctyeah
I think this only makes sense for the case where you are accessing the array entries via index, which I only do for when I expect there to be exactly zero or one results
oh hey, that's smart. Instead of
const [existingEntity] = maybeDrizzleResult(...)
, I'll make my function do just thatName your function
justOne
and just add a limit(1) to the query, access it and return T | undefined
There you goyes
well, there are two potential use cases here
sometimes you want to select the first entry, if present. Sometimes you want to select the first entry and assert that there is only one matching row
justOneOrThrow
I already have a utility function for
assert that this update query modifies only one row
because... I forgot a WHERE and overwrote my whole table, that was fun
I wrote the eslint plugin to avoid that
ah, I didn't realize there was a plugin now! excellent
feature request: would be nice if your plugin also throw an error if you renamed your drizzle object to something else 🙂 not sure if that is possible
e.g. if you switch from
const db = drizzle(...)
to const somethingElse = drizzle(...)
and somethingElse
is not in your drizzleObjectName
, explode
similarly for the variable names used in transactions
(having never worked with eslint plugins, I don't know if that is possible)I would like to make it so that it would only work if it is a drizzle object
sure, but how would you tell what is a drizzle object at parse time? you don't have access to the type information, I'm guessing
idk
For now we released it like that, it is not an easy one
exactly
yeah, I totally understand
hence my fake solution of "if you specify an object list, we will enforce it on creation and on use"
e.g. if you assign the output of
drizzle()
to something not in that list, explode, since the list must be wrong
though... that won't work in most cases, actually. since I assign drizzle through multiple levels of constructors, etc
import renames, etcYeah, you just have to be consistent
re: "work only if it is a drizzle object": would you be able to handle the case I have where for row level security I actually access all of my drizzle instances through a proxy object that wraps the transaction to set transaction variables for user id and claims?
The other option that I thought was to provide a list of names on which NOT to work on
(I am not sure if there is a better way to do that now, when I spun up this project, there was no way to do that)
usage:
request.locals.rlsDrizzle = createRlsDrizzle(...some claims function based on request user...)
and then all database queries made in request handling are automatically limited to only that user's permissions in row level security. it's quite nice.Just put rlsDrizzle in the list
ah yeah
I was speaking more for your desired future of "detect drizzle instances and only error on those"
since I'm not sure this will detect as a drizzle instance, as it is a Proxy
Interesting...
I think every js runtime treats proxies differently
is there a better way now to do what I am trying here, to hook into transactions to set variables on each one? I couldn't find one a few months ago
but you said there was more RLS support now, so I am hoping... 🙂
No, not now
Actually, I would love to have your input in the issue
I still have it as a draft PR because I would like some input from somebody using the feature
GitHub
[FEATURE]: Support PostgreSQL's Row Level Security (RLS) · Issue #5...
Describe want to want Supabase is really nicely using Row Level Secruity for granular authorization rules. 🔗 Here's the link to their docs: https://supabase.com/docs/guides/auth/row-level-secur...
I will look later - thank you!
I just thought of another way:
(I haven't forgotten about this btw - have been v busy with work but will get to it. the tab is open!)
busy dude
@Angelelz (not urgent) added some feedback on https://github.com/drizzle-team/drizzle-orm/issues/594 - my only real concern is the ability to bypass RLS by accident, where really it should fail loudly if you attempt to use an RLS client without the proper creds
GitHub
[FEATURE]: Support PostgreSQL's Row Level Security (RLS) · Issue #5...
Describe want to want Supabase is really nicely using Row Level Secruity for granular authorization rules. 🔗 Here's the link to their docs: https://supabase.com/docs/guides/auth/row-level-secur...
I know that this feature isn't so much an RLS client as it is RLS claims support for transactions, but it would be great to have an RLS client as well. That way, we could pass the client object around safely and be confident that the consumers of it can't bypass RLS by mistake