Skip to content

Commit 8ea8aa3

Browse files
committed
Instead of another column being added to the relation table for the type a JOIN is done when getting new values for many-to-many relationships
1 parent d177fce commit 8ea8aa3

File tree

1 file changed

+57
-93
lines changed

1 file changed

+57
-93
lines changed

Incremental Store/EncryptedStore.m

Lines changed: 57 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -489,15 +489,28 @@ - (id)newValueForRelationship:(NSRelationshipDescription *)relationship
489489
sqlite3_bind_int64(statement, 1, key);
490490

491491
} 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
493493

494-
NSString *relationTable = [self tableNameForRelationship:relationship];
494+
NSString *sourceEntityName = [[self rootForEntity:sourceEntity] name];
495+
NSString *destinationEntityName = [[self rootForEntity:destinationEntity] name];
495496

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+
}
499512

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];
501514
statement = [self preparedStatementForQuery:string];
502515
sqlite3_bind_int64(statement, 1, key);
503516

@@ -1158,13 +1171,16 @@ - (BOOL)alterTableForSourceEntity:(NSEntityDescription *)sourceEntity
11581171
return YES;
11591172
}
11601173

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];
11621179
// create table
1163-
NSArray *columns = [self columnNamesForRelationship:relationship withQuotes:YES forCreation:YES];
11641180
NSString *string = [NSString stringWithFormat:
1165-
@"CREATE TABLE %@ (%@);",
1181+
@"CREATE TABLE %@ ('%@' INTEGER NOT NULL, '%@' INTEGER NOT NULL, PRIMARY KEY('%@', '%@'));",
11661182
[self tableNameForRelationship:relationship],
1167-
[columns componentsJoinedByString:@", "]];
1183+
firstIDColumn, secondIDColumn, firstIDColumn, secondIDColumn];
11681184
sqlite3_stmt *statement = [self preparedStatementForQuery:string];
11691185
sqlite3_step(statement);
11701186

@@ -1196,25 +1212,11 @@ -(NSString *)tableNameForRelationship:(NSRelationshipDescription *)relationship
11961212
return [NSString stringWithFormat:@"ecd_%@",[names componentsJoinedByString:@"_"]];
11971213
}
11981214

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
12011217
{
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);
12181220

12191221
NSEntityDescription *rootSourceEntity = [self rootForEntity:relationship.entity];
12201222
NSEntityDescription *rootDestinationEntity = [self rootForEntity:relationship.destinationEntity];
@@ -1224,38 +1226,16 @@ -(NSArray *)columnNamesForRelationship:(NSRelationshipDescription *)relationship
12241226
NSEntityDescription *firstEntity = [orderedEntities firstObject];
12251227
NSEntityDescription *secondEntity = [orderedEntities lastObject];
12261228

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";
12301230

12311231
// 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];
12411233

12421234
// 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];
12571236

1258-
return columns;
1237+
// Return if the relationship.entity was first
1238+
return orderedEntities[0] == rootSourceEntity;
12591239
}
12601240

12611241
#pragma mark - save changes to the database
@@ -1368,16 +1348,16 @@ - (BOOL)handleInsertedRelationInSaveRequest:(NSRelationshipDescription *)relatio
13681348

13691349
NSString *tableName = [self tableNameForRelationship:relationship];
13701350

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];
13741354

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];
13791357

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];
13811361

13821362
__block BOOL success = YES;
13831363

@@ -1388,12 +1368,7 @@ - (BOOL)handleInsertedRelationInSaveRequest:(NSRelationshipDescription *)relatio
13881368
sqlite3_stmt *statement = [self preparedStatementForQuery:string];
13891369

13901370
// 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]);
13971372

13981373
sqlite3_step(statement);
13991374

@@ -1850,19 +1825,19 @@ - (BOOL) maybeAddJoinStatementsForKey: (NSString *) key
18501825

18511826
if ([rel isToMany] && [inverse isToMany]) {
18521827

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];
18571832

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;
18601838
} 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;
18661841
}
18671842

18681843
NSString *joinTableAsClause1 = [NSString stringWithFormat:@"%@ AS %@",
@@ -1872,28 +1847,17 @@ - (BOOL) maybeAddJoinStatementsForKey: (NSString *) key
18721847
NSString *joinTableOnClause1 = [NSString stringWithFormat:@"%@.__objectID = %@.%@",
18731848
lastTableName,
18741849
relTableName,
1875-
[columns objectAtIndex:index]];
1850+
clause1Column];
18761851

18771852
NSString *firstJoinClause = [NSString stringWithFormat:@"LEFT OUTER JOIN %@ ON %@", joinTableAsClause1, joinTableOnClause1];
18781853

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-
18901854
NSString *joinTableAsClause2 = [NSString stringWithFormat:@"%@ AS %@",
18911855
[self tableNameForEntity:[rel destinationEntity]],
18921856
nextTableName];
18931857

18941858
NSString *joinTableOnClause2 = [NSString stringWithFormat:@"%@.%@ = %@.__objectID",
18951859
relTableName,
1896-
[columns objectAtIndex:index],
1860+
clause2Column,
18971861
nextTableName];
18981862

18991863
NSString *secondJoinClause = [NSString stringWithFormat:@"LEFT OUTER JOIN %@ ON %@", joinTableAsClause2, joinTableOnClause2];

0 commit comments

Comments
 (0)