diff --git a/TightDbObjcDyn/TightDbObjcDyn.xcodeproj/project.pbxproj b/TightDbObjcDyn/TightDbObjcDyn.xcodeproj/project.pbxproj index 9cd852e18d..74f814b0a7 100644 --- a/TightDbObjcDyn/TightDbObjcDyn.xcodeproj/project.pbxproj +++ b/TightDbObjcDyn/TightDbObjcDyn.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 4D01A9EF18C75B4100527AD5 /* table_view.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D01A9EE18C75B4100527AD5 /* table_view.m */; }; 4D79966018BDFC3E009EB0C0 /* table_macros.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D79965F18BDFC3E009EB0C0 /* table_macros.h */; }; 4DB1DEFB18BF70AE005A7234 /* dynamic_table.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DB1DEF818BF70AE005A7234 /* dynamic_table.m */; }; 4DB1DEFC18BF70AE005A7234 /* functional.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DB1DEF918BF70AE005A7234 /* functional.m */; }; @@ -59,6 +60,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 4D01A9EE18C75B4100527AD5 /* table_view.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = table_view.m; sourceTree = ""; }; 4D79965F18BDFC3E009EB0C0 /* table_macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = table_macros.h; path = ../../src/tightdb/objc/table_macros.h; sourceTree = ""; }; 4DB1DEF818BF70AE005A7234 /* dynamic_table.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = dynamic_table.m; path = ../../src/tightdb/objc/test/dynamic_table.m; sourceTree = ""; }; 4DB1DEF918BF70AE005A7234 /* functional.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = functional.m; path = ../../src/tightdb/objc/test/functional.m; sourceTree = ""; }; @@ -206,6 +208,7 @@ 4DB1DEF818BF70AE005A7234 /* dynamic_table.m */, 4DB1DEF918BF70AE005A7234 /* functional.m */, 4DB1DEFA18BF70AE005A7234 /* typed_table.m */, + 4D01A9EE18C75B4100527AD5 /* table_view.m */, E91890E7177B71E400653D7A /* data_type.mm */, E91890E8177B71E400653D7A /* enumerator.m */, E91890E9177B71E400653D7A /* err_handling.mm */, @@ -378,6 +381,7 @@ E91890FE177B71E400653D7A /* subtable.m in Sources */, 4DB1DEFC18BF70AE005A7234 /* functional.m in Sources */, 4DB1DEFD18BF70AE005A7234 /* typed_table.m in Sources */, + 4D01A9EF18C75B4100527AD5 /* table_view.m in Sources */, E91890FF177B71E400653D7A /* table_delete_all.m in Sources */, 4DB1DEFB18BF70AE005A7234 /* dynamic_table.m in Sources */, E9189101177B71E400653D7A /* template.m in Sources */, diff --git a/TightDbObjcDyn/TightDbObjcDynTests/table_view.m b/TightDbObjcDyn/TightDbObjcDynTests/table_view.m new file mode 100644 index 0000000000..abbb69e0a5 --- /dev/null +++ b/TightDbObjcDyn/TightDbObjcDynTests/table_view.m @@ -0,0 +1,257 @@ +/************************************************************************* + * + * TIGHTDB CONFIDENTIAL + * __________________ + * + * [2011] - [2014] TightDB Inc + * All Rights Reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of TightDB Incorporated and its suppliers, + * if any. The intellectual and technical concepts contained + * herein are proprietary to TightDB Incorporated + * and its suppliers and may be covered by U.S. and Foreign Patents, + * patents in process, and are protected by trade secret or copyright law. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from TightDB Incorporated. + * + **************************************************************************/ + +#import + +#import + + +@interface table_view : SenTestCase + +@end + +@implementation table_view + +- (void)setUp +{ + [super setUp]; + // Put setup code here; it will be run once, before the first test case. +} + +- (void)tearDown +{ + // Put teardown code here; it will be run once, after the last test case. + [super tearDown]; +} + +-(void)getColumnCount +{ + TightdbTable *t = [[TightdbTable alloc] init]; + TightdbQuery *q = [t where]; + TightdbView *v = [q findAll]; + + STAssertEquals(0, [v getColumnCount], @"no columns added yet"); + + [t addColumnWithType:tightdb_Int andName:@"col0"]; + STAssertEquals(1, [v getColumnCount], @"1 column added to table"); + + for (int i=0;i<10;i++) { + [t addColumnWithType:tightdb_Int andName:@"name"]; + } + STAssertEquals(11, [v getColumnCount], @"10 more columns added to table"); + + // remove column on table not yet implemented +} + +- (void)testColumnTypesOnView +{ + TightdbTable *t = [[TightdbTable alloc] init]; + + NSUInteger boolCol = [t addColumnWithType:tightdb_Bool andName:@"boolCol"]; + NSUInteger binaryCol = [t addColumnWithType:tightdb_Binary andName:@"binaryCol"]; + NSUInteger dateCol = [t addColumnWithType:tightdb_Date andName:@"dateCol"]; + NSUInteger doubleCol = [t addColumnWithType:tightdb_Double andName:@"doubleCol"]; + NSUInteger floatCol = [t addColumnWithType:tightdb_Float andName:@"floatCol"]; + NSUInteger intCol = [t addColumnWithType:tightdb_Int andName:@"intCol"]; + NSUInteger mixedCol = [t addColumnWithType:tightdb_Mixed andName:@"MixedCol"]; + NSUInteger stringCol = [t addColumnWithType:tightdb_String andName:@"stringCol"]; + NSUInteger tableCol = [t addColumnWithType:tightdb_Table andName:@"tableCol"]; + + + TightdbQuery *q = [t where]; + TightdbView *v = [q findAll]; + + STAssertTrue([v getColumnType:boolCol] == tightdb_Bool, @"Column types matches"); + STAssertTrue([v getColumnType:binaryCol] == tightdb_Binary, @"Column types matches"); + STAssertTrue([v getColumnType:dateCol] == tightdb_Date, @"Column types matches"); + STAssertTrue([v getColumnType:doubleCol] == tightdb_Double, @"Column types matches"); + STAssertTrue([v getColumnType:floatCol] == tightdb_Float, @"Column types matches"); + STAssertTrue([v getColumnType:intCol] == tightdb_Int, @"Column types matches"); + STAssertTrue([v getColumnType:mixedCol] == tightdb_Mixed, @"Column types matches"); + STAssertTrue([v getColumnType:stringCol] == tightdb_String, @"Column types matches"); + STAssertTrue([v getColumnType:tableCol] == tightdb_Table, @"Column types matches"); + + STAssertThrows([v getColumnType:[v getColumnCount] + 1], @"Out of bounds"); + STAssertThrows([v getColumnType:100], @"Out of bounds"); + STAssertThrows([v getColumnType:-1], @"Out of bounds"); +} + +- (void)testSortOnViewIntColumn +{ + TightdbTable *t = [[TightdbTable alloc] init]; + NSUInteger intCol = [t addColumnWithType:tightdb_Int andName:@"intCol"]; + + TightdbCursor *row = [t addEmptyRow]; + [row setInt:2 inColumn:intCol]; + + row = [t addEmptyRow]; + [row setInt:1 inColumn:intCol]; + + row = [t addEmptyRow]; + [row setInt:0 inColumn:intCol]; + + TightdbQuery *q = [t where]; + TightdbView *v = [q findAll]; + + // Not yet sorted + STAssertTrue([v get:intCol ndx:0] == 2, @"matcing value after no sort"); + STAssertTrue([v get:intCol ndx:1] == 1, @"matcing value after no sort"); + STAssertTrue([v get:intCol ndx:2] == 0, @"matcing value after no sort"); + + // Sort same way without order specified. Ascending default + [v sortColumnWithIndex:intCol]; + STAssertTrue([v get:intCol ndx:0] == 0, @"matcing value after default sort"); + STAssertTrue([v get:intCol ndx:1] == 1, @"matcing value after default sort"); + STAssertTrue([v get:intCol ndx:2] == 2, @"matcing value after default sort"); + + // Sort same way + [v sortColumnWithIndex:intCol inOrder:tightdb_ascending]; + STAssertTrue([v get:intCol ndx:0] == 0, @"matcing value after ascending sort"); + STAssertTrue([v get:intCol ndx:1] == 1, @"matcing value after ascending sort"); + STAssertTrue([v get:intCol ndx:2] == 2, @"matcing value after ascending sort"); + + // Sort descending + [v sortColumnWithIndex:intCol inOrder: tightdb_descending]; + STAssertTrue([v get:intCol ndx:0] == 2, @"matcing value after descending sort"); + STAssertTrue([v get:intCol ndx:1] == 1, @"matcing value after descending sort"); + STAssertTrue([v get:intCol ndx:2] == 0, @"matcing value after descending sort"); +} + +- (void)testSortOnViewBoolColumn +{ + TightdbTable *t = [[TightdbTable alloc] init]; + NSUInteger boolCol = [t addColumnWithType:tightdb_Bool andName:@"boolCol"]; + + TightdbCursor *row = [t addEmptyRow]; + [row setBool:YES inColumn:boolCol]; + + row = [t addEmptyRow]; + [row setBool:YES inColumn:boolCol]; + + row = [t addEmptyRow]; + [row setBool:NO inColumn:boolCol]; + + TightdbQuery *q = [t where]; + TightdbView *v = [q findAll]; + + // Not yet sorted + STAssertTrue([v getBool:boolCol ndx:0] == YES, @"matcing value after no sort"); + STAssertTrue([v getBool:boolCol ndx:1] == YES, @"matcing value after no sort"); + STAssertTrue([v getBool:boolCol ndx:2] == NO, @"matcing value after no sort"); + + // Sort same way without order specified. Ascending default + [v sortColumnWithIndex:boolCol]; + STAssertTrue([v getBool:boolCol ndx:0] == NO, @"matcing value after default sort"); + STAssertTrue([v getBool:boolCol ndx:1] == YES, @"matcing value after default sort"); + STAssertTrue([v getBool:boolCol ndx:2] == YES, @"matcing value after default sort"); + + // Sort same way + [v sortColumnWithIndex:boolCol inOrder:tightdb_ascending]; + STAssertTrue([v getBool:boolCol ndx:0] == NO, @"matcing value after ascending sort"); + STAssertTrue([v getBool:boolCol ndx:1] == YES, @"matcing value after ascending sort"); + STAssertTrue([v getBool:boolCol ndx:2] == YES, @"matcing value after ascending sort"); + + // Sort descending + [v sortColumnWithIndex:boolCol inOrder: tightdb_descending]; + STAssertTrue([v getBool:boolCol ndx:0] == YES, @"matcing value after descending sort"); + STAssertTrue([v getBool:boolCol ndx:1] == YES, @"matcing value after descending sort"); + STAssertTrue([v getBool:boolCol ndx:2] == NO, @"matcing value after descending sort"); +} + + +- (void)testSortOnViewDateColumn +{ + TightdbTable *t = [[TightdbTable alloc] init]; + NSUInteger dateCol = [t addColumnWithType:tightdb_Date andName:@"dateCol"]; + + + NSDateFormatter *formatter = [[NSDateFormatter alloc]init]; + [formatter setDateFormat:@"MM/dd/yyyy hh:mm a"]; + + NSDate *dateFirst = [formatter dateFromString:@"01/01/2014 10:10 PM"]; + NSDate *dateMiddle = [formatter dateFromString:@"02/01/2014 10:10 PM"]; + NSDate *dateLast = [formatter dateFromString:@"03/01/2014 10:10 PM"]; + + TightdbCursor *row = [t addEmptyRow]; + [row setDate:[dateLast timeIntervalSince1970] inColumn:dateCol]; + + row = [t addEmptyRow]; + [row setDate:[dateMiddle timeIntervalSince1970] inColumn:dateCol]; + + row = [t addEmptyRow]; + [row setDate:[dateFirst timeIntervalSince1970] inColumn:dateCol]; + + TightdbQuery *q = [t where]; + TightdbView *v = [q findAll]; + + // Not yet sorted + STAssertTrue([v getDate:dateCol ndx:0] == [dateLast timeIntervalSince1970], @"matcing value after no sort"); + STAssertTrue([v getDate:dateCol ndx:1] == [dateMiddle timeIntervalSince1970], @"matcing value after no sort"); + STAssertTrue([v getDate:dateCol ndx:2] == [dateFirst timeIntervalSince1970], @"matcing value after no sort"); + + // Sort same way without order specified. Ascending default + [v sortColumnWithIndex:dateCol]; + STAssertTrue([v getDate:dateCol ndx:0] == [dateFirst timeIntervalSince1970], @"matcing value after default sort"); + STAssertTrue([v getDate:dateCol ndx:1] == [dateMiddle timeIntervalSince1970], @"matcing value after default sort"); + STAssertTrue([v getDate:dateCol ndx:2] == [dateLast timeIntervalSince1970], @"matcing value after default sort"); + + // Sort same way + [v sortColumnWithIndex:dateCol inOrder:tightdb_ascending]; + STAssertTrue([v getDate:dateCol ndx:0] == [dateFirst timeIntervalSince1970], @"matcing value after ascending sort"); + STAssertTrue([v getDate:dateCol ndx:1] == [dateMiddle timeIntervalSince1970], @"matcing value after ascending sort"); + STAssertTrue([v getDate:dateCol ndx:2] == [dateLast timeIntervalSince1970], @"matcing value after ascending sort"); + + // Sort descending + [v sortColumnWithIndex:dateCol inOrder: tightdb_descending]; + STAssertTrue([v getDate:dateCol ndx:0] == [dateLast timeIntervalSince1970], @"matcing value after descending sort"); + STAssertTrue([v getDate:dateCol ndx:1] == [dateMiddle timeIntervalSince1970], @"matcing value after descending sort"); + STAssertTrue([v getDate:dateCol ndx:2] == [dateFirst timeIntervalSince1970], @"matcing value after descending sort"); +} + + +- (void)testSortOnAllColumnTypes +{ + TightdbTable *t = [[TightdbTable alloc] init]; + + NSUInteger boolCol = [t addColumnWithType:tightdb_Bool andName:@"boolCol"]; + NSUInteger binaryCol = [t addColumnWithType:tightdb_Binary andName:@"binaryCol"]; + NSUInteger dateCol = [t addColumnWithType:tightdb_Date andName:@"dateCol"]; + NSUInteger doubleCol = [t addColumnWithType:tightdb_Double andName:@"doubleCol"]; + NSUInteger floatCol = [t addColumnWithType:tightdb_Float andName:@"floatCol"]; + NSUInteger intCol = [t addColumnWithType:tightdb_Int andName:@"intCol"]; + NSUInteger mixedCol = [t addColumnWithType:tightdb_Mixed andName:@"MixedCol"]; + NSUInteger stringCol = [t addColumnWithType:tightdb_String andName:@"stringCol"]; + NSUInteger tableCol = [t addColumnWithType:tightdb_Table andName:@"tableCol"]; + + TightdbQuery *q = [t where]; + TightdbView *v = [q findAll]; + + [v sortColumnWithIndex:boolCol]; // bool is supported + STAssertThrows([v sortColumnWithIndex:binaryCol], @"Not supported on binary column"); + [v sortColumnWithIndex:dateCol]; // bool is supported + STAssertThrows([v sortColumnWithIndex:doubleCol], @"Not supported on double column"); + STAssertThrows([v sortColumnWithIndex:floatCol], @"Not supported on float column"); + [v sortColumnWithIndex:intCol]; // int is supported + STAssertThrows([v sortColumnWithIndex:mixedCol], @"Not supported on mixed column"); + STAssertThrows([v sortColumnWithIndex:stringCol], @"Not supported on string column"); + STAssertThrows([v sortColumnWithIndex:tableCol], @"Not supported on table column"); +} + +@end diff --git a/changes.txt b/changes.txt index b4565b22c1..cd9bb3548a 100644 --- a/changes.txt +++ b/changes.txt @@ -5,6 +5,9 @@ 2014-03-05 ========== ++ tableview now supports sort on column with column type bool, date and int ++ tableview has method for checking the column type of a specified column ++ tableview has method for getting the number of columns * Adding methods getVersion, getCoreVersion and isAtLeast. 2014-02-27 diff --git a/src/tightdb/objc/query.h b/src/tightdb/objc/query.h index 406ec4e328..d037778876 100644 --- a/src/tightdb/objc/query.h +++ b/src/tightdb/objc/query.h @@ -22,7 +22,6 @@ @class TightdbBinary; @class TightdbTable; -@class TightdbTableView; /* jjepsen: this must be an error? */ /* jjepsen: please review this */ @class TightdbView; diff --git a/src/tightdb/objc/table.h b/src/tightdb/objc/table.h index 74c04b24f3..c6c9869c24 100644 --- a/src/tightdb/objc/table.h +++ b/src/tightdb/objc/table.h @@ -282,6 +282,10 @@ -(size_t)count; -(BOOL)isEmpty; +-(TightdbType)getColumnType:(size_t)colNdx; +-(size_t)getColumnCount; +-(void) sortColumnWithIndex: (size_t)columnIndex; +-(void) sortColumnWithIndex: (size_t)columnIndex inOrder: (TightdbSortOrder)order; -(int64_t)get:(size_t)colNdx ndx:(size_t)ndx; -(BOOL)getBool:(size_t)colNdx ndx:(size_t)ndx; -(time_t)getDate:(size_t)colNdx ndx:(size_t)ndx; diff --git a/src/tightdb/objc/table_objc.mm b/src/tightdb/objc/table_objc.mm index 6ef8eb86b2..765a695166 100644 --- a/src/tightdb/objc/table_objc.mm +++ b/src/tightdb/objc/table_objc.mm @@ -394,6 +394,40 @@ -(BOOL)isEmpty { return m_view->is_empty(); } +-(size_t)getColumnCount +{ + return m_view->get_column_count(); +} + +-(TightdbType)getColumnType:(size_t)colNdx +{ + TIGHTDB_EXCEPTION_HANDLER_COLUMN_INDEX_VALID(colNdx); + return TightdbType(m_view->get_column_type(colNdx)); +} +-(void) sortColumnWithIndex: (size_t)columnIndex +{ + [self sortColumnWithIndex:columnIndex inOrder:tightdb_ascending]; +} +-(void) sortColumnWithIndex: (size_t)columnIndex inOrder: (TightdbSortOrder)order +{ + TightdbType columnType = [self getColumnType:columnIndex]; + + if(columnType != tightdb_Int && columnType != tightdb_Bool && columnType != tightdb_Date) { + NSException* exception = [NSException exceptionWithName:@"tightdb:sort_on_column_with_type_not_supported" + reason:@"Sort is currently only supported on Integer, Boolean and Date columns." + userInfo:[NSMutableDictionary dictionary]]; + [exception raise]; + } + + try { + m_view->sort(columnIndex, order == 0); + } catch(std::exception& ex) { + NSException* exception = [NSException exceptionWithName:@"tightdb:core_exception" + reason:[NSString stringWithUTF8String:ex.what()] + userInfo:[NSMutableDictionary dictionary]]; + [exception raise]; + } +} -(int64_t)get:(size_t)col_ndx ndx:(size_t)ndx { return m_view->get_int(col_ndx, ndx); diff --git a/src/tightdb/objc/type.h b/src/tightdb/objc/type.h index 915ff04b2c..0f5368839c 100644 --- a/src/tightdb/objc/type.h +++ b/src/tightdb/objc/type.h @@ -33,4 +33,11 @@ typedef enum { tightdb_Mixed = 6, } TightdbType; + +typedef enum { + tightdb_ascending = 0, + tightdb_descending = 1, + +} TightdbSortOrder; + #endif /* TIGHTDB_OBJC_TYPE_H */ diff --git a/src/tightdb/objc/util.hpp b/src/tightdb/objc/util.hpp index 691e2a9a9a..fb4e8d3fe5 100644 --- a/src/tightdb/objc/util.hpp +++ b/src/tightdb/objc/util.hpp @@ -135,7 +135,7 @@ catch(std::exception& ex) { \ } #define TIGHTDB_EXCEPTION_HANDLER_COLUMN_INDEX_VALID(columnIndex) \ - if (columnIndex >= [self getColumnCount]) { \ +if (columnIndex >= [self getColumnCount]) { \ NSException* exception = [NSException exceptionWithName:@"tightdb:column_index_out_of_bounds" \ reason:@"The specified column index is not within the table bounds" \ userInfo:[NSMutableDictionary dictionary]]; \ @@ -151,4 +151,11 @@ catch(std::exception& ex) { \ [exception raise]; \ } + + + + + + + #endif // TIGHTDB_OBJC_UTIL_HPP