Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Using object literals to append rows to tables #42

Merged
merged 15 commits into from
Mar 7, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2014-03-07
==========
* Adding appendRow to TightdbTable.

2014-03-05
==========
* Adding methods getVersion, getCoreVersion and isAtLeast.
Expand Down
2 changes: 1 addition & 1 deletion src/tightdb/objc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ nobase_subinclude_HEADERS_EXTRA_UNINSTALL = *.h
lib_LIBRARIES = libtightdb-objc.a

libtightdb_objc_a_SOURCES = table_objc.mm cursor_objc.mm group_objc.mm query_objc.mm \
group_shared_objc.mm version_objc.mm
group_shared_objc.mm support.mm version_objc.mm

libtightdb_objc_a_CFLAGS = -fobjc-arc -fobjc-abi-version=2
libtightdb_objc_a_LDFLAGS = -fobjc-link-runtime -framework Cocoa
Expand Down
29 changes: 29 additions & 0 deletions src/tightdb/objc/support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*************************************************************************
*
* 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.
*
**************************************************************************/

#ifndef TIGHTDB_OBJC_SUPPORT_H
#define TIGHTDB_OBJC_SUPPORT_H

#import <Foundation/Foundation.h>
#include <tightdb/descriptor.hpp>

BOOL verify_row(const tightdb::Descriptor& descr, NSArray * data);
BOOL insert_row(size_t ndx, tightdb::Table& table, NSArray * data);
#endif /* TIGHTDB_OBJC_SUPPORT_H */
241 changes: 241 additions & 0 deletions src/tightdb/objc/support.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
#import <Foundation/Foundation.h>

#include <tightdb/descriptor.hpp>

#import "table.h"

using namespace tightdb;

BOOL verify_row(const Descriptor& descr, NSArray * data)
{
if (descr.get_column_count() != [data count]) {
return NO;
}

NSEnumerator *enumerator = [data objectEnumerator];
id obj;

/* type encodings: http://nshipster.com/type-encodings/ */
size_t col_ndx = 0;
while (obj = [enumerator nextObject]) {
DataType type = descr.get_column_type(col_ndx);
switch (type) {
case type_String:
if (![obj isKindOfClass:[NSString class]])
return NO;
break;
case type_Bool:
if ([obj isKindOfClass:[NSNumber class]]) {
const char * data_type = [obj objCType];
const char dt = data_type[0];
if (dt == 'B' || dt == 'c')
break;
return NO;
}
break;
case type_DateTime:
if ([obj isKindOfClass:[NSNumber class]]) {
const char * data_type = [obj objCType];
const char dt = data_type[0];
/* time_t is an integer */
if (dt == 'i' || dt == 's' || dt == 'l' || dt == 'q' ||
dt == 'I' || dt == 'S' || dt == 'L' || dt == 'Q')
break;
else {
return NO;
}
}
if ([obj isKindOfClass:[NSDate class]]) {
break;
}
return NO;
case type_Int:
if ([obj isKindOfClass:[NSNumber class]]) {
const char * data_type = [obj objCType];
const char dt = data_type[0];
/* FIXME: what about: 'c', 'C' */
if (dt == 'i' || dt == 's' || dt == 'l' || dt == 'q' ||
dt == 'I' || dt == 'S' || dt == 'L' || dt == 'Q')
break;
else
return NO;
}
else {
return NO;
}
break;
case type_Float:
if ([obj isKindOfClass:[NSNumber class]]) {
const char * data_type = [obj objCType];
const char dt = data_type[0];
/* FIXME: what about: 'c', 'C' */
if (dt == 'i' || dt == 's' || dt == 'l' || dt == 'q' ||
dt == 'I' || dt == 'S' || dt == 'L' || dt == 'Q' ||
dt == 'f')
break;
else
return NO;
}
else
return NO;
break; /* FIXME: remove */
case type_Double:
if ([obj isKindOfClass:[NSNumber class]]) {
const char * data_type = [obj objCType];
const char dt = data_type[0];
/* FIXME: what about: 'c', 'C' */
if (dt == 'i' || dt == 's' || dt == 'l' || dt == 'q' ||
dt == 'I' || dt == 'S' || dt == 'L' || dt == 'Q' ||
dt == 'f' || dt == 'd')
break;
else
return NO;
}
else
return NO;
break; /* FIXME: remove */
case type_Binary:
if ([obj isKindOfClass:[TightdbBinary class]] ||
[obj isKindOfClass:[NSData class]])
break;
return NO;
case type_Mixed:
break; /* everything goes */
case type_Table:
if ([obj isKindOfClass:[NSArray class]]) {
if ([obj count] == 0)
break; /* empty subtable */
id subobj;
ConstDescriptorRef subdescr = descr.get_subdescriptor(col_ndx);
NSEnumerator *subenumerator = [obj objectEnumerator];
while (subobj = [subenumerator nextObject]) {
if (![subobj isKindOfClass:[NSArray class]])
return NO;
if (!verify_row(*subdescr, (NSArray *)subobj))
return NO;
}
}
else {
return NO;
}
break;

}
++col_ndx;
}
return YES;
}

BOOL insert_row(size_t row_ndx, tightdb::Table& table, NSArray * data)
{
/*
Assumption:
- data has been validated by verify_row
*/

NSEnumerator *enumerator = [data objectEnumerator];
id obj;

/* FIXME: handling of tightdb exceptions => return NO */
size_t col_ndx = 0;
while (obj = [enumerator nextObject]) {
DataType type = table.get_column_type(col_ndx);
switch (type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To quote a conversation we had earlier with @kspangsege and @kneth :

The general paradigm I use is

switch(column_type)
{
case type_Int:
    ...
    goto ok;
case type_Float:
    ...
    goto ok;
case type_Double:
    ...
    goto ok;
case type_Bool:
case type_DateTime:
case type_String:
case type_Binary:
case type_Mixed:
case type_Table:
    RAISE_COLUMN_TYPE(column_ndx,
        "either int, float, or double");
    return Qnil;
}

RAISE_UNKNOWN_TIGHTDB_TYPE(); // returns from the function

ok:
    return result;

The effect is that the compiler will warn of any missing cases, and if
any new cases are added (to core) after the extension has been
compiled, the extension will duly fail.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is nothing common to do after "ok:", I would definitely 'return result' in the 'case' instead of 'goto ok'.

case type_Bool:
table.insert_bool(col_ndx, row_ndx, bool([obj boolValue]));
break;
case type_DateTime:
if ([obj isKindOfClass:[NSDate class]]) {
table.insert_datetime(col_ndx, row_ndx, time_t([obj timeIntervalSince1970]));
}
else {
table.insert_datetime(col_ndx, row_ndx, time_t([obj longValue]));
}
break;
case type_Int:
table.insert_int(col_ndx, row_ndx, int64_t([obj longValue]));
break;
case type_Float:
table.insert_float(col_ndx, row_ndx, float([obj floatValue]));
break;
case type_Double:
table.insert_double(col_ndx, row_ndx, double([obj doubleValue]));
break;
case type_String:
{
StringData sd([obj UTF8String]);
table.insert_string(col_ndx, row_ndx, sd);
}
break;
case type_Binary:
if ([obj isKindOfClass:[TightdbBinary class]]) {
BinaryData bd([obj getData], [obj getSize]);
table.insert_binary(col_ndx, row_ndx, bd);
}
else { /* NSData */
const void *data = [obj bytes];
BinaryData bd(static_cast<const char *>(data), [obj length]);
table.insert_binary(col_ndx, row_ndx, bd);
}
break;
case type_Table:
if ([obj count]) {
table.clear_subtable(col_ndx, row_ndx);
}
else {
// Clear sub-table to prepare for new values
table.clear_subtable(col_ndx, row_ndx);
table.insert_subtable(col_ndx, row_ndx);
TableRef subtable = table.get_subtable(col_ndx, row_ndx);
NSEnumerator *subenumerator = [obj objectEnumerator];
id subobj;
size_t subrow_ndx = 0;
while (subobj = [subenumerator nextObject]) {
if (!insert_row(subrow_ndx, *subtable, subobj))
return NO;
++subrow_ndx;
}
}
break;
case type_Mixed:
/* FIXME: subtable, datetime are missing */
if ([obj isKindOfClass:[NSString class]]) {
StringData sd([obj UTF8String]);
table.insert_mixed(col_ndx, row_ndx, sd);
break;
}
if ([obj isKindOfClass:[TightdbBinary class]]) {
BinaryData bd([obj getData], [obj getSize]);
table.insert_mixed(col_ndx, row_ndx, bd);
break;
}
if ([obj isKindOfClass:[NSNumber class]]) {
const char *data_type = [obj objCType];
const char dt = data_type[0];
switch (dt) {
case 'i':
case 's':
case 'l':
table.insert_mixed(col_ndx, row_ndx, (int64_t)[obj longValue]);
break;
case 'f':
table.insert_mixed(col_ndx, row_ndx, [obj floatValue]);
break;
case 'd':
table.insert_mixed(col_ndx, row_ndx, [obj doubleValue]);
break;
case 'B':
case 'c':
table.insert_mixed(col_ndx, row_ndx, [obj boolValue] == YES);
break;
}
break;
}
return NO;
}
++col_ndx;
}
table.insert_done();

return YES;
}
2 changes: 2 additions & 0 deletions src/tightdb/objc/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@

-(TightdbCursor *)insertRowAtIndex:(size_t)ndx;

-(BOOL)appendRow:(NSArray *)data;

-(BOOL)insertRow:(size_t)ndx;
-(BOOL)insertRow:(size_t)ndx error:(NSError *__autoreleasing *)error;

Expand Down
15 changes: 15 additions & 0 deletions src/tightdb/objc/table_objc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// TightDB
//

#import <Foundation/Foundation.h>

#include <tightdb/util/unique_ptr.hpp>
#include <tightdb/table.hpp>
#include <tightdb/descriptor.hpp>
Expand All @@ -14,6 +16,7 @@
#import <tightdb/objc/query.h>
#import <tightdb/objc/query_priv.h>
#import <tightdb/objc/cursor.h>
#import <tightdb/objc/support.h>

#include <tightdb/objc/util.hpp>

Expand Down Expand Up @@ -673,6 +676,18 @@ -(TightdbCursor*)insertRowAtIndex:(size_t)ndx
return [[TightdbCursor alloc] initWithTable:self ndx:ndx];
}

-(BOOL)appendRow:(NSArray*)data
{
tightdb::Table& table = *m_table;
tightdb::ConstDescriptorRef desc = table.get_descriptor();
if (!verify_row(*desc, data)) {
return NO;
}

/* append row */
return insert_row(table.size(), table, data);
}

-(BOOL)insertRow:(size_t)ndx
{
return [self insertRow:ndx error:nil];
Expand Down
Loading