[FEATURE]: return a object instead of a array if insert value is a object not array
Describe what you want
Hi, I want to create a row, so I code this.
const model = await this.db.drizzle
.insert(schema.user)
.values({
authCode,
...userDto,
password: hashSync(userDto.password, 10),
})
.returning()
return model[0]
I added a .returning to get the new model. But I got model[], to I should destruct it first. model[0] is the data I want. But I insert just a single object, so the expected result should be an object, which can save one step of writing.
This is the expected behaviour.
const model = await this.db.drizzle
.insert(schema.user)
.values({
authCode,
...userDto,
password: hashSync(userDto.password, 10),
})
.returning()
return model
I truly hope they develop this feature; constantly having to destructure like this can be quite frustrating.
const [model]= await this.db.drizzle .insert(schema.user) .values({ authCode, ...userDto, password: hashSync(userDto.password, 10), }) .returning()
const model = await this.db.drizzle
.insert(schema.user)
.values({
authCode,
...userDto,
password: hashSync(userDto.password, 10),
})
.returning().first()
how about this
i find this very useful!
Just destructure on response:
const [ model ] = await this.db.drizzle
.insert(schema.user)
.values({
authCode,
...userDto,
password: hashSync(userDto.password, 10),
})
.returning()
return model
Are we guaranteed that there is a first element in the returned array if the call to returning is successful?
what about ?
const model = await this.db.drizzle
.insert(schema.user)
.values({
authCode,
...userDto,
password: hashSync(userDto.password, 10),
})
.returning()
.then((res) => res[0] ?? null)
return model
the problem is that we have to do modal.id ?? "" while returning, coz the modal is not a garenteed response, even thought it should be
the problem is that we have to do modal.id ?? "" while returning, coz the modal is not a garenteed response, even thought it should be
This sounds like a really nasty bug if this is the case and should be rewarded with its own ticket. How are you supposed to handle it when the row exists but the lib thinks it's not there and no error is thrown? Select it again? Delete it and retry?
will throw in here that "then"-ing or destructuring the response isn't ideal when you are reusing your "repository layer" for batch calls. the moment you return something other than the drizzle sql object, it can no longer be used inside db.batch([])
I think the proposal also applies to select , especially when we do the count
Other downside of the way it's working is that even if the promise resolves correctly, typescript can't infer correctly the type since Array[i] could be undefined. Would be awesome to have this feature.
I also hope for some built-in solution.
In the meantime, by combining with Lodash's first(), we get a nicer syntax over .then((res) => res[0] ?? null):
import { first } from "lodash-es"
db.insert(schema.user).values(data).returning().then(first)
Can someone please confirm if this is indeed an issue? Currently, the typings indicate that this cannot occur.
try {
const [res] = await db.insert(users).values({
...validated.data
}).returning();
} catch (err) {
// ...
}
According to the typings in "drizzle-orm": "^0.31.1", the destructured object res is not typed to include undefined or null.
Can someone please confirm if this is indeed an issue? Currently, the typings indicate that this cannot occur.
try { const [res] = await db.insert(users).values({ ...validated.data }).returning(); } catch (err) { // ... }According to the typings in "drizzle-orm": "^0.31.1", the destructured object
resis not typed to includeundefinedornull.
I'm not sure if I understood correctly, but it's not a matter of "res" typing. The promise resolves to an array of the entity or the filtered fields passed in returning(). When destructuring, typescript can't know if the array[0] is defined. Of course noUncheckedIndexedAccess must be enabled to see this problem.
That's an obvious DX improvement!
that would be nice
Oh no, was hoping thsi would have gotten some traction
I would love this as well
upvote!!
+1
+1
+1
ye thats a nice improvement
this would be great.
There’s a potential issue if you use .onConflictDoNothing(). If a conflict is found, it returns an empty array because nothing was inserted. So, in some cases, it might actually be empty.
+1
It would also be nice if we can get this functionality on queries that select, including the useLiveQuery hook. For example, if I have a todo app and I have a screen that only displays one todo list, I might use the useLiveQuery hook to get the data for the list and then display it on the UI. But since the data returned from the query is always an array of objects, I have to use data[0] throughout the screen to access the todo list's values. It's a bit inconvenient to have to do that all the time...
I also hope for some built-in solution.
In the meantime, by combining with Lodash's
first(), we get a nicer syntax over.then((res) => res[0] ?? null):import { first } from "lodash-es"
db.insert(schema.user).values(data).returning().then(first)
For those who want a quick copy paste and not install yet another library:
export function first<T>(array: T[]): T | undefined {
return array[0];
}
For typescript just do
const newUser = await drizzle
.insert(user)
.values({...}).then([u] => u!)
In this case newUser will have type User and not User | undefined
Be cautious when you have .onConflictDoNothing() - then this will not work correctly...