Hello! My project is very simple, I'm just learning TypeScript. I have only 1 table to which I'm storing crypto coins from GeckoCoin's API.
Upsert works with one testing call via rest api but fails via other. I'll explain.
Error:
Invalid `prisma.coin.upsert()` invocation in
/home/vergil333/NodeJSProjects/GraphQL-Demo/src/coin-repository.ts:59:23
Started http server on 127.0.0.1:42703
This is a non-recoverable error which probably happens when the Prisma Query Engine has a panic.
| Name | Version |
|----------|--------------------|
| Node | v10.19.0 |
| OS | debian-openssl-1.1.x|
| Prisma | 2.1.3 |
Started http server on 127.0.0.1:42703
Hey,
I checked your code. After transforming few imports and non existant ErrorMsg object in app.ts I was able to run it. Looks like you are not properly waiting over async code. The javascript array doesn't actually pause on the callback function as the internal code won't await on the promise that was returned by that async function. Also, map doesn't modify the source array so Promise.all call is of no use.
So you had this function in your code which is problematic:
async function updateCoinsFromCG(): Promise<CGCoin[]> {
const coins: CGCoin[] = await cgClient.getAllCoins()
coins.map(async (coin) => {
await repository.updateOrCreateCoin(coin)
})
return Promise.all(coins)
.finally(() => repository.disconnect())
}
Instead you should do this:
async function updateCoinsFromCG(): Promise<Coin[]> {
const coins: CGCoin[] = await cgClient.getAllCoins();
const coinPromises = coins.map((coin) => {
return repository.updateOrCreateCoin(coin);
});
return Promise.all(coinPromises).finally(() => repository.disconnect());
}
This function that I would map over the coins and turns them into a promise. Since map doesn't modify the original array, we store the mapped result into a coinPromises variable. Now we wait over all of them via Promise.all.
I have changed the return type of the function from CGCoin to Coin so that we can match the type returned by updateOrCreateCoin. Also, I have modified updateOrCreateCoin so that it returns the updated value instead of void like so:
async function updateOrCreateCoin(coin: CGCoin): Promise<Coin> {
try {
let result = await prisma.coin.upsert({
where: { cg_id: coin.id },
update: {
cg_id: coin.id,
name: coin.name,
symbol: coin.symbol,
},
create: {
cg_id: coin.id,
name: coin.name,
symbol: coin.symbol,
},
});
return result;
} catch (e) {
console.error("Upsert error: ", e);
throw e;
}
}
I have made a PR so that you can see the changes at a glance: https://github.com/Vergil333/GraphQL-Demo/pull/1
Now after these changes there is no panic and I can see all the records in the database:


I have also seen this wrong pattern in many other places in your code which you should fix.
@pantharshit00 that's a better answer that I was hoping for. Your explanation to the issue is very helpful and educational. Very much appreciated.
Most helpful comment
Hey,
I checked your code. After transforming few imports and non existant ErrorMsg object in
app.tsI was able to run it. Looks like you are not properly waiting over async code. The javascript array doesn't actually pause on the callback function as the internal code won't await on the promise that was returned by that async function. Also, map doesn't modify the source array soPromise.allcall is of no use.So you had this function in your code which is problematic:
Instead you should do this:
This function that I would map over the coins and turns them into a promise. Since map doesn't modify the original array, we store the mapped result into a coinPromises variable. Now we wait over all of them via Promise.all.
I have changed the return type of the function from
CGCointoCoinso that we can match the type returned byupdateOrCreateCoin. Also, I have modifiedupdateOrCreateCoinso that it returns the updated value instead of void like so:I have made a PR so that you can see the changes at a glance: https://github.com/Vergil333/GraphQL-Demo/pull/1
Now after these changes there is no panic and I can see all the records in the database:

