static NSString *GCSPathRecordName = @"c_path";
static NSString *GCSGenericFolderTypeName = @"Container";
static const char *GCSPathColumnPattern = "c_path%i";
+static NSCharacterSet *asciiAlphaNumericCS = nil;
+ (void)initialize {
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
debugOn = [ud boolForKey:@"GCSFolderManagerDebugEnabled"];
debugSQLGen = [ud boolForKey:@"GCSFolderManagerSQLDebugEnabled"];
emptyArray = [[NSArray alloc] init];
+ if (!asciiAlphaNumericCS)
+ {
+ asciiAlphaNumericCS
+ = [NSCharacterSet characterSetWithCharactersInString:
+ @"0123456789"
+ @"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ @"abcdefghijklmnopqrstuvwxyz"];
+ [asciiAlphaNumericCS retain];
+ }
}
+ (id)defaultFolderManager {
if ((self = [super init])) {
self->channelManager = [[GCSChannelManager defaultChannelManager] retain];
self->folderInfoLocation = [_url retain];
+ self->folderNamePrefix = nil;
if ([[self folderInfoTableName] length] == 0) {
[self logWithFormat:@"ERROR(%s): missing tablename in URL: %@",
[self->nameToType release];
[self->folderInfoLocation release];
[self->channelManager release];
+ [self->folderNamePrefix release];
[super dealloc];
}
/* accessors */
+- (void) setFolderNamePrefix:(NSString *)_folderNamePrefix
+{
+ ASSIGN(self->folderNamePrefix, _folderNamePrefix);
+}
+
+- (NSString *) folderNamePrefix
+{
+ return self->folderNamePrefix;
+}
+
- (NSURL *)folderInfoLocation {
return self->folderInfoLocation;
}
return [self folderForRecord:record];
}
+- (NSString *)sqlCreateWithTableName: (NSString *)_tabName {
+ return [NSString stringWithFormat: @"CREATE TABLE %@ (\n"
+ @" c_name VARCHAR (256) NOT NULL,\n"
+ @" c_content VARCHAR (100000) NOT NULL,\n"
+ @" c_creationdate INT4 NOT NULL,\n"
+ @" c_lastmodified INT4 NOT NULL,\n"
+ @" c_version INT4 NOT NULL\n"
+ @")",
+ _tabName];
+}
+
+- (NSString *)sqlAclCreateWithTableName: (NSString *)_tabName {
+ return [NSString stringWithFormat: @"CREATE TABLE %@ (\n"
+ @" c_uid VARCHAR (256) NOT NULL,\n"
+ @" c_object VARCHAR (256) NOT NULL,\n"
+ @" c_role VARCHAR (80) NOT NULL\n"
+ @")",
+ _tabName];
+}
+
+- (NSString *)baseTableNameForFolderAtPath:(NSString *)_path {
+ NSMutableString *fixedPath;
+ unsigned int count, max;
+ unichar currentChar;
+
+ fixedPath = [NSMutableString new];
+ [fixedPath autorelease];
+
+ if (self->folderNamePrefix != nil)
+ [fixedPath appendString: self->folderNamePrefix];
+
+ max = [_path length];
+ for (count = 0; count < max; count++) {
+ currentChar = [_path characterAtIndex: count];
+ if ([asciiAlphaNumericCS characterIsMember: currentChar])
+ [fixedPath appendFormat: @"%Lc", currentChar];
+ else
+ [fixedPath appendString: @"_"];
+ }
+
+ return (([fixedPath length] < 49)
+ ? (NSString *)fixedPath : [fixedPath substringToIndex: 49]);
+}
+
+- (NSString *)finalizedTableNameForBaseName:(NSString *)_baseName
+ atBaseURL:(NSString *)_baseURL
+ withChannel:(EOAdaptorChannel *)_channel {
+ NSString *potentialName, *sqlTestFormat, *sqlTest;
+ unsigned int count;
+
+ potentialName = _baseName;
+ sqlTestFormat = [NSString stringWithFormat: @"SELECT * FROM %@"
+ @" WHERE c_location = '%@/%%@'"
+ @" OR c_quick_location = '%@/%%@_quick'"
+ @" OR c_acl_location = '%@/%%@_acl'",
+ [self folderInfoTableName],
+ _baseURL, _baseURL, _baseURL];
+
+ sqlTest = [NSString stringWithFormat: sqlTestFormat,
+ potentialName, potentialName, potentialName];
+ count = 0;
+ while ([[self performSQL: sqlTest] count] > 0) {
+ count++;
+ potentialName = [NSString stringWithFormat: @"%@%d", _baseName, count];
+ sqlTest = [NSString stringWithFormat: sqlTestFormat,
+ potentialName, potentialName, potentialName];
+ }
+
+ return potentialName;
+}
+
- (NSException *)createFolderOfType:(NSString *)_type atPath:(NSString *)_path{
- // TODO: implement folder create
GCSFolderType *ftype;
-
+ NSString *tableName, *quickTableName, *aclTableName;
+ NSString *baseURL;
+ EOAdaptorChannel *channel;
+ NSMutableArray *paths;
+
+ if ([[self performSQL: [NSString stringWithFormat: @"SELECT * FROM %@"
+ @" WHERE c_path = '%@'",
+ [self folderInfoTableName], _path]]
+ count] > 0) {
+ return [NSException exceptionWithName:@"GCSExitingFolder"
+ reason:@"a folder already exists at that path"
+ userInfo:nil];
+ }
if ((ftype = [self folderTypeWithName:_type]) == nil) {
return [NSException exceptionWithName:@"GCSMissingFolderType"
- reason:@"missing folder type"
+ reason:@"missing folder type"userInfo:nil];
+ }
+ if ((channel = [self acquireOpenChannel]) == nil) {
+ return [NSException exceptionWithName:@"GCSNoChannel"
+ reason:@"could not open channel"
userInfo:nil];
}
-
- [self logWithFormat:@"create folder of type: %@", ftype];
-
- return [NSException exceptionWithName:@"NotYetImplemented"
- reason:@"no money, no time, ..."
- userInfo:nil];
+
+ tableName = [self baseTableNameForFolderAtPath: _path];
+ baseURL
+ = [[folderInfoLocation absoluteString] stringByDeletingLastPathComponent];
+ tableName = [self finalizedTableNameForBaseName: tableName
+ atBaseURL: baseURL withChannel: channel];
+ quickTableName = [NSString stringWithFormat: @"%@_quick", tableName];
+ aclTableName = [NSString stringWithFormat: @"%@_acl", tableName];
+
+ [channel evaluateExpressionX:
+ [NSString stringWithFormat: @"DROP TABLE %@", tableName]];
+ [channel evaluateExpressionX:
+ [NSString stringWithFormat: @"DROP TABLE %@", quickTableName]];
+ [channel evaluateExpressionX:
+ [NSString stringWithFormat: @"DROP TABLE %@", aclTableName]];
+ [channel evaluateExpressionX:
+ [self sqlCreateWithTableName: tableName]];
+ [channel evaluateExpressionX:
+ [ftype sqlQuickCreateWithTableName: quickTableName]];
+ [channel evaluateExpressionX:
+ [self sqlAclCreateWithTableName: aclTableName]];
+
+ paths = [NSMutableArray
+ arrayWithArray: [_path componentsSeparatedByString: @"/"]];
+ while ([paths count] < 5)
+ [paths addObject: @""];
+
+ [channel evaluateExpressionX:
+ [NSString stringWithFormat: @"INSERT INTO %@"
+ @" (c_path, c_path1, c_path2, c_path3, c_path4,"
+ @" c_foldername, c_location, c_quick_location,"
+ @" c_acl_location, c_folder_type)"
+ @" VALUES ('%@', '%@', '%@', '%@', '%@', '%@', '%@/%@',"
+ @" '%@/%@', '%@/%@', '%@')",
+ [self folderInfoTableName], _path,
+ [paths objectAtIndex: 1], [paths objectAtIndex: 2],
+ [paths objectAtIndex: 3], [paths objectAtIndex: 4],
+ [_path lastPathComponent],
+ baseURL, tableName,
+ baseURL, quickTableName,
+ baseURL, aclTableName,
+ _type]];
+
+ [self releaseChannel: channel];
+
+ return nil;
+}
+
+- (NSException *)deleteFolderAtPath:(NSString *)_path {
+ GCSFolder *folder;
+ NSArray *fnames;
+ NSString *sql, *ws;
+ EOAdaptorChannel *channel;
+ NSException *ex;
+
+ if ((folder = [self folderAtPath:_path]) == nil) {
+ return [NSException exceptionWithName:@"GCSMissingFolder"
+ reason:@"missing folder"
+ userInfo:nil];
+ }
+
+ if ((fnames = [self internalNamesFromPath:_path]) == nil) {
+ [self debugWithFormat:@"got no internal names for path: '%@'", _path];
+ return nil;
+ }
+
+ ws = [self generateSQLWhereForInternalNames:fnames
+ exactMatch:YES orDirectSubfolderMatch:NO];
+
+ sql = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@",
+ [self folderInfoTableName], ws];
+ if ((channel = [self acquireOpenChannel]) == nil) {
+ return [NSException exceptionWithName:@"GCSNoChannel"
+ reason:@"could not "
+ userInfo:nil];
+ }
+
+ if ((ex = [channel evaluateExpressionX:sql]) != nil) {
+ [self releaseChannel:channel];
+ return ex;
+ }
+
+ [self releaseChannel:channel];
+
+ return [folder deleteFolder];
}
/* folder types */