Browse Source

Merge pull request #7524 from nocodb/nc-fix/m2m-table

Nc fix/m2m table
pull/7540/head
Pranav C 9 months ago committed by GitHub
parent
commit
12cf69e03b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      packages/nc-gui/components/smartsheet/column/FormulaOptions.vue
  2. 6
      packages/nc-gui/components/smartsheet/toolbar/CreateGroupBy.vue
  3. 6
      packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue
  4. 10
      packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue
  5. 4
      packages/nc-gui/composables/useViewColumns.ts
  6. 15
      packages/nocodb-sdk/src/lib/UITypes.ts
  7. 4
      packages/nocodb-sdk/src/lib/globals.ts
  8. 1
      packages/nocodb-sdk/src/lib/index.ts
  9. 6
      packages/nocodb/src/db/BaseModelSqlv2.ts
  10. 8
      packages/nocodb/src/db/genRollupSelectv2.ts
  11. 33
      packages/nocodb/src/services/tables.service.ts

4
packages/nc-gui/components/smartsheet/column/FormulaOptions.vue

@ -5,7 +5,7 @@ import jsep from 'jsep'
import { import {
FormulaError, FormulaError,
UITypes, UITypes,
isCreatedOrLastModifiedByCol, isHiddenCol,
jsepCurlyHook, jsepCurlyHook,
substituteColumnIdWithAliasInFormula, substituteColumnIdWithAliasInFormula,
validateFormulaAndExtractTreeWithType, validateFormulaAndExtractTreeWithType,
@ -58,7 +58,7 @@ const supportedColumns = computed(
return false return false
} }
if (isCreatedOrLastModifiedByCol(col) && col.system) { if (isHiddenCol(col)) {
return false return false
} }

6
packages/nc-gui/components/smartsheet/toolbar/CreateGroupBy.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isCreatedOrLastModifiedByCol, isLinksOrLTAR, isSystemColumn } from 'nocodb-sdk' import { RelationTypes, UITypes, isHiddenCol, isLinksOrLTAR, isSystemColumn } from 'nocodb-sdk'
const props = defineProps<{ const props = defineProps<{
// As we need to focus search box when the parent is opened // As we need to focus search box when the parent is opened
@ -40,8 +40,8 @@ const options = computed<ColumnType[]>(
return false return false
} }
if (isCreatedOrLastModifiedByCol(c)) { if (isHiddenCol(c)) {
/** ignore created by and last modified by system field */ /** ignore mm relation column, created by and last modified by system field */
return false return false
} }

6
packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isCreatedOrLastModifiedByCol, isLinksOrLTAR, isSystemColumn } from 'nocodb-sdk' import { RelationTypes, UITypes, isHiddenCol, isLinksOrLTAR, isSystemColumn } from 'nocodb-sdk'
const props = defineProps<{ const props = defineProps<{
// As we need to focus search box when the parent is opened // As we need to focus search box when the parent is opened
@ -33,8 +33,8 @@ const options = computed<ColumnType[]>(
return true return true
} }
if (isSystemColumn(metaColumnById?.value?.[c.id!])) { if (isSystemColumn(metaColumnById?.value?.[c.id!])) {
if (isCreatedOrLastModifiedByCol(c)) { if (isHiddenCol(c)) {
/** ignore created by and last modified by system field */ /** ignore mm relation column, created by and last modified by system field */
return false return false
} }

10
packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectProps } from 'ant-design-vue' import type { SelectProps } from 'ant-design-vue'
import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isCreatedOrLastModifiedByCol, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk' import { RelationTypes, UITypes, isHiddenCol, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { MetaInj, computed, inject, ref, resolveComponent, useViewColumnsOrThrow } from '#imports' import { MetaInj, computed, inject, ref, resolveComponent, useViewColumnsOrThrow } from '#imports'
const { modelValue, isSort, allowEmpty, ...restProps } = defineProps<{ const { modelValue, isSort, allowEmpty, ...restProps } = defineProps<{
@ -28,8 +28,8 @@ const options = computed<SelectProps['options']>(() =>
( (
customColumns.value?.filter((c: ColumnType) => { customColumns.value?.filter((c: ColumnType) => {
if (isSystemColumn(metaColumnById?.value?.[c.id!])) { if (isSystemColumn(metaColumnById?.value?.[c.id!])) {
if (isCreatedOrLastModifiedByCol(c)) { if (isHiddenCol(c)) {
/** ignore created by and last modified by system field */ /** ignore mm relation column, created by and last modified by system field */
return false return false
} }
} }
@ -40,8 +40,8 @@ const options = computed<SelectProps['options']>(() =>
return true return true
} }
if (isSystemColumn(metaColumnById?.value?.[c.id!])) { if (isSystemColumn(metaColumnById?.value?.[c.id!])) {
if (isCreatedOrLastModifiedByCol(c)) { if (isHiddenCol(c)) {
/** ignore created by and last modified by system field */ /** ignore mm relation column, created by and last modified by system field */
return false return false
} }

4
packages/nc-gui/composables/useViewColumns.ts

@ -1,4 +1,4 @@
import { ViewTypes, isCreatedOrLastModifiedByCol, isSystemColumn } from 'nocodb-sdk' import { ViewTypes, isHiddenCol, isSystemColumn } from 'nocodb-sdk'
import type { ColumnType, GridColumnReqType, GridColumnType, MapType, TableType, ViewType } from 'nocodb-sdk' import type { ColumnType, GridColumnReqType, GridColumnType, MapType, TableType, ViewType } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import { computed, ref, storeToRefs, useBase, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports' import { computed, ref, storeToRefs, useBase, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports'
@ -72,7 +72,7 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
fields.value = meta.value?.columns fields.value = meta.value?.columns
?.filter((column: ColumnType) => { ?.filter((column: ColumnType) => {
// filter created by and last modified by system columns // filter created by and last modified by system columns
if (isCreatedOrLastModifiedByCol(column) && column.system) return false if (isHiddenCol(column)) return false
return true return true
}) })
.map((column: ColumnType) => { .map((column: ColumnType) => {

15
packages/nocodb-sdk/src/lib/UITypes.ts

@ -162,6 +162,21 @@ export function isCreatedOrLastModifiedByCol(
); );
} }
export function isHiddenCol(
col: (ColumnReqType | ColumnType) & { system?: number | boolean }
) {
return (
col.system &&
(
[
UITypes.CreatedBy,
UITypes.LastModifiedBy,
UITypes.LinkToAnotherRecord,
] as string[]
).includes(col.uidt)
);
}
export function isLinksOrLTAR( export function isLinksOrLTAR(
colOrUidt: ColumnType | { uidt: UITypes | string } | UITypes | string colOrUidt: ColumnType | { uidt: UITypes | string } | UITypes | string
) { ) {

4
packages/nocodb-sdk/src/lib/globals.ts

@ -123,6 +123,10 @@ export enum TiptapMarksTypes {
underline = 'underline', underline = 'underline',
} }
export enum NcDataErrorCodes {
NC_ERR_MM_MODEL_NOT_FOUND = 'NC_ERR_MM_MODEL_NOT_FOUND',
}
type Roles = OrgUserRoles | ProjectRoles | WorkspaceUserRoles; type Roles = OrgUserRoles | ProjectRoles | WorkspaceUserRoles;
type RolesObj = Partial<Record<Roles, boolean>>; type RolesObj = Partial<Record<Roles, boolean>>;

1
packages/nocodb-sdk/src/lib/index.ts

@ -16,6 +16,7 @@ export {
isLinksOrLTAR, isLinksOrLTAR,
isCreatedOrLastModifiedTimeCol, isCreatedOrLastModifiedTimeCol,
isCreatedOrLastModifiedByCol, isCreatedOrLastModifiedByCol,
isHiddenCol,
} from '~/lib/UITypes'; } from '~/lib/UITypes';
export { default as CustomAPI, FileType } from '~/lib/CustomAPI'; export { default as CustomAPI, FileType } from '~/lib/CustomAPI';
export { default as TemplateGenerator } from '~/lib/TemplateGenerator'; export { default as TemplateGenerator } from '~/lib/TemplateGenerator';

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

@ -1251,6 +1251,12 @@ class BaseModelSqlv2 {
// const tn = this.model.tn; // const tn = this.model.tn;
// const cn = (await relColOptions.getChildColumn()).title; // const cn = (await relColOptions.getChildColumn()).title;
const mmTable = await relColOptions.getMMModel(); const mmTable = await relColOptions.getMMModel();
// if mm table is not present then return
if (!mmTable) {
return;
}
const vtn = this.getTnPath(mmTable); const vtn = this.getTnPath(mmTable);
const vcn = (await relColOptions.getMMChildColumn()).column_name; const vcn = (await relColOptions.getMMChildColumn()).column_name;
const vrcn = (await relColOptions.getMMParentColumn()).column_name; const vrcn = (await relColOptions.getMMParentColumn()).column_name;

8
packages/nocodb/src/db/genRollupSelectv2.ts

@ -1,4 +1,4 @@
import { RelationTypes } from 'nocodb-sdk'; import { NcDataErrorCodes, RelationTypes } from 'nocodb-sdk';
import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2';
import type { LinksColumn } from '~/models'; import type { LinksColumn } from '~/models';
import type { RollupColumn } from '~/models'; import type { RollupColumn } from '~/models';
@ -56,6 +56,12 @@ export default async function ({
const mmChildCol = await relationColumnOption.getMMChildColumn(); const mmChildCol = await relationColumnOption.getMMChildColumn();
const mmParentCol = await relationColumnOption.getMMParentColumn(); const mmParentCol = await relationColumnOption.getMMParentColumn();
if (!mmModel) {
return this.dbDriver.raw(`?`, [
NcDataErrorCodes.NC_ERR_MM_MODEL_NOT_FOUND,
]);
}
return { return {
builder: knex( builder: knex(
knex.raw(`?? as ??`, [ knex.raw(`?? as ??`, [

33
packages/nocodb/src/services/tables.service.ts

@ -8,6 +8,7 @@ import {
isVirtualCol, isVirtualCol,
ModelTypes, ModelTypes,
ProjectRoles, ProjectRoles,
RelationTypes,
UITypes, UITypes,
} from 'nocodb-sdk'; } from 'nocodb-sdk';
import { MetaDiffsService } from './meta-diffs.service'; import { MetaDiffsService } from './meta-diffs.service';
@ -172,6 +173,38 @@ export class TablesService {
const table = await Model.getByIdOrName({ id: param.tableId }); const table = await Model.getByIdOrName({ id: param.tableId });
await table.getColumns(); await table.getColumns();
if (table.mm) {
const columns = await table.getColumns();
// get table names of the relation which uses the current table as junction table
const tables = await Promise.all(
columns
.filter((c) => isLinksOrLTAR(c))
.map((c) => c.colOptions.getRelatedTable()),
);
// get relation column names
const relColumns = await Promise.all(
tables.map((t) => {
return t.getColumns().then((cols) => {
return cols.find((c) => {
return (
isLinksOrLTAR(c) &&
(c.colOptions as LinkToAnotherRecordColumn).type ===
RelationTypes.MANY_TO_MANY &&
(c.colOptions as LinkToAnotherRecordColumn).fk_mm_model_id ===
table.id
);
});
});
}),
);
NcError.badRequest(
`This is a many to many table for ${tables[0]?.title} (${relColumns[0]?.title}) & ${tables[1]?.title} (${relColumns[1]?.title}). You can disable "Show M2M tables" in base settings to avoid seeing this.`,
);
}
const base = await Base.getWithInfo(table.base_id); const base = await Base.getWithInfo(table.base_id);
const source = base.sources.find((b) => b.id === table.source_id); const source = base.sources.find((b) => b.id === table.source_id);

Loading…
Cancel
Save