diff --git a/packages/nocodb-sdk/src/lib/globals.ts b/packages/nocodb-sdk/src/lib/globals.ts index e0b4ec186e..3145173bac 100644 --- a/packages/nocodb-sdk/src/lib/globals.ts +++ b/packages/nocodb-sdk/src/lib/globals.ts @@ -146,6 +146,7 @@ export enum NcErrorType { DATABASE_ERROR = 'DATABASE_ERROR', UNKNOWN_ERROR = 'UNKNOWN_ERROR', BAD_JSON = 'BAD_JSON', + INVALID_PK_VALUE = 'INVALID_PK_VALUE', } type Roles = OrgUserRoles | ProjectRoles | WorkspaceUserRoles; diff --git a/packages/nocodb/src/db/BaseModelSqlv2.ts b/packages/nocodb/src/db/BaseModelSqlv2.ts index ecabddcbe1..5b57ca33a1 100644 --- a/packages/nocodb/src/db/BaseModelSqlv2.ts +++ b/packages/nocodb/src/db/BaseModelSqlv2.ts @@ -3007,9 +3007,9 @@ class BaseModelSqlv2 { } } - async _wherePk(id, skipGetColumns = false) { + async _wherePk(id, skipGetColumns = false, skipPkValidation = false) { if (!skipGetColumns) await this.model.getColumns(); - return _wherePk(this.model.primaryKeys, id); + return _wherePk(this.model.primaryKeys, id, skipPkValidation); } comparePks(pk1, pk2) { @@ -6894,24 +6894,35 @@ function applyPaginate( return query; } -export function _wherePk(primaryKeys: Column[], id: unknown | unknown[]) { +export function _wherePk( + primaryKeys: Column[], + id: unknown | unknown[], + skipPkValidation = false, +) { const where = {}; // if id object is provided use as it is if (id && typeof id === 'object' && !Array.isArray(id)) { // verify all pk columns are present in id object for (const pk of primaryKeys) { + let key: string; if (pk.id in id) { - where[pk.column_name] = id[pk.id]; + key = pk.id; } else if (pk.title in id) { - where[pk.column_name] = id[pk.title]; + key = pk.title; } else if (pk.column_name in id) { - where[pk.column_name] = id[pk.column_name]; + key = pk.column_name; } else { NcError.badRequest( `Primary key column ${pk.title} not found in id object`, ); } + where[pk.column_name] = id[key]; + // validate value if auto-increment column + // todo: add more validation based on column constraints + if (!skipPkValidation && pk.ai && !/^\d+$/.test(id[key])) { + NcError.invalidPrimaryKey(id[key], pk.title); + } } return where; diff --git a/packages/nocodb/src/helpers/catchError.ts b/packages/nocodb/src/helpers/catchError.ts index 86269874c3..334c2c9da3 100644 --- a/packages/nocodb/src/helpers/catchError.ts +++ b/packages/nocodb/src/helpers/catchError.ts @@ -520,6 +520,11 @@ const errorHelpers: { message: (offset: string) => `Offset value '${offset}' is invalid`, code: 422, }, + [NcErrorType.INVALID_PK_VALUE]: { + message: (value: any, pkColumn: string) => + `Primary key value '${value}' is invalid for column '${pkColumn}'`, + code: 422, + }, [NcErrorType.INVALID_LIMIT_VALUE]: { message: `Limit value should be between ${defaultLimitConfig.limitMin} and ${defaultLimitConfig.limitMax}`, code: 422, @@ -681,6 +686,13 @@ export class NcError { }); } + static invalidPrimaryKey(value: any, pkColumn: string, args?: NcErrorArgs) { + throw new NcBaseErrorv2(NcErrorType.INVALID_PK_VALUE, { + params: [value, pkColumn], + ...args, + }); + } + static invalidLimitValue(args?: NcErrorArgs) { throw new NcBaseErrorv2(NcErrorType.INVALID_LIMIT_VALUE, { ...args,