From a6884a2ee44548777fbb5f88757a7a126c8635e9 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 28 Nov 2021 17:26:36 +0000 Subject: [PATCH] Server: Remove unique constraint errors from the log when they are already handled by the application --- packages/server/src/db.ts | 15 +++++++++++++++ packages/server/src/models/BaseModel.ts | 7 ++++--- packages/server/src/models/ShareModel.ts | 6 +++--- packages/server/src/models/UserFlagModel.ts | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/server/src/db.ts b/packages/server/src/db.ts index 3d2cab475c..e14d63a20f 100644 --- a/packages/server/src/db.ts +++ b/packages/server/src/db.ts @@ -47,6 +47,10 @@ export interface DbConfigConnection { password?: string; } +export interface QueryContext { + uniqueConstraintErrorLoggingDisabled?: boolean; +} + export interface KnexDatabaseConfig { client: string; connection: DbConfigConnection; @@ -204,6 +208,7 @@ interface KnexQueryErrorResponse { interface KnexQueryErrorData { bindings: any[]; + queryContext: QueryContext; } export async function connectDb(dbConfig: DatabaseConfig): Promise { @@ -214,6 +219,16 @@ export async function connectDb(dbConfig: DatabaseConfig): Promise } connection.on('query-error', (response: KnexQueryErrorResponse, data: KnexQueryErrorData) => { + // It is possible to set certain properties on the query context to + // disable this handler. This is useful for example for constraint + // errors which are often already handled application side. + + if (data.queryContext) { + if (data.queryContext.uniqueConstraintErrorLoggingDisabled && isUniqueConstraintError(response)) { + return; + } + } + const msg: string[] = []; msg.push(response.message); if (data.bindings && data.bindings.length) msg.push(JSON.stringify(filterBindings(data.bindings), null, ' ')); diff --git a/packages/server/src/models/BaseModel.ts b/packages/server/src/models/BaseModel.ts index f1ef38bca7..54bf187e2a 100644 --- a/packages/server/src/models/BaseModel.ts +++ b/packages/server/src/models/BaseModel.ts @@ -1,5 +1,5 @@ import { WithDates, WithUuid, databaseSchema, ItemType, Uuid, User } from '../services/database/types'; -import { DbConnection } from '../db'; +import { DbConnection, QueryContext } from '../db'; import TransactionHandler from '../utils/TransactionHandler'; import uuidgen from '../utils/uuidgen'; import { ErrorUnprocessableEntity, ErrorBadRequest } from '../utils/errors'; @@ -24,6 +24,7 @@ export interface SaveOptions { skipValidation?: boolean; validationRules?: any; previousItem?: any; + queryContext?: QueryContext; } export interface LoadOptions { @@ -297,12 +298,12 @@ export default abstract class BaseModel { await this.withTransaction(async () => { if (isNew) { - await this.db(this.tableName).insert(toSave); + await this.db(this.tableName).insert(toSave).queryContext(options.queryContext || {}); } else { const objectId: string = (toSave as WithUuid).id; if (!objectId) throw new Error('Missing "id" property'); delete (toSave as WithUuid).id; - const updatedCount: number = await this.db(this.tableName).update(toSave).where({ id: objectId }); + const updatedCount: number = await this.db(this.tableName).update(toSave).where({ id: objectId }).queryContext(options.queryContext || {}); (toSave as WithUuid).id = objectId; // Sanity check: diff --git a/packages/server/src/models/ShareModel.ts b/packages/server/src/models/ShareModel.ts index 0f896c39f2..d2a37d51cf 100644 --- a/packages/server/src/models/ShareModel.ts +++ b/packages/server/src/models/ShareModel.ts @@ -179,7 +179,7 @@ export default class ShareModel extends BaseModel { const addUserItem = async (shareUserId: Uuid, itemId: Uuid) => { try { - await this.models().userItem().add(shareUserId, itemId); + await this.models().userItem().add(shareUserId, itemId, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } }); } catch (error) { if (!isUniqueConstraintError(error)) throw error; } @@ -322,7 +322,7 @@ export default class ShareModel extends BaseModel { for (const resourceItem of resourceItems) { if (doShare) { try { - await this.models().userItem().add(toUserId, resourceItem.id); + await this.models().userItem().add(toUserId, resourceItem.id, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } }); } catch (error) { if (isUniqueConstraintError(error)) { continue; @@ -337,7 +337,7 @@ export default class ShareModel extends BaseModel { for (const resourceBlobItem of resourceBlobItems) { if (doShare) { try { - await this.models().userItem().add(toUserId, resourceBlobItem.id); + await this.models().userItem().add(toUserId, resourceBlobItem.id, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } }); } catch (error) { if (isUniqueConstraintError(error)) { continue; diff --git a/packages/server/src/models/UserFlagModel.ts b/packages/server/src/models/UserFlagModel.ts index be5c5aba74..6176f42b00 100644 --- a/packages/server/src/models/UserFlagModel.ts +++ b/packages/server/src/models/UserFlagModel.ts @@ -37,7 +37,7 @@ export default class UserFlagModels extends BaseModel { await this.save({ user_id: userId, type, - }); + }, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } }); } catch (error) { if (!isUniqueConstraintError(error)) { throw error;