Skip to content

Instantly share code, notes, and snippets.

@cmkilger
Last active September 28, 2017 07:51
Show Gist options
  • Save cmkilger/3e1a3a8878f75f4a96f2e72cd84a2f95 to your computer and use it in GitHub Desktop.
Save cmkilger/3e1a3a8878f75f4a96f2e72cd84a2f95 to your computer and use it in GitHub Desktop.
Objective-C SQLite wrapper
#import <Foundation/Foundation.h>
@interface SQLiteDatabase: NSObject
- (nullable instancetype)initWithPath:(nonnull NSString *)path;
- (void)executeQuery:(nonnull NSString *)query;
- (void)executeQuery:(nonnull NSString *)query callback:(void(^ _Nullable)(NSDictionary<NSString *, id> * _Nonnull, BOOL * _Nonnull))callback;
@end
@interface SQLiteStatement: NSObject
- (nullable instancetype)initWithQueryTemplate:(nonnull NSString *)template inDatabase:(nonnull SQLiteDatabase *)database;
- (void)execute;
- (void)executeWithParameters:(nullable NSArray *)parameters;
- (void)executeWithCallback:(void(^ _Nullable)(NSDictionary<NSString *, id> * _Nonnull, BOOL * _Nonnull))callback;
- (void)executeWithParameters:(nullable NSArray *)parameters callback:(void(^ _Nullable)(NSDictionary<NSString *, id> * _Nonnull, BOOL * _Nonnull))callback;
@end
#import "SQLite.h"
#import <sqlite3.h>
@interface SQLiteDatabase ()
@property (assign) sqlite3 *database;
@end
@interface SQLiteStatement ()
@property (assign) sqlite3_stmt *statement;
@end
@implementation SQLiteDatabase
- (instancetype)initWithPath:(NSString *)path {
self = [super init];
if (self) {
if (sqlite3_open([path cStringUsingEncoding:NSUTF8StringEncoding], &_database) != SQLITE_OK) {
return nil;
}
}
return self;
}
- (void)dealloc {
if (_database) {
sqlite3_close(_database);
}
}
- (void)executeQuery:(NSString *)query {
[self executeQuery:query callback:nil];
}
- (void)executeQuery:(NSString *)query callback:(void(^)(NSDictionary<NSString *, id> *, BOOL *))callback {
[[[SQLiteStatement alloc] initWithQueryTemplate:query inDatabase:self] executeWithCallback:callback];
}
@end
@implementation SQLiteStatement
- (instancetype)initWithQueryTemplate:(NSString *)template inDatabase:(SQLiteDatabase *)database {
self = [super init];
if (self) {
if (sqlite3_prepare_v2(database.database, [template cStringUsingEncoding:NSUTF8StringEncoding], -1, &_statement, NULL) != SQLITE_OK) {
return nil;
}
}
return self;
}
- (void)dealloc {
if (_statement) {
sqlite3_finalize(_statement);
}
}
- (void)execute {
[self executeWithParameters:nil callback:nil];
}
- (void)executeWithParameters:(NSArray *)parameters {
[self executeWithParameters:parameters callback:nil];
}
- (void)executeWithCallback:(void(^)(NSDictionary<NSString *, id> *, BOOL *))callback {
[self executeWithParameters:nil callback:callback];
}
- (void)executeWithParameters:(NSArray *)parameters callback:(void(^)(NSDictionary<NSString *, id> *, BOOL *))callback {
sqlite3_reset(_statement);
for (int i = 0; i < parameters.count; i++) {
id parameter = parameters[i];
if ([parameter isKindOfClass:[NSNull class]]) {
sqlite3_bind_null(_statement, i+1);
} else if ([parameter isKindOfClass:[NSString class]]) {
sqlite3_bind_text(_statement, i+1, [parameter cStringUsingEncoding:NSUTF8StringEncoding], -1, SQLITE_STATIC);
} else if ([parameter isKindOfClass:[NSData class]]) {
sqlite3_bind_blob(_statement, i+1, [parameter bytes], [parameter length], NULL);
} else if ([parameter isKindOfClass:[NSNumber class]]) {
switch ([parameter objCType][0]) {
case 'd':
case 'f':
sqlite3_bind_double(_statement, i+1, [parameter doubleValue]);
break;
default:
sqlite3_bind_int64(_statement, i+1, [parameter longLongValue]);
break;
}
}
}
BOOL stop = NO;
int columnCount = sqlite3_column_count(_statement);
while (!stop && sqlite3_step(_statement) == SQLITE_ROW && callback) {
NSMutableDictionary<NSString *, id> *row = [[NSMutableDictionary alloc] init];
for (int i = 0; i < columnCount; i++) {
NSString *key = [[NSString alloc] initWithCString:sqlite3_column_name(_statement, i) encoding:NSUTF8StringEncoding];
id value = nil;
switch (sqlite3_column_type(_statement, i)) {
case SQLITE_NULL: {
value = [NSNull null];
} break;
case SQLITE_INTEGER: {
value = [[NSNumber alloc] initWithLongLong:sqlite3_column_int64(_statement, i)];
} break;
case SQLITE_FLOAT: {
value = [[NSNumber alloc] initWithDouble:sqlite3_column_double(_statement, i)];
} break;
case SQLITE_BLOB: {
int length = sqlite3_column_bytes(_statement, i);
const void *bytes = sqlite3_column_blob(_statement, i);
value = [[NSData alloc] initWithBytes:bytes length:length];
} break;
case SQLITE3_TEXT: {
int length = sqlite3_column_bytes(_statement, i);
const void *bytes = sqlite3_column_blob(_statement, i);
value = [[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding];
} break;
}
row[key] = value;
}
callback(row, &stop);
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment