Skip to content

Commit

Permalink
Added an NSArray style interface to ARBase
Browse files Browse the repository at this point in the history
  • Loading branch information
fjolnir committed Aug 29, 2008
1 parent 52aaa37 commit b7ba943
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 0 deletions.
30 changes: 30 additions & 0 deletions ActiveRecord.xcodeproj/project.pbxproj
Expand Up @@ -15,6 +15,9 @@
F80750CB0E22BFAC006504CC /* inflections.plist in Resources */ = {isa = PBXBuildFile; fileRef = F80750C20E22BFAC006504CC /* inflections.plist */; };
F80750CC0E22BFAC006504CC /* singulars.plist in Resources */ = {isa = PBXBuildFile; fileRef = F80750C40E22BFAC006504CC /* singulars.plist */; };
F80750CD0E22BFAC006504CC /* uncountables.plist in Resources */ = {isa = PBXBuildFile; fileRef = F80750C60E22BFAC006504CC /* uncountables.plist */; };
F81CC1620E608994004CA13A /* ARBaseArrayInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F81CC1600E608994004CA13A /* ARBaseArrayInterface.h */; settings = {ATTRIBUTES = (Public, ); }; };
F81CC1630E608994004CA13A /* ARBaseArrayInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = F81CC1610E608994004CA13A /* ARBaseArrayInterface.m */; };
F81CC1E70E609E32004CA13A /* ARBaseArrayInterfaceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F81CC1E60E609E32004CA13A /* ARBaseArrayInterfaceTest.m */; };
F834BE060E2A7A4200191322 /* chartables.c in Sources */ = {isa = PBXBuildFile; fileRef = F834BDFB0E2A7A4200191322 /* chartables.c */; };
F834BE070E2A7A4200191322 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = F834BDFC0E2A7A4200191322 /* config.h */; };
F834BE080E2A7A4200191322 /* get.c in Sources */ = {isa = PBXBuildFile; fileRef = F834BDFD0E2A7A4200191322 /* get.c */; };
Expand All @@ -34,6 +37,8 @@
F87B106B0E06F74C00580499 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F87B106A0E06F74C00580499 /* libsqlite3.dylib */; };
F87B106E0E06F76300580499 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F87B106D0E06F76300580499 /* libcrypto.dylib */; };
F87B108F0E06F7FF00580499 /* ActiveRecord.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* ActiveRecord.framework */; };
F87CDB2C0E65EF400054FA45 /* NSObject+iPhoneHacks.h in Headers */ = {isa = PBXBuildFile; fileRef = F87CDB2A0E65EF400054FA45 /* NSObject+iPhoneHacks.h */; };
F87CDB2D0E65EF410054FA45 /* NSObject+iPhoneHacks.m in Sources */ = {isa = PBXBuildFile; fileRef = F87CDB2B0E65EF400054FA45 /* NSObject+iPhoneHacks.m */; };
F8D301F20E17A9F30075AFFF /* my_alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D301E80E17A9F30075AFFF /* my_alloc.h */; };
F8D301F30E17A9F30075AFFF /* my_list.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D301E90E17A9F30075AFFF /* my_list.h */; };
F8D301F40E17A9F30075AFFF /* mysql.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D301EA0E17A9F30075AFFF /* mysql.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -110,6 +115,10 @@
F80750C50E22BFAC006504CC /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = English; path = English.lproj/singulars.plist; sourceTree = "<group>"; };
F80750C70E22BFAC006504CC /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = English; path = English.lproj/uncountables.plist; sourceTree = "<group>"; };
F807FA730E3A6B0D00AB3808 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.markdown; sourceTree = "<group>"; };
F81CC1600E608994004CA13A /* ARBaseArrayInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARBaseArrayInterface.h; sourceTree = "<group>"; };
F81CC1610E608994004CA13A /* ARBaseArrayInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARBaseArrayInterface.m; sourceTree = "<group>"; };
F81CC1E50E609E32004CA13A /* ARBaseArrayInterfaceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARBaseArrayInterfaceTest.h; sourceTree = "<group>"; };
F81CC1E60E609E32004CA13A /* ARBaseArrayInterfaceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARBaseArrayInterfaceTest.m; sourceTree = "<group>"; };
F834BDFB0E2A7A4200191322 /* chartables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chartables.c; sourceTree = "<group>"; };
F834BDFC0E2A7A4200191322 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
F834BDFD0E2A7A4200191322 /* get.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = get.c; sourceTree = "<group>"; };
Expand All @@ -136,6 +145,8 @@
F87B10400E06F6D500580499 /* SenTestCase+Fixtures.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SenTestCase+Fixtures.m"; sourceTree = "<group>"; };
F87B106A0E06F74C00580499 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
F87B106D0E06F76300580499 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; };
F87CDB2A0E65EF400054FA45 /* NSObject+iPhoneHacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+iPhoneHacks.h"; sourceTree = "<group>"; };
F87CDB2B0E65EF400054FA45 /* NSObject+iPhoneHacks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+iPhoneHacks.m"; sourceTree = "<group>"; };
F882A3D90E070C6700C375FB /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
F8D301E80E17A9F30075AFFF /* my_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = my_alloc.h; sourceTree = "<group>"; };
F8D301E90E17A9F30075AFFF /* my_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = my_list.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -334,6 +345,8 @@
F83BC4D60E5C4C6E00E474B8 /* Bindings */ = {
isa = PBXGroup;
children = (
F81CC1600E608994004CA13A /* ARBaseArrayInterface.h */,
F81CC1610E608994004CA13A /* ARBaseArrayInterface.m */,
);
path = Bindings;
sourceTree = "<group>";
Expand All @@ -345,6 +358,8 @@
F87B10340E06F6D500580499 /* AGRegexTest.m */,
F87B10350E06F6D500580499 /* ARBaseTest.h */,
F87B10360E06F6D500580499 /* ARBaseTest.m */,
F81CC1E50E609E32004CA13A /* ARBaseArrayInterfaceTest.h */,
F81CC1E60E609E32004CA13A /* ARBaseArrayInterfaceTest.m */,
F87B10370E06F6D500580499 /* ARInflectorTest.h */,
F87B10380E06F6D500580499 /* ARInflectorTest.m */,
F87B10390E06F6D500580499 /* ARMySQLConnectionTest.h */,
Expand All @@ -357,6 +372,15 @@
path = "Unit tests";
sourceTree = "<group>";
};
F87CDB270E65EF140054FA45 /* iPhone Hacks */ = {
isa = PBXGroup;
children = (
F87CDB2A0E65EF400054FA45 /* NSObject+iPhoneHacks.h */,
F87CDB2B0E65EF400054FA45 /* NSObject+iPhoneHacks.m */,
);
path = "iPhone Hacks";
sourceTree = "<group>";
};
F882A3E10E070C7100C375FB /* iPhone libraries */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -464,6 +488,7 @@
F8DA530A0E058F10002C3ADB /* NSData-Base64Extensions.m */,
F8DA530D0E058F10002C3ADB /* NSString-Base64Extensions.h */,
F8DA530E0E058F10002C3ADB /* NSString-Base64Extensions.m */,
F87CDB270E65EF140054FA45 /* iPhone Hacks */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -507,6 +532,8 @@
F834BE090E2A7A4200191322 /* internal.h in Headers */,
F834BE0C0E2A7A4200191322 /* pcre.h in Headers */,
F834BE0E0E2A7A4200191322 /* AGRegex.h in Headers */,
F81CC1620E608994004CA13A /* ARBaseArrayInterface.h in Headers */,
F87CDB2C0E65EF400054FA45 /* NSObject+iPhoneHacks.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -668,6 +695,8 @@
F834BE0B0E2A7A4200191322 /* pcre.c in Sources */,
F834BE0D0E2A7A4200191322 /* study.c in Sources */,
F834BE0F0E2A7A4200191322 /* AGRegex.m in Sources */,
F81CC1630E608994004CA13A /* ARBaseArrayInterface.m in Sources */,
F87CDB2D0E65EF410054FA45 /* NSObject+iPhoneHacks.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -681,6 +710,7 @@
F87B10460E06F6D500580499 /* ARMySQLConnectionTest.m in Sources */,
F87B10470E06F6D500580499 /* ARSQLiteConnectionTest.m in Sources */,
F87B104A0E06F6D500580499 /* SenTestCase+Fixtures.m in Sources */,
F81CC1E70E609E32004CA13A /* ARBaseArrayInterfaceTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
125 changes: 125 additions & 0 deletions Source/Bindings/ARBaseArrayInterface.h
@@ -0,0 +1,125 @@
////////////////////////////////////////////////////////////////////////////////////////////
//
// ARBaseArrayInterface.h
// An NSArray style interface to ARBase records
//
////////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007, Fjölnir Ásgeirsson
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list of conditions
// and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided with
// the distribution.
// Neither the name of Fjölnir Ásgeirsson, ninja kitten nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _ARBASE_ARRAYINTERFACE_H_
#define _ARBASE_ARRAYINTERFACE_H_
#import <Cocoa/Cocoa.h>
#import <ActiveRecord/ARBase.h>

/*!
* An NSArray style interface to ARBase records\n
* \n
* The interface is by no means compatible with NSMutableArray. It implements only what's required to
* implement binding support for ActiveRecord\n
* \n
* To use ARBaseArrayInterface, subclass it with a class named <prefix>ModelNameArrayInterface
* ARBaseArrayInterface will then determine the name of the model to use (<prefix>ModelNameArrayInterface -> modelname)\n
* \n
* <b>Do not</b> use ARBaseArrayInterface directly. Hic sunt dracones
*/
@interface ARBaseArrayInterface : NSObject {
NSMutableDictionary *queryInfo;
}
@property(readwrite, retain) NSMutableDictionary *queryInfo;

/*! Finds records based on the find specification.
* @param idOrSpecification The find specification
*/
+ (id)find:(ARFindSpecification)idOrSpecification;
/*! Finds records based on the find specification, filter and limit using the specified connection.
* @param idOrSpecification The find specification
* @param limit The maximum number of records to retrieve
*/
+ (id)find:(ARFindSpecification)idOrSpecification connection:(id<ARConnection>)connection;
/*! Finds records based on the find specification, filter and limit.
* @param idOrSpecification The find specification
* @param whereSQL A valid SQL WHERE statement (omitting the actual "WHERE")
* @param orderSQL A valud SQL ORDER statement (omitting the actual "ORDER BY")
* @param limit The maximum number of records to retrieve
*/
+ (id)find:(ARFindSpecification)idOrSpecification
filter:(NSString *)whereSQL
join:(NSString *)joinSQL
order:(NSString *)orderSQL
limit:(NSUInteger)limit;

/*! Finds records based on the find specification, filter and limit using the specified connection.
* @param idOrSpecification The find specification
* @param whereSQL A valid SQL WHERE statement (omitting the actual "WHERE")
* @param orderSQL A valud SQL ORDER statement (omitting the actual "ORDER BY")
* @param limit The maximum number of records to retrieve
* @param connection The connection to use for the record. (Pass nil to use the default connection)
*/
+ (id)find:(ARFindSpecification)idOrSpecification
filter:(NSString *)whereSQL
join:(NSString *)joinSQL
order:(NSString *)orderSQL
limit:(NSUInteger)limit
connection:(id<ARConnection>)aConnection;

/*! Returns the class name of the model to use */
+ (NSString *)modelName;
/*! Returns the model class to use */
+ (Class)modelClass;

/*! Returns an array of dictionaries containing the database ids matching records */
- (NSArray *)matchingIds;
/*! Returns an array of records matching the find specification */
- (NSArray *)allObjects;

/*! Returns the nth record matching the find specification\n
* @param index The index to look up
*/
- (id)objectAtIndex:(NSUInteger)index;
/*! Returns the last record matching the find specification */
- (id)lastObject;

/*! Adds a record to the database
* @param object A NSDictionary containing attributes for the record.
*/
- (void)addObject:(NSDictionary *)attributes;

/*! Destroys the nth record matching the find specification
* @param index The index of the record to destroy
*/
- (BOOL)removeObjectAtIndex:(NSUInteger)index;

/*! Returns the number of records matching the find specification */
- (NSUInteger)count;

/*! Returns an array containing the results of invoking valueForKey: using key on each of the receiver's records. */
- (NSArray *)valueForKey:(NSString *)key;
/*! Invokes setValue:forKey: on each of the receiver's records using the specified value and key. */
- (void)setValue:(id)value forKey:(NSString *)key;
@end
#endif _ARBASE_ARRAYINTERFACE_H_
160 changes: 160 additions & 0 deletions Source/Bindings/ARBaseArrayInterface.m
@@ -0,0 +1,160 @@
//
// ARBaseArrayInterface.m
// ActiveRecord
//
// Created by Fjölnir Ásgeirsson on 23.8.2008.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "ARBaseArrayInterface.h"


@implementation ARBaseArrayInterface
@synthesize queryInfo;
#pragma mark -
#pragma mark Creation
+ (id)find:(ARFindSpecification)idOrSpecification
{
return [self find:idOrSpecification
connection:[ARBase defaultConnection]];
}
+ (id)find:(ARFindSpecification)idOrSpecification connection:(id<ARConnection>)connection
{
return [self find:idOrSpecification
filter:nil
join:nil
order:nil
limit:0
connection:connection];
}
+ (id)find:(ARFindSpecification)idOrSpecification
filter:(NSString *)whereSQL
join:(NSString *)joinSQL
order:(NSString *)orderSQL
limit:(NSUInteger)limit
{
return [self find:idOrSpecification
filter:whereSQL
join:joinSQL
order:orderSQL
limit:limit
connection:[ARBase defaultConnection]];
}

+ (id)find:(ARFindSpecification)idOrSpecification
filter:(NSString *)whereSQL
join:(NSString *)joinSQL
order:(NSString *)orderSQL
limit:(NSUInteger)limit
connection:(id<ARConnection>)aConnection
{
ARBaseArrayInterface *ret = [[self alloc] init];
[ret.queryInfo setObject:[NSNumber numberWithInt:idOrSpecification] forKey:@"findSpecification"];
if(whereSQL)
[ret.queryInfo setObject:whereSQL forKey:@"whereSQL"];
if(joinSQL)
[ret.queryInfo setObject:joinSQL forKey:@"joinSQL"];
if(orderSQL)
[ret.queryInfo setObject:orderSQL forKey:@"orderSQL"];
[ret.queryInfo setObject:[NSNumber numberWithInt:limit] forKey:@"limit"];
if(aConnection)
[ret.queryInfo setObject:aConnection forKey:@"connection"];

return [ret autorelease];
}
- (id)init
{
if(![super init])
return nil;
self.queryInfo = [NSMutableDictionary dictionary];

return self;
}

#pragma mark -
+ (NSString *)modelName
{
NSMutableString *ret = [[[self className] mutableCopy] autorelease];
[ret replaceOccurrencesOfString:@"ArrayInterface"
withString:@""
options:0
range:NSMakeRange(0, [ret length])];
return ret;
}
+ (Class)modelClass
{
return NSClassFromString([self modelName]);
}

#pragma mark -
#pragma mark Database access
- (NSArray *)matchingIds
{
Class modelClass = [[self class] modelClass];
return [modelClass findIds:[[queryInfo objectForKey:@"findSpecification"] intValue]
filter:[queryInfo objectForKey:@"whereSQL"]
join:[queryInfo objectForKey:@"joinSQL"]
order:[queryInfo objectForKey:@"orderSQL"]
limit:[queryInfo objectForKey:@"limit"]
connection:[queryInfo objectForKey:@"connection"]];
}
- (NSArray *)allObjects
{
Class modelClass = [[self class] modelClass];
return (NSArray *)[modelClass find:[[queryInfo objectForKey:@"findSpecification"] intValue]
filter:[queryInfo objectForKey:@"whereSQL"]
join:[queryInfo objectForKey:@"joinSQL"]
order:[queryInfo objectForKey:@"orderSQL"]
limit:[[queryInfo objectForKey:@"limit"] intValue]
connection:[queryInfo objectForKey:@"connection"]];
}
- (id)objectAtIndex:(NSUInteger)index
{
// Fetch the id
Class modelClass = [[self class] modelClass];
NSArray *ids = [self matchingIds];
if([ids count] > index)
return [[[modelClass alloc] initWithId:[[[ids objectAtIndex:index] objectForKey:@"id"] unsignedIntValue]] autorelease];
return nil;
}
- (id)lastObject
{
NSUInteger count = [self count];
if(count > 0)
return [self objectAtIndex:count - 1];
return nil;
}
- (void)addObject:(NSDictionary *)attributes
{
[[[self class] modelClass] createWithAttributes:attributes connection:[queryInfo objectForKey:@"connection"]];
}

- (BOOL)removeObjectAtIndex:(NSUInteger)index
{
return [[self objectAtIndex:index] destroy];
}

- (NSUInteger)count
{
return [[self matchingIds] count];
}

#pragma mark -
#pragma mark KVC
- (NSArray *)valueForKey:(NSString *)key
{
NSMutableArray *ret = [NSMutableArray array];
for(ARBase *record in [self allObjects])
{
[ret addObject:[record valueForKey:key]];
}
return ret;
}
- (void)setValue:(id)value forKey:(NSString *)key
{
for(ARBase *record in [self allObjects])
{
[record setValue:value forKey:key];
}
}
@end

0 comments on commit b7ba943

Please sign in to comment.