├── Pods ├── Headers │ ├── Private │ │ └── FMDB │ │ │ ├── FMDB.h │ │ │ ├── FMDatabase.h │ │ │ ├── FMResultSet.h │ │ │ ├── FMDatabasePool.h │ │ │ ├── FMDatabaseQueue.h │ │ │ └── FMDatabaseAdditions.h │ └── Public │ │ └── FMDB │ │ ├── FMDB.h │ │ ├── FMDatabase.h │ │ ├── FMResultSet.h │ │ ├── FMDatabasePool.h │ │ ├── FMDatabaseQueue.h │ │ └── FMDatabaseAdditions.h ├── Target Support Files │ └── Pods │ │ ├── Pods-dummy.m │ │ ├── Pods.debug.xcconfig │ │ ├── Pods.release.xcconfig │ │ ├── Pods-acknowledgements.markdown │ │ ├── Pods-acknowledgements.plist │ │ └── Pods-resources.sh ├── FMDB │ ├── src │ │ └── fmdb │ │ │ ├── FMDB.h │ │ │ ├── FMDatabaseAdditions.h │ │ │ ├── FMDatabaseAdditions.m │ │ │ ├── FMDatabasePool.h │ │ │ ├── FMDatabasePool.m │ │ │ ├── FMDatabaseQueue.m │ │ │ ├── FMDatabaseQueue.h │ │ │ ├── FMResultSet.h │ │ │ └── FMResultSet.m │ └── LICENSE.txt ├── Manifest.lock └── Pods.xcodeproj │ └── xcuserdata │ └── bing.xcuserdatad │ └── xcschemes │ ├── xcschememanagement.plist │ └── Pods.xcscheme ├── FMDataTable.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── bing.xcuserdatad │ └── xcschemes │ ├── xcschememanagement.plist │ └── FMDataTable.xcscheme ├── FMDataTable ├── Message.m ├── ViewController.h ├── Users.m ├── AppDelegate.h ├── main.m ├── Message.h ├── DBSet.h ├── Users.h ├── DBSet.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.xib ├── AppDelegate.m └── ViewController.m ├── FMDataTable.xcworkspace └── contents.xcworkspacedata ├── podfile ├── Podfile.lock ├── Classes ├── NSObject+runtime.h ├── FMDTObject.h ├── FMDTUpdateObjectCommand.h ├── FMDTCommand.h ├── FMDTObject.m ├── FMDTInsertCommand.h ├── FMDTManager.h ├── NSObject+runtime.m ├── FMDTSchema.h ├── FMDTContext.h ├── FMDTKeyValueStorage.h ├── FMDTDeleteCommand.h ├── FMDTUpdateCommand.h ├── FMDTManager.m ├── FMDTKeyValueStorage.m ├── FMDTSelectCommand.h ├── FMDTUpdateObjectCommand.m ├── FMDTInsertCommand.m ├── FMDTContext.m ├── FMDTDeleteCommand.m ├── FMDTUpdateCommand.m ├── FMDTSchema.m └── FMDTSelectCommand.m ├── FMDataTableTests ├── Info.plist └── FMDataTableTests.m ├── LICENSE ├── FMDBDataTable.podspec └── README.md /Pods/Headers/Private/FMDB/FMDB.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDB.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDB.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDB.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabase.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabase.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabase.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabase.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMResultSet.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMResultSet.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMResultSet.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMResultSet.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabasePool.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseQueue.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabasePool.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseQueue.h -------------------------------------------------------------------------------- /Pods/Headers/Private/FMDB/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseAdditions.h -------------------------------------------------------------------------------- /Pods/Headers/Public/FMDB/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | ../../../FMDB/src/fmdb/FMDatabaseAdditions.h -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods/Pods-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods : NSObject 3 | @end 4 | @implementation PodsDummy_Pods 5 | @end 6 | -------------------------------------------------------------------------------- /FMDataTable.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FMDataTable/Message.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Message.m 4 | // FMDataTable 5 | // 6 | // Created by bing.hao on 16/3/10. 7 | // Copyright © 2016年 bing.hao. All rights reserved. 8 | // 9 | 10 | #import "Message.h" 11 | 12 | @implementation Message 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /FMDataTable/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/8/31. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /FMDataTable.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | target 'FMDataTable' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | # use_frameworks! 7 | 8 | inhibit_all_warnings! 9 | 10 | pod 'FMDB' 11 | 12 | end 13 | -------------------------------------------------------------------------------- /FMDataTable/Users.m: -------------------------------------------------------------------------------- 1 | // 2 | // Users.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "Users.h" 10 | 11 | @implementation Users 12 | 13 | + (NSString *)primaryKeyFieldName { 14 | return @"userId,nickname"; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDB.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | FOUNDATION_EXPORT double FMDBVersionNumber; 4 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[]; 5 | 6 | #import "FMDatabase.h" 7 | #import "FMResultSet.h" 8 | #import "FMDatabaseAdditions.h" 9 | #import "FMDatabaseQueue.h" 10 | #import "FMDatabasePool.h" 11 | -------------------------------------------------------------------------------- /FMDataTable/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/8/31. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods/Pods.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/FMDB" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"FMDB" -l"sqlite3" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods/Pods.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/FMDB" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/FMDB" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"FMDB" -l"sqlite3" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.7.5): 3 | - FMDB/standard (= 2.7.5) 4 | - FMDB/standard (2.7.5) 5 | 6 | DEPENDENCIES: 7 | - FMDB 8 | 9 | SPEC REPOS: 10 | https://github.com/CocoaPods/Specs.git: 11 | - FMDB 12 | 13 | SPEC CHECKSUMS: 14 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 15 | 16 | PODFILE CHECKSUM: b01c94bd99c739c9cd7d417d5db25eb58478ece0 17 | 18 | COCOAPODS: 1.5.0.beta.1 19 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.7.5): 3 | - FMDB/standard (= 2.7.5) 4 | - FMDB/standard (2.7.5) 5 | 6 | DEPENDENCIES: 7 | - FMDB 8 | 9 | SPEC REPOS: 10 | https://github.com/CocoaPods/Specs.git: 11 | - FMDB 12 | 13 | SPEC CHECKSUMS: 14 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 15 | 16 | PODFILE CHECKSUM: b01c94bd99c739c9cd7d417d5db25eb58478ece0 17 | 18 | COCOAPODS: 1.5.0.beta.1 19 | -------------------------------------------------------------------------------- /FMDataTable/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/8/31. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FMDataTable/Message.h: -------------------------------------------------------------------------------- 1 | // 2 | // Message.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/10. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTObject.h" 10 | 11 | @interface Message : FMDTObject 12 | 13 | @property (nonatomic, strong) NSString *mid; 14 | @property (nonatomic, strong) NSString *text; 15 | @property (nonatomic, strong) NSDate *createdAt; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/NSObject+runtime.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+runtime.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/9/1. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSObject (runtime) 12 | 13 | + (void)enumeratePropertiesWithClassType:(Class)ctype usingBlick:(void(^)(BOOL read, NSString *name, NSString *type, NSArray *attrs))block; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /FMDataTable/DBSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // DBSet.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTManager.h" 10 | #import "Users.h" 11 | #import "Message.h" 12 | 13 | @interface DBSet : FMDTManager 14 | 15 | @property (nonatomic, strong, readonly) FMDTContext *user; 16 | 17 | - (FMDTContext *)dynamicTable:(NSString *)name; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /FMDataTable/Users.h: -------------------------------------------------------------------------------- 1 | // 2 | // Users.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTObject.h" 10 | 11 | @interface Users : FMDTObject 12 | 13 | @property (nonatomic, assign) NSInteger userId; 14 | @property (nonatomic, strong) NSString *nickname; 15 | @property (nonatomic, strong) NSString *sex; 16 | @property (nonatomic, strong) NSDictionary *other; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/FMDTObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTObject.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 获取UUID字符串 13 | * 14 | * @return NSString 15 | */ 16 | NSString * FMDT_UUID(); 17 | 18 | /** 19 | * 实体对像 20 | */ 21 | @interface FMDTObject : NSObject 22 | 23 | /** 24 | * 设置主键字段 25 | * 26 | * @return NSString 27 | */ 28 | + (NSString *)primaryKeyFieldName; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Classes/FMDTUpdateObjectCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTUpdateObjectCommand.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTCommand.h" 11 | 12 | @interface FMDTUpdateObjectCommand : NSObject 13 | 14 | - (FMDTUpdateObjectCommand *)add:(FMDTObject *)obj; 15 | - (FMDTUpdateObjectCommand *)addWithArray:(NSArray *)array; 16 | 17 | - (void)saveChanges; 18 | - (void)saveChangesInBackground:(void(^)())complete; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/bing.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FMDB.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-FMDataTable.xcscheme 13 | 14 | isShown 15 | 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Classes/FMDTCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTCommand.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "FMDTSchema.h" 12 | #import "FMDTObject.h" 13 | 14 | typedef void(^FMDT_CALLBACK_RESULT_OBJECT)(id result); 15 | typedef void(^FMDT_CALLBACK_RESULT_ARRAY)(NSArray *result); 16 | typedef void(^FMDT_CALLBACK_RESULT_INT)(NSInteger result); 17 | typedef void(^FMDT_CALLBACK_RESULT_NOT)(); 18 | 19 | 20 | @protocol FMDTCommand 21 | 22 | @property (nonatomic, weak, readonly) FMDTSchemaTable *schema; 23 | 24 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /FMDataTable/DBSet.m: -------------------------------------------------------------------------------- 1 | // 2 | // DBSet.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "DBSet.h" 10 | 11 | @implementation DBSet 12 | 13 | - (FMDTContext *)user { 14 | /** 15 | * 缓存FMDTContext对象,第一次创建时会自动生成表结构 16 | * 默认存储在默认会存储在沙盒下的Library/Caches/{Bundle Identifier}.db, 17 | * 如果想要对每一个用户生成一个库,可以自定义Path, 18 | * 使用[self cacheWithClass: dbPath:]方法 19 | */ 20 | return [self cacheWithClass:[Users class]]; 21 | } 22 | 23 | - (FMDTContext *)dynamicTable:(NSString *)name { 24 | 25 | /** 26 | * 设置将对象映射到不同的数据表 27 | */ 28 | return [self cacheWithClass:[Message class] tableName:name]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /FMDataTable.xcodeproj/xcuserdata/bing.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FMDataTable.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 371FF00C1B93E0DD001D59BB 16 | 17 | primary 18 | 19 | 20 | 371FF0251B93E0DE001D59BB 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Classes/FMDTObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTObject.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTObject.h" 10 | #import "NSObject+runtime.h" 11 | 12 | NSString * FMDT_UUID() { 13 | CFUUIDRef uuid_ref = CFUUIDCreate(NULL); 14 | CFStringRef uuid_string_ref = CFUUIDCreateString(NULL, uuid_ref); 15 | CFRelease(uuid_ref); 16 | NSString *uuid = [NSString stringWithString:(__bridge NSString*)uuid_string_ref]; 17 | CFRelease(uuid_string_ref); 18 | return [uuid stringByReplacingOccurrencesOfString:@"-" withString:@""]; 19 | } 20 | 21 | @implementation FMDTObject 22 | 23 | + (NSString *)primaryKeyFieldName { 24 | return nil; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /FMDataTable/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /FMDataTableTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.ks.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Classes/FMDTInsertCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTInsertCommand.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTCommand.h" 11 | 12 | @interface FMDTInsertCommand : NSObject 13 | 14 | /** 15 | * 是否使用replace语句 16 | * 注:replace语句必须指定唯一键,也就是说需要设置FMDTObject的primaryKeyFieldName类方法, 17 | * replace会根据唯一键来判断是否需要插入或者更新数据 18 | */ 19 | @property (nonatomic, assign) BOOL relpace; 20 | 21 | /** 22 | * 添加要插入的实体对象 23 | * 24 | * @param obj 实体对象 25 | * 26 | * @return 27 | */ 28 | - (FMDTInsertCommand *)add:(FMDTObject *)obj; 29 | 30 | /** 31 | * 添加一组要插入的实体对象 32 | * 33 | * @param array 一组对象 34 | * 35 | * @return 36 | */ 37 | - (FMDTInsertCommand *)addWithArray:(NSArray *)array; 38 | 39 | /** 40 | * 提交到数据库 41 | */ 42 | - (void)saveChanges; 43 | 44 | /** 45 | * 提交到数据库,后台执行 46 | * 47 | * @param complete 回调方法 48 | */ 49 | - (void)saveChangesInBackground:(void(^)())complete; 50 | 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /FMDataTableTests/FMDataTableTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDataTableTests.m 3 | // FMDataTableTests 4 | // 5 | // Created by bing.hao on 15/8/31. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface FMDataTableTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation FMDataTableTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Bing, bing.hao1982@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Classes/FMDTManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTManager.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTContext.h" 11 | 12 | /** 13 | * FMDTContext管理类 14 | */ 15 | @interface FMDTManager : NSObject 16 | 17 | + (instancetype)shared; 18 | 19 | /** 20 | * 缓存FMDTContext对象 21 | * 22 | * @param cls 继承FMDBObject的类型 23 | * 24 | * @return FMDTContext 25 | */ 26 | - (FMDTContext *)cacheWithClass:(Class)cls; 27 | 28 | /** 29 | * 缓存FMDTContext对象 30 | * 31 | * @param cls 继承FMDBObject的类型 32 | * @param dbPath 存储位置 33 | * 34 | * @return 35 | */ 36 | - (FMDTContext *)cacheWithClass:(Class)cls dbPath:(NSString *)dbPath; 37 | 38 | /** 39 | * 缓存FMDTContext对象 40 | * 41 | * @param cls 继承FMDBObject的类型 42 | * @param tableName 自定义数据库表名 43 | * 44 | * @return 45 | */ 46 | - (FMDTContext *)cacheWithClass:(Class)cls tableName:(NSString *)tableName; 47 | 48 | /** 49 | * 缓存FMDTContext对象 50 | * 51 | * @param cls 继承FMDBObject的类型 52 | * @param tableName 自定义数据库表名 53 | * @param dbPath 存储位置 54 | * 55 | * @return 56 | */ 57 | - (FMDTContext *)cacheWithClass:(Class)cls tableName:(NSString *)tableName dbPath:(NSString *)dbPath; 58 | 59 | /** 60 | * 清除缓存 61 | */ 62 | - (void)clearCache; 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Classes/NSObject+runtime.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+runtime.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/9/1. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "NSObject+runtime.h" 10 | #import 11 | 12 | @implementation NSObject (runtime) 13 | 14 | + (void)enumeratePropertiesWithClassType:(Class)ctype usingBlick:(void (^)(BOOL, NSString *, NSString *, NSArray *))block 15 | { 16 | if (ctype == NULL) { 17 | return; 18 | } 19 | if (block) { 20 | while (true) { 21 | //获得类属性的数量 22 | u_int count; 23 | objc_property_t *ps = class_copyPropertyList(ctype, &count); 24 | for (int i = 0; i < count; i++) { 25 | NSString * attr = [NSString stringWithFormat:@"%s", property_getAttributes(ps[i])]; 26 | NSString * name = [NSString stringWithUTF8String:property_getName(ps[i])]; 27 | NSArray * list = [attr componentsSeparatedByString:@","]; 28 | NSString * type = [list objectAtIndex:0]; 29 | block([list containsObject:@"R"], name, type, list); 30 | } 31 | free(ps); 32 | ctype = [ctype superclass]; 33 | if (ctype == [NSObject class]) { 34 | break; 35 | } 36 | } 37 | } 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /FMDataTable/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.ks.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 2.2.3 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 2.2.3 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Pods/FMDB/LICENSE.txt: -------------------------------------------------------------------------------- 1 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 2 | by sending an email to gus@flyingmeat.com. 3 | 4 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 5 | might consider purchasing a drink of their choosing if FMDB has been useful to 6 | you. 7 | 8 | Finally, and shortly, this is the MIT License. 9 | 10 | Copyright (c) 2008-2014 Flying Meat Inc. 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. -------------------------------------------------------------------------------- /Classes/FMDTSchema.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTSchema.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | BOOL FMDT_IsCollectionObject(NSString *type); 12 | BOOL FMDT_IsDateObject(NSString *type); 13 | BOOL FMDT_IsDataObject(NSString *type); 14 | 15 | /** 16 | * 数据表与类对象的映射关系 17 | */ 18 | @interface FMDTSchemaTable : NSObject 19 | 20 | @property (nonatomic, strong) NSString * storage; 21 | /** 22 | * @brief 类名 23 | */ 24 | @property (nonatomic, strong) NSString * className; 25 | /** 26 | * @brief 表名 27 | */ 28 | @property (nonatomic, strong) NSString * tableName; 29 | /** 30 | * @brief 字段 31 | */ 32 | @property (nonatomic, strong) NSArray * fields; 33 | 34 | - (instancetype)initWithClass:(Class)cls storage:(NSString *)storage; 35 | - (instancetype)initWithClass:(Class)cls customTableName:(NSString *)name storage:(NSString *)storage; 36 | 37 | @property (nonatomic, strong) NSString *statementUpdate; 38 | @property (nonatomic, strong) NSString *statementDelete; 39 | @property (nonatomic, strong) NSString *statementInsert; 40 | @property (nonatomic, strong) NSString *statementReplace; 41 | 42 | @end 43 | 44 | @interface FMDTSchemaField : NSObject 45 | 46 | @property (nonatomic, strong) NSString *objName; 47 | @property (nonatomic, strong) NSString *objType; 48 | @property (nonatomic, strong) NSString *name; 49 | @property (nonatomic, strong) NSString *type; 50 | @property (nonatomic, assign) BOOL primaryKey; 51 | 52 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 53 | 54 | @end -------------------------------------------------------------------------------- /Classes/FMDTContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTSet.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTSelectCommand.h" 11 | #import "FMDTInsertCommand.h" 12 | #import "FMDTUpdateCommand.h" 13 | #import "FMDTDeleteCommand.h" 14 | #import "FMDTUpdateObjectCommand.h" 15 | #import "FMDTSchema.h" 16 | #import "FMDTObject.h" 17 | 18 | #define FMDT_INSERT(ctx) [ctx createInsertCommand] 19 | #define FMDT_UPDATE(ctx) [ctx createUpdateCommand] 20 | #define FMDT_DELETE(ctx) [ctx createDeleteCommand] 21 | #define FMDT_SELECT(ctx) [ctx createSelectCommand] 22 | #define FMDT_UPDATE_OBJECT(ctx) [ctx createUpdateObjectCommand] 23 | 24 | @interface FMDTContext : NSObject 25 | 26 | @property (nonatomic, strong, readonly) FMDTSchemaTable *schema; 27 | 28 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema; 29 | 30 | /** 31 | * 创建一个查询指令对象 32 | * 33 | * @return FMDTSelectCommand 34 | */ 35 | - (FMDTSelectCommand *)createSelectCommand; 36 | 37 | /** 38 | * 创建一个条件更新指令对象 39 | * 40 | * @return FMDTUpdateCommand 41 | */ 42 | - (FMDTUpdateCommand *)createUpdateCommand; 43 | 44 | /** 45 | * 创建一个插入指令对象 46 | * 47 | * @return FMDTInsertCommand 48 | */ 49 | - (FMDTInsertCommand *)createInsertCommand; 50 | 51 | /** 52 | * 创建一个删除指令对象 53 | * 54 | * @return FMDTDeleteCommand 55 | */ 56 | - (FMDTDeleteCommand *)createDeleteCommand; 57 | 58 | /** 59 | * 创建一个更新指令对象 60 | * 61 | * @return FMDTUpdateObjectCommand 62 | */ 63 | - (FMDTUpdateObjectCommand *)createUpdateObjectCommand; 64 | 65 | 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Classes/FMDTKeyValueStorage.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTKeyValueStorage.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 2017/2/22. 6 | // Copyright © 2017年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTManager.h" 11 | 12 | #define STORE [FMDTKeyValueStorage shared] 13 | 14 | @interface FMDTKeyValueObject : FMDTObject 15 | 16 | @property (nonatomic, strong) NSString *m_key; 17 | @property (nonatomic, strong) NSDictionary *m_value; 18 | 19 | @end 20 | 21 | @interface FMDTKeyValueStorage : FMDTManager 22 | 23 | 24 | @property (nonatomic, strong, readonly) FMDTContext *kv; 25 | /** 26 | 添加键值存储 27 | 28 | @param key 关键字 29 | @param value 具体的值,可以是NSString, NSNumber, Dictionary, Array等类型 30 | */ 31 | - (void)set:(NSString *)key value:(id)value; 32 | 33 | 34 | /** 35 | 获取值 36 | 37 | @param key 关键字 38 | @return 返回值 39 | */ 40 | - (id)objectForKey:(NSString *)key; 41 | 42 | 43 | /** 44 | 获取值 45 | 46 | @param key 关键字 47 | @return 返回值 48 | */ 49 | - (NSString *)stringForKey:(NSString *)key; 50 | 51 | 52 | /** 53 | 获取值 54 | 55 | @param key 关键字 56 | @return 返回值 57 | */ 58 | - (NSNumber *)numberForKey:(NSString *)key; 59 | 60 | 61 | /** 62 | 获取值 63 | 64 | @param key 关键字 65 | @return 返回值 66 | */ 67 | - (NSDictionary *)dictionaryForKey:(NSString *)key; 68 | 69 | 70 | /** 71 | 获取值 72 | 73 | @param key 关键字 74 | @return 返回值 75 | */ 76 | - (NSArray *)arrayForKey:(NSString *)key; 77 | 78 | 79 | /** 80 | 删除 81 | 82 | @param key 关键字 83 | */ 84 | - (void)removeForKey:(NSString *)key; 85 | 86 | 87 | /** 88 | 删除所有 89 | */ 90 | - (void)removeAll; 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /FMDataTable/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods/Pods-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## FMDB 5 | 6 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 7 | by sending an email to gus@flyingmeat.com. 8 | 9 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 10 | might consider purchasing a drink of their choosing if FMDB has been useful to 11 | you. 12 | 13 | Finally, and shortly, this is the MIT License. 14 | 15 | Copyright (c) 2008-2014 Flying Meat Inc. 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in 25 | all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | Generated by CocoaPods - http://cocoapods.org 35 | -------------------------------------------------------------------------------- /Classes/FMDTDeleteCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTDeleteCommand.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTCommand.h" 11 | 12 | @interface FMDTDeleteCommand : NSObject 13 | 14 | - (FMDTDeleteCommand *)where:(NSString *)key equalTo:(id)object; 15 | - (FMDTDeleteCommand *)where:(NSString *)key notEqualTo:(id)object; 16 | - (FMDTDeleteCommand *)where:(NSString *)key lessThan:(id)object; 17 | - (FMDTDeleteCommand *)where:(NSString *)key lessThanOrEqualTo:(id)object; 18 | - (FMDTDeleteCommand *)where:(NSString *)key greaterThan:(id)object; 19 | - (FMDTDeleteCommand *)where:(NSString *)key greaterThanOrEqualTo:(id)object; 20 | - (FMDTDeleteCommand *)where:(NSString *)key containedIn:(NSArray *)array; 21 | - (FMDTDeleteCommand *)where:(NSString *)key notContainedIn:(NSArray *)array; 22 | - (FMDTDeleteCommand *)where:(NSString *)key containsString:(NSString *)string; 23 | - (FMDTDeleteCommand *)where:(NSString *)key notContainsString:(NSString *)string; 24 | 25 | - (FMDTDeleteCommand *)whereOr:(NSString *)key equalTo:(id)object; 26 | - (FMDTDeleteCommand *)whereOr:(NSString *)key notEqualTo:(id)object; 27 | - (FMDTDeleteCommand *)whereOr:(NSString *)key lessThan:(id)object; 28 | - (FMDTDeleteCommand *)whereOr:(NSString *)key lessThanOrEqualTo:(id)object; 29 | - (FMDTDeleteCommand *)whereOr:(NSString *)key greaterThan:(id)object; 30 | - (FMDTDeleteCommand *)whereOr:(NSString *)key greaterThanOrEqualTo:(id)object; 31 | - (FMDTDeleteCommand *)whereOr:(NSString *)key containedIn:(NSArray *)array; 32 | - (FMDTDeleteCommand *)whereOr:(NSString *)key notContainedIn:(NSArray *)array; 33 | - (FMDTDeleteCommand *)whereOr:(NSString *)key containsString:(NSString *)string; 34 | - (FMDTDeleteCommand *)whereOr:(NSString *)key notContainsString:(NSString *)string; 35 | 36 | - (void)saveChanges; 37 | - (void)saveChangesInBackground:(void(^)())callback; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /FMDataTable/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/8/31. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Classes/FMDTUpdateCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTUpdateCommand.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTCommand.h" 11 | 12 | @interface FMDTUpdateCommand : NSObject 13 | 14 | - (FMDTUpdateCommand *)where:(NSString *)key equalTo:(id)object; 15 | - (FMDTUpdateCommand *)where:(NSString *)key notEqualTo:(id)object; 16 | - (FMDTUpdateCommand *)where:(NSString *)key lessThan:(id)object; 17 | - (FMDTUpdateCommand *)where:(NSString *)key lessThanOrEqualTo:(id)object; 18 | - (FMDTUpdateCommand *)where:(NSString *)key greaterThan:(id)object; 19 | - (FMDTUpdateCommand *)where:(NSString *)key greaterThanOrEqualTo:(id)object; 20 | - (FMDTUpdateCommand *)where:(NSString *)key containedIn:(NSArray *)array; 21 | - (FMDTUpdateCommand *)where:(NSString *)key notContainedIn:(NSArray *)array; 22 | - (FMDTUpdateCommand *)where:(NSString *)key containsString:(NSString *)string; 23 | - (FMDTUpdateCommand *)where:(NSString *)key notContainsString:(NSString *)string; 24 | 25 | - (FMDTUpdateCommand *)whereOr:(NSString *)key equalTo:(id)object; 26 | - (FMDTUpdateCommand *)whereOr:(NSString *)key notEqualTo:(id)object; 27 | - (FMDTUpdateCommand *)whereOr:(NSString *)key lessThan:(id)object; 28 | - (FMDTUpdateCommand *)whereOr:(NSString *)key lessThanOrEqualTo:(id)object; 29 | - (FMDTUpdateCommand *)whereOr:(NSString *)key greaterThan:(id)object; 30 | - (FMDTUpdateCommand *)whereOr:(NSString *)key greaterThanOrEqualTo:(id)object; 31 | - (FMDTUpdateCommand *)whereOr:(NSString *)key containedIn:(NSArray *)array; 32 | - (FMDTUpdateCommand *)whereOr:(NSString *)key notContainedIn:(NSArray *)array; 33 | - (FMDTUpdateCommand *)whereOr:(NSString *)key containsString:(NSString *)string; 34 | - (FMDTUpdateCommand *)whereOr:(NSString *)key notContainsString:(NSString *)string; 35 | 36 | /** 37 | * 要更新的字段 38 | * 39 | * @param key 数据库对应的字段名 40 | * @param val 具体值 41 | * 42 | * @return 43 | */ 44 | - (FMDTUpdateCommand *)fieldWithKey:(NSString *)key val:(id)val; 45 | 46 | /** 47 | * 提交到数据库 48 | */ 49 | - (void)saveChanges; 50 | 51 | /** 52 | * 提交到数据库,后台执行 53 | * 54 | * @param callback 回调方法 55 | */ 56 | - (void)saveChangesInBackground:(void(^)())callback; 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/bing.xcuserdatad/xcschemes/Pods.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Classes/FMDTManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTManager.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTManager.h" 10 | 11 | #define FMDT_DEF_PATH [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] 12 | #define FMDT_IDENTIFIER [[NSBundle mainBundle].infoDictionary objectForKey:@"CFBundleIdentifier"] 13 | 14 | @interface FMDTManager () 15 | { 16 | NSObject *_lock; 17 | } 18 | 19 | @property (nonatomic, strong) NSMutableDictionary *cache; 20 | 21 | @end 22 | 23 | @implementation FMDTManager 24 | 25 | + (instancetype)shared { 26 | static id _staticObject = nil; 27 | static dispatch_once_t onceToken; 28 | dispatch_once(&onceToken, ^{ 29 | _staticObject = [self new]; 30 | }); 31 | return _staticObject; 32 | } 33 | 34 | - (instancetype)init 35 | { 36 | self = [super init]; 37 | if (self) { 38 | _cache = [NSMutableDictionary new]; 39 | _lock = [NSObject new]; 40 | } 41 | return self; 42 | } 43 | 44 | - (FMDTContext *)cacheWithClass:(Class)cls { 45 | return [self cacheWithClass:cls tableName:nil dbPath:nil]; 46 | } 47 | 48 | - (FMDTContext *)cacheWithClass:(Class)cls dbPath:(NSString *)dbPath { 49 | return [self cacheWithClass:cls tableName:nil dbPath:dbPath]; 50 | } 51 | 52 | - (FMDTContext *)cacheWithClass:(Class)cls tableName:(NSString *)tableName { 53 | return [self cacheWithClass:cls tableName:tableName dbPath:nil]; 54 | } 55 | 56 | - (FMDTContext *)cacheWithClass:(Class)cls tableName:(NSString *)tableName dbPath:(NSString *)dbPath { 57 | 58 | if (tableName == nil) { 59 | tableName = NSStringFromClass(cls); 60 | } 61 | if (![self.cache.allKeys containsObject:tableName]) { 62 | @synchronized(_lock) { 63 | if (![self.cache.allKeys containsObject:tableName]) { 64 | if (dbPath == nil) { 65 | dbPath = [NSString stringWithFormat:@"%@/%@.db", FMDT_DEF_PATH, FMDT_IDENTIFIER]; 66 | } 67 | FMDTSchemaTable *schema = [[FMDTSchemaTable alloc] initWithClass:cls customTableName:tableName storage:dbPath]; 68 | FMDTContext *set = [[FMDTContext alloc] initWithSchema:schema]; 69 | 70 | [self.cache setObject:set forKey:tableName]; 71 | } 72 | } 73 | } 74 | return [self.cache objectForKey:tableName]; 75 | } 76 | 77 | - (void)clearCache { 78 | [self.cache removeAllObjects]; 79 | } 80 | 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods/Pods-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 18 | by sending an email to gus@flyingmeat.com. 19 | 20 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 21 | might consider purchasing a drink of their choosing if FMDB has been useful to 22 | you. 23 | 24 | Finally, and shortly, this is the MIT License. 25 | 26 | Copyright (c) 2008-2014 Flying Meat Inc. 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in 36 | all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 44 | THE SOFTWARE. 45 | Title 46 | FMDB 47 | Type 48 | PSGroupSpecifier 49 | 50 | 51 | FooterText 52 | Generated by CocoaPods - http://cocoapods.org 53 | Title 54 | 55 | Type 56 | PSGroupSpecifier 57 | 58 | 59 | StringsTable 60 | Acknowledgements 61 | Title 62 | Acknowledgements 63 | 64 | 65 | -------------------------------------------------------------------------------- /Classes/FMDTKeyValueStorage.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTKeyValueStorage.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 2017/2/22. 6 | // Copyright © 2017年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTKeyValueStorage.h" 10 | #import "FMDTObject.h" 11 | 12 | @implementation FMDTKeyValueObject 13 | 14 | + (NSString *)primaryKeyFieldName { 15 | return @"m_key"; 16 | } 17 | 18 | @end 19 | 20 | @interface FMDTKeyValueStorage () 21 | 22 | @property (nonatomic, strong) FMDTContext *kv; 23 | 24 | @end 25 | 26 | @implementation FMDTKeyValueStorage 27 | 28 | + (instancetype)shared { 29 | static id _staticObject = nil; 30 | static dispatch_once_t onceToken; 31 | dispatch_once(&onceToken, ^{ 32 | _staticObject = [self new]; 33 | }); 34 | return _staticObject; 35 | } 36 | 37 | - (FMDTContext *)kv { 38 | NSString *path = [NSString stringWithFormat:@"%@/kv.db", [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]]; 39 | return [self cacheWithClass:[FMDTKeyValueObject class] dbPath:path]; 40 | } 41 | 42 | - (void)set:(NSString *)key value:(id)value { 43 | if (key == nil || value == nil) { 44 | return; 45 | } 46 | FMDTKeyValueObject *obj = [[FMDTKeyValueObject alloc] init]; 47 | obj.m_key = key; 48 | obj.m_value = @{ @"value": value }; 49 | FMDTInsertCommand *cmd = [self.kv createInsertCommand]; 50 | [cmd add:obj]; 51 | [cmd setRelpace:YES]; 52 | [cmd saveChanges]; 53 | } 54 | 55 | - (id)objectForKey:(NSString *)key { 56 | 57 | if (key == nil) { 58 | return nil; 59 | } 60 | 61 | FMDTSelectCommand *cmd = [self.kv createSelectCommand]; 62 | [cmd where:@"m_key" equalTo:key]; 63 | FMDTKeyValueObject *obj = [cmd fetchObject]; 64 | if (obj) { 65 | return [obj.m_value objectForKey:@"value"]; 66 | } 67 | return nil; 68 | } 69 | 70 | - (NSString *)stringForKey:(NSString *)key { 71 | return [self objectForKey:key]; 72 | } 73 | 74 | - (NSNumber *)numberForKey:(NSString *)key { 75 | return [self objectForKey:key]; 76 | } 77 | 78 | - (NSDictionary *)dictionaryForKey:(NSString *)key { 79 | return [self objectForKey:key]; 80 | }; 81 | 82 | - (NSArray *)arrayForKey:(NSString *)key { 83 | return [self objectForKey:key]; 84 | } 85 | 86 | - (void)removeForKey:(NSString *)key { 87 | 88 | if (key == nil) { 89 | return; 90 | } 91 | FMDTDeleteCommand *cmd = [self.kv createDeleteCommand]; 92 | [cmd where:@"m_key" equalTo:key]; 93 | [cmd saveChanges]; 94 | } 95 | 96 | - (void)removeAll { 97 | FMDTDeleteCommand *cmd = [self.kv createDeleteCommand]; 98 | [cmd saveChanges]; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /FMDataTable/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Classes/FMDTSelectCommand.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTQuery.h 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDTCommand.h" 11 | 12 | #define FMDT_SELECT_MAX(field) max(field) as field 13 | #define FMDT_SELECT_MIN(field) min(field) as field 14 | #define FMDT_SELECT_SUM(field) sum(field) as field 15 | #define FMDT_SELECT_AVG(field) avg(field) as field 16 | 17 | @interface FMDTSelectCommand : NSObject 18 | 19 | @property (nonatomic, assign) NSInteger limit; 20 | @property (nonatomic, assign) NSInteger skip; 21 | 22 | - (FMDTSelectCommand *)where:(NSString *)key equalTo:(id)object; 23 | - (FMDTSelectCommand *)where:(NSString *)key notEqualTo:(id)object; 24 | - (FMDTSelectCommand *)where:(NSString *)key lessThan:(id)object; 25 | - (FMDTSelectCommand *)where:(NSString *)key lessThanOrEqualTo:(id)object; 26 | - (FMDTSelectCommand *)where:(NSString *)key greaterThan:(id)object; 27 | - (FMDTSelectCommand *)where:(NSString *)key greaterThanOrEqualTo:(id)object; 28 | - (FMDTSelectCommand *)where:(NSString *)key containedIn:(NSArray *)array; 29 | - (FMDTSelectCommand *)where:(NSString *)key notContainedIn:(NSArray *)array; 30 | - (FMDTSelectCommand *)where:(NSString *)key containsString:(NSString *)string; 31 | - (FMDTSelectCommand *)where:(NSString *)key notContainsString:(NSString *)string; 32 | - (FMDTSelectCommand *)whereIsNull:(NSString *)key; 33 | - (FMDTSelectCommand *)whereIsNotNull:(NSString *)key; 34 | 35 | - (FMDTSelectCommand *)whereOr:(NSString *)key equalTo:(id)object; 36 | - (FMDTSelectCommand *)whereOr:(NSString *)key notEqualTo:(id)object; 37 | - (FMDTSelectCommand *)whereOr:(NSString *)key lessThan:(id)object; 38 | - (FMDTSelectCommand *)whereOr:(NSString *)key lessThanOrEqualTo:(id)object; 39 | - (FMDTSelectCommand *)whereOr:(NSString *)key greaterThan:(id)object; 40 | - (FMDTSelectCommand *)whereOr:(NSString *)key greaterThanOrEqualTo:(id)object; 41 | - (FMDTSelectCommand *)whereOr:(NSString *)key containedIn:(NSArray *)array; 42 | - (FMDTSelectCommand *)whereOr:(NSString *)key notContainedIn:(NSArray *)array; 43 | - (FMDTSelectCommand *)whereOr:(NSString *)key containsString:(NSString *)string; 44 | - (FMDTSelectCommand *)whereOr:(NSString *)key notContainsString:(NSString *)string; 45 | - (FMDTSelectCommand *)whereOrIsNull:(NSString *)key; 46 | - (FMDTSelectCommand *)whereOrIsNotNull:(NSString *)key; 47 | 48 | - (FMDTSelectCommand *)orderByDescending:(NSString *)key; 49 | - (FMDTSelectCommand *)orderByAscending:(NSString *)key; 50 | 51 | - (FMDTSelectCommand *)groupBy:(NSString *)key; 52 | 53 | /** 54 | * 执行查询 55 | * 56 | * @return NSArray 57 | */ 58 | - (NSArray *)fetchArray; 59 | 60 | /** 61 | * 异步执行查询 62 | * 63 | * @param callback 回调方法 64 | */ 65 | - (void)fetchArrayInBackground:(FMDT_CALLBACK_RESULT_ARRAY)callback; 66 | 67 | /** 68 | * 执行查询 69 | * 70 | * @return 返回单一对象 71 | */ 72 | - (id)fetchObject; 73 | 74 | /** 75 | * 异步执行查询 76 | * 77 | * @param callback 回调方法 78 | */ 79 | - (void)fetchObjectInBackground:(FMDT_CALLBACK_RESULT_OBJECT)callback; 80 | 81 | 82 | /** 83 | * 执行查询 84 | * 85 | * @return 返回记录总数 86 | */ 87 | - (NSInteger)fetchCount; 88 | 89 | /** 90 | * 异步执行查询 91 | * 92 | * @param callback 回调方法 93 | */ 94 | - (void)fetchCountInBackground:(FMDT_CALLBACK_RESULT_INT)callback; 95 | 96 | /** 97 | * 执行查询,自定义返回字段 98 | * 99 | * @param fields 返回字段 100 | * 101 | * @return NSArray 102 | */ 103 | - (NSArray *)fetchArrayWithFields:(NSArray *)fields; 104 | 105 | /** 106 | * 执行查询,自定义返回字段 107 | * 108 | * @param fields 返回字段 109 | * @param callback 回调方法 110 | */ 111 | - (void)fetchArrayInBackgroundWithFields:(NSArray *)fields callback:(FMDT_CALLBACK_RESULT_ARRAY)callback; 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /Classes/FMDTUpdateObjectCommand.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTUpdateObjectCommand.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/9. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTUpdateObjectCommand.h" 10 | 11 | @interface FMDTUpdateObjectCommand () 12 | 13 | @property (nonatomic, strong) NSMutableArray *dataArray; 14 | 15 | @end 16 | 17 | @implementation FMDTUpdateObjectCommand 18 | @synthesize schema = _schema; 19 | 20 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema { 21 | self = [super init]; 22 | if (self) { 23 | _schema = schema; 24 | _dataArray = [NSMutableArray new]; 25 | } 26 | return self; 27 | } 28 | 29 | - (FMDTUpdateObjectCommand *)add:(FMDTObject *)obj { 30 | [self.dataArray addObject:obj]; 31 | return self; 32 | } 33 | 34 | - (FMDTUpdateObjectCommand *)addWithArray:(NSArray *)array { 35 | [self.dataArray addObjectsFromArray:array]; 36 | return self; 37 | } 38 | 39 | - (void)saveChanges { 40 | 41 | if (self.dataArray.count == 0) { 42 | NSLog(@"没有发现要更新的数据."); 43 | return; 44 | } 45 | 46 | FMDatabase *db = [FMDatabase databaseWithPath:self.schema.storage]; 47 | 48 | [db open]; 49 | for (FMDTObject *entry in self.dataArray) { 50 | [db executeUpdate:self.schema.statementUpdate withParameterDictionary:[self getUpdateData:entry]]; 51 | } 52 | [db close]; 53 | 54 | [self.dataArray removeAllObjects]; 55 | } 56 | 57 | - (void)saveChangesInBackground:(void (^)())complete { 58 | 59 | if (self.dataArray.count == 0) { 60 | NSLog(@"没有发现要更新的数据."); 61 | return; 62 | } 63 | 64 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 65 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 66 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 67 | @try { 68 | for (FMDTObject *entry in self.dataArray) { 69 | [db executeUpdate:self.schema.statementUpdate withParameterDictionary:[self getUpdateData:entry]]; 70 | } 71 | } 72 | @catch (NSException *exception) { 73 | *rollback = YES; 74 | } 75 | 76 | [self.dataArray removeAllObjects]; 77 | 78 | if (complete) { 79 | complete(); 80 | } 81 | }]; 82 | }); 83 | } 84 | 85 | - (NSDictionary *)getUpdateData:(FMDTObject *)obj { 86 | NSMutableDictionary *result = [NSMutableDictionary new]; 87 | for (FMDTSchemaField *entry in self.schema.fields) { 88 | id val = [obj valueForKey:entry.objName]; 89 | if (val) { 90 | if (FMDT_IsCollectionObject(entry.objType)) { 91 | NSData *data = [NSJSONSerialization dataWithJSONObject:val 92 | options:NSJSONWritingPrettyPrinted 93 | error:nil]; 94 | if (data) { 95 | NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 96 | [result setObject:str forKey:entry.name]; 97 | } else { 98 | [result setObject:[NSNull null] forKey:entry.name]; 99 | } 100 | } else if (FMDT_IsDateObject(entry.objType)) { 101 | [result setObject:@([val timeIntervalSince1970]) forKey:entry.name]; 102 | } else { 103 | [result setObject:val forKey:entry.name]; 104 | } 105 | } else { 106 | [result setObject:[NSNull null] forKey:entry.name]; 107 | } 108 | } 109 | return result; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Classes/FMDTInsertCommand.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTInsertCommand.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTInsertCommand.h" 10 | 11 | @interface FMDTInsertCommand () 12 | 13 | @property (nonatomic, strong) NSMutableArray *dataArray; 14 | 15 | @end 16 | 17 | @implementation FMDTInsertCommand 18 | @synthesize schema = _schema; 19 | 20 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema { 21 | self = [super init]; 22 | if (self) { 23 | _schema = schema; 24 | _dataArray = [NSMutableArray new]; 25 | } 26 | return self; 27 | } 28 | 29 | - (FMDTInsertCommand *)add:(FMDTObject *)obj { 30 | [self.dataArray addObject:obj]; 31 | return self; 32 | } 33 | 34 | - (FMDTInsertCommand *)addWithArray:(NSArray *)array { 35 | [self.dataArray addObjectsFromArray:array]; 36 | return self; 37 | } 38 | 39 | - (void)saveChanges { 40 | 41 | FMDatabase *db = [FMDatabase databaseWithPath:self.schema.storage]; 42 | 43 | [db open]; 44 | for (FMDTObject *entry in self.dataArray) { 45 | NSArray *array = [self getObjectValues:entry]; 46 | NSString *statement = nil; 47 | if (self.relpace) { 48 | statement = self.schema.statementReplace; 49 | } else { 50 | statement = self.schema.statementInsert; 51 | } 52 | [db executeUpdate:statement withArgumentsInArray:array]; 53 | } 54 | [db close]; 55 | [self.dataArray removeAllObjects]; 56 | } 57 | 58 | - (void)saveChangesInBackground:(void (^)())complete { 59 | 60 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 61 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 62 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 63 | @try { 64 | for (FMDTObject *entry in self.dataArray) { 65 | NSArray *array = [self getObjectValues:entry]; 66 | NSString *statement = nil; 67 | if (self.relpace) { 68 | statement = self.schema.statementReplace; 69 | } else { 70 | statement = self.schema.statementInsert; 71 | } 72 | [db executeUpdate:statement withArgumentsInArray:array]; 73 | } 74 | } 75 | @catch (NSException *exception) { 76 | *rollback = YES; 77 | } 78 | 79 | [self.dataArray removeAllObjects]; 80 | 81 | if (complete) { 82 | complete(); 83 | } 84 | }]; 85 | }); 86 | 87 | } 88 | 89 | - (NSArray *)getObjectValues:(FMDTObject *)obj { 90 | NSMutableArray *result = [NSMutableArray new]; 91 | for (FMDTSchemaField *entry in self.schema.fields) { 92 | id val = [obj valueForKey:entry.objName]; 93 | if (val) { 94 | if (FMDT_IsCollectionObject(entry.objType)) { 95 | NSData *data = [NSJSONSerialization dataWithJSONObject:val 96 | options:NSJSONWritingPrettyPrinted 97 | error:nil]; 98 | if (data) { 99 | NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 100 | [result addObject:str]; 101 | } else { 102 | [result addObject:[NSNull null]]; 103 | } 104 | } else if (FMDT_IsDateObject(entry.objType)) { 105 | [result addObject:@([val timeIntervalSince1970])]; 106 | } else { 107 | [result addObject:val]; 108 | } 109 | } else { 110 | [result addObject:[NSNull null]]; 111 | } 112 | } 113 | return result; 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /Classes/FMDTContext.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTSet.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTContext.h" 10 | 11 | @implementation FMDTContext 12 | 13 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema { 14 | self = [super init]; 15 | if (self) { 16 | _schema = schema; 17 | [self autoCreateTable]; 18 | } 19 | return self; 20 | } 21 | 22 | - (FMDTSelectCommand *)createSelectCommand { 23 | return [[FMDTSelectCommand alloc] initWithSchema:self.schema]; 24 | } 25 | 26 | - (FMDTUpdateCommand *)createUpdateCommand { 27 | return [[FMDTUpdateCommand alloc] initWithSchema:self.schema]; 28 | } 29 | 30 | - (FMDTInsertCommand *)createInsertCommand { 31 | return [[FMDTInsertCommand alloc] initWithSchema:self.schema]; 32 | } 33 | 34 | - (FMDTDeleteCommand *)createDeleteCommand { 35 | return [[FMDTDeleteCommand alloc] initWithSchema:self.schema]; 36 | } 37 | 38 | - (FMDTUpdateObjectCommand *)createUpdateObjectCommand { 39 | return [[FMDTUpdateObjectCommand alloc] initWithSchema:self.schema]; 40 | } 41 | 42 | - (void)autoCreateTable { 43 | //获取表结构 44 | NSString *ts = [NSString stringWithFormat:@"select * from sqlite_master where type='table' and name='%@'", _schema.tableName]; 45 | FMDatabase *db = [FMDatabase databaseWithPath:_schema.storage]; 46 | [db open]; 47 | FMResultSet *set = [db executeQuery:ts]; 48 | //如果为YES,说明数据库已经有表了,那么我们需要判断是否要对字段更新 49 | if ([set next]) { 50 | NSString *text = [self getAlterTableSql:_schema dbts:[set stringForColumn:@"sql"]]; 51 | @try { 52 | if (text.length > 0) { 53 | [db executeStatements:text]; 54 | } 55 | } 56 | @catch (NSException *exception) { 57 | NSLog(@"数据更新错误:更新字段冲突."); 58 | } 59 | @finally { 60 | [db close]; 61 | } 62 | } else { 63 | NSString * text = [self getCrateSql:_schema]; 64 | if (text) { 65 | [db executeUpdate:text]; 66 | } 67 | [db close]; 68 | } 69 | } 70 | 71 | - (NSString *)getCrateSql:(FMDTSchemaTable *)dts 72 | { 73 | if (dts.fields.count == 0) { 74 | return nil; 75 | } 76 | 77 | NSMutableString *text = [NSMutableString stringWithFormat:@"create table if not exists [%@] (", dts.tableName]; 78 | Class cls = NSClassFromString(dts.className); 79 | NSString *pk = [(id)cls performSelector:@selector(primaryKeyFieldName) withObject:nil]; 80 | 81 | if (pk == nil) { 82 | for (FMDTSchemaField *entry in dts.fields) { 83 | [text appendFormat:@"[%@] %@,", entry.name, entry.type]; 84 | } 85 | } else { 86 | NSArray *pks = [pk componentsSeparatedByString:@","]; 87 | 88 | if (pks.count == 1) { 89 | for (FMDTSchemaField *entry in dts.fields) { 90 | if ([entry.objName isEqualToString:pk]) { 91 | [text appendFormat:@"[%@] %@ PRIMARY KEY,", entry.name, entry.type]; 92 | } else { 93 | [text appendFormat:@"[%@] %@,", entry.name, entry.type]; 94 | } 95 | } 96 | } else { 97 | for (FMDTSchemaField *entry in dts.fields) { 98 | [text appendFormat:@"[%@] %@,", entry.name, entry.type]; 99 | } 100 | [text appendFormat:@"PRIMARY KEY(%@),", pk]; 101 | } 102 | } 103 | 104 | [text deleteCharactersInRange:NSMakeRange(text.length - 1, 1)]; 105 | [text appendString:@")"]; 106 | return text; 107 | } 108 | 109 | - (NSString *)getAlterTableSql:(FMDTSchemaTable *)ldts dbts:(NSString *)dbts 110 | { 111 | NSMutableString *text = [[NSMutableString alloc] init]; 112 | NSRange s = [dbts rangeOfString:@"("]; 113 | NSRange e = [dbts rangeOfString:@")"]; 114 | NSString * findStr = [dbts substringWithRange:NSMakeRange(s.location, e.location - s.location)]; 115 | for (FMDTSchemaField *entry in ldts.fields) { 116 | // if (![findStr containsString:entry.name]) { 117 | if (!([findStr rangeOfString:[NSString stringWithFormat:@"`%@`", entry.name]].length > 0 || 118 | [findStr rangeOfString:[NSString stringWithFormat:@"[%@]", entry.name]].length > 0)) { 119 | [text appendFormat:@"alter table [%@] add column [%@] %@;", ldts.tableName, entry.name, entry.type]; 120 | } 121 | } 122 | return text; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /FMDataTable.xcodeproj/xcuserdata/bing.xcuserdatad/xcschemes/FMDataTable.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods/Pods-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | realpath() { 12 | DIRECTORY="$(cd "${1%/*}" && pwd)" 13 | FILENAME="${1##*/}" 14 | echo "$DIRECTORY/$FILENAME" 15 | } 16 | 17 | install_resource() 18 | { 19 | case $1 in 20 | *.storyboard) 21 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 22 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 23 | ;; 24 | *.xib) 25 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 26 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 27 | ;; 28 | *.framework) 29 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 30 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 31 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 32 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 33 | ;; 34 | *.xcdatamodel) 35 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" 36 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" 37 | ;; 38 | *.xcdatamodeld) 39 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" 40 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" 41 | ;; 42 | *.xcmappingmodel) 43 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" 44 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" 45 | ;; 46 | *.xcassets) 47 | ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") 48 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 49 | ;; 50 | /*) 51 | echo "$1" 52 | echo "$1" >> "$RESOURCES_TO_COPY" 53 | ;; 54 | *) 55 | echo "${PODS_ROOT}/$1" 56 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" 57 | ;; 58 | esac 59 | } 60 | 61 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 62 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 63 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 64 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 65 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 66 | fi 67 | rm -f "$RESOURCES_TO_COPY" 68 | 69 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 70 | then 71 | case "${TARGETED_DEVICE_FAMILY}" in 72 | 1,2) 73 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 74 | ;; 75 | 1) 76 | TARGET_DEVICE_ARGS="--target-device iphone" 77 | ;; 78 | 2) 79 | TARGET_DEVICE_ARGS="--target-device ipad" 80 | ;; 81 | *) 82 | TARGET_DEVICE_ARGS="--target-device mac" 83 | ;; 84 | esac 85 | 86 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 87 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 88 | while read line; do 89 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then 90 | XCASSET_FILES+=("$line") 91 | fi 92 | done <<<"$OTHER_XCASSETS" 93 | 94 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 95 | fi 96 | -------------------------------------------------------------------------------- /FMDBDataTable.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint FMDBDataTable.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "FMDBDataTable" 19 | s.version = "2.2.4" 20 | s.summary = "基于FMDB的一个ORM解决方案" 21 | 22 | s.description = <<-DESC 23 | A longer description of FMDBDataTable in Markdown format. 24 | 25 | * Think: Why did you write this? What is the focus? What does it do? 26 | * CocoaPods will be using this to generate tags, and improve search results. 27 | * Try to keep it short, snappy and to the point. 28 | * Finally, don't worry about the indent, CocoaPods strips it! 29 | DESC 30 | 31 | s.homepage = "https://github.com/bing6/FMDBDataTable" 32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 33 | 34 | 35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 36 | # 37 | # Licensing your code is important. See http://choosealicense.com for more info. 38 | # CocoaPods will detect a license file if there is a named LICENSE* 39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 40 | # 41 | 42 | s.license = "MIT (MIT)" 43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 44 | 45 | 46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 47 | # 48 | # Specify the authors of the library, with email addresses. Email addresses 49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 50 | # accepts just a name if you'd rather not provide an email address. 51 | # 52 | # Specify a social_media_url where others can refer to, for example a twitter 53 | # profile URL. 54 | # 55 | 56 | s.author = { "Howard" => "bing.hao1982@gmail.com" } 57 | # Or just: s.author = "Howard" 58 | # s.authors = { "Howard" => "bing.hao1982@gmail.com" } 59 | # s.social_media_url = "http://twitter.com/Howard" 60 | 61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 62 | # 63 | # If this Pod runs only on iOS or OS X, then specify the platform and 64 | # the deployment target. You can optionally include the target after the platform. 65 | # 66 | 67 | # s.platform = :ios 68 | s.platform = :ios, "7.0" 69 | 70 | # When using multiple platforms 71 | s.ios.deployment_target = "7.0" 72 | # s.osx.deployment_target = "10.7" 73 | 74 | 75 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 76 | # 77 | # Specify the location from where the source should be retrieved. 78 | # Supports git, hg, bzr, svn and HTTP. 79 | # 80 | 81 | s.source = { :git => "https://github.com/bing6/FMDBDataTable.git", :tag => "2.2.3" } 82 | 83 | 84 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 85 | # 86 | # CocoaPods is smart about how it includes source code. For source files 87 | # giving a folder will include any swift, h, m, mm, c & cpp files. 88 | # For header files it will include any header in the folder. 89 | # Not including the public_header_files will make all headers public. 90 | # 91 | 92 | s.source_files = "Classes", "Classes/*.{h,m}" 93 | s.exclude_files = "Classes/Exclude" 94 | 95 | # s.public_header_files = "Classes/*.h" 96 | 97 | 98 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 99 | # 100 | # A list of resources included with the Pod. These are copied into the 101 | # target bundle with a build phase script. Anything else will be cleaned. 102 | # You can preserve files from being cleaned, please don't preserve 103 | # non-essential files like tests, examples and documentation. 104 | # 105 | 106 | # s.resource = "icon.png" 107 | # s.resources = "Resources/*.png" 108 | 109 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 110 | 111 | 112 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 113 | # 114 | # Link your library with frameworks, or libraries. Libraries do not include 115 | # the lib prefix of their name. 116 | # 117 | 118 | # s.framework = "SomeFramework" 119 | # s.frameworks = "SomeFramework", "AnotherFramework" 120 | 121 | # s.library = "iconv" 122 | # s.libraries = "iconv", "xml2" 123 | 124 | 125 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 126 | # 127 | # If your library depends on compiler flags you can set them in the xcconfig hash 128 | # where they will only apply to your library. If you depend on other Podspecs 129 | # you can include multiple dependencies to ensure it works. 130 | 131 | # s.requires_arc = true 132 | 133 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 134 | s.dependency "FMDB", "~> 2.5" 135 | 136 | end 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FMDBDataTable 2 | 3 | 这是一个简易的ORM工具,只需要几步就可以完成对单表的CRUD操作. 4 | 5 | 6 | # 建立模型 7 | 8 | @interface Users : FMDTObject 9 | 10 | @property (nonatomic, assign) NSInteger userId; 11 | @property (nonatomic, strong) NSString *nickname; 12 | @property (nonatomic, strong) NSString *sex; 13 | @property (nonatomic, strong) NSDictionary *other; 14 | 15 | @end 16 | 17 | @interface Message : FMDTObject 18 | 19 | @property (nonatomic, strong) NSString *mid; 20 | @property (nonatomic, strong) NSString *text; 21 | @property (nonatomic, strong) NSDate *createdAt; 22 | 23 | @end 24 | 25 | 26 | # 设置FMDTContext管理类 27 | 28 | @interface DBSet : FMDTManager 29 | 30 | @property (nonatomic, strong, readonly) FMDTContext *user; 31 | 32 | - (FMDTContext *)dynamicTable:(NSString *)name; 33 | 34 | @end 35 | 36 | 37 | @implementation DBSet 38 | 39 | - (FMDTContext *)user { 40 | /** 41 | * 缓存FMDTContext对象,第一次创建时会自动生成表结构 42 | * 默认存储在默认会存储在沙盒下的Library/Caches/{Bundle Identifier}.db, 43 | * 如果想要对每一个用户生成一个库,可以自定义Path, 44 | * 使用[self cacheWithClass: dbPath:]方法 45 | */ 46 | return [self cacheWithClass:[Users class]]; 47 | } 48 | 49 | - (FMDTContext *)dynamicTable:(NSString *)name { 50 | 51 | /** 52 | * 设置将对象映射到不同的数据表 53 | */ 54 | return [self cacheWithClass:[Message class] tableName:name]; 55 | } 56 | 57 | @end 58 | 59 | #添加数据 60 | 61 | //创建插入对象 62 | FMDTInsertCommand *icmd = [[DBSet shared].user createInsertCommand]; 63 | //添加要插入的对象集合 64 | [icmd addWithArray:userArray]; 65 | //设置添加操作是否使用replace语句 66 | [icmd setRelpace:YES]; 67 | //执行插入操作 68 | [icmd saveChangesInBackground:^{ 69 | NSLog(@"批量数据提交完成"); 70 | }]; 71 | 72 | #更新数据 73 | 74 | //通过对象更新数据 75 | FMDTUpdateObjectCommand *ucmd1 = [[DBSet shared].user createUpdateObjectCommand]; 76 | 77 | //添加要更新的对象 78 | [ucmd1 add:userObjct]; 79 | //执行更新操作 80 | [ucmd1 saveChangesInBackground:^{ 81 | NSLog(@"更新完成"); 82 | }]; 83 | 84 | //通过条件更新数据 85 | FMDTUpdateCommand *ucmd2 = [[DBSet shared].user createUpdateCommand]; 86 | //设置要更新的字段与值 87 | [ucmd2 fieldWithKey:@"nickname" val:@"小红"]; 88 | //设置更新条件 89 | [ucmd2 where:@"userId" equalTo:@(2)]; 90 | //执行更新操作 91 | [ucmd2 saveChanges]; 92 | 93 | 94 | #删除数据 95 | 96 | FMDTDeleteCommand *dcmd = FMDT_DELETE([DBSet shared].user); 97 | //设置条件 98 | [dcmd where:@"userId" greaterThan:@"50"]; 99 | //执行删除操作 100 | [dcmd saveChanges]; 101 | 102 | #查询数据 103 | 104 | //查询数据 105 | FMDTSelectCommand *cmd = [[DBSet shared].user createSelectCommand]; 106 | 107 | //单一条件查询 108 | //SQL:select * from [Users] where sex = '男' 109 | [cmd where:@"sex" equalTo:@"男"]; 110 | [cmd fetchArray]; 111 | 112 | //多条件And查询 113 | //SQL:select * from [Users] where sex = '男' and nickname like '%1%' 114 | [cmd where:@"sex" equalTo:@"男"]; 115 | [cmd where:@"nickname" containsString:@"%1%"]; 116 | [cmd fetchArray]; 117 | 118 | //多条件Or查询 119 | //SQL:select * from [Users] where nickname like '%1%' or sex = '男' 120 | [cmd where:@"nickname" containsString:@"%1%"]; 121 | [cmd whereOr:@"sex" equalTo:@"男"]; 122 | [cmd fetchArray]; 123 | 124 | //In 125 | //SQL:select count(*) from Users where sex in ('女','男') 126 | [cmd where:@"sex" containedIn:@[ @"女", @"男"]]; 127 | [cmd fetchArray]; 128 | 129 | //Not In 130 | //SQL:select count(*) from Users where sex not in ('女','男') 131 | [cmd where:@"sex" notContainedIn:@[ @"女", @"男"]]; 132 | [cmd fetchArray]; 133 | 134 | //Like 135 | //SQL:select * from [Users] where nickname like '%1%' 136 | [cmd where:@"nickname" containsString:@"%1%"]; 137 | [cmd fetchArray]; 138 | 139 | //Not Like 140 | //SQL:select * from [Users] where nickname not like '%1%' 141 | [cmd where:@"nickname" notContainsString:@"%1%"]; 142 | [cmd fetchArray]; 143 | 144 | // < 145 | //SQL:select * from Users where userId < '30' 146 | [cmd where:@"userId" lessThan:@(30)]; 147 | [cmd fetchArray]; 148 | 149 | // <= 150 | //SQL:select * from Users where userId <= '30' 151 | [cmd where:@"userId" lessThanOrEqualTo:@(30)]; 152 | [cmd fetchArray]; 153 | 154 | // > 155 | //SQL:select * from Users where userId > '30' 156 | [cmd where:@"userId" greaterThan:@(30)]; 157 | [cmd fetchArray]; 158 | 159 | // >= 160 | //SQL:select * from Users where userId >= '30' 161 | [cmd where:@"userId" greaterThanOrEqualTo:@(30)]; 162 | [cmd fetchArray]; 163 | 164 | //排序 ascending. 165 | //SQL:select * from Users order by userId asc 166 | [cmd orderByAscending:@"userId"]; 167 | [cmd fetchArray]; 168 | 169 | //排序 descending. 170 | //SQL:select * from Users order by userId desc 171 | [cmd orderByDescending:@"userId"]; 172 | [cmd fetchArray]; 173 | 174 | //获取前10条 175 | //SQL:select * from Users limit 10 176 | [cmd setLimit:10]; 177 | [cmd fetchArray]; 178 | 179 | //分页获取数据 180 | //SQL:select * from Users limit 10 offset 10 181 | [cmd setLimit:10]; 182 | [cmd setSkip:10]; 183 | [cmd fetchArray]; 184 | 185 | # 基于KeyValue的存储功能 186 | 187 | //字符串存储 188 | [STORE set:@"a1" value:@"我是字符串"]; 189 | //数值存储 190 | [STORE set:@"a2" value:@(1)]; 191 | //字典存储 192 | [STORE set:@"a3" value:@{@"test1": @"abc", @"test2": @"abc222"}]; 193 | //数组存储 194 | [STORE set:@"a4" value:@[@(1),@(2),@(3),@(4)]]; 195 | 196 | //读取字符串 197 | NSLog(@"%@", [STORE stringForKey:@"a1"]); 198 | //读取数值 199 | NSLog(@"%@", [STORE numberForKey:@"a2"]); 200 | //读取字典 201 | NSLog(@"%@", [STORE dictionaryForKey:@"a3"]); 202 | //读取数组 203 | NSLog(@"%@", [STORE arrayForKey:@"a4"]); 204 | 205 | //删除键值 206 | [STORE removeForKey:@"a1"]; 207 | //清除所有的键值 208 | [STORE removeAll]; 209 | 210 | # Installation 211 | 212 | pod 'FMDBDataTable' 213 | 214 | -------------------------------------------------------------------------------- /Classes/FMDTDeleteCommand.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // FMDTDeleteCommand.m 4 | // FMDataTable 5 | // 6 | // Created by bing.hao on 16/3/8. 7 | // Copyright © 2016年 bing.hao. All rights reserved. 8 | // 9 | 10 | #import "FMDTDeleteCommand.h" 11 | 12 | @interface FMDTDeleteCommand () 13 | 14 | @property (nonatomic, strong) NSMutableArray *whereArray; 15 | 16 | @end 17 | 18 | @implementation FMDTDeleteCommand 19 | @synthesize schema = _schema; 20 | 21 | - (instancetype)init 22 | { 23 | self = [super init]; 24 | if (self) { 25 | self.whereArray = [NSMutableArray new]; 26 | } 27 | return self; 28 | } 29 | 30 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema { 31 | self = [self init]; 32 | if (self) { 33 | _schema = schema; 34 | } 35 | return self; 36 | } 37 | 38 | - (FMDTDeleteCommand *)where:(NSString *)key equalTo:(id)object { 39 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ = '%@'", key, object]]; 40 | return self; 41 | } 42 | 43 | - (FMDTDeleteCommand *)where:(NSString *)key notEqualTo:(id)object { 44 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ <> '%@'", key, object]]; 45 | return self; 46 | } 47 | 48 | - (FMDTDeleteCommand *)where:(NSString *)key lessThan:(id)object { 49 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ < '%@'", key, object]]; 50 | return self; 51 | } 52 | 53 | - (FMDTDeleteCommand *)where:(NSString *)key lessThanOrEqualTo:(id)object { 54 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ <= '%@'", key, object]]; 55 | return self; 56 | } 57 | 58 | - (FMDTDeleteCommand *)where:(NSString *)key greaterThan:(id)object { 59 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ > '%@'", key, object]]; 60 | return self; 61 | } 62 | 63 | - (FMDTDeleteCommand *)where:(NSString *)key greaterThanOrEqualTo:(id)object { 64 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ >= '%@'", key, object]]; 65 | return self; 66 | } 67 | 68 | - (FMDTDeleteCommand *)where:(NSString *)key containedIn:(NSArray *)array { 69 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 70 | return self; 71 | } 72 | 73 | - (FMDTDeleteCommand *)where:(NSString *)key notContainedIn:(NSArray *)array { 74 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ not in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 75 | return self; 76 | } 77 | 78 | - (FMDTDeleteCommand *)where:(NSString *)key containsString:(NSString *)string { 79 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ like '%@'", key, string]]; 80 | return self; 81 | } 82 | 83 | - (FMDTDeleteCommand *)where:(NSString *)key notContainsString:(NSString *)string { 84 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ not like '%@'", key, string]]; 85 | return self; 86 | } 87 | 88 | - (FMDTDeleteCommand *)whereOr:(NSString *)key equalTo:(id)object { 89 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ = '%@'", key, object]]; 90 | return self; 91 | } 92 | 93 | - (FMDTDeleteCommand *)whereOr:(NSString *)key notEqualTo:(id)object { 94 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ <> '%@'", key, object]]; 95 | return self; 96 | } 97 | 98 | - (FMDTDeleteCommand *)whereOr:(NSString *)key lessThan:(id)object { 99 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ < '%@'", key, object]]; 100 | return self; 101 | } 102 | 103 | - (FMDTDeleteCommand *)whereOr:(NSString *)key lessThanOrEqualTo:(id)object { 104 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ <= '%@'", key, object]]; 105 | return self; 106 | } 107 | 108 | - (FMDTDeleteCommand *)whereOr:(NSString *)key greaterThan:(id)object { 109 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ > '%@'", key, object]]; 110 | return self; 111 | } 112 | 113 | - (FMDTDeleteCommand *)whereOr:(NSString *)key greaterThanOrEqualTo:(id)object { 114 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ >= '%@'", key, object]]; 115 | return self; 116 | } 117 | 118 | - (FMDTDeleteCommand *)whereOr:(NSString *)key containedIn:(NSArray *)array { 119 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 120 | return self; 121 | } 122 | 123 | - (FMDTDeleteCommand *)whereOr:(NSString *)key notContainedIn:(NSArray *)array { 124 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ not in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 125 | return self; 126 | } 127 | 128 | - (FMDTDeleteCommand *)whereOr:(NSString *)key containsString:(NSString *)string { 129 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ like '%@'", key, string]]; 130 | return self; 131 | } 132 | 133 | - (FMDTDeleteCommand *)whereOr:(NSString *)key notContainsString:(NSString *)string { 134 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ not like '%@'", key, string]]; 135 | return self; 136 | } 137 | 138 | - (void)saveChanges { 139 | 140 | FMDatabase *db = [FMDatabase databaseWithPath:self.schema.storage]; 141 | 142 | [db open]; 143 | [db executeUpdate:[self runSql]]; 144 | [db close]; 145 | 146 | [self.whereArray removeAllObjects]; 147 | } 148 | 149 | - (NSString *)runSql { 150 | NSMutableString *sql = [[NSMutableString alloc] initWithString:self.schema.statementDelete]; 151 | if (self.whereArray.count > 0) { 152 | NSString *str = [self.whereArray componentsJoinedByString:@" "]; 153 | if ([str hasPrefix:@"and"]) { 154 | str = [str substringFromIndex:3]; 155 | } else { 156 | str = [str substringFromIndex:2]; 157 | } 158 | [sql appendFormat:@" where %@", str]; 159 | } 160 | return sql; 161 | } 162 | 163 | - (void)saveChangesInBackground:(void(^)())callback { 164 | 165 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 166 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 167 | [queue inDatabase:^(FMDatabase *db) { 168 | [db executeUpdate:[self runSql]]; 169 | [self.whereArray removeAllObjects]; 170 | if (callback) { 171 | callback(); 172 | } 173 | }]; 174 | [queue close]; 175 | }); 176 | } 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /FMDataTable/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 15/8/31. 6 | // Copyright (c) 2015年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "DBSet.h" 11 | #import "FMDTKeyValueStorage.h" 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | //批量添加数据 20 | - (void)insertData { 21 | NSMutableArray *userArray = [NSMutableArray new]; 22 | for (int i = 0; i < 100; i++) { 23 | Users *userObjct = [Users new]; 24 | userObjct.userId = i + 1; 25 | userObjct.nickname = [NSString stringWithFormat:@"user%d", i]; 26 | userObjct.sex = i % 2 == 0 ? @"女" : @"男"; 27 | [userArray addObject:userObjct]; 28 | } 29 | 30 | //创建插入对象 31 | FMDTInsertCommand *icmd = [[DBSet shared].user createInsertCommand]; 32 | //添加要插入的对象集合 33 | [icmd addWithArray:userArray]; 34 | //设置添加操作是否使用replace语句 35 | [icmd setRelpace:YES]; 36 | //执行插入操作 37 | [icmd saveChangesInBackground:^{ 38 | NSLog(@"批量数据提交完成"); 39 | }]; 40 | } 41 | 42 | //更新数据 43 | - (void)updateData { 44 | 45 | Users *userObjct = [Users new]; 46 | 47 | userObjct.userId = 1; 48 | userObjct.nickname = @"小明"; 49 | userObjct.sex = @"男"; 50 | userObjct.other = @{ @"f1" : @(1), @"f2" : @"f2" }; 51 | 52 | //通过对象更新数据 53 | FMDTUpdateObjectCommand *ucmd1 = [[DBSet shared].user createUpdateObjectCommand]; 54 | 55 | //添加要更新的对象 56 | [ucmd1 add:userObjct]; 57 | //执行更新操作 58 | [ucmd1 saveChangesInBackground:^{ 59 | NSLog(@"更新完成"); 60 | }]; 61 | 62 | //通过条件更新数据 63 | FMDTUpdateCommand *ucmd2 = [[DBSet shared].user createUpdateCommand]; 64 | //设置要更新的字段与值 65 | [ucmd2 fieldWithKey:@"sex" val:@"女"]; 66 | //设置更新条件 67 | [ucmd2 where:@"userId" equalTo:@(2)]; 68 | //执行更新操作 69 | [ucmd2 saveChanges]; 70 | } 71 | 72 | //删除数据 73 | - (void)deleteData { 74 | 75 | FMDTDeleteCommand *dcmd = FMDT_DELETE([DBSet shared].user); 76 | //设置条件 77 | [dcmd where:@"userId" greaterThan:@"50"]; 78 | //执行删除操作 79 | [dcmd saveChanges]; 80 | } 81 | 82 | //查询数据 83 | - (void)selectData { 84 | //查询数据 85 | FMDTSelectCommand *cmd = [[DBSet shared].user createSelectCommand]; 86 | 87 | //单一条件查询 88 | //SQL:select * from [Users] where sex = '男' 89 | [cmd where:@"sex" equalTo:@"男"]; 90 | [cmd fetchArray]; 91 | 92 | //多条件And查询 93 | //SQL:select * from [Users] where sex = '男' and nickname like '%1%' 94 | [cmd where:@"sex" equalTo:@"男"]; 95 | [cmd where:@"nickname" containsString:@"%1%"]; 96 | [cmd fetchArray]; 97 | 98 | //多条件Or查询 99 | //SQL:select * from [Users] where nickname like '%1%' or sex = '男' 100 | [cmd where:@"nickname" containsString:@"%1%"]; 101 | [cmd whereOr:@"sex" equalTo:@"男"]; 102 | [cmd fetchArray]; 103 | 104 | //In 105 | //SQL:select count(*) from Users where sex in ('女','男') 106 | [cmd where:@"sex" containedIn:@[ @"女", @"男"]]; 107 | [cmd fetchArray]; 108 | 109 | //Not In 110 | //SQL:select count(*) from Users where sex not in ('女','男') 111 | [cmd where:@"sex" notContainedIn:@[ @"女", @"男"]]; 112 | [cmd fetchArray]; 113 | 114 | //Like 115 | //SQL:select * from [Users] where nickname like '%1%' 116 | [cmd where:@"nickname" containsString:@"%1%"]; 117 | [cmd fetchArray]; 118 | 119 | //Not Like 120 | //SQL:select * from [Users] where nickname not like '%1%' 121 | [cmd where:@"nickname" notContainsString:@"%1%"]; 122 | [cmd fetchArray]; 123 | 124 | // < 125 | //SQL:select * from Users where userId < '30' 126 | [cmd where:@"userId" lessThan:@(30)]; 127 | [cmd fetchArray]; 128 | 129 | // <= 130 | //SQL:select * from Users where userId <= '30' 131 | [cmd where:@"userId" lessThanOrEqualTo:@(30)]; 132 | [cmd fetchArray]; 133 | 134 | // > 135 | //SQL:select * from Users where userId > '30' 136 | [cmd where:@"userId" greaterThan:@(30)]; 137 | [cmd fetchArray]; 138 | 139 | // >= 140 | //SQL:select * from Users where userId >= '30' 141 | [cmd where:@"userId" greaterThanOrEqualTo:@(30)]; 142 | [cmd fetchArray]; 143 | 144 | //排序 ascending. 145 | //SQL:select * from Users order by userId asc 146 | [cmd orderByAscending:@"userId"]; 147 | [cmd fetchArray]; 148 | 149 | //排序 descending. 150 | //SQL:select * from Users order by userId desc 151 | [cmd orderByDescending:@"userId"]; 152 | [cmd fetchArray]; 153 | 154 | //获取前10条 155 | //SQL:select * from Users limit 10 156 | [cmd setLimit:10]; 157 | [cmd fetchArray]; 158 | 159 | //分页获取数据 160 | //SQL:select * from Users limit 10 offset 10 161 | [cmd setLimit:10]; 162 | [cmd setSkip:10]; 163 | [cmd fetchArray]; 164 | 165 | [cmd groupBy:@"sex"]; 166 | [cmd fetchArrayInBackground:^(NSArray *result) { 167 | NSLog(@"%@", result); 168 | }]; 169 | } 170 | 171 | - (void)dyInsertData { 172 | NSMutableArray *array = [NSMutableArray new]; 173 | for (int i = 0; i < 100; i++) { 174 | Message *mobj = [Message new]; 175 | mobj.mid = FMDT_UUID(); 176 | mobj.text = FMDT_UUID(); 177 | mobj.createdAt = [NSDate new]; 178 | [array addObject:mobj]; 179 | } 180 | 181 | //创建插入对象 182 | FMDTInsertCommand *icmd = [[[DBSet shared] dynamicTable:@"message_2B8970F2F4394B7CB4C8027FB198817A"] createInsertCommand]; 183 | //添加要插入的对象集合 184 | [icmd addWithArray:array]; 185 | //设置添加操作是否使用replace语句 186 | [icmd setRelpace:YES]; 187 | //执行插入操作 188 | [icmd saveChangesInBackground:^{ 189 | NSLog(@"批量数据提交完成"); 190 | }]; 191 | 192 | } 193 | 194 | - (void)testKeyValue { 195 | 196 | //字符串存储 197 | [STORE set:@"a1" value:@"我是字符串"]; 198 | //数值存储 199 | [STORE set:@"a2" value:@(1)]; 200 | //字典存储 201 | [STORE set:@"a3" value:@{@"test1": @"abc", @"test2": @"abc222"}]; 202 | //数组存储 203 | [STORE set:@"a4" value:@[@(1),@(2),@(3),@(4)]]; 204 | 205 | //读取字符串 206 | NSLog(@"%@", [STORE stringForKey:@"a1"]); 207 | //读取数值 208 | NSLog(@"%@", [STORE numberForKey:@"a2"]); 209 | //读取字典 210 | NSLog(@"%@", [STORE dictionaryForKey:@"a3"]); 211 | //读取数组 212 | NSLog(@"%@", [STORE arrayForKey:@"a4"]); 213 | 214 | //删除键值 215 | [STORE removeForKey:@"a1"]; 216 | //清除所有的键值 217 | [STORE removeAll]; 218 | } 219 | 220 | - (void)viewDidLoad { 221 | [super viewDidLoad]; 222 | 223 | NSLog(@"%@", [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]); 224 | 225 | // [self insertData]; //插入数据 226 | // [self updateData]; //更新数据 227 | // [self deleteData]; //删除数据 228 | // [self selectData]; //查询数据 229 | // 230 | // [self dyInsertData]; //向动态表里添加数据 231 | 232 | [self testKeyValue]; 233 | } 234 | 235 | - (void)didReceiveMemoryWarning { 236 | [super didReceiveMemoryWarning]; 237 | // Dispose of any resources that can be recreated. 238 | } 239 | 240 | @end 241 | -------------------------------------------------------------------------------- /Classes/FMDTUpdateCommand.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTUpdateCommand.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTUpdateCommand.h" 10 | 11 | @interface FMDTUpdateCommand () 12 | 13 | @property (nonatomic, strong) NSMutableArray *whereArray; 14 | @property (nonatomic, strong) NSMutableDictionary *dataDict; 15 | 16 | @end 17 | 18 | @implementation FMDTUpdateCommand 19 | @synthesize schema = _schema; 20 | 21 | - (instancetype)init 22 | { 23 | self = [super init]; 24 | if (self) { 25 | self.whereArray = [NSMutableArray new]; 26 | self.dataDict = [NSMutableDictionary new]; 27 | } 28 | return self; 29 | } 30 | 31 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema { 32 | self = [self init]; 33 | if (self) { 34 | _schema = schema; 35 | } 36 | return self; 37 | } 38 | 39 | - (FMDTUpdateCommand *)where:(NSString *)key equalTo:(id)object { 40 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ = '%@'", key, object]]; 41 | return self; 42 | } 43 | 44 | - (FMDTUpdateCommand *)where:(NSString *)key notEqualTo:(id)object { 45 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ <> '%@'", key, object]]; 46 | return self; 47 | } 48 | 49 | - (FMDTUpdateCommand *)where:(NSString *)key lessThan:(id)object { 50 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ < '%@'", key, object]]; 51 | return self; 52 | } 53 | 54 | - (FMDTUpdateCommand *)where:(NSString *)key lessThanOrEqualTo:(id)object { 55 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ <= '%@'", key, object]]; 56 | return self; 57 | } 58 | 59 | - (FMDTUpdateCommand *)where:(NSString *)key greaterThan:(id)object { 60 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ > '%@'", key, object]]; 61 | return self; 62 | } 63 | 64 | - (FMDTUpdateCommand *)where:(NSString *)key greaterThanOrEqualTo:(id)object { 65 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ >= '%@'", key, object]]; 66 | return self; 67 | } 68 | 69 | - (FMDTUpdateCommand *)where:(NSString *)key containedIn:(NSArray *)array { 70 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 71 | return self; 72 | } 73 | 74 | - (FMDTUpdateCommand *)where:(NSString *)key notContainedIn:(NSArray *)array { 75 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ not in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 76 | return self; 77 | } 78 | 79 | - (FMDTUpdateCommand *)where:(NSString *)key containsString:(NSString *)string { 80 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ like '%@'", key, string]]; 81 | return self; 82 | } 83 | 84 | - (FMDTUpdateCommand *)where:(NSString *)key notContainsString:(NSString *)string { 85 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ not like '%@'", key, string]]; 86 | return self; 87 | } 88 | 89 | - (FMDTUpdateCommand *)whereOr:(NSString *)key equalTo:(id)object { 90 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ = '%@'", key, object]]; 91 | return self; 92 | } 93 | 94 | - (FMDTUpdateCommand *)whereOr:(NSString *)key notEqualTo:(id)object { 95 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ <> '%@'", key, object]]; 96 | return self; 97 | } 98 | 99 | - (FMDTUpdateCommand *)whereOr:(NSString *)key lessThan:(id)object { 100 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ < '%@'", key, object]]; 101 | return self; 102 | } 103 | 104 | - (FMDTUpdateCommand *)whereOr:(NSString *)key lessThanOrEqualTo:(id)object { 105 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ <= '%@'", key, object]]; 106 | return self; 107 | } 108 | 109 | - (FMDTUpdateCommand *)whereOr:(NSString *)key greaterThan:(id)object { 110 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ > '%@'", key, object]]; 111 | return self; 112 | } 113 | 114 | - (FMDTUpdateCommand *)whereOr:(NSString *)key greaterThanOrEqualTo:(id)object { 115 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ >= '%@'", key, object]]; 116 | return self; 117 | } 118 | 119 | - (FMDTUpdateCommand *)whereOr:(NSString *)key containedIn:(NSArray *)array { 120 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 121 | return self; 122 | } 123 | 124 | - (FMDTUpdateCommand *)whereOr:(NSString *)key notContainedIn:(NSArray *)array { 125 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ not in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 126 | return self; 127 | } 128 | 129 | - (FMDTUpdateCommand *)whereOr:(NSString *)key containsString:(NSString *)string { 130 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ like '%@'", key, string]]; 131 | return self; 132 | } 133 | 134 | - (FMDTUpdateCommand *)whereOr:(NSString *)key notContainsString:(NSString *)string { 135 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ not like '%@'", key, string]]; 136 | return self; 137 | } 138 | 139 | - (FMDTUpdateCommand *)fieldWithKey:(NSString *)key val:(id)val { 140 | [self.dataDict setObject:val forKey:key]; 141 | return self; 142 | } 143 | 144 | - (void)saveChanges { 145 | 146 | if (self.dataDict.count == 0) { 147 | return; 148 | } 149 | 150 | FMDatabase *db = [FMDatabase databaseWithPath:self.schema.storage]; 151 | 152 | [db open]; 153 | [db executeUpdate:[self runSql] withParameterDictionary:self.dataDict]; 154 | [db close]; 155 | 156 | [self.whereArray removeAllObjects]; 157 | [self.dataDict removeAllObjects]; 158 | } 159 | 160 | - (void)saveChangesInBackground:(void (^)())callback { 161 | 162 | if (self.dataDict.count == 0) { 163 | return; 164 | } 165 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 166 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 167 | [queue inDatabase:^(FMDatabase *db) { 168 | [db executeUpdate:[self runSql] withParameterDictionary:self.dataDict]; 169 | [self.whereArray removeAllObjects]; 170 | [self.dataDict removeAllObjects]; 171 | callback(); 172 | }]; 173 | [queue close]; 174 | }); 175 | } 176 | 177 | - (NSString *)runSql { 178 | NSMutableString *sql = [[NSMutableString alloc] initWithFormat:@"update [%@] set", self.schema.tableName]; 179 | 180 | for (NSString *key in self.dataDict.allKeys) { 181 | [sql appendFormat:@" %@=:%@,", key, key]; 182 | } 183 | if (self.dataDict.count > 0) { 184 | [sql deleteCharactersInRange:NSMakeRange(sql.length-1, 1)]; 185 | } 186 | if (self.whereArray.count > 0) { 187 | NSString *str = [self.whereArray componentsJoinedByString:@" "]; 188 | if ([str hasPrefix:@"and"]) { 189 | str = [str substringFromIndex:3]; 190 | } else { 191 | str = [str substringFromIndex:2]; 192 | } 193 | [sql appendFormat:@" where %@", str]; 194 | } 195 | return sql; 196 | } 197 | 198 | @end 199 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDatabase.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** Category of additions for `` class. 15 | 16 | ### See also 17 | 18 | - `` 19 | */ 20 | 21 | @interface FMDatabase (FMDatabaseAdditions) 22 | 23 | ///---------------------------------------- 24 | /// @name Return results of SQL to variable 25 | ///---------------------------------------- 26 | 27 | /** Return `int` value for query 28 | 29 | @param query The SQL query to be performed. 30 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 31 | 32 | @return `int` value. 33 | 34 | @note This is not available from Swift. 35 | */ 36 | 37 | - (int)intForQuery:(NSString*)query, ...; 38 | 39 | /** Return `long` value for query 40 | 41 | @param query The SQL query to be performed. 42 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 43 | 44 | @return `long` value. 45 | 46 | @note This is not available from Swift. 47 | */ 48 | 49 | - (long)longForQuery:(NSString*)query, ...; 50 | 51 | /** Return `BOOL` value for query 52 | 53 | @param query The SQL query to be performed. 54 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 55 | 56 | @return `BOOL` value. 57 | 58 | @note This is not available from Swift. 59 | */ 60 | 61 | - (BOOL)boolForQuery:(NSString*)query, ...; 62 | 63 | /** Return `double` value for query 64 | 65 | @param query The SQL query to be performed. 66 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 67 | 68 | @return `double` value. 69 | 70 | @note This is not available from Swift. 71 | */ 72 | 73 | - (double)doubleForQuery:(NSString*)query, ...; 74 | 75 | /** Return `NSString` value for query 76 | 77 | @param query The SQL query to be performed. 78 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 79 | 80 | @return `NSString` value. 81 | 82 | @note This is not available from Swift. 83 | */ 84 | 85 | - (NSString * _Nullable)stringForQuery:(NSString*)query, ...; 86 | 87 | /** Return `NSData` value for query 88 | 89 | @param query The SQL query to be performed. 90 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 91 | 92 | @return `NSData` value. 93 | 94 | @note This is not available from Swift. 95 | */ 96 | 97 | - (NSData * _Nullable)dataForQuery:(NSString*)query, ...; 98 | 99 | /** Return `NSDate` value for query 100 | 101 | @param query The SQL query to be performed. 102 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 103 | 104 | @return `NSDate` value. 105 | 106 | @note This is not available from Swift. 107 | */ 108 | 109 | - (NSDate * _Nullable)dateForQuery:(NSString*)query, ...; 110 | 111 | 112 | // Notice that there's no dataNoCopyForQuery:. 113 | // That would be a bad idea, because we close out the result set, and then what 114 | // happens to the data that we just didn't copy? Who knows, not I. 115 | 116 | 117 | ///-------------------------------- 118 | /// @name Schema related operations 119 | ///-------------------------------- 120 | 121 | /** Does table exist in database? 122 | 123 | @param tableName The name of the table being looked for. 124 | 125 | @return `YES` if table found; `NO` if not found. 126 | */ 127 | 128 | - (BOOL)tableExists:(NSString*)tableName; 129 | 130 | /** The schema of the database. 131 | 132 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: 133 | 134 | - `type` - The type of entity (e.g. table, index, view, or trigger) 135 | - `name` - The name of the object 136 | - `tbl_name` - The name of the table to which the object references 137 | - `rootpage` - The page number of the root b-tree page for tables and indices 138 | - `sql` - The SQL that created the entity 139 | 140 | @return `FMResultSet` of schema; `nil` on error. 141 | 142 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html) 143 | */ 144 | 145 | - (FMResultSet * _Nullable)getSchema; 146 | 147 | /** The schema of the database. 148 | 149 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: 150 | 151 | PRAGMA table_info('employees') 152 | 153 | This will report: 154 | 155 | - `cid` - The column ID number 156 | - `name` - The name of the column 157 | - `type` - The data type specified for the column 158 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required) 159 | - `dflt_value` - The default value for the column 160 | - `pk` - Whether the field is part of the primary key of the table 161 | 162 | @param tableName The name of the table for whom the schema will be returned. 163 | 164 | @return `FMResultSet` of schema; `nil` on error. 165 | 166 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) 167 | */ 168 | 169 | - (FMResultSet * _Nullable)getTableSchema:(NSString*)tableName; 170 | 171 | /** Test to see if particular column exists for particular table in database 172 | 173 | @param columnName The name of the column. 174 | 175 | @param tableName The name of the table. 176 | 177 | @return `YES` if column exists in table in question; `NO` otherwise. 178 | */ 179 | 180 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; 181 | 182 | /** Test to see if particular column exists for particular table in database 183 | 184 | @param columnName The name of the column. 185 | 186 | @param tableName The name of the table. 187 | 188 | @return `YES` if column exists in table in question; `NO` otherwise. 189 | 190 | @see columnExists:inTableWithName: 191 | 192 | @warning Deprecated - use `` instead. 193 | */ 194 | 195 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __deprecated_msg("Use columnExists:inTableWithName: instead"); 196 | 197 | 198 | /** Validate SQL statement 199 | 200 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. 201 | 202 | @param sql The SQL statement being validated. 203 | 204 | @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. 205 | 206 | @return `YES` if validation succeeded without incident; `NO` otherwise. 207 | 208 | */ 209 | 210 | - (BOOL)validateSQL:(NSString*)sql error:(NSError * _Nullable *)error; 211 | 212 | 213 | ///----------------------------------- 214 | /// @name Application identifier tasks 215 | ///----------------------------------- 216 | 217 | /** Retrieve application ID 218 | 219 | @return The `uint32_t` numeric value of the application ID. 220 | 221 | @see setApplicationID: 222 | */ 223 | 224 | @property (nonatomic) uint32_t applicationID; 225 | 226 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 227 | 228 | /** Retrieve application ID string 229 | 230 | @see setApplicationIDString: 231 | */ 232 | 233 | @property (nonatomic, retain) NSString *applicationIDString; 234 | 235 | #endif 236 | 237 | ///----------------------------------- 238 | /// @name user version identifier tasks 239 | ///----------------------------------- 240 | 241 | /** Retrieve user version 242 | 243 | @see setUserVersion: 244 | */ 245 | 246 | @property (nonatomic) uint32_t userVersion; 247 | 248 | @end 249 | 250 | NS_ASSUME_NONNULL_END 251 | -------------------------------------------------------------------------------- /Classes/FMDTSchema.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTSchema.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTSchema.h" 10 | #import "NSObject+runtime.h" 11 | #import "FMDTObject.h" 12 | 13 | #define FMDT_DB_TYPE_TEXT @"text" 14 | #define FMDT_DB_TYPE_NUMBER @"integer" 15 | #define FMDT_DB_TYPE_BLOB @"blob" 16 | #define FMDT_DB_TYPE_DATE @"date" 17 | 18 | #define FMDT_DTS_F_OBJ_NAME @"__DTS_F_OBJ_NAME" 19 | #define FMDT_DTS_F_OBJ_TYPE @"__DTS_F_OBJ_TYPE" 20 | #define FMDT_DTS_F_NAME @"__DTS_F_NAME" 21 | #define FMDT_DTS_F_TYPE @"__DTS_F_TYPE" 22 | 23 | BOOL FMDT_IsCollectionObject(NSString *type) { 24 | if ([type isEqualToString:@"T@\"NSDictionary\""] || 25 | [type isEqualToString:@"T@\"NSMutableDictionary\""] || 26 | [type isEqualToString:@"T@\"NSArray\""] || 27 | [type isEqualToString:@"T@\"NSMutableArray\""]) { 28 | return YES; 29 | } 30 | return NO; 31 | } 32 | 33 | BOOL FMDT_IsDateObject(NSString *type) { 34 | if ([type isEqualToString:@"T@\"NSDate\""]) { 35 | return YES; 36 | } 37 | return NO; 38 | } 39 | 40 | BOOL FMDT_IsDataObject(NSString *type) { 41 | if ([type isEqualToString:@"T@\"NSData\""]) { 42 | return YES; 43 | } 44 | return NO; 45 | } 46 | 47 | NSDictionary * FMDTNewField(NSString *name, NSString *type) 48 | { 49 | static NSDictionary *__map; 50 | static dispatch_once_t onceToken; 51 | dispatch_once(&onceToken, ^{ 52 | __map = @{ @"T@\"NSString\"":FMDT_DB_TYPE_TEXT, 53 | @"T@\"NSNumber\"":FMDT_DB_TYPE_NUMBER, 54 | @"T@\"NSDate\"":FMDT_DB_TYPE_DATE, 55 | @"T@\"NSData\"":FMDT_DB_TYPE_BLOB, 56 | @"Ti":FMDT_DB_TYPE_NUMBER, 57 | @"T^i":FMDT_DB_TYPE_NUMBER, 58 | @"Tf":FMDT_DB_TYPE_NUMBER, 59 | @"Tq":FMDT_DB_TYPE_NUMBER, 60 | @"Td":FMDT_DB_TYPE_NUMBER, 61 | @"T@\"NSDictionary\"":FMDT_DB_TYPE_TEXT, 62 | @"T@\"NSMutableDictionary\"":FMDT_DB_TYPE_TEXT, 63 | @"T@\"NSArray\"":FMDT_DB_TYPE_TEXT, 64 | @"T@\"NSMutableArray\"":FMDT_DB_TYPE_TEXT, 65 | }; 66 | }); 67 | NSString *dbType = [__map objectForKey:type]; 68 | if (dbType) { 69 | return @{ FMDT_DTS_F_OBJ_NAME:name, FMDT_DTS_F_OBJ_TYPE : type, FMDT_DTS_F_NAME:name, FMDT_DTS_F_TYPE:dbType }; 70 | } 71 | return nil; 72 | } 73 | 74 | @implementation FMDTSchemaTable 75 | 76 | - (NSString *)statementUpdate { 77 | if (_statementUpdate == nil) { 78 | 79 | Class cls = NSClassFromString(self.className); 80 | NSString *pk = [(id)cls performSelector:@selector(primaryKeyFieldName) withObject:nil]; 81 | NSAssert(pk, @"必须指定主键字段"); 82 | NSMutableString *where = [NSMutableString stringWithString:@"where "]; 83 | NSArray *tmp = [pk componentsSeparatedByString:@","]; 84 | if (tmp.count > 1) { 85 | for (NSString *entry in tmp) { 86 | [where appendFormat:@"[%@]=:%@ and ", entry, entry]; 87 | } 88 | [where deleteCharactersInRange:NSMakeRange(where.length - 5, 5)]; 89 | } else { 90 | [where appendFormat:@"[%@]=:%@", pk, pk]; 91 | } 92 | NSMutableArray * keys = [NSMutableArray arrayWithCapacity:self.fields.count]; 93 | for (int i = 0; i < self.fields.count; i++) { 94 | NSString *fname = [[self.fields objectAtIndex:i] name]; 95 | if ((int)[pk rangeOfString:fname].location < 0) { 96 | [keys addObject:[NSString stringWithFormat:@"[%@]=:%@", fname, fname]]; 97 | } 98 | // if ([fname isEqualToString:pk] == NO) { 99 | // [keys addObject:[NSString stringWithFormat:@"[%@]=:%@", fname, fname]]; 100 | // } 101 | } 102 | NSString * key = [keys componentsJoinedByString:@","]; 103 | _statementUpdate = [NSString stringWithFormat:@"update [%@] set %@ %@", self.tableName, key, where]; 104 | } 105 | return _statementUpdate; 106 | } 107 | 108 | - (NSString *)statementDelete { 109 | if (_statementDelete == nil) { 110 | _statementDelete = [NSString stringWithFormat:@"delete from [%@]", self.tableName];; 111 | } 112 | return _statementDelete; 113 | } 114 | 115 | - (NSString *)statementInsert { 116 | if (_statementInsert == nil) { 117 | NSMutableArray * keys = [NSMutableArray arrayWithCapacity:self.fields.count]; 118 | NSMutableArray * vals = [NSMutableArray arrayWithCapacity:self.fields.count]; 119 | for (int i = 0; i < self.fields.count; i++) { 120 | FMDTSchemaField *field = self.fields[i]; 121 | [keys addObject:[NSString stringWithFormat:@"[%@]", field.name]]; 122 | [vals addObject:@"?"]; 123 | } 124 | NSString * key = [keys componentsJoinedByString:@","]; 125 | NSString * val = [vals componentsJoinedByString:@","]; 126 | _statementInsert = [NSString stringWithFormat:@"insert into [%@] (%@) values (%@)", self.tableName, key, val]; 127 | } 128 | return _statementInsert; 129 | } 130 | 131 | - (NSString *)statementReplace { 132 | if (_statementReplace == nil) { 133 | NSMutableArray * keys = [NSMutableArray arrayWithCapacity:self.fields.count]; 134 | NSMutableArray * vals = [NSMutableArray arrayWithCapacity:self.fields.count]; 135 | for (int i = 0; i < self.fields.count; i++) { 136 | FMDTSchemaField *field = self.fields[i]; 137 | [keys addObject:[NSString stringWithFormat:@"[%@]", field.name]]; 138 | [vals addObject:@"?"]; 139 | } 140 | NSString * key = [keys componentsJoinedByString:@","]; 141 | NSString * val = [vals componentsJoinedByString:@","]; 142 | _statementReplace = [NSString stringWithFormat:@"replace into [%@] (%@) values (%@)", self.tableName, key, val]; 143 | } 144 | return _statementReplace; 145 | } 146 | 147 | - (instancetype)initWithClass:(Class)cls storage:(NSString *)storage { 148 | self = [super init]; 149 | if (self) { 150 | self.className = NSStringFromClass(cls); 151 | self.tableName = self.className; 152 | self.storage = storage; 153 | 154 | NSString *pk = [(id)cls performSelector:@selector(primaryKeyFieldName) withObject:nil]; 155 | 156 | NSMutableArray * fields = [NSMutableArray new]; 157 | [NSObject enumeratePropertiesWithClassType:cls usingBlick:^(BOOL read, NSString *name, NSString *type, NSArray *attrs) { 158 | NSDictionary * item = nil; 159 | if (!read && (item = FMDTNewField(name, type))) { 160 | FMDTSchemaField *field = [[FMDTSchemaField alloc] initWithDictionary:item]; 161 | if (pk && [field.objName isEqualToString:pk]) { 162 | field.primaryKey = YES; 163 | } 164 | [fields addObject:field]; 165 | } 166 | }]; 167 | 168 | self.fields = fields; 169 | } 170 | return self; 171 | } 172 | 173 | - (instancetype)initWithClass:(Class)cls customTableName:(NSString *)name storage:(NSString *)storage { 174 | self = [self initWithClass:cls storage:storage]; 175 | if (self) { 176 | self.tableName = name; 177 | } 178 | return self; 179 | } 180 | 181 | @end 182 | 183 | @implementation FMDTSchemaField 184 | 185 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary { 186 | self = [super init]; 187 | if (self) { 188 | self.objName = [dictionary objectForKey:FMDT_DTS_F_OBJ_NAME]; 189 | self.objType = [dictionary objectForKey:FMDT_DTS_F_OBJ_TYPE]; 190 | self.name = [dictionary objectForKey:FMDT_DTS_F_NAME]; 191 | self.type = [dictionary objectForKey:FMDT_DTS_F_TYPE]; 192 | } 193 | return self; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabaseAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import "FMDatabase.h" 10 | #import "FMDatabaseAdditions.h" 11 | #import "TargetConditionals.h" 12 | 13 | #if FMDB_SQLITE_STANDALONE 14 | #import 15 | #else 16 | #import 17 | #endif 18 | 19 | @interface FMDatabase (PrivateStuff) 20 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray * _Nullable)arrayArgs orDictionary:(NSDictionary * _Nullable)dictionaryArgs orVAList:(va_list)args; 21 | @end 22 | 23 | @implementation FMDatabase (FMDatabaseAdditions) 24 | 25 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ 26 | va_list args; \ 27 | va_start(args, query); \ 28 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ 29 | va_end(args); \ 30 | if (![resultSet next]) { return (type)0; } \ 31 | type ret = [resultSet sel:0]; \ 32 | [resultSet close]; \ 33 | [resultSet setParentDB:nil]; \ 34 | return ret; 35 | 36 | 37 | - (NSString *)stringForQuery:(NSString*)query, ... { 38 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); 39 | } 40 | 41 | - (int)intForQuery:(NSString*)query, ... { 42 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); 43 | } 44 | 45 | - (long)longForQuery:(NSString*)query, ... { 46 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); 47 | } 48 | 49 | - (BOOL)boolForQuery:(NSString*)query, ... { 50 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); 51 | } 52 | 53 | - (double)doubleForQuery:(NSString*)query, ... { 54 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); 55 | } 56 | 57 | - (NSData*)dataForQuery:(NSString*)query, ... { 58 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); 59 | } 60 | 61 | - (NSDate*)dateForQuery:(NSString*)query, ... { 62 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); 63 | } 64 | 65 | 66 | - (BOOL)tableExists:(NSString*)tableName { 67 | 68 | tableName = [tableName lowercaseString]; 69 | 70 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; 71 | 72 | //if at least one next exists, table exists 73 | BOOL returnBool = [rs next]; 74 | 75 | //close and free object 76 | [rs close]; 77 | 78 | return returnBool; 79 | } 80 | 81 | /* 82 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 83 | check if table exist in database (patch from OZLB) 84 | */ 85 | - (FMResultSet * _Nullable)getSchema { 86 | 87 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 88 | FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; 89 | 90 | return rs; 91 | } 92 | 93 | /* 94 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 95 | */ 96 | - (FMResultSet * _Nullable)getTableSchema:(NSString*)tableName { 97 | 98 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 99 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; 100 | 101 | return rs; 102 | } 103 | 104 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { 105 | 106 | BOOL returnBool = NO; 107 | 108 | tableName = [tableName lowercaseString]; 109 | columnName = [columnName lowercaseString]; 110 | 111 | FMResultSet *rs = [self getTableSchema:tableName]; 112 | 113 | //check if column is present in table schema 114 | while ([rs next]) { 115 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { 116 | returnBool = YES; 117 | break; 118 | } 119 | } 120 | 121 | //If this is not done FMDatabase instance stays out of pool 122 | [rs close]; 123 | 124 | return returnBool; 125 | } 126 | 127 | 128 | 129 | - (uint32_t)applicationID { 130 | #if SQLITE_VERSION_NUMBER >= 3007017 131 | uint32_t r = 0; 132 | 133 | FMResultSet *rs = [self executeQuery:@"pragma application_id"]; 134 | 135 | if ([rs next]) { 136 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 137 | } 138 | 139 | [rs close]; 140 | 141 | return r; 142 | #else 143 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 144 | if (self.logsErrors) NSLog(@"%@", errorMessage); 145 | return 0; 146 | #endif 147 | } 148 | 149 | - (void)setApplicationID:(uint32_t)appID { 150 | #if SQLITE_VERSION_NUMBER >= 3007017 151 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; 152 | FMResultSet *rs = [self executeQuery:query]; 153 | [rs next]; 154 | [rs close]; 155 | #else 156 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 157 | if (self.logsErrors) NSLog(@"%@", errorMessage); 158 | #endif 159 | } 160 | 161 | 162 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 163 | 164 | - (NSString*)applicationIDString { 165 | #if SQLITE_VERSION_NUMBER >= 3007017 166 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); 167 | 168 | assert([s length] == 6); 169 | 170 | s = [s substringWithRange:NSMakeRange(1, 4)]; 171 | 172 | 173 | return s; 174 | #else 175 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 176 | if (self.logsErrors) NSLog(@"%@", errorMessage); 177 | return nil; 178 | #endif 179 | } 180 | 181 | - (void)setApplicationIDString:(NSString*)s { 182 | #if SQLITE_VERSION_NUMBER >= 3007017 183 | if ([s length] != 4) { 184 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); 185 | } 186 | 187 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; 188 | #else 189 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 190 | if (self.logsErrors) NSLog(@"%@", errorMessage); 191 | #endif 192 | } 193 | 194 | #endif 195 | 196 | - (uint32_t)userVersion { 197 | uint32_t r = 0; 198 | 199 | FMResultSet *rs = [self executeQuery:@"pragma user_version"]; 200 | 201 | if ([rs next]) { 202 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 203 | } 204 | 205 | [rs close]; 206 | return r; 207 | } 208 | 209 | - (void)setUserVersion:(uint32_t)version { 210 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; 211 | FMResultSet *rs = [self executeQuery:query]; 212 | [rs next]; 213 | [rs close]; 214 | } 215 | 216 | #pragma clang diagnostic push 217 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 218 | 219 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { 220 | return [self columnExists:columnName inTableWithName:tableName]; 221 | } 222 | 223 | #pragma clang diagnostic pop 224 | 225 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { 226 | sqlite3_stmt *pStmt = NULL; 227 | BOOL validationSucceeded = YES; 228 | 229 | int rc = sqlite3_prepare_v2([self sqliteHandle], [sql UTF8String], -1, &pStmt, 0); 230 | if (rc != SQLITE_OK) { 231 | validationSucceeded = NO; 232 | if (error) { 233 | *error = [NSError errorWithDomain:NSCocoaErrorDomain 234 | code:[self lastErrorCode] 235 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] 236 | forKey:NSLocalizedDescriptionKey]]; 237 | } 238 | } 239 | 240 | sqlite3_finalize(pStmt); 241 | 242 | return validationSucceeded; 243 | } 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabasePool.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @class FMDatabase; 14 | 15 | /** Pool of `` objects. 16 | 17 | ### See also 18 | 19 | - `` 20 | - `` 21 | 22 | @warning Before using `FMDatabasePool`, please consider using `` instead. 23 | 24 | If you really really really know what you're doing and `FMDatabasePool` is what 25 | you really really need (ie, you're using a read only database), OK you can use 26 | it. But just be careful not to deadlock! 27 | 28 | For an example on deadlocking, search for: 29 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` 30 | in the main.m file. 31 | */ 32 | 33 | @interface FMDatabasePool : NSObject 34 | 35 | /** Database path */ 36 | 37 | @property (atomic, copy, nullable) NSString *path; 38 | 39 | /** Delegate object */ 40 | 41 | @property (atomic, assign, nullable) id delegate; 42 | 43 | /** Maximum number of databases to create */ 44 | 45 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; 46 | 47 | /** Open flags */ 48 | 49 | @property (atomic, readonly) int openFlags; 50 | 51 | /** Custom virtual file system name */ 52 | 53 | @property (atomic, copy, nullable) NSString *vfsName; 54 | 55 | 56 | ///--------------------- 57 | /// @name Initialization 58 | ///--------------------- 59 | 60 | /** Create pool using path. 61 | 62 | @param aPath The file path of the database. 63 | 64 | @return The `FMDatabasePool` object. `nil` on error. 65 | */ 66 | 67 | + (instancetype)databasePoolWithPath:(NSString * _Nullable)aPath; 68 | 69 | /** Create pool using file URL. 70 | 71 | @param url The file `NSURL` of the database. 72 | 73 | @return The `FMDatabasePool` object. `nil` on error. 74 | */ 75 | 76 | + (instancetype)databasePoolWithURL:(NSURL * _Nullable)url; 77 | 78 | /** Create pool using path and specified flags 79 | 80 | @param aPath The file path of the database. 81 | @param openFlags Flags passed to the openWithFlags method of the database. 82 | 83 | @return The `FMDatabasePool` object. `nil` on error. 84 | */ 85 | 86 | + (instancetype)databasePoolWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 87 | 88 | /** Create pool using file URL and specified flags 89 | 90 | @param url The file `NSURL` of the database. 91 | @param openFlags Flags passed to the openWithFlags method of the database. 92 | 93 | @return The `FMDatabasePool` object. `nil` on error. 94 | */ 95 | 96 | + (instancetype)databasePoolWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 97 | 98 | /** Create pool using path. 99 | 100 | @param aPath The file path of the database. 101 | 102 | @return The `FMDatabasePool` object. `nil` on error. 103 | */ 104 | 105 | - (instancetype)initWithPath:(NSString * _Nullable)aPath; 106 | 107 | /** Create pool using file URL. 108 | 109 | @param url The file `NSURL of the database. 110 | 111 | @return The `FMDatabasePool` object. `nil` on error. 112 | */ 113 | 114 | - (instancetype)initWithURL:(NSURL * _Nullable)url; 115 | 116 | /** Create pool using path and specified flags. 117 | 118 | @param aPath The file path of the database. 119 | @param openFlags Flags passed to the openWithFlags method of the database 120 | 121 | @return The `FMDatabasePool` object. `nil` on error. 122 | */ 123 | 124 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 125 | 126 | /** Create pool using file URL and specified flags. 127 | 128 | @param url The file `NSURL` of the database. 129 | @param openFlags Flags passed to the openWithFlags method of the database 130 | 131 | @return The `FMDatabasePool` object. `nil` on error. 132 | */ 133 | 134 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 135 | 136 | /** Create pool using path and specified flags. 137 | 138 | @param aPath The file path of the database. 139 | @param openFlags Flags passed to the openWithFlags method of the database 140 | @param vfsName The name of a custom virtual file system 141 | 142 | @return The `FMDatabasePool` object. `nil` on error. 143 | */ 144 | 145 | - (instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 146 | 147 | /** Create pool using file URL and specified flags. 148 | 149 | @param url The file `NSURL` of the database. 150 | @param openFlags Flags passed to the openWithFlags method of the database 151 | @param vfsName The name of a custom virtual file system 152 | 153 | @return The `FMDatabasePool` object. `nil` on error. 154 | */ 155 | 156 | - (instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 157 | 158 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 159 | 160 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 161 | 162 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 163 | */ 164 | 165 | + (Class)databaseClass; 166 | 167 | ///------------------------------------------------ 168 | /// @name Keeping track of checked in/out databases 169 | ///------------------------------------------------ 170 | 171 | /** Number of checked-in databases in pool 172 | */ 173 | 174 | @property (nonatomic, readonly) NSUInteger countOfCheckedInDatabases; 175 | 176 | /** Number of checked-out databases in pool 177 | */ 178 | 179 | @property (nonatomic, readonly) NSUInteger countOfCheckedOutDatabases; 180 | 181 | /** Total number of databases in pool 182 | */ 183 | 184 | @property (nonatomic, readonly) NSUInteger countOfOpenDatabases; 185 | 186 | /** Release all databases in pool */ 187 | 188 | - (void)releaseAllDatabases; 189 | 190 | ///------------------------------------------ 191 | /// @name Perform database operations in pool 192 | ///------------------------------------------ 193 | 194 | /** Synchronously perform database operations in pool. 195 | 196 | @param block The code to be run on the `FMDatabasePool` pool. 197 | */ 198 | 199 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block; 200 | 201 | /** Synchronously perform database operations in pool using transaction. 202 | 203 | @param block The code to be run on the `FMDatabasePool` pool. 204 | 205 | @warning Unlike SQLite's `BEGIN TRANSACTION`, this method currently performs 206 | an exclusive transaction, not a deferred transaction. This behavior 207 | is likely to change in future versions of FMDB, whereby this method 208 | will likely eventually adopt standard SQLite behavior and perform 209 | deferred transactions. If you really need exclusive tranaction, it is 210 | recommended that you use `inExclusiveTransaction`, instead, not only 211 | to make your intent explicit, but also to future-proof your code. 212 | */ 213 | 214 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 215 | 216 | /** Synchronously perform database operations in pool using exclusive transaction. 217 | 218 | @param block The code to be run on the `FMDatabasePool` pool. 219 | */ 220 | 221 | - (void)inExclusiveTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 222 | 223 | /** Synchronously perform database operations in pool using deferred transaction. 224 | 225 | @param block The code to be run on the `FMDatabasePool` pool. 226 | */ 227 | 228 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 229 | 230 | /** Synchronously perform database operations on queue, using immediate transactions. 231 | 232 | @param block The code to be run on the queue of `FMDatabaseQueue` 233 | */ 234 | 235 | - (void)inImmediateTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 236 | 237 | /** Synchronously perform database operations in pool using save point. 238 | 239 | @param block The code to be run on the `FMDatabasePool` pool. 240 | 241 | @return `NSError` object if error; `nil` if successful. 242 | 243 | @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead. 244 | */ 245 | 246 | - (NSError * _Nullable)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 247 | 248 | @end 249 | 250 | 251 | /** FMDatabasePool delegate category 252 | 253 | This is a category that defines the protocol for the FMDatabasePool delegate 254 | */ 255 | 256 | @interface NSObject (FMDatabasePoolDelegate) 257 | 258 | /** Asks the delegate whether database should be added to the pool. 259 | 260 | @param pool The `FMDatabasePool` object. 261 | @param database The `FMDatabase` object. 262 | 263 | @return `YES` if it should add database to pool; `NO` if not. 264 | 265 | */ 266 | 267 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; 268 | 269 | /** Tells the delegate that database was added to the pool. 270 | 271 | @param pool The `FMDatabasePool` object. 272 | @param database The `FMDatabase` object. 273 | 274 | */ 275 | 276 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; 277 | 278 | @end 279 | 280 | NS_ASSUME_NONNULL_END 281 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabasePool.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabasePool.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #if FMDB_SQLITE_STANDALONE 10 | #import 11 | #else 12 | #import 13 | #endif 14 | 15 | #import "FMDatabasePool.h" 16 | #import "FMDatabase.h" 17 | 18 | typedef NS_ENUM(NSInteger, FMDBTransaction) { 19 | FMDBTransactionExclusive, 20 | FMDBTransactionDeferred, 21 | FMDBTransactionImmediate, 22 | }; 23 | 24 | @interface FMDatabasePool () { 25 | dispatch_queue_t _lockQueue; 26 | 27 | NSMutableArray *_databaseInPool; 28 | NSMutableArray *_databaseOutPool; 29 | } 30 | 31 | - (void)pushDatabaseBackInPool:(FMDatabase*)db; 32 | - (FMDatabase*)db; 33 | 34 | @end 35 | 36 | 37 | @implementation FMDatabasePool 38 | @synthesize path=_path; 39 | @synthesize delegate=_delegate; 40 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; 41 | @synthesize openFlags=_openFlags; 42 | 43 | 44 | + (instancetype)databasePoolWithPath:(NSString *)aPath { 45 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); 46 | } 47 | 48 | + (instancetype)databasePoolWithURL:(NSURL *)url { 49 | return FMDBReturnAutoreleased([[self alloc] initWithPath:url.path]); 50 | } 51 | 52 | + (instancetype)databasePoolWithPath:(NSString *)aPath flags:(int)openFlags { 53 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); 54 | } 55 | 56 | + (instancetype)databasePoolWithURL:(NSURL *)url flags:(int)openFlags { 57 | return FMDBReturnAutoreleased([[self alloc] initWithPath:url.path flags:openFlags]); 58 | } 59 | 60 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags vfs:(NSString *)vfsName { 61 | return [self initWithPath:url.path flags:openFlags vfs:vfsName]; 62 | } 63 | 64 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 65 | 66 | self = [super init]; 67 | 68 | if (self != nil) { 69 | _path = [aPath copy]; 70 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 71 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]); 72 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); 73 | _openFlags = openFlags; 74 | _vfsName = [vfsName copy]; 75 | } 76 | 77 | return self; 78 | } 79 | 80 | - (instancetype)initWithPath:(NSString *)aPath flags:(int)openFlags { 81 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 82 | } 83 | 84 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags { 85 | return [self initWithPath:url.path flags:openFlags vfs:nil]; 86 | } 87 | 88 | - (instancetype)initWithPath:(NSString*)aPath { 89 | // default flags for sqlite3_open 90 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 91 | } 92 | 93 | - (instancetype)initWithURL:(NSURL *)url { 94 | return [self initWithPath:url.path]; 95 | } 96 | 97 | - (instancetype)init { 98 | return [self initWithPath:nil]; 99 | } 100 | 101 | + (Class)databaseClass { 102 | return [FMDatabase class]; 103 | } 104 | 105 | - (void)dealloc { 106 | 107 | _delegate = 0x00; 108 | FMDBRelease(_path); 109 | FMDBRelease(_databaseInPool); 110 | FMDBRelease(_databaseOutPool); 111 | FMDBRelease(_vfsName); 112 | 113 | if (_lockQueue) { 114 | FMDBDispatchQueueRelease(_lockQueue); 115 | _lockQueue = 0x00; 116 | } 117 | #if ! __has_feature(objc_arc) 118 | [super dealloc]; 119 | #endif 120 | } 121 | 122 | 123 | - (void)executeLocked:(void (^)(void))aBlock { 124 | dispatch_sync(_lockQueue, aBlock); 125 | } 126 | 127 | - (void)pushDatabaseBackInPool:(FMDatabase*)db { 128 | 129 | if (!db) { // db can be null if we set an upper bound on the # of databases to create. 130 | return; 131 | } 132 | 133 | [self executeLocked:^() { 134 | 135 | if ([self->_databaseInPool containsObject:db]) { 136 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; 137 | } 138 | 139 | [self->_databaseInPool addObject:db]; 140 | [self->_databaseOutPool removeObject:db]; 141 | 142 | }]; 143 | } 144 | 145 | - (FMDatabase*)db { 146 | 147 | __block FMDatabase *db; 148 | 149 | 150 | [self executeLocked:^() { 151 | db = [self->_databaseInPool lastObject]; 152 | 153 | BOOL shouldNotifyDelegate = NO; 154 | 155 | if (db) { 156 | [self->_databaseOutPool addObject:db]; 157 | [self->_databaseInPool removeLastObject]; 158 | } 159 | else { 160 | 161 | if (self->_maximumNumberOfDatabasesToCreate) { 162 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; 163 | 164 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { 165 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); 166 | return; 167 | } 168 | } 169 | 170 | db = [[[self class] databaseClass] databaseWithPath:self->_path]; 171 | shouldNotifyDelegate = YES; 172 | } 173 | 174 | //This ensures that the db is opened before returning 175 | #if SQLITE_VERSION_NUMBER >= 3005000 176 | BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName]; 177 | #else 178 | BOOL success = [db open]; 179 | #endif 180 | if (success) { 181 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { 182 | [db close]; 183 | db = 0x00; 184 | } 185 | else { 186 | //It should not get added in the pool twice if lastObject was found 187 | if (![self->_databaseOutPool containsObject:db]) { 188 | [self->_databaseOutPool addObject:db]; 189 | 190 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { 191 | [self->_delegate databasePool:self didAddDatabase:db]; 192 | } 193 | } 194 | } 195 | } 196 | else { 197 | NSLog(@"Could not open up the database at path %@", self->_path); 198 | db = 0x00; 199 | } 200 | }]; 201 | 202 | return db; 203 | } 204 | 205 | - (NSUInteger)countOfCheckedInDatabases { 206 | 207 | __block NSUInteger count; 208 | 209 | [self executeLocked:^() { 210 | count = [self->_databaseInPool count]; 211 | }]; 212 | 213 | return count; 214 | } 215 | 216 | - (NSUInteger)countOfCheckedOutDatabases { 217 | 218 | __block NSUInteger count; 219 | 220 | [self executeLocked:^() { 221 | count = [self->_databaseOutPool count]; 222 | }]; 223 | 224 | return count; 225 | } 226 | 227 | - (NSUInteger)countOfOpenDatabases { 228 | __block NSUInteger count; 229 | 230 | [self executeLocked:^() { 231 | count = [self->_databaseOutPool count] + [self->_databaseInPool count]; 232 | }]; 233 | 234 | return count; 235 | } 236 | 237 | - (void)releaseAllDatabases { 238 | [self executeLocked:^() { 239 | [self->_databaseOutPool removeAllObjects]; 240 | [self->_databaseInPool removeAllObjects]; 241 | }]; 242 | } 243 | 244 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block { 245 | 246 | FMDatabase *db = [self db]; 247 | 248 | block(db); 249 | 250 | [self pushDatabaseBackInPool:db]; 251 | } 252 | 253 | - (void)beginTransaction:(FMDBTransaction)transaction withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 254 | 255 | BOOL shouldRollback = NO; 256 | 257 | FMDatabase *db = [self db]; 258 | 259 | switch (transaction) { 260 | case FMDBTransactionExclusive: 261 | [db beginTransaction]; 262 | break; 263 | case FMDBTransactionDeferred: 264 | [db beginDeferredTransaction]; 265 | break; 266 | case FMDBTransactionImmediate: 267 | [db beginImmediateTransaction]; 268 | break; 269 | } 270 | 271 | 272 | block(db, &shouldRollback); 273 | 274 | if (shouldRollback) { 275 | [db rollback]; 276 | } 277 | else { 278 | [db commit]; 279 | } 280 | 281 | [self pushDatabaseBackInPool:db]; 282 | } 283 | 284 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 285 | [self beginTransaction:FMDBTransactionExclusive withBlock:block]; 286 | } 287 | 288 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 289 | [self beginTransaction:FMDBTransactionDeferred withBlock:block]; 290 | } 291 | 292 | - (void)inExclusiveTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 293 | [self beginTransaction:FMDBTransactionExclusive withBlock:block]; 294 | } 295 | 296 | - (void)inImmediateTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 297 | [self beginTransaction:FMDBTransactionImmediate withBlock:block]; 298 | } 299 | 300 | - (NSError*)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 301 | #if SQLITE_VERSION_NUMBER >= 3007000 302 | static unsigned long savePointIdx = 0; 303 | 304 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 305 | 306 | BOOL shouldRollback = NO; 307 | 308 | FMDatabase *db = [self db]; 309 | 310 | NSError *err = 0x00; 311 | 312 | if (![db startSavePointWithName:name error:&err]) { 313 | [self pushDatabaseBackInPool:db]; 314 | return err; 315 | } 316 | 317 | block(db, &shouldRollback); 318 | 319 | if (shouldRollback) { 320 | // We need to rollback and release this savepoint to remove it 321 | [db rollbackToSavePointWithName:name error:&err]; 322 | } 323 | [db releaseSavePointWithName:name error:&err]; 324 | 325 | [self pushDatabaseBackInPool:db]; 326 | 327 | return err; 328 | #else 329 | NSString *errorMessage = NSLocalizedStringFromTable(@"Save point functions require SQLite 3.7", @"FMDB", nil); 330 | if (self.logsErrors) NSLog(@"%@", errorMessage); 331 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 332 | #endif 333 | } 334 | 335 | @end 336 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabaseQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseQueue.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import "FMDatabaseQueue.h" 10 | #import "FMDatabase.h" 11 | 12 | #if FMDB_SQLITE_STANDALONE 13 | #import 14 | #else 15 | #import 16 | #endif 17 | 18 | typedef NS_ENUM(NSInteger, FMDBTransaction) { 19 | FMDBTransactionExclusive, 20 | FMDBTransactionDeferred, 21 | FMDBTransactionImmediate, 22 | }; 23 | 24 | /* 25 | 26 | Note: we call [self retain]; before using dispatch_sync, just incase 27 | FMDatabaseQueue is released on another thread and we're in the middle of doing 28 | something in dispatch_sync 29 | 30 | */ 31 | 32 | /* 33 | * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. 34 | * This in turn is used for deadlock detection by seeing if inDatabase: is called on 35 | * the queue's dispatch queue, which should not happen and causes a deadlock. 36 | */ 37 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; 38 | 39 | @interface FMDatabaseQueue () { 40 | dispatch_queue_t _queue; 41 | FMDatabase *_db; 42 | } 43 | @end 44 | 45 | @implementation FMDatabaseQueue 46 | 47 | + (instancetype)databaseQueueWithPath:(NSString *)aPath { 48 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; 49 | 50 | FMDBAutorelease(q); 51 | 52 | return q; 53 | } 54 | 55 | + (instancetype)databaseQueueWithURL:(NSURL *)url { 56 | return [self databaseQueueWithPath:url.path]; 57 | } 58 | 59 | + (instancetype)databaseQueueWithPath:(NSString *)aPath flags:(int)openFlags { 60 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; 61 | 62 | FMDBAutorelease(q); 63 | 64 | return q; 65 | } 66 | 67 | + (instancetype)databaseQueueWithURL:(NSURL *)url flags:(int)openFlags { 68 | return [self databaseQueueWithPath:url.path flags:openFlags]; 69 | } 70 | 71 | + (Class)databaseClass { 72 | return [FMDatabase class]; 73 | } 74 | 75 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags vfs:(NSString *)vfsName { 76 | return [self initWithPath:url.path flags:openFlags vfs:vfsName]; 77 | } 78 | 79 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { 80 | self = [super init]; 81 | 82 | if (self != nil) { 83 | 84 | _db = [[[self class] databaseClass] databaseWithPath:aPath]; 85 | FMDBRetain(_db); 86 | 87 | #if SQLITE_VERSION_NUMBER >= 3005000 88 | BOOL success = [_db openWithFlags:openFlags vfs:vfsName]; 89 | #else 90 | BOOL success = [_db open]; 91 | #endif 92 | if (!success) { 93 | NSLog(@"Could not create database queue for path %@", aPath); 94 | FMDBRelease(self); 95 | return 0x00; 96 | } 97 | 98 | _path = FMDBReturnRetained(aPath); 99 | 100 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 101 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 102 | _openFlags = openFlags; 103 | _vfsName = [vfsName copy]; 104 | } 105 | 106 | return self; 107 | } 108 | 109 | - (instancetype)initWithPath:(NSString *)aPath flags:(int)openFlags { 110 | return [self initWithPath:aPath flags:openFlags vfs:nil]; 111 | } 112 | 113 | - (instancetype)initWithURL:(NSURL *)url flags:(int)openFlags { 114 | return [self initWithPath:url.path flags:openFlags vfs:nil]; 115 | } 116 | 117 | - (instancetype)initWithURL:(NSURL *)url { 118 | return [self initWithPath:url.path]; 119 | } 120 | 121 | - (instancetype)initWithPath:(NSString *)aPath { 122 | // default flags for sqlite3_open 123 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil]; 124 | } 125 | 126 | - (instancetype)init { 127 | return [self initWithPath:nil]; 128 | } 129 | 130 | - (void)dealloc { 131 | FMDBRelease(_db); 132 | FMDBRelease(_path); 133 | FMDBRelease(_vfsName); 134 | 135 | if (_queue) { 136 | FMDBDispatchQueueRelease(_queue); 137 | _queue = 0x00; 138 | } 139 | #if ! __has_feature(objc_arc) 140 | [super dealloc]; 141 | #endif 142 | } 143 | 144 | - (void)close { 145 | FMDBRetain(self); 146 | dispatch_sync(_queue, ^() { 147 | [self->_db close]; 148 | FMDBRelease(_db); 149 | self->_db = 0x00; 150 | }); 151 | FMDBRelease(self); 152 | } 153 | 154 | - (void)interrupt { 155 | [[self database] interrupt]; 156 | } 157 | 158 | - (FMDatabase*)database { 159 | if (![_db isOpen]) { 160 | if (!_db) { 161 | _db = FMDBReturnRetained([[[self class] databaseClass] databaseWithPath:_path]); 162 | } 163 | 164 | #if SQLITE_VERSION_NUMBER >= 3005000 165 | BOOL success = [_db openWithFlags:_openFlags vfs:_vfsName]; 166 | #else 167 | BOOL success = [_db open]; 168 | #endif 169 | if (!success) { 170 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); 171 | FMDBRelease(_db); 172 | _db = 0x00; 173 | return 0x00; 174 | } 175 | } 176 | 177 | return _db; 178 | } 179 | 180 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block { 181 | #ifndef NDEBUG 182 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue 183 | * and then check it against self to make sure we're not about to deadlock. */ 184 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 185 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); 186 | #endif 187 | 188 | FMDBRetain(self); 189 | 190 | dispatch_sync(_queue, ^() { 191 | 192 | FMDatabase *db = [self database]; 193 | 194 | block(db); 195 | 196 | if ([db hasOpenResultSets]) { 197 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); 198 | 199 | #if defined(DEBUG) && DEBUG 200 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); 201 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { 202 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; 203 | NSLog(@"query: '%@'", [rs query]); 204 | } 205 | #endif 206 | } 207 | }); 208 | 209 | FMDBRelease(self); 210 | } 211 | 212 | - (void)beginTransaction:(FMDBTransaction)transaction withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 213 | FMDBRetain(self); 214 | dispatch_sync(_queue, ^() { 215 | 216 | BOOL shouldRollback = NO; 217 | 218 | switch (transaction) { 219 | case FMDBTransactionExclusive: 220 | [[self database] beginTransaction]; 221 | break; 222 | case FMDBTransactionDeferred: 223 | [[self database] beginDeferredTransaction]; 224 | break; 225 | case FMDBTransactionImmediate: 226 | [[self database] beginImmediateTransaction]; 227 | break; 228 | } 229 | 230 | block([self database], &shouldRollback); 231 | 232 | if (shouldRollback) { 233 | [[self database] rollback]; 234 | } 235 | else { 236 | [[self database] commit]; 237 | } 238 | }); 239 | 240 | FMDBRelease(self); 241 | } 242 | 243 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 244 | [self beginTransaction:FMDBTransactionExclusive withBlock:block]; 245 | } 246 | 247 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 248 | [self beginTransaction:FMDBTransactionDeferred withBlock:block]; 249 | } 250 | 251 | - (void)inExclusiveTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 252 | [self beginTransaction:FMDBTransactionExclusive withBlock:block]; 253 | } 254 | 255 | - (void)inImmediateTransaction:(__attribute__((noescape)) void (^)(FMDatabase * _Nonnull, BOOL * _Nonnull))block { 256 | [self beginTransaction:FMDBTransactionImmediate withBlock:block]; 257 | } 258 | 259 | - (NSError*)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block { 260 | #if SQLITE_VERSION_NUMBER >= 3007000 261 | static unsigned long savePointIdx = 0; 262 | __block NSError *err = 0x00; 263 | FMDBRetain(self); 264 | dispatch_sync(_queue, ^() { 265 | 266 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 267 | 268 | BOOL shouldRollback = NO; 269 | 270 | if ([[self database] startSavePointWithName:name error:&err]) { 271 | 272 | block([self database], &shouldRollback); 273 | 274 | if (shouldRollback) { 275 | // We need to rollback and release this savepoint to remove it 276 | [[self database] rollbackToSavePointWithName:name error:&err]; 277 | } 278 | [[self database] releaseSavePointWithName:name error:&err]; 279 | 280 | } 281 | }); 282 | FMDBRelease(self); 283 | return err; 284 | #else 285 | NSString *errorMessage = NSLocalizedStringFromTable(@"Save point functions require SQLite 3.7", @"FMDB", nil); 286 | if (_db.logsErrors) NSLog(@"%@", errorMessage); 287 | return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; 288 | #endif 289 | } 290 | 291 | - (BOOL)checkpoint:(FMDBCheckpointMode)mode error:(NSError * __autoreleasing *)error 292 | { 293 | return [self checkpoint:mode name:nil logFrameCount:NULL checkpointCount:NULL error:error]; 294 | } 295 | 296 | - (BOOL)checkpoint:(FMDBCheckpointMode)mode name:(NSString *)name error:(NSError * __autoreleasing *)error 297 | { 298 | return [self checkpoint:mode name:name logFrameCount:NULL checkpointCount:NULL error:error]; 299 | } 300 | 301 | - (BOOL)checkpoint:(FMDBCheckpointMode)mode name:(NSString *)name logFrameCount:(int * _Nullable)logFrameCount checkpointCount:(int * _Nullable)checkpointCount error:(NSError * __autoreleasing _Nullable * _Nullable)error 302 | { 303 | __block BOOL result; 304 | __block NSError *blockError; 305 | 306 | FMDBRetain(self); 307 | dispatch_sync(_queue, ^() { 308 | result = [self.database checkpoint:mode name:name logFrameCount:NULL checkpointCount:NULL error:&blockError]; 309 | }); 310 | FMDBRelease(self); 311 | 312 | if (error) { 313 | *error = blockError; 314 | } 315 | return result; 316 | } 317 | 318 | @end 319 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseQueue.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDatabase.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. 15 | 16 | Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. 17 | 18 | Instead, use `FMDatabaseQueue`. Here's how to use it: 19 | 20 | First, make your queue. 21 | 22 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 23 | 24 | Then use it like so: 25 | 26 | [queue inDatabase:^(FMDatabase *db) { 27 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 28 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 29 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 30 | 31 | FMResultSet *rs = [db executeQuery:@"select * from foo"]; 32 | while ([rs next]) { 33 | //… 34 | } 35 | }]; 36 | 37 | An easy way to wrap things up in a transaction can be done like this: 38 | 39 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 40 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 41 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 42 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 43 | 44 | if (whoopsSomethingWrongHappened) { 45 | *rollback = YES; 46 | return; 47 | } 48 | // etc… 49 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; 50 | }]; 51 | 52 | `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. 53 | 54 | ### See also 55 | 56 | - `` 57 | 58 | @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. 59 | 60 | @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. 61 | 62 | */ 63 | 64 | @interface FMDatabaseQueue : NSObject 65 | /** Path of database */ 66 | 67 | @property (atomic, retain, nullable) NSString *path; 68 | 69 | /** Open flags */ 70 | 71 | @property (atomic, readonly) int openFlags; 72 | 73 | /** Custom virtual file system name */ 74 | 75 | @property (atomic, copy, nullable) NSString *vfsName; 76 | 77 | ///---------------------------------------------------- 78 | /// @name Initialization, opening, and closing of queue 79 | ///---------------------------------------------------- 80 | 81 | /** Create queue using path. 82 | 83 | @param aPath The file path of the database. 84 | 85 | @return The `FMDatabaseQueue` object. `nil` on error. 86 | */ 87 | 88 | + (nullable instancetype)databaseQueueWithPath:(NSString * _Nullable)aPath; 89 | 90 | /** Create queue using file URL. 91 | 92 | @param url The file `NSURL` of the database. 93 | 94 | @return The `FMDatabaseQueue` object. `nil` on error. 95 | */ 96 | 97 | + (nullable instancetype)databaseQueueWithURL:(NSURL * _Nullable)url; 98 | 99 | /** Create queue using path and specified flags. 100 | 101 | @param aPath The file path of the database. 102 | @param openFlags Flags passed to the openWithFlags method of the database. 103 | 104 | @return The `FMDatabaseQueue` object. `nil` on error. 105 | */ 106 | + (nullable instancetype)databaseQueueWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 107 | 108 | /** Create queue using file URL and specified flags. 109 | 110 | @param url The file `NSURL` of the database. 111 | @param openFlags Flags passed to the openWithFlags method of the database. 112 | 113 | @return The `FMDatabaseQueue` object. `nil` on error. 114 | */ 115 | + (nullable instancetype)databaseQueueWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 116 | 117 | /** Create queue using path. 118 | 119 | @param aPath The file path of the database. 120 | 121 | @return The `FMDatabaseQueue` object. `nil` on error. 122 | */ 123 | 124 | - (nullable instancetype)initWithPath:(NSString * _Nullable)aPath; 125 | 126 | /** Create queue using file URL. 127 | 128 | @param url The file `NSURL of the database. 129 | 130 | @return The `FMDatabaseQueue` object. `nil` on error. 131 | */ 132 | 133 | - (nullable instancetype)initWithURL:(NSURL * _Nullable)url; 134 | 135 | /** Create queue using path and specified flags. 136 | 137 | @param aPath The file path of the database. 138 | @param openFlags Flags passed to the openWithFlags method of the database. 139 | 140 | @return The `FMDatabaseQueue` object. `nil` on error. 141 | */ 142 | 143 | - (nullable instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags; 144 | 145 | /** Create queue using file URL and specified flags. 146 | 147 | @param url The file path of the database. 148 | @param openFlags Flags passed to the openWithFlags method of the database. 149 | 150 | @return The `FMDatabaseQueue` object. `nil` on error. 151 | */ 152 | 153 | - (nullable instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags; 154 | 155 | /** Create queue using path and specified flags. 156 | 157 | @param aPath The file path of the database. 158 | @param openFlags Flags passed to the openWithFlags method of the database 159 | @param vfsName The name of a custom virtual file system 160 | 161 | @return The `FMDatabaseQueue` object. `nil` on error. 162 | */ 163 | 164 | - (nullable instancetype)initWithPath:(NSString * _Nullable)aPath flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 165 | 166 | /** Create queue using file URL and specified flags. 167 | 168 | @param url The file `NSURL of the database. 169 | @param openFlags Flags passed to the openWithFlags method of the database 170 | @param vfsName The name of a custom virtual file system 171 | 172 | @return The `FMDatabaseQueue` object. `nil` on error. 173 | */ 174 | 175 | - (nullable instancetype)initWithURL:(NSURL * _Nullable)url flags:(int)openFlags vfs:(NSString * _Nullable)vfsName; 176 | 177 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 178 | 179 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 180 | 181 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 182 | */ 183 | 184 | + (Class)databaseClass; 185 | 186 | /** Close database used by queue. */ 187 | 188 | - (void)close; 189 | 190 | /** Interupt pending database operation. */ 191 | 192 | - (void)interrupt; 193 | 194 | ///----------------------------------------------- 195 | /// @name Dispatching database operations to queue 196 | ///----------------------------------------------- 197 | 198 | /** Synchronously perform database operations on queue. 199 | 200 | @param block The code to be run on the queue of `FMDatabaseQueue` 201 | */ 202 | 203 | - (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block; 204 | 205 | /** Synchronously perform database operations on queue, using transactions. 206 | 207 | @param block The code to be run on the queue of `FMDatabaseQueue` 208 | 209 | @warning Unlike SQLite's `BEGIN TRANSACTION`, this method currently performs 210 | an exclusive transaction, not a deferred transaction. This behavior 211 | is likely to change in future versions of FMDB, whereby this method 212 | will likely eventually adopt standard SQLite behavior and perform 213 | deferred transactions. If you really need exclusive tranaction, it is 214 | recommended that you use `inExclusiveTransaction`, instead, not only 215 | to make your intent explicit, but also to future-proof your code. 216 | 217 | */ 218 | 219 | - (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 220 | 221 | /** Synchronously perform database operations on queue, using deferred transactions. 222 | 223 | @param block The code to be run on the queue of `FMDatabaseQueue` 224 | */ 225 | 226 | - (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 227 | 228 | /** Synchronously perform database operations on queue, using exclusive transactions. 229 | 230 | @param block The code to be run on the queue of `FMDatabaseQueue` 231 | */ 232 | 233 | - (void)inExclusiveTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 234 | 235 | /** Synchronously perform database operations on queue, using immediate transactions. 236 | 237 | @param block The code to be run on the queue of `FMDatabaseQueue` 238 | */ 239 | 240 | - (void)inImmediateTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 241 | 242 | ///----------------------------------------------- 243 | /// @name Dispatching database operations to queue 244 | ///----------------------------------------------- 245 | 246 | /** Synchronously perform database operations using save point. 247 | 248 | @param block The code to be run on the queue of `FMDatabaseQueue` 249 | */ 250 | 251 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. 252 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead. 253 | - (NSError * _Nullable)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block; 254 | 255 | ///----------------- 256 | /// @name Checkpoint 257 | ///----------------- 258 | 259 | /** Performs a WAL checkpoint 260 | 261 | @param checkpointMode The checkpoint mode for sqlite3_wal_checkpoint_v2 262 | @param error The NSError corresponding to the error, if any. 263 | @return YES on success, otherwise NO. 264 | */ 265 | - (BOOL)checkpoint:(FMDBCheckpointMode)checkpointMode error:(NSError * _Nullable *)error; 266 | 267 | /** Performs a WAL checkpoint 268 | 269 | @param checkpointMode The checkpoint mode for sqlite3_wal_checkpoint_v2 270 | @param name The db name for sqlite3_wal_checkpoint_v2 271 | @param error The NSError corresponding to the error, if any. 272 | @return YES on success, otherwise NO. 273 | */ 274 | - (BOOL)checkpoint:(FMDBCheckpointMode)checkpointMode name:(NSString * _Nullable)name error:(NSError * _Nullable *)error; 275 | 276 | /** Performs a WAL checkpoint 277 | 278 | @param checkpointMode The checkpoint mode for sqlite3_wal_checkpoint_v2 279 | @param name The db name for sqlite3_wal_checkpoint_v2 280 | @param error The NSError corresponding to the error, if any. 281 | @param logFrameCount If not NULL, then this is set to the total number of frames in the log file or to -1 if the checkpoint could not run because of an error or because the database is not in WAL mode. 282 | @param checkpointCount If not NULL, then this is set to the total number of checkpointed frames in the log file (including any that were already checkpointed before the function was called) or to -1 if the checkpoint could not run due to an error or because the database is not in WAL mode. 283 | @return YES on success, otherwise NO. 284 | */ 285 | - (BOOL)checkpoint:(FMDBCheckpointMode)checkpointMode name:(NSString * _Nullable)name logFrameCount:(int * _Nullable)logFrameCount checkpointCount:(int * _Nullable)checkpointCount error:(NSError * _Nullable *)error; 286 | 287 | @end 288 | 289 | NS_ASSUME_NONNULL_END 290 | -------------------------------------------------------------------------------- /Classes/FMDTSelectCommand.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDTQuery.m 3 | // FMDataTable 4 | // 5 | // Created by bing.hao on 16/3/8. 6 | // Copyright © 2016年 bing.hao. All rights reserved. 7 | // 8 | 9 | #import "FMDTSelectCommand.h" 10 | 11 | @interface FMDTSelectCommand () 12 | 13 | @property (nonatomic, strong) NSMutableArray *whereArray; 14 | @property (nonatomic, strong) NSMutableArray *orderArray; 15 | @property (nonatomic, strong) NSMutableArray *groupArray; 16 | 17 | @end 18 | 19 | @implementation FMDTSelectCommand 20 | @synthesize schema = _schema; 21 | 22 | - (instancetype)init 23 | { 24 | self = [super init]; 25 | if (self) { 26 | self.whereArray = [NSMutableArray new]; 27 | self.orderArray = [NSMutableArray new]; 28 | self.groupArray = [NSMutableArray new]; 29 | } 30 | return self; 31 | } 32 | 33 | - (instancetype)initWithSchema:(FMDTSchemaTable *)schema { 34 | self = [self init]; 35 | if (self) { 36 | _schema = schema; 37 | } 38 | return self; 39 | } 40 | 41 | - (FMDTSelectCommand *)where:(NSString *)key equalTo:(id)object { 42 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ = '%@'", key, object]]; 43 | return self; 44 | } 45 | 46 | - (FMDTSelectCommand *)where:(NSString *)key notEqualTo:(id)object { 47 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ <> '%@'", key, object]]; 48 | return self; 49 | } 50 | 51 | - (FMDTSelectCommand *)where:(NSString *)key lessThan:(id)object { 52 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ < '%@'", key, object]]; 53 | return self; 54 | } 55 | 56 | - (FMDTSelectCommand *)where:(NSString *)key lessThanOrEqualTo:(id)object { 57 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ <= '%@'", key, object]]; 58 | return self; 59 | } 60 | 61 | - (FMDTSelectCommand *)where:(NSString *)key greaterThan:(id)object { 62 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ > '%@'", key, object]]; 63 | return self; 64 | } 65 | 66 | - (FMDTSelectCommand *)where:(NSString *)key greaterThanOrEqualTo:(id)object { 67 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ >= '%@'", key, object]]; 68 | return self; 69 | } 70 | 71 | - (FMDTSelectCommand *)where:(NSString *)key containedIn:(NSArray *)array { 72 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 73 | return self; 74 | } 75 | 76 | - (FMDTSelectCommand *)where:(NSString *)key notContainedIn:(NSArray *)array { 77 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ not in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 78 | return self; 79 | } 80 | 81 | - (FMDTSelectCommand *)where:(NSString *)key containsString:(NSString *)string { 82 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ like '%@'", key, string]]; 83 | return self; 84 | } 85 | 86 | - (FMDTSelectCommand *)where:(NSString *)key notContainsString:(NSString *)string { 87 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ not like '%@'", key, string]]; 88 | return self; 89 | } 90 | 91 | - (FMDTSelectCommand *)whereIsNull:(NSString *)key { 92 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ is null", key]]; 93 | return self; 94 | } 95 | 96 | - (FMDTSelectCommand *)whereIsNotNull:(NSString *)key { 97 | [self.whereArray addObject:[NSString stringWithFormat:@"and %@ is not null", key]]; 98 | return self; 99 | } 100 | 101 | - (FMDTSelectCommand *)whereOr:(NSString *)key equalTo:(id)object { 102 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ = '%@'", key, object]]; 103 | return self; 104 | } 105 | 106 | - (FMDTSelectCommand *)whereOr:(NSString *)key notEqualTo:(id)object { 107 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ <> '%@'", key, object]]; 108 | return self; 109 | } 110 | 111 | - (FMDTSelectCommand *)whereOr:(NSString *)key lessThan:(id)object { 112 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ < '%@'", key, object]]; 113 | return self; 114 | } 115 | 116 | - (FMDTSelectCommand *)whereOr:(NSString *)key lessThanOrEqualTo:(id)object { 117 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ <= '%@'", key, object]]; 118 | return self; 119 | } 120 | 121 | - (FMDTSelectCommand *)whereOr:(NSString *)key greaterThan:(id)object { 122 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ > '%@'", key, object]]; 123 | return self; 124 | } 125 | 126 | - (FMDTSelectCommand *)whereOr:(NSString *)key greaterThanOrEqualTo:(id)object { 127 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ >= '%@'", key, object]]; 128 | return self; 129 | } 130 | 131 | - (FMDTSelectCommand *)whereOr:(NSString *)key containedIn:(NSArray *)array { 132 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 133 | return self; 134 | } 135 | 136 | - (FMDTSelectCommand *)whereOr:(NSString *)key notContainedIn:(NSArray *)array { 137 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ not in ('%@')", key, [array componentsJoinedByString:@"','"]]]; 138 | return self; 139 | } 140 | 141 | - (FMDTSelectCommand *)whereOr:(NSString *)key containsString:(NSString *)string { 142 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ like '%@'", key, string]]; 143 | return self; 144 | } 145 | 146 | - (FMDTSelectCommand *)whereOr:(NSString *)key notContainsString:(NSString *)string { 147 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ not like '%@'", key, string]]; 148 | return self; 149 | } 150 | 151 | - (FMDTSelectCommand *)whereOrIsNull:(NSString *)key { 152 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ is null", key]]; 153 | return self; 154 | } 155 | 156 | - (FMDTSelectCommand *)whereOrIsNotNull:(NSString *)key { 157 | [self.whereArray addObject:[NSString stringWithFormat:@"or %@ is not null", key]]; 158 | return self; 159 | } 160 | 161 | - (FMDTSelectCommand *)orderByDescending:(NSString *)key { 162 | [self.orderArray addObject:[NSString stringWithFormat:@" %@ desc", key]]; 163 | return self; 164 | } 165 | 166 | - (FMDTSelectCommand *)orderByAscending:(NSString *)key { 167 | [self.orderArray addObject:[NSString stringWithFormat:@" %@ asc", key]]; 168 | return self; 169 | } 170 | 171 | - (FMDTSelectCommand *)groupBy:(NSString *)key { 172 | [self.groupArray addObject:key]; 173 | return self; 174 | } 175 | 176 | - (NSArray *)fetchArray { 177 | return [self fetchArrayWithDb:nil]; 178 | } 179 | 180 | - (NSArray *)fetchArrayWithDb:(FMDatabase *)db { 181 | 182 | NSString *sql = [self runSql:@"*"]; 183 | 184 | NSMutableArray *resultArray = [NSMutableArray new]; 185 | 186 | if (db == nil) { 187 | db = [FMDatabase databaseWithPath:self.schema.storage]; 188 | } 189 | 190 | [db open]; 191 | 192 | FMResultSet *set = [db executeQuery:sql]; 193 | while ([set next]) { 194 | id obj = [NSClassFromString(self.schema.className) new]; 195 | 196 | for (FMDTSchemaField *entry in self.schema.fields) { 197 | if (![set columnIsNull:entry.name]) { 198 | if (FMDT_IsCollectionObject(entry.objType)) { 199 | NSString *jsonStr = [set stringForColumn:entry.name]; 200 | id data = [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] 201 | options:NSJSONReadingAllowFragments 202 | error:nil]; 203 | if (data) { 204 | [obj setValue:data forKeyPath:entry.objName]; 205 | } 206 | } else if (FMDT_IsDateObject(entry.objType)) { 207 | NSNumber *dateNum = [set objectForColumnName:entry.name]; 208 | NSDate *date = [NSDate dateWithTimeIntervalSince1970:[dateNum doubleValue]]; 209 | if (date) { 210 | [obj setValue:date forKeyPath:entry.objName]; 211 | } 212 | } else { 213 | id val = [set objectForColumnName:entry.name]; 214 | [obj setValue:val forKeyPath:entry.objName]; 215 | } 216 | } 217 | } 218 | [resultArray addObject:obj]; 219 | } 220 | [db close]; 221 | [self removeCacheAllObject]; 222 | return resultArray; 223 | } 224 | 225 | - (void)fetchArrayInBackground:(void (^)(NSArray *))callback { 226 | 227 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 228 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 229 | [queue inDatabase:^(FMDatabase *db) { 230 | if (callback) { 231 | callback([self fetchArrayWithDb:db]); 232 | } 233 | }]; 234 | [queue close]; 235 | }); 236 | } 237 | 238 | - (id)fetchObject { 239 | return [[self fetchArray] firstObject]; 240 | } 241 | 242 | - (void)fetchObjectInBackground:(void (^)(id))callback { 243 | 244 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 245 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 246 | [queue inDatabase:^(FMDatabase *db) { 247 | if (callback) { 248 | callback([[self fetchArrayWithDb:db] firstObject]); 249 | } 250 | }]; 251 | [queue close]; 252 | }); 253 | 254 | } 255 | 256 | - (NSInteger)fetchCount { 257 | return [self fetchCountWithDb:nil]; 258 | } 259 | 260 | - (NSInteger)fetchCountWithDb:(FMDatabase *)db { 261 | NSString *sql = [self runSql:@"count(*)"]; 262 | 263 | NSInteger count = 0; 264 | if (db == nil) { 265 | db = [FMDatabase databaseWithPath:self.schema.storage]; 266 | } 267 | 268 | [db open]; 269 | 270 | FMResultSet *set = [db executeQuery:sql]; 271 | if ([set next]) { 272 | count = [set intForColumnIndex:0]; 273 | } 274 | 275 | [db close]; 276 | [self removeCacheAllObject]; 277 | 278 | return count; 279 | } 280 | 281 | - (void)fetchCountInBackground:(void (^)(NSInteger))callback { 282 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 283 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 284 | [queue inDatabase:^(FMDatabase *db) { 285 | NSInteger count = [self fetchCountWithDb:db]; 286 | if (callback) { 287 | callback(count); 288 | } 289 | }]; 290 | [queue close]; 291 | }); 292 | } 293 | 294 | - (NSArray *)fetchArrayWithFields:(NSArray *)fields { 295 | 296 | return [self fetchArrayWithFields:fields db:nil]; 297 | } 298 | 299 | - (void)fetchArrayInBackgroundWithFields:(NSArray *)fields callback:(FMDT_CALLBACK_RESULT_ARRAY)callback { 300 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 301 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.schema.storage]; 302 | [queue inDatabase:^(FMDatabase *db) { 303 | if (callback) { 304 | callback([self fetchArrayWithFields:fields db:db]); 305 | } 306 | }]; 307 | [queue close]; 308 | }); 309 | } 310 | 311 | - (NSArray *)fetchArrayWithFields:(NSArray *)fields db:(FMDatabase *)db { 312 | if (fields == nil || fields.count == 0) { 313 | return nil; 314 | } 315 | NSString *sql = [self runSql:[fields componentsJoinedByString:@","]]; 316 | 317 | if (db == nil) { 318 | db = [FMDatabase databaseWithPath:self.schema.storage]; 319 | } 320 | 321 | [db open]; 322 | 323 | FMResultSet *set = [db executeQuery:sql]; 324 | NSMutableArray *results = [NSMutableArray new]; 325 | 326 | while ([set next]) { 327 | [results addObject:[set resultDictionary]]; 328 | } 329 | 330 | [db close]; 331 | [self removeCacheAllObject]; 332 | 333 | return results; 334 | } 335 | 336 | - (void)removeCacheAllObject { 337 | [self.whereArray removeAllObjects]; 338 | [self.orderArray removeAllObjects]; 339 | [self.groupArray removeAllObjects]; 340 | self.limit = 0; 341 | self.skip = 0; 342 | } 343 | 344 | - (NSString *)runSql:(NSString *)resultField { 345 | 346 | if (self.groupArray.count > 0) { 347 | resultField = [self.groupArray componentsJoinedByString:@","]; 348 | } 349 | 350 | NSMutableString *sql = [[NSMutableString alloc] initWithFormat:@"select %@ from [%@]", resultField, self.schema.tableName]; 351 | if (self.whereArray.count > 0) { 352 | NSString *str = [self.whereArray componentsJoinedByString:@" "]; 353 | if ([str hasPrefix:@"and"]) { 354 | str = [str substringFromIndex:3]; 355 | } else { 356 | str = [str substringFromIndex:2]; 357 | } 358 | [sql appendFormat:@" where %@", str]; 359 | } 360 | if (self.orderArray.count > 0) { 361 | NSString *str = [self.orderArray componentsJoinedByString:@","]; 362 | [sql appendFormat:@" order by %@", str]; 363 | } 364 | if (self.groupArray.count > 0) { 365 | [sql appendFormat:@" group by %@", [self.groupArray componentsJoinedByString:@","]]; 366 | } 367 | NSInteger limit = MAX(self.limit, 0); 368 | NSInteger skip = MAX(self.skip, 0); 369 | if (limit > 0) { 370 | [sql appendFormat:@" limit %@", @(limit)]; 371 | if (skip > 0) { 372 | [sql appendFormat:@" offset %@", @(skip)]; 373 | } 374 | } 375 | return sql; 376 | } 377 | 378 | @end 379 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMResultSet.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | NS_ASSUME_NONNULL_BEGIN 4 | 5 | #ifndef __has_feature // Optional. 6 | #define __has_feature(x) 0 // Compatibility with non-clang compilers. 7 | #endif 8 | 9 | #ifndef NS_RETURNS_NOT_RETAINED 10 | #if __has_feature(attribute_ns_returns_not_retained) 11 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) 12 | #else 13 | #define NS_RETURNS_NOT_RETAINED 14 | #endif 15 | #endif 16 | 17 | @class FMDatabase; 18 | @class FMStatement; 19 | 20 | /** Represents the results of executing a query on an ``. 21 | 22 | ### See also 23 | 24 | - `` 25 | */ 26 | 27 | @interface FMResultSet : NSObject 28 | 29 | @property (nonatomic, retain, nullable) FMDatabase *parentDB; 30 | 31 | ///----------------- 32 | /// @name Properties 33 | ///----------------- 34 | 35 | /** Executed query */ 36 | 37 | @property (atomic, retain, nullable) NSString *query; 38 | 39 | /** `NSMutableDictionary` mapping column names to numeric index */ 40 | 41 | @property (readonly) NSMutableDictionary *columnNameToIndexMap; 42 | 43 | /** `FMStatement` used by result set. */ 44 | 45 | @property (atomic, retain, nullable) FMStatement *statement; 46 | 47 | ///------------------------------------ 48 | /// @name Creating and closing a result set 49 | ///------------------------------------ 50 | 51 | /** Create result set from `` 52 | 53 | @param statement A `` to be performed 54 | 55 | @param aDB A `` to be used 56 | 57 | @return A `FMResultSet` on success; `nil` on failure 58 | */ 59 | 60 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; 61 | 62 | /** Close result set */ 63 | 64 | - (void)close; 65 | 66 | ///--------------------------------------- 67 | /// @name Iterating through the result set 68 | ///--------------------------------------- 69 | 70 | /** Retrieve next row for result set. 71 | 72 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 73 | 74 | @return `YES` if row successfully retrieved; `NO` if end of result set reached 75 | 76 | @see hasAnotherRow 77 | */ 78 | 79 | - (BOOL)next; 80 | 81 | /** Retrieve next row for result set. 82 | 83 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 84 | 85 | @param outErr A 'NSError' object to receive any error object (if any). 86 | 87 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached 88 | 89 | @see hasAnotherRow 90 | */ 91 | 92 | - (BOOL)nextWithError:(NSError * _Nullable *)outErr; 93 | 94 | /** Did the last call to `` succeed in retrieving another row? 95 | 96 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. 97 | 98 | @see next 99 | 100 | @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not. 101 | */ 102 | 103 | - (BOOL)hasAnotherRow; 104 | 105 | ///--------------------------------------------- 106 | /// @name Retrieving information from result set 107 | ///--------------------------------------------- 108 | 109 | /** How many columns in result set 110 | 111 | @return Integer value of the number of columns. 112 | */ 113 | 114 | @property (nonatomic, readonly) int columnCount; 115 | 116 | /** Column index for column name 117 | 118 | @param columnName `NSString` value of the name of the column. 119 | 120 | @return Zero-based index for column. 121 | */ 122 | 123 | - (int)columnIndexForName:(NSString*)columnName; 124 | 125 | /** Column name for column index 126 | 127 | @param columnIdx Zero-based index for column. 128 | 129 | @return columnName `NSString` value of the name of the column. 130 | */ 131 | 132 | - (NSString * _Nullable)columnNameForIndex:(int)columnIdx; 133 | 134 | /** Result set integer value for column. 135 | 136 | @param columnName `NSString` value of the name of the column. 137 | 138 | @return `int` value of the result set's column. 139 | */ 140 | 141 | - (int)intForColumn:(NSString*)columnName; 142 | 143 | /** Result set integer value for column. 144 | 145 | @param columnIdx Zero-based index for column. 146 | 147 | @return `int` value of the result set's column. 148 | */ 149 | 150 | - (int)intForColumnIndex:(int)columnIdx; 151 | 152 | /** Result set `long` value for column. 153 | 154 | @param columnName `NSString` value of the name of the column. 155 | 156 | @return `long` value of the result set's column. 157 | */ 158 | 159 | - (long)longForColumn:(NSString*)columnName; 160 | 161 | /** Result set long value for column. 162 | 163 | @param columnIdx Zero-based index for column. 164 | 165 | @return `long` value of the result set's column. 166 | */ 167 | 168 | - (long)longForColumnIndex:(int)columnIdx; 169 | 170 | /** Result set `long long int` value for column. 171 | 172 | @param columnName `NSString` value of the name of the column. 173 | 174 | @return `long long int` value of the result set's column. 175 | */ 176 | 177 | - (long long int)longLongIntForColumn:(NSString*)columnName; 178 | 179 | /** Result set `long long int` value for column. 180 | 181 | @param columnIdx Zero-based index for column. 182 | 183 | @return `long long int` value of the result set's column. 184 | */ 185 | 186 | - (long long int)longLongIntForColumnIndex:(int)columnIdx; 187 | 188 | /** Result set `unsigned long long int` value for column. 189 | 190 | @param columnName `NSString` value of the name of the column. 191 | 192 | @return `unsigned long long int` value of the result set's column. 193 | */ 194 | 195 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; 196 | 197 | /** Result set `unsigned long long int` value for column. 198 | 199 | @param columnIdx Zero-based index for column. 200 | 201 | @return `unsigned long long int` value of the result set's column. 202 | */ 203 | 204 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; 205 | 206 | /** Result set `BOOL` value for column. 207 | 208 | @param columnName `NSString` value of the name of the column. 209 | 210 | @return `BOOL` value of the result set's column. 211 | */ 212 | 213 | - (BOOL)boolForColumn:(NSString*)columnName; 214 | 215 | /** Result set `BOOL` value for column. 216 | 217 | @param columnIdx Zero-based index for column. 218 | 219 | @return `BOOL` value of the result set's column. 220 | */ 221 | 222 | - (BOOL)boolForColumnIndex:(int)columnIdx; 223 | 224 | /** Result set `double` value for column. 225 | 226 | @param columnName `NSString` value of the name of the column. 227 | 228 | @return `double` value of the result set's column. 229 | 230 | */ 231 | 232 | - (double)doubleForColumn:(NSString*)columnName; 233 | 234 | /** Result set `double` value for column. 235 | 236 | @param columnIdx Zero-based index for column. 237 | 238 | @return `double` value of the result set's column. 239 | 240 | */ 241 | 242 | - (double)doubleForColumnIndex:(int)columnIdx; 243 | 244 | /** Result set `NSString` value for column. 245 | 246 | @param columnName `NSString` value of the name of the column. 247 | 248 | @return String value of the result set's column. 249 | 250 | */ 251 | 252 | - (NSString * _Nullable)stringForColumn:(NSString*)columnName; 253 | 254 | /** Result set `NSString` value for column. 255 | 256 | @param columnIdx Zero-based index for column. 257 | 258 | @return String value of the result set's column. 259 | */ 260 | 261 | - (NSString * _Nullable)stringForColumnIndex:(int)columnIdx; 262 | 263 | /** Result set `NSDate` value for column. 264 | 265 | @param columnName `NSString` value of the name of the column. 266 | 267 | @return Date value of the result set's column. 268 | */ 269 | 270 | - (NSDate * _Nullable)dateForColumn:(NSString*)columnName; 271 | 272 | /** Result set `NSDate` value for column. 273 | 274 | @param columnIdx Zero-based index for column. 275 | 276 | @return Date value of the result set's column. 277 | 278 | */ 279 | 280 | - (NSDate * _Nullable)dateForColumnIndex:(int)columnIdx; 281 | 282 | /** Result set `NSData` value for column. 283 | 284 | This is useful when storing binary data in table (such as image or the like). 285 | 286 | @param columnName `NSString` value of the name of the column. 287 | 288 | @return Data value of the result set's column. 289 | 290 | */ 291 | 292 | - (NSData * _Nullable)dataForColumn:(NSString*)columnName; 293 | 294 | /** Result set `NSData` value for column. 295 | 296 | @param columnIdx Zero-based index for column. 297 | 298 | @return Data value of the result set's column. 299 | */ 300 | 301 | - (NSData * _Nullable)dataForColumnIndex:(int)columnIdx; 302 | 303 | /** Result set `(const unsigned char *)` value for column. 304 | 305 | @param columnName `NSString` value of the name of the column. 306 | 307 | @return `(const unsigned char *)` value of the result set's column. 308 | */ 309 | 310 | - (const unsigned char * _Nullable)UTF8StringForColumn:(NSString*)columnName; 311 | 312 | - (const unsigned char * _Nullable)UTF8StringForColumnName:(NSString*)columnName __deprecated_msg("Use UTF8StringForColumn instead"); 313 | 314 | /** Result set `(const unsigned char *)` value for column. 315 | 316 | @param columnIdx Zero-based index for column. 317 | 318 | @return `(const unsigned char *)` value of the result set's column. 319 | */ 320 | 321 | - (const unsigned char * _Nullable)UTF8StringForColumnIndex:(int)columnIdx; 322 | 323 | /** Result set object for column. 324 | 325 | @param columnName Name of the column. 326 | 327 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 328 | 329 | @see objectForKeyedSubscript: 330 | */ 331 | 332 | - (id _Nullable)objectForColumn:(NSString*)columnName; 333 | 334 | - (id _Nullable)objectForColumnName:(NSString*)columnName __deprecated_msg("Use objectForColumn instead"); 335 | 336 | /** Result set object for column. 337 | 338 | @param columnIdx Zero-based index for column. 339 | 340 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 341 | 342 | @see objectAtIndexedSubscript: 343 | */ 344 | 345 | - (id _Nullable)objectForColumnIndex:(int)columnIdx; 346 | 347 | /** Result set object for column. 348 | 349 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: 350 | 351 | id result = rs[@"employee_name"]; 352 | 353 | This simplified syntax is equivalent to calling: 354 | 355 | id result = [rs objectForKeyedSubscript:@"employee_name"]; 356 | 357 | which is, it turns out, equivalent to calling: 358 | 359 | id result = [rs objectForColumnName:@"employee_name"]; 360 | 361 | @param columnName `NSString` value of the name of the column. 362 | 363 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 364 | */ 365 | 366 | - (id _Nullable)objectForKeyedSubscript:(NSString *)columnName; 367 | 368 | /** Result set object for column. 369 | 370 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: 371 | 372 | id result = rs[0]; 373 | 374 | This simplified syntax is equivalent to calling: 375 | 376 | id result = [rs objectForKeyedSubscript:0]; 377 | 378 | which is, it turns out, equivalent to calling: 379 | 380 | id result = [rs objectForColumnName:0]; 381 | 382 | @param columnIdx Zero-based index for column. 383 | 384 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 385 | */ 386 | 387 | - (id _Nullable)objectAtIndexedSubscript:(int)columnIdx; 388 | 389 | /** Result set `NSData` value for column. 390 | 391 | @param columnName `NSString` value of the name of the column. 392 | 393 | @return Data value of the result set's column. 394 | 395 | @warning If you are going to use this data after you iterate over the next row, or after you close the 396 | result set, make sure to make a copy of the data first (or just use ``/``) 397 | If you don't, you're going to be in a world of hurt when you try and use the data. 398 | 399 | */ 400 | 401 | - (NSData * _Nullable)dataNoCopyForColumn:(NSString *)columnName NS_RETURNS_NOT_RETAINED; 402 | 403 | /** Result set `NSData` value for column. 404 | 405 | @param columnIdx Zero-based index for column. 406 | 407 | @return Data value of the result set's column. 408 | 409 | @warning If you are going to use this data after you iterate over the next row, or after you close the 410 | result set, make sure to make a copy of the data first (or just use ``/``) 411 | If you don't, you're going to be in a world of hurt when you try and use the data. 412 | 413 | */ 414 | 415 | - (NSData * _Nullable)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; 416 | 417 | /** Is the column `NULL`? 418 | 419 | @param columnIdx Zero-based index for column. 420 | 421 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 422 | */ 423 | 424 | - (BOOL)columnIndexIsNull:(int)columnIdx; 425 | 426 | /** Is the column `NULL`? 427 | 428 | @param columnName `NSString` value of the name of the column. 429 | 430 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 431 | */ 432 | 433 | - (BOOL)columnIsNull:(NSString*)columnName; 434 | 435 | 436 | /** Returns a dictionary of the row results mapped to case sensitive keys of the column names. 437 | 438 | @warning The keys to the dictionary are case sensitive of the column names. 439 | */ 440 | 441 | @property (nonatomic, readonly, nullable) NSDictionary *resultDictionary; 442 | 443 | /** Returns a dictionary of the row results 444 | 445 | @see resultDictionary 446 | 447 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! 448 | */ 449 | 450 | - (NSDictionary * _Nullable)resultDict __deprecated_msg("Use resultDictionary instead"); 451 | 452 | ///----------------------------- 453 | /// @name Key value coding magic 454 | ///----------------------------- 455 | 456 | /** Performs `setValue` to yield support for key value observing. 457 | 458 | @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe. 459 | 460 | */ 461 | 462 | - (void)kvcMagic:(id)object; 463 | 464 | 465 | @end 466 | 467 | NS_ASSUME_NONNULL_END 468 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMResultSet.m: -------------------------------------------------------------------------------- 1 | #import "FMResultSet.h" 2 | #import "FMDatabase.h" 3 | #import 4 | 5 | #if FMDB_SQLITE_STANDALONE 6 | #import 7 | #else 8 | #import 9 | #endif 10 | 11 | @interface FMDatabase () 12 | - (void)resultSetDidClose:(FMResultSet *)resultSet; 13 | @end 14 | 15 | @interface FMResultSet () { 16 | NSMutableDictionary *_columnNameToIndexMap; 17 | } 18 | @end 19 | 20 | @implementation FMResultSet 21 | 22 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB { 23 | 24 | FMResultSet *rs = [[FMResultSet alloc] init]; 25 | 26 | [rs setStatement:statement]; 27 | [rs setParentDB:aDB]; 28 | 29 | NSParameterAssert(![statement inUse]); 30 | [statement setInUse:YES]; // weak reference 31 | 32 | return FMDBReturnAutoreleased(rs); 33 | } 34 | 35 | #if ! __has_feature(objc_arc) 36 | - (void)finalize { 37 | [self close]; 38 | [super finalize]; 39 | } 40 | #endif 41 | 42 | - (void)dealloc { 43 | [self close]; 44 | 45 | FMDBRelease(_query); 46 | _query = nil; 47 | 48 | FMDBRelease(_columnNameToIndexMap); 49 | _columnNameToIndexMap = nil; 50 | 51 | #if ! __has_feature(objc_arc) 52 | [super dealloc]; 53 | #endif 54 | } 55 | 56 | - (void)close { 57 | [_statement reset]; 58 | FMDBRelease(_statement); 59 | _statement = nil; 60 | 61 | // we don't need this anymore... (i think) 62 | //[_parentDB setInUse:NO]; 63 | [_parentDB resultSetDidClose:self]; 64 | [self setParentDB:nil]; 65 | } 66 | 67 | - (int)columnCount { 68 | return sqlite3_column_count([_statement statement]); 69 | } 70 | 71 | - (NSMutableDictionary *)columnNameToIndexMap { 72 | if (!_columnNameToIndexMap) { 73 | int columnCount = sqlite3_column_count([_statement statement]); 74 | _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; 75 | int columnIdx = 0; 76 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 77 | [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] 78 | forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; 79 | } 80 | } 81 | return _columnNameToIndexMap; 82 | } 83 | 84 | - (void)kvcMagic:(id)object { 85 | 86 | int columnCount = sqlite3_column_count([_statement statement]); 87 | 88 | int columnIdx = 0; 89 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 90 | 91 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 92 | 93 | // check for a null row 94 | if (c) { 95 | NSString *s = [NSString stringWithUTF8String:c]; 96 | 97 | [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; 98 | } 99 | } 100 | } 101 | 102 | #pragma clang diagnostic push 103 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 104 | 105 | - (NSDictionary *)resultDict { 106 | 107 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 108 | 109 | if (num_cols > 0) { 110 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 111 | 112 | NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; 113 | NSString *columnName = nil; 114 | while ((columnName = [columnNames nextObject])) { 115 | id objectValue = [self objectForColumnName:columnName]; 116 | [dict setObject:objectValue forKey:columnName]; 117 | } 118 | 119 | return FMDBReturnAutoreleased([dict copy]); 120 | } 121 | else { 122 | NSLog(@"Warning: There seem to be no columns in this set."); 123 | } 124 | 125 | return nil; 126 | } 127 | 128 | #pragma clang diagnostic pop 129 | 130 | - (NSDictionary*)resultDictionary { 131 | 132 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 133 | 134 | if (num_cols > 0) { 135 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 136 | 137 | int columnCount = sqlite3_column_count([_statement statement]); 138 | 139 | int columnIdx = 0; 140 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 141 | 142 | NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; 143 | id objectValue = [self objectForColumnIndex:columnIdx]; 144 | [dict setObject:objectValue forKey:columnName]; 145 | } 146 | 147 | return dict; 148 | } 149 | else { 150 | NSLog(@"Warning: There seem to be no columns in this set."); 151 | } 152 | 153 | return nil; 154 | } 155 | 156 | 157 | 158 | 159 | - (BOOL)next { 160 | return [self nextWithError:nil]; 161 | } 162 | 163 | - (BOOL)nextWithError:(NSError **)outErr { 164 | 165 | int rc = sqlite3_step([_statement statement]); 166 | 167 | if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { 168 | NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); 169 | NSLog(@"Database busy"); 170 | if (outErr) { 171 | *outErr = [_parentDB lastError]; 172 | } 173 | } 174 | else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { 175 | // all is well, let's return. 176 | } 177 | else if (SQLITE_ERROR == rc) { 178 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 179 | if (outErr) { 180 | *outErr = [_parentDB lastError]; 181 | } 182 | } 183 | else if (SQLITE_MISUSE == rc) { 184 | // uh oh. 185 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 186 | if (outErr) { 187 | if (_parentDB) { 188 | *outErr = [_parentDB lastError]; 189 | } 190 | else { 191 | // If 'next' or 'nextWithError' is called after the result set is closed, 192 | // we need to return the appropriate error. 193 | NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; 194 | *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage]; 195 | } 196 | 197 | } 198 | } 199 | else { 200 | // wtf? 201 | NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 202 | if (outErr) { 203 | *outErr = [_parentDB lastError]; 204 | } 205 | } 206 | 207 | 208 | if (rc != SQLITE_ROW) { 209 | [self close]; 210 | } 211 | 212 | return (rc == SQLITE_ROW); 213 | } 214 | 215 | - (BOOL)hasAnotherRow { 216 | return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; 217 | } 218 | 219 | - (int)columnIndexForName:(NSString*)columnName { 220 | columnName = [columnName lowercaseString]; 221 | 222 | NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; 223 | 224 | if (n != nil) { 225 | return [n intValue]; 226 | } 227 | 228 | NSLog(@"Warning: I could not find the column named '%@'.", columnName); 229 | 230 | return -1; 231 | } 232 | 233 | - (int)intForColumn:(NSString*)columnName { 234 | return [self intForColumnIndex:[self columnIndexForName:columnName]]; 235 | } 236 | 237 | - (int)intForColumnIndex:(int)columnIdx { 238 | return sqlite3_column_int([_statement statement], columnIdx); 239 | } 240 | 241 | - (long)longForColumn:(NSString*)columnName { 242 | return [self longForColumnIndex:[self columnIndexForName:columnName]]; 243 | } 244 | 245 | - (long)longForColumnIndex:(int)columnIdx { 246 | return (long)sqlite3_column_int64([_statement statement], columnIdx); 247 | } 248 | 249 | - (long long int)longLongIntForColumn:(NSString*)columnName { 250 | return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; 251 | } 252 | 253 | - (long long int)longLongIntForColumnIndex:(int)columnIdx { 254 | return sqlite3_column_int64([_statement statement], columnIdx); 255 | } 256 | 257 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { 258 | return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; 259 | } 260 | 261 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { 262 | return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; 263 | } 264 | 265 | - (BOOL)boolForColumn:(NSString*)columnName { 266 | return [self boolForColumnIndex:[self columnIndexForName:columnName]]; 267 | } 268 | 269 | - (BOOL)boolForColumnIndex:(int)columnIdx { 270 | return ([self intForColumnIndex:columnIdx] != 0); 271 | } 272 | 273 | - (double)doubleForColumn:(NSString*)columnName { 274 | return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; 275 | } 276 | 277 | - (double)doubleForColumnIndex:(int)columnIdx { 278 | return sqlite3_column_double([_statement statement], columnIdx); 279 | } 280 | 281 | - (NSString *)stringForColumnIndex:(int)columnIdx { 282 | 283 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) { 284 | return nil; 285 | } 286 | 287 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 288 | 289 | if (!c) { 290 | // null row. 291 | return nil; 292 | } 293 | 294 | return [NSString stringWithUTF8String:c]; 295 | } 296 | 297 | - (NSString*)stringForColumn:(NSString*)columnName { 298 | return [self stringForColumnIndex:[self columnIndexForName:columnName]]; 299 | } 300 | 301 | - (NSDate*)dateForColumn:(NSString*)columnName { 302 | return [self dateForColumnIndex:[self columnIndexForName:columnName]]; 303 | } 304 | 305 | - (NSDate*)dateForColumnIndex:(int)columnIdx { 306 | 307 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) { 308 | return nil; 309 | } 310 | 311 | return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; 312 | } 313 | 314 | 315 | - (NSData*)dataForColumn:(NSString*)columnName { 316 | return [self dataForColumnIndex:[self columnIndexForName:columnName]]; 317 | } 318 | 319 | - (NSData*)dataForColumnIndex:(int)columnIdx { 320 | 321 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) { 322 | return nil; 323 | } 324 | 325 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 326 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 327 | 328 | if (dataBuffer == NULL) { 329 | return nil; 330 | } 331 | 332 | return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; 333 | } 334 | 335 | 336 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName { 337 | return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; 338 | } 339 | 340 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { 341 | 342 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) { 343 | return nil; 344 | } 345 | 346 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 347 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 348 | 349 | NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; 350 | 351 | return data; 352 | } 353 | 354 | 355 | - (BOOL)columnIndexIsNull:(int)columnIdx { 356 | return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; 357 | } 358 | 359 | - (BOOL)columnIsNull:(NSString*)columnName { 360 | return [self columnIndexIsNull:[self columnIndexForName:columnName]]; 361 | } 362 | 363 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { 364 | 365 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count([_statement statement])) { 366 | return nil; 367 | } 368 | 369 | return sqlite3_column_text([_statement statement], columnIdx); 370 | } 371 | 372 | - (const unsigned char *)UTF8StringForColumn:(NSString*)columnName { 373 | return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; 374 | } 375 | 376 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { 377 | return [self UTF8StringForColumn:columnName]; 378 | } 379 | 380 | - (id)objectForColumnIndex:(int)columnIdx { 381 | if (columnIdx < 0 || columnIdx >= sqlite3_column_count([_statement statement])) { 382 | return nil; 383 | } 384 | 385 | int columnType = sqlite3_column_type([_statement statement], columnIdx); 386 | 387 | id returnValue = nil; 388 | 389 | if (columnType == SQLITE_INTEGER) { 390 | returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; 391 | } 392 | else if (columnType == SQLITE_FLOAT) { 393 | returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; 394 | } 395 | else if (columnType == SQLITE_BLOB) { 396 | returnValue = [self dataForColumnIndex:columnIdx]; 397 | } 398 | else { 399 | //default to a string for everything else 400 | returnValue = [self stringForColumnIndex:columnIdx]; 401 | } 402 | 403 | if (returnValue == nil) { 404 | returnValue = [NSNull null]; 405 | } 406 | 407 | return returnValue; 408 | } 409 | 410 | - (id)objectForColumnName:(NSString*)columnName { 411 | return [self objectForColumn:columnName]; 412 | } 413 | 414 | - (id)objectForColumn:(NSString*)columnName { 415 | return [self objectForColumnIndex:[self columnIndexForName:columnName]]; 416 | } 417 | 418 | // returns autoreleased NSString containing the name of the column in the result set 419 | - (NSString*)columnNameForIndex:(int)columnIdx { 420 | return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; 421 | } 422 | 423 | - (id)objectAtIndexedSubscript:(int)columnIdx { 424 | return [self objectForColumnIndex:columnIdx]; 425 | } 426 | 427 | - (id)objectForKeyedSubscript:(NSString *)columnName { 428 | return [self objectForColumn:columnName]; 429 | } 430 | 431 | 432 | @end 433 | --------------------------------------------------------------------------------