Browse Source

Merge pull request #9683 from nocodb/nc-fix/9679-pk-with-underscore

fix: Handle primary key value with 3 or more consecutive underscore
pull/9709/head
Pranav C 2 months ago committed by GitHub
parent
commit
030a213610
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      packages/nc-gui/composables/useData.ts
  2. 5
      packages/nc-gui/composables/useKanbanViewStore.ts
  3. 12
      packages/nc-gui/composables/useLTARStore.ts
  4. 12
      packages/nc-gui/utils/dataUtils.ts
  5. 28
      packages/nocodb/src/db/BaseModelSqlv2.ts
  6. 33
      packages/nocodb/src/helpers/catchError.ts
  7. 6
      packages/nocodb/src/services/data-table.service.ts

5
packages/nc-gui/composables/useData.ts

@ -550,10 +550,7 @@ export function useData(args: {
try {
const row = formattedData.value[rowIndex]
if (!row.rowMeta.new) {
const id = meta?.value?.columns
?.filter((c) => c.pk)
.map((c) => row.row[c.title!])
.join('___')
const id = extractPkFromRow(row.row, meta?.value?.columns)
const fullRecord = await $api.dbTableRow.read(
NOCO,

5
packages/nc-gui/composables/useKanbanViewStore.ts

@ -659,10 +659,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
}
if (!row.rowMeta.new) {
const id = (meta?.value?.columns as ColumnType[])
?.filter((c) => c.pk)
.map((c) => row.row[c.title!])
.join('___')
const id = extractPkFromRow(row.row, meta?.value?.columns)
const deleted = await deleteRowById(id as string)
if (!deleted) {

12
packages/nc-gui/composables/useLTARStore.ts

@ -88,18 +88,10 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
return metas.value?.[colOptions.value?.fk_related_model_id as string]
})
const rowId = computed(() =>
meta.value.columns
.filter((c: Required<ColumnType>) => c.pk)
.map((c: Required<ColumnType>) => row?.value?.row?.[c.title])
.join('___'),
)
const rowId = computed(() => extractPkFromRow(row.value.row, meta.value.columns))
const getRelatedTableRowId = (row: Record<string, any>) => {
return relatedTableMeta.value?.columns
?.filter((c) => c.pk)
.map((c) => row?.[c.title as string] ?? row?.[c.id as string])
.join('___')
return extractPkFromRow(row, relatedTableMeta.value?.columns)
}
// actions

12
packages/nc-gui/utils/dataUtils.ts

@ -26,11 +26,13 @@ export const isValidValue = (val: unknown) => {
export const extractPkFromRow = (row: Record<string, any>, columns: ColumnType[]) => {
if (!row || !columns) return null
const pkColumns = columns.filter((c) => c.pk)
if (pkColumns.every((c) => row?.[c.title as string] === null || row?.[c.title as string] === undefined)) return null
return pkColumns.map((c) => row?.[c.title as string]).join('___')
const pkCols = columns.filter((c: Required<ColumnType>) => c.pk)
// if multiple pk columns, join them with ___ and escape _ in id values with \_ to avoid conflicts
if (pkCols.length > 1) {
return pkCols.map((c: Required<ColumnType>) => row?.[c.title]?.toString?.().replaceAll('_', '\\_') ?? null).join('___')
} else if (pkCols.length) {
return row?.[pkCols[0].title] ?? null
}
}
export const rowPkData = (row: Record<string, any>, columns: ColumnType[]) => {

28
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -6517,7 +6517,11 @@ class BaseModelSqlv2 {
for (const pk of this.model.primaryKeys) {
pkValues[pk.title] = data[pk.title] ?? data[pk.column_name];
}
return asString ? Object.values(pkValues).join('___') : pkValues;
return asString
? Object.values(pkValues)
.map((val) => val?.toString?.().replaceAll('_', '\\_'))
.join('___')
: pkValues;
} else if (this.model.primaryKey) {
return (
data[this.model.primaryKey.title] ??
@ -10170,7 +10174,16 @@ export function _wherePk(
return where;
}
const ids = Array.isArray(id) ? id : (id + '').split('___');
let ids = id;
if (Array.isArray(id)) {
ids = id;
} else if (primaryKeys.length === 1) {
ids = [id];
} else {
ids = (id + '').split('___').map((val) => val.replaceAll('\\_', '_'));
}
for (let i = 0; i < primaryKeys.length; ++i) {
if (primaryKeys[i].dt === 'bytea') {
// if column is bytea, then we need to encode the id to hex based on format
@ -10216,7 +10229,16 @@ export function getCompositePkValue(primaryKeys: Column[], row) {
if (typeof row !== 'object') return row;
return primaryKeys.map((c) => row[c.title] ?? row[c.column_name]).join('___');
if (primaryKeys.length > 1) {
return primaryKeys.map((c) =>
(row[c.title] ?? row[c.column_name])?.toString?.().replaceAll('_', '\\_'),
).join('___');
}
return (
primaryKeys[0] &&
(row[primaryKeys[0].title] ?? row[primaryKeys[0].column_name])
);
}
export function haveFormulaColumn(columns: Column[]) {

33
packages/nocodb/src/helpers/catchError.ts

@ -795,22 +795,43 @@ export class NcError {
id: string | string[] | Record<string, string> | Record<string, string>[],
args?: NcErrorArgs,
) {
let formatedId: string | string[] = '';
if (!id) {
id = 'unknown';
formatedId = 'unknown';
} else if (typeof id === 'string') {
id = [id];
formatedId = [id];
} else if (Array.isArray(id)) {
if (id.every((i) => typeof i === 'string')) {
id = id as string[];
formatedId = id as string[];
} else {
id = id.map((i) => Object.values(i).join('___'));
formatedId = id.map((val) => {
const idsArr = Object.values(val);
if (idsArr.length > 1) {
return idsArr
.map((idVal) => idVal?.toString?.().replaceAll('_', '\\_'))
.join('___');
} else if (idsArr.length) {
return idsArr[0] as any;
} else {
return 'unknown';
}
});
}
} else {
id = Object.values(id).join('___');
const idsArr = Object.values(id);
if (idsArr.length > 1) {
formatedId = idsArr
.map((idVal) => idVal?.toString?.().replaceAll('_', '\\_'))
.join('___');
} else if (idsArr.length) {
formatedId = idsArr[0] as any;
} else {
formatedId = 'unknown';
}
}
throw new NcBaseErrorv2(NcErrorType.RECORD_NOT_FOUND, {
params: id,
params: formatedId,
...args,
});
}

6
packages/nocodb/src/services/data-table.service.ts

@ -315,7 +315,11 @@ export class DataTableService {
// if composite primary key then join the values with ___
else
pk = model.primaryKeys
.map((pk) => row[pk.title] ?? row[pk.column_name])
.map((pk) =>
(row[pk.title] ?? row[pk.column_name])
?.toString?.()
?.replaceAll('_', '\\_'),
)
.join('___');
// if duplicate then throw error
if (keys.has(pk)) {

Loading…
Cancel
Save