1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Server: Remove unique constraint errors from the log when they are already handled by the application

This commit is contained in:
Laurent Cozic 2021-11-28 17:26:36 +00:00
parent 7eb1d89d66
commit a6884a2ee4
4 changed files with 23 additions and 7 deletions

View File

@ -47,6 +47,10 @@ export interface DbConfigConnection {
password?: string; password?: string;
} }
export interface QueryContext {
uniqueConstraintErrorLoggingDisabled?: boolean;
}
export interface KnexDatabaseConfig { export interface KnexDatabaseConfig {
client: string; client: string;
connection: DbConfigConnection; connection: DbConfigConnection;
@ -204,6 +208,7 @@ interface KnexQueryErrorResponse {
interface KnexQueryErrorData { interface KnexQueryErrorData {
bindings: any[]; bindings: any[];
queryContext: QueryContext;
} }
export async function connectDb(dbConfig: DatabaseConfig): Promise<DbConnection> { export async function connectDb(dbConfig: DatabaseConfig): Promise<DbConnection> {
@ -214,6 +219,16 @@ export async function connectDb(dbConfig: DatabaseConfig): Promise<DbConnection>
} }
connection.on('query-error', (response: KnexQueryErrorResponse, data: KnexQueryErrorData) => { 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[] = []; const msg: string[] = [];
msg.push(response.message); msg.push(response.message);
if (data.bindings && data.bindings.length) msg.push(JSON.stringify(filterBindings(data.bindings), null, ' ')); if (data.bindings && data.bindings.length) msg.push(JSON.stringify(filterBindings(data.bindings), null, ' '));

View File

@ -1,5 +1,5 @@
import { WithDates, WithUuid, databaseSchema, ItemType, Uuid, User } from '../services/database/types'; 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 TransactionHandler from '../utils/TransactionHandler';
import uuidgen from '../utils/uuidgen'; import uuidgen from '../utils/uuidgen';
import { ErrorUnprocessableEntity, ErrorBadRequest } from '../utils/errors'; import { ErrorUnprocessableEntity, ErrorBadRequest } from '../utils/errors';
@ -24,6 +24,7 @@ export interface SaveOptions {
skipValidation?: boolean; skipValidation?: boolean;
validationRules?: any; validationRules?: any;
previousItem?: any; previousItem?: any;
queryContext?: QueryContext;
} }
export interface LoadOptions { export interface LoadOptions {
@ -297,12 +298,12 @@ export default abstract class BaseModel<T> {
await this.withTransaction(async () => { await this.withTransaction(async () => {
if (isNew) { if (isNew) {
await this.db(this.tableName).insert(toSave); await this.db(this.tableName).insert(toSave).queryContext(options.queryContext || {});
} else { } else {
const objectId: string = (toSave as WithUuid).id; const objectId: string = (toSave as WithUuid).id;
if (!objectId) throw new Error('Missing "id" property'); if (!objectId) throw new Error('Missing "id" property');
delete (toSave as WithUuid).id; 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; (toSave as WithUuid).id = objectId;
// Sanity check: // Sanity check:

View File

@ -179,7 +179,7 @@ export default class ShareModel extends BaseModel<Share> {
const addUserItem = async (shareUserId: Uuid, itemId: Uuid) => { const addUserItem = async (shareUserId: Uuid, itemId: Uuid) => {
try { try {
await this.models().userItem().add(shareUserId, itemId); await this.models().userItem().add(shareUserId, itemId, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } });
} catch (error) { } catch (error) {
if (!isUniqueConstraintError(error)) throw error; if (!isUniqueConstraintError(error)) throw error;
} }
@ -322,7 +322,7 @@ export default class ShareModel extends BaseModel<Share> {
for (const resourceItem of resourceItems) { for (const resourceItem of resourceItems) {
if (doShare) { if (doShare) {
try { try {
await this.models().userItem().add(toUserId, resourceItem.id); await this.models().userItem().add(toUserId, resourceItem.id, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } });
} catch (error) { } catch (error) {
if (isUniqueConstraintError(error)) { if (isUniqueConstraintError(error)) {
continue; continue;
@ -337,7 +337,7 @@ export default class ShareModel extends BaseModel<Share> {
for (const resourceBlobItem of resourceBlobItems) { for (const resourceBlobItem of resourceBlobItems) {
if (doShare) { if (doShare) {
try { try {
await this.models().userItem().add(toUserId, resourceBlobItem.id); await this.models().userItem().add(toUserId, resourceBlobItem.id, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } });
} catch (error) { } catch (error) {
if (isUniqueConstraintError(error)) { if (isUniqueConstraintError(error)) {
continue; continue;

View File

@ -37,7 +37,7 @@ export default class UserFlagModels extends BaseModel<UserFlag> {
await this.save({ await this.save({
user_id: userId, user_id: userId,
type, type,
}); }, { queryContext: { uniqueConstraintErrorLoggingDisabled: true } });
} catch (error) { } catch (error) {
if (!isUniqueConstraintError(error)) { if (!isUniqueConstraintError(error)) {
throw error; throw error;