From 5d6a5eae04004beaf844dfe607975087821c724f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=9A=E5=AE=87?= Date: Tue, 20 Jan 2015 21:25:33 +0800 Subject: [PATCH 1/3] added migrater --- .gitignore | 2 + README | 103 +++++++ SQLiteManager.h | 7 + SQLiteManager.m | 284 +++++++++++------- SQLiteManagerExample/Classes/MyMigrater.h | 15 + SQLiteManagerExample/Classes/MyMigrater.m | 41 +++ .../Classes/UntitledViewController.m | 2 + .../project.pbxproj | 14 + SQLiteMigrater.h | 29 ++ SQLiteMigrater.m | 67 +++++ 10 files changed, 462 insertions(+), 102 deletions(-) create mode 100644 .gitignore create mode 100644 SQLiteManagerExample/Classes/MyMigrater.h create mode 100644 SQLiteManagerExample/Classes/MyMigrater.m create mode 100644 SQLiteMigrater.h create mode 100644 SQLiteMigrater.m diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0f6783 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +SQLiteManagerExample/SQLiteManagerExample.xcodeproj/project.xcworkspace/ +SQLiteManagerExample/SQLiteManagerExample.xcodeproj/xcuserdata/ diff --git a/README b/README index 4385b5d..57648f5 100644 --- a/README +++ b/README @@ -39,3 +39,106 @@ If you have any doubts, don't hesitate to contact me at esanchez [at] misato [do You have also an usage example in SQLiteManagerExample directory. +********************** + + MIGRATION + +********************** + +If your app is version 0.1, and then you released version 0.2, and in version 0.2 you did modified the structure of database, so you have to migrate the old version database to a new version, SQLiteMigrater will help you to solve this issue :D + +here is an example: + +```objc + +////////////////////////////////////////////////// MyMigrater.h + +#import "SQLiteMigrater.h" + +static NSString * const kIGLocalStorageTableNameSystemMessage = @"SystemMessage"; // this is your table name + +@interface MyMigrater : SQLiteMigrater +@end + + +////////////////////////////////////////////////// MyMigrater.m + +#import "MyMigrater.h" +#import "SQLiteManager.h" + +@implementation MyMigrater + +@synthesize migrateList = _migrateList; +@synthesize versionList = _versionList; + +#pragma mark - getters and setters +- (NSDictionary *)migrateList +{ + if (_migrateList == nil) { + SQLiteManagerMigrateObject *migrate0_1 = [[SQLiteManagerMigrateObject alloc] init]; + migrate0_1.upSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);", kIGLocalStorageTableNameSystemMessage]; + migrate0_1.downSql = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@;", kIGLocalStorageTableNameSystemMessage]; + + SQLiteManagerMigrateObject *migrate0_2 = [[SQLiteManagerMigrateObject alloc] init]; + migrate0_2.upSql = [NSString stringWithFormat:@"INSERT INTO %@ (name) VALUES ('casa');", kIGLocalStorageTableNameSystemMessage]; + + _migrateList = @{@"0.1":migrate0_1, @"0.2":migrate0_2}; + } + return _migrateList; +} + +- (NSArray *)versionList +{ + if (_versionList == nil) { + _versionList = @[kSQLiteVersionDefaultVersion, @"0.1", @"0.2"]; + } + return _versionList; +} + +@end + +``` + +and you should set your instance of migrator after you created SQLiteManager: + +```objc + +dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; +dbManager.migrator = [[MyMigrater alloc] init]; + +``` + +********************** + + HOW TO CREATE MIGRATER + +********************** + +1. inherit SQLiteMigrater + +2. synthesize migrateList and versionList + +3. write getter for `migrateList` + + 3.1 the key is version string, and the value is instance of `SQLiteManagerMigrateObject` + + 3.2 set upSql of `SQLiteManagerMigrateObject`, upSql is the SQL to do your change of new version. + + 3.3 set downSql of `SQLiteManagerMigrateObject`, if upSql failed, migrater will run downSql to rollback. You don't have to set it + +4. write getter for `versionList` + + 4.1 the first one must be `kSQLiteVersionDefaultVersion` + + 4.2 migrator will execute `SQLiteManagerMigrateObject` in the order of this versionList + +5. make sure your `migrateList` is correct with `versionList` + +6. instanciate your migrater and set it to your SQLiteManager: +```objc +dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; +dbManager.migrator = [[MyMigrater alloc] init]; +``` + +7. done! + diff --git a/SQLiteManager.h b/SQLiteManager.h index ea6d83f..fdf812d 100644 --- a/SQLiteManager.h +++ b/SQLiteManager.h @@ -8,7 +8,10 @@ #import #import "sqlite3.h" +#import "SQLiteMigrater.h" +static NSString * const kSQLiteVersionTableName = @"ThisIsAStrangeVersionTableName"; +static NSString * const kSQLiteVersionDefaultVersion = @"InitialVersion"; enum errorCodes { kDBNotExists, @@ -24,6 +27,10 @@ enum errorCodes { NSString *databaseName; // The database name } +// migrater related +@property (nonatomic, strong) SQLiteMigrater *migrator; +@property (nonatomic, copy, readonly) NSString *currentVersion; + - (id)initWithDatabaseNamed:(NSString *)name; // SQLite Operations diff --git a/SQLiteManager.m b/SQLiteManager.m index 1f04a91..eb9ee39 100644 --- a/SQLiteManager.m +++ b/SQLiteManager.m @@ -8,15 +8,22 @@ #import "SQLiteManager.h" -// Private methods + @interface SQLiteManager (Private) - (NSString *)getDatabasePath; - (NSError *)createDBErrorWithDescription:(NSString*)description andCode:(int)code; +- (NSError *)executeQuery:(NSString *)sqlStirng; +- (void)modifyCurrentVersionWithVersionString:(NSString *)string; +- (NSArray *)fetchRowsWithQuery:(NSString *)sqlString; @end +@interface SQLiteManager () + +@property (nonatomic, strong, readwrite) NSString *currentVerson; +@end @implementation SQLiteManager @@ -56,6 +63,7 @@ - (NSError *) openDatabase { NSError *error = nil; NSString *databasePath = [self getDatabasePath]; + BOOL isNewDataBase = !([[NSFileManager defaultManager] fileExistsAtPath:databasePath]); const char *dbpath = [databasePath UTF8String]; int result = sqlite3_open(dbpath, &db); @@ -63,7 +71,15 @@ - (NSError *) openDatabase { const char *errorMsg = sqlite3_errmsg(db); NSString *errorStr = [NSString stringWithFormat:@"The database could not be opened: %@",[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding]]; error = [self createDBErrorWithDescription:errorStr andCode:kDBFailAtOpen]; - } + } else { + if (isNewDataBase) { + [self executeQuery:[NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id integer primary key autoincrement, version text);", kSQLiteVersionTableName]]; + [self executeQuery:[NSString stringWithFormat:@"INSERT INTO %@ (id, version) VALUES (0, '%@');", kSQLiteVersionTableName, kSQLiteVersionDefaultVersion]]; + } + if ([self.migrator sqliteManagerShouldMigrate:self]) { + [self.migrator sqliteManagerPerformMigrate:self]; + } + } return error; } @@ -90,16 +106,7 @@ - (NSError *)doQuery:(NSString *)sql { } if (openError == nil) { - sqlite3_stmt *statement; - const char *query = [sql UTF8String]; - sqlite3_prepare_v2(db, query, -1, &statement, NULL); - - if (sqlite3_step(statement) == SQLITE_ERROR) { - const char *errorMsg = sqlite3_errmsg(db); - errorQuery = [self createDBErrorWithDescription:[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding] - andCode:kDBErrorQuery]; - } - sqlite3_finalize(statement); + errorQuery = [self executeQuery:sql]; errorQuery = [self closeDatabase]; } else { @@ -109,6 +116,8 @@ - (NSError *)doQuery:(NSString *)sql { return errorQuery; } + + /** * Does an SQL parameterized query. * @@ -218,91 +227,17 @@ - (NSInteger)getLastInsertRowID { - (NSArray *)getRowsForQuery:(NSString *)sql { - NSMutableArray *resultsArray = [[NSMutableArray alloc] initWithCapacity:1]; + NSArray *resultsArray = nil; if (db == nil) { [self openDatabase]; } - - sqlite3_stmt *statement; - const char *query = [sql UTF8String]; - int returnCode = sqlite3_prepare_v2(db, query, -1, &statement, NULL); - - if (returnCode == SQLITE_ERROR) { - const char *errorMsg = sqlite3_errmsg(db); - NSError *errorQuery = [self createDBErrorWithDescription:[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding] - andCode:kDBErrorQuery]; - NSLog(@"%@", errorQuery); - } - - while (sqlite3_step(statement) == SQLITE_ROW) { - int columns = sqlite3_column_count(statement); - NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:columns]; - - for (int i = 0; i 0) { - const void *blob = sqlite3_column_blob(statement, i); - if (blob != NULL) { - [result setObject:[NSData dataWithBytes:blob length:bytes] forKey:columnName]; - } - } - break; - } - - case SQLITE_NULL: - [result setObject:[NSNull null] forKey:columnName]; - break; - - default: - { - const char *value = (const char *)sqlite3_column_text(statement, i); - [result setObject:[NSString stringWithCString:value encoding:NSUTF8StringEncoding] forKey:columnName]; - break; - } - - } //end switch - - - } //end for - - [resultsArray addObject:result]; - - } //end while - sqlite3_finalize(statement); - + + resultsArray = [self fetchRowsWithQuery:sql]; + [self closeDatabase]; return resultsArray; - } @@ -436,10 +371,33 @@ - (NSString *)getDatabaseDump { return dump; } -@end +/** + * + * get current version of database + * + * @return current version, if got any error, return nil. + */ +- (NSString *)currentVersion +{ + if (_currentVerson == nil) { + NSArray *results = [self fetchRowsWithQuery:[NSString stringWithFormat:@"SELECT version FROM %@ WHERE id = 0", kSQLiteVersionTableName]]; + if ([results count]) { + _currentVerson = results[0][@"version"]; + } else { + _currentVerson = nil; + } + } + return _currentVerson; +} + + +@end #pragma mark - + +////////////////////////////////////// Private Methods //////////////////////////////////////// + @implementation SQLiteManager (Private) /** @@ -449,17 +407,17 @@ @implementation SQLiteManager (Private) */ - (NSString *)getDatabasePath{ - - if([[NSFileManager defaultManager] fileExistsAtPath:databaseName]){ - // Already Full Path - return databaseName; - } else { + + if([[NSFileManager defaultManager] fileExistsAtPath:databaseName]){ + // Already Full Path + return databaseName; + } else { // Get the documents directory NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docsDir = [dirPaths objectAtIndex:0]; return [docsDir stringByAppendingPathComponent:databaseName]; - } + } } /** @@ -473,12 +431,134 @@ - (NSString *)getDatabasePath{ */ - (NSError *)createDBErrorWithDescription:(NSString*)description andCode:(int)code { - - NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:description, NSLocalizedDescriptionKey, nil]; - NSError *error = [NSError errorWithDomain:@"SQLite Error" code:code userInfo:userInfo]; - - return error; + + NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:description, NSLocalizedDescriptionKey, nil]; + NSError *error = [NSError errorWithDomain:@"SQLite Error" code:code userInfo:userInfo]; + + return error; +} + +/** + * Executes query after database opened. + * + * @param sqlString sql to be execute. + * + * @return the NSError just created. + */ +- (NSError *)executeQuery:(NSString *)sqlStirng +{ + NSError *errorQuery = nil; + sqlite3_stmt *statement; + const char *query = [sqlStirng UTF8String]; + sqlite3_prepare_v2(db, query, -1, &statement, NULL); + + if (sqlite3_step(statement) == SQLITE_ERROR) { + const char *errorMsg = sqlite3_errmsg(db); + errorQuery = [self createDBErrorWithDescription:[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding] + andCode:kDBErrorQuery]; + } + sqlite3_finalize(statement); + + return errorQuery; +} + +- (NSArray *)fetchRowsWithQuery:(NSString *)sqlString +{ + NSMutableArray *resultsArray = [[NSMutableArray alloc] init]; + sqlite3_stmt *statement; + const char *query = [sqlString UTF8String]; + int returnCode = sqlite3_prepare_v2(db, query, -1, &statement, NULL); + + if (returnCode == SQLITE_ERROR) { + const char *errorMsg = sqlite3_errmsg(db); + NSError *errorQuery = [self createDBErrorWithDescription:[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding] + andCode:kDBErrorQuery]; + NSLog(@"%@", errorQuery); + } + + while (sqlite3_step(statement) == SQLITE_ROW) { + int columns = sqlite3_column_count(statement); + NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:columns]; + + for (int i = 0; i 0) { + const void *blob = sqlite3_column_blob(statement, i); + if (blob != NULL) { + [result setObject:[NSData dataWithBytes:blob length:bytes] forKey:columnName]; + } + } + break; + } + + case SQLITE_NULL: + [result setObject:[NSNull null] forKey:columnName]; + break; + + default: + { + const char *value = (const char *)sqlite3_column_text(statement, i); + [result setObject:[NSString stringWithCString:value encoding:NSUTF8StringEncoding] forKey:columnName]; + break; + } + + } //end switch + + + } //end for + + [resultsArray addObject:result]; + + } //end while + sqlite3_finalize(statement); + + return resultsArray; +} + +/** + * + * modify the version column in VersionTable + * + * @param string the string of version + * + */ +- (void)modifyCurrentVersionWithVersionString:(NSString *)string +{ + _currentVerson = nil; + [self executeQuery:[NSString stringWithFormat:@"UPDATE %@ SET version = %@ WHERE id = 0;", kSQLiteVersionTableName, string]]; } @end + + + + diff --git a/SQLiteManagerExample/Classes/MyMigrater.h b/SQLiteManagerExample/Classes/MyMigrater.h new file mode 100644 index 0000000..857b281 --- /dev/null +++ b/SQLiteManagerExample/Classes/MyMigrater.h @@ -0,0 +1,15 @@ +// +// MyMigrater.h +// SQLiteManagerExample +// +// Created by casa on 15/1/20. +// +// + +#import "SQLiteMigrater.h" + +static NSString * const kIGLocalStorageTableNameSystemMessage = @"SystemMessage"; + +@interface MyMigrater : SQLiteMigrater + +@end diff --git a/SQLiteManagerExample/Classes/MyMigrater.m b/SQLiteManagerExample/Classes/MyMigrater.m new file mode 100644 index 0000000..73b6e89 --- /dev/null +++ b/SQLiteManagerExample/Classes/MyMigrater.m @@ -0,0 +1,41 @@ +// +// MyMigrater.m +// SQLiteManagerExample +// +// Created by casa on 15/1/20. +// +// + +#import "MyMigrater.h" +#import "SQLiteManager.h" + +@implementation MyMigrater + +@synthesize migrateList = _migrateList; +@synthesize versionList = _versionList; + +#pragma mark - getters and setters +- (NSDictionary *)migrateList +{ + if (_migrateList == nil) { + SQLiteManagerMigrateObject *migrate0_1 = [[SQLiteManagerMigrateObject alloc] init]; + migrate0_1.upSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);", kIGLocalStorageTableNameSystemMessage]; + migrate0_1.downSql = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@;", kIGLocalStorageTableNameSystemMessage]; + + SQLiteManagerMigrateObject *migrate0_2 = [[SQLiteManagerMigrateObject alloc] init]; + migrate0_2.upSql = [NSString stringWithFormat:@"INSERT INTO %@ (name) VALUES ('casa');", kIGLocalStorageTableNameSystemMessage]; + + _migrateList = @{@"0.1":migrate0_1, @"0.2":migrate0_2}; + } + return _migrateList; +} + +- (NSArray *)versionList +{ + if (_versionList == nil) { + _versionList = @[kSQLiteVersionDefaultVersion, @"0.1", @"0.2"]; + } + return _versionList; +} + +@end diff --git a/SQLiteManagerExample/Classes/UntitledViewController.m b/SQLiteManagerExample/Classes/UntitledViewController.m index 6cd5a18..6ec6fb9 100644 --- a/SQLiteManagerExample/Classes/UntitledViewController.m +++ b/SQLiteManagerExample/Classes/UntitledViewController.m @@ -7,6 +7,7 @@ // #import "UntitledViewController.h" +#import "MyMigrater.h" @implementation UntitledViewController @@ -68,6 +69,7 @@ - (void)viewDidLoad { [super viewDidLoad]; dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; + dbManager.migrator = [[MyMigrater alloc] init]; NSString *dump = [dbManager getDatabaseDump]; textView.text = dump; diff --git a/SQLiteManagerExample/SQLiteManagerExample.xcodeproj/project.pbxproj b/SQLiteManagerExample/SQLiteManagerExample.xcodeproj/project.pbxproj index 24ddcd7..af83460 100755 --- a/SQLiteManagerExample/SQLiteManagerExample.xcodeproj/project.pbxproj +++ b/SQLiteManagerExample/SQLiteManagerExample.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 2899E5220DE3E06400AC0155 /* UntitledViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* UntitledViewController.xib */; }; 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 28D7ACF80DDB3853001CB0EB /* UntitledViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* UntitledViewController.m */; }; + 4A528E211A6E6AC1001C101B /* SQLiteMigrater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A528E201A6E6AC1001C101B /* SQLiteMigrater.m */; }; + 4A528E241A6E7707001C101B /* MyMigrater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A528E231A6E7707001C101B /* MyMigrater.m */; }; 6818867B132943B300459EB0 /* SQLiteManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6818867A132943B300459EB0 /* SQLiteManager.m */; }; 68C7103013297178004555F8 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 68C7102F13297178004555F8 /* libsqlite3.dylib */; }; /* End PBXBuildFile section */ @@ -32,6 +34,10 @@ 28D7ACF70DDB3853001CB0EB /* UntitledViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UntitledViewController.m; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* SQLiteManagerExample_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQLiteManagerExample_Prefix.pch; sourceTree = ""; }; + 4A528E1F1A6E6AC1001C101B /* SQLiteMigrater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SQLiteMigrater.h; path = ../../SQLiteMigrater.h; sourceTree = ""; }; + 4A528E201A6E6AC1001C101B /* SQLiteMigrater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SQLiteMigrater.m; path = ../../SQLiteMigrater.m; sourceTree = ""; }; + 4A528E221A6E7707001C101B /* MyMigrater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyMigrater.h; sourceTree = ""; }; + 4A528E231A6E7707001C101B /* MyMigrater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyMigrater.m; sourceTree = ""; }; 68188679132943B300459EB0 /* SQLiteManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SQLiteManager.h; path = ../SQLiteManager.h; sourceTree = SOURCE_ROOT; }; 6818867A132943B300459EB0 /* SQLiteManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SQLiteManager.m; path = ../SQLiteManager.m; sourceTree = SOURCE_ROOT; }; 68C7102F13297178004555F8 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; @@ -58,10 +64,14 @@ children = ( 68188679132943B300459EB0 /* SQLiteManager.h */, 6818867A132943B300459EB0 /* SQLiteManager.m */, + 4A528E221A6E7707001C101B /* MyMigrater.h */, + 4A528E231A6E7707001C101B /* MyMigrater.m */, 1D3623240D0F684500981E51 /* UntitledAppDelegate.h */, 1D3623250D0F684500981E51 /* UntitledAppDelegate.m */, 28D7ACF60DDB3853001CB0EB /* UntitledViewController.h */, 28D7ACF70DDB3853001CB0EB /* UntitledViewController.m */, + 4A528E1F1A6E6AC1001C101B /* SQLiteMigrater.h */, + 4A528E201A6E6AC1001C101B /* SQLiteMigrater.m */, ); path = Classes; sourceTree = ""; @@ -141,6 +151,8 @@ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; + attributes = { + }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "SQLiteManagerExample" */; compatibilityVersion = "Xcode 3.1"; developmentRegion = English; @@ -177,7 +189,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4A528E211A6E6AC1001C101B /* SQLiteMigrater.m in Sources */, 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + 4A528E241A6E7707001C101B /* MyMigrater.m in Sources */, 1D3623260D0F684500981E51 /* UntitledAppDelegate.m in Sources */, 28D7ACF80DDB3853001CB0EB /* UntitledViewController.m in Sources */, 6818867B132943B300459EB0 /* SQLiteManager.m in Sources */, diff --git a/SQLiteMigrater.h b/SQLiteMigrater.h new file mode 100644 index 0000000..2813bce --- /dev/null +++ b/SQLiteMigrater.h @@ -0,0 +1,29 @@ +// +// SQLiteMigrater.h +// SQLiteManagerExample +// +// Created by casa on 15/1/20. +// +// + +#import + + +@class SQLiteManager; + +@interface SQLiteMigrater : NSObject + +@property (nonatomic, strong) NSDictionary *migrateList; +@property (nonatomic, strong) NSArray *versionList; + +- (BOOL)sqliteManagerShouldMigrate:(SQLiteManager *)manager; +- (void)sqliteManagerPerformMigrate:(SQLiteManager *)manager; + +@end + +@interface SQLiteManagerMigrateObject : NSObject + +@property (nonatomic, strong) NSString *upSql; +@property (nonatomic, strong) NSString *downSql; + +@end diff --git a/SQLiteMigrater.m b/SQLiteMigrater.m new file mode 100644 index 0000000..30432bd --- /dev/null +++ b/SQLiteMigrater.m @@ -0,0 +1,67 @@ +// +// SQLiteMigrater.m +// SQLiteManagerExample +// +// Created by casa on 15/1/20. +// +// + +#import "SQLiteMigrater.h" +#import "SQLiteManager.h" + +@implementation SQLiteMigrater + +- (BOOL)sqliteManagerShouldMigrate:(SQLiteManager *)manager +{ + NSString *currentVersion = manager.currentVersion; + NSUInteger index = [self.versionList indexOfObject:currentVersion]; + if (index == [self.versionList count] - 1) { + return NO; + } + return YES; +} + +- (void)sqliteManagerPerformMigrate:(SQLiteManager *)manager +{ + BOOL shouldPerformMigration = NO; + NSArray *versionList = [self versionList]; + NSDictionary *migrationObjectContainer = [self migrateList]; + for (NSString *version in versionList) { + if (shouldPerformMigration) { + SQLiteManagerMigrateObject *object = migrationObjectContainer[version]; + NSError *error = [manager performSelector:@selector(executeQuery:) withObject:object.upSql]; + if (error) { + [manager performSelector:@selector(executeQuery:) withObject:object.downSql]; + break; + } else { + [manager performSelector:@selector(modifyCurrentVersionWithVersionString:) withObject:version]; + } + } + + if ([version isEqualToString:manager.currentVersion]) { + shouldPerformMigration = YES; + } + } +} + +@end + +@implementation SQLiteManagerMigrateObject + +- (NSString *)upSql +{ + if (_upSql == nil) { + _upSql = @""; + } + return _upSql; +} + +- (NSString *)downSql +{ + if (_downSql == nil) { + _downSql = @""; + } + return _downSql; +} + +@end From 0bec404ad6104bb905ab5ea86814a8d480d5866d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=9A=E5=AE=87?= Date: Tue, 20 Jan 2015 21:28:21 +0800 Subject: [PATCH 2/3] change the readme to markdown --- README | 144 --------------------------------------------------------- 1 file changed, 144 deletions(-) delete mode 100644 README diff --git a/README b/README deleted file mode 100644 index 57648f5..0000000 --- a/README +++ /dev/null @@ -1,144 +0,0 @@ -************************* - - SQLITE MANAGER FOR IOS - -************************* - -SQLiteManager is a simple Class "wrapper" to use SQLite3 within iOS SDK. -It provides methods to: -- connect/create a database in your documents app folder -- do a simple query -- get rows in NSDictionary format -- close the connection -- dump your data in sql dump format - -For the moment that's all ;) - -SQLiteManager is made by Ester Sanchez (aka misato) and it's free to use, modify and distribute. -If you use it, don't forget to mention me as the original creator. - -Thanks and enjoy! - -********************** - - INSTALLATION & USAGE - -********************** - -Just drag the two classes into your project. Also you need to import SQLite3 framework. Go to frameworks-> add existing framework->libsql3.dylib - -To use an existing database, the full path is required: - -```objc -NSString *dbPath = [[NSBundle mainBundle] pathForResource:@"users" ofType:@"db"]; -dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:dbPath]; -``` - -The code is pretty self-explanatory so i hope you'll understand it. -If you have any doubts, don't hesitate to contact me at esanchez [at] misato [dot] es - -You have also an usage example in SQLiteManagerExample directory. - -********************** - - MIGRATION - -********************** - -If your app is version 0.1, and then you released version 0.2, and in version 0.2 you did modified the structure of database, so you have to migrate the old version database to a new version, SQLiteMigrater will help you to solve this issue :D - -here is an example: - -```objc - -////////////////////////////////////////////////// MyMigrater.h - -#import "SQLiteMigrater.h" - -static NSString * const kIGLocalStorageTableNameSystemMessage = @"SystemMessage"; // this is your table name - -@interface MyMigrater : SQLiteMigrater -@end - - -////////////////////////////////////////////////// MyMigrater.m - -#import "MyMigrater.h" -#import "SQLiteManager.h" - -@implementation MyMigrater - -@synthesize migrateList = _migrateList; -@synthesize versionList = _versionList; - -#pragma mark - getters and setters -- (NSDictionary *)migrateList -{ - if (_migrateList == nil) { - SQLiteManagerMigrateObject *migrate0_1 = [[SQLiteManagerMigrateObject alloc] init]; - migrate0_1.upSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);", kIGLocalStorageTableNameSystemMessage]; - migrate0_1.downSql = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@;", kIGLocalStorageTableNameSystemMessage]; - - SQLiteManagerMigrateObject *migrate0_2 = [[SQLiteManagerMigrateObject alloc] init]; - migrate0_2.upSql = [NSString stringWithFormat:@"INSERT INTO %@ (name) VALUES ('casa');", kIGLocalStorageTableNameSystemMessage]; - - _migrateList = @{@"0.1":migrate0_1, @"0.2":migrate0_2}; - } - return _migrateList; -} - -- (NSArray *)versionList -{ - if (_versionList == nil) { - _versionList = @[kSQLiteVersionDefaultVersion, @"0.1", @"0.2"]; - } - return _versionList; -} - -@end - -``` - -and you should set your instance of migrator after you created SQLiteManager: - -```objc - -dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; -dbManager.migrator = [[MyMigrater alloc] init]; - -``` - -********************** - - HOW TO CREATE MIGRATER - -********************** - -1. inherit SQLiteMigrater - -2. synthesize migrateList and versionList - -3. write getter for `migrateList` - - 3.1 the key is version string, and the value is instance of `SQLiteManagerMigrateObject` - - 3.2 set upSql of `SQLiteManagerMigrateObject`, upSql is the SQL to do your change of new version. - - 3.3 set downSql of `SQLiteManagerMigrateObject`, if upSql failed, migrater will run downSql to rollback. You don't have to set it - -4. write getter for `versionList` - - 4.1 the first one must be `kSQLiteVersionDefaultVersion` - - 4.2 migrator will execute `SQLiteManagerMigrateObject` in the order of this versionList - -5. make sure your `migrateList` is correct with `versionList` - -6. instanciate your migrater and set it to your SQLiteManager: -```objc -dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; -dbManager.migrator = [[MyMigrater alloc] init]; -``` - -7. done! - From 3a5695e2331dd6867d248d2292148d2ff2f5524a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=9A=E5=AE=87?= Date: Tue, 20 Jan 2015 21:28:40 +0800 Subject: [PATCH 3/3] changed readme to markdown --- README.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..57648f5 --- /dev/null +++ b/README.md @@ -0,0 +1,144 @@ +************************* + + SQLITE MANAGER FOR IOS + +************************* + +SQLiteManager is a simple Class "wrapper" to use SQLite3 within iOS SDK. +It provides methods to: +- connect/create a database in your documents app folder +- do a simple query +- get rows in NSDictionary format +- close the connection +- dump your data in sql dump format + +For the moment that's all ;) + +SQLiteManager is made by Ester Sanchez (aka misato) and it's free to use, modify and distribute. +If you use it, don't forget to mention me as the original creator. + +Thanks and enjoy! + +********************** + + INSTALLATION & USAGE + +********************** + +Just drag the two classes into your project. Also you need to import SQLite3 framework. Go to frameworks-> add existing framework->libsql3.dylib + +To use an existing database, the full path is required: + +```objc +NSString *dbPath = [[NSBundle mainBundle] pathForResource:@"users" ofType:@"db"]; +dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:dbPath]; +``` + +The code is pretty self-explanatory so i hope you'll understand it. +If you have any doubts, don't hesitate to contact me at esanchez [at] misato [dot] es + +You have also an usage example in SQLiteManagerExample directory. + +********************** + + MIGRATION + +********************** + +If your app is version 0.1, and then you released version 0.2, and in version 0.2 you did modified the structure of database, so you have to migrate the old version database to a new version, SQLiteMigrater will help you to solve this issue :D + +here is an example: + +```objc + +////////////////////////////////////////////////// MyMigrater.h + +#import "SQLiteMigrater.h" + +static NSString * const kIGLocalStorageTableNameSystemMessage = @"SystemMessage"; // this is your table name + +@interface MyMigrater : SQLiteMigrater +@end + + +////////////////////////////////////////////////// MyMigrater.m + +#import "MyMigrater.h" +#import "SQLiteManager.h" + +@implementation MyMigrater + +@synthesize migrateList = _migrateList; +@synthesize versionList = _versionList; + +#pragma mark - getters and setters +- (NSDictionary *)migrateList +{ + if (_migrateList == nil) { + SQLiteManagerMigrateObject *migrate0_1 = [[SQLiteManagerMigrateObject alloc] init]; + migrate0_1.upSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);", kIGLocalStorageTableNameSystemMessage]; + migrate0_1.downSql = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@;", kIGLocalStorageTableNameSystemMessage]; + + SQLiteManagerMigrateObject *migrate0_2 = [[SQLiteManagerMigrateObject alloc] init]; + migrate0_2.upSql = [NSString stringWithFormat:@"INSERT INTO %@ (name) VALUES ('casa');", kIGLocalStorageTableNameSystemMessage]; + + _migrateList = @{@"0.1":migrate0_1, @"0.2":migrate0_2}; + } + return _migrateList; +} + +- (NSArray *)versionList +{ + if (_versionList == nil) { + _versionList = @[kSQLiteVersionDefaultVersion, @"0.1", @"0.2"]; + } + return _versionList; +} + +@end + +``` + +and you should set your instance of migrator after you created SQLiteManager: + +```objc + +dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; +dbManager.migrator = [[MyMigrater alloc] init]; + +``` + +********************** + + HOW TO CREATE MIGRATER + +********************** + +1. inherit SQLiteMigrater + +2. synthesize migrateList and versionList + +3. write getter for `migrateList` + + 3.1 the key is version string, and the value is instance of `SQLiteManagerMigrateObject` + + 3.2 set upSql of `SQLiteManagerMigrateObject`, upSql is the SQL to do your change of new version. + + 3.3 set downSql of `SQLiteManagerMigrateObject`, if upSql failed, migrater will run downSql to rollback. You don't have to set it + +4. write getter for `versionList` + + 4.1 the first one must be `kSQLiteVersionDefaultVersion` + + 4.2 migrator will execute `SQLiteManagerMigrateObject` in the order of this versionList + +5. make sure your `migrateList` is correct with `versionList` + +6. instanciate your migrater and set it to your SQLiteManager: +```objc +dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:@"prueba.db"]; +dbManager.migrator = [[MyMigrater alloc] init]; +``` + +7. done! +