Skip to content

Commit ba9815e

Browse files
committed
improve logic
1 parent 55a8b4c commit ba9815e

File tree

1 file changed

+74
-39
lines changed

1 file changed

+74
-39
lines changed

packages/compass-data-modeling/src/components/diagram-editor.tsx

Lines changed: 74 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ import {
1818
Banner,
1919
Body,
2020
CancelLoader,
21-
Tooltip,
2221
WorkspaceContainer,
2322
css,
2423
spacing,
2524
Button,
2625
palette,
2726
ErrorSummary,
2827
useDarkMode,
28+
InlineDefinition,
2929
} from '@mongodb-js/compass-components';
3030
import { CodemirrorMultilineEditor } from '@mongodb-js/compass-editor';
3131
import { cancelAnalysis, retryAnalysis } from '../store/analysis-process';
@@ -41,7 +41,6 @@ import { UUID } from 'bson';
4141
import DiagramEditorToolbar from './diagram-editor-toolbar';
4242
import ExportDiagramModal from './export-diagram-modal';
4343
import { useLogger } from '@mongodb-js/compass-logging/provider';
44-
import type { MongoDBJSONSchema } from 'mongodb-schema';
4544

4645
const loadingContainerStyles = css({
4746
width: '100%',
@@ -87,27 +86,90 @@ const ErrorBannerWithRetry: React.FunctionComponent<{
8786
);
8887
};
8988

90-
function getFieldTypeDisplay(field: MongoDBJSONSchema) {
91-
if (field.bsonType === undefined) {
89+
function getBsonTypeName(bsonType: string) {
90+
switch (bsonType) {
91+
case 'array':
92+
return '[]';
93+
default:
94+
return bsonType;
95+
}
96+
}
97+
98+
function getFieldTypeDisplay(bsonTypes: string[]) {
99+
if (bsonTypes.length === 0) {
92100
return 'unknown';
93101
}
94102

95-
if (typeof field.bsonType === 'string') {
96-
return field.bsonType;
103+
if (bsonTypes.length === 1) {
104+
return getBsonTypeName(bsonTypes[0]);
97105
}
98106

99-
const typesString = field.bsonType.join(', ');
107+
const typesString = bsonTypes
108+
.map((bsonType) => getBsonTypeName(bsonType))
109+
.join(', ');
100110

101111
// We show `mixed` with a tooltip when multiple bsonTypes were found.
102112
return (
103-
<Tooltip justify="end" spacing={5} trigger={<div>(mixed)</div>}>
104-
<Body className={mixedTypeTooltipContentStyles}>
105-
Multiple types found in sample: {typesString}
106-
</Body>
107-
</Tooltip>
113+
<InlineDefinition
114+
definition={
115+
<Body className={mixedTypeTooltipContentStyles}>
116+
Multiple types found in sample: {typesString}
117+
</Body>
118+
}
119+
>
120+
<div>(mixed)</div>
121+
</InlineDefinition>
108122
);
109123
}
110124

125+
const getFieldsFromSchema = (
126+
jsonSchema: MongoDBJSONSchema,
127+
depth = 0
128+
): NodeProps['fields'] => {
129+
if (!jsonSchema || !jsonSchema.properties) {
130+
return [];
131+
}
132+
let fields: NodeProps['fields'] = [];
133+
for (const [name, field] of Object.entries(jsonSchema.properties)) {
134+
// field has types, properties and (optional) children
135+
// types are either direct, or from anyof
136+
// children are either direct (properties), from anyOf, items or items.anyOf
137+
const types: (string | string[])[] = [];
138+
const children = [];
139+
if (field.bsonType) types.push(field.bsonType);
140+
if (field.properties) children.push(field);
141+
if (field.items)
142+
children.push((field.items as MongoDBJSONSchema).anyOf || field.items);
143+
if (field.anyOf) {
144+
for (const variant of field.anyOf) {
145+
if (variant.bsonType) types.push(variant.bsonType);
146+
if (variant.properties) {
147+
children.push(variant);
148+
}
149+
if (variant.items) children.push(variant.items);
150+
}
151+
}
152+
153+
fields.push({
154+
name,
155+
type: getFieldTypeDisplay(types.flat()),
156+
depth: depth,
157+
glyphs: types.length === 1 && types[0] === 'objectId' ? ['key'] : [],
158+
});
159+
160+
if (children.length > 0) {
161+
fields = [
162+
...fields,
163+
...children
164+
.flat()
165+
.flatMap((child) => getFieldsFromSchema(child, depth + 1)),
166+
];
167+
}
168+
}
169+
170+
return fields;
171+
};
172+
111173
const modelPreviewContainerStyles = css({
112174
display: 'grid',
113175
gridTemplateColumns: '100%',
@@ -145,33 +207,6 @@ const editorContainerPlaceholderButtonStyles = css({
145207
paddingTop: spacing[200],
146208
});
147209

148-
const getFieldsFromSchema = (
149-
jsonSchema: MongoDBJSONSchema,
150-
depth = 0
151-
): NodeProps['fields'] => {
152-
let fields = [] as NodeProps['fields'];
153-
if (jsonSchema.anyOf) {
154-
for (const variant of jsonSchema.anyOf) {
155-
fields = [...fields, ...getFieldsFromSchema(variant, depth + 1)];
156-
}
157-
}
158-
if (!jsonSchema.properties) return [];
159-
for (const [name, field] of Object.entries(jsonSchema.properties)) {
160-
const type = getFieldTypeDisplay(field);
161-
fields.push({
162-
name,
163-
type,
164-
depth: depth,
165-
glyphs: type === 'objectId' ? ['key'] : [],
166-
});
167-
if (field.properties) {
168-
fields = [...fields, ...getFieldsFromSchema(field, depth + 1)];
169-
}
170-
}
171-
172-
return fields;
173-
};
174-
175210
const DiagramEditor: React.FunctionComponent<{
176211
diagramLabel: string;
177212
step: DataModelingState['step'];

0 commit comments

Comments
 (0)