diff --git a/packages/nc-gui/components/smartsheet/column/RollupOptions.vue b/packages/nc-gui/components/smartsheet/column/RollupOptions.vue
index 1fbe5b9e93..e52ad0da7f 100644
--- a/packages/nc-gui/components/smartsheet/column/RollupOptions.vue
+++ b/packages/nc-gui/components/smartsheet/column/RollupOptions.vue
@@ -1,4 +1,5 @@
@@ -80,7 +96,7 @@ const columns = $computed(() => {
diff --git a/packages/nc-gui/components/smartsheet/header/Menu.vue b/packages/nc-gui/components/smartsheet/header/Menu.vue
index a619cd5caa..3a98197be4 100644
--- a/packages/nc-gui/components/smartsheet/header/Menu.vue
+++ b/packages/nc-gui/components/smartsheet/header/Menu.vue
@@ -285,8 +285,8 @@ const hideField = async () => {
-
- {{ $t('activity.setPrimary') }}
+
+ {{ $t('activity.setDisplay') }}
diff --git a/packages/nc-gui/lang/ar.json b/packages/nc-gui/lang/ar.json
index 57aff2b0ec..e696c04abd 100644
--- a/packages/nc-gui/lang/ar.json
+++ b/packages/nc-gui/lang/ar.json
@@ -380,7 +380,6 @@
"renameTable": "إعادة تسمية الجدول",
"deleteTable": "حذف الجدول",
"addField": "إضافة حقل جديد إلى هذا الجدول",
- "setPrimary": "تعيين كقيمة أساسية",
"addRow": "إضافة صف جديد",
"saveRow": "حفظ الصف",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/bn_IN.json b/packages/nc-gui/lang/bn_IN.json
index 9bf9698739..64f499703f 100644
--- a/packages/nc-gui/lang/bn_IN.json
+++ b/packages/nc-gui/lang/bn_IN.json
@@ -380,7 +380,6 @@
"renameTable": "টেবিল নাম পরিবর্তন",
"deleteTable": "टेबल मिटाये",
"addField": "এই টেবিলে নতুন ক্ষেত্র যুক্ত করুন",
- "setPrimary": "প্রাথমিক মান হিসাবে সেট করুন",
"addRow": "নতুন সারি যুক্ত করুন",
"saveRow": "সারি সংরক্ষণ করুন",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/cs.json b/packages/nc-gui/lang/cs.json
index 5650c189d1..a1b1bf8b78 100644
--- a/packages/nc-gui/lang/cs.json
+++ b/packages/nc-gui/lang/cs.json
@@ -380,7 +380,6 @@
"renameTable": "Přejmenování tabulky",
"deleteTable": "Tabulka Odstranit",
"addField": "Přidání nového pole do této tabulky",
- "setPrimary": "Nastavit jako primární hodnotu",
"addRow": "Přidat nový řádek",
"saveRow": "Uložit řádek",
"saveAndExit": "Uložit a odejít",
diff --git a/packages/nc-gui/lang/da.json b/packages/nc-gui/lang/da.json
index 5bd56eb7d3..a3bfd15136 100644
--- a/packages/nc-gui/lang/da.json
+++ b/packages/nc-gui/lang/da.json
@@ -380,7 +380,6 @@
"renameTable": "Bord omdøb",
"deleteTable": "TABEL DELETE.",
"addField": "Tilføj nyt felt til denne tabel",
- "setPrimary": "Indstil som primær værdi",
"addRow": "Tilføj ny række",
"saveRow": "Gem ro",
"saveAndExit": "Gem og afslutning",
diff --git a/packages/nc-gui/lang/de.json b/packages/nc-gui/lang/de.json
index 5bdf4c7962..5824629bbd 100644
--- a/packages/nc-gui/lang/de.json
+++ b/packages/nc-gui/lang/de.json
@@ -380,7 +380,6 @@
"renameTable": "Tabelle umbenennen",
"deleteTable": "Tabelle löschen",
"addField": "Neues Feld zu dieser Tabelle hinzufügen",
- "setPrimary": "Als Primärwert festlegen",
"addRow": "Neue Zeile hinzufügen",
"saveRow": "Zeile speichern",
"saveAndExit": "Speichern & Verlassen",
diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json
index 93b8c01162..3de8197b80 100644
--- a/packages/nc-gui/lang/en.json
+++ b/packages/nc-gui/lang/en.json
@@ -380,7 +380,7 @@
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"addField": "Add new field to this table",
- "setPrimary": "Set as Primary value",
+ "setDisplay": "Set as Display value",
"addRow": "Add new row",
"saveRow": "Save row",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/es.json b/packages/nc-gui/lang/es.json
index a78cb51e94..754016be56 100644
--- a/packages/nc-gui/lang/es.json
+++ b/packages/nc-gui/lang/es.json
@@ -380,7 +380,6 @@
"renameTable": "Cambiar el nombre de la tabla",
"deleteTable": "Borrar tabla",
"addField": "Añadir nuevo campo a esta tabla",
- "setPrimary": "Establecido como clave primaria",
"addRow": "Añadir nueva fila",
"saveRow": "Grabar la fila",
"saveAndExit": "Guardar y salir",
diff --git a/packages/nc-gui/lang/eu.json b/packages/nc-gui/lang/eu.json
index 7aa588922c..bc70e36e2d 100644
--- a/packages/nc-gui/lang/eu.json
+++ b/packages/nc-gui/lang/eu.json
@@ -380,7 +380,6 @@
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"addField": "Add new field to this table",
- "setPrimary": "Set as Primary value",
"addRow": "Add new row",
"saveRow": "Save row",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/fa.json b/packages/nc-gui/lang/fa.json
index 425d6caeab..04edb17a07 100644
--- a/packages/nc-gui/lang/fa.json
+++ b/packages/nc-gui/lang/fa.json
@@ -380,7 +380,6 @@
"renameTable": "تغییر نام جدول",
"deleteTable": "حذف جدول",
"addField": "اضافه کردن فیلد جدید به این جدول",
- "setPrimary": "تنظیم به عنوان مقدار اولیه",
"addRow": "اضافه کردن ردیف جدید",
"saveRow": "دخیره ردیف",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/fi.json b/packages/nc-gui/lang/fi.json
index a8de5ebbcd..13db0b3a1a 100644
--- a/packages/nc-gui/lang/fi.json
+++ b/packages/nc-gui/lang/fi.json
@@ -380,7 +380,6 @@
"renameTable": "Taulukko uudelleen",
"deleteTable": "Taulukko poistaa",
"addField": "Lisää uusi kenttä tähän taulukkoon",
- "setPrimary": "Aseta ensisijainen arvo",
"addRow": "Lisää uusi rivi",
"saveRow": "Tallenna rivi",
"saveAndExit": "Tallenna & poistu",
diff --git a/packages/nc-gui/lang/fr.json b/packages/nc-gui/lang/fr.json
index cd2b520e72..9b4607bc6e 100644
--- a/packages/nc-gui/lang/fr.json
+++ b/packages/nc-gui/lang/fr.json
@@ -380,7 +380,6 @@
"renameTable": "Renommer le tableau",
"deleteTable": "Supprimer le tableau",
"addField": "Ajouter un nouveau champ à ce tableau",
- "setPrimary": "Définir comme valeur primaire",
"addRow": "Ajouter une nouvelle ligne",
"saveRow": "Enregistrer la ligne",
"saveAndExit": "Enregistrer et quitter",
diff --git a/packages/nc-gui/lang/he.json b/packages/nc-gui/lang/he.json
index edc1fc67b3..0796b06903 100644
--- a/packages/nc-gui/lang/he.json
+++ b/packages/nc-gui/lang/he.json
@@ -380,7 +380,6 @@
"renameTable": "שולחן שינוי שם",
"deleteTable": "טבלה מחיקה",
"addField": "הוסף שדה חדש לטבלה זו",
- "setPrimary": "להגדיר כערך ראשי",
"addRow": "הוסף שורה חדשה",
"saveRow": "שמור שורה",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/hi.json b/packages/nc-gui/lang/hi.json
index 12190e9571..76e74135c3 100644
--- a/packages/nc-gui/lang/hi.json
+++ b/packages/nc-gui/lang/hi.json
@@ -380,7 +380,6 @@
"renameTable": "तालिका का नाम",
"deleteTable": "टेबल मिटाये",
"addField": "इस तालिका में नया फ़ील्ड जोड़ें",
- "setPrimary": "प्राथमिक मूल्य के रूप में सेट करें",
"addRow": "नई पंक्ति जोड़ें",
"saveRow": "पंक्ति सहेजें",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/hr.json b/packages/nc-gui/lang/hr.json
index d3681c9f6e..450d411657 100644
--- a/packages/nc-gui/lang/hr.json
+++ b/packages/nc-gui/lang/hr.json
@@ -380,7 +380,6 @@
"renameTable": "Preimenovati stolom",
"deleteTable": "Obriši tablicu",
"addField": "Dodajte novo polje na ovu tablicu",
- "setPrimary": "Postavite kao primarnu vrijednost",
"addRow": "Dodaj novi red",
"saveRow": "Spremanje retka",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/id.json b/packages/nc-gui/lang/id.json
index 19ae2886b7..8c2d9141c6 100644
--- a/packages/nc-gui/lang/id.json
+++ b/packages/nc-gui/lang/id.json
@@ -380,7 +380,6 @@
"renameTable": "Ganti nama meja",
"deleteTable": "Table Delete.",
"addField": "Tambahkan bidang baru ke tabel ini",
- "setPrimary": "Tetapkan sebagai nilai utama",
"addRow": "Tambahkan baris baru",
"saveRow": "Hemat Baris",
"saveAndExit": "Simpan & Keluar",
diff --git a/packages/nc-gui/lang/it.json b/packages/nc-gui/lang/it.json
index de5eb9c337..d158168071 100644
--- a/packages/nc-gui/lang/it.json
+++ b/packages/nc-gui/lang/it.json
@@ -380,7 +380,6 @@
"renameTable": "Rinomina tabella",
"deleteTable": "Elimina tabella",
"addField": "Aggiungi un nuovo campo a questa tabella",
- "setPrimary": "Impostare come valore primario",
"addRow": "Aggiungi nuova riga",
"saveRow": "Salva riga",
"saveAndExit": "Salvare e uscire",
diff --git a/packages/nc-gui/lang/ja.json b/packages/nc-gui/lang/ja.json
index a6db39ebc3..f2cdde17ac 100644
--- a/packages/nc-gui/lang/ja.json
+++ b/packages/nc-gui/lang/ja.json
@@ -380,7 +380,6 @@
"renameTable": "テーブル名の変更",
"deleteTable": "テーブルを削除",
"addField": "新しいフィールドを追加",
- "setPrimary": "プライマリ値として設定",
"addRow": "行を追加",
"saveRow": "行を保存",
"saveAndExit": "保存して終了",
diff --git a/packages/nc-gui/lang/ko.json b/packages/nc-gui/lang/ko.json
index 388a074997..39b91f6f37 100644
--- a/packages/nc-gui/lang/ko.json
+++ b/packages/nc-gui/lang/ko.json
@@ -380,7 +380,6 @@
"renameTable": "테이블 이름 바꾸기",
"deleteTable": "테이블 삭제",
"addField": "테이블에 새 필드 추가",
- "setPrimary": "Primary value로 설정",
"addRow": "행 추가",
"saveRow": "행 저장",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/lv.json b/packages/nc-gui/lang/lv.json
index a164c883d9..70b9722285 100644
--- a/packages/nc-gui/lang/lv.json
+++ b/packages/nc-gui/lang/lv.json
@@ -380,7 +380,6 @@
"renameTable": "Tabulas pārdēvēšana",
"deleteTable": "Tabulas dzēšana",
"addField": "Jauna lauka pievienošana",
- "setPrimary": "Uzstādīt kā primāro atslēgu",
"addRow": "Pievienot ierakstu",
"saveRow": "Saglabāt ierakstu",
"saveAndExit": "Saglabāt un iziet",
diff --git a/packages/nc-gui/lang/nl.json b/packages/nc-gui/lang/nl.json
index 600b2f936a..f1c0bb68f2 100644
--- a/packages/nc-gui/lang/nl.json
+++ b/packages/nc-gui/lang/nl.json
@@ -380,7 +380,6 @@
"renameTable": "Tabel hernoemen",
"deleteTable": "Tabel verwijderen",
"addField": "Voeg nieuw veld toe aan deze tabel",
- "setPrimary": "Instellen als primaire waarde",
"addRow": "Nieuwe rij toevoegen",
"saveRow": "Sla rij op",
"saveAndExit": "Opslaan en afsluiten",
diff --git a/packages/nc-gui/lang/no.json b/packages/nc-gui/lang/no.json
index 76c09699ba..c7af1b9fac 100644
--- a/packages/nc-gui/lang/no.json
+++ b/packages/nc-gui/lang/no.json
@@ -380,7 +380,6 @@
"renameTable": "Tabell omdøpe",
"deleteTable": "Bordet slett",
"addField": "Legg til nytt felt i denne tabellen",
- "setPrimary": "Sett som primærverdi",
"addRow": "Legg til ny rad",
"saveRow": "Lagre rad",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/pl.json b/packages/nc-gui/lang/pl.json
index f44c17ac62..83df241b48 100644
--- a/packages/nc-gui/lang/pl.json
+++ b/packages/nc-gui/lang/pl.json
@@ -380,7 +380,6 @@
"renameTable": "Zmień nazwę tabeli.",
"deleteTable": "Usuń tabelę",
"addField": "Dodaj nowe pole do tej tabeli",
- "setPrimary": "Ustaw jako wartość podstawowa",
"addRow": "Dodaj nowy rząd",
"saveRow": "Zapisz wiersz",
"saveAndExit": "Zapisz i wyjdź",
diff --git a/packages/nc-gui/lang/pt.json b/packages/nc-gui/lang/pt.json
index 5bc34baa81..e5ca35262b 100644
--- a/packages/nc-gui/lang/pt.json
+++ b/packages/nc-gui/lang/pt.json
@@ -380,7 +380,6 @@
"renameTable": "Tabela Renomear",
"deleteTable": "Tabela Delete.",
"addField": "Adicionar novo campo a esta tabela",
- "setPrimary": "Definido como valor primário",
"addRow": "Adicionar nova linha",
"saveRow": "Salvar linha",
"saveAndExit": "Salvar & Sair",
diff --git a/packages/nc-gui/lang/pt_BR.json b/packages/nc-gui/lang/pt_BR.json
index 4c9443db22..1966cadb71 100644
--- a/packages/nc-gui/lang/pt_BR.json
+++ b/packages/nc-gui/lang/pt_BR.json
@@ -380,7 +380,6 @@
"renameTable": "Tabela Renomear",
"deleteTable": "Tabela Delete.",
"addField": "Adicionar novo campo a esta tabela",
- "setPrimary": "Definido como valor primário",
"addRow": "Adicionar nova linha",
"saveRow": "Salvar linha",
"saveAndExit": "Salvar & Sair",
diff --git a/packages/nc-gui/lang/ru.json b/packages/nc-gui/lang/ru.json
index 50c8309d9e..86aeec735d 100644
--- a/packages/nc-gui/lang/ru.json
+++ b/packages/nc-gui/lang/ru.json
@@ -380,7 +380,6 @@
"renameTable": "Переименовать таблицу",
"deleteTable": "Удалить таблицу",
"addField": "Добавить новое поле в эту таблицу",
- "setPrimary": "Установить в качестве основного значения",
"addRow": "Добавить новую строку",
"saveRow": "Сохранить строку",
"saveAndExit": "Сохранить и выйти",
diff --git a/packages/nc-gui/lang/sk.json b/packages/nc-gui/lang/sk.json
index 421c42281d..3b31f34bb4 100644
--- a/packages/nc-gui/lang/sk.json
+++ b/packages/nc-gui/lang/sk.json
@@ -380,7 +380,6 @@
"renameTable": "Premenovanie tabuľky",
"deleteTable": "Tabuľka Vymazať",
"addField": "Pridanie nového poľa do tejto tabuľky",
- "setPrimary": "Nastaviť ako primárnu hodnotu",
"addRow": "Pridanie nového riadku",
"saveRow": "Uložiť riadok",
"saveAndExit": "Uložiť a ukončiť",
diff --git a/packages/nc-gui/lang/sl.json b/packages/nc-gui/lang/sl.json
index 59b0112372..e93d48f62c 100644
--- a/packages/nc-gui/lang/sl.json
+++ b/packages/nc-gui/lang/sl.json
@@ -380,7 +380,6 @@
"renameTable": "Preimenuj tabele",
"deleteTable": "Tabela Delete.",
"addField": "V to tabelo dodajte novo polje",
- "setPrimary": "Kot primarna vrednost",
"addRow": "Dodaj novo vrstico",
"saveRow": "Shrani vrstico",
"saveAndExit": "Shranjevanje in izhod",
diff --git a/packages/nc-gui/lang/sv.json b/packages/nc-gui/lang/sv.json
index 4afc5e12f2..9ed31dde81 100644
--- a/packages/nc-gui/lang/sv.json
+++ b/packages/nc-gui/lang/sv.json
@@ -380,7 +380,6 @@
"renameTable": "Bordsbyte",
"deleteTable": "Bord radera",
"addField": "Lägg till nytt fält till den här tabellen",
- "setPrimary": "Ange som primärt värde",
"addRow": "Lägg till ny rad",
"saveRow": "Spara rad",
"saveAndExit": "Spara och avsluta",
diff --git a/packages/nc-gui/lang/th.json b/packages/nc-gui/lang/th.json
index 6f551306ad..edb45ae050 100644
--- a/packages/nc-gui/lang/th.json
+++ b/packages/nc-gui/lang/th.json
@@ -380,7 +380,6 @@
"renameTable": "ตารางเปลี่ยนชื่อ",
"deleteTable": "ลบตาราง",
"addField": "เพิ่มฟิลด์ใหม่ลงในตารางนี้",
- "setPrimary": "ตั้งค่าเป็นค่าปฐมภูมิ",
"addRow": "เพิ่มแถวใหม่",
"saveRow": "บันทึกแถว",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/tr.json b/packages/nc-gui/lang/tr.json
index b8b6b217af..6e6a1c0cb2 100644
--- a/packages/nc-gui/lang/tr.json
+++ b/packages/nc-gui/lang/tr.json
@@ -380,7 +380,6 @@
"renameTable": "Tabloyu Yeniden Adlandır",
"deleteTable": "Tabloyu Sil",
"addField": "Tabloya yeni alan ekle",
- "setPrimary": "Birincil değer yap",
"addRow": "Yeni satır ekle",
"saveRow": "Satırı kaydet",
"saveAndExit": "Kaydet ve Çık",
diff --git a/packages/nc-gui/lang/uk.json b/packages/nc-gui/lang/uk.json
index b2096345fa..e3f6329059 100644
--- a/packages/nc-gui/lang/uk.json
+++ b/packages/nc-gui/lang/uk.json
@@ -380,7 +380,6 @@
"renameTable": "Перейменувати таблицю",
"deleteTable": "Видалити таблицю",
"addField": "Додати нове поле до цієї таблиці",
- "setPrimary": "Встановити як основне значення",
"addRow": "Додати новий рядок",
"saveRow": "Зберегти рядок",
"saveAndExit": "Зберегти та вийти",
diff --git a/packages/nc-gui/lang/vi.json b/packages/nc-gui/lang/vi.json
index cae9ebdec2..35157784a5 100644
--- a/packages/nc-gui/lang/vi.json
+++ b/packages/nc-gui/lang/vi.json
@@ -380,7 +380,6 @@
"renameTable": "Đổi tên bảng.",
"deleteTable": "Bảng xóa",
"addField": "Thêm trường mới vào bảng này",
- "setPrimary": "Đặt dưới dạng giá trị chính",
"addRow": "Thêm hàng mới",
"saveRow": "Lưu hàng.",
"saveAndExit": "Save & Exit",
diff --git a/packages/nc-gui/lang/zh-Hans.json b/packages/nc-gui/lang/zh-Hans.json
index 1f68794466..296a860a17 100644
--- a/packages/nc-gui/lang/zh-Hans.json
+++ b/packages/nc-gui/lang/zh-Hans.json
@@ -380,7 +380,6 @@
"renameTable": "重命名表格",
"deleteTable": "删除表格",
"addField": "添加新字段",
- "setPrimary": "设置为主要值",
"addRow": "添加新行",
"saveRow": "保存行",
"saveAndExit": "保存并退出",
diff --git a/packages/nc-gui/lang/zh-Hant.json b/packages/nc-gui/lang/zh-Hant.json
index c0e5e341e1..a57c3d6361 100644
--- a/packages/nc-gui/lang/zh-Hant.json
+++ b/packages/nc-gui/lang/zh-Hant.json
@@ -380,7 +380,6 @@
"renameTable": "表重命名",
"deleteTable": "表刪除",
"addField": "將新字段添加到此表",
- "setPrimary": "設置為主要值",
"addRow": "新增行",
"saveRow": "儲存行",
"saveAndExit": "儲存並結束",
diff --git a/packages/nocodb/src/lib/meta/api/columnApis.ts b/packages/nocodb/src/lib/meta/api/columnApis.ts
index 69b9e1f962..0617b01e48 100644
--- a/packages/nocodb/src/lib/meta/api/columnApis.ts
+++ b/packages/nocodb/src/lib/meta/api/columnApis.ts
@@ -6,7 +6,6 @@ import Column from '../../models/Column';
import { Tele } from 'nc-help';
import validateParams from '../helpers/validateParams';
-import { customAlphabet } from 'nanoid';
import LinkToAnotherRecordColumn from '../../models/LinkToAnotherRecordColumn';
import {
getUniqueColumnAliasName,
@@ -19,9 +18,7 @@ import {
isVirtualCol,
LinkToAnotherColumnReqType,
LinkToAnotherRecordType,
- LookupColumnReqType,
RelationTypes,
- RollupColumnReqType,
substituteColumnAliasWithIdInFormula,
substituteColumnIdWithAliasInFormula,
TableType,
@@ -41,8 +38,14 @@ import FormulaColumn from '../../models/FormulaColumn';
import KanbanView from '../../models/KanbanView';
import { MetaTable } from '../../utils/globals';
import formulaQueryBuilderv2 from '../../db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2';
-
-const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10);
+import {
+ createHmAndBtColumn,
+ generateFkName,
+ randomID,
+ validateLookupPayload,
+ validateRequiredField,
+ validateRollupPayload,
+} from './helpers';
export enum Altered {
NEW_COLUMN = 1,
@@ -50,73 +53,6 @@ export enum Altered {
UPDATE_COLUMN = 8,
}
-// generate unique foreign key constraint name for foreign key
-const generateFkName = (parent: TableType, child: TableType) => {
- // generate a unique constraint name by taking first 10 chars of parent and child table name (by replacing all non word chars with _)
- // and appending a random string of 15 chars maximum length.
- // In database constraint name can be upto 64 chars and here we are generating a name of maximum 40 chars
- const constraintName = `fk_${parent.table_name
- .replace(/\W+/g, '_')
- .slice(0, 10)}_${child.table_name
- .replace(/\W+/g, '_')
- .slice(0, 10)}_${randomID(15)}`;
- return constraintName;
-};
-
-async function createHmAndBtColumn(
- child: Model,
- parent: Model,
- childColumn: Column,
- type?: RelationTypes,
- alias?: string,
- fkColName?: string,
- virtual = false,
- isSystemCol = false
-) {
- // save bt column
- {
- const title = getUniqueColumnAliasName(
- await child.getColumns(),
- type === 'bt' ? alias : `${parent.title}`
- );
- await Column.insert({
- title,
-
- fk_model_id: child.id,
- // ref_db_alias
- uidt: UITypes.LinkToAnotherRecord,
- type: 'bt',
- // db_type:
-
- fk_child_column_id: childColumn.id,
- fk_parent_column_id: parent.primaryKey.id,
- fk_related_model_id: parent.id,
- virtual,
- system: isSystemCol,
- fk_index_name: fkColName,
- });
- }
- // save hm column
- {
- const title = getUniqueColumnAliasName(
- await parent.getColumns(),
- type === 'hm' ? alias : `${child.title} List`
- );
- await Column.insert({
- title,
- fk_model_id: parent.id,
- uidt: UITypes.LinkToAnotherRecord,
- type: 'hm',
- fk_child_column_id: childColumn.id,
- fk_parent_column_id: parent.primaryKey.id,
- fk_related_model_id: child.id,
- virtual,
- system: isSystemCol,
- fk_index_name: fkColName,
- });
- }
-}
-
export async function columnGet(req: Request, res: Response) {
res.json(await Column.get({ colId: req.params.columnId }));
}
@@ -153,49 +89,7 @@ export async function columnAdd(
switch (colBody.uidt) {
case UITypes.Rollup:
{
- validateParams(
- [
- 'title',
- 'fk_relation_column_id',
- 'fk_rollup_column_id',
- 'rollup_function',
- ],
- req.body
- );
-
- const relation = await (
- await Column.get({
- colId: (req.body as RollupColumnReqType).fk_relation_column_id,
- })
- ).getColOptions();
-
- if (!relation) {
- throw new Error('Relation column not found');
- }
-
- let relatedColumn: Column;
- switch (relation.type) {
- case 'hm':
- relatedColumn = await Column.get({
- colId: relation.fk_child_column_id,
- });
- break;
- case 'mm':
- case 'bt':
- relatedColumn = await Column.get({
- colId: relation.fk_parent_column_id,
- });
- break;
- }
-
- const relatedTable = await relatedColumn.getModel();
- if (
- !(await relatedTable.getColumns()).find(
- (c) =>
- c.id === (req.body as RollupColumnReqType).fk_rollup_column_id
- )
- )
- throw new Error('Rollup column not found in related table');
+ await validateRollupPayload(req.body);
await Column.insert({
...colBody,
@@ -205,44 +99,7 @@ export async function columnAdd(
break;
case UITypes.Lookup:
{
- validateParams(
- ['title', 'fk_relation_column_id', 'fk_lookup_column_id'],
- req.body
- );
-
- const relation = await (
- await Column.get({
- colId: (req.body as LookupColumnReqType).fk_relation_column_id,
- })
- ).getColOptions();
-
- if (!relation) {
- throw new Error('Relation column not found');
- }
-
- let relatedColumn: Column;
- switch (relation.type) {
- case 'hm':
- relatedColumn = await Column.get({
- colId: relation.fk_child_column_id,
- });
- break;
- case 'mm':
- case 'bt':
- relatedColumn = await Column.get({
- colId: relation.fk_parent_column_id,
- });
- break;
- }
-
- const relatedTable = await relatedColumn.getModel();
- if (
- !(await relatedTable.getColumns()).find(
- (c) =>
- c.id === (req.body as LookupColumnReqType).fk_lookup_column_id
- )
- )
- throw new Error('Lookup column not found in related table');
+ await validateLookupPayload(req.body);
await Column.insert({
...colBody,
@@ -252,7 +109,6 @@ export async function columnAdd(
break;
case UITypes.LinkToAnotherRecord:
- // case UITypes.ForeignKey:
{
validateParams(['parentId', 'childId', 'type'], req.body);
@@ -753,6 +609,29 @@ export async function columnSetAsPrimary(req: Request, res: Response) {
res.json(await Model.updatePrimaryColumn(column.fk_model_id, column.id));
}
+async function updateRollupOrLookup(colBody: any, column: Column) {
+ if (
+ UITypes.Lookup === column.uidt &&
+ validateRequiredField(colBody, [
+ 'fk_lookup_column_id',
+ 'fk_relation_column_id',
+ ])
+ ) {
+ await validateLookupPayload(colBody, column.id);
+ await Column.update(column.id, colBody);
+ } else if (
+ UITypes.Rollup === column.uidt &&
+ validateRequiredField(colBody, [
+ 'fk_relation_column_id',
+ 'fk_rollup_column_id',
+ 'rollup_function',
+ ])
+ ) {
+ await validateRollupPayload(colBody);
+ await Column.update(column.id, colBody);
+ }
+}
+
export async function columnUpdate(req: Request, res: Response) {
const column = await Column.get({ colId: req.params.columnId });
@@ -824,6 +703,7 @@ export async function columnUpdate(req: Request, res: Response) {
title: colBody.title,
});
}
+ await updateRollupOrLookup(colBody, column);
} else {
NcError.notImplemented(
`Updating ${colBody.uidt} => ${colBody.uidt} is not implemented`
diff --git a/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts b/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts
new file mode 100644
index 0000000000..bc331105ba
--- /dev/null
+++ b/packages/nocodb/src/lib/meta/api/helpers/columnHelpers.ts
@@ -0,0 +1,209 @@
+import { customAlphabet } from 'nanoid';
+import {
+ ColumnReqType,
+ LinkToAnotherRecordType,
+ LookupColumnReqType,
+ RelationTypes,
+ RollupColumnReqType,
+ TableType,
+ UITypes,
+} from 'nocodb-sdk';
+import Column from '../../../models/Column';
+import LinkToAnotherRecordColumn from '../../../models/LinkToAnotherRecordColumn';
+import LookupColumn from '../../../models/LookupColumn';
+import Model from '../../../models/Model';
+import { getUniqueColumnAliasName } from '../../helpers/getUniqueName';
+import validateParams from '../../helpers/validateParams';
+
+export const randomID = customAlphabet(
+ '1234567890abcdefghijklmnopqrstuvwxyz_',
+ 10
+);
+
+export async function createHmAndBtColumn(
+ child: Model,
+ parent: Model,
+ childColumn: Column,
+ type?: RelationTypes,
+ alias?: string,
+ fkColName?: string,
+ virtual = false,
+ isSystemCol = false
+) {
+ // save bt column
+ {
+ const title = getUniqueColumnAliasName(
+ await child.getColumns(),
+ type === 'bt' ? alias : `${parent.title}`
+ );
+ await Column.insert({
+ title,
+
+ fk_model_id: child.id,
+ // ref_db_alias
+ uidt: UITypes.LinkToAnotherRecord,
+ type: 'bt',
+ // db_type:
+
+ fk_child_column_id: childColumn.id,
+ fk_parent_column_id: parent.primaryKey.id,
+ fk_related_model_id: parent.id,
+ virtual,
+ system: isSystemCol,
+ fk_col_name: fkColName,
+ fk_index_name: fkColName,
+ });
+ }
+ // save hm column
+ {
+ const title = getUniqueColumnAliasName(
+ await parent.getColumns(),
+ type === 'hm' ? alias : `${child.title} List`
+ );
+ await Column.insert({
+ title,
+ fk_model_id: parent.id,
+ uidt: UITypes.LinkToAnotherRecord,
+ type: 'hm',
+ fk_child_column_id: childColumn.id,
+ fk_parent_column_id: parent.primaryKey.id,
+ fk_related_model_id: child.id,
+ virtual,
+ system: isSystemCol,
+ fk_col_name: fkColName,
+ fk_index_name: fkColName,
+ });
+ }
+}
+
+export async function validateRollupPayload(
+ payload: ColumnReqType & { uidt: UITypes }
+) {
+ validateParams(
+ [
+ 'title',
+ 'fk_relation_column_id',
+ 'fk_rollup_column_id',
+ 'rollup_function',
+ ],
+ payload
+ );
+
+ const relation = await (
+ await Column.get({
+ colId: (payload as RollupColumnReqType).fk_relation_column_id,
+ })
+ ).getColOptions();
+
+ if (!relation) {
+ throw new Error('Relation column not found');
+ }
+
+ let relatedColumn: Column;
+ switch (relation.type) {
+ case 'hm':
+ relatedColumn = await Column.get({
+ colId: relation.fk_child_column_id,
+ });
+ break;
+ case 'mm':
+ case 'bt':
+ relatedColumn = await Column.get({
+ colId: relation.fk_parent_column_id,
+ });
+ break;
+ }
+
+ const relatedTable = await relatedColumn.getModel();
+ if (
+ !(await relatedTable.getColumns()).find(
+ (c) => c.id === (payload as RollupColumnReqType).fk_rollup_column_id
+ )
+ )
+ throw new Error('Rollup column not found in related table');
+}
+
+export async function validateLookupPayload(
+ payload: ColumnReqType & { uidt: UITypes },
+ columnId?: string
+) {
+ validateParams(
+ ['title', 'fk_relation_column_id', 'fk_lookup_column_id'],
+ payload
+ );
+
+ // check for circular reference
+ if (columnId) {
+ let lkCol: LookupColumn | LookupColumnReqType =
+ payload as LookupColumnReqType;
+ while (lkCol) {
+ // check if lookup column is same as column itself
+ if (columnId === lkCol.fk_lookup_column_id)
+ throw new Error('Circular lookup reference not allowed');
+ lkCol = await Column.get({ colId: lkCol.fk_lookup_column_id }).then(
+ (c: Column) => {
+ if (c.uidt === 'Lookup') {
+ return c.getColOptions();
+ }
+ return null;
+ }
+ );
+ }
+ }
+
+ const relation = await (
+ await Column.get({
+ colId: (payload as LookupColumnReqType).fk_relation_column_id,
+ })
+ ).getColOptions();
+
+ if (!relation) {
+ throw new Error('Relation column not found');
+ }
+
+ let relatedColumn: Column;
+ switch (relation.type) {
+ case 'hm':
+ relatedColumn = await Column.get({
+ colId: relation.fk_child_column_id,
+ });
+ break;
+ case 'mm':
+ case 'bt':
+ relatedColumn = await Column.get({
+ colId: relation.fk_parent_column_id,
+ });
+ break;
+ }
+
+ const relatedTable = await relatedColumn.getModel();
+ if (
+ !(await relatedTable.getColumns()).find(
+ (c) => c.id === (payload as LookupColumnReqType).fk_lookup_column_id
+ )
+ )
+ throw new Error('Lookup column not found in related table');
+}
+
+export const validateRequiredField = (
+ payload: Record,
+ requiredProps: string[]
+) => {
+ return requiredProps.every(
+ (prop) =>
+ prop in payload && payload[prop] !== undefined && payload[prop] !== null
+ );
+};
+
+// generate unique foreign key constraint name for foreign key
+export const generateFkName = (parent: TableType, child: TableType) => {
+ // generate a unique constraint name by taking first 10 chars of parent and child table name (by replacing all non word chars with _)
+ // and appending a random string of 15 chars maximum length.
+ // In database constraint name can be upto 64 chars and here we are generating a name of maximum 40 chars
+ const constraintName = `fk_${parent.table_name
+ .replace(/\W+/g, '_')
+ .slice(0, 10)}_${child.table_name
+ .replace(/\W+/g, '_')
+ .slice(0, 10)}_${randomID(15)}`;
+ return constraintName;
+};
diff --git a/packages/nocodb/src/lib/meta/api/helpers/index.ts b/packages/nocodb/src/lib/meta/api/helpers/index.ts
index ab5d63a717..1b1e81ecfa 100644
--- a/packages/nocodb/src/lib/meta/api/helpers/index.ts
+++ b/packages/nocodb/src/lib/meta/api/helpers/index.ts
@@ -1,3 +1,4 @@
import { populateMeta } from './populateMeta';
+export * from './columnHelpers';
export { populateMeta };
diff --git a/tests/playwright/tests/columnLookupRollup.spec.ts b/tests/playwright/tests/columnLookupRollup.spec.ts
index eacf7dae31..710a298db6 100644
--- a/tests/playwright/tests/columnLookupRollup.spec.ts
+++ b/tests/playwright/tests/columnLookupRollup.spec.ts
@@ -41,7 +41,7 @@ test.describe('Virtual columns', () => {
title: 'Rollup',
type: 'Rollup',
childTable: 'City List',
- childColumn: 'City',
+ childColumn: 'CityId',
rollupType: 'count',
});
for (let i = 0; i < pinCode.length; i++) {