Tuukka Norri avatar Tuukka Norri committed 95754aa

SQL expressions, container proxies
- Fixed a bug which caused some SQL expressions to be interpreted as constant values. The bug hadn't been triggered in any known case, though.
- Added logging to container proxies to make cases where key and owner haven't been set more obvious.
- Made PGTSConstantValue public (as BXVerbatimExpressionValue).
- Added a protocol for transforming constant values. It should be possible to pass an SQL adaptor, though, but the predicate visitor assumes that it's producing SQL for PostgreSQL only.
- Made some predicate creation methods a bit safer to call.

Comments (0)

Files changed (26)

BaseTen.xcodeproj/project.pbxproj

 		5338E5540E5EE69E0045B6D7 /* BXPGInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = 530132E109D460230037C485 /* BXPGInterface.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		533BAACB0F2C000A0030CD05 /* PGTSDatabaseDescription.mm in Sources */ = {isa = PBXBuildFile; fileRef = 533BAAC90F2C000A0030CD05 /* PGTSDatabaseDescription.mm */; };
 		533BAACC0F2C000A0030CD05 /* PGTSTableDescription.mm in Sources */ = {isa = PBXBuildFile; fileRef = 533BAACA0F2C000A0030CD05 /* PGTSTableDescription.mm */; };
+		533C1A6E11E227D100C11E86 /* BXPGSQLExpressionValueType.h in Headers */ = {isa = PBXBuildFile; fileRef = 533C1A6C11E227D100C11E86 /* BXPGSQLExpressionValueType.h */; };
+		533C1A6F11E227D100C11E86 /* BXPGSQLExpressionValueType.m in Sources */ = {isa = PBXBuildFile; fileRef = 533C1A6D11E227D100C11E86 /* BXPGSQLExpressionValueType.m */; };
+		533C1D3111E243D300C11E86 /* BXVerbatimExpressionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 533C1D2F11E243D300C11E86 /* BXVerbatimExpressionValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		533C1D3211E243D300C11E86 /* BXVerbatimExpressionValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 533C1D3011E243D300C11E86 /* BXVerbatimExpressionValue.m */; };
+		533C1D7811E2478300C11E86 /* BXExpressionValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 533C1D7711E2478300C11E86 /* BXExpressionValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		533F88410F35482000041C02 /* BXForeignKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 536892570F30B9E800AAC65D /* BXForeignKey.m */; };
 		534369C811AFEF8700ADD6C1 /* BXCollectionFunctions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 534369C711AFEF8700ADD6C1 /* BXCollectionFunctions.mm */; };
 		5348B7110F575A3C00B2655E /* BXKeyPathParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 53680C0D0E59922C00A53B26 /* BXKeyPathParser.m */; };
 		5348B8160F575E4A00B2655E /* PGTSResultSet.mm in Sources */ = {isa = PBXBuildFile; fileRef = 53666CCE0E1CD8D20028DBEA /* PGTSResultSet.mm */; };
 		5348B81E0F575E8700B2655E /* BXPGVisitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B143E50E65A7F80043B75D /* BXPGVisitor.m */; };
 		5348B8260F575E9000B2655E /* BXPGConstantParameterMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B143F40E65AC4B0043B75D /* BXPGConstantParameterMapper.m */; };
-		5348B82E0F575E9900B2655E /* PGTSConstantValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 53877EAC0E27667B0097C35F /* PGTSConstantValue.m */; };
 		5348B8440F575ED400B2655E /* BXPropertyDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B86FF90A0A1D6F007315BC /* BXPropertyDescription.m */; };
 		5348B8460F575ED700B2655E /* BXAttributeDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 539EDD740C46218B00B6E5EC /* BXAttributeDescription.m */; };
 		5348B84A0F575EE100B2655E /* BXDatabaseObjectModelStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 535736CA0F333CCD00DB3D0B /* BXDatabaseObjectModelStorage.m */; };
 		53857ABA11921BA100426CEA /* BXPGFromItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 539A84DA0E5B3AFF00A2625C /* BXPGFromItem.h */; };
 		53857ABB11921BA200426CEA /* BXPGSQLFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 5338E5C90E62CEAE0045B6D7 /* BXPGSQLFunction.m */; };
 		53857ABE11921BA700426CEA /* BXPGSQLFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 5338E5C80E62CEAE0045B6D7 /* BXPGSQLFunction.h */; };
-		53857ABF11921BA800426CEA /* PGTSConstantValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 53877EAB0E27667B0097C35F /* PGTSConstantValue.h */; };
 		53857AC211921BAB00426CEA /* BXPGQueryHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CE796A0E87F29C00D5A310 /* BXPGQueryHandler.m */; };
 		53857AC311921BAC00426CEA /* BXPGQueryHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CE79690E87F29C00D5A310 /* BXPGQueryHandler.h */; };
 		53857ACC11921C1F00426CEA /* BXOpenSSLCompatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 538FA0240F576278005EBFAC /* BXOpenSSLCompatibility.h */; };
 		53877E930E26AE920097C35F /* NSEntityDescription+BXPGAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53877E910E26AE920097C35F /* NSEntityDescription+BXPGAdditions.h */; };
 		53877E940E26AE920097C35F /* NSEntityDescription+BXPGAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 53877E920E26AE920097C35F /* NSEntityDescription+BXPGAdditions.m */; };
 		53877E990E26B3F00097C35F /* NSAttributeDescription+BXPGAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53877E970E26B3F00097C35F /* NSAttributeDescription+BXPGAdditions.h */; };
-		53877EAD0E27667B0097C35F /* PGTSConstantValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 53877EAB0E27667B0097C35F /* PGTSConstantValue.h */; };
-		53877EAE0E27667B0097C35F /* PGTSConstantValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 53877EAC0E27667B0097C35F /* PGTSConstantValue.m */; };
 		53877EEB0E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53877EE90E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.h */; };
 		53877EEC0E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 53877EEA0E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.m */; };
 		538E031C11A4A5F700C3447F /* BXSocketDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 538E031A11A4A5F700C3447F /* BXSocketDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		5339AB920A7542EC00994B1A /* BXException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXException.m; path = Sources/BXException.m; sourceTree = "<group>"; };
 		533BAAC90F2C000A0030CD05 /* PGTSDatabaseDescription.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PGTSDatabaseDescription.mm; path = Sources/PGTSDatabaseDescription.mm; sourceTree = "<group>"; };
 		533BAACA0F2C000A0030CD05 /* PGTSTableDescription.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PGTSTableDescription.mm; path = Sources/PGTSTableDescription.mm; sourceTree = "<group>"; };
+		533C1A6C11E227D100C11E86 /* BXPGSQLExpressionValueType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXPGSQLExpressionValueType.h; path = Sources/BXPGSQLExpressionValueType.h; sourceTree = "<group>"; };
+		533C1A6D11E227D100C11E86 /* BXPGSQLExpressionValueType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXPGSQLExpressionValueType.m; path = Sources/BXPGSQLExpressionValueType.m; sourceTree = "<group>"; };
+		533C1D2F11E243D300C11E86 /* BXVerbatimExpressionValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXVerbatimExpressionValue.h; path = Sources/BXVerbatimExpressionValue.h; sourceTree = "<group>"; };
+		533C1D3011E243D300C11E86 /* BXVerbatimExpressionValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXVerbatimExpressionValue.m; path = Sources/BXVerbatimExpressionValue.m; sourceTree = "<group>"; };
+		533C1D7711E2478300C11E86 /* BXExpressionValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXExpressionValue.h; path = Sources/BXExpressionValue.h; sourceTree = "<group>"; };
 		534369C711AFEF8700ADD6C1 /* BXCollectionFunctions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BXCollectionFunctions.mm; path = Sources/BXCollectionFunctions.mm; sourceTree = "<group>"; };
 		5347BB510B37F78000D963E7 /* BXDatabaseObjectIDPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = BXDatabaseObjectIDPrivate.h; path = Sources/BXDatabaseObjectIDPrivate.h; sourceTree = "<group>"; };
 		534A14AE0F0FBBE6002A9F68 /* BaseTenModifications.sql.m4 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = BaseTenModifications.sql.m4; path = Resources/BaseTenModifications.sql.m4; sourceTree = "<group>"; };
 		53877E920E26AE920097C35F /* NSEntityDescription+BXPGAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSEntityDescription+BXPGAdditions.m"; path = "Sources/NSEntityDescription+BXPGAdditions.m"; sourceTree = "<group>"; };
 		53877E970E26B3F00097C35F /* NSAttributeDescription+BXPGAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSAttributeDescription+BXPGAdditions.h"; path = "Sources/NSAttributeDescription+BXPGAdditions.h"; sourceTree = "<group>"; };
 		53877E980E26B3F00097C35F /* NSAttributeDescription+BXPGAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributeDescription+BXPGAdditions.m"; path = "Sources/NSAttributeDescription+BXPGAdditions.m"; sourceTree = "<group>"; };
-		53877EAB0E27667B0097C35F /* PGTSConstantValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGTSConstantValue.h; path = Sources/PGTSConstantValue.h; sourceTree = "<group>"; };
-		53877EAC0E27667B0097C35F /* PGTSConstantValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGTSConstantValue.m; path = Sources/PGTSConstantValue.m; sourceTree = "<group>"; };
 		53877EE90E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSRelationshipDescription+BXPGAdditions.h"; path = "Sources/NSRelationshipDescription+BXPGAdditions.h"; sourceTree = "<group>"; };
 		53877EEA0E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSRelationshipDescription+BXPGAdditions.m"; path = "Sources/NSRelationshipDescription+BXPGAdditions.m"; sourceTree = "<group>"; };
 		5389E1A20C464107002714B8 /* BXRelationshipDescriptionPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXRelationshipDescriptionPrivate.h; path = Sources/BXRelationshipDescriptionPrivate.h; sourceTree = "<group>"; };
 		53666D860E1CE01A0028DBEA /* SQL Generation */ = {
 			isa = PBXGroup;
 			children = (
+				533C1D7711E2478300C11E86 /* BXExpressionValue.h */,
 				53B144B10E65BD460043B75D /* BXPGQueryBuilder.h */,
 				53B144B20E65BD460043B75D /* BXPGQueryBuilder.m */,
 				53B143E40E65A7F80043B75D /* BXPGVisitor.h */,
 				539A84DB0E5B3AFF00A2625C /* BXPGFromItem.m */,
 				5338E5C80E62CEAE0045B6D7 /* BXPGSQLFunction.h */,
 				5338E5C90E62CEAE0045B6D7 /* BXPGSQLFunction.m */,
-				53877EAB0E27667B0097C35F /* PGTSConstantValue.h */,
-				53877EAC0E27667B0097C35F /* PGTSConstantValue.m */,
 				53CE79690E87F29C00D5A310 /* BXPGQueryHandler.h */,
 				53CE796A0E87F29C00D5A310 /* BXPGQueryHandler.m */,
+				533C1D2F11E243D300C11E86 /* BXVerbatimExpressionValue.h */,
+				533C1D3011E243D300C11E86 /* BXVerbatimExpressionValue.m */,
 				537A23C00E84055F002AAE95 /* Expression value types */,
 				53B143F90E65B08D0043B75D /* Visited classes */,
 			);
 				537A23B80E840544002AAE95 /* BXPGAggregateExpressionValueType.m */,
 				537A23BB0E840556002AAE95 /* BXPGPredefinedFunctionExpressionValueType.h */,
 				537A23BC0E840556002AAE95 /* BXPGPredefinedFunctionExpressionValueType.m */,
+				533C1A6C11E227D100C11E86 /* BXPGSQLExpressionValueType.h */,
+				533C1A6D11E227D100C11E86 /* BXPGSQLExpressionValueType.m */,
 			);
 			name = "Expression value types";
 			sourceTree = "<group>";
 				53B24CFA0E223C8C007AED76 /* BXPGTableDescription.h in Headers */,
 				53877E930E26AE920097C35F /* NSEntityDescription+BXPGAdditions.h in Headers */,
 				53877E990E26B3F00097C35F /* NSAttributeDescription+BXPGAdditions.h in Headers */,
-				53877EAD0E27667B0097C35F /* PGTSConstantValue.h in Headers */,
 				53877EEB0E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.h in Headers */,
 				53D9DDED0E2B4F310009D370 /* BXPGEntityConverter.h in Headers */,
 				5395E7260E2F77DF006E8441 /* BXPGEntityImporter.h in Headers */,
 				53950A0811CFBD730049F36C /* NSNumber+BaseTenAdditions.h in Headers */,
 				53950A0C11CFBDAE0049F36C /* NSValue+BaseTenAdditions.h in Headers */,
 				53950AC711CFD6840049F36C /* BXValueGetter.h in Headers */,
+				533C1A6E11E227D100C11E86 /* BXPGSQLExpressionValueType.h in Headers */,
+				533C1D3111E243D300C11E86 /* BXVerbatimExpressionValue.h in Headers */,
+				533C1D7811E2478300C11E86 /* BXExpressionValue.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				53857AB611921B9D00426CEA /* BXPGRelationAliasMapper.h in Headers */,
 				53857ABA11921BA100426CEA /* BXPGFromItem.h in Headers */,
 				53857ABE11921BA700426CEA /* BXPGSQLFunction.h in Headers */,
-				53857ABF11921BA800426CEA /* PGTSConstantValue.h in Headers */,
 				53857AC311921BAC00426CEA /* BXPGQueryHandler.h in Headers */,
 				53857ACC11921C1F00426CEA /* BXOpenSSLCompatibility.h in Headers */,
 				53857ACD11921C2000426CEA /* BXExport.h in Headers */,
 				5348B8160F575E4A00B2655E /* PGTSResultSet.mm in Sources */,
 				5348B81E0F575E8700B2655E /* BXPGVisitor.m in Sources */,
 				5348B8260F575E9000B2655E /* BXPGConstantParameterMapper.m in Sources */,
-				5348B82E0F575E9900B2655E /* PGTSConstantValue.m in Sources */,
 				5348B8440F575ED400B2655E /* BXPropertyDescription.m in Sources */,
 				5348B8460F575ED700B2655E /* BXAttributeDescription.m in Sources */,
 				5348B84A0F575EE100B2655E /* BXDatabaseObjectModelStorage.m in Sources */,
 				53B24CF50E223A14007AED76 /* BXPGDatabaseDescription.m in Sources */,
 				53B24CFB0E223C8C007AED76 /* BXPGTableDescription.m in Sources */,
 				53877E940E26AE920097C35F /* NSEntityDescription+BXPGAdditions.m in Sources */,
-				53877EAE0E27667B0097C35F /* PGTSConstantValue.m in Sources */,
 				53877EEC0E2773E30097C35F /* NSRelationshipDescription+BXPGAdditions.m in Sources */,
 				53D9DDEC0E2B4F300009D370 /* BXPGEntityConverter.m in Sources */,
 				5395E7270E2F77DF006E8441 /* BXPGEntityImporter.m in Sources */,
 				53950A0911CFBD730049F36C /* NSNumber+BaseTenAdditions.mm in Sources */,
 				53950A0D11CFBDAE0049F36C /* NSValue+BaseTenAdditions.m in Sources */,
 				53950AC811CFD6840049F36C /* BXValueGetter.mm in Sources */,
+				533C1A6F11E227D100C11E86 /* BXPGSQLExpressionValueType.m in Sources */,
+				533C1D3211E243D300C11E86 /* BXVerbatimExpressionValue.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

InterfaceBuilderPlugin/Sources/BXSynchronizedArrayController+IBAdditions.m

 		NSString* predicateString = *ioValue;
 		NSPredicate* predicate = nil;		
 		if ([predicateString length] > 0)
-			predicate = [NSPredicate predicateWithFormat:predicateString];
+			predicate = [NSPredicate predicateWithFormat: predicateString argumentArray: nil];
 		*ioValue = predicate;
 		retval = YES;
 	}

Sources/BXAttributeDescription.m

 	return retval;
 }
 @end
+
+
+
+@implementation BXAttributeDescription (BXExpressionValue)
+- (enum BXExpressionValueType) getBXExpressionValue: (id *) outValue usingContext: (NSMutableDictionary *) ctx;
+{
+	ExpectR (outValue, kBXExpressionValueTypeUndefined);
+	
+	BXEntityDescription* myEntity = [self entity];
+	BXEntityDescription* primaryRelation = [ctx objectForKey: kBXEntityDescriptionKey];
+	ExpectR (primaryRelation, kBXExpressionValueTypeUndefined);
+	BXAssertValueReturn ([myEntity isEqual: primaryRelation], kBXExpressionValueTypeUndefined, 
+						 @"BXAttributeDescription as expression value is required to be one of the primary relation's attributes.");
+	NSString* key = [self name];
+	*outValue = [NSExpression expressionForKeyPath: key];
+	return kBXExpressionValueTypeEvaluated;
+}
+@end

Sources/BXAttributeDescriptionPrivate.h

 //
 
 #import <BaseTen/BXAttributeDescription.h>
+#import <BaseTen/BXExpressionValue.h>
+
 
 @class BXRelationshipDescription;
 @class BXDatabaseObject;
 - (void) removeDependentRelationship: (BXRelationshipDescription *) rel;
 - (NSSet *) dependentRelationships;
 @end
+
+
+@interface BXAttributeDescription (BXExpressionValue) <BXExpressionValue>
+@end

Sources/BXContainerProxy.m

     //Post notifications since modifying a self-updating collection won't cause
     //value cache to be changed.
 	NSString* key = [self key];
+	ExpectL (mOwner && key);
+	
     [mOwner willChangeValueForKey: key];    
     [self handleAddedObjects: objects];
     [mOwner didChangeValueForKey: key];
     //Post notifications since modifying a self-updating collection won't cause
     //value cache to be changed.
 	NSString* key = [self key];
+	ExpectL (mOwner && key);
+
     [mOwner willChangeValueForKey: key];    
     [self handleRemovedObjects: [mContext registeredObjectsWithIDs: ids]];
     [mOwner didChangeValueForKey: key];
 	if (changed)
 	{
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
 		[mOwner willChangeValueForKey: key];    
 		[self handleRemovedObjects: removedObjects];
 		[self handleAddedObjects: addedObjects];
 
 - (void) setEntity: (BXEntityDescription *) entity
 {
-    BXAssertVoidReturn (nil != mContext, @"Expected mContext not to be nil.");
+	ExpectV (mContext);
     
     //Set up the modification notification
     if (mEntity != entity) 
         mEntity = [entity retain];
         
         NSNotificationCenter* nc = [mContext notificationCenter];
+		ExpectV (nc);
         [nc removeObserver: self];
         
         SEL addSelector = @selector (addedObjects:);

Sources/BXDatabaseContext.m

 			if (0 < [rels count])
 			{
 				oldTargets = [self targetsByObject: objects forRelationships: rels fireFaults: NO];
-				newTargets= [self targetsByObject: objects forRelationships: rels fireFaults: YES];
+				newTargets = [self targetsByObject: objects forRelationships: rels fireFaults: YES];
 				BXEnumerate (currentObject, e, [objects objectEnumerator])
 					[currentObject willChangeInverseToOneRelationships: rels from: oldTargets to: newTargets];
 			}

Sources/BXExpressionValue.h

+//
+// BXExpressionValue.h
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Foundation/Foundation.h>
+
+
+enum BXExpressionValueType
+{
+	kBXExpressionValueTypeUndefined = 0,
+	kBXExpressionValueTypeConstant,
+	kBXExpressionValueTypeEvaluated,
+	kBXExpressionValueTypeVerbatim
+};
+
+
+@protocol BXExpressionValue
+- (enum BXExpressionValueType) getBXExpressionValue: (id *) outValue usingContext: (NSMutableDictionary *) context;
+@end

Sources/BXPGAdditions.m

 	return [[self name] BXPGEscapedName: connection];
 }
 
-- (id) PGTSConstantExpressionValue: (NSMutableDictionary *) ctx
-{
-	BXEntityDescription* myEntity = [self entity];
-	BXEntityDescription* primaryRelation = [ctx objectForKey: kBXEntityDescriptionKey];
-	Expect (primaryRelation);
-	BXAssertValueReturn ([myEntity isEqual: primaryRelation], nil, 
-						 @"BXAttributeDescription as expression value is required to be one of the primary relation's attributes.");
-	NSString* key = [self name];
-	return [NSExpression expressionForKeyPath: key];
-}
-
 - (void) BXPGVisitKeyPathComponent: (id <BXPGExpressionVisitor>) visitor
 {
 	[visitor visitAttribute: self];

Sources/BXPGSQLExpressionValueType.h

+//
+// BXPGSQLExpressionValueType.h
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Foundation/Foundation.h>
+#import <BaseTen/BXPGObjectExpressionValueType.h>
+
+
+@interface BXPGSQLExpressionValueType : BXPGObjectExpressionValueType
+{
+}
+@end

Sources/BXPGSQLExpressionValueType.m

+//
+// BXPGSQLExpressionValueType.m
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import "BXPGSQLExpressionValueType.h"
+#import "BXLogger.h"
+
+
+@implementation BXPGSQLExpressionValueType
+- (NSString *) expressionSQL: (id <BXPGExpressionHandler>) visitor
+{
+	return [mValue description];
+}
+@end

Sources/BXPredicateVisitor.m

 #import "BXPGQueryHandler.h"
 #import "BXPGIdentityExpressionValueType.h"
 #import "BXEnumerate.h"
+#import "BXPGSQLExpressionValueType.h"
 
 
 enum ComparisonType
 {
 	BXPGExpressionValueType* retval = nil;
 	id constantValue = [expression constantValue];
-    if (YES == [constantValue respondsToSelector: @selector (PGTSConstantExpressionValue:)])
-    {
+	if ([constantValue conformsToProtocol: @protocol (BXExpressionValue)])
+	{
 		//If we need some special behaviour, like translating boolean NSNumbers to true or false
 		//instead of 1 or 0, this is the place to do it.
-        id value = [constantValue PGTSConstantExpressionValue: mContext];
-		if ([value isKindOfClass: [NSExpression class]])
-			retval = [value BXPGVisitExpression: self];
-		else
-			retval = [BXPGExpressionValueType valueTypeForObject: value];
-    }
+		id value = nil;
+		enum BXExpressionValueType valueType = [constantValue getBXExpressionValue: &value usingContext: mContext];
+		switch (valueType)
+		{
+			case kBXExpressionValueTypeEvaluated:
+				retval = [value BXPGVisitExpression: self];
+				break;
+				
+			case kBXExpressionValueTypeConstant:
+				retval = [BXPGExpressionValueType valueTypeForObject: value];
+				break;
+								
+			case kBXExpressionValueTypeVerbatim:
+				retval = [BXPGSQLExpressionValueType typeWithValue: value];
+				break;
+				
+			default:
+				BXLogAssertionFailure (@"Unexpected expression value type: %d", valueType);
+				break;
+		}
+		
+		Expect (value);
+	}
 	else
 	{
 		retval = [self evaluateExpression: expression];
 	}
-	return retval;
+	return retval;	
 }
 
 - (BXPGExpressionValueType *) visitEvaluatedObjectExpression: (NSExpression *) expression

Sources/BXSetHelperTableRelationProxy.m

 		//Post notifications since modifying a self-updating collection won't cause
 		//value cache to be changed.
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
 		[mOwner willChangeValueForKey: key];
         [self handleAddedObjects: [mContext faultsWithIDs: objectIDs]];
 		[mOwner didChangeValueForKey: key];
 	{
 		//See above.
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
 		[mOwner willChangeValueForKey: key];
         [self handleRemovedObjects: [mContext registeredObjectsWithIDs: objectIDs]];
 		[mOwner didChangeValueForKey: key];
 	{
 		//See above.
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
 		[mOwner willChangeValueForKey: key];
 		if (0 < [removedIDs count])
 			[self handleRemovedObjects: [mContext registeredObjectsWithIDs: removedIDs]];

Sources/BXSetProxy.m

 	{
 		NSSet* change = [NSSet setWithArray: objects];
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
 		[mOwner willChangeValueForKey: key
 					  withSetMutation: NSKeyValueUnionSetMutation 
 						 usingObjects: change];
 	if (0 < [change count])
 	{
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
 		[mOwner willChangeValueForKey: key
 					  withSetMutation: NSKeyValueMinusSetMutation 
 						 usingObjects: change];
     if (changed)
     {
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
         [mOwner willChangeValueForKey: key withSetMutation: mutation usingObjects: changed];
         switch (mutation)
         {

Sources/BXSetRelationProxy.m

         mContainer = oldValue;
         mForwardToHelper = NO;
 		NSString* key = [self key];
+		ExpectL (mOwner && key);
+
         [mOwner willChangeValueForKey: key
                       withSetMutation: mutationKind
                          usingObjects: changed];

Sources/BXVerbatimExpressionValue.h

+//
+// BXVerbatimExpressionValue.h
+// BaseTen
+//
+// Copyright (C) 2006-2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Foundation/Foundation.h>
+#import <BaseTen/BXExpressionValue.h>
+
+
+@interface BXVerbatimExpressionValue : NSObject <BXExpressionValue>
+{
+	id mValue;
+}
++ (id) valueWithString: (NSString *) aString;
+- (id) initWithString: (NSString *) aString;
+@end

Sources/BXVerbatimExpressionValue.m

+//
+// BXVerbatimExpressionValue.m
+// BaseTen
+//
+// Copyright (C) 2006-2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import "BXVerbatimExpressionValue.h"
+#import "BXLogger.h"
+
+
+@implementation BXVerbatimExpressionValue
++ (id) valueWithString: (NSString *) aString
+{
+	id retval = [[[self alloc] initWithString: aString] autorelease];
+	return retval;
+}
+
+- (id) initWithString: (NSString *) aString
+{
+	if ((self = [super init]))
+	{
+		mValue = [aString retain];
+	}
+	return self;
+}
+
+- (void) dealloc
+{
+	[mValue release];
+	[super dealloc];
+}
+
+- (enum BXExpressionValueType) getBXExpressionValue: (id *) outValue usingContext: (NSMutableDictionary *) context
+{
+	ExpectR (outValue, kBXExpressionValueTypeUndefined);
+	*outValue = mValue;
+    return kBXExpressionValueTypeVerbatim;
+}
+@end

Sources/BaseTen.h

 #import <BaseTen/BXRelationshipDescription.h>
 #import <BaseTen/BXException.h>
 #import <BaseTen/BXContainerProxy.h>
+#import <BaseTen/BXVerbatimExpressionValue.h>
 
 /*
  * Helpful breakpoints:

Sources/NSAttributeDescription+BXPGAdditions.m

 #import "NSAttributeDescription+BXPGAdditions.h"
 #import "NSPredicate+PGTSAdditions.h"
 #import "BXHOM.h"
-#import "PGTSConstantValue.h"
+#import "BXVerbatimExpressionValue.h"
 #import "BXLogger.h"
 #import "PGTSFoundationObjects.h"
 #import "PGTSConstants.h"
 CharLengthExpression (NSString* name)
 {
 	NSString* fcall = [NSString stringWithFormat: @"char_length (\"%@\")", name];
-	PGTSConstantValue* value = [PGTSConstantValue valueWithString: fcall];
+	BXVerbatimExpressionValue* value = [BXVerbatimExpressionValue valueWithString: fcall];
 	NSExpression* retval = [NSExpression expressionForConstantValue: value];
 	return retval;
 }

Sources/NSExpression+PGTSAdditions.m

         case NSConstantValueExpressionType:
         {
             id constantValue = [self constantValue];
-            if (YES == [constantValue respondsToSelector: @selector (PGTSConstantExpressionValue:)])
-            {
-                retval = [constantValue PGTSConstantExpressionValue: context];
-                break;
-            }
-            //Otherwise continue.
+			if ([constantValue conformsToProtocol: @protocol (BXExpressionValue)])
+			{
+				enum BXExpressionValueType retvalType = [constantValue getBXExpressionValue: &retval usingContext: context];
+				if (kBXExpressionValueTypeEvaluated != retvalType)
+					break;
+
+				//Otherwise continue.
+			}
         }
 
         case NSEvaluatedObjectExpressionType:

Sources/NSNumber+BaseTenAdditions.h

 //
 
 #import <Foundation/Foundation.h>
+#import <BaseTen/BXExpressionValue.h>
+
 
 
 @interface NSNumber (BaseTenAdditions)
 @end
+
+
+
+@interface NSNumber (BXExpressionValue) <BXExpressionValue>
+@end

Sources/NSNumber+BaseTenAdditions.mm

 
 #import "NSNumber+BaseTenAdditions.h"
 #import "NSValue+BaseTenAdditions.h"
+#import "BXLogger.h"
 
 
 @implementation NSNumber (BaseTenAdditions)
 	return retval;
 }
 @end
+
+
+
+@implementation NSNumber (BXExpressionValue)
+- (enum BXExpressionValueType) getBXExpressionValue: (id *) outValue usingContext: (NSMutableDictionary *) context;
+{
+	ExpectR (outValue, kBXExpressionValueTypeUndefined);
+	
+	if (0 == strcmp ("c", [self objCType]))
+		*outValue = ([self boolValue] ? @"true" : @"false");
+	else
+		*outValue = self;
+	
+	return kBXExpressionValueTypeConstant;
+}
+@end

Sources/PGTSAdditions.h

 @class PGTSConnection;
 
 
-@interface NSObject (PGTSOptionalAdditions)
-- (id) PGTSConstantExpressionValue: (NSDictionary *) context;
-@end
-
-
 @interface NSObject (PGTSAdditions)
 - (NSString *) PGTSEscapedObjectParameter: (PGTSConnection *) connection;
 - (NSString *) PGTSEscapedName: (PGTSConnection *) connection;

Sources/PGTSAdditions.m

 	return retval;
 }
 @end
-
-
-@implementation NSNumber (PGTSAdditions)
-- (id) PGTSConstantExpressionValue: (NSDictionary *) context
-{
-	id retval = self;
-	if (0 == strcmp ("c", [self objCType]))
-		retval = ([self boolValue] ? @"true" : @"false");
-    return retval;
-}
-@end

Sources/PGTSConstantValue.h

-//
-// PGTSConstantValue.h
-// BaseTen
-//
-// Copyright (C) 2006-2008 Marko Karppinen & Co. LLC.
-//
-// Before using this software, please review the available licensing options
-// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
-// us at sales@karppinen.fi. Without an additional license, this software
-// may be distributed only in compliance with the GNU General Public License.
-//
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License, version 2.0,
-// as published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-//
-// $Id$
-//
-
-#import <Foundation/Foundation.h>
-
-
-@interface PGTSConstantValue : NSObject 
-{
-	id mValue;
-}
-+ (id) valueWithString: (NSString *) aString;
-- (id) initWithString: (NSString *) aString;
-@end

Sources/PGTSConstantValue.m

-//
-// PGTSConstantValue.m
-// BaseTen
-//
-// Copyright (C) 2006-2008 Marko Karppinen & Co. LLC.
-//
-// Before using this software, please review the available licensing options
-// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
-// us at sales@karppinen.fi. Without an additional license, this software
-// may be distributed only in compliance with the GNU General Public License.
-//
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License, version 2.0,
-// as published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-//
-// $Id$
-//
-
-#import "PGTSConstantValue.h"
-
-
-@implementation PGTSConstantValue
-+ (id) valueWithString: (NSString *) aString
-{
-	id retval = [[[self alloc] initWithString: aString] autorelease];
-	return retval;
-}
-
-- (id) initWithString: (NSString *) aString
-{
-	if ((self = [super init]))
-	{
-		mValue = [aString retain];
-	}
-	return self;
-}
-
-- (void) dealloc
-{
-	[mValue release];
-	[super dealloc];
-}
-
-- (id) PGTSConstantExpressionValue: (id) context
-{
-    return mValue;
-}
-@end

UnitTests/Sources/BXPredicateTests.m

 	mConnection = [[handler connection] retain];
 }
 
+
 - (void) tearDown
 {
 	[mQueryBuilder release];
 	[super tearDown];
 }
 
+
 - (void) testAddition
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"1 + 2 == 3"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testSubtraction
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"3 - 2 == 1"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testBegins
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"'foobar' BEGINSWITH 'foo'"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testEndsCase
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"'foobar' ENDSWITH[c] 'b%a_r'"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testBetween
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"2 BETWEEN {1, 3}"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testGt
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"1 < 2"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testContains
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"{1, 2, 3} CONTAINS 2"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testIn
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"2 IN {1, 2, 3}"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testIn2
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"'bb' IN 'aabbccdd'"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testIn3
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"'bb' IN[c] 'aabbccdd'"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testAndOr
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"1 < 2 AND (2 < 3 OR 4 > 5)"];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testNull
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"1 == %@", [NSNull null]];
 	MKCAssertEqualObjects (parameters, expected);
 }
 
+
 - (void) testAdditionWithKeyPath
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"1 + id == 2"];
 	MKCAssertEqualObjects (parameters, expected);	
 }
 
+
 - (void) testDiacriticInsensitivity
 {
 	NSPredicate* predicate = [NSPredicate predicateWithFormat: @"'a' LIKE[cd] 'b'"];
 }
 
 
+- (void) testCustomExpression
+{
+	BXVerbatimExpressionValue *val = [BXVerbatimExpressionValue valueWithString: @"SESSION_USER"];
+	NSExpression *lhs = [NSExpression expressionForConstantValue: val];
+	NSExpression *rhs = [NSExpression expressionForConstantValue: @"tsnorri"];
+	
+	NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression: lhs
+																rightExpression: rhs
+																	   modifier: NSDirectPredicateModifier
+																		   type: NSEqualToPredicateOperatorType
+																		options: 0];
+	
+	[mQueryBuilder setQueryType: kBXPGQueryTypeSelect];
+	NSString *whereClause = [mQueryBuilder whereClauseForPredicate: predicate entity: nil connection: mConnection].p_where_clause;
+	MKCAssertEqualObjects (whereClause, @"$1 = SESSION_USER");
+	NSArray *parameters = [mQueryBuilder parameters];
+	MKCAssertEqualObjects (parameters, [NSArray arrayWithObject: @"tsnorri"]);
+}
 @end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.