aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2012-02-23 02:13:56 +0000
committerrowanbeentje <rowan@beent.je>2012-02-23 02:13:56 +0000
commit05f1612cbb7e33cf9135a346fc2505cc0e87e853 (patch)
tree785824be4e44a61389271343d958851fa4ff7dd0 /Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m
parenta889340b9cb1eca0d3ff022e8e6e2c718480bf44 (diff)
downloadsequelpro-05f1612cbb7e33cf9135a346fc2505cc0e87e853.tar.gz
sequelpro-05f1612cbb7e33cf9135a346fc2505cc0e87e853.tar.bz2
sequelpro-05f1612cbb7e33cf9135a346fc2505cc0e87e853.zip
Warning: this branch commit is largely untested, and known to throw exceptions as database structure retrieval is currently missing!
Further work on SPMySQLFramework integration: - Improve SPMySQL framework build settings including correct ppc builds and a Distribution configuration for the build distributions to match - Add new convenience querying and result methods to the framework - Amend Sequel Pro source to use the new SPMySQL.framework methods everywhere, replacing MCPKit methods where they differ and improving some functions - Remove MCPKit from the source - Fix a number of warnings on Release-style builds
Diffstat (limited to 'Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m')
-rw-r--r--Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m1342
1 files changed, 0 insertions, 1342 deletions
diff --git a/Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m b/Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m
deleted file mode 100644
index dba963c6..00000000
--- a/Frameworks/MCPKit/MCPEntrepriseKit/MCPObject.m
+++ /dev/null
@@ -1,1342 +0,0 @@
-//
-// $Id$
-//
-// MCPObject.m
-// MCPKit
-//
-// Created by Serge Cohen (serge.cohen@m4x.org) on 19/05/04.
-// Copyright (c) 2004 Serge Cohen. All rights reserved.
-//
-// Forked by the Sequel Pro team (sequelpro.com), April 2009
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-// More info at <http://mysql-cocoa.sourceforge.net/>
-// More info at <http://code.google.com/p/sequel-pro/>
-
-#import "MCPObject.h"
-
-#import <MCPKit/MCPKit.h>
-
-#import "MCPClassDescription.h"
-#import "MCPClassDescription+MCPEntreprise.h"
-#import "MCPAttribute.h"
-#import "MCPRelation.h"
-#import "MCPJoin.h"
-
-@implementation MCPObject
-
-#pragma mark Life of the object
-- (id) init
-/*" Taking care of getting the class description for self (after passing the message up). "*/
-{
-// NSArray theAttributes;
-// unsigned int i;
-
- if (self = [super init]) {
- classDescription = [[NSClassDescription classDescriptionForClass:[self class]] retain];
- [self setAttributesToDefault];
-/*
- theAttributes = [classDescription attributeKeys];
- for (i=0; [theAttributes count] != i; ++i) { // setting the attributtes with proper defaults.
- NSString *theKey = (NSString *) [theAttributes objectAtIndex:i];
-
- [self setValue:[self defaultValueForKey:theKey] forKey:theKey];
- }
- */
- }
- return self;
-}
-
-- (id) initWithDictionary:(NSDictionary *) dictionary
-/*" This method will use the class description to fetch in the dictionary the values of the attributes of the object....
- Should try to get this description a bit clearer."*/
-{
- self = [super init];
- if (self) {
- NSUInteger i;
- NSArray *attrArray;
-
- classDescription = [[NSClassDescription classDescriptionForClass:[self class]] retain];
- [self setAttributesToDefault];
- attrArray = [classDescription attributes];
- for (i=0; [attrArray count] != i; ++i) {
- MCPAttribute *currentAttribute = (MCPAttribute *)[attrArray objectAtIndex:i];
- id currentValue = [dictionary objectForKey:[currentAttribute name]];
-
- if (! currentValue) {
- currentValue = [dictionary objectForKey:[currentAttribute externalName]];
- }
- if (currentValue) {
- [self setValue:currentValue forKey:[currentAttribute name]];
- }
- }
- }
- return self;
-}
-
-- (void) dealloc
-/*" Deallocating the class description, then passes the message to super. "*/
-{
-// unsigned int i;
-// NSArray *tmpAttributes = [classDescription attributes];
-
-/* for (i=0; [tmpAttributes count] != i; ++i) {
- MCPAttribute *tmpAttr = [tmpAttributes objectAtIndex:i];
- if ([tmpAttr valueClass]) {
- [self setValue:nil forKey:[tmpAttr name]];
- }
- }
-*/
- [classDescription release];
- [connection release];
- [super dealloc];
-}
-
-- (void) setAttributesToDefault
-/*" Set all the attributes to default values, except for auto-generated and primary key attributes, which are set to NULL.
-
- NOTE : !! In the current version the auto-generated and key are ALSO set to default values!!.
- "*/
-{
- NSArray *theAttributes = [classDescription attributes];
-// NSArray *thePrimKeys = [classDescription primaryKeyAttributes];
- NSUInteger i;
-
- for (i=0; [theAttributes count] != i; ++i) {
- MCPAttribute *theAttribute = (MCPAttribute *) [theAttributes objectAtIndex:i];
- NSString *theKey = [theAttribute name];
-
- if (! [theAttribute autoGenerated]) {
- [self setValue:[self defaultValueForKey:theKey] forKey:theKey];
- }
- else { // Auto-generated attribute ... set it to NULL:
- [self setValue:[self defaultValueForKey:theKey] forKey:theKey];
- }
- }
-/*
- for (i=0; [thePrimKeys count] != i; ++i) {
- MCPAttribute *theAttribute = (MCPAttribute *) [thePrimKeys objectAtIndex:i];
- if (! [theAttribute autoGenerated]) {
- NSString *theKey = [theAttribute name];
-
- [[self valueForKey:theKey] release];
- [self setValue:NULL forKey:theKey];
- }
- }
- */
- return;
-}
-
-#pragma mark Accessor(s)
-- (MCPClassDescription *) classDescription
-{
- return classDescription;
-}
-
-- (MCPConnection *) connection
-{
- if ((! connection) || (! [connection checkConnection])) {
- [self setConnection:nil];
- }
- return connection;
-}
-
-- (void) setConnection:(MCPConnection *) iConnection
-{
- if (iConnection != connection) {
- [connection release];
- connection = [iConnection retain];
- }
-}
-
-
-
-#pragma mark Database interface
-- (id) readFromDBRow:(NSDictionary *) iDictionary withTableName:(NSString *) iTableName
-/*" Uses a query result row (described as a NSDictionary) to set the instance variables of self. If
- the result contains columns from multiple tables, the iTableName can be used to specify the alias
- used for the table name corresponding to the class.
-
-If iTableName == nil, the columns will be searched first without table name (column_name) and if
- not found then with the table name in front (from the class description : table_name.column_name).
-
-Otherwise, the search will be performed in the following order : iTableName.column_name, column_name,
- table_name.column_name.
- "*/
-{
- NSArray *theAttributeKeys = [classDescription attributeKeys];
- NSArray *thePrefixArray;
- NSUInteger i;
-
-// Depending on the value of iTableName, get the search order.
- if ((nil == iTableName) || ([@"" isEqualToString:iTableName])) {
- thePrefixArray = [NSArray arrayWithObjects:@"", [NSMutableString stringWithFormat:@"%@.", [classDescription externalName]], nil];
- }
- else {
- thePrefixArray = [NSArray arrayWithObjects:[NSString stringWithFormat:@"%@.", iTableName], [NSMutableString stringWithFormat:@"%@.", [classDescription externalName]], @"", nil];
- }
- for (i=0; [theAttributeKeys count] != i; ++i) {
- id theValue = nil;
- MCPAttribute *theAttribute = [classDescription attributeWithName:[theAttributeKeys objectAtIndex:i]];
- NSUInteger j;
-
- for (j=0; [thePrefixArray count] != j; ++j) {
- if (theValue = [iDictionary objectForKey:[NSString stringWithFormat:@"%@%@", [thePrefixArray objectAtIndex:j], [theAttribute externalName]]]) {
- break;
- }
- }
- if (theValue) {
- [self takeValue:theValue forKey:[theAttribute name]];
- }
- }
- return self;
-}
-
-
-//- (MCPDBReturnCode) setPrimaryKey:(NSDictionary *) iDictionary andFetchFromDB:(MCPConnection *) iConnection
-- (MCPDBReturnCode) setPrimaryKey:(id) iDictionary andFetchFromDB:(MCPConnection *) iConnection
-/*" This method is used to retrieve an object from the DB given its precise primary key. It will return self.
- If the object is not found in the DB, then all instance variable are set to the default
- (and autogenerated/primary-key attributes are set to null)."*/
-{
- BOOL missingKey = NO;
- NSArray *theKeyAttr = [classDescription primaryKeyAttributes];
- NSUInteger i;
- NSMutableString *query = [NSMutableString stringWithFormat:@"SELECT * FROM %@ WHERE ", [classDescription externalName]];
- MCPResult *result;
- NSDictionary *row;
-
- [self setConnection:iConnection];
- if (! iConnection) {
- return MCPDBReturnNoConnection;
- }
- for (i=0; [theKeyAttr count] != i; ++i) {
- MCPAttribute *theAttr = [classDescription attributeWithName:[(MCPAttribute *)[theKeyAttr objectAtIndex:i] name]];
- id theKeyValue;
-
-// if (theKeyValue = [iDictionary objectForKey:[theAttr name]]) {
- if (theKeyValue = [iDictionary valueForKey:[theAttr name]]) {
- if (i != 0) {
- [query appendString:@" and "];
- }
-// Implies the iDictionary IS a dictionary:
-// [query appendFormat:@"(%@ = %@)", [theAttr externalName], [iConnection quoteObject:[iDictionary objectForKey:[theAttr name]]]];
-// If the iDictionary is just an object complying with NSValueCodeing:
- [query appendFormat:@"(%@ = %@)", [theAttr externalName], [iConnection quoteObject:theKeyValue]];
- }
- else { // Part of the primary key is missing... look for the DB name of the attribute
- if (theKeyValue = [iDictionary valueForKey:[theAttr externalName]]) {
- if (i != 0) {
- [query appendString:@" and "];
- }
- [query appendFormat:@"(%@ = %@)", [theAttr externalName], [iConnection quoteObject:theKeyValue]];
- }
- else { // Not able to find the value for this attribute !!!
- missingKey = YES;
- NSLog(@"Unable to find the value for attribute %@ of object of class %@, will make it default", [theAttr name], [self className]);
- break;
- }
- }
- } // Now the query is prepared... or a key part is missing:
- if (missingKey) {
- [self setAttributesToDefault];
- return MCPDBReturnIncompleteKey;
- }
- result = [iConnection queryString:query];
- if ([result numOfRows] == 0) {
- [self setAttributesToDefault];
- return MCPDBReturnNone;
- }
- row = [result fetchRowAsDictionary];
- [self readFromDBRow:row withTableName:@""];
- if ([result numOfRows] != 1) {
- NSLog(@"Got more than one row when querying : %@.... will take only the first one!!! that an IMPORTANT flaw in your data model!!!", query);
- return MCPDBReturnMultiple;
- }
- return MCPDBReturnOK;
-}
-
-
-- (NSDictionary *) checkDBId
-/*" Using the identity properties of the class, this method will check if self already exists in the DB,
- in which case it will set the primary key attributes to match the DB entry. If the object is not present
- in the DB, the primary key attributes are set to null if they are declared as aut-generated (untouched otherwise).
-
-The returned dictionary contains the values of the primary key attributes. It also contains one entry with
- key MCPDBReturnCode, which contains the result of the operation (was the object in DB?).
-
-If the identityAttributes of the class description is empty, the entry will always be considered not to be
- in the DB, AND the primary key attributes of the object will be left unchnaged and returned as they are at
- call time."*/
-{
- NSArray *theIdAttr = [classDescription identityAttributes];
- NSMutableDictionary *theKeys = [NSMutableDictionary dictionary];
- NSArray *theKeyAttr = [classDescription primaryKeyAttributes];
- MCPConnection *theConnection = [self connection];
- MCPResult *theResult;
- NSUInteger i;
-
- if (! theConnection) {
- return [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:MCPDBReturnNoConnection], @"MCPDBReturnCode", nil];
- }
- if (! [theKeyAttr count]) { // There is no primary key for this object.
- [theKeys setObject:[NSNumber numberWithInteger:MCPDBReturnNoKey] forKey:@"MCPDBReturnCode"];
- return [NSDictionary dictionaryWithDictionary:theKeys];
- }
- if (! [theIdAttr count]) { // Identity is not defined for this object.
- [theKeys setObject:[NSNumber numberWithInteger:MCPDBReturnNoIdentity] forKey:@"MCPDBReturnCode"];
- for (i=0; [theKeyAttr count] != i; ++i) {
- NSString *theKey = [(MCPAttribute*)[theKeyAttr objectAtIndex:i] name];
- [theKeys setObject:[self valueForKey:theKey] forKey:theKey];
- }
- return [NSDictionary dictionaryWithDictionary:theKeys];
- }
-// Do the fetch in the DB.
- NSMutableString *theQuery = [NSMutableString stringWithString:@"SELECT "];
-
- for (i = 0; [theKeyAttr count] != i; ++i) {
- if (i) {
- [theQuery appendString:@", "];
- }
- [theQuery appendString:[(MCPAttribute *)[theKeyAttr objectAtIndex:i] externalName]];
- }
- [theQuery appendFormat:@" FROM %@ WHERE ", [classDescription externalName]];
- for (i = 0; [theIdAttr count] != i; ++i) {
- if (i) {
- [theQuery appendString:@" AND "];
- }
-/*
- if ([[(MCPAttribute *)[theIdAttr objectAtIndex:i] valueClass] isSubclassOfClass:[NSString class]]) {
- if ([(MCPAttribute *)[theIdAttr objectAtIndex:i] width] != 0) {
- [theQuery appendFormat:@"(BINARY %@ = SUBSTRING(%@ FROM 1 FOR %u)", [(MCPAttribute *)[theIdAttr objectAtIndex:i] externalName], [theConnection quoteObject:[self valueForKey:[(MCPAttribute *)[theIdAttr objectAtIndex:i] name]]], [(MCPAttribute *)[theIdAttr objectAtIndex:i] width]];
- }
- else {
- [theQuery appendFormat:@"(BINARY %@ = %@)", [(MCPAttribute *)[theIdAttr objectAtIndex:i] externalName], [theConnection quoteObject:[self valueForKey:[(MCPAttribute *)[theIdAttr objectAtIndex:i] name]]]];
- }
- }
- */
- if (([[(MCPAttribute *)[theIdAttr objectAtIndex:i] valueClass] isSubclassOfClass:[NSString class]]) && ([(MCPAttribute *)[theIdAttr objectAtIndex:i] width] != 0)) {
- [theQuery appendFormat:@"(%@ = SUBSTRING(%@ FROM 1 FOR %ld))", [(MCPAttribute *)[theIdAttr objectAtIndex:i] externalName], [theConnection quoteObject:[self valueForKey:[(MCPAttribute *)[theIdAttr objectAtIndex:i] name]]], [(MCPAttribute *)[theIdAttr objectAtIndex:i] width]];
- }
- else {
- [theQuery appendFormat:@"(%@ = %@)", [(MCPAttribute *)[theIdAttr objectAtIndex:i] externalName], [theConnection quoteObject:[self valueForKey:[(MCPAttribute *)[theIdAttr objectAtIndex:i] name]]]];
- }
- }
- [theQuery appendString:@" ORDER BY "];
- for (i = 0; [theKeyAttr count] != i; ++i) {
- if (i) {
- [theQuery appendString:@", "];
- }
- [theQuery appendString:[(MCPAttribute *)[theKeyAttr objectAtIndex:i] externalName]];
- }
- theResult = [theConnection queryString:theQuery];
- if ([theResult numOfRows]) { // the object was found.
- NSDictionary *theFirstRow = [theResult fetchRowAsDictionary];
- if ([theResult numOfRows] != 1) {
- NSLog(@"in MCPObject -checkDBIdWithConnection: method.... not only one (as expected) but %ld results were found, will take the first one.");
- [theKeys setObject:[NSNumber numberWithInteger:MCPDBReturnMultiple] forKey:@"MCPDBReturnCode"];
- }
- else {
- [theKeys setObject:[NSNumber numberWithInteger:MCPDBReturnOK] forKey:@"MCPDBReturnCode"];
- }
- [theKeys addEntriesFromDictionary:theFirstRow];
-// Setting the value of self for the primary key to the one just found.
- for (i=0; [theKeyAttr count] != i; ++i) {
- MCPAttribute *theAttribute = (MCPAttribute *) [theKeyAttr objectAtIndex:i];
-
- [self setValue:[theFirstRow objectForKey:[theAttribute externalName]] forKey:[theAttribute name]];
- }
- }
- else { // Object not found in the DB.
- for (i = 0; [theKeyAttr count] != i; ++i) {
- MCPAttribute *theAttribute = (MCPAttribute *)[theKeyAttr objectAtIndex:i];
-
- if ([theAttribute autoGenerated]) {
- [self setValue:[self defaultValueForKey:[theAttribute name]] forKey:[theAttribute name]];
- }
- [theKeys setObject:[self valueForKey:[theAttribute name]] forKey:[theAttribute name]];
- }
- [theKeys setObject:[NSNumber numberWithInteger:MCPDBReturnNone] forKey:@"MCPDBReturnCode"];
-// Setting the value of self for the primary key to the default values.
-/*
- for (i=0; [theKeyAttr count] != i; ++i) {
- MCPAttribute *theAttribute = (MCPAttribute *) [theKeyAttr objectAtIndex:i];
-
- [self setValue:[self defaultValueForKey:[theAttribute name]] forKey:[theAttribute name]];
- }
-*/
- }
- return [NSDictionary dictionaryWithDictionary:theKeys];
-}
-
-
-- (NSDictionary *) saveInDB
-/*" First will use the checkDBIdWithConnection method to check if the entry is already in the database. If this is the case,
- it will use the updateInDB... method to update the current DB instance. Otherwise it will make an insert into the database
- to save the entry, than it makes a select to get the value of autogenerated column, and use them (if necessary) to return
- the primary key (as NSDictionary).
-
- As for checkDBId... the returned dictionary also have a MCPDBReturnCode key with a NSNumber as value containing the
- return code of the operation."*/
-{
- MCPConnection *theConnection = [self connection];
- NSDictionary *theCheckReturn = [self checkDBId];
- NSMutableDictionary *theRet;
- NSInteger theCheckCode = [(NSNumber *)[theCheckReturn objectForKey:@"MCPDBReturnCode"] integerValue];
- NSUInteger i;
- NSUInteger j;
- NSMutableString *theQuery = [NSMutableString string];
- NSArray *theAttr = [classDescription attributes];
-
- switch (theCheckCode) {
- case MCPDBReturnNoIdentity : // For this object the identity is not set... so we try to save.
- break;
-
- case MCPDBReturnOK : // Object already in the DB (found using checkDBId... method).
- // NSLog(@"in saveUsingConnection: the entry already existed so will update the one with key : %@", theCheckReturn);
- theCheckCode = [self updateInDB];
- theRet = [NSMutableDictionary dictionaryWithDictionary:[self primaryKey]];
- [theRet setObject:[NSNumber numberWithInteger:theCheckCode] forKey:@"MCPDBReturnCode"];
- return [NSDictionary dictionaryWithDictionary:theRet];
- break;
-
- case MCPDBReturnMultiple : // Multiple were found, the first one will be updated.
- NSLog(@"Multiple entries found with the same identity ... will update the first one.");
- theCheckCode = [self updateInDB];
- theRet = [NSMutableDictionary dictionaryWithDictionary:[self primaryKey]];
- [theRet setObject:[NSNumber numberWithInteger:theCheckCode] forKey:@"MCPDBReturnCode"];
- return [NSDictionary dictionaryWithDictionary:theRet];
- break;
-
- case MCPDBReturnNone : // The entry is not already in the DB, save it...
- break;
-
- case MCPDBReturnNoConnection : // Self does not have a connection.
- NSLog(@"Can not save when the connection is not working...");
- break;
-
- default : // We should not arrive here anyway.
- NSLog(@"For some resons we got a unexpected result from checkDBId : %ld", theCheckCode);
- break;
- }
-
-// Generate the INSERT query:
- [theQuery appendFormat:@"INSERT INTO %@ (", [classDescription externalName]];
- j = 0;
- for (i=0; [theAttr count] != i; ++i) {
- if (! [(MCPAttribute *)[theAttr objectAtIndex:i] autoGenerated]) {
- if (j) {
- [theQuery appendString:@", "];
- }
- [theQuery appendString:[(MCPAttribute *)[theAttr objectAtIndex:i] externalName]];
- ++j;
- }
- }
- [theQuery appendString:@") VALUES ("];
- j = 0;
- for (i=0; [theAttr count] != i; ++i) {
- if (! [(MCPAttribute *)[theAttr objectAtIndex:i] autoGenerated]) {
- if (j) {
- [theQuery appendString:@", "];
- }
- [theQuery appendString:[theConnection quoteObject:[self valueForKey:[(MCPAttribute *)[theAttr objectAtIndex:i] name]]]];
- ++j;
- }
- }
- [theQuery appendString:@")"];
-// Finished preparing the query.
-
-// Now we perform the query...
- [theConnection queryString:theQuery];
- if (1 != (i = [theConnection affectedRows])) { // More than one row affected ... Should NEVER occure.
- NSLog(@"Problem while saving a MCPObject to the database : number of inserted rows is : %ld !!!", i);
- NSLog(@"Maybe there is an error : %@ ", [theConnection getLastErrorMessage]);
- NSLog(@"The class of the object is : %@, and it's description is :\n%@", [self className], [self descriptionWithLocale:nil]);
- theCheckCode = (i == 0) ? MCPDBReturnNone : MCPDBReturnMultiple;
- }
- else {
- theCheckCode = MCPDBReturnOK;
- }
-
-// Finally we get the primary key of the inserted object:
- if ([classDescription singleIntAutoGenKey]) {
- NSString *thePrimKey = [(MCPAttribute *) [[classDescription primaryKeyAttributes] objectAtIndex:0] name];
-
- [self setValue:[NSNumber numberWithLongLong:[theConnection insertId]] forKey:thePrimKey];
- }
- [self getAutoGenerated];
- theRet = [NSMutableDictionary dictionaryWithDictionary:[self primaryKey]];
- [theRet setObject:[NSNumber numberWithInteger:theCheckCode] forKey:@"MCPDBReturnCode"];
-
- return [NSDictionary dictionaryWithDictionary:theRet];
-}
-
-
-
-- (MCPDBReturnCode) getAutoGenerated
-/*" This method will use the Identity attributes of the object to retrieve the autogenerated
-attributes from the database.
-
-If the identity is not defined for this class/entity, then it will try to use the primary key
-to get the auto-generated values.
-
-Obviously this might generate a bug if one of the Identity attributes is autogenerated.
-This will create a trouble if some object does not have an identity defined but still contains
-some auto-generated attributes.
-"*/
-{
- NSMutableArray *theAutoAttr = [NSMutableArray array];
- NSArray *theAttr = [classDescription attributes];
- NSArray *theKeyAttr = [classDescription primaryKeyAttributes];
- NSUInteger i,j;
- NSMutableString *theQuery;
- NSInteger theCheckCode;
- MCPResult *theResult;
- NSDictionary *theRow;
- MCPConnection *theConnection = [self connection];
-
- if (! theConnection) {
- return MCPDBReturnNoConnection;
- }
-
- if (0 != [[classDescription identityAttributes] count]) {
- theCheckCode = [(NSNumber *)[[self checkDBId] objectForKey:@"MCPDBReturnCode"] integerValue];
- if ((MCPDBReturnOK != theCheckCode) && (MCPDBReturnMultiple != theCheckCode)) {
- NSLog(@"Unable to get the primary key for the object, will abort now the fetch of autoGenerated attributes (left unchanged)!");
- return theCheckCode;
- }
- if (MCPDBReturnMultiple == theCheckCode) {
- NSLog(@"Will get the autoGenerated values for the first entry....");
- }
- }
- j = 0;
- for (i=0; [theAttr count] != i; ++i) { // generate the array with autoGenerated attributes.
- if ([(MCPAttribute *)[theAttr objectAtIndex:i] autoGenerated]) {
- [theAutoAttr insertObject:[theAttr objectAtIndex:i] atIndex:j];
- ++j;
- }
- }
- if (0 == [theAutoAttr count]) {
- return MCPDBReturnOK;
- }
-
-// Make the query:
- theQuery = [NSMutableString stringWithString:@"SELECT "];
- for (i=0; [theAutoAttr count] != i; ++i) {
- if (i) {
- [theQuery appendString:@", "];
- }
- [theQuery appendString:[(MCPAttribute *)[theAutoAttr objectAtIndex:i] externalName]];
- }
- [theQuery appendFormat:@" FROM %@ WHERE ", [classDescription externalName]];
-// Preparing the Where Clause:
- for (i=0; [theKeyAttr count] != i; ++i) {
- if (i) {
- [theQuery appendString:@" AND "];
- }
- [theQuery appendFormat:@"( %@ = %@ )", [(MCPAttribute*)[theKeyAttr objectAtIndex:i] externalName], [theConnection quoteObject:[self valueForKey:[(MCPAttribute*)[theKeyAttr objectAtIndex:i] name]]]];
- }
-// Query is ready:
- theResult = [theConnection queryString:theQuery];
- if (! theResult) {
- NSLog(@"While fetching the auto-generated part of the object, got an error -a nil MCPResult-. Will report that as a MCPDBReturnNone.");
- return MCPDBReturnNone;
- }
- if (0 == [theResult numOfRows]) { // The entry was not found in the DB.
- if (0 == [[classDescription identityAttributes] count]) {
- NSLog(@"It seems that the object is not in the DB... but the identity is not defined so there might be a trouble with having the proper ID.");
- }
- return MCPDBReturnNone;
- }
-// Getting the values from the DB select:
- theRow = [theResult fetchRowAsDictionary];
- for (i=0; [theAutoAttr count] != i; ++i) {
- [self setValue:[theRow objectForKey:[(MCPAttribute*)[theAutoAttr objectAtIndex:i] externalName]] forKey:[(MCPAttribute*)[theAutoAttr objectAtIndex:i] name]];
- }
-// Returning the proper value:
- if (1 != [theResult numOfRows]) {
- NSLog(@"Multiple entries (or none : %llu), got the values for the first one...", [theResult numOfRows]);
- return MCPDBReturnMultiple;
- }
- return MCPDBReturnOK;
-}
-
-
-- (MCPDBReturnCode) updateInDB
-/*"This method will use the primary key value held by the object to modify the object that is saved in the DB.
-
- (NO YET IMPLEMENTED) If the primary key is not complete (some of the attributes are to null or 0) and the identityAttributes
- (from class description) is not an empty list then it will perform a checkDBId... to try to retrieve the
- missing part of the primary key.
- "*/
-{
- NSArray *theAttributes = [classDescription attributes];
- NSArray *thePrimKeyAttributes = [classDescription primaryKeyAttributes];
- NSMutableString *theQuery = [NSMutableString string];
- NSInteger theCheckCode;
- NSUInteger i, j;
- MCPConnection *theConnection = [self connection];
-
- if (! theConnection) {
- return MCPDBReturnNoConnection;
- }
-// Generate the query
- [theQuery appendFormat:@"UPDATE %@ SET ", [classDescription externalName]];
- // Prepare the value key pairs:
- j=0;
- for (i=0 ; [theAttributes count] != i; ++i) {
- id theValue = [self valueForKey:[(MCPAttribute *)[theAttributes objectAtIndex:i] name]];
-
- if ((theValue) && (! [(MCPAttribute *)[theAttributes objectAtIndex:i] autoGenerated])) {
- if (j) {
- [theQuery appendString:@", "];
- }
- [theQuery appendFormat:@"%@ = %@ ", [(MCPAttribute *)[theAttributes objectAtIndex:i] externalName], [theConnection quoteObject:theValue]];
- ++j;
- }
- }
- if (0 == j) { // Nothing has to be updated in this entry....
- NSLog(@"Tried to update a row from an object that does NOT contain any information!!");
- return MCPDBReturnNone;
- }
- // Prepare the WHERE clause:
- [theQuery appendFormat:@" WHERE "];
- j = 0;
- for (i=0; [thePrimKeyAttributes count] != i; ++i) {
- id theValue = [self valueForKey:[(MCPAttribute *)[thePrimKeyAttributes objectAtIndex:i] name]];
-
- if (j) {
- [theQuery appendString:@" AND "];
- }
- if (theValue) {
- [theQuery appendFormat:@"%@ = %@", [(MCPAttribute *)[thePrimKeyAttributes objectAtIndex:i] externalName], [theConnection quoteObject:theValue]];
- ++j;
- }
- }
-// Perform the update:
- if (j == [thePrimKeyAttributes count]) {
- [theConnection queryString:theQuery];
- i = [theConnection affectedRows];
- switch (i) {
- case 0 :
- theCheckCode = MCPDBReturnNone;
- break;
- case 1 :
- theCheckCode = MCPDBReturnOK;
- break;
- default :
- theCheckCode = MCPDBReturnMultiple;
- break;
- }
- }
- else {
- NSDictionary *theKeyCheck = [self checkDBId];
- NSInteger theIdCheckCode = [(NSNumber *) [theKeyCheck objectForKey:@"MCPDBReturnCode"] integerValue];
-
- if (MCPDBReturnOK == theIdCheckCode) {
- theCheckCode = [self updateInDB];
- }
- else {
- theCheckCode = MCPDBReturnNoKey;
- }
- }
-// Return proper code:
- return theCheckCode;
-}
-
-
-- (MCPDBReturnCode) deleteInDB
-/*" Uses the connection to delete the object from the DB. In this process the autoGenerated attributes are set to null.
- If the primary key is not completely set, this method calls checkDBId... method to try to complete it
- (if the identityAttributes of the class description is not empty)."*/
-{
- NSArray *theKeyAttributes = [classDescription primaryKeyAttributes];
- NSArray *theAttributes = [classDescription attributes];
- NSUInteger i;
-// NSMutableDictionary *theKeyValue = [NSMutableDictionary dictionary];
- NSInteger theCheckCode = MCPDBReturnOK;
- MCPConnection *theConnection = [self connection];
-
- if (! theConnection) {
- return MCPDBReturnNoConnection;
- }
-// Get the value of the primary key:
- for (i=0; [theKeyAttributes count] != i; ++i) {
- id theValue = [self valueForKey:[(MCPAttribute*) [theKeyAttributes objectAtIndex:i] name]];
- if ((! theValue) || ([theValue isKindOfClass:[NSNumber class]] && (0 == [theValue integerValue]))) {
- theCheckCode = MCPDBReturnIncompleteKey;
- break;
- }
- }
-// If incomplete, try to find the rest, and perform again:
- if (MCPDBReturnIncompleteKey == theCheckCode) {
- if (MCPDBReturnOK == [(NSNumber *)[[self checkDBId] objectForKey:@"MCPDBReturnCode"] integerValue]) {
- return [self deleteInDB];
- }
- else {
- return MCPDBReturnIncompleteKey;
- }
- }
-
-// Perform the deletion from the DB:
- theCheckCode = [[self class] deleteInDBUsingConnection:theConnection withId:self];
-
-// set the auto-generated attributes to proper values:
- for (i=0 ; [theAttributes count] != i; ++i) {
- MCPAttribute *theAttribute = (MCPAttribute *) [theAttributes objectAtIndex:i];
- if ([theAttribute autoGenerated]) {
-// [self setValue:NULL forKey:[theAttribute name]];
- [self setValue:[self defaultValueForKey:[theAttribute name]] forKey:[theAttribute name]];
- }
- }
-
-// Finished... just have to return the proper value:
- return theCheckCode;
-}
-
-
-+ (MCPDBReturnCode) deleteInDBUsingConnection:(MCPConnection *) iConnection withId:(id) iId
-/*" Uses the connection to remove from the DB the entry corresponding to the primary key id given by iId.
- If any part of the primary key is missing, nothing is done."*/
-{
- NSMutableString *theQuery = [NSMutableString string];
- MCPClassDescription *theClassDescription = (MCPClassDescription *) [NSClassDescription classDescriptionForClass:[self class]];
- NSArray *theKeyAttributes = [theClassDescription primaryKeyAttributes];
- NSUInteger i;
-
- if (! [iConnection checkConnection]) {
- return MCPDBReturnNoConnection;
- }
-// Generate the query:
- [theQuery appendFormat:@"DELETE FROM %@ WHERE ", [theClassDescription externalName]];
-// Prepare the WHERE STATEMENT:
- for (i=0; [theKeyAttributes count] != i; ++i) {
- if (i) {
- [theQuery appendString:@" AND "];
- }
-// [theQuery appendFormat:@"( %@ = %@ )", [(MCPAttribute*)[theKeyAttributes objectAtIndex:i] externalName], [iConnection quoteObject:[iId objectForKey:[(MCPAttribute*)[theKeyAttributes objectAtIndex:i] name]]]];
- [theQuery appendFormat:@"( %@ = %@ )", [(MCPAttribute*)[theKeyAttributes objectAtIndex:i] externalName], [iConnection quoteObject:[iId valueForKey:[(MCPAttribute*)[theKeyAttributes objectAtIndex:i] name]]]];
- }
-// Perform the query:
- [iConnection queryString:theQuery];
-// Return the proper code:
- i = [iConnection affectedRows];
-
- if (1 < i) {
- return MCPDBReturnMultiple;
- }
- if (0 == i) {
- return MCPDBReturnNone;
- }
- return MCPDBReturnOK;
-}
-
-
-#pragma mark Handling realtions
-- (id) getTargetOfRelation:(MCPRelation *) iRelation
-/*" This method is using the information from iRelation to fetch the targe of the relation in the DB.
-
-If iRelation is flagged as a to-one, then the return type is the type of the target object (value might be nil, if the target was not found).
-If iRelation is flagged as a to-many, then the return type is NSArray (and might be empty if no target were found).
-
-In any case this method is first checking that iRelation is starting from the class of self, and that self is connected to the DB.
-Also the returned object is ALWAYS autoreleased before being returned.
-"*/
-{
- NSMutableString *query;
- MCPClassDescription *destinationDesc;
- NSArray *joins;
- NSArray *keys;
- NSArray *ids;
- MCPResult *result;
- NSUInteger i;
- NSDictionary *theRow;
- id theRet;
-
- if (! iRelation) {
- NSLog(@"Tried to get the target of a relation... but the relation object is nil");
- }
- else {
-// NSLog(@"Trying to get the target of the realtion : %@", [iRelation descriptionWithLocale:nil]);
- }
- if ((! [connection isConnected]) || (! [classDescription isEqual:[iRelation origin]])) { // Error condition.
- return nil;
- }
-// Generating the query:
- destinationDesc = [iRelation destination];
- keys = [destinationDesc primaryKeyAttributes];
- joins = [iRelation joins];
- ids = [destinationDesc identityAttributes];
- query = [[NSMutableString alloc] initWithString:@"SELECT "];
- for (i=0; [keys count] != i; ++i) {
- if (i) {
- [query appendString:@", "];
- }
- [query appendString:[(MCPAttribute *)[keys objectAtIndex:i] externalName]];
- }
- [query appendFormat:@" FROM %@ WHERE ", [destinationDesc externalName]];
- for (i=0; [joins count] != i; ++i) {
- MCPJoin *theJoin = (MCPJoin *)[joins objectAtIndex:i];
-
- if (i) {
- [query appendString:@" and "];
- }
- [query appendFormat:@"(%@ = %@)", [[theJoin destination] externalName], [connection quoteObject:[self valueForKey:[[theJoin origin] name]]]];
- }
-// NSLog(@"in -[MCPObject getTargetOfRelation:%@]; query is %@...", [iRelation descriptionWithLocale:nil], query);
- [query appendString:[self orderSQLForClassDescription:destinationDesc]];
-// NSLog(@"in -[MCPObject getTargetOfRelation:%@]; query is %@...", [iRelation descriptionWithLocale:nil], query);
-/*
- [query appendString:@" ORDER BY "];
- for (i=0; [ids count] != i; ++i) { // Generating the order :
- if (i) {
- [query appendString:@", "];
- }
- [query appendString:[(MCPAttribute *)[ids objectAtIndex:i] externalName]];
- }
-*/
- result = [connection queryString:query];
- [query release];
-
-// Getting the results in proper objects:
- if ([iRelation isToMany]) { // To-Many relation
- NSMutableArray *theArrayRet = [[NSMutableArray alloc] init];
-
- theRet = theArrayRet;
- while (theRow = [result fetchRowAsDictionary]) {
- MCPObject *theTarget = [[[destinationDesc representedClass] alloc] init];
-
- [theTarget setPrimaryKey:theRow andFetchFromDB:connection];
- [theArrayRet insertObject:theTarget atIndex:[theArrayRet count]];
- [theTarget release];
- }
- }
- else { // To-One relation
- theRow = [result fetchRowAsDictionary];
- if (theRow) {
- theRet = [[[destinationDesc representedClass] alloc] init];
- [theRet setPrimaryKey:theRow andFetchFromDB:connection];
- }
- else {
- theRet = nil;
- }
- }
- [theRet autorelease];
- return theRet;
-}
-
-- (id) getTargetOfRelationNamed:(NSString *) iRelationName
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self getTargetOfRelation:theRelation] : nil;
-}
-
-- (MCPDBReturnCode) setTarget:(id) iTarget forRelation:(MCPRelation *) iRelation
-/*" This method will modify the DB content so that the corresponding relation is deleted.
- If any value corresping to an attribute of self is modified in the DB, then it will update all attributes of self to reflect DB status.
-
-Obviuosly this method is taking care of only to-one relation. It will hence check that iRelation is a to-one relation starting from self.
-Finally, you can use setTarget:nil forRelation:... to 'delete' a previously establlished relation (if the model and DB permit it)."*/
-{
- NSUInteger i;
- MCPObject *oldTarget;
-
- if (! [connection isConnected]) {
- return MCPDBReturnNoConnection;
- }
- if (! [classDescription isEqual:[iRelation origin]]) {
- return MCPDBReturnWrongRelationOrigin;
- }
- if ([iRelation isToMany]) {
- return MCPDBReturnWrongRelationCardinality;
- }
-
- oldTarget = [self getTargetOfRelation:iRelation];
- if ((oldTarget) && ([iTarget isEqual:oldTarget])) { // No need to change the relation's target.
- return MCPDBReturnOK;
- }
- for (i=0; [iRelation countOfJoins] != i; ++i) {
- MCPJoin *theJoin = [iRelation objectInJoinsAtIndex:i];
-
- if (([[theJoin origin] isPartOfKey]) && (![[theJoin destination] isPartOfKey])) { // Will change the destination...
- [iTarget setValue:[self valueForKey:[[theJoin origin] name]] forKey:[[theJoin destination] name]];
- [oldTarget setValue:[oldTarget defaultValueForKey:[[theJoin destination] name]] forKey:[[theJoin destination] name]];
- }
- else { // Will change the origin
- [self setValue:[iTarget valueForKey:[[theJoin destination] name]] forKey:[[theJoin origin] name]];
- }
- }
- if ([iRelation ownsDestination]) {
- [oldTarget deleteInDB];
- }
- return MCPDBReturnOK;
-}
-
-- (MCPDBReturnCode) setTarget:(id) iTarget forRelationNamed:(NSString *) iRelationName
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self setTarget:iTarget forRelation:theRelation] : MCPDBReturnNoSuchRelation;
-}
-
-- (NSUInteger) countTargetForRelation:(MCPRelation *) iRelation
-{
- NSMutableString *theQuery;
- NSUInteger i;
- NSArray *theJoinArray;
- MCPResult *theResult;
- NSDictionary *theRow;
-
- if ((! [connection isConnected]) || (! [classDescription isEqual:[iRelation origin]])){
- return 0;
- }
- theJoinArray = [iRelation joins];
- theQuery = [[NSMutableString alloc] initWithFormat:@"SELECT COUNT(1) FROM %@ WHERE ", [[iRelation destination] externalName]];
- for (i=0; [theJoinArray count] != i; ++i) {
- MCPJoin *theJoin = (MCPJoin *)[theJoinArray objectAtIndex:i];
- if (i) {
- [theQuery appendString:@" AND "];
- }
- [theQuery appendFormat:@"( %@ = %@ )", [[theJoin destination] externalName], [connection quoteObject:[self valueForKey:[[theJoin origin] name]]]];
- }
- theResult = [connection queryString:theQuery];
- [theQuery release];
- theRow = [theResult fetchRowAsDictionary];
- return [(NSNumber *)[theRow objectForKey:@"COUNT(1)"] unsignedIntegerValue];
-}
-
-- (NSUInteger) countTargetForRelationNamed:(NSString *) iRelationName
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self countTargetForRelation:theRelation] : 0;
-}
-
-
-- (MCPObject *) getTargetOfRelation:(MCPRelation *) iRelation atIndex:(NSUInteger) iIndex
-/*" This method will return the specific object which is the iIndex'th object of th relation (after ordering the object using the destination identity).
-
-This method (like other assuming order in the relation targets) will be doubtfull if the class does NOT have a single identity attribute."*/
-{
- NSMutableString *query;
- MCPClassDescription *destinationDesc;
- NSArray *joins;
- NSArray *keys;
- NSArray *ids;
- MCPResult *result;
- NSUInteger i;
- NSDictionary *theRow;
- MCPObject *theRet;
-
- if (! iRelation) {
- NSLog(@"Tried to get the target of a relation... but the relation object is nil");
- }
- else {
-// NSLog(@"Trying to get the target of the realtion : %@", [iRelation descriptionWithLocale:nil]);
- }
- if ((! [connection isConnected]) || (! [classDescription isEqual:[iRelation origin]])) { // Error condition.
- return nil;
- }
- if (! [iRelation isToMany]) {
- NSLog(@"Tried to use the -[MCPObject getTargetOfRelation:atIndex:] on a to-one relation... this does NOT works!!! You should use -[MCPObject getTargetOfRelation:] instead!!!");
- return [self getTargetOfRelation:iRelation];
- }
-// Generating the query:
- destinationDesc = [iRelation destination];
- keys = [destinationDesc primaryKeyAttributes];
- joins = [iRelation joins];
- ids = [destinationDesc identityAttributes];
- query = [[NSMutableString alloc] initWithString:@"SELECT "];
- for (i=0; [keys count] != i; ++i) {
- if (i) {
- [query appendString:@", "];
- }
- [query appendString:[(MCPAttribute *)[keys objectAtIndex:i] externalName]];
- }
- [query appendFormat:@" FROM %@ WHERE ", [destinationDesc externalName]];
- for (i=0; [joins count] != i; ++i) {
- MCPJoin *theJoin = (MCPJoin *)[joins objectAtIndex:i];
-
- if (i) {
- [query appendString:@" and "];
- }
- [query appendFormat:@"(%@ = %@)", [[theJoin destination] externalName], [connection quoteObject:[self valueForKey:[[theJoin origin] name]]]];
- }
- [query appendString:[self orderSQLForClassDescription:destinationDesc]];
-/*
- [query appendString:@" ORDER BY "];
- for (i=0; [ids count] != i; ++i) { // Generating the order :
- if (i) {
- [query appendString:@", "];
- }
- [query appendString:[(MCPAttribute *)[ids objectAtIndex:i] externalName]];
- }
-*/
- [query appendFormat:@" LIMIT 1 OFFSET %ld", iIndex];
- result = [connection queryString:query];
- [query release];
-
-// Getting the results in proper objects:
- theRow = [result fetchRowAsDictionary];
- if (theRow) {
- theRet = (MCPObject *)[[[destinationDesc representedClass] alloc] init];
- [theRet setPrimaryKey:theRow andFetchFromDB:connection];
- [theRet autorelease];
- }
- else {
- theRet = nil;
- }
- return theRet;
-}
-
-- (MCPObject *) getTargetOfRelationNamed:(NSString *) iRelationName atIndex:(NSUInteger) iIndex
-/*"This is the equivalent of the getTargetOfRelation:atIndex:, but giving a relation name instead of the MCPRelation object itself."*/
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self getTargetOfRelation:theRelation atIndex:iIndex]: nil;
-}
-
-- (MCPDBReturnCode) addTarget:(MCPObject *) iTarget toRelation:(MCPRelation *) iRelation
-/*" This method will modify the DB content so that the corresponding relation is added.
-If any value corresping to an attribute of self i modified in the DB, then it will update all attributes of self to reflect DB status.
-
-Obviuosly this method is taking care of only to-many relation. It will hence check that iRelation is a to-many relation starting from self."*/
-{
- NSArray *joins;
- NSUInteger i;
- NSDictionary *saveReturn;
-
- if (! [connection isConnected]) {
- return MCPDBReturnNoConnection;
- }
- if (! [classDescription isEqual:[iRelation origin]]) {
- return MCPDBReturnWrongRelationOrigin;
- }
- if (! [iRelation isToMany]) {
- return MCPDBReturnWrongRelationCardinality;
- }
- joins = [iRelation joins];
- for (i=0; [joins count] != i; ++i) { // Will change only values of iTarget, because it is a to-many relation.
- MCPJoin *join = (MCPJoin *)[joins objectAtIndex:i];
-
- [iTarget setValue:[self valueForKey:[[join origin] name]] forKey:[[join destination] name]];
- }
- if (! [[iTarget connection] isConnected]) {
- [iTarget setConnection:connection];
- }
- saveReturn = [iTarget saveInDB];
- return (MCPDBReturnCode)[(NSNumber *)[saveReturn objectForKey:@"MCPDBReturnCode"] unsignedIntegerValue];
-}
-
-- (MCPDBReturnCode) addTarget:(MCPObject *) iTarget toRelationNamed:(NSString *) iRelationName
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self addTarget:iTarget toRelation:theRelation] : MCPDBReturnNoSuchRelation;
-}
-
-- (MCPDBReturnCode) removeTarget:(MCPObject *) iTarget toRelation:(MCPRelation *) iRelation
-/*" This method will modify the DB content so that the corresponding relation is removed.
-If any value corresping to an attribute of self i modified in the DB, then it will update all attributes of self to reflect DB status.
-
-Obviuosly this method is taking care of only to-many relation. It will hence check that iRelation is a to-many relation starting from self."*/
-{
- NSArray *joins;
- NSUInteger i;
-// NSDictionary *saveReturn;
- BOOL targetIsTarget = YES;
- MCPDBReturnCode returnCode;
-
- if (! [connection isConnected]) {
- return MCPDBReturnNoConnection;
- }
- if (! [classDescription isEqual:[iRelation origin]]) {
- return MCPDBReturnWrongRelationOrigin;
- }
- if (! [iRelation isToMany]) {
- return MCPDBReturnWrongRelationCardinality;
- }
- joins = [iRelation joins];
- for (i=0; [joins count] != i; ++i) {
- MCPJoin *join = (MCPJoin *)[joins objectAtIndex:i];
- targetIsTarget = targetIsTarget && [[iTarget valueForKey:[[join destination] name]] isEqual:[self valueForKey:[[join origin] name]]];
- }
- if (! targetIsTarget) {
- return MCPDBReturnNotTarget;
- }
- if ([iRelation ownsDestination]) { // just delete the target from the DB.
- returnCode = [iTarget deleteInDB];
- }
- for (i=0; [joins count] != i; ++i) { // Put all the destination to default...
- MCPJoin *join = (MCPJoin *)[joins objectAtIndex:i];
-
- [iTarget setValue:[[join destination] defaultValue] forKey:[[join destination] name]];
- }
- if (! [iRelation ownsDestination]) {
- returnCode = [(NSNumber *)[[iTarget saveInDB] objectForKey:@"MCPDBReturnCode"] unsignedIntegerValue];
- }
- return returnCode;
-}
-
-- (MCPDBReturnCode) removeTarget:(MCPObject *) iTarget toRelationNamed:(NSString *) iRelationName
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self removeTarget:iTarget toRelation:theRelation] : MCPDBReturnNoSuchRelation;
-}
-
-- (MCPDBReturnCode) removeTargetToRelation:(MCPRelation *) iRelation atIndex:(NSUInteger) iIndex
-/*" This method will use an index t first query the object that it should remove from the relation, then uses the -[MCPObject removeTarget:toRelation:]
- method to remove the object from the relation. If the index is out of bound (the returned object is nil), it will return MCPDBReturnNone, to signal
- there was no object with this index in the relation."*/
-{
- MCPObject *target;
-
- if (! [connection isConnected]) {
- return MCPDBReturnNoConnection;
- }
- if (! [classDescription isEqual:[iRelation origin]]) {
- return MCPDBReturnWrongRelationOrigin;
- }
- if (! [iRelation isToMany]) {
- return MCPDBReturnWrongRelationCardinality;
- }
- target = [self getTargetOfRelation:iRelation atIndex:iIndex];
- if (target) {
- return [self removeTarget:target toRelation:iRelation];
- }
- else {
- return MCPDBReturnNone;
- }
-}
-
-- (MCPDBReturnCode) removeTargetToRelationNamed:(NSString *) iRelationName atIndex:(NSUInteger) iIndex
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self removeTargetToRelation:theRelation atIndex:iIndex] : MCPDBReturnNoSuchRelation;
-}
-
-- (NSUInteger) indexOfTarget:(MCPObject *) iTarget inRelation:(MCPRelation *) iRelation
-/*" Returns the index of the target object within the relation. Return NSNotFound if the objkect is NOT in the relation!!"*/
-{
- NSMutableString *query;
- NSArray *joins;
- NSArray *keys;
- NSArray *ids;
- NSUInteger i;
- MCPResult *result;
- NSDictionary *row;
- NSMutableDictionary *targetKey;
- BOOL targetIsTarget = YES;
-
- if ((! [connection isConnected]) || (! [classDescription isEqual:[iRelation origin]]) || (! [iRelation isToMany])) { // Checking the realtion object.
- return NSNotFound;
- }
- query = [[NSMutableString alloc] initWithString:@"SELECT "];
- joins = [iRelation joins];
-// keys = [[iRelation destination] attributeKeys];
- keys = [[iRelation destination] primaryKeyAttributes];
- ids = [[iRelation destination] identityAttributes];
- for (i=0; [keys count] != i; ++i) {
- if (i) {
- [query appendString:@", "];
- }
- [query appendString:[(MCPAttribute *)[keys objectAtIndex:i] externalName]];
- }
- [query appendFormat:@"FROM %@ WHERE ", [[iRelation destination] externalName]];
- for (i=0; [joins count] != i; ++i) {
- MCPJoin *join = (MCPJoin *)[joins objectAtIndex:i];
-
- targetIsTarget = targetIsTarget && [[iTarget valueForKey:[[join destination] name]] isEqual:[self valueForKey:[[join origin] name]]];
- if (i) {
- [query appendString:@" AND "];
- }
- [query appendFormat:@"( %@ = %@ )", [[join destination] externalName], [connection quoteObject:[self valueForKey:[[join origin] name]]]];
- }
- if (! targetIsTarget) { // Checking that iTarget belongs to the relation.
- [query release];
- return NSNotFound;
- }
- [query appendString:[self orderSQLForClassDescription:[iRelation destination]]];
-/*
- [query appendString:@" ORDER BY "];
- for (i=0; [ids count] != i; ++i) {
- if (i) {
- [query appendString:@", "];
- }
- [query appendString:[(MCPAttribute *)[ids objectAtIndex:i] externalName]];
- }
-*/
- targetKey = [[NSMutableDictionary alloc] init];
- for (i=0; [keys count] != i; ++i) { // Setting the targetKey to the row that should gives the target.
- MCPAttribute *attribute = (MCPAttribute *)[keys objectAtIndex:i];
-
- [targetKey setObject:[iTarget valueForKey:[attribute name]] forKey:[attribute externalName]];
- }
- result = [connection queryString:query];
- [query release];
- i = 0;
- while (row = [result fetchRowAsDictionary]) {
- if ([targetKey isEqualToDictionary:row]) { // We have found the proper object return i (after cleaning up);
- [targetKey release];
- return i;
- }
- ++i;
- }
- return NSNotFound;
-}
-
-- (NSUInteger) indexOfTarget:(MCPObject *) iTarget inRelationNamed:(NSString *) iRelationName
-/*" The equivalent of -[MCPObject indexOfTarget:inRelation:] but using relation name instead of a MCPRelation
-object. Indeed after getting the MCPRelation object corresponding to the name, this method will only return
-the result of the corresponding call to -[MCPObject indexOfTarget:inRelation:]."*/
-{
- MCPRelation *theRelation = [classDescription relationWithName:iRelationName];
- return (theRelation) ? [self indexOfTarget:iTarget inRelation:theRelation] : NSNotFound;
-}
-
-#pragma mark Utility methods
-- (id) defaultValueForKey:(NSString *) iKey
-/*" This method will return the default value (object) for the given key."*/
-{
- MCPAttribute *theAttribute = [classDescription attributeWithName:iKey];
-
- if ([theAttribute allowsNull]) {
-// return [NSNull null];
- return nil;
- }
- else {
- Class theAttrClass = [theAttribute valueClass];
- id theRet;
-
- if ([theAttrClass isSubclassOfClass:[NSNumber class]]) {
- return [NSNumber numberWithInteger:0];
- }
- theRet = [[[theAttrClass alloc] init] autorelease];
- if (nil == theRet) {
- NSLog(@"in MCPObject defaultValueForKey:%@ , for object of class %@, (attribute of class %@) the return value will be nil!!!", iKey, [self className], theAttrClass);
- }
- return theRet;
- }
-}
-
-
-- (NSDictionary *) primaryKey
-/*" Returns a dictionary with the values of the primary key. "*/
-{
- NSMutableDictionary *theRet = [NSMutableDictionary dictionary];
- NSArray *theIdAttr = [classDescription primaryKeyAttributes];
- NSUInteger i;
-
- for (i=0; [theIdAttr count] != i; ++i) {
- NSString *theKey = [(MCPAttribute *)[theIdAttr objectAtIndex:i] name];
-
- if ([self valueForKey:theKey]) {
- [theRet setObject:[self valueForKey:theKey] forKey:theKey];
- }
- else {
- [theRet setObject:[NSNull null] forKey:theKey];
- }
- }
- return [NSDictionary dictionaryWithDictionary:theRet];
-}
-
-#pragma mark Testing equality (VERY important for relation management)
-- (BOOL) isEqual:(id) iObject
-{
- NSArray *theIdAttr;
- NSUInteger i;
- BOOL theRet;
-
- if (self == iObject) {
- return YES;
- }
- if ([self class] != [iObject class]) {
- return NO;
- }
- theIdAttr = [classDescription identityAttributes];
- for (i = 0; [theIdAttr count] != i; ++i) {
- MCPAttribute *theAttr = [theIdAttr objectAtIndex:i];
-
- theRet = theRet && [[self valueForKey:[theAttr name]] isEqual:[iObject valueForKey:[theAttr name]]];
- }
- return theRet;
-}
-
-
-#pragma mark Output
-- (NSString *) description
-{
- return [self descriptionWithLocale:nil];
-}
-
-- (NSString *) descriptionWithLocale:(NSDictionary *) locale
-{
- NSMutableString *theOutput = [NSMutableString string];
- NSUInteger i;
- NSArray *theAttributes = [classDescription attributes];
- BOOL trunc = [MCPConnection truncateLongField];
-
- [theOutput appendFormat:@"MCPObject subclass : %@\n", [self className]];
-
- for (i = 0; [theAttributes count] != i; ++i)
- {
- MCPAttribute *theAttribute = (MCPAttribute *) [theAttributes objectAtIndex:i];
- id theValue = [self valueForKey:[theAttribute name]];
-
- if (trunc) {
- if (([theValue isKindOfClass:[NSString class]]) && (kLengthOfTruncationForLog < [(NSString *)theValue length])) {
- theValue = [theValue substringToIndex:kLengthOfTruncationForLog];
- }
- else if (([theValue isKindOfClass:[NSData class]]) && (kLengthOfTruncationForLog < [(NSData *)theValue length])) {
- theValue = [NSData dataWithBytes:[theValue bytes] length:kLengthOfTruncationForLog];
- }
- }
-
- [theOutput appendFormat:@"\tAttribute %ld : name = %@, value = %@\n", i, [theAttribute name], theValue];
- }
-
- [theOutput appendString:@"\n"];
-
- return theOutput;
-}
-
-#pragma mark Ordering the array for relations
-- (NSString *) orderSQLForClassDescription:(MCPClassDescription *) iClassDescription
-{
- NSMutableArray *theAttributes = [[NSMutableArray alloc] initWithArray:[iClassDescription identityAttributes]];
- NSMutableString *theReturn = [NSMutableString string];
- NSUInteger i;
-
- for (i = 0; [[iClassDescription primaryKeyAttributes] count] != i; ++i) {
- [theAttributes insertObject:[[iClassDescription primaryKeyAttributes] objectAtIndex:i] atIndex:[theAttributes count]];
- }
- for (i = 0; [theAttributes count] != i; ++i) {
- if (i) {
- [theReturn appendString:@", "];
- }
- else {
- [theReturn appendString:@" ORDER BY "];
- }
- [theReturn appendString:[(MCPAttribute *)[theAttributes objectAtIndex:i] externalName]];
- }
- return theReturn;
-}
-
-#pragma mark Anti-crash method...
-- (void) setNilValueForKey:(NSString *) iKey
-{
- NSLog(@"Try to set %@ to nil .... not possible, will set it to zero instead...", iKey);
- [self setValue:[NSNumber numberWithInteger:0] forKey:iKey];
-}
-
-@end