将NSPredicate转换为SQL

时间:2013-07-07 19:40:28

标签: sql objective-c macos cocoa nspredicate

我需要一个我可以直接进入项目的类,将谓词作为参数发送给它,并让它返回它所代表的SQL查询的NSString。

下面的内容可能是原型?

@interface PSPredicateToSQL : NSObject

+ (NSString *)SQLClauseForPredictate:(NSPredicate*) predicate;

@end

有没有人知道这样做的课程,或者如果没有这样做怎么办?

我需要这个搜索窗口,我已经实现了搜索数据存储在SQLite数据库中的地方。

enter image description here

1 个答案:

答案 0 :(得分:2)

我终于上了自己的课,希望这可以帮助你们。

.H文件

@interface PredicateToSQL : NSObject

+ (PredicateToSQL *) sharedObject;
- (NSString *) SQLFilterForPredicate:(NSPredicate *)predicate;
@end

.M文件

#import "PredicateToSQL.h"

@implementation PredicateToSQL

static NSString *SQLNullValueString = @"NULL";

/* Implementation */
static PredicateToSQL *sharedObject;

+ (PredicateToSQL *) sharedObject
{
    return sharedObject;
}

+ (void) initialize
{
    sharedObject = [PredicateToSQL new];
}

- (NSString *)SQLExpressionForKeyPath:(NSString *)keyPath
{
NSString     *retStr = nil;
NSDictionary *convertibleSetOperations = @{@"@avg" : @"avg",@"@max" : @"max",@"@min" : @"min",@"@sum" : @"sum",@"@distinctUnionOfObjects" : @"distinct" };

for (NSString *setOpt in [convertibleSetOperations allKeys])
 { if ([keyPath hasSuffix:setOpt])
    { NSString *clean = [[keyPath stringByReplacingOccurrencesOfString:setOpt withString:@""] stringByReplacingOccurrencesOfString:@".." withString:@"."];
      retStr = [NSString stringWithFormat:@"%@(%@)",convertibleSetOperations[setOpt], clean];
     };
  };
if (retStr != nil) return(retStr);
return(keyPath);
}

- (NSString *) SQLSelectClauseForSubqueryExpression:(NSExpression *)expression
{
PSLog(@"SQLSelectClauseForSubqueryExpression not implemented");
return(nil);
}

- (NSString *) SQLLiteralListForArray:(NSArray *)array
{
NSMutableArray *retArray = [NSMutableArray array];

for (NSExpression *obj in array) { [retArray addObject:[self SQLExpressionForNSExpression:obj]]; };
return([NSString stringWithFormat:@"(%@)",[retArray componentsJoinedByString:@","]]);
}



- (NSString *) SQLFunctionLiteralForFunctionExpression:(NSExpression *)exp
{  
NSDictionary *convertibleNullaryFunctions = @{ @"now" : @"date('now')",@"random" : @"random()" };
NSDictionary *convertibleUnaryFunctions   = @{ @"uppercase:" : @"upper",@"lowercase:" : @"lower",@"abs:" : @"abs" };
NSDictionary *convertibleBinaryFunctions  = @{ @"add:to:"        : @"+" ,
                                               @"from:subtract:" : @"-" ,
                                               @"multiply:by:"   : @"*" ,
                                               @"divide:by:"     : @"/" ,
                                               @"modulus:by:"    : @"%" ,
                                               @"leftshift:by"   : @"<<",
                                               @"rightshift:by:" : @">>"
                                               };

if ([[convertibleNullaryFunctions allKeys] containsObject:[exp function]])
      { return(convertibleNullaryFunctions[[exp function]]);
       }
 else { if ([[convertibleUnaryFunctions allKeys] containsObject:[exp function]])
         { return([NSString stringWithFormat:@"%@(%@)",convertibleUnaryFunctions[[exp function]],[self SQLExpressionForNSExpression:[exp arguments][0]]]);
          }
    else { if ([[convertibleBinaryFunctions allKeys] containsObject:[exp function]])
            { return([NSString stringWithFormat:@"(%@ %@ %@)",[self SQLExpressionForNSExpression:[exp arguments][0]],convertibleBinaryFunctions[[exp function]],[self SQLExpressionForNSExpression:[exp arguments][1]]]);
             }
       else { PSLog(@"SQLFunctionLiteralForFunctionExpression could not be converted because it uses an unconvertible function");
             };
          };
       };
return(nil);
}

- (NSString *) SQLNamedReplacementVariableForVariable:(NSString *)var
{
//PSLog(@"SQLNamedReplacementVariableForVariable not implemented");
return(var);
}

/*
NSArray *temp = [gPatientDatabaseDictionary allKeysForObject:var];
NSString *key = [temp objectAtIndex:0];
return(key);
*/


- (NSString *)DatabaseKeyfor:(NSString *)obj
{
NSArray *keysForObj = [DatabaseDictionary allKeysForObject:obj];
if ([keysForObj count] > 0) return([keysForObj objectAtIndex:0]);
return(obj);
}



- (NSString *)SQLExpressionForLeftKeyPath:(NSString *)keyPath
{
NSString     *retStr = nil;
NSDictionary *convertibleSetOperations = @{ @"@avg" : @"avg",@"@max" : @"max",@"@min" : @"min",@"@sum" : @"sum",@"@distinctUnionOfObjects" : @"distinct" };

for (NSString *setOpt in [convertibleSetOperations allKeys])
 { if ([keyPath hasSuffix:setOpt])
    { NSString *clean = [[keyPath stringByReplacingOccurrencesOfString:setOpt withString:@""] stringByReplacingOccurrencesOfString:@".." withString:@"."];
      retStr = [NSString stringWithFormat:@"%@(%@)",convertibleSetOperations[setOpt],clean];
     };
  };

if (retStr != nil) return([self DatabaseKeyfor:retStr]);
return([self DatabaseKeyfor:keyPath]);
}


- (NSString *) SQLConstantForLeftValue:(id) val
{
if (val == nil) return(SQLNullValueString);
if ([val isEqual:[NSNull null]]) return(SQLNullValueString);

if ([val isKindOfClass:[NSString class]])
      { //PSLog(@"SQLConstantForLeftValue val %@",val);
        return([self DatabaseKeyfor:val]);
       }
 else { if ([val respondsToSelector:@selector(intValue)])
         { return([self DatabaseKeyfor:[val stringValue]]);
          }
    else { return([self SQLConstantForLeftValue:[val description]]);
          };
      };
return(nil);
}



-(NSString *)SQLExpressionForLeftNSExpression:(NSExpression *)expression
{
NSString *retStr = nil;

switch ([expression expressionType])
 { case NSConstantValueExpressionType: { retStr = [self SQLConstantForLeftValue:[expression constantValue]];
                                         //NSLog(@"LEFT  NSConstantValueExpressionType %@",retStr); // contains 'Patient Name' etc..
                                         break; }
        case NSVariableExpressionType: { retStr = [self SQLNamedReplacementVariableForVariable:[expression variable]];
                                         //NSLog(@"LEFT NSVariableExpressionType %@",retStr);
                                         break; }
         case NSKeyPathExpressionType: { retStr = [self SQLExpressionForLeftKeyPath:[expression keyPath]];
                                         //NSLog(@"LEFT NSKeyPathExpressionType %@",retStr); // first "Patient Name'
                                         break; }
        case NSFunctionExpressionType: { retStr = [self SQLFunctionLiteralForFunctionExpression:expression];
                                         //NSLog(@"LEFT NSFunctionExpressionType %@",retStr);
                                         break; }
        case NSSubqueryExpressionType: { retStr = [self SQLSelectClauseForSubqueryExpression:expression];
                                         //NSLog(@"LEFT NSSubqueryExpressionType %@",retStr);
                                         break; }
       case NSAggregateExpressionType: { retStr = [self SQLLiteralListForArray:[expression collection]];
                                         //NSLog(@"LEFT NSAggregateExpressionType %@",retStr);
                                         break; }
        case NSUnionSetExpressionType: { break; }
    case NSIntersectSetExpressionType: { break; }
        case NSMinusSetExpressionType: { break; }

 case NSEvaluatedObjectExpressionType: { break; } // these can't be converted 
           case NSBlockExpressionType: { break; }
        //case NSAnyKeyExpressionType: { break; }
  };
return retStr;
}



-(NSString *)SQLConstantForValue:(id) val
{
if (val == nil) return(SQLNullValueString);
if ([val isEqual:[NSNull null]]) return(SQLNullValueString);

if ([val isKindOfClass:[NSString class]])
      { //NSLog(@"SQLConstantForValue val %@",val);
        return(val);
       }
 else { if ([val respondsToSelector:@selector(intValue)])
         { return([val stringValue]);
          }
    else { return([self SQLConstantForValue:[val description]]);
          };
      };
return(nil);
}



-(NSString *)SQLExpressionForNSExpression:(NSExpression *)expression
{
NSString *retStr = nil;

switch ([expression expressionType])
 { case NSConstantValueExpressionType: { retStr = [self SQLConstantForValue:[expression constantValue]];
                                         //NSLog(@"NSConstantValueExpressionType %@",retStr); // contains 'Patient Name' etc..
                                         break; }
        case NSVariableExpressionType: { retStr = [self SQLNamedReplacementVariableForVariable:[expression variable]];
                                         //NSLog(@"NSVariableExpressionType %@",retStr);
                                         break; }
         case NSKeyPathExpressionType: { retStr = [self SQLExpressionForKeyPath:[expression keyPath]];
                                         //NSLog(@"NSKeyPathExpressionType %@",retStr);
                                         break; }
        case NSFunctionExpressionType: { retStr = [self SQLFunctionLiteralForFunctionExpression:expression];
                                         //NSLog(@"NSFunctionExpressionType %@",retStr);
                                         break; }
        case NSSubqueryExpressionType: { retStr = [self SQLSelectClauseForSubqueryExpression:expression];
                                         //NSLog(@"NSSubqueryExpressionType %@",retStr);
                                         break; }
       case NSAggregateExpressionType: { retStr = [self SQLLiteralListForArray:[expression collection]];
                                         //PSLog(@"NSAggregateExpressionType %@",retStr);
                                         break; }
        case NSUnionSetExpressionType: { break; }
    case NSIntersectSetExpressionType: { break; }
        case NSMinusSetExpressionType: { break; }

 case NSEvaluatedObjectExpressionType: { break; } // these can't be converted 
           case NSBlockExpressionType: { break; }
        //case NSAnyKeyExpressionType: { break; }
  };
return retStr;
}

/*
- (NSString *) SQLInfixOperatorForOperatorType:(NSPredicateOperatorType) type
{
switch (type)
 {           case NSLessThanPredicateOperatorType: { return(@"<");
                                                     break; }
    case NSLessThanOrEqualToPredicateOperatorType: { return(@"<=");
                                                     break; }
          case NSGreaterThanPredicateOperatorType: { return(@">");
                                                     break; }
 case NSGreaterThanOrEqualToPredicateOperatorType: { return(@">=");
                                                     break; }
              case NSEqualToPredicateOperatorType: { return(@"=");
                                                     break; }
           case NSNotEqualToPredicateOperatorType: { return(@"<>");
                                                     break; }
              case NSMatchesPredicateOperatorType: { return(@"MATCH");
                                                     break; }
                   case NSInPredicateOperatorType: { return(@"IN");
                                                     break; }
              case NSBetweenPredicateOperatorType: { return(@"BETWEEN");
                                                     break; }
                 case NSLikePredicateOperatorType: { return(@"LIKE");
                                                     break; }
             case NSContainsPredicateOperatorType: { return(@"CONTAINS");
                                                     break; }
           case NSBeginsWithPredicateOperatorType:
             case NSEndsWithPredicateOperatorType: { //NSAssert(0,@"predicate not converted because 'beginswith' and 'endswith' are not consistently supported by SQL");
                                                     break; }
       case NSCustomSelectorPredicateOperatorType: { //NSAssert(0,@"predicate cannot be converted to a where clause because it calls a custom selector");
                                                     break; }
  };
return(nil);
}
*/

- (NSString *) SQLWhereClauseForComparisonPredicate:(NSComparisonPredicate *)predicate
{
NSString *leftSQLExpression  = [self SQLExpressionForLeftNSExpression:[predicate leftExpression]];
NSString *rightSQLExpression = [self SQLExpressionForNSExpression:[predicate rightExpression]];

switch ([predicate predicateOperatorType])
 {           case NSLessThanPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ < '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
    case NSLessThanOrEqualToPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ <= '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
          case NSGreaterThanPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ > '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
 case NSGreaterThanOrEqualToPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ >= '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
              case NSEqualToPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ = '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
           case NSNotEqualToPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ <> '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
              case NSMatchesPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ MATCH '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
                   case NSInPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ IN '%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
              case NSBetweenPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ BETWEEN '%@' AND '%@')",[self SQLExpressionForLeftNSExpression:[predicate leftExpression]],
                      [self SQLExpressionForNSExpression:[[predicate rightExpression] collection][0]],
                      [self SQLExpressionForNSExpression:[[predicate rightExpression] collection][1]]]);
                                                     break; }
                 case NSLikePredicateOperatorType:
             case NSContainsPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ LIKE '%%%@%%')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
           case NSBeginsWithPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ LIKE '%@%%')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
             case NSEndsWithPredicateOperatorType: { return([NSString stringWithFormat:@"(%@ LIKE '%%%@')",leftSQLExpression,rightSQLExpression]);
                                                     break; }
       case NSCustomSelectorPredicateOperatorType: { PSLog(@"SQLWhereClauseForComparisonPredicate custom selectors are not supported");
                                                     break; }
  };

/*
//NSAssert(0,@"predicate not converted because 'beginswith' and 'endswith' are not consistently supported by SQL");
//NSAssert(0,@"predicate cannot be converted to a where clause because it calls a custom selector");

NSString *comparator = [self SQLInfixOperatorForOperatorType:[predicate predicateOperatorType]];
if (comparator != nil)
   { if ([comparator isEqual:@"BETWEEN"])
      { return([NSString stringWithFormat:@"(%@ %@ '%@' AND '%@')",[self SQLExpressionForLeftNSExpression:[predicate leftExpression]],comparator,
                      [self SQLExpressionForNSExpression:[[predicate rightExpression] collection][0]],
                      [self SQLExpressionForNSExpression:[[predicate rightExpression] collection][1]]]);

       }
 else { if ([comparator isEqual:@"CONTAINS"])
         { return([NSString stringWithFormat:@"(%@ LIKE '%%%@%%')",[self SQLExpressionForLeftNSExpression:[predicate leftExpression]],
                      [self SQLExpressionForNSExpression:[predicate rightExpression]]]);
          }
    else { return([NSString stringWithFormat:@"(%@ %@ '%@')",[self SQLExpressionForLeftNSExpression:[predicate leftExpression]],comparator,
                      [self SQLExpressionForNSExpression:[predicate rightExpression]]]);
          };
       };
   } else { PSLog(@"SQLWhereClauseForComparisonPredicate predicate could not be converted to comparator"); };
   */
return(nil);
}

- (NSString *) SQLWhereClauseForCompoundPredicate:(NSCompoundPredicate *)predicate
{
NSMutableArray *subs = [NSMutableArray array];

for (NSPredicate *sub in [predicate subpredicates]) { [subs addObject:[self SQLFilterForPredicate:sub]]; };

NSString *conjunction;
switch ([(NSCompoundPredicate *)predicate compoundPredicateType])
 { case NSAndPredicateType: { conjunction = @" AND "; break; }
    case NSOrPredicateType: { conjunction = @" OR ";  break; }
   case NSNotPredicateType: { conjunction = @" NOT "; break; }
                   default: { conjunction = @" ";     break; }
 };

//NSLog(@"SQLWhereClauseForCompoundPredicate conjunction %@",conjunction);

return([NSString stringWithFormat:@"(%@)", [subs componentsJoinedByString:conjunction]]);
}

- (NSString *)SQLFilterForPredicate:(NSPredicate *)predicate
{    
if ([predicate respondsToSelector:@selector(compoundPredicateType)])
      { return([self SQLWhereClauseForCompoundPredicate:(NSCompoundPredicate *)predicate]);
       }
 else { if ([predicate respondsToSelector:@selector(predicateOperatorType)])
         { return([self SQLWhereClauseForComparisonPredicate:(NSComparisonPredicate *)predicate]);
          }
    else { PSLog(@"SQLFilterForPredicate predicate is not of a convertible class");
          }
      };
return(nil);
}

@end

您可以在某个全局变量中创建自己的数据库信息,如下所示。

gDatabaseTitles = [NSArray arrayWithObjects:@"Name",@"Phone Number",@"Location",@"Date Of Birth",@"Miscellaneous",nil];

   gDatabaseKeys = [NSArray arrayWithObjects:@"name",@"phone_number",@"location",@"date_of_birth",@"misc",nil];

   gDatabaseTypes = [NSArray arrayWithObjects:@"name TEXT",@"phone_number TEXT",@"location TEXT",@"date_of_birth DATE",@"misc TEXT",nil];

   gDatabaseDictionary = [NSDictionary dictionaryWithObjects:gPatientDatabaseTitles forKeys:gPatientDatabaseKeys];

我必须编辑很多代码来取出与我的项目相关的东西,所以如果我错过了某些内容,这可能无法编译,但这是有效的概念。如果您有任何问题,请告诉我,我会解决它。你看到的任何地方gVariable都是一个我所指的全局变量,它帮助了我的项目并且可能对你有帮助。