#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 } })