Browse Source

Merge pull request #8428 from nocodb/nc-fix/2834-one-to-one-erd

fix: add one to one relation in ERD diagram
pull/8433/head
Pranav C 6 months ago committed by GitHub
parent
commit
2455c47088
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 12
      packages/nc-gui/components/erd/RelationEdge.vue
  2. 45
      packages/nc-gui/components/erd/utils.ts

12
packages/nc-gui/components/erd/RelationEdge.vue

@ -116,7 +116,19 @@ export default {
</EdgeLabelRenderer> </EdgeLabelRenderer>
<template v-if="!showSkeleton"> <template v-if="!showSkeleton">
<circle
v-if="data.isOneToOne"
class="nc-erd-edge-circle"
:cx="sourceX"
:cy="sourceY"
fill="#fff"
:r="5"
stroke="#898E99"
:stroke-width="2"
/>
<rect <rect
v-else
class="nc-erd-edge-rect" class="nc-erd-edge-rect"
:x="sourceX" :x="sourceX"
:y="sourceY - 4" :y="sourceY - 4"

45
packages/nc-gui/components/erd/utils.ts

@ -1,9 +1,9 @@
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk' import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes, isLinksOrLTAR } from 'nocodb-sdk' import { RelationTypes, UITypes, isLinksOrLTAR } from 'nocodb-sdk'
import dagre from 'dagre' import dagre from 'dagre'
import type { Edge, EdgeMarker, Elements, Node } from '@vue-flow/core' import type { Edge, EdgeMarker, Elements, Node } from '@vue-flow/core'
import type { MaybeRef } from '@vueuse/core'
import { MarkerType, Position, isEdge, isNode } from '@vue-flow/core' import { MarkerType, Position, isEdge, isNode } from '@vue-flow/core'
import type { MaybeRef } from '@vueuse/core'
import { scaleLinear as d3ScaleLinear } from 'd3-scale' import { scaleLinear as d3ScaleLinear } from 'd3-scale'
import tinycolor from 'tinycolor2' import tinycolor from 'tinycolor2'
@ -29,6 +29,7 @@ export interface NodeData {
export interface EdgeData { export interface EdgeData {
isManyToMany: boolean isManyToMany: boolean
isOneToOne: boolean
isSelfRelation: boolean isSelfRelation: boolean
label?: string label?: string
simpleLabel?: string simpleLabel?: string
@ -41,7 +42,7 @@ interface Relation {
childColId?: string childColId?: string
parentColId?: string parentColId?: string
modelId?: string modelId?: string
type: 'mm' | 'hm' type: RelationTypes
} }
/** /**
@ -89,27 +90,36 @@ export function useErdElements(tables: MaybeRef<TableType[]>, props: MaybeRef<ER
childColId: colOptions.fk_child_column_id, childColId: colOptions.fk_child_column_id,
parentColId: colOptions.fk_parent_column_id, parentColId: colOptions.fk_parent_column_id,
modelId: colOptions.fk_mm_model_id, modelId: colOptions.fk_mm_model_id,
type: 'hm', type: RelationTypes.HAS_MANY,
}
if (colOptions.type === RelationTypes.HAS_MANY) {
relation.type = RelationTypes.HAS_MANY
acc.push(relation)
continue
} }
if (colOptions.type === RelationTypes.ONE_TO_ONE) {
relation.type = RelationTypes.ONE_TO_ONE
if (colOptions.type === 'hm') { // skip adding relation link from both side
relation.type = 'hm' if (column.meta?.bt) continue
acc.push(relation) acc.push(relation)
continue continue
} }
if (colOptions.type === 'mm') { if (colOptions.type === RelationTypes.MANY_TO_MANY) {
// Avoid duplicate mm connections // Avoid duplicate mm connections
const correspondingColumn = acc.find( const correspondingColumn = acc.find(
(relation) => (relation) =>
relation.type === 'mm' && relation.type === RelationTypes.MANY_TO_MANY &&
relation.parentColId === colOptions.fk_child_column_id && relation.parentColId === colOptions.fk_child_column_id &&
relation.childColId === colOptions.fk_parent_column_id, relation.childColId === colOptions.fk_parent_column_id,
) )
if (!correspondingColumn) { if (!correspondingColumn) {
relation.type = 'mm' relation.type = RelationTypes.MANY_TO_MANY
acc.push(relation) acc.push(relation)
continue continue
@ -123,7 +133,11 @@ export function useErdElements(tables: MaybeRef<TableType[]>, props: MaybeRef<ER
) )
function edgeLabel({ type, source, target, modelId, childColId, parentColId }: Relation) { function edgeLabel({ type, source, target, modelId, childColId, parentColId }: Relation) {
const typeLabel = type === 'mm' ? 'many to many' : 'has many' let typeLabel: string
if (type === RelationTypes.HAS_MANY) typeLabel = 'has many'
else if (type === RelationTypes.MANY_TO_MANY) typeLabel = 'many to many'
else if (type === 'oo') typeLabel = 'one to one'
const parentCol = metasWithIdAsKey.value[source].columns?.find((col) => { const parentCol = metasWithIdAsKey.value[source].columns?.find((col) => {
const colOptions = col.colOptions as LinkToAnotherRecordType const colOptions = col.colOptions as LinkToAnotherRecordType
@ -140,12 +154,12 @@ export function useErdElements(tables: MaybeRef<TableType[]>, props: MaybeRef<ER
const colOptions = col.colOptions as LinkToAnotherRecordType const colOptions = col.colOptions as LinkToAnotherRecordType
if (!colOptions) return false if (!colOptions) return false
return colOptions.fk_parent_column_id === (type === 'mm' ? childColId : parentColId) return colOptions.fk_parent_column_id === (type === RelationTypes.MANY_TO_MANY ? childColId : parentColId)
}) })
if (!parentCol || !childCol) return '' if (!parentCol || !childCol) return ''
if (type === 'mm') { if (type === RelationTypes.MANY_TO_MANY) {
if (config.value.showJunctionTableNames) { if (config.value.showJunctionTableNames) {
if (!modelId) return '' if (!modelId) return ''
@ -208,12 +222,12 @@ export function useErdElements(tables: MaybeRef<TableType[]>, props: MaybeRef<ER
return relations.value.reduce<Edge<EdgeData>[]>((acc, { source, target, childColId, parentColId, type, modelId }) => { return relations.value.reduce<Edge<EdgeData>[]>((acc, { source, target, childColId, parentColId, type, modelId }) => {
let sourceColumnId, targetColumnId let sourceColumnId, targetColumnId
if (type === 'hm') { if (type === RelationTypes.HAS_MANY || type === 'oo') {
sourceColumnId = childColId sourceColumnId = childColId
targetColumnId = childColId targetColumnId = childColId
} }
if (type === 'mm') { if (type === RelationTypes.MANY_TO_MANY) {
sourceColumnId = parentColId sourceColumnId = parentColId
targetColumnId = childColId targetColumnId = childColId
} }
@ -239,7 +253,8 @@ export function useErdElements(tables: MaybeRef<TableType[]>, props: MaybeRef<ER
type: MarkerType.ArrowClosed, type: MarkerType.ArrowClosed,
}, },
data: { data: {
isManyToMany: type === 'mm', isManyToMany: type === RelationTypes.MANY_TO_MANY,
isOneToOne: type === 'oo',
isSelfRelation: source === target && sourceColumnId === targetColumnId, isSelfRelation: source === target && sourceColumnId === targetColumnId,
label, label,
simpleLabel, simpleLabel,

Loading…
Cancel
Save