mirror of
				https://github.com/chartdb/chartdb.git
				synced 2025-10-31 12:03:51 +00:00 
			
		
		
		
	fix(dbml): fix dbml output format (#815)
This commit is contained in:
		| @@ -44,6 +44,7 @@ export interface CodeSnippetProps { | |||||||
|     editorProps?: React.ComponentProps<EditorType>; |     editorProps?: React.ComponentProps<EditorType>; | ||||||
|     actions?: CodeSnippetAction[]; |     actions?: CodeSnippetAction[]; | ||||||
|     actionsTooltipSide?: 'top' | 'right' | 'bottom' | 'left'; |     actionsTooltipSide?: 'top' | 'right' | 'bottom' | 'left'; | ||||||
|  |     allowCopy?: boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
| export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo( | export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo( | ||||||
| @@ -58,6 +59,7 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo( | |||||||
|         editorProps, |         editorProps, | ||||||
|         actions, |         actions, | ||||||
|         actionsTooltipSide, |         actionsTooltipSide, | ||||||
|  |         allowCopy = true, | ||||||
|     }) => { |     }) => { | ||||||
|         const { t } = useTranslation(); |         const { t } = useTranslation(); | ||||||
|         const monaco = useMonaco(); |         const monaco = useMonaco(); | ||||||
| @@ -131,6 +133,7 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo( | |||||||
|                     <Suspense fallback={<Spinner />}> |                     <Suspense fallback={<Spinner />}> | ||||||
|                         {isComplete ? ( |                         {isComplete ? ( | ||||||
|                             <div className="absolute right-1 top-1 z-10 flex flex-col gap-1"> |                             <div className="absolute right-1 top-1 z-10 flex flex-col gap-1"> | ||||||
|  |                                 {allowCopy ? ( | ||||||
|                                     <Tooltip |                                     <Tooltip | ||||||
|                                         onOpenChange={setTooltipOpen} |                                         onOpenChange={setTooltipOpen} | ||||||
|                                         open={isCopied || tooltipOpen} |                                         open={isCopied || tooltipOpen} | ||||||
| @@ -150,7 +153,9 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo( | |||||||
|                                                 </Button> |                                                 </Button> | ||||||
|                                             </span> |                                             </span> | ||||||
|                                         </TooltipTrigger> |                                         </TooltipTrigger> | ||||||
|                                     <TooltipContent side={actionsTooltipSide}> |                                         <TooltipContent | ||||||
|  |                                             side={actionsTooltipSide} | ||||||
|  |                                         > | ||||||
|                                             {t( |                                             {t( | ||||||
|                                                 isCopied |                                                 isCopied | ||||||
|                                                     ? 'copied' |                                                     ? 'copied' | ||||||
| @@ -158,6 +163,7 @@ export const CodeSnippet: React.FC<CodeSnippetProps> = React.memo( | |||||||
|                                             )} |                                             )} | ||||||
|                                         </TooltipContent> |                                         </TooltipContent> | ||||||
|                                     </Tooltip> |                                     </Tooltip> | ||||||
|  |                                 ) : null} | ||||||
|  |  | ||||||
|                                 {actions && |                                 {actions && | ||||||
|                                     actions.length > 0 && |                                     actions.length > 0 && | ||||||
|   | |||||||
| @@ -362,7 +362,8 @@ export const exportBaseSQL = ({ | |||||||
|                 .join(', '); |                 .join(', '); | ||||||
|  |  | ||||||
|             if (fieldNames) { |             if (fieldNames) { | ||||||
|                 const indexName = table.schema |                 const indexName = | ||||||
|  |                     table.schema && !isDBMLFlow | ||||||
|                         ? `${table.schema}_${index.name}` |                         ? `${table.schema}_${index.name}` | ||||||
|                         : index.name; |                         : index.name; | ||||||
|                 sqlScript += `CREATE ${index.unique ? 'UNIQUE ' : ''}INDEX ${indexName} ON ${tableName} (${fieldNames});\n`; |                 sqlScript += `CREATE ${index.unique ? 'UNIQUE ' : ''}INDEX ${indexName} ON ${tableName} (${fieldNames});\n`; | ||||||
|   | |||||||
| @@ -937,26 +937,24 @@ describe('DBML Export - Issue Fixes', () => { | |||||||
|         // Check that indexes are properly formatted with names |         // Check that indexes are properly formatted with names | ||||||
|         // Note: When a table has a schema, index names are prefixed with the schema |         // Note: When a table has a schema, index names are prefixed with the schema | ||||||
|         expect(result.standardDbml).toContain( |         expect(result.standardDbml).toContain( | ||||||
|             'email [unique, name: "public_idx_email"]' |             'email [unique, name: "idx_email"]' | ||||||
|         ); |         ); | ||||||
|         expect(result.standardDbml).toContain( |         expect(result.standardDbml).toContain( | ||||||
|             'created_at [name: "public_idx_created_at"]' |             'created_at [name: "idx_created_at"]' | ||||||
|         ); |         ); | ||||||
|         expect(result.standardDbml).toContain( |         expect(result.standardDbml).toContain( | ||||||
|             '(email, created_at) [name: "public_idx_email_created"]' |             '(email, created_at) [name: "idx_email_created"]' | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|         // Verify proper index syntax in the table |         // Verify proper index syntax in the table | ||||||
|         const indexSection = result.standardDbml.match(/Indexes \{[\s\S]*?\}/); |         const indexSection = result.standardDbml.match(/Indexes \{[\s\S]*?\}/); | ||||||
|         expect(indexSection).toBeTruthy(); |         expect(indexSection).toBeTruthy(); | ||||||
|  |         expect(indexSection![0]).toContain('email [unique, name: "idx_email"]'); | ||||||
|         expect(indexSection![0]).toContain( |         expect(indexSection![0]).toContain( | ||||||
|             'email [unique, name: "public_idx_email"]' |             'created_at [name: "idx_created_at"]' | ||||||
|         ); |         ); | ||||||
|         expect(indexSection![0]).toContain( |         expect(indexSection![0]).toContain( | ||||||
|             'created_at [name: "public_idx_created_at"]' |             '(email, created_at) [name: "idx_email_created"]' | ||||||
|         ); |  | ||||||
|         expect(indexSection![0]).toContain( |  | ||||||
|             '(email, created_at) [name: "public_idx_email_created"]' |  | ||||||
|         ); |         ); | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -350,7 +350,10 @@ const convertToInlineRefs = (dbml: string): string => { | |||||||
|                     // Combine all attributes into a single bracket |                     // Combine all attributes into a single bracket | ||||||
|                     const combinedAttributes = allAttributes.join(', '); |                     const combinedAttributes = allAttributes.join(', '); | ||||||
|  |  | ||||||
|                     return `${fieldPart.trim()} [${combinedAttributes}]${commentPart || ''}`; |                     // Preserve original spacing from fieldPart | ||||||
|  |                     const leadingSpaces = fieldPart.match(/^(\s*)/)?.[1] || ''; | ||||||
|  |                     const fieldDefWithoutSpaces = fieldPart.trim(); | ||||||
|  |                     return `${leadingSpaces}${fieldDefWithoutSpaces} [${combinedAttributes}]${commentPart || ''}`; | ||||||
|                 } |                 } | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
| @@ -388,7 +391,10 @@ const convertToInlineRefs = (dbml: string): string => { | |||||||
|         .filter((line) => !line.trim().startsWith('Ref ')); |         .filter((line) => !line.trim().startsWith('Ref ')); | ||||||
|     const finalDbml = finalLines.join('\n').trim(); |     const finalDbml = finalLines.join('\n').trim(); | ||||||
|  |  | ||||||
|     return finalDbml; |     // Clean up excessive empty lines - replace multiple consecutive empty lines with just one | ||||||
|  |     const cleanedDbml = finalDbml.replace(/\n\s*\n\s*\n/g, '\n\n'); | ||||||
|  |  | ||||||
|  |     return cleanedDbml; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Function to check for SQL keywords (add more if needed) | // Function to check for SQL keywords (add more if needed) | ||||||
| @@ -804,9 +810,15 @@ export function generateDBMLFromDiagram(diagram: Diagram): DBMLExportResult { | |||||||
|         standard = restoreTableSchemas(standard, diagram); |         standard = restoreTableSchemas(standard, diagram); | ||||||
|  |  | ||||||
|         // Prepend Enum DBML to the standard output |         // Prepend Enum DBML to the standard output | ||||||
|         standard = enumsDBML + '\n' + standard; |         if (enumsDBML) { | ||||||
|  |             standard = enumsDBML + '\n\n' + standard; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         inline = normalizeCharTypeFormat(convertToInlineRefs(standard)); |         inline = normalizeCharTypeFormat(convertToInlineRefs(standard)); | ||||||
|  |  | ||||||
|  |         // Clean up excessive empty lines in both outputs | ||||||
|  |         standard = standard.replace(/\n\s*\n\s*\n/g, '\n\n'); | ||||||
|  |         inline = inline.replace(/\n\s*\n\s*\n/g, '\n\n'); | ||||||
|     } catch (error: unknown) { |     } catch (error: unknown) { | ||||||
|         console.error( |         console.error( | ||||||
|             'Error during DBML generation process:', |             'Error during DBML generation process:', | ||||||
| @@ -822,11 +834,11 @@ export function generateDBMLFromDiagram(diagram: Diagram): DBMLExportResult { | |||||||
|  |  | ||||||
|         // If an error occurred, still prepend enums if they exist, or they'll be lost. |         // If an error occurred, still prepend enums if they exist, or they'll be lost. | ||||||
|         // The error message will then follow. |         // The error message will then follow. | ||||||
|         if (standard.startsWith('// Error generating DBML:')) { |         if (standard.startsWith('// Error generating DBML:') && enumsDBML) { | ||||||
|             standard = enumsDBML + standard; |             standard = enumsDBML + '\n\n' + standard; | ||||||
|         } |         } | ||||||
|         if (inline.startsWith('// Error generating DBML:')) { |         if (inline.startsWith('// Error generating DBML:') && enumsDBML) { | ||||||
|             inline = enumsDBML + inline; |             inline = enumsDBML + '\n\n' + inline; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user