aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/QueryKit/Source/QKQuery.m
diff options
context:
space:
mode:
Diffstat (limited to 'Frameworks/QueryKit/Source/QKQuery.m')
-rw-r--r--Frameworks/QueryKit/Source/QKQuery.m436
1 files changed, 436 insertions, 0 deletions
diff --git a/Frameworks/QueryKit/Source/QKQuery.m b/Frameworks/QueryKit/Source/QKQuery.m
new file mode 100644
index 00000000..21053203
--- /dev/null
+++ b/Frameworks/QueryKit/Source/QKQuery.m
@@ -0,0 +1,436 @@
+//
+// $Id: QKQuery.m 3432 2011-09-27 00:21:35Z stuart02 $
+//
+// QKQuery.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 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.
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "QKQuery.h"
+
+static NSString *QKNoQueryTypeException = @"QKNoQueryType";
+static NSString *QKNoQueryTableException = @"QKNoQueryTable";
+
+@interface QKQuery ()
+
+- (void)_validateRequiements;
+
+- (NSString *)_buildQuery;
+- (NSString *)_buildFieldList;
+- (NSString *)_buildConstraints;
+- (NSString *)_buildGroupByClause;
+- (NSString *)_buildOrderByClause;
+
+- (BOOL)_addString:(NSString *)string toArray:(NSMutableArray *)array;
+
+@end
+
+@implementation QKQuery
+
+@synthesize _database;
+@synthesize _table;
+@synthesize _parameters;
+@synthesize _queryType;
+@synthesize _fields;
+@synthesize _quoteFields;
+
+#pragma mark -
+#pragma mark Initialization
+
++ (QKQuery *)queryTable:(NSString *)table
+{
+ return [[[QKQuery alloc] initWithTable:table] autorelease];
+}
+
++ (QKQuery *)selectQueryFromTable:(NSString *)table
+{
+ QKQuery *query = [[[QKQuery alloc] initWithTable:table] autorelease];
+
+ [query setQueryType:QKSelectQuery];
+
+ return query;
+}
+
+- (id)initWithTable:(NSString *)table
+{
+ if ((self = [super init])) {
+ [self setTable:table];
+ [self setFields:[[NSMutableArray alloc] init]];
+ [self setParameters:[[NSMutableArray alloc] init]];
+ [self setQueryType:(QKQueryType)-1];
+ [self setQuoteFields:NO];
+
+ _orderDescending = NO;
+
+ _groupByFields = [[NSMutableArray alloc] init];
+ _orderByFields = [[NSMutableArray alloc] init];
+
+ _query = [[NSMutableString alloc] init];
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Public API
+
+- (NSString *)query
+{
+ return _query ? [self _buildQuery] : @"";
+}
+
+#pragma mark -
+#pragma mark Fields
+
+/**
+ * Shortcut for adding a new field to this query.
+ */
+- (void)addField:(NSString *)field
+{
+ [self _addString:field toArray:_fields];
+}
+
+/**
+ * Convenience method for adding more than one field.
+ *
+ * @param The array (of strings) of fields to add.
+ */
+- (void)addFields:(NSArray *)fields
+{
+ for (NSString *field in fields)
+ {
+ [self addField:field];
+ }
+}
+
+#pragma mark -
+#pragma mark Parameters
+
+/**
+ * Adds the supplied parameter.
+ *
+ * @param parameter The parameter to add.
+ */
+- (void)addParameter:(QKQueryParameter *)parameter
+{
+ if ([parameter field] && ([[parameter field] length] > 0) && ((NSInteger)[parameter operator] > -1) && [parameter value]) {
+ [_parameters addObject:parameter];
+ }
+}
+
+/**
+ * Convenience method for adding a new parameter.
+ */
+- (void)addParameter:(NSString *)field operator:(QKQueryOperator)operator value:(id)value
+{
+ [self addParameter:[QKQueryParameter queryParamWithField:field operator:operator value:value]];
+}
+
+#pragma mark -
+#pragma mark Grouping
+
+/**
+ * Adds the supplied field to the query's GROUP BY clause.
+ */
+- (void)groupByField:(NSString *)field
+{
+ [self _addString:field toArray:_groupByFields];
+}
+
+/**
+ * Convenience method for adding more than one field to the query's GROUP BY clause.
+ */
+- (void)groupByFields:(NSArray *)fields
+{
+ for (NSString *field in fields)
+ {
+ [self groupByField:field];
+ }
+}
+
+#pragma mark -
+#pragma mark Ordering
+
+/**
+ * Adds the supplied field to the query's ORDER BY clause.
+ */
+- (void)orderByField:(NSString *)field descending:(BOOL)descending
+{
+ _orderDescending = descending;
+
+ [self _addString:field toArray:_orderByFields];
+}
+
+/**
+ * Convenience method for adding more than one field to the query's ORDER BY clause.
+ */
+- (void)orderByFields:(NSArray *)fields descending:(BOOL)descending
+{
+ for (NSString *field in fields)
+ {
+ [self orderByField:field descending:descending];
+ }
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Validates that everything necessary to build the query has been set.
+ */
+- (void)_validateRequiements
+{
+ if (_queryType == -1) {
+ [NSException raise:QKNoQueryTypeException format:@"Attempt to build query with no query type specified."];
+ }
+
+ if (!_table || [_table length] == 0) {
+ [NSException raise:QKNoQueryTableException format:@"Attempt to build query with no query table specified."];
+ }
+}
+
+/**
+ * Builds the actual query.
+ */
+- (NSString *)_buildQuery
+{
+ [self _validateRequiements];
+
+ BOOL isSelect = (_queryType == QKSelectQuery);
+ BOOL isInsert = (_queryType == QKInsertQuery);
+ BOOL isUpdate = (_queryType == QKUpdateQuery);
+ BOOL isDelete = (_queryType == QKDeleteQuery);
+
+ NSString *fields = [self _buildFieldList];
+
+ if (isSelect) {
+ [_query appendFormat:@"SELECT %@ FROM ", fields];
+ }
+ else if (isInsert) {
+ [_query appendString:@"INSERT INTO "];
+ }
+ else if (isUpdate) {
+ [_query appendString:@"UPDATE "];
+ }
+ else if (isDelete) {
+ [_query appendString:@"DELETE FROM "];
+ }
+
+ if (_database && [_database length] > 0) {
+ [_query appendFormat:@"%@.", _database];
+ }
+
+ [_query appendString:_table];
+
+ if ([_parameters count] > 0) {
+ [_query appendString:@" WHERE "];
+ [_query appendString:[self _buildConstraints]];
+ }
+
+ if (isSelect) {
+ NSString *groupBy = [self _buildGroupByClause];
+ NSString *orderBy = [self _buildOrderByClause];
+
+ if ([groupBy length] > 0) {
+ [_query appendFormat:@" %@", groupBy];
+ }
+
+ if ([orderBy length] > 0) {
+ [_query appendFormat:@" %@", orderBy];
+ }
+ }
+
+ return _query;
+}
+
+/**
+ * Builds the string representation of the query's field list.
+ */
+- (NSString *)_buildFieldList
+{
+ NSMutableString *fields = [NSMutableString string];
+
+ if ([_fields count] == 0) {
+ [fields appendString:@"*"];
+
+ return fields;
+ }
+
+ for (NSString *field in _fields)
+ {
+ field = [field stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+ if ([field length] == 0) continue;
+
+ if (_quoteFields) {
+ [fields appendString:@"`"];
+ }
+
+ [fields appendString:field];
+
+ if (_quoteFields) {
+ [fields appendString:@"`"];
+ }
+
+ [fields appendString:@", "];
+ }
+
+ if ([fields hasSuffix:@", "]) {
+ [fields setString:[fields substringToIndex:([fields length] - 2)]];
+ }
+
+ return fields;
+}
+
+/**
+ * Builds the string representation of the query's constraints.
+ */
+- (NSString *)_buildConstraints
+{
+ NSMutableString *constraints = [NSMutableString string];
+
+ if ([_parameters count] == 0) return constraints;
+
+ for (QKQueryParameter *param in _parameters)
+ {
+ [constraints appendFormat:@"%@ ", param];
+
+ [constraints appendString:@" AND "];
+ }
+
+ if ([constraints hasSuffix:@" AND "]) {
+ [constraints setString:[constraints substringToIndex:([constraints length] - 5)]];
+ }
+
+ return constraints;
+}
+
+/**
+ * Builds the string representation of the query's GROUP BY clause.
+ *
+ * @return The GROUP BY clause
+ */
+- (NSString *)_buildGroupByClause
+{
+ NSMutableString *groupBy = [NSMutableString string];
+
+ if ([_groupByFields count] == 0) return groupBy;
+
+ [groupBy appendString:@"GROUP BY "];
+
+ for (NSString *field in _groupByFields)
+ {
+ [groupBy appendString:field];
+ [groupBy appendString:@", "];
+ }
+
+ if ([groupBy hasSuffix:@", "]) {
+ [groupBy setString:[groupBy substringToIndex:([groupBy length] - 2)]];
+ }
+
+ return groupBy;
+}
+
+/**
+ * Builds the string representation of the query's ORDER BY clause.
+ *
+ * @return The ORDER BY clause
+ */
+- (NSString *)_buildOrderByClause
+{
+ NSMutableString *orderBy = [NSMutableString string];
+
+ if ([_orderByFields count] == 0) return orderBy;
+
+ [orderBy appendString:@"ORDER BY "];
+
+ for (NSString *field in _orderByFields)
+ {
+ [orderBy appendString:field];
+ [orderBy appendString:@", "];
+ }
+
+ if ([orderBy hasSuffix:@", "]) {
+ [orderBy setString:[orderBy substringToIndex:([orderBy length] - 2)]];
+ }
+
+ [orderBy appendString:_orderDescending ? @" DESC" : @" ASC"];
+
+ return orderBy;
+}
+
+/**
+ * Adds the supplied string to the supplied array, but only if the length is greater than zero.
+ *
+ * @param string The string to add to the array
+ * @param array The array to add the string to
+ *
+ * @return A BOOL indicating whether or not the string was added.
+ */
+- (BOOL)_addString:(NSString *)string toArray:(NSMutableArray *)array
+{
+ BOOL result = NO;
+
+ if (!string || !array) return result;
+
+ string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+ if ([string length] > 0) {
+ [array addObject:string];
+
+ result = YES;
+ }
+
+ return result;
+}
+
+#pragma mark -
+
+/**
+ * Same as calling -query.
+ */
+- (NSString *)description
+{
+ return [self query];
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ if (_table) [_table release], _table = nil;
+ if (_database) [_database release], _database = nil;
+ if (_query) [_query release], _query = nil;
+ if (_parameters) [_parameters release], _parameters = nil;
+ if (_fields) [_fields release], _fields = nil;
+ if (_groupByFields) [_groupByFields release], _groupByFields = nil;
+ if (_orderByFields) [_orderByFields release], _orderByFields = nil;
+
+ [super dealloc];
+}
+
+@end