需要将可观察结果中的过去 2 个结果作为输入到第三个结果中



有没有办法从可观察序列中获取过去 2 个结果并用作第三个结果的输入。

这是没有任何可观察量的代码。

public login(...): Promise<any> {
const user: any = ctx.prisma.query.user({ where: { email } });
if (!user) {
throw new Error(`No such user found for email: ${email}`);
}
const valid = bcrypt.compare(password, user.password);
if (!valid) {
throw new Error("Invalid password");
}
return {
token: jwt.sign({ userId: user.id }, process.env.APP_SECRET),
user,
};
}

这是我的解决方案,它不起作用,让我问这个问题。这不起作用,因为我没有调用ctx.prisma.query.user(...)user结果,当我需要检查valid并执行我的map时。

public login(...): Promise<any> {
return from(ctx.prisma.query.user({ where: { email } })).pipe(
mergeMap(
(user: User) => {
if (!user) {
throw new Error(`No such user found for email: ${email}`);
}
return from(bcrypt.compare(password, user.password));
}
),
map(
(valid: boolean) => {
if (!valid) {
throw new Error("Invalid password");
}
return {
token: jwt.sign({ userId: user.id }, process.env.APP_SECRET),
user,
};
}
)
).toPromise();
}

这是我对这个有效解决方案的尝试,但我只是想知道这是否正确或是否有更好的方法。

我需要uservalid结果在我的map,以便我可以创建正确的对象。

我的解决方案只是感觉很奇怪,因为如果我需要继续使用这个序列和之前的结果,它会变得非常深入。

public login(...): Promise<any> {
return from(ctx.prisma.query.user({ where: { email } })).pipe(
switchMap(
(user: User) => {
if (!user) {
throw new Error(`No such user found for email: ${email}`);
}
return from(bcrypt.compare(password, user.password)).pipe(
map(
(valid: boolean) => {
if (!valid) {
throw new Error("Invalid password");
}
return {
token: jwt.sign({ userId: user.id }, process.env.APP_SECRET),
user,
};
}
)
);
}
)
).toPromise();
}

switchMap 是你想要的运算符,switchMap 的第二个参数是一个 map 函数,它获取内部和外部可观察量的结果,并允许您将它们组合在一起(mergemap 接受相同的第二个参数,但首选 switchMap,因为它是"更安全"的运算符(:

public login(...): Promise<any> {
return from(ctx.prisma.query.user({ where: { email } })).pipe(
switchMap(
(user: User) => {
if (!user) {
throw new Error(`No such user found for email: ${email}`);
}
return from(bcrypt.compare(password, user.password));
}
, (user, valid) => {
if (!valid) {
throw new Error("Invalid password");
}
return {
token: jwt.sign({ userId: user.id }, process.env.APP_SECRET),
user,
};
}
)).toPromise();
}

在您的解决方案中,您可以做一些事情来避免所有级别的嵌套,但 IMO 您拥有的东西没有错。

我所做的第一个更改是使用tap进行错误检查。 这实际上只是为了外观,尽管我想检查地图中的错误感觉不对。

接下来,将switchMap更改为采用一个forkJoin,该将检索到的用户值和解密结果组合在一起。forkJoin是我能想到的最干净的方式,可以在序列中进一步传递用户。

其余的都很简单。

from(ctx.prisma.query.user({ where: { email } })).pipe(
tap(user => { if (!user) throw new Error(`No such user found for email: ${email}`); }),
switchMap(user => forkJoin(of(user), from(bcrypt.compare(password, user.password))),
tap(([user, valid]) => { if (!valid) throw new Error('Invalid password'); })
map(([user, valid]) => ({
token: jwt.sign({ userId: user.id }, process.env.APP_SECRET),
user,
}))
)

在 @bryan60 和 @Daniel Gimenez 的帮助下,我们得出的结论是,我在问题中提供的解决方案在版本 6 中是最准确的。这是我的最终解决方案。

public login(
source: any, 
{email, password}, 
ctx: IContext, 
info: GraphQLResolveInfo): Promise<any> {
return from(ctx.prisma.query.user({ where: { email } })).pipe(
tap(
(user: User) => {
if (!user) {
throw new Error(`No such user found for email: ${email}`);
}
}
),
switchMap(
(user: User) => {
return from(bcrypt.compare(password, user.password)).pipe(
map(
(valid: boolean) => {
if (!valid) {
throw new Error("Invalid password");
}
return {
token: jwt.sign(
{ userId: user.id }, 
process.env.APP_SECRET
),
user,
};
}
)
);
}
)
).toPromise();
}

相关内容

最新更新