diff options
Diffstat (limited to 'Frameworks')
20 files changed, 287 insertions, 53 deletions
diff --git a/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj b/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj index d84389e0..decc195b 100644 --- a/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj +++ b/Frameworks/QueryKit/QueryKit.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 1719E4BD151F51F1003F98C5 /* QKUpdateQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1719E4BA151F51EA003F98C5 /* QKUpdateQueryTests.m */; }; 1726972915AAF6CE009586E1 /* QKQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1726972815AAF6CE009586E1 /* QKQueryTests.m */; }; 1726976715AC3DD2009586E1 /* QKQueryDatabases.h in Headers */ = {isa = PBXBuildFile; fileRef = 1726976515AC3DD2009586E1 /* QKQueryDatabases.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1726979515AEE939009586E1 /* QKQueryStringAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1726979315AEE939009586E1 /* QKQueryStringAdditions.h */; }; + 1726979615AEE939009586E1 /* QKQueryStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1726979415AEE939009586E1 /* QKQueryStringAdditions.m */; }; 17577F6715A98FEA00CDF67A /* QKTestConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 17577F6615A98FEA00CDF67A /* QKTestConstants.m */; }; 17577FC615A99AC000CDF67A /* QKQueryConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 17577FC415A99AC000CDF67A /* QKQueryConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1757801E15A9A14400CDF67A /* QKQueryGenericParameter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1757801C15A9A14400CDF67A /* QKQueryGenericParameter.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -55,6 +57,8 @@ 1726972715AAF6CE009586E1 /* QKQueryTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKQueryTests.h; sourceTree = "<group>"; }; 1726972815AAF6CE009586E1 /* QKQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QKQueryTests.m; sourceTree = "<group>"; }; 1726976515AC3DD2009586E1 /* QKQueryDatabases.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKQueryDatabases.h; sourceTree = "<group>"; }; + 1726979315AEE939009586E1 /* QKQueryStringAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKQueryStringAdditions.h; sourceTree = "<group>"; }; + 1726979415AEE939009586E1 /* QKQueryStringAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QKQueryStringAdditions.m; sourceTree = "<group>"; }; 17577F6515A98FEA00CDF67A /* QKTestConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKTestConstants.h; sourceTree = "<group>"; }; 17577F6615A98FEA00CDF67A /* QKTestConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QKTestConstants.m; sourceTree = "<group>"; }; 17577FC415A99AC000CDF67A /* QKQueryConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKQueryConstants.h; sourceTree = "<group>"; }; @@ -218,6 +222,8 @@ isa = PBXGroup; children = ( 17577FC415A99AC000CDF67A /* QKQueryConstants.h */, + 1726979315AEE939009586E1 /* QKQueryStringAdditions.h */, + 1726979415AEE939009586E1 /* QKQueryStringAdditions.m */, ); name = Other; sourceTree = "<group>"; @@ -261,6 +267,7 @@ 17577FC615A99AC000CDF67A /* QKQueryConstants.h in Headers */, 1757801E15A9A14400CDF67A /* QKQueryGenericParameter.h in Headers */, 1726976715AC3DD2009586E1 /* QKQueryDatabases.h in Headers */, + 1726979515AEE939009586E1 /* QKQueryStringAdditions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -379,6 +386,7 @@ 17E5952614F301DF0054EE08 /* QKQueryUtilities.m in Sources */, 1719E47E151E8CA7003F98C5 /* QKQueryUpdateParameter.m in Sources */, 1757801F15A9A14400CDF67A /* QKQueryGenericParameter.m in Sources */, + 1726979615AEE939009586E1 /* QKQueryStringAdditions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Frameworks/QueryKit/Source/QKQuery.h b/Frameworks/QueryKit/Source/QKQuery.h index e3b7f148..117da9b3 100644 --- a/Frameworks/QueryKit/Source/QKQuery.h +++ b/Frameworks/QueryKit/Source/QKQuery.h @@ -29,6 +29,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #import "QKQueryTypes.h" +#import "QKQueryDatabases.h" #import "QKQueryOperators.h" #import "QKQueryParameter.h" #import "QKQueryUpdateParameter.h" @@ -44,6 +45,7 @@ { NSString *_database; NSString *_table; + NSString *_identifierQuote; NSMutableString *_query; @@ -54,8 +56,9 @@ NSMutableArray *_orderByFields; QKQueryType _queryType; + QKQueryDatabase _queryDatabase; - BOOL _useQuotes; + BOOL _useQuotedIdentifiers; BOOL _orderDescending; } @@ -90,23 +93,43 @@ @property(readwrite, assign, getter=queryType, setter=setQueryType:) QKQueryType _queryType; /** - * @property _useQuotes Indicates whether or not the query's fields should be quoted. + * @property _queryDatabase The underlying database system this query will be run against. */ -@property(readwrite, assign, getter=useQuotes) BOOL _useQuotes; +@property(readwrite, assign, getter=queryDatabase, setter=setQueryDatabase:) QKQueryDatabase _queryDatabase; +/** + * @property _useQuotedIdentifiers Indicates whether or not the query's fields should be quoted. + */ +@property(readwrite, assign, getter=useQuotedIdentifiers) BOOL _useQuotedIdentifiers; + +/** + * @property _groupByFields The group by fields of the query. + */ @property(readonly, getter=groupByFields) NSMutableArray *_groupByFields; +/** + * @property _orderByFields The order by fields of the query. + */ @property(readonly, getter=orderByFields) NSMutableArray *_orderByFields; +/** + * @property _identifierQuote The character to use when quoting identifiers. + */ +@property(readonly, getter=identifierQuote) NSString *_identifierQuote; + + (QKQuery *)queryTable:(NSString *)table; ++ (QKQuery *)queryTable:(NSString *)table database:(NSString *)database; + + (QKQuery *)selectQueryFromTable:(NSString *)table; ++ (QKQuery *)selectQueryFromTable:(NSString *)table database:(NSString *)database; - (id)initWithTable:(NSString *)table; +- (id)initWithTable:(NSString *)table database:(NSString *)database; - (NSString *)query; - (void)clear; -- (void)setUseQuotes:(BOOL)quote; +- (void)setUseQuotedIdentifiers:(BOOL)quote; - (void)addField:(NSString *)field; - (void)addFields:(NSArray *)fields; diff --git a/Frameworks/QueryKit/Source/QKQuery.m b/Frameworks/QueryKit/Source/QKQuery.m index c60f3162..08499b8d 100644 --- a/Frameworks/QueryKit/Source/QKQuery.m +++ b/Frameworks/QueryKit/Source/QKQuery.m @@ -29,6 +29,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #import "QKQuery.h" +#import "QKQueryUtilities.h" #import "QKQueryConstants.h" #import "QKQueryGenericParameter.h" @@ -55,11 +56,13 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; @synthesize _database; @synthesize _table; +@synthesize _identifierQuote; @synthesize _parameters; @synthesize _queryType; +@synthesize _queryDatabase; @synthesize _fields; @synthesize _updateParameters; -@synthesize _useQuotes; +@synthesize _useQuotedIdentifiers; @synthesize _groupByFields; @synthesize _orderByFields; @@ -68,29 +71,54 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; + (QKQuery *)queryTable:(NSString *)table { - return [[[QKQuery alloc] initWithTable:table] autorelease]; + return [QKQuery queryTable:table database:nil]; +} + ++ (QKQuery *)queryTable:(NSString *)table database:(NSString *)database +{ + return [[[QKQuery alloc] initWithTable:table database:database] autorelease]; } + (QKQuery *)selectQueryFromTable:(NSString *)table +{ + return [QKQuery selectQueryFromTable:table database:nil]; +} + ++ (QKQuery *)selectQueryFromTable:(NSString *)table database:(NSString *)database { - QKQuery *query = [[[QKQuery alloc] initWithTable:table] autorelease]; + QKQuery *query = [[[QKQuery alloc] initWithTable:table database:database] autorelease]; [query setQueryType:QKSelectQuery]; return query; } +- (id)init +{ + return [self initWithTable:nil]; +} + - (id)initWithTable:(NSString *)table { + return [self initWithTable:table database:nil]; +} + +- (id)initWithTable:(NSString *)table database:(NSString *)database +{ if ((self = [super init])) { [self setTable:table]; + [self setDatabase:database]; [self setFields:[[NSMutableArray alloc] init]]; [self setUpdateParameters:[[NSMutableArray alloc] init]]; [self setParameters:[[NSMutableArray alloc] init]]; [self setQueryType:QKUnknownQuery]; - [self setUseQuotes:YES]; + [self setUseQuotedIdentifiers:YES]; + + // Default to MySQL + [self setQueryDatabase:QKDatabaseMySQL]; _orderDescending = NO; + _identifierQuote = EMPTY_STRING; _groupByFields = [[NSMutableArray alloc] init]; _orderByFields = [[NSMutableArray alloc] init]; @@ -111,7 +139,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; */ - (NSString *)query { - return _query ? [self _buildQuery] : @""; + return _query ? [self _buildQuery] : EMPTY_STRING; } /** @@ -121,31 +149,41 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; { [self setTable:nil]; [self setDatabase:nil]; - [self setUseQuotes:YES]; + [self setUseQuotedIdentifiers:YES]; [self setQueryType:QKUnknownQuery]; + [self setQueryDatabase:QKDatabaseUnknown]; [_fields removeAllObjects]; [_parameters removeAllObjects]; [_updateParameters removeAllObjects]; [_groupByFields removeAllObjects]; [_orderByFields removeAllObjects]; + + _identifierQuote = EMPTY_STRING; + + if (_query) [_query release], _query = [[NSMutableString alloc] init]; } #pragma mark - #pragma mark Accessors -- (void)setUseQuotes:(BOOL)quote +/** + * Sets whether to quote identifiers in the query. + * + * @param quote A BOOL indicating whether quoting should be used. + */ +- (void)setUseQuotedIdentifiers:(BOOL)quote { - _useQuotes = quote; + _useQuotedIdentifiers = quote; for (QKQueryParameter *param in _parameters) { - [param setUseQuotes:_useQuotes]; + [param setUseQuotedIdentifier:_useQuotedIdentifiers]; } for (QKQueryUpdateParameter *param in _updateParameters) { - [param setUseQuotes:_useQuotes]; + [param setUseQuotedIdentifier:_useQuotedIdentifiers]; } } @@ -154,6 +192,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Shortcut for adding a new field to this query. + * + * @param field The field to add. */ - (void)addField:(NSString *)field { @@ -163,7 +203,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Convenience method for adding more than one field. * - * @param The array (of strings) of fields to add. + * @param fields The array (of strings) of fields to add. */ - (void)addFields:(NSArray *)fields { @@ -190,6 +230,9 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Convenience method for adding a new parameter. + * + * @param field + * @param value */ - (void)addParameter:(NSString *)field operator:(QKQueryOperator)operator value:(id)value { @@ -213,6 +256,9 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Convenience method for adding a new update parameter. + * + * @param field + * @param value */ - (void)addFieldToUpdate:(NSString *)field toValue:(id)value { @@ -224,6 +270,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Adds the supplied field to the query's GROUP BY clause. + * + * @param field */ - (void)groupByField:(NSString *)field { @@ -232,6 +280,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Convenience method for adding more than one field to the query's GROUP BY clause. + * + * @param fields */ - (void)groupByFields:(NSArray *)fields { @@ -246,6 +296,9 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Adds the supplied field to the query's ORDER BY clause. + * + * @param field + * @param descending */ - (void)orderByField:(NSString *)field descending:(BOOL)descending { @@ -256,6 +309,9 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Convenience method for adding more than one field to the query's ORDER BY clause. + * + * @param fields + * @param descending */ - (void)orderByFields:(NSArray *)fields descending:(BOOL)descending { @@ -284,6 +340,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Builds the actual query. + * + * @return The built SQL query. */ - (NSString *)_buildQuery { @@ -294,6 +352,20 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; BOOL isUpdate = _queryType == QKUpdateQuery; BOOL isDelete = _queryType == QKDeleteQuery; + if ([self useQuotedIdentifiers]) { + _identifierQuote = [QKQueryUtilities identifierQuoteCharacterForDatabase:_queryDatabase]; + + for (QKQueryParameter *param in _parameters) + { + [param setIdentifierQuote:_identifierQuote]; + } + + for (QKQueryUpdateParameter *param in _updateParameters) + { + [param setIdentifierQuote:_identifierQuote]; + } + } + NSString *fields = [self _buildFieldList]; if (isSelect) { @@ -310,10 +382,10 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; } if (_database && [_database length] > 0) { - [_query appendFormat:@"%@%@%@.", _useQuotes ? QUERY_QUOTE : EMPTY_STRING, _database, _useQuotes ? QUERY_QUOTE : EMPTY_STRING]; + [_query appendFormat:@"%1$@%2$@%1$@.", _identifierQuote, _database]; } - [_query appendFormat:@"%@%@%@", _useQuotes ? QUERY_QUOTE : EMPTY_STRING, _table, _useQuotes ? QUERY_QUOTE : EMPTY_STRING]; + [_query appendFormat:@"%1$@%2$@%1$@", _identifierQuote, _table]; if (isUpdate) { [_query appendFormat:@" %@", [self _buildUpdateClause]]; @@ -332,6 +404,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Builds the string representation of the query's field list. + * + * @return The field list as SQL. */ - (NSString *)_buildFieldList { @@ -349,7 +423,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; if ([field length] == 0) continue; - [fields appendFormat:@"%@%@%@, ", _useQuotes ? QUERY_QUOTE : EMPTY_STRING, field, _useQuotes ? QUERY_QUOTE : EMPTY_STRING]; + [fields appendFormat:@"%1$@%2$@%1$@, ", _identifierQuote, field]; } if ([fields hasSuffix:@", "]) { @@ -361,6 +435,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Builds the string representation of the query's constraints. + * + * @return The query constraints as SQL. */ - (NSString *)_buildConstraints { @@ -384,7 +460,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Builds the string representation of the query's GROUP BY clause. * - * @return The GROUP BY clause + * @return The GROUP BY SQL clause. */ - (NSString *)_buildGroupByClause { @@ -396,7 +472,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; for (NSString *field in _groupByFields) { - [groupBy appendFormat:@"%@%@%@, ", _useQuotes ? QUERY_QUOTE : EMPTY_STRING, field, _useQuotes ? QUERY_QUOTE : EMPTY_STRING]; + [groupBy appendFormat:@"%1$@%2$@%1$@, ", _identifierQuote, field]; } if ([groupBy hasSuffix:@", "]) { @@ -409,7 +485,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Builds the string representation of the query's ORDER BY clause. * - * @return The ORDER BY clause + * @return The ORDER BY SQL clause. */ - (NSString *)_buildOrderByClause { @@ -421,7 +497,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; for (NSString *field in _orderByFields) { - [orderBy appendFormat:@"%@%@%@, ", _useQuotes ? QUERY_QUOTE : EMPTY_STRING, field, _useQuotes ? QUERY_QUOTE : EMPTY_STRING]; + [orderBy appendFormat:@"%1$@%2$@%1$@, ", _identifierQuote, field]; } if ([orderBy hasSuffix:@", "]) { @@ -436,7 +512,7 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Builds the string representation of the query's UPDATE parameters. * - * @return The fields to be updated + * @return The fields to update section of the SQL query. */ - (NSString *)_buildUpdateClause { @@ -510,6 +586,8 @@ static NSString *QKNoQueryTableException = @"QKNoQueryTable"; /** * Same as calling -query. + * + * @return the query that was built. */ - (NSString *)description { diff --git a/Frameworks/QueryKit/Source/QKQueryConstants.h b/Frameworks/QueryKit/Source/QKQueryConstants.h index 9d843169..57c7a55b 100644 --- a/Frameworks/QueryKit/Source/QKQueryConstants.h +++ b/Frameworks/QueryKit/Source/QKQueryConstants.h @@ -28,5 +28,4 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. -#define QUERY_QUOTE @"`" #define EMPTY_STRING @"" diff --git a/Frameworks/QueryKit/Source/QKQueryDatabases.h b/Frameworks/QueryKit/Source/QKQueryDatabases.h index 16843b2a..cdb76221 100644 --- a/Frameworks/QueryKit/Source/QKQueryDatabases.h +++ b/Frameworks/QueryKit/Source/QKQueryDatabases.h @@ -35,6 +35,7 @@ */ typedef enum { + QKDatabaseUnknown = -1, QKDatabaseMySQL, QKDatabasePostgreSQL } diff --git a/Frameworks/QueryKit/Source/QKQueryGenericParameter.h b/Frameworks/QueryKit/Source/QKQueryGenericParameter.h index 63e9b529..562689f5 100644 --- a/Frameworks/QueryKit/Source/QKQueryGenericParameter.h +++ b/Frameworks/QueryKit/Source/QKQueryGenericParameter.h @@ -31,8 +31,10 @@ @interface QKQueryGenericParameter : NSObject { id _value; + BOOL _useQuotedIdentifier; + NSString *_field; - BOOL _useQuotes; + NSString *_identiferQuote; } /** @@ -41,9 +43,14 @@ @property(readwrite, retain, getter=field, setter=setField:) NSString *_field; /** - * @property _quoteField Indicates whether or not this parameters field should be quoted. + * @property _identifierQuote */ -@property(readwrite, assign, getter=useQuotes, setter=setUseQuotes:) BOOL _useQuotes; +@property(readwrite, retain, getter=identifierQuote, setter=setIdentifierQuote:) NSString *_identiferQuote; + +/** + * @property _useQuotedIdentifier Indicates whether or not this parameters field should be quoted. + */ +@property(readwrite, assign, getter=useQuotedIdentifier, setter=setUseQuotedIdentifier:) BOOL _useQuotedIdentifier; /** *@property _value The value component of the parameter. diff --git a/Frameworks/QueryKit/Source/QKQueryGenericParameter.m b/Frameworks/QueryKit/Source/QKQueryGenericParameter.m index 8648dc0a..efaf10d3 100644 --- a/Frameworks/QueryKit/Source/QKQueryGenericParameter.m +++ b/Frameworks/QueryKit/Source/QKQueryGenericParameter.m @@ -33,7 +33,8 @@ @implementation QKQueryGenericParameter @synthesize _field; -@synthesize _useQuotes; +@synthesize _useQuotedIdentifier; +@synthesize _identiferQuote; @synthesize _value; #pragma mark - @@ -42,7 +43,8 @@ - (id)init { if ((self = [super init])) { - [self setUseQuotes:YES]; + [self setUseQuotedIdentifier:YES]; + [self setIdentifierQuote:EMPTY_STRING]; } return self; diff --git a/Frameworks/QueryKit/Source/QKQueryParameter.m b/Frameworks/QueryKit/Source/QKQueryParameter.m index c4f9cc29..87035d00 100644 --- a/Frameworks/QueryKit/Source/QKQueryParameter.m +++ b/Frameworks/QueryKit/Source/QKQueryParameter.m @@ -63,8 +63,8 @@ NSString *field = [_field stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - [string appendFormat:@"%@%@%@", [self useQuotes] ? QUERY_QUOTE : EMPTY_STRING, field, [self useQuotes] ? QUERY_QUOTE : EMPTY_STRING]; - [string appendFormat:@" %@ ", [QKQueryUtilities operatorRepresentationForType:_operator]]; + [string appendFormat:@"%1$@%2$@%1$@", [self useQuotedIdentifier] ? _identiferQuote : EMPTY_STRING, field]; + [string appendFormat:@" %@ ", [QKQueryUtilities stringRepresentationOfQueryOperator:_operator]]; [string appendFormat:![_value isKindOfClass:[NSNumber class]] ? @"'%@'" : @"%@", [_value description]]; return string; diff --git a/Frameworks/QueryKit/Source/QKQueryStringAdditions.h b/Frameworks/QueryKit/Source/QKQueryStringAdditions.h new file mode 100644 index 00000000..3a0b8e89 --- /dev/null +++ b/Frameworks/QueryKit/Source/QKQueryStringAdditions.h @@ -0,0 +1,35 @@ +// +// $Id$ +// +// QKQueryStringAdditions.h +// QueryKit +// +// Created by Stuart Connolly (stuconnolly.com) on July 12, 2012 +// Copyright (c) 2012 Stuart Connolly. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +@interface NSString (QKQueryStringAdditions) + +- (NSString *)quotedStringWithCharacter:(NSString *)character; + +@end diff --git a/Frameworks/QueryKit/Source/QKQueryStringAdditions.m b/Frameworks/QueryKit/Source/QKQueryStringAdditions.m new file mode 100644 index 00000000..7c87e458 --- /dev/null +++ b/Frameworks/QueryKit/Source/QKQueryStringAdditions.m @@ -0,0 +1,47 @@ +// +// $Id$ +// +// QKQueryStringAdditions.m +// QueryKit +// +// Created by Stuart Connolly (stuconnolly.com) on July 12, 2012 +// Copyright (c) 2012 Stuart Connolly. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#import "QKQueryStringAdditions.h" + +@implementation NSString (QKQueryStringAdditions) + +/** + * Returns the string quoted with supplied character. + * + * @return The quoted string + */ +- (NSString *)quotedStringWithCharacter:(NSString *)character +{ + NSString *escapedVersion = [NSString stringWithFormat:@"%@%@", character, character]; + + return [NSString stringWithFormat: @"%@%@%@", character, [self stringByReplacingOccurrencesOfString:character withString:escapedVersion], character]; +} + +@end diff --git a/Frameworks/QueryKit/Source/QKQueryUpdateParameter.m b/Frameworks/QueryKit/Source/QKQueryUpdateParameter.m index 8df3aba5..3c271e99 100644 --- a/Frameworks/QueryKit/Source/QKQueryUpdateParameter.m +++ b/Frameworks/QueryKit/Source/QKQueryUpdateParameter.m @@ -59,7 +59,7 @@ NSString *field = [_field stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - [string appendFormat:@"%@%@%@", [self useQuotes] ? QUERY_QUOTE : EMPTY_STRING, field, [self useQuotes] ? QUERY_QUOTE : EMPTY_STRING]; + [string appendFormat:@"%1$@%2$@%1$@", [self useQuotedIdentifier] ? _identiferQuote : EMPTY_STRING, field]; [string appendString:@" = "]; [string appendFormat:(![_value isKindOfClass:[NSNumber class]]) ? @"'%@'" : @"%@", [_value description]]; diff --git a/Frameworks/QueryKit/Source/QKQueryUtilities.h b/Frameworks/QueryKit/Source/QKQueryUtilities.h index 228385f8..7aa6124a 100644 --- a/Frameworks/QueryKit/Source/QKQueryUtilities.h +++ b/Frameworks/QueryKit/Source/QKQueryUtilities.h @@ -29,6 +29,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #import "QKQueryOperators.h" +#import "QKQueryDatabases.h" /** * @class QKQueryUtilities QKQueryUtilities.h @@ -39,6 +40,7 @@ */ @interface QKQueryUtilities : NSObject -+ (NSString *)operatorRepresentationForType:(QKQueryOperator)operator; ++ (NSString *)identifierQuoteCharacterForDatabase:(QKQueryDatabase)database; ++ (NSString *)stringRepresentationOfQueryOperator:(QKQueryOperator)operator; @end diff --git a/Frameworks/QueryKit/Source/QKQueryUtilities.m b/Frameworks/QueryKit/Source/QKQueryUtilities.m index 8519eb20..06396ddc 100644 --- a/Frameworks/QueryKit/Source/QKQueryUtilities.m +++ b/Frameworks/QueryKit/Source/QKQueryUtilities.m @@ -35,13 +35,34 @@ static NSString *QKUnrecognisedQueryOperatorException = @"QKUnrecognisedQueryOpe @implementation QKQueryUtilities /** - * Returns a string representation of the supplied operator type. + * Returns the identifier quote character for the supplied database. + * + * @param database The database to return the character for + * + * @return The character as a string. + */ ++ (NSString *)identifierQuoteCharacterForDatabase:(QKQueryDatabase)database +{ + NSString *character = EMPTY_STRING; + + if (database == QKDatabaseMySQL) { + character = @"`"; + } + else if (database == QKDatabasePostgreSQL) { + character = @""""; + } + + return character; +} + +/** + * Returns a string representation of the supplied operator. * * @param operator The operator * * @return A string represenation of the operator. */ -+ (NSString *)operatorRepresentationForType:(QKQueryOperator)operator ++ (NSString *)stringRepresentationOfQueryOperator:(QKQueryOperator)operator { NSString *opString = nil; diff --git a/Frameworks/QueryKit/Source/QueryKit-Prefix.pch b/Frameworks/QueryKit/Source/QueryKit-Prefix.pch index 5e15c359..d5c5da40 100644 --- a/Frameworks/QueryKit/Source/QueryKit-Prefix.pch +++ b/Frameworks/QueryKit/Source/QueryKit-Prefix.pch @@ -30,4 +30,6 @@ #ifdef __OBJC__ #import <Foundation/Foundation.h> + + #import "QKQueryConstants.h" #endif diff --git a/Frameworks/QueryKit/Tests/QKQueryTests.m b/Frameworks/QueryKit/Tests/QKQueryTests.m index 63b0ec73..35212cff 100644 --- a/Frameworks/QueryKit/Tests/QKQueryTests.m +++ b/Frameworks/QueryKit/Tests/QKQueryTests.m @@ -40,7 +40,8 @@ { _query = [QKQuery selectQueryFromTable:QKTestTableName]; - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; + [_query setQueryDatabase:QKDatabaseMySQL]; [_query setDatabase:QKTestDatabaseName]; @@ -63,13 +64,17 @@ STAssertNil([_query table], @"query table"); STAssertNil([_query database], @"query database"); - STAssertTrue([_query useQuotes], @"query use quotes"); - STAssertTrue([_query queryType] == QKUnknownQuery, @"query type"); + + STAssertTrue([_query useQuotedIdentifiers], @"query use quoted identifiers"); + STAssertTrue([[_query identifierQuote] isEqualToString:EMPTY_STRING], @"query identifier quote"); STAssertTrue([[_query fields] count] == 0, @"query fields"); STAssertTrue([[_query parameters] count] == 0, @"query parameters"); STAssertTrue([[_query updateParameters] count] == 0, @"query update parameters"); STAssertTrue([[_query groupByFields] count] == 0, @"query group by fields"); STAssertTrue([[_query orderByFields] count] == 0, @"query order by fields"); + + STAssertEquals([_query queryType], QKUnknownQuery, @"query type"); + STAssertEquals([_query queryDatabase], QKDatabaseUnknown, @"query database"); } @end diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m b/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m index e9edbea1..c0ee4681 100644 --- a/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m +++ b/Frameworks/QueryKit/Tests/QKSelectQueryGroupByTests.m @@ -63,7 +63,7 @@ - (void)testSelectQueryGroupByWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; [_query groupByField:QKTestFieldOne]; NSString *query = [NSString stringWithFormat:@"GROUP BY %@", QKTestFieldOne]; @@ -82,7 +82,7 @@ - (void)testSelectQueryGroupByMultipleFieldsWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; [_query groupByFields:[NSArray arrayWithObjects:QKTestFieldOne, QKTestFieldTwo, nil]]; NSString *query = [NSString stringWithFormat:@"GROUP BY %@, %@", QKTestFieldOne, QKTestFieldTwo]; diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m b/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m index cb1a472f..4ea01e4a 100644 --- a/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m +++ b/Frameworks/QueryKit/Tests/QKSelectQueryOrderByTests.m @@ -63,7 +63,7 @@ - (void)testSelectQueryOrderByAscendingWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; [_query orderByField:QKTestFieldOne descending:NO]; NSString *query = [NSString stringWithFormat:@"ORDER BY %@ ASC", QKTestFieldOne]; @@ -82,7 +82,7 @@ - (void)testSelectQueryOrderByMultipleFieldsAscendingWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; [_query orderByFields:[NSArray arrayWithObjects:QKTestFieldOne, QKTestFieldTwo, nil] descending:NO]; NSString *query = [NSString stringWithFormat:@"ORDER BY %@, %@ ASC", QKTestFieldOne, QKTestFieldTwo]; @@ -101,7 +101,7 @@ - (void)testSelectQueryOrderByDescendingWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; [_query orderByField:QKTestFieldOne descending:YES]; NSString *query = [NSString stringWithFormat:@"ORDER BY %@ DESC", QKTestFieldOne]; @@ -120,7 +120,7 @@ - (void)testSelectQueryOrderByMultipleFieldsDescendingWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; [_query orderByFields:[NSArray arrayWithObjects:QKTestFieldOne, QKTestFieldTwo, nil] descending:YES]; NSString *query = [NSString stringWithFormat:@"ORDER BY %@, %@ DESC", QKTestFieldOne, QKTestFieldTwo]; diff --git a/Frameworks/QueryKit/Tests/QKSelectQueryTests.m b/Frameworks/QueryKit/Tests/QKSelectQueryTests.m index 75cf7ed2..dc31d353 100644 --- a/Frameworks/QueryKit/Tests/QKSelectQueryTests.m +++ b/Frameworks/QueryKit/Tests/QKSelectQueryTests.m @@ -65,7 +65,7 @@ - (void)testSelectQueryFieldWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; NSString *query = [NSString stringWithFormat:@"SELECT %@", QKTestFieldOne]; @@ -81,7 +81,7 @@ - (void)testSelectQueryMultipleFieldsWithoutQuotesAreCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; NSString *query = [NSString stringWithFormat:@"SELECT %@, %@, %@, %@", QKTestFieldOne, QKTestFieldTwo, QKTestFieldThree, QKTestFieldFour]; @@ -90,16 +90,16 @@ - (void)testSelectQueryConstraintsAreCorrect { - NSString *query = [NSString stringWithFormat:@"WHERE `%@` %@ %@", QKTestFieldOne, [QKQueryUtilities operatorRepresentationForType:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; + NSString *query = [NSString stringWithFormat:@"WHERE `%@` %@ %@", QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; STAssertTrue(([[_query query] rangeOfString:query].location != NSNotFound), @"select query constraint"); } - (void)testSelectQueryConstraintsWithoutQuotesAreCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; - NSString *query = [NSString stringWithFormat:@"WHERE %@ %@ %@", QKTestFieldOne, [QKQueryUtilities operatorRepresentationForType:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; + NSString *query = [NSString stringWithFormat:@"WHERE %@ %@ %@", QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; STAssertTrue(([[_query query] rangeOfString:query].location != NSNotFound), @"select query constraint without quotes"); } diff --git a/Frameworks/QueryKit/Tests/QKTestConstants.h b/Frameworks/QueryKit/Tests/QKTestConstants.h index 10e3fa7e..7c200d3e 100644 --- a/Frameworks/QueryKit/Tests/QKTestConstants.h +++ b/Frameworks/QueryKit/Tests/QKTestConstants.h @@ -28,6 +28,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. +#define EMPTY_STRING @"" + extern NSString *QKTestDatabaseName; extern NSString *QKTestTableName; diff --git a/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m b/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m index 6a24881d..65c31dae 100644 --- a/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m +++ b/Frameworks/QueryKit/Tests/QKUpdateQueryTests.m @@ -65,25 +65,27 @@ - (void)testUpdateQueryFieldsWithoutQuotesAreCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; NSString *query = [NSString stringWithFormat:@"UPDATE %@ SET %@ = '%@', %@ = '%@'", QKTestTableName, QKTestFieldOne, QKTestUpdateValueOne, QKTestFieldTwo, QKTestUpdateValueTwo]; + NSLog(@"%@", [_query query]); + STAssertTrue([[_query query] hasPrefix:query], @"update query fields without quotes"); } - (void)testUpdateQueryConstraintIsCorrect { - NSString *query = [NSString stringWithFormat:@"WHERE `%@` %@ %@", QKTestFieldOne, [QKQueryUtilities operatorRepresentationForType:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; + NSString *query = [NSString stringWithFormat:@"WHERE `%@` %@ %@", QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; STAssertTrue(([[_query query] rangeOfString:query].location != NSNotFound), @"update query constraint"); } - (void)testUpdateQueryConstraintWithoutQuotesIsCorrect { - [_query setUseQuotes:NO]; + [_query setUseQuotedIdentifiers:NO]; - NSString *query = [NSString stringWithFormat:@"WHERE %@ %@ %@", QKTestFieldOne, [QKQueryUtilities operatorRepresentationForType:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; + NSString *query = [NSString stringWithFormat:@"WHERE %@ %@ %@", QKTestFieldOne, [QKQueryUtilities stringRepresentationOfQueryOperator:QKEqualityOperator], [NSNumber numberWithUnsignedInteger:QKTestParameterOne]]; STAssertTrue(([[_query query] rangeOfString:query].location != NSNotFound), @"update query constraint without quotes"); } |