aadish
aadish4w ago

Using Neverthrow with functions

error image attached. example backend code:
import type { QueryCtx, MutationCtx } from '../_generated/server';
import type { Doc } from '../_generated/dataModel';
import { ResultAsync } from 'neverthrow';
import { query, mutation } from '../_generated/server';
import { v } from 'convex/values';
import { err, ok } from 'neverthrow';

export function requireUser(ctx: Ctx): ResultAsync<Doc<"users">, string> {
return ResultAsync.fromPromise(
(async () => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error();
const user = await ctx.db
.query('users')
.withIndex('byTokenIdentifier', (q) => q.eq('tokenIdentifier', identity.subject))
.first();
if (!user) throw new Error();
return user;
})(),
() => "unauthenticated"
);
}


export const listNames = query({
handler: async (ctx) => {
return await requireUser(ctx)
.map(async (user) => {
const pages = await ctx.db
.query('campaigns')
.withIndex('byUserId', (q) => q.eq('userId', user._id))
.order('desc')
.collect();
return pages.map((c) => ({ id: c._id, name: c.name }));
})
},
});
import type { QueryCtx, MutationCtx } from '../_generated/server';
import type { Doc } from '../_generated/dataModel';
import { ResultAsync } from 'neverthrow';
import { query, mutation } from '../_generated/server';
import { v } from 'convex/values';
import { err, ok } from 'neverthrow';

export function requireUser(ctx: Ctx): ResultAsync<Doc<"users">, string> {
return ResultAsync.fromPromise(
(async () => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error();
const user = await ctx.db
.query('users')
.withIndex('byTokenIdentifier', (q) => q.eq('tokenIdentifier', identity.subject))
.first();
if (!user) throw new Error();
return user;
})(),
() => "unauthenticated"
);
}


export const listNames = query({
handler: async (ctx) => {
return await requireUser(ctx)
.map(async (user) => {
const pages = await ctx.db
.query('campaigns')
.withIndex('byUserId', (q) => q.eq('userId', user._id))
.order('desc')
.collect();
return pages.map((c) => ({ id: c._id, name: c.name }));
})
},
});
I imagine its just because Convex can't serialize the Neverthrow Result/Ok object to JSON, is there a clean workaround to this?
No description
7 Replies
Sara
Sara4w ago
oh, and what's the result from 'ResultAsync.fromPromise'? either string or json, correct? you might need to give the query a return type I am asking because there's a detatched "Ok" before the value
aadish
aadishOP4w ago
yeah, I think Ok is a generic class or maybe an object ResultAsync<T, E> is just Promise<Ok<T> | Err<E>>
Sara
Sara4w ago
Yep, now this makes sense, this si not a valid convex type to by pass this, give the query a return type, using the returns
aadish
aadishOP4w ago
oh okay, that makes sense could I do returns: v.any() as Validator<Result<...>> or would that break
Sara
Sara4w ago
I remember there's a way to make it a valid convex type, I just can't remember how I'd chat gpt it
aadish
aadishOP4w ago
okay thx!
erquhart
erquhart4w ago
You can use regular validators, you just need to unwrap the result inside of your convex function before you return: https://github.com/supermacro/neverthrow/wiki/Accessing-The-Value-Inside-A-Result
GitHub
Accessing The Value Inside A Result
Type-Safe Errors for JS & TypeScript. Contribute to supermacro/neverthrow development by creating an account on GitHub.

Did you find this page helpful?