@@ -489,15 +489,28 @@ - (id)newValueForRelationship:(NSRelationshipDescription *)relationship
489
489
sqlite3_bind_int64 (statement, 1 , key);
490
490
491
491
} else if ([relationship isToMany ] && [inverseRelationship isToMany ]) {
492
- // many-to-many relationship, foreign key exists in relation table
492
+ // many-to-many relationship, foreign key exists in relation table, join to get the type
493
493
494
- NSString *relationTable = [self tableNameForRelationship: relationship];
494
+ NSString *sourceEntityName = [[self rootForEntity: sourceEntity] name ];
495
+ NSString *destinationEntityName = [[self rootForEntity: destinationEntity] name ];
495
496
496
- NSString *rootObjectColumn = [[self rootForEntity: relationship.entity] name ];
497
- NSString *rootInverseObjectColumn = [[self rootForEntity: destinationEntity] name ];
498
- NSString *rootInverseObjectTypeColumn = shouldFetchDestinationEntityType ? [NSString stringWithFormat: @" , %@ __entityType" , rootInverseObjectColumn] : @" " ;
497
+ NSString *relationTable = [self tableNameForRelationship: relationship];
498
+ NSString *sourceIDColumn = [NSString stringWithFormat: @" %@ __objectid" , sourceEntityName];
499
+ NSString *destinationIDColumn = [NSString stringWithFormat: @" %@ __objectid" , destinationEntityName];
500
+
501
+ NSString *join = @" " ;
502
+ NSString *destinationTypeColumn = @" " ;
503
+ if (shouldFetchDestinationEntityType) {
504
+ NSString *destinationTable = [self tableNameForEntity: destinationEntity];
505
+ destinationTypeColumn = [NSString stringWithFormat: @" , %@ .__entityType" , destinationTable];
506
+ join = [NSString stringWithFormat: @" INNER JOIN %@ ON %@ .__objectid=%@ .%@ " , destinationTable, destinationTable, relationTable, destinationIDColumn];
507
+
508
+ // Add tables so we don't get ambigious column errors
509
+ sourceIDColumn = [relationTable stringByAppendingFormat: @" .%@ " , sourceIDColumn];
510
+ destinationIDColumn = [relationTable stringByAppendingFormat: @" .%@ " , destinationIDColumn];
511
+ }
499
512
500
- NSString *string = [NSString stringWithFormat: @" SELECT %@ __objectid %@ FROM %@ WHERE %@ __objectid =?" , rootInverseObjectColumn, rootInverseObjectTypeColumn , relationTable, rootObjectColumn ];
513
+ NSString *string = [NSString stringWithFormat: @" SELECT %@%@ FROM %@%@ WHERE %@ =?" , destinationIDColumn, destinationTypeColumn , relationTable, join, sourceIDColumn ];
501
514
statement = [self preparedStatementForQuery: string];
502
515
sqlite3_bind_int64 (statement, 1 , key);
503
516
@@ -1158,13 +1171,16 @@ - (BOOL)alterTableForSourceEntity:(NSEntityDescription *)sourceEntity
1158
1171
return YES ;
1159
1172
}
1160
1173
1161
- - (BOOL )createTableForRelationship : (NSRelationshipDescription *)relationship error : (NSError **)error {
1174
+ - (BOOL )createTableForRelationship : (NSRelationshipDescription *)relationship error : (NSError **)error
1175
+ {
1176
+ NSString *firstIDColumn;
1177
+ NSString *secondIDColumn;
1178
+ [self relationships: relationship firstIDColumn: &firstIDColumn secondIDColumn: &secondIDColumn];
1162
1179
// create table
1163
- NSArray *columns = [self columnNamesForRelationship: relationship withQuotes: YES forCreation: YES ];
1164
1180
NSString *string = [NSString stringWithFormat:
1165
- @" CREATE TABLE %@ (%@ );" ,
1181
+ @" CREATE TABLE %@ (' %@ ' INTEGER NOT NULL, ' %@ ' INTEGER NOT NULL, PRIMARY KEY(' %@ ', ' %@ ') );" ,
1166
1182
[self tableNameForRelationship: relationship],
1167
- [columns componentsJoinedByString: @" , " ] ];
1183
+ firstIDColumn, secondIDColumn, firstIDColumn, secondIDColumn ];
1168
1184
sqlite3_stmt *statement = [self preparedStatementForQuery: string];
1169
1185
sqlite3_step (statement);
1170
1186
@@ -1196,25 +1212,11 @@ -(NSString *)tableNameForRelationship:(NSRelationshipDescription *)relationship
1196
1212
return [NSString stringWithFormat: @" ecd_%@ " ,[names componentsJoinedByString: @" _" ]];
1197
1213
}
1198
1214
1199
- // / Create columns for both object IDs and add any type columns if needed
1200
- -(NSArray *) columnNamesForRelationship : (NSRelationshipDescription *)relationship withQuotes : ( BOOL ) withQuotes forCreation : ( BOOL ) creation
1215
+ // / Create columns for both object IDs. @returns YES if the relationship.entity was first
1216
+ -(BOOL ) relationships : (NSRelationshipDescription *)relationship firstIDColumn : ( NSString *__autoreleasing*) firstIDColumn secondIDColumn : ( NSString *__autoreleasing*) secondIDColumn
1201
1217
{
1202
- NSString *format;
1203
- NSString *typeFormat;
1204
- if (withQuotes) {
1205
- static NSString *formatWithQuotes = @" '%@ __objectid'" ;
1206
- static NSString *typeFormatWithQuotes = @" '%@ __entityType'" ;
1207
- format = formatWithQuotes;
1208
- typeFormat = typeFormatWithQuotes;
1209
- } else {
1210
- static NSString *formatNoQuotes = @" %@ __objectid" ;
1211
- static NSString *typeFormatNoQuotes = @" %@ __entityType" ;
1212
- format = formatNoQuotes;
1213
- typeFormat = typeFormatNoQuotes;
1214
- }
1215
- if (creation) {
1216
- typeFormat = [typeFormat stringByAppendingString: @" INTEGER" ];
1217
- }
1218
+ NSParameterAssert (firstIDColumn);
1219
+ NSParameterAssert (secondIDColumn);
1218
1220
1219
1221
NSEntityDescription *rootSourceEntity = [self rootForEntity: relationship.entity];
1220
1222
NSEntityDescription *rootDestinationEntity = [self rootForEntity: relationship.destinationEntity];
@@ -1224,38 +1226,16 @@ -(NSArray *)columnNamesForRelationship:(NSRelationshipDescription *)relationship
1224
1226
NSEntityDescription *firstEntity = [orderedEntities firstObject ];
1225
1227
NSEntityDescription *secondEntity = [orderedEntities lastObject ];
1226
1228
1227
- // No creation: Max columns ObjectID, Type, Inverse ObjectID, Inverse Type
1228
- // Creation: No creation columns, PK
1229
- NSMutableArray *columns = [NSMutableArray arrayWithCapacity: creation ? 5 : 4 ];
1229
+ static NSString *format = @" %@ __objectid" ;
1230
1230
1231
1231
// 1st
1232
- NSString *firstIDColumn = [NSString stringWithFormat: format, firstEntity.name];
1233
- if (creation) {
1234
- [columns addObject: [NSString stringWithFormat: @" %@ INTEGER NOT NULL" , firstIDColumn]];
1235
- } else {
1236
- [columns addObject: firstIDColumn];
1237
- }
1238
- if ((firstEntity == rootSourceEntity && rootSourceEntity != relationship.entity ) || (firstEntity == rootDestinationEntity && rootDestinationEntity != relationship.destinationEntity )) {
1239
- [columns addObject: [NSString stringWithFormat: typeFormat, firstEntity.name]];
1240
- }
1232
+ *firstIDColumn = [NSString stringWithFormat: format, firstEntity.name];
1241
1233
1242
1234
// 2nd
1243
- NSString *secondIDColumn = [NSString stringWithFormat: format, secondEntity.name];
1244
- if (creation) {
1245
- [columns addObject: [NSString stringWithFormat: @" %@ INTEGER NOT NULL" , secondIDColumn]];
1246
- } else {
1247
- [columns addObject: secondIDColumn];
1248
- }
1249
- if ((secondEntity == rootSourceEntity && rootSourceEntity != relationship.entity ) || (secondEntity == rootDestinationEntity && rootDestinationEntity != relationship.destinationEntity )) {
1250
- [columns addObject: [NSString stringWithFormat: typeFormat, secondEntity.name]];
1251
- }
1252
-
1253
- if (creation) {
1254
- // PK
1255
- [columns addObject: [NSString stringWithFormat: @" PRIMARY KEY(%@ , %@ )" , firstIDColumn, secondIDColumn]];
1256
- }
1235
+ *secondIDColumn = [NSString stringWithFormat: format, secondEntity.name];
1257
1236
1258
- return columns;
1237
+ // Return if the relationship.entity was first
1238
+ return orderedEntities[0 ] == rootSourceEntity;
1259
1239
}
1260
1240
1261
1241
#pragma mark - save changes to the database
@@ -1368,16 +1348,16 @@ - (BOOL)handleInsertedRelationInSaveRequest:(NSRelationshipDescription *)relatio
1368
1348
1369
1349
NSString *tableName = [self tableNameForRelationship: relationship];
1370
1350
1371
- // Object
1372
- NSNumber *objectID = [ self referenceObjectForObjectID: [object objectID ]] ;
1373
- NSNumber *objectType = [self entityNeedsEntityTypeColumn : relationship.entity] ? @([object.entity.name hash ]) : nil ;
1351
+ NSString *firstIDColumn;
1352
+ NSString *secondIDColumn ;
1353
+ BOOL firstColumnIsSource = [self relationships : relationship firstIDColumn: &firstIDColumn secondIDColumn: &secondIDColumn] ;
1374
1354
1375
- // Inverse
1376
- BOOL needsInverseType = [self entityNeedsEntityTypeColumn: relationship.destinationEntity];
1377
-
1378
- id objectValues = objectType ? [NSString stringWithFormat: @" %@ , %@ " , objectID, objectType] : objectID;
1355
+ // Object
1356
+ unsigned long long objectID = [[self referenceObjectForObjectID: [object objectID ]] unsignedLongLongValue ];
1379
1357
1380
- NSString *string = [NSString stringWithFormat: @" INSERT INTO %@ VALUES (%@ , ?%@ );" , tableName, objectValues, needsInverseType ? @" , ?" : @" " ];
1358
+ // TODO: make sure of order
1359
+ NSString *values = [NSString stringWithFormat: (firstColumnIsSource ? @" %llu , ?" : @" ?, %llu " ), objectID];
1360
+ NSString *string = [NSString stringWithFormat: @" INSERT INTO %@ (%@ , %@ ) VALUES (%@ );" , tableName, firstIDColumn, secondIDColumn, values];
1381
1361
1382
1362
__block BOOL success = YES ;
1383
1363
@@ -1388,12 +1368,7 @@ - (BOOL)handleInsertedRelationInSaveRequest:(NSRelationshipDescription *)relatio
1388
1368
sqlite3_stmt *statement = [self preparedStatementForQuery: string];
1389
1369
1390
1370
// Add the related objects properties
1391
- sqlite3_bind_int64 (statement, 1 , [inverseObjectID unsignedIntegerValue ]);
1392
-
1393
- if (needsInverseType) {
1394
- // If this relations scheme requires a inverse type column add the entity type
1395
- sqlite3_bind_int64 (statement, 2 , [obj.entity.name hash ]);
1396
- }
1371
+ sqlite3_bind_int64 (statement, 1 , [inverseObjectID unsignedLongLongValue ]);
1397
1372
1398
1373
sqlite3_step (statement);
1399
1374
@@ -1850,19 +1825,19 @@ - (BOOL) maybeAddJoinStatementsForKey: (NSString *) key
1850
1825
1851
1826
if ([rel isToMany ] && [inverse isToMany ]) {
1852
1827
1853
- // source entity table to relation table join
1854
- NSUInteger index ;
1855
- NSArray *columns = [ self columnNamesForRelationship: rel withQuotes: NO forCreation: NO ] ;
1856
- NSString *entity_name = [[ self rootForEntity: [ rel entity ]] name ];
1828
+ // ID columns
1829
+ NSString *firstIDColumn ;
1830
+ NSString *secondIDColumn ;
1831
+ BOOL sourceFirst = [self relationships: rel firstIDColumn: &firstIDColumn secondIDColumn: &secondIDColumn ];
1857
1832
1858
- if ([[columns firstObject ] isEqualToString: [NSString stringWithFormat: @" %@ __objectid" , entity_name]]) {
1859
- index = 0 ;
1833
+ NSString *clause1Column;
1834
+ NSString *clause2Column;
1835
+ if (sourceFirst) {
1836
+ clause1Column = firstIDColumn;
1837
+ clause2Column = secondIDColumn;
1860
1838
} else {
1861
- index = 1 ;
1862
- // Check to see if we need to skip a column as the second column might be a type column
1863
- if ([self entityNeedsEntityTypeColumn: [rel destinationEntity ]]) {
1864
- index++;
1865
- }
1839
+ clause1Column = secondIDColumn;
1840
+ clause2Column = firstIDColumn;
1866
1841
}
1867
1842
1868
1843
NSString *joinTableAsClause1 = [NSString stringWithFormat: @" %@ AS %@ " ,
@@ -1872,28 +1847,17 @@ - (BOOL) maybeAddJoinStatementsForKey: (NSString *) key
1872
1847
NSString *joinTableOnClause1 = [NSString stringWithFormat: @" %@ .__objectID = %@ .%@ " ,
1873
1848
lastTableName,
1874
1849
relTableName,
1875
- [columns objectAtIndex: index] ];
1850
+ clause1Column ];
1876
1851
1877
1852
NSString *firstJoinClause = [NSString stringWithFormat: @" LEFT OUTER JOIN %@ ON %@ " , joinTableAsClause1, joinTableOnClause1];
1878
1853
1879
- // relation table to destination entity table join
1880
- if (index >= 1 ) {
1881
- index = 0 ;
1882
- } else {
1883
- index = 1 ;
1884
- // Check to see if we need to skip a column as the second column might be a type column
1885
- if ([self entityNeedsEntityTypeColumn: [rel entity ]]) {
1886
- index++;
1887
- }
1888
- }
1889
-
1890
1854
NSString *joinTableAsClause2 = [NSString stringWithFormat: @" %@ AS %@ " ,
1891
1855
[self tableNameForEntity: [rel destinationEntity ]],
1892
1856
nextTableName];
1893
1857
1894
1858
NSString *joinTableOnClause2 = [NSString stringWithFormat: @" %@ .%@ = %@ .__objectID" ,
1895
1859
relTableName,
1896
- [columns objectAtIndex: index] ,
1860
+ clause2Column ,
1897
1861
nextTableName];
1898
1862
1899
1863
NSString *secondJoinClause = [NSString stringWithFormat: @" LEFT OUTER JOIN %@ ON %@ " , joinTableAsClause2, joinTableOnClause2];
0 commit comments