TypeORM отбрасывает предложение where

#typescript #postgresql #typeorm

#машинописный текст #postgresql #типоорм

Вопрос:

Я расширяю и улучшаю API, созданный другим (недоступным) разработчиком. Он использует TypeORM, мы используем базу данных PostgreSQL.

Это «функциональный фрейм» (не знаю правильной терминологии) в начале файла, который я намерен изменить:

 type Handler = RequestHandler<ParamsDictionary, any, any, Query>;

const createNew = <TReq, TParent, TChild, TRes = DataNode.DataNode>(
    parentEntityClass: ObjectType<TParent>,
    childPropertyName: string,
    parentPropertyName: string,
    reqValidator: (body: TReq) => boolean,
    constraintSelector: (body: TReq) => string | number | Date | ObjectID,
    dataMapper: (body: TReq, res: Response) => Promise<TChild>,
    responseSerializer?: (
        entity: TChild,
        req?: Request<ParamsDictionary, any, any, Query>
    ) => Promise<TRes>
): Handler => asyncHandler(async (req, res) => {
    const logger = req.getLogger();
    const db = req.getDbContext();

    const reqBody = RequestUtility.getJsonAndValidate<TReq>(
        req,
        reqValidator,
        logger
    );

    const child = await dataMapper(reqBody, res);

    if (parentEntityClass) {
        const parent = await QueryUtility.findOneOrFail(
            db,
            parentEntityClass,
            constraintSelector(reqBody)
        );

        const childsParentWrapped: { [k: string]: any } = {};

        logger.debug(`checking if child refs parent ${JSON.stringify({
            childProps: Object.getOwnPropertyNames(child),
            prop: parentPropertyName
        })}`);

        if (Object.getOwnPropertyNames(child).includes(parentPropertyName) ||
            Object.getOwnPropertyNames(child).includes(`__${parentPropertyName}__`)) {
            childsParentWrapped[parentPropertyName] = Promise.resolve(parent);

            Object.assign(child, childsParentWrapped);
        }

        if (Object.getOwnPropertyNames(parent).includes(childPropertyName)) {
            await QueryUtility.addChild(db, parentEntityClass, childPropertyName, parent, child);
        } else {
            await db.manager.save(child);
        }
    } else {
        await db.manager.save(child);
    }

    const result = await responseSerializer(child, req);

    res.json(result);
});

 

Это функция (другая часть того же файла) Я намерен изменить.

 type NewFile = { fileName: string};
type CreatedNewFileResponse = { uploadUrl: string; file: DataNode.DataNode };

export const createNewFile: Handler = createNew<NewFile, EUser, EFile, CreatedNewFileResponse>(
    EUser,
    "",
    "user",
    (body) => body.fileName ? true : false,
    (body) => null,
    async (body, res) => {
        const newFile = new EFile();
        const fileType = body.fileName.toLowerCase().split(/.(?=[^.] $)/);
        if (['jpg', 'jpeg', 'gif', 'bmp', 'png'].includes(fileType[1])){
            newFile.fileName = body.fileName;
            newFile.fileType = 'image';
            newFile.storageProvider = "internal-storage";
            newFile.isMarkedForDeletion = false;
            const id = JSON.parse(JSON.stringify(res.locals.jwtPayload.id));
            newFile.user = Promise.resolve(
                        await getRepository(EUser).findOne({where: { id } })    
                        );
            return newFile;

        } else if (['avi', 'wmv', 'mp4', 'mkv', 'flv', 'mov'].includes(fileType[1])) {
            newFile.fileName = body.fileName;
            newFile.fileType = 'video';
            newFile.storageProvider = "internal-storage";
            newFile.isMarkedForDeletion = false;
            const id = JSON.parse(JSON.stringify(res.locals.jwtPayload.id));
            newFile.user = Promise.resolve(
                        await getRepository(EUser).findOne({where: { id } })    
                        );

            return newFile;

        } else if (['ogg', 'wma', 'wave', 'mp3', 'wav', 'm4a'].includes(fileType[1])) {
            newFile.fileName = body.fileName;
            newFile.fileType = 'audio';
            newFile.storageProvider = "internal-storage";
            newFile.isMarkedForDeletion = false;
            const id = JSON.parse(JSON.stringify(res.locals.jwtPayload.id));
            newFile.user = Promise.resolve(
                        await getRepository(EUser).findOne({where: { id } })    
                        );

            return newFile;

        } else {
            throw errors.create(BadRequestError);
        }
    },
    async (newFile, req) => {
        const minioContext = req.getMinioContext();
        let uploadUrl = await minioContext.client.presignedUrl(
            "PUT",
            minioContext.bucket,
            newFile.fileName,
            7 * 24 * 60 * 60,
            { query: {}, headers: { host: req.hostname } }
        );
        uploadUrl = uploadUrl.replace(
            `${minioContext.config.host}:${minioContext.config.port}`,
            req.hostname
        ).replace("localhost", `${minioContext.config.minioUrl}`).replace("http", "https")

        return {
            uploadUrl,
            file: await DataNode.fromFile(newFile)
        };
    }
);

 

Функция работает (например, она служит своей цели без ошибок) и вставляет нужную строку в базу данных. Но в строке, в которой указано newFile.user = JSON.parse(JSON.stringify(res.locals.jwtPayload.id)); , что, хотя она и извлекает правильную информацию (возвращает идентификатор из JWT), эта информация отбрасывается, как мы можем видеть в журнале PostgreSQL, используя затем первую строку из таблицы Users (что означает, что не используется полученный нами идентификатор):

 2020-12-04 18:39:20.395 UTC [690] DETAIL:  parameters: $1 = '1'
2020-12-04 18:39:20.405 UTC [690] LOG:  execute <unnamed>: SELECT "User"."id" AS "User_id", "User"."created" AS "User_created", "User"."updatedAt" AS "User_updatedAt", "User"."username" AS "User_username", "User"."password" AS "User_password", "User"."role" AS "User_role", "User"."firstName" AS "User_firstName", "User"."lastName" AS "User_lastName", "User"."email" AS "User_email" FROM "Users" "User" WHERE "User"."id" = $1 LIMIT 1
2020-12-04 18:39:20.405 UTC [690] DETAIL:  parameters: $1 = '1'
2020-12-04 18:39:20.413 UTC [690] LOG:  statement: SELECT "User"."id" AS "User_id", "User"."created" AS "User_created", "User"."updatedAt" AS "User_updatedAt", "User"."username" AS "User_username", "User"."password" AS "User_password", "User"."role" AS "User_role", "User"."firstName" AS "User_firstName", "User"."lastName" AS "User_lastName", "User"."email" AS "User_email" FROM "Users" "User" LIMIT 1
2020-12-04 18:39:20.420 UTC [690] LOG:  statement: START TRANSACTION
2020-12-04 18:39:20.429 UTC [690] LOG:  execute <unnamed>: INSERT INTO "Files"("fileName", "fileType", "storageProvider", "isMarkedForDeletion", "userId") VALUES ($1, $2, $3, $4, $5) RETURNING "id", "created", "updatedAt"
2020-12-04 18:39:20.429 UTC [690] DETAIL:  parameters: $1 = 'test.jpg', $2 = 'image', $3 = 'internal-storage', $4 = 'f', $5 = '2'
2020-12-04 18:39:20.433 UTC [690] LOG:  statement: COMMIT
 

Как вы можете видеть в строке 2 снипета журнала, условие where соблюдается. Но когда мы доходим до той части, где информация должна быть вставлена в базу данных (строка 4 снипета), предложение where отбрасывается.

Я не знаю достаточно, чтобы отлаживать это в одиночку. Любая помощь будет глубоко признательна.

Ответ №1:

Решил ее.

В итоге я сменил «пользователь» на «».

Каким-то образом это решило проблему, и теперь запрос, который достигает моего postgres, включает идентификатор пользователя, как я и хотел.

В любом случае спасибо.

Ответ №2:

Похоже, вы указываете только столбец в предложении where, а не значение. Предполагая, что значение id находится в переменной с именем ‘id’, оператор find должен быть таким: await getRepository(EUser).findOne({где: { id: id } })