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

Typescript 需要将可观察到的过去2个结果作为输入到第三个,typescript,rxjs,Typescript,Rxjs,有没有一种方法可以从一个可观察的序列中获得过去的两个结果,并将其作为第三个序列的输入 这是没有任何可见项的代码 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}`);

有没有一种方法可以从一个可观察的序列中获得过去的两个结果,并将其作为第三个序列的输入

这是没有任何可见项的代码

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,
    };
}

这是我尝试的有效解决方案,但我只是想知道这是正确的还是有更好的方法

我需要
用户
有效的
结果生成我的
映射
,以便创建正确的对象

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

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();
}
公共登录(…):承诺{
从(ctx.prisma.query.user({where:{email}}]).pipe返回(
开关图(
(用户:用户)=>{
如果(!用户){
抛出新错误(`没有为电子邮件找到这样的用户:${email}`);
}
从(bcrypt.compare(password,user.password)).pipe返回(
地图(
(有效:布尔)=>{
如果(!有效){
抛出新错误(“无效密码”);
}
返回{
令牌:jwt.sign({userId:user.id},process.env.APP_SECRET),
用户,
};
}
)
);
}
)
).toPromise();
}

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

公共登录(…):承诺{
从(ctx.prisma.query.user({where:{email}}]).pipe返回(
开关图(
(用户:用户)=>{
如果(!用户){
抛出新错误(`没有为电子邮件找到这样的用户:${email}`);
}
从(bcrypt.compare(password,user.password))返回;
}
,(用户,有效)=>{
如果(!有效){
抛出新错误(“无效密码”);
}
返回{
令牌:jwt.sign({userId:user.id},process.env.APP_SECRET),
用户,
};
}
)).toPromise();
}

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

公共登录(…):承诺{
从(ctx.prisma.query.user({where:{email}}]).pipe返回(
开关图(
(用户:用户)=>{
如果(!用户){
抛出新错误(`没有为电子邮件找到这样的用户:${email}`);
}
从(bcrypt.compare(password,user.password))返回;
}
,(用户,有效)=>{
如果(!有效){
抛出新错误(“无效密码”);
}
返回{
令牌:jwt.sign({userId:user.id},process.env.APP_SECRET),
用户,
};
}
)).toPromise();
}

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

我所做的第一个更改是使用
点击
进行错误检查。这真的只是为了外观,尽管我猜检查地图中的错误感觉是错误的

接下来,将
开关映射
更改为采用结合检索到的用户值和解密结果的
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,
    }))
)

在您的解决方案中,您可以做一些事情来避免所有级别的嵌套,但在我看来,您所做的并没有错

我所做的第一个更改是使用
点击
进行错误检查。这真的只是为了外观,尽管我猜检查地图中的错误感觉是错误的

接下来,将
开关映射
更改为采用结合检索到的用户值和解密结果的
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();
}
公共登录(
资料来源:任何,
{电子邮件,密码},
ctx:IContext,
信息:GraphQLResolveInfo):承诺{
从(ctx.prisma.query.user({where:{email}}]).pipe返回(
水龙头(
(用户:用户)=>{
如果(!用户){
抛出新错误(`没有为电子邮件找到这样的用户:${email}`);
}
}
),
开关图(
(用户:用户)=>{
从(bcrypt.compare(password,user.password)).pipe返回(
地图(
(有效:布尔)=>{
如果(!有效){
抛出新错误(“无效密码”);
}
返回{
令牌:jwt.sign(
{userId:user.id},
process.env.APP_SECRET
),
用户,
};
}
)
);
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();
}