From bb4115fc38de4823cb535e409c217f9811f4a424 Mon Sep 17 00:00:00 2001 From: mtvee Date: Fri, 5 Jun 2009 06:27:53 +0000 Subject: - added schema export to basic graphviz dot file --- Source/TableDump.h | 1 + Source/TableDump.m | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) (limited to 'Source') diff --git a/Source/TableDump.h b/Source/TableDump.h index 1d34e8fa..0bf7ffcc 100644 --- a/Source/TableDump.h +++ b/Source/TableDump.h @@ -132,6 +132,7 @@ // Export methods - (BOOL)dumpSelectedTablesAsSqlToFileHandle:(NSFileHandle *)fileHandle; +- (BOOL)dumpSchemaAsDotToFileHandle:(NSFileHandle *)fileHandle; - (BOOL)writeCsvForArray:(NSArray *)array orQueryResult:(CMMCPResult *)queryResult toFileHandle:(NSFileHandle *)fileHandle outputFieldNames:(BOOL)firstLine terminatedBy:(NSString *)terminated diff --git a/Source/TableDump.m b/Source/TableDump.m index 2fe99121..94bf8af7 100644 --- a/Source/TableDump.m +++ b/Source/TableDump.m @@ -193,6 +193,15 @@ [savePanel setAccessoryView:exportMultipleXMLView]; contextInfo = @"exportMultipleTablesAsXML"; break; + + // graphviz dot file + case 14: + [self reloadTables:self]; + file = [NSString stringWithString:[tableDocumentInstance database]]; + [savePanel setRequiredFileType:@"dot"]; + contextInfo = @"exportDot"; + break; + default: ALog(@"ERROR: unknown export item with tag %d", tag); return; @@ -311,6 +320,10 @@ } else if ( [contextInfo isEqualToString:@"exportMultipleTablesAsXML"] ) { success = [self exportSelectedTablesToFileHandle:fileHandle usingFormat:@"xml"]; + // Export the tables selected in the MySQL export sheet to a file + } else if ( [contextInfo isEqualToString:@"exportDot"] ) { + success = [self dumpSchemaAsDotToFileHandle:fileHandle]; + // Unknown operation } else { ALog(@"Unknown export operation: %@", [contextInfo description]); @@ -1092,6 +1105,134 @@ return TRUE; } +/* + Dump the selected tables to a file handle in Graphviz dot format. + */ +- (BOOL)dumpSchemaAsDotToFileHandle:(NSFileHandle *)fileHandle +{ + NSMutableString *metaString = [NSMutableString string]; + int progressBarWidth; + NSString *previousConnectionEncoding; + BOOL previousConnectionEncodingViaLatin1; + + [singleProgressText setStringValue:NSLocalizedString(@"Dumping...", @"text showing that app is writing dump")]; + [singleProgressText displayIfNeeded]; + progressBarWidth = (int)[singleProgressBar bounds].size.width; + [singleProgressBar setDoubleValue:0]; + [singleProgressBar displayIfNeeded]; + + // Open the progress sheet + [NSApp beginSheet:singleProgressSheet + modalForWindow:tableWindow modalDelegate:self + didEndSelector:nil contextInfo:nil]; + + [metaString setString:@"// Generated by: Sequel Pro\n"]; + [metaString appendString:[NSString stringWithFormat:@"// Version %@\n", + [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]]; + [metaString appendString:@"// http://code.google.com/p/sequel-pro\n//\n"]; + [metaString appendString:[NSString stringWithFormat:@"// Host: %@ (MySQL %@)\n", + [tableDocumentInstance host], [tableDocumentInstance mySQLVersion]]]; + [metaString appendString:[NSString stringWithFormat:@"// Database: %@\n", [tableDocumentInstance database]]]; + [metaString appendString:[NSString stringWithFormat:@"// Generation Time: %@\n", [NSDate date]]]; + [metaString appendString:@"// ************************************************************\n\n"]; + + [metaString appendString:@"digraph \"Database Structure\" {\n"]; + [metaString appendString:[NSString stringWithFormat:@"\tlabel = \"ER Diagram: %@\";\n", [tableDocumentInstance database]]]; + [metaString appendString:@"\tlabelloc = t;\n"]; + [metaString appendString:@"\tcompound = true;\n"]; + [metaString appendString:@"\tnode [ shape = record ];\n"]; + [metaString appendString:@"\tfontsize = 11;\n"]; + [metaString appendString:@"\tfontname = \"Helvetica\";\n"]; + [metaString appendString:@"\tranksep = 2.5;\n"]; + [metaString appendString:@"\tratio = 0.7;\n"]; + [metaString appendString:@"\trankdir = global;\n"]; + + // Write information to the file + [fileHandle writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]]; + + // store connection encoding + previousConnectionEncoding = [tableDocumentInstance connectionEncoding]; + previousConnectionEncodingViaLatin1 = [tableDocumentInstance connectionEncodingViaLatin1]; + + + // tables here + for ( int i = 0 ; i < [tables count] ; i++ ) { + + NSString *tableName = [[tables objectAtIndex:i] objectAtIndex:1]; + + [singleProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %i of %i (%@): Fetching data...", @"text showing that app is fetching data for table dump"), (i+1), [tables count], tableName]]; + [singleProgressText displayIfNeeded]; + [singleProgressBar setIndeterminate:YES]; + [singleProgressBar setUsesThreadedAnimation:YES]; + [singleProgressBar startAnimation:self]; + + + [metaString setString:[NSString stringWithFormat:@"\tsubgraph \"table_%@\" {\n", tableName]]; + [metaString appendString:@"\t\tnode = [ shape = \"plaintext\" ];\n"]; + [metaString appendString:[NSString stringWithFormat:@"\t\t\"%@\" [ label=<\n", tableName]]; + [metaString appendString:@"\t\t\t\n"]; + [metaString appendString:[NSString stringWithFormat:@"\t\t\t\n", tableName]]; + + // grab column info + CMMCPResult *theResult = [[mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [tableName backtickQuotedString]]] retain]; + + if ([theResult numOfRows]) + [theResult dataSeek:0]; + for ( int j = 0 ; j < [theResult numOfRows] ; j++ ) { + NSMutableDictionary *tempRow = [NSMutableDictionary dictionaryWithDictionary:[theResult fetchRowAsDictionary]]; + [metaString appendString:[NSString stringWithFormat:@"\t\t\t\n", [tempRow objectForKey:@"Field"]]]; + } + + [theResult release]; + + [metaString appendString:@"\t\t\t
%@
%@
>\n"]; + [metaString appendString:@"\t\t];\n"]; + [metaString appendString:@"\t}\n"]; + [fileHandle writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]]; + } + + [singleProgressText setStringValue:NSLocalizedString(@"Fetching relations...", @"text showing that app is fetching data")]; + [singleProgressText displayIfNeeded]; + [singleProgressBar setIndeterminate:YES]; + [singleProgressBar setUsesThreadedAnimation:YES]; + [singleProgressBar startAnimation:self]; + + [metaString setString:@"\n"]; + + // grab the relations + CMMCPResult *theResult = [[mySQLConnection queryString: + [NSString stringWithFormat:@"SELECT CONCAT( table_name, ' -> ', referenced_table_name ) AS list_of_fks FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = ('%@') AND REFERENCED_TABLE_NAME is not null ORDER BY TABLE_NAME, COLUMN_NAME", + [tableDocumentInstance database]]] retain]; + + if ([theResult numOfRows]) + [theResult dataSeek:0]; + for ( int i = 0 ; i < [theResult numOfRows] ; i++ ) { + [metaString appendString:[NSString stringWithFormat:@"%@ [ color=grey, arrowhead=crow, arrowtail=inv];\n", [[theResult fetchRowAsDictionary] objectForKey:@"list_of_fks"]]]; + } + + [theResult release]; + + // done + [metaString appendString:@"}\n"]; + + // Write information to the file + [fileHandle writeData:[metaString dataUsingEncoding:NSUTF8StringEncoding]]; + + // Restore the connection character set to pre-export details + [tableDocumentInstance + setConnectionEncoding:[NSString stringWithFormat:@"%@%@", previousConnectionEncoding, previousConnectionEncodingViaLatin1?@"-":@""] + reloadingViews:NO]; + + + // Close the progress sheet + [NSApp endSheet:singleProgressSheet]; + [singleProgressSheet orderOut:nil]; + + + return TRUE; +} + + /* Takes an array and writes it in CSV format to the supplied NSFileHandle */ -- cgit v1.2.3