From da5be601f7bb3364774f31251894760cf4098803 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 14:01:37 +0800 Subject: [PATCH 1/9] feat(nc-gui): include fieldLengthValidator --- packages/nc-gui/components/template/Editor.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/components/template/Editor.vue b/packages/nc-gui/components/template/Editor.vue index 6d1092bb5e..4b7a1a7d96 100644 --- a/packages/nc-gui/components/template/Editor.vue +++ b/packages/nc-gui/components/template/Editor.vue @@ -13,6 +13,7 @@ import { createEventHook, extractSdkResponseErrorMsg, fieldRequiredValidator, + fieldLengthValidator, getDateFormat, getDateTimeFormat, getUIDTIcon, @@ -110,12 +111,12 @@ const data = reactive<{ }) const validators = computed(() => - data.tables.reduce]>>((acc, table, tableIdx) => { + data.tables.reduce]>>((acc: Record, table, tableIdx) => { acc[`tables.${tableIdx}.table_name`] = [fieldRequiredValidator()] hasSelectColumn.value[tableIdx] = false table.columns?.forEach((column, columnIdx) => { - acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator()] + acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator(), fieldLengthValidator()] acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()] if (isSelect(column)) { hasSelectColumn.value[tableIdx] = true From e7268325a47ad5b7f2f1fa05bd27cdaac673a1b0 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:07:55 +0800 Subject: [PATCH 2/9] feat(nc-gui): add columnNameExceedsCharacters --- packages/nc-gui/lang/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 7169e07026..bdbc84d36d 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -690,6 +690,7 @@ "nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _", "followingCharactersAreNotAllowed": "Following characters are not allowed", "columnNameRequired": "Column name is required", + "columnNameExceedsCharacters": "The length of column name exceeds the max {value} characters", "projectNameExceeds50Characters": "Project name exceeds 50 characters", "projectNameCannotStartWithSpace": "Project name cannot start with space", "requiredField": "Required field", From 48188c2e6ac703f4941f479b763a7b1c271e8013 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:08:35 +0800 Subject: [PATCH 3/9] feat(nc-gui): add fieldLengthValidator --- packages/nc-gui/utils/validation.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/nc-gui/utils/validation.ts b/packages/nc-gui/utils/validation.ts index 3524a1f928..fb1c50ea41 100644 --- a/packages/nc-gui/utils/validation.ts +++ b/packages/nc-gui/utils/validation.ts @@ -80,6 +80,32 @@ export const fieldRequiredValidator = () => { } } +export const fieldLengthValidator = (sqlClientType: string) => { + return { + validator: (rule: any, value: any) => { + const { t } = getI18n().global + + // no limit for sqlite but set as 255 + let fieldLengthLimit = 255 + + if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { + fieldLengthLimit = 64 + } else if (sqlClientType === 'pg') { + fieldLengthLimit = 59 + } else if (sqlClientType === 'mssql') { + fieldLengthLimit = 128 + } + + return new Promise((resolve, reject) => { + if (value?.length > fieldLengthLimit) { + reject(new Error(t('msg.error.columnNameExceedsCharacters', { value: fieldLengthLimit }))) + } + resolve(true) + }) + }, + } +} + export const importUrlValidator = { validator: (rule: any, value: any) => { return new Promise((resolve, reject) => { From 23b55b02c254c18ea20eaaf906e13bca87324eb9 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:09:25 +0800 Subject: [PATCH 4/9] feat(nc-gui): include fieldLengthValidator --- packages/nc-gui/components/template/Editor.vue | 7 +++++-- packages/nc-gui/composables/useColumnCreateStore.ts | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/components/template/Editor.vue b/packages/nc-gui/components/template/Editor.vue index 4b7a1a7d96..3d44a13a73 100644 --- a/packages/nc-gui/components/template/Editor.vue +++ b/packages/nc-gui/components/template/Editor.vue @@ -12,8 +12,8 @@ import { computed, createEventHook, extractSdkResponseErrorMsg, - fieldRequiredValidator, fieldLengthValidator, + fieldRequiredValidator, getDateFormat, getDateTimeFormat, getUIDTIcon, @@ -116,7 +116,10 @@ const validators = computed(() => hasSelectColumn.value[tableIdx] = false table.columns?.forEach((column, columnIdx) => { - acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [fieldRequiredValidator(), fieldLengthValidator()] + acc[`tables.${tableIdx}.columns.${columnIdx}.column_name`] = [ + fieldRequiredValidator(), + fieldLengthValidator(project.value?.bases?.[0].type || ClientType.MYSQL), + ] acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()] if (isSelect(column)) { hasSelectColumn.value[tableIdx] = true diff --git a/packages/nc-gui/composables/useColumnCreateStore.ts b/packages/nc-gui/composables/useColumnCreateStore.ts index 4a23f1e013..d1b5ebb68b 100644 --- a/packages/nc-gui/composables/useColumnCreateStore.ts +++ b/packages/nc-gui/composables/useColumnCreateStore.ts @@ -27,7 +27,8 @@ interface ValidationsObj { const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState( (meta: Ref, column: Ref) => { - const { sqlUis, isMysql: isMysqlFunc, isPg: isPgFunc, isMssql: isMssqlFunc } = useProject() + const { project, sqlUis, isMysql: isMysqlFunc, isPg: isPgFunc, isMssql: isMssqlFunc } = useProject() + const { $api } = useNuxtApp() const { getMeta } = useMetas() @@ -93,6 +94,7 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState }) }, }, + fieldLengthValidator(project.value?.bases?.[0].type || ClientType.MYSQL), ], uidt: [ { From b67f3134464bad5f141e0bc2e55239096a6c7ef9 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:41:46 +0800 Subject: [PATCH 5/9] feat(nocodb): add getMaxColumnNameLength --- packages/nocodb/src/lib/models/Column.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/nocodb/src/lib/models/Column.ts b/packages/nocodb/src/lib/models/Column.ts index 69b20dfe9a..6d7b2d5345 100644 --- a/packages/nocodb/src/lib/models/Column.ts +++ b/packages/nocodb/src/lib/models/Column.ts @@ -1151,4 +1151,17 @@ export default class Column implements ColumnType { colId ); } + + static getMaxColumnNameLength(sqlClientType: string) { + // no limit for sqlite but set as 255 + let fieldLengthLimit = 255; + if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { + fieldLengthLimit = 64; + } else if (sqlClientType === 'pg') { + fieldLengthLimit = 59; + } else if (sqlClientType === 'mssql') { + fieldLengthLimit = 128; + } + return fieldLengthLimit; + } } From c47787d95902b3cfacae9855f63b587f3e7313c8 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:42:12 +0800 Subject: [PATCH 6/9] feat(nocodb): validate column name at api level --- packages/nocodb/src/lib/meta/api/columnApis.ts | 14 ++++++++++++++ packages/nocodb/src/lib/meta/api/tableApis.ts | 17 ++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/nocodb/src/lib/meta/api/columnApis.ts b/packages/nocodb/src/lib/meta/api/columnApis.ts index 97fbb68c06..b99f7a5cba 100644 --- a/packages/nocodb/src/lib/meta/api/columnApis.ts +++ b/packages/nocodb/src/lib/meta/api/columnApis.ts @@ -64,9 +64,23 @@ export async function columnAdd( const table = await Model.getWithInfo({ id: req.params.tableId, }); + const base = await Base.get(table.base_id); + const project = await base.getProject(); + const dbDriver = NcConnectionMgrv2.get(base); + + const sqlClientType = dbDriver.clientType(); + + const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); + + if (req.body.column_name.length > mxColumnLength) { + NcError.badRequest( + `Column name ${req.body.column_name} exceeds ${mxColumnLength} characters` + ); + } + if ( !isVirtualCol(req.body) && !(await Column.checkTitleAvailable({ diff --git a/packages/nocodb/src/lib/meta/api/tableApis.ts b/packages/nocodb/src/lib/meta/api/tableApis.ts index 8eb3d6a10e..7fe1f5e905 100644 --- a/packages/nocodb/src/lib/meta/api/tableApis.ts +++ b/packages/nocodb/src/lib/meta/api/tableApis.ts @@ -148,10 +148,15 @@ export async function tableCreate(req: Request, res) { } const sqlMgr = await ProjectMgrv2.getSqlMgr(project); + const sqlClient = await NcConnectionMgrv2.getSqlClient(base); + const dbDriver = NcConnectionMgrv2.get(base); + + const sqlClientType = dbDriver.clientType(); + let tableNameLengthLimit = 255; - const sqlClientType = sqlClient.clientType; + if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { tableNameLengthLimit = 64; } else if (sqlClientType === 'pg') { @@ -164,6 +169,16 @@ export async function tableCreate(req: Request, res) { NcError.badRequest(`Table name exceeds ${tableNameLengthLimit} characters`); } + const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); + + for (const column of req.body.columns) { + if (column.column_name.length > mxColumnLength) { + NcError.badRequest( + `Column name ${column.column_name} exceeds ${mxColumnLength} characters` + ); + } + } + req.body.columns = req.body.columns?.map((c) => ({ ...getColumnPropsFromUIDT(c as any, base), cn: c.column_name, From 2a1abc1acdcf7f5a6547b10dd0222412b7a923be Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:49:56 +0800 Subject: [PATCH 7/9] feat(nocodb): validate column name length in columnUpdate --- packages/nocodb/src/lib/meta/api/columnApis.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/nocodb/src/lib/meta/api/columnApis.ts b/packages/nocodb/src/lib/meta/api/columnApis.ts index b99f7a5cba..d2cf932860 100644 --- a/packages/nocodb/src/lib/meta/api/columnApis.ts +++ b/packages/nocodb/src/lib/meta/api/columnApis.ts @@ -652,8 +652,21 @@ export async function columnUpdate(req: Request, res: Response) { const table = await Model.getWithInfo({ id: column.fk_model_id, }); + const base = await Base.get(table.base_id); + const dbDriver = NcConnectionMgrv2.get(base); + + const sqlClientType = dbDriver.clientType(); + + const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); + + if (req.body.column_name.length > mxColumnLength) { + NcError.badRequest( + `Column name ${req.body.column_name} exceeds ${mxColumnLength} characters` + ); + } + if ( !isVirtualCol(req.body) && !(await Column.checkTitleAvailable({ From 055264a96efd340673a2acea1778f198edd158ff Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 16:54:08 +0800 Subject: [PATCH 8/9] refactor(nocodb): use sqlClient --- packages/nocodb/src/lib/meta/api/columnApis.ts | 4 ++-- packages/nocodb/src/lib/meta/api/tableApis.ts | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/nocodb/src/lib/meta/api/columnApis.ts b/packages/nocodb/src/lib/meta/api/columnApis.ts index d2cf932860..30751c9c48 100644 --- a/packages/nocodb/src/lib/meta/api/columnApis.ts +++ b/packages/nocodb/src/lib/meta/api/columnApis.ts @@ -655,9 +655,9 @@ export async function columnUpdate(req: Request, res: Response) { const base = await Base.get(table.base_id); - const dbDriver = NcConnectionMgrv2.get(base); + const sqlClient = await NcConnectionMgrv2.getSqlClient(base); - const sqlClientType = dbDriver.clientType(); + const sqlClientType = sqlClient.knex.clientType(); const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); diff --git a/packages/nocodb/src/lib/meta/api/tableApis.ts b/packages/nocodb/src/lib/meta/api/tableApis.ts index 7fe1f5e905..b47fa5e5e6 100644 --- a/packages/nocodb/src/lib/meta/api/tableApis.ts +++ b/packages/nocodb/src/lib/meta/api/tableApis.ts @@ -151,12 +151,8 @@ export async function tableCreate(req: Request, res) { const sqlClient = await NcConnectionMgrv2.getSqlClient(base); - const dbDriver = NcConnectionMgrv2.get(base); - - const sqlClientType = dbDriver.clientType(); - let tableNameLengthLimit = 255; - + const sqlClientType = sqlClient.knex.clientType(); if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { tableNameLengthLimit = 64; } else if (sqlClientType === 'pg') { @@ -313,7 +309,7 @@ export async function tableUpdate(req: Request, res) { const sqlClient = await NcConnectionMgrv2.getSqlClient(base); let tableNameLengthLimit = 255; - const sqlClientType = sqlClient.clientType; + const sqlClientType = sqlClient.knex.clientType(); if (sqlClientType === 'mysql2' || sqlClientType === 'mysql') { tableNameLengthLimit = 64; } else if (sqlClientType === 'pg') { From 5082c873199a89ed6bebecd0587157c7b79537b9 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 17 Feb 2023 18:11:02 +0800 Subject: [PATCH 9/9] fix(nocodb): cover title case for validation --- packages/nocodb/src/lib/meta/api/columnApis.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/nocodb/src/lib/meta/api/columnApis.ts b/packages/nocodb/src/lib/meta/api/columnApis.ts index 30751c9c48..ab36b0103c 100644 --- a/packages/nocodb/src/lib/meta/api/columnApis.ts +++ b/packages/nocodb/src/lib/meta/api/columnApis.ts @@ -69,16 +69,20 @@ export async function columnAdd( const project = await base.getProject(); - const dbDriver = NcConnectionMgrv2.get(base); + if (req.body.title || req.body.column_name) { + const dbDriver = NcConnectionMgrv2.get(base); - const sqlClientType = dbDriver.clientType(); + const sqlClientType = dbDriver.clientType(); - const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); + const mxColumnLength = Column.getMaxColumnNameLength(sqlClientType); - if (req.body.column_name.length > mxColumnLength) { - NcError.badRequest( - `Column name ${req.body.column_name} exceeds ${mxColumnLength} characters` - ); + if ((req.body.title || req.body.column_name).length > mxColumnLength) { + NcError.badRequest( + `Column name ${ + req.body.title || req.body.column_name + } exceeds ${mxColumnLength} characters` + ); + } } if (