diff options
author | mtvee <emptyvee@gmail.com> | 2009-05-14 20:41:57 +0000 |
---|---|---|
committer | mtvee <emptyvee@gmail.com> | 2009-05-14 20:41:57 +0000 |
commit | 840079ef1085b588b5c30f666f9c3ac2af65b291 (patch) | |
tree | dab7cd3046cd99011538cb29000c2988577403d6 /Source | |
parent | be4aac5c809f8f74c20f1d7b03a932e5ee0720df (diff) | |
download | sequelpro-840079ef1085b588b5c30f666f9c3ac2af65b291.tar.gz sequelpro-840079ef1085b588b5c30f666f9c3ac2af65b291.tar.bz2 sequelpro-840079ef1085b588b5c30f666f9c3ac2af65b291.zip |
preliminary support for constraint editing
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPTableData.h | 2 | ||||
-rw-r--r-- | Source/SPTableData.m | 114 | ||||
-rw-r--r-- | Source/TableDocument.h | 2 | ||||
-rw-r--r-- | Source/TableDocument.m | 22 | ||||
-rw-r--r-- | Source/TableRelations.h | 72 | ||||
-rw-r--r-- | Source/TableRelations.m | 219 |
6 files changed, 430 insertions, 1 deletions
diff --git a/Source/SPTableData.h b/Source/SPTableData.h index 099b1e22..d1398844 100644 --- a/Source/SPTableData.h +++ b/Source/SPTableData.h @@ -30,6 +30,7 @@ NSMutableArray *columns; NSMutableArray *columnNames; + NSMutableArray *constraints; NSMutableDictionary *status; NSString *tableEncoding; @@ -42,6 +43,7 @@ - (NSDictionary *) columnWithName:(NSString *)colName; - (NSArray *) columnNames; - (NSDictionary *) columnAtIndex:(int)index; +- (NSArray *) getConstraints; - (BOOL) columnIsBlobOrText:(NSString *)colName; - (NSString *) statusValueForKey:(NSString *)aKey; - (NSDictionary *) statusValues; diff --git a/Source/SPTableData.m b/Source/SPTableData.m index 4ed5823a..23f3f396 100644 --- a/Source/SPTableData.m +++ b/Source/SPTableData.m @@ -39,6 +39,7 @@ if ((self = [super init])) { columns = [[NSMutableArray alloc] init]; columnNames = [[NSMutableArray alloc] init]; + constraints = [[NSMutableArray alloc] init]; status = [[NSMutableDictionary alloc] init]; tableEncoding = nil; mySQLConnection = nil; @@ -89,6 +90,10 @@ return columns; } +- (NSArray *) getConstraints +{ + return constraints; +} /* * Retrieve a column with a specified name, using or refreshing the cache as appropriate. @@ -225,6 +230,7 @@ if (tableData == nil ) { [columns removeAllObjects]; [columnNames removeAllObjects]; + [constraints removeAllObjects]; return FALSE; } @@ -260,6 +266,8 @@ NSString *encodingString; unsigned i, stringStart; + [constraints removeAllObjects]; + // Catch unselected tables and return nil if ([tableName isEqualToString:@""] || !tableName) return nil; @@ -342,7 +350,109 @@ // TODO: Otherwise it's a key definition, constraint, check, or other 'metadata'. Would be useful to parse/display these! } else { - + NSArray *parts = [fieldsParser splitStringByCharacter:' ' skippingBrackets:YES ignoringQuotedStrings:YES]; + NSCharacterSet *junk = [NSCharacterSet characterSetWithCharactersInString:@"`()"]; + // constraints + if( [[parts objectAtIndex:0] hasPrefix:@"CONSTRAINT"] ) { + NSMutableDictionary *constraintDetails = [[NSMutableDictionary alloc] init]; + /* + NSLog( @"constraint %@ on %@ ref %@.%@", + [[parts objectAtIndex:1] stringByTrimmingCharactersInSet:junk], + [[parts objectAtIndex:4] stringByTrimmingCharactersInSet:junk], + [[parts objectAtIndex:6] stringByTrimmingCharactersInSet:junk], + [[parts objectAtIndex:7] stringByTrimmingCharactersInSet:junk] ); + */ + [constraintDetails setObject:[[parts objectAtIndex:1] stringByTrimmingCharactersInSet:junk] + forKey:@"name"]; + [constraintDetails setObject:[[parts objectAtIndex:4] stringByTrimmingCharactersInSet:junk] + forKey:@"columns"]; + [constraintDetails setObject:[[parts objectAtIndex:6] stringByTrimmingCharactersInSet:junk] + forKey:@"ref_table"]; + [constraintDetails setObject:[[parts objectAtIndex:7] stringByTrimmingCharactersInSet:junk] + forKey:@"ref_columns"]; + + int nextOffs = 12; + if( [parts count] > 8 ) { + // NOTE: this won't get SET NULL | NO ACTION + if( [[parts objectAtIndex:9] hasPrefix:@"UPDATE"] ) { + //NSLog( @"update: %@", [parts objectAtIndex:10] ); + if( [[parts objectAtIndex:10] hasPrefix:@"SET"] ) { + [constraintDetails setObject:@"SET NULL" + forKey:@"update"]; + nextOffs = 13; + } else if( [[parts objectAtIndex:10] hasPrefix:@"NO"] ) { + [constraintDetails setObject:@"NO ACTION" + forKey:@"update"]; + nextOffs = 13; + } else { + [constraintDetails setObject:[parts objectAtIndex:10] + forKey:@"update"]; + } + } + else if( [[parts objectAtIndex:9] hasPrefix:@"DELETE"] ) { + //NSLog( @"delete: %@", [parts objectAtIndex:10] ); + if( [[parts objectAtIndex:10] hasPrefix:@"SET"] ) { + [constraintDetails setObject:@"SET NULL" + forKey:@"delete"]; + nextOffs = 13; + } else if( [[parts objectAtIndex:10] hasPrefix:@"NO"] ) { + [constraintDetails setObject:@"NO ACTION" + forKey:@"delete"]; + nextOffs = 13; + } else { + [constraintDetails setObject:[parts objectAtIndex:10] + forKey:@"delete"]; + } + } + } + if( [parts count] > nextOffs - 1 ) { + if( [[parts objectAtIndex:nextOffs] hasPrefix:@"UPDATE"] ) { + //NSLog( @"update: %@", [parts objectAtIndex:13] ); + if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"SET"] ) { + [constraintDetails setObject:@"SET NULL" + forKey:@"update"]; + nextOffs = 13; + } else if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"NO"] ) { + [constraintDetails setObject:@"NO ACTION" + forKey:@"update"]; + nextOffs = 13; + } else { + [constraintDetails setObject:[parts objectAtIndex:nextOffs+1] + forKey:@"update"]; + } + } + else if( [[parts objectAtIndex:nextOffs] hasPrefix:@"DELETE"] ) { + //NSLog( @"delete: %@", [parts objectAtIndex:13] ); + if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"SET"] ) { + [constraintDetails setObject:@"SET NULL" + forKey:@"delete"]; + nextOffs = 13; + } else if( [[parts objectAtIndex:nextOffs+1] hasPrefix:@"NO"] ) { + [constraintDetails setObject:@"NO ACTION" + forKey:@"delete"]; + nextOffs = 13; + } else { + [constraintDetails setObject:[parts objectAtIndex:nextOffs+1] + forKey:@"delete"]; + } + } + } + [constraints addObject:constraintDetails]; + } + // primary key + else if( [[parts objectAtIndex:0] hasPrefix:@"PRIMARY"] ) { + NSLog( @"pkey is %@", [[parts objectAtIndex:2] stringByTrimmingCharactersInSet:junk] ); + } + // key + else if( [[parts objectAtIndex:0] hasPrefix:@"KEY"] ) { + NSLog( @"key %@.%@", + [[parts objectAtIndex:1] stringByTrimmingCharactersInSet:junk], + [[parts objectAtIndex:2] stringByTrimmingCharactersInSet:junk] ); + } + // who knows + else { + NSLog( @"not parsed: %@", [parts objectAtIndex:0] ); + } } } [fieldStrings release]; @@ -400,6 +510,7 @@ if (viewData == nil) { [columns removeAllObjects]; [columnNames removeAllObjects]; + [constraints removeAllObjects]; return FALSE; } @@ -718,6 +829,7 @@ { [columns release]; [columnNames release]; + [constraints release]; [status release]; if (tableEncoding != nil) [tableEncoding release]; diff --git a/Source/TableDocument.h b/Source/TableDocument.h index 33a70e90..b24977f5 100644 --- a/Source/TableDocument.h +++ b/Source/TableDocument.h @@ -39,6 +39,7 @@ IBOutlet id tablesListInstance; IBOutlet id tableSourceInstance; IBOutlet id tableContentInstance; + IBOutlet id tableRelationsInstance; IBOutlet id customQueryInstance; IBOutlet id tableDumpInstance; IBOutlet id tableDataInstance; @@ -188,6 +189,7 @@ - (IBAction)viewContent:(id)sender; - (IBAction)viewQuery:(id)sender; - (IBAction)viewStatus:(id)sender; +- (IBAction)viewRelations:(id)sender; - (IBAction)addConnectionToFavorites:(id)sender; //toolbar methods diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 3e666cfd..f292e691 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -333,6 +333,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum [tablesListInstance setConnection:mySQLConnection]; [tableSourceInstance setConnection:mySQLConnection]; [tableContentInstance setConnection:mySQLConnection]; + [tableRelationsInstance setConnection:mySQLConnection]; [customQueryInstance setConnection:mySQLConnection]; [customQueryInstance setMySQLversion:mySQLVersion]; [tableDumpInstance setConnection:mySQLConnection]; @@ -1622,6 +1623,27 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum [mainToolbar setSelectedItemIdentifier:@"SwitchToTableStatusToolbarItemIdentifier"]; } +- (IBAction)viewRelations:(id)sender +{ + // Cancel the selection if currently editing structure/a field and unable to save + if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 0 + && ![tableSourceInstance saveRowOnDeselect]) { + [mainToolbar setSelectedItemIdentifier:@"SwitchToTableStructureToolbarItemIdentifier"]; + return; + } + + // Cancel the selection if currently editing a content row and unable to save + if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 1 + && ![tableContentInstance saveRowOnDeselect]) { + [mainToolbar setSelectedItemIdentifier:@"SwitchToTableContentToolbarItemIdentifier"]; + return; + } + + [tableTabView selectTabViewItemAtIndex:4]; + [mainToolbar setSelectedItemIdentifier:@"SwitchToTableStatusToolbarItemIdentifier"]; +} + + /** * Adds the current database connection details to the user's favorites if it doesn't already exist. */ diff --git a/Source/TableRelations.h b/Source/TableRelations.h new file mode 100644 index 00000000..9e385e95 --- /dev/null +++ b/Source/TableRelations.h @@ -0,0 +1,72 @@ +// +// TableRelations.h +// sequel-pro +// +// Created by J Knight on 13/05/09. +// Copyright 2009 TalonEdge Ltd.. All rights reserved. +// + +#import <Cocoa/Cocoa.h> +#import <MCPKit_bundled/MCPKit_bundled.h> + +@class CMMCPConnection, CMMCPResult, CMCopyTable; + +@interface TableRelations : NSObject { + + IBOutlet id tableDocumentInstance; + IBOutlet id tablesListInstance; + IBOutlet id tableList; + IBOutlet id tableWindow; + IBOutlet id tableDataInstance; + IBOutlet id addButton; + IBOutlet id removeButton; + IBOutlet id labelText; + IBOutlet id relationsView; + IBOutlet id relationSheet; + + IBOutlet id tableBox; + IBOutlet id columnSelect; + IBOutlet id refTableSelect; + IBOutlet id refColumnSelect; + IBOutlet id onUpdateSelect; + IBOutlet id onDeleteSelect; + + + CMMCPConnection *mySQLConnection; + + NSMutableArray *relData; +} + +- (void)setConnection:(CMMCPConnection *)theConnection; + +//edit methods +- (IBAction)addRow:(id)sender; +- (IBAction)removeRow:(id)sender; +- (IBAction)closeRelationSheet:(id)sender; +- (IBAction)addRelation:(id)sender; +- (IBAction)chooseRefTable:(id)sender; + +- (IBAction)refresh:(id)sender; + +- (void)tableChanged:(NSNotification *)notification; + +//tableView datasource methods +- (int)numberOfRowsInTableView:(NSTableView *)aTableView; +- (id)tableView:(NSTableView *)aTableView +objectValueForTableColumn:(NSTableColumn *)aTableColumn + row:(int)rowIndex; +- (void)tableView:(NSTableView *)aTableView + setObjectValue:(id)anObject + forTableColumn:(NSTableColumn *)aTableColumn + row:(int)rowIndex; + +//tableView delegate methods +- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn; +- (void)tableViewSelectionDidChange:(NSNotification *)aNotification; +- (void)tableViewSelectionIsChanging:(NSNotification *)aNotification; +- (void)tableViewColumnDidResize:(NSNotification *)aNotification; +- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; +- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard; +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command; + +@end diff --git a/Source/TableRelations.m b/Source/TableRelations.m new file mode 100644 index 00000000..60f19aca --- /dev/null +++ b/Source/TableRelations.m @@ -0,0 +1,219 @@ +// +// TableRelations.m +// sequel-pro +// +// Created by J Knight on 13/05/09. +// Copyright 2009 TalonEdge Ltd.. All rights reserved. +// + +#import "TableRelations.h" +#import "TableDocument.h" +#import "TablesList.h" +#import "CMMCPConnection.h" +#import "CMMCPResult.h" +#import "SPTableData.h" + +@implementation TableRelations + +- (id)init +{ + if (![super init]) + return nil; + + relData = [[NSMutableArray alloc] init]; + + return self; +} + +- (void)dealloc +{ + [relData release], relData = nil; + + [super dealloc]; +} + +- (void)awakeFromNib +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(tableChanged:) + name:NSTableViewSelectionDidChangeNotification + object:tableList]; +} + +- (void)setConnection:(CMMCPConnection *)theConnection +{ + mySQLConnection = theConnection; +} + +- (IBAction)closeRelationSheet:(id)sender +{ + [NSApp stopModalWithCode:1]; +} + +- (IBAction)addRelation:(id)sender +{ + [NSApp stopModalWithCode:0]; +} + +// user choose a reference table +- (IBAction)chooseRefTable:(id)sender +{ + NSString *table = [refTableSelect titleOfSelectedItem]; + + [refColumnSelect removeAllItems]; + + NSDictionary *info = [tableDataInstance informationForTable:table]; + NSArray *cols = [info objectForKey:@"columns"]; + NSMutableArray *colNames = [[NSMutableArray alloc] init]; + for( int i = 0; i < [cols count]; i++ ) { + [colNames addObject:[[cols objectAtIndex:i] objectForKey:@"name"]]; + } + [refColumnSelect addItemsWithTitles:colNames]; + [colNames release]; +} + +- (IBAction)addRow:(id)sender +{ + // set up the controls + [tableBox setTitle:[NSString stringWithFormat:@"Table: %@",[tablesListInstance tableName] ]]; + [columnSelect removeAllItems]; + [columnSelect addItemsWithTitles:[tableDataInstance columnNames]]; + [refTableSelect removeAllItems]; + // grab only real tables + NSArray *tables = [tablesListInstance tables]; + NSArray *types = [tablesListInstance tableTypes]; + NSMutableArray *validTables = [[NSMutableArray alloc] init]; + for( int i = 0; i < [tables count]; i++ ) { + NSLog( @"%@ %@", [tables objectAtIndex:i], [types objectAtIndex:i] ); + if( [[types objectAtIndex:i] intValue] == SP_TABLETYPE_TABLE ) { + [validTables addObject:[tables objectAtIndex:i]]; + } + } + [refTableSelect addItemsWithTitles:validTables]; + [validTables release]; + [self chooseRefTable:nil]; + + [NSApp beginSheet:relationSheet + modalForWindow:tableWindow + modalDelegate:self + didEndSelector:nil + contextInfo:nil]; + + + [NSApp runModalForWindow:relationSheet]; + + [NSApp endSheet:relationSheet]; + [relationSheet orderOut:nil]; +} + +- (IBAction)removeRow:(id)sender +{ + if ( [relationsView numberOfSelectedRows] ) { + int resp = NSRunAlertPanel(@"Remove Relations", + @"Are you sure you want to remove the selected relations?", + @"OK", @"Cancel", nil ); + if( resp == NSAlertDefaultReturn ) { + + } + } +} + +- (IBAction)refresh:(id)sender +{ + + [relData removeAllObjects]; + + if( [tablesListInstance tableType] == SP_TABLETYPE_TABLE ) { + [labelText setStringValue:[NSString stringWithFormat:@"Relations for table: %@",[tablesListInstance tableName]]]; + [tableDataInstance updateInformationForCurrentTable]; + NSArray *constraints = [tableDataInstance getConstraints]; + for( int i = 0; i < [constraints count]; i++ ) { + [relData addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [tablesListInstance tableName], @"table", + [[constraints objectAtIndex:i] objectForKey:@"name"], @"name", + [[constraints objectAtIndex:i] objectForKey:@"columns"], @"columns", + [[constraints objectAtIndex:i] objectForKey:@"ref_table"], @"fk_table", + [[constraints objectAtIndex:i] objectForKey:@"ref_columns"], @"fk_columns", + [[constraints objectAtIndex:i] objectForKey:@"update"], @"on_update", + [[constraints objectAtIndex:i] objectForKey:@"delete"], @"on_delete", + nil]]; + + } + } else { + [labelText setStringValue:@""]; + } + + [relationsView reloadData]; + +} + +- (void)tableChanged:(NSNotification *)notification +{ + if( [tablesListInstance tableType] == SP_TABLETYPE_TABLE ) { + [addButton setEnabled:YES]; + } else { + [addButton setEnabled:NO]; + } + + [self refresh:nil]; +} + + +//tableView datasource methods +- (int)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return [relData count]; +} + +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn + row:(int)rowIndex +{ + //NSNumber *theIdentifier = [aTableColumn identifier]; + NSDictionary *theRow = [relData objectAtIndex:rowIndex]; + return [theRow objectForKey:[aTableColumn identifier]]; +} + +- (void)tableView:(NSTableView *)aTableView + setObjectValue:(id)anObject + forTableColumn:(NSTableColumn *)aTableColumn + row:(int)rowIndex +{ + +} + +//tableView delegate methods +- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn *)tableColumn +{ + +} +- (void)tableViewSelectionDidChange:(NSNotification *)aNotification +{ + if ( [relationsView numberOfSelectedRows] ) { + [removeButton setEnabled:YES]; + } else { + [removeButton setEnabled:NO]; + } +} +- (void)tableViewSelectionIsChanging:(NSNotification *)aNotification +{ + +} +- (void)tableViewColumnDidResize:(NSNotification *)aNotification +{ + +} +- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex +{ + return NO; +} +- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard +{ + return FALSE; +} +- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command +{ + return FALSE; +} + + +@end |