├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── PYFMDB.podspec ├── PYFMDB ├── PYFMDB.h ├── PYFMDB.m ├── PYStructure.h ├── PYStructure.m ├── PYTable.h └── PYTable.m ├── README.md ├── README_TW.md ├── README_ZH.md └── pyfmdbdemo ├── FMDB ├── FMDB.h ├── FMDatabase.h ├── FMDatabase.m ├── FMDatabaseAdditions.h ├── FMDatabaseAdditions.m ├── FMDatabasePool.h ├── FMDatabasePool.m ├── FMDatabaseQueue.h ├── FMDatabaseQueue.m ├── FMResultSet.h └── FMResultSet.m ├── PYFMDB ├── PYFMDB.h ├── PYFMDB.m ├── PYStructure.h ├── PYStructure.m ├── PYTable.h └── PYTable.m ├── pyfmdbdemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── pyfmdbdemo.xcscheme │ └── pyfmdbdemoTests.xcscheme ├── pyfmdbdemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CarTable.h ├── CarTable.m ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m └── pyfmdbdemoTests ├── Info.plist ├── Schemes ├── pyfmdbdemo.xcscheme └── pyfmdbdemoTests.xcscheme └── pyfmdbdemoTests.m /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-pro 2 | repo_token: FMR7ZRTSSV0Sx2eVy1GrVebtSySzT9RLQ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7.1 3 | xcode_project: pyfmdbdemo/pyfmdbdemo.xcodeproj 4 | xcode_scheme: pyfmdbdemo 5 | before_install: 6 | - mkdir -p "pyfmdbdemo/pyfmdbdemo.xcodeproj/xcshareddata/xcschemes" && cp pyfmdbdemo/pyfmdbdemoTests/Schemes/*.xcscheme "pyfmdbdemo/pyfmdbdemo.xcodeproj/xcshareddata/xcschemes/" 7 | script: 8 | - xctool -project pyfmdbdemo/pyfmdbdemo.xcodeproj -scheme pyfmdbdemo ONLY_ACTIVE_ARCH=NO build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2015 PYFMDB https://github.com/iterrypeng 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /PYFMDB.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PYFMDB" 3 | s.version = "0.0.5" 4 | s.summary = "Operations library of sqlite base on FMDB" 5 | s.homepage = "https://github.com/iterrypeng/PYFMDB" 6 | s.license = "MIT" 7 | s.author = { "pengyong" => "pengyong@veldasoft.com" } 8 | s.platform = :ios 9 | s.source = { :git => "https://github.com/iterrypeng/PYFMDB.git", :tag => s.version.to_s } 10 | s.source_files = "PYFMDB/*.{h,m}" 11 | s.platform = :ios,'6.0' 12 | s.requires_arc = true 13 | s.dependency "FMDB", "~> 2.0" 14 | end 15 | -------------------------------------------------------------------------------- /PYFMDB/PYFMDB.h: -------------------------------------------------------------------------------- 1 | // 2 | // PYFMDB.h 3 | // Operations library of sqlite base on FMDB 4 | // 5 | // Created by terry on 15/3/28. 6 | // Copyright (c) 2015年 Velda. All rights reserved. 7 | // 8 | 9 | #import 10 | @class FMDatabaseQueue; 11 | @interface PYFMDB : NSObject{ 12 | //以下是因为同时重写了get和set方法,故将变量写在这里 13 | /** 14 | * 查询条件 15 | */ 16 | NSString *_limit; 17 | NSString *_where; 18 | NSString *_order; 19 | NSString *_group; 20 | /** 21 | * 缓存ID 22 | */ 23 | NSString *_cacheID; 24 | } 25 | 26 | /** 27 | * 数据库队列 28 | */ 29 | @property (nonatomic,strong) FMDatabaseQueue * queue; 30 | /** 31 | * 数据库文件名 32 | */ 33 | @property (nonatomic,copy) NSString * dbName; 34 | /** 35 | * 数据库文件名(锁定) 36 | */ 37 | @property (nonatomic,copy) NSString * dbName_lock; 38 | /** 39 | * 数据库位置 40 | */ 41 | @property (nonatomic,copy) NSString * dbPath; 42 | /** 43 | * 数据库位置(锁定) 44 | */ 45 | @property (nonatomic,copy) NSString * dbPath_lock; 46 | /** 47 | * 最后执行的sql语句 48 | */ 49 | @property (nonatomic,copy) NSString * lastSql; 50 | /** 51 | * 最后执行的sql语句(锁定) 52 | */ 53 | @property (nonatomic,copy) NSString * lastSql_lock; 54 | /** 55 | * 数据库表前缀 56 | */ 57 | @property (nonatomic,copy) NSString * prefix; 58 | /** 59 | * 数据库表前缀(锁定) 60 | */ 61 | @property (nonatomic,copy) NSString * prefix_lock; 62 | /** 63 | * 要查询出的字段(默认) 64 | */ 65 | @property (nonatomic,strong) NSArray * fields; 66 | /** 67 | * 要查询出的字段(锁定) 68 | */ 69 | @property (nonatomic,strong) NSArray * fields_lock; 70 | 71 | /** 72 | * 要查询出的字段(字符串) 73 | */ 74 | @property (nonatomic,copy) NSString * fieldsString; 75 | 76 | /** 77 | * 要查询出的字段(数组) 78 | */ 79 | @property (nonatomic,strong) NSArray * fieldsArray; 80 | /** 81 | * 当前操作的表名 82 | */ 83 | @property (nonatomic,copy) NSString * currentTableName; 84 | /** 85 | * 当前操作的表名(锁定) 86 | */ 87 | @property (nonatomic,copy) NSString * currentTableName_lock; 88 | /** 89 | * 表里的所有字段 90 | */ 91 | @property (nonatomic,strong) NSDictionary * currentTableFields; 92 | /** 93 | * 表里的所有字段(锁定) 94 | */ 95 | @property (nonatomic,strong) NSDictionary * currentTableFields_lock; 96 | /** 97 | * 要执行的查询条件(锁定) 98 | */ 99 | @property (nonatomic,copy) NSString * where_lock; 100 | 101 | /** 102 | * 待更新的数据源 103 | */ 104 | @property (nonatomic,strong) id data; 105 | /** 106 | * 待更新的数据源(锁定) 107 | */ 108 | @property (nonatomic,strong) id data_lock; 109 | /** 110 | * Order条件(锁定) 111 | */ 112 | @property (nonatomic,copy) NSString * order_lock; 113 | 114 | /** 115 | * group条件(锁定) 116 | */ 117 | @property (nonatomic,copy) NSString * group_lock; 118 | /** 119 | * 缓存标识(锁定) 120 | */ 121 | @property (nonatomic,copy) NSString * cacheID_lock; 122 | /** 123 | * 查询限制条数(锁定) 124 | */ 125 | @property (nonatomic,copy) NSString * limit_lock; 126 | 127 | /** 128 | * 静态方法初始化数据库连接 129 | * 130 | * @param dbName 数据库名 131 | * 132 | * @return PYFMDB对象 133 | */ 134 | +(instancetype)dbWithDbName:(NSString *)dbName; 135 | /** 136 | * 动态方法初始化数据库连接 137 | * 138 | * @param dbName 数据库名 139 | * 140 | * @return PYFMDB对象 141 | */ 142 | -(instancetype)initWithDbName:(NSString *)dbName; 143 | 144 | 145 | 146 | 147 | /** 148 | * 根据字典创建数据库表 149 | * 150 | * @param dict 字典 151 | * @param tablename 表名 152 | * 153 | * @return 执行是否成功 154 | */ 155 | -(bool)createTableWithDict:(NSDictionary *)dict : (NSString *)tableName; 156 | /** 157 | * 执行sql查询 158 | * 159 | * @param sql sql语句 160 | * 161 | * @return 查询结果集 162 | */ 163 | -(NSArray *)excuteQueryWithSql:(NSString *)sql; 164 | /** 165 | * 执行sql更新 166 | * 167 | * @param sql sql语句 168 | * 169 | * @return 执行是否成功 170 | */ 171 | -(bool)excuteUpdateWithSql:(NSString *)sql; 172 | 173 | /** 174 | * 从数组中设置查询的字段信息 175 | * 176 | * @param arr 数组 177 | * 178 | * @return fields数组 179 | */ 180 | -(instancetype)fieldsWithArray:(NSArray *)arr; 181 | /** 182 | * 从字符串中设置查询的字段信息 183 | * 184 | * @param str 字符串 185 | * 186 | * @return fields数组 187 | */ 188 | -(instancetype)fieldsWithString:(NSString *)str; 189 | /** 190 | * 从字符串中设置查询的where条件 191 | * 192 | * @param str 字符串 193 | * 194 | * @return where条件 195 | */ 196 | -(instancetype)whereWithString:(NSString *)str; 197 | /** 198 | * 从字典中设置查询的where条件 199 | * 200 | * @param dict 字典 201 | * 202 | * @return PYFMDB对象 203 | */ 204 | -(instancetype)whereWithDict:(NSDictionary *)dict; 205 | /** 206 | * 从字符串中设置limit条件 207 | * 208 | * @param str 字符串 209 | * 210 | * @return PYFMDB 对象 211 | */ 212 | -(instancetype)limitWithString:(NSString *)str; 213 | /** 214 | * 从数组中设置limit条件 215 | * 216 | * @param arr 数组 217 | * 218 | * @return PYFMDB对象 219 | */ 220 | -(instancetype)limitWithArray:(NSArray *)arr; 221 | /** 222 | * 从start 到 end limit限制 223 | * 224 | * @param start 开始位置 225 | * @param End 结束位置 226 | * 227 | * @return PYFMDB对象 228 | */ 229 | -(instancetype)limitWithStart:(int)start End:(int)end; 230 | /** 231 | * 查询单条记录 232 | * 233 | * @return 字典数据 234 | */ 235 | -(NSDictionary *)find; 236 | /** 237 | * 从字典添加更新数据源 238 | * 239 | * @param PYFMDB对象 240 | */ 241 | -(instancetype)dataWithDict:(NSDictionary *)dict; 242 | /** 243 | * 从数组添加更新数据源 244 | * 245 | * @param arr 数组 246 | * 247 | * @return PYFMDB对象 248 | */ 249 | -(instancetype)dataWithArray:(NSArray *)arr; 250 | /** 251 | * 从JSON中添加更新数据源 252 | * 253 | * @param json json数据 254 | * 255 | * @return PYFMDB对象 256 | */ 257 | -(instancetype)datawithJson:(NSData *)json; 258 | /** 259 | * 新增记录到数据库 260 | * 261 | * @return 是否执行sql成功 262 | */ 263 | -(bool)add; 264 | /** 265 | * 按数据源新增记录到数据库 266 | * 267 | * @param data 数据源 268 | * 269 | * @return 是否执行sql成功 270 | */ 271 | -(bool)add:(id)data; 272 | /** 273 | * 保存记录到数据库 274 | * 275 | * @return 是否执行sql成功 276 | */ 277 | -(bool)save; 278 | /** 279 | * 从数据源保存记录到数据库 280 | * 281 | * @param data 数据源 282 | * 283 | * @return 是否执行sql成功 284 | */ 285 | -(bool)save:(id)data; 286 | /** 287 | * 获取指定字段的数据值 288 | * 289 | * @param field 字段名 290 | * 291 | * @return 数据源 292 | */ 293 | -(id)getField:(NSString *)field; 294 | /** 295 | * 设置指定字段名的值 296 | * 297 | * @param value 字段值 298 | * @param field 字段名 299 | * 300 | * @return 是否成功执行sql 301 | */ 302 | -(bool)setValue: (id)value forField:(NSString *)field; 303 | /** 304 | * 查询到的数据库结果 305 | * 306 | * @return 数组 307 | */ 308 | -(NSArray *)select; 309 | /** 310 | * 过滤掉非数据库表字段 311 | * 312 | * @param dict 字典数据 313 | * 314 | * @return 过滤后字典数据 315 | */ 316 | -(NSDictionary *)filterWithDict:(NSDictionary *)dict; 317 | /** 318 | * 执行删除 319 | * 320 | * @return 是否成功执行sql 321 | */ 322 | -(BOOL)delete; 323 | /** 324 | * 根据where条件删除操作 325 | * 326 | * @param where where条件 327 | * 328 | * @return 是否成功执行sql 329 | */ 330 | -(BOOL)delete:(id)where; 331 | /** 332 | * count统计操作 333 | * 334 | * @return 查询结果集数目 335 | */ 336 | -(NSNumber *)queryCount; 337 | 338 | /** 339 | * 清除设置条件 340 | * 341 | * @return PYFMDB对象 342 | */ 343 | -(instancetype)clean; 344 | /** 345 | * 锁定上次设置条件 346 | * 347 | * @return PYFMDB对象 348 | */ 349 | -(instancetype)lock; 350 | /** 351 | * 重置到上次设置的条件 352 | * 353 | * @return PYFMDB对象 354 | */ 355 | -(instancetype)reset; 356 | /** 357 | * 重写order get方法 358 | * 359 | * @return 要排序的条件 360 | */ 361 | - (NSString *)order; 362 | /** 363 | * 设置order条件 364 | * 365 | * @param order order条件 366 | */ 367 | -(void)setOrder:(NSString *)order; 368 | /** 369 | * 数据表是否为空 370 | * 371 | * @param tableName 数据库表名 372 | * 373 | * @return bool类型值 YES =为空, NO = 不为空 374 | */ 375 | -(BOOL)isEmptyWithTableName:(NSString *)tableName; 376 | /** 377 | * 清空数据表 378 | * 379 | * @param tableName 表名 380 | */ 381 | -(void)truncateTableWithTableName:(NSString *)tableName; 382 | /** 383 | * 公共删除方法 384 | * 385 | * @param dict 字典 386 | */ 387 | -(void)deleteTableWithDict:(NSDictionary *)dict : (NSString *)tableName; 388 | /** 389 | * 展示Table数据 390 | * 391 | * @param page 当前页 392 | * @param pagesize 分页大小 393 | * @param tableName 表名 394 | * 395 | * @return 数组 396 | */ 397 | -(NSArray *)showTableWithPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andTableName:(NSString *)tableName; 398 | /** 399 | * 展示Table数据 400 | * 401 | * @param page 当前页 402 | * @param pagesize 分页大小 403 | * @param order 排序 404 | * @param tableName 表名 405 | * 406 | * @return 数组 407 | */ 408 | -(NSArray *)showTableWithPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order andTableName:(NSString *)tableName; 409 | 410 | /** 411 | * 展示Table数据 412 | * 413 | * @param fields 字段,(多个字段半角逗号隔开) 414 | * @param page 当前页 415 | * @param pagesize 分页大小 416 | * @param tableName 表名 417 | * 418 | * @return 数组 419 | */ 420 | -(NSArray *)showTableWithFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andTableName:(NSString *)tableName; 421 | 422 | 423 | /** 424 | * 展示Table数据 425 | * 426 | * @param fields 字段,(多个字段半角逗号隔开) 427 | * @param page 当前页 428 | * @param pagesize 分页大小 429 | * @param order 排序 430 | * @param tableName 表名 431 | * 432 | * @return 数组 433 | */ 434 | -(NSArray *)showTableWithFields:(NSString *)fields andPages:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order andTableName:(NSString *)tableName; 435 | #pragma mark - cache 缓存处理方法 436 | /** 437 | * 将数据缓存入文件 438 | * 439 | * @param data 数据源 440 | * @param cacheKey 缓存键名 441 | * 442 | * @return 是否成功缓存 443 | */ 444 | -(BOOL)setObject:(id)data ForCacheKey:(NSString *)cacheKey; 445 | /** 446 | * 根据缓存键名读取缓存内容 447 | * 448 | * @param cacheKey 缓存键名 449 | * 450 | * @return 缓存键值 451 | */ 452 | - (id )objectForCacheKey:(NSString *)cacheKey; 453 | #pragma mark - 索引操作 454 | /** 455 | * 为字段创建普通索引 456 | * 457 | * @param field 字段名称 458 | * @param tableName 表名 459 | * 460 | * @return 执行是否成功 461 | */ 462 | -(bool)createIndexWithField:(NSString *)field andTableName: (NSString *)tableName; 463 | @end 464 | -------------------------------------------------------------------------------- /PYFMDB/PYFMDB.m: -------------------------------------------------------------------------------- 1 | // 2 | // PYFMDB.m 3 | // Operations library of sqlite base on FMDB 4 | // 5 | // Created by terry on 15/3/28. 6 | // Copyright (c) 2015年 Velda. All rights reserved. 7 | // 8 | 9 | #import "PYFMDB.h" 10 | #import "FMDB.h" 11 | @implementation PYFMDB 12 | #pragma mark - set方法重写 13 | /** 14 | * 重写tablename set方法 15 | * 16 | * @param tablename 表名 17 | */ 18 | - (void)setCurrentTableName:(NSString *)currentTableName{ 19 | _currentTableName = [NSString stringWithFormat:@"%@%@",self.prefix,currentTableName]; 20 | __block NSString *sql = [NSString stringWithFormat:@"PRAGMA table_info(%@)",_currentTableName]; 21 | __block NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 22 | [_queue inDatabase:^(FMDatabase *db) { 23 | FMResultSet *rs= [db executeQuery:sql]; 24 | while (rs.next) { 25 | [dict addEntriesFromDictionary: [NSDictionary dictionaryWithObject:[rs stringForColumn:@"type"] forKey:[rs stringForColumn:@"name"]]]; 26 | } 27 | }]; 28 | _currentTableFields = [NSDictionary dictionaryWithDictionary:dict]; 29 | _lastSql = sql; 30 | } 31 | 32 | /** 33 | * 设置连接的数据库 34 | * 35 | * @param database 数据库名称 36 | */ 37 | -(void)setDbName:(NSString *)dbName{ 38 | _dbName = dbName; 39 | _dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:_dbName]; 40 | _queue = [FMDatabaseQueue databaseQueueWithPath:_dbPath]; 41 | } 42 | /** 43 | * 设置limit条件 44 | * 45 | * @param limit limit条件 46 | */ 47 | -(void)setLimit:(NSString *)limit{ 48 | _limit = limit; 49 | } 50 | /** 51 | * 设置group条件 52 | * 53 | * @param group group条件 54 | */ 55 | -(void)setGroup:(NSString *)group{ 56 | _group = group; 57 | } 58 | /** 59 | * 设置order条件 60 | * 61 | * @param order order条件 62 | */ 63 | -(void)setOrder:(NSString *)order{ 64 | _order = order; 65 | } 66 | /** 67 | * 设置where条件 68 | * 69 | * @param where where条件 70 | */ 71 | -(void)setWhere:(NSString *)where{ 72 | _where = where; 73 | } 74 | /** 75 | * 设置缓存标识 76 | * 77 | * @param cacheID 缓存标识 78 | */ 79 | -(void)setCacheID:(NSString *)cacheID{ 80 | _cacheID = cacheID; 81 | } 82 | 83 | #pragma mark - get方法重写 84 | 85 | /** 86 | * 重写fields get方法 87 | * 88 | * @return 要查询的字段数组 89 | */ 90 | -(NSArray *)fields{ 91 | if ([_fields count]==0) { 92 | _fields = [_currentTableFields allKeys]; 93 | } 94 | return _fields; 95 | } 96 | /** 97 | * 重写prefix get方法 98 | * 99 | * @return 数据库表前缀 100 | */ 101 | -(NSString *)prefix{ 102 | if (_prefix.length==0) { 103 | return [NSString string]; 104 | } 105 | return _prefix; 106 | } 107 | /** 108 | * 重写limit get方法 109 | * 110 | * @return 返回limit 格式 111 | */ 112 | -(NSString *)limit{ 113 | if (_limit.length==0) { 114 | return [NSString string]; 115 | } 116 | return [NSString stringWithFormat:@"LIMIT %@",_limit]; 117 | } 118 | /** 119 | * 重写where get 方法 120 | * 121 | * @return 要查询的条件 122 | */ 123 | 124 | -(NSString *)where{ 125 | if (_where.length>0) { 126 | return [NSString stringWithFormat:@" WHERE %@",[[NSMutableString stringWithString:_where] stringByReplacingOccurrencesOfString:@" WHERE " withString:@""]]; 127 | } 128 | return [NSString string]; 129 | } 130 | /** 131 | * 重写order get方法 132 | * 133 | * @return 要排序的条件 134 | */ 135 | - (NSString *)order{ 136 | if(_order.length>0){ 137 | return [NSString stringWithFormat:@" ORDER BY %@",_order]; 138 | } 139 | return [NSString string]; 140 | } 141 | /** 142 | * 重写group get方法 143 | * 144 | * @return 要group的字段 145 | */ 146 | - (NSString *)group{ 147 | if (_group.length >0) { 148 | return [NSString stringWithFormat:@" GROUP BY %@",_group]; 149 | } 150 | return [NSString string]; 151 | } 152 | /** 153 | * 重写 fieldsArray get方法 154 | * 155 | * @return 数组版本fields 156 | */ 157 | -(NSArray *)fieldsArray{ 158 | return _fields; 159 | } 160 | /** 161 | * 重写fieldsString get方法 162 | * 163 | * @return 字符串版本fields 164 | */ 165 | -(NSString *)fieldsString{ 166 | __block NSMutableString *str = [NSMutableString string]; 167 | [self.fields enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 168 | str = [NSMutableString stringWithFormat:@"%@,%@",str,obj]; 169 | }]; 170 | NSString *ref = [str stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; 171 | if ([ref isEqualToString:@""] || [ref isEqual:nil]) { 172 | return @" * "; 173 | } 174 | return ref; 175 | } 176 | /** 177 | * 重写缓存ID get方法 178 | * 179 | * @return 缓存ID 180 | */ 181 | -(NSString *)cacheID{ 182 | if (!_cacheID) { 183 | return [NSString stringWithFormat:@"%d" ,(int)[[NSDate date] timeIntervalSince1970]]; 184 | } 185 | return _cacheID; 186 | } 187 | 188 | 189 | 190 | #pragma mark - 创建数据库连接 191 | /** 192 | * 静态方法创建数据库连接 193 | * 194 | * @param dbName 数据库名 195 | * 196 | * @return PYFMDB对象 197 | */ 198 | +(instancetype)dbWithDbName:(NSString *)dbName{ 199 | return [[self alloc] initWithDbName:dbName]; 200 | } 201 | /** 202 | * 动态方法创建数据库连接 203 | * 204 | * @param dbName 数据库名 205 | * 206 | * @return PYFMDB对象 207 | */ 208 | -(instancetype)initWithDbName:(NSString *)dbName{ 209 | if(self =[super init]){ 210 | [self setDbName:dbName]; 211 | [self createCacheTable]; 212 | } 213 | return self; 214 | } 215 | 216 | #pragma mark -创建数据库表 217 | /** 218 | * 根据字典创建数据库表 219 | * 220 | * @param dict 字典 @{@"字段名称1":@"字段类型1",@"字段名称2":@"字段类型2"} 221 | * @param tablename 表名 222 | * 223 | * @return 返回bool类型 创建成功返回YES 失败返回NO 224 | */ 225 | - (bool)createTableWithDict:(NSDictionary *)dict :(NSString *)tableName{ 226 | NSString *currentTableName = [NSString stringWithFormat:@"%@%@",self.prefix,tableName]; 227 | __block NSMutableString *sql = [NSMutableString stringWithFormat:@"CREATE TABLE IF NOT EXISTS `%@` (",currentTableName]; 228 | [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 229 | sql = [NSMutableString stringWithFormat:@"%@ %@ %@,",sql,key,obj]; 230 | }]; 231 | //去除右侧多余 ',' 232 | NSString *leftsql = [sql stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; 233 | sql = [NSMutableString stringWithFormat:@"%@);",leftsql]; 234 | _lastSql = sql; 235 | return [self excuteUpdateWithSql:sql]; 236 | } 237 | /** 238 | * 创建缓存数据库表 239 | * 240 | * @return 返回bool类型 创建成功返回YES 失败返回NO 241 | */ 242 | -(BOOL)createCacheTable{ 243 | NSString *sql = @"CREATE TABLE IF NOT EXISTS `_cache` (cacheID text primary key,cacheData BLOB);"; 244 | return [self excuteUpdateWithSql:sql]; 245 | } 246 | 247 | #pragma mark - 执行数据库查询与更新 248 | /** 249 | * 执行sql查询 250 | * 251 | * @param sql sql语句 252 | * 253 | * @return 查询结果集(字典) 254 | */ 255 | - (NSArray *)excuteQueryWithSql:(NSString *)sql{ 256 | __block NSArray *result = [NSArray array]; 257 | [_queue inDatabase:^(FMDatabase *db) { 258 | NSMutableArray *arr = [NSMutableArray array]; 259 | FMResultSet *rs = [db executeQuery:sql]; 260 | while ([rs next]) { 261 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 262 | NSMutableString *key = [NSMutableString string]; 263 | for (int i=0; i<_fields.count; i++) { 264 | key = [NSMutableString stringWithString:[_fields objectAtIndex:i]]; 265 | //过滤"xxx as yyy" 情况 266 | NSArray *keyarr =[key componentsSeparatedByString:@" as "]; 267 | if ([keyarr count]>0) { 268 | key =[NSMutableString stringWithString: [[keyarr lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]; 269 | } 270 | //找到对应的currentTableField的type;keytype 只区分bloc和非bloc,非bloc一律转成nsstring 271 | NSMutableString *keytype = nil; 272 | //当key=*时则遍历_fields 273 | if ([key isEqualToString:@"*"]) { 274 | for (int j=0; j<_currentTableFields.count; j++) { 275 | key = [NSMutableString stringWithString:[_currentTableFields.allKeys objectAtIndex:j]]; 276 | keytype = [NSMutableString stringWithString:[_currentTableFields.allValues objectAtIndex:j]]; 277 | [keytype isEqualToString:@"bloc"] ? [dict setObject:[rs dataForColumn:key] forKey:key]:[dict setObject:[rs stringForColumn:key] forKey:key]; 278 | } 279 | } 280 | else{ 281 | //其他情况则分析key是否在currentTableFields.allKeys中是否存在 282 | keytype = [_currentTableFields.allKeys containsObject:key] ? _currentTableFields[key]:nil; 283 | [keytype isEqualToString:@"bloc"] ? [dict setObject:[rs dataForColumn:key] forKey:key]:[dict setObject:[rs stringForColumn:key] forKey:key]; 284 | } 285 | } 286 | [arr addObject:dict]; 287 | } 288 | result = [NSArray arrayWithArray:arr]; 289 | }]; 290 | //记录到最后sql 291 | _lastSql = sql; 292 | if(!result){ 293 | NSLog(@"PYFMDB QUERY Empty: %@",sql); 294 | } 295 | return result; 296 | } 297 | 298 | /** 299 | * 执行sql更新 300 | * 301 | * @param sql sql语句 302 | * 303 | * @return bool YES执行成功 NO执行失败 304 | */ 305 | -(bool)excuteUpdateWithSql:(NSString *)sql{ 306 | __block bool result; 307 | [_queue inDatabase:^(FMDatabase *db) { 308 | result = [db executeUpdate:sql]; 309 | }]; 310 | //记录到最后sql 311 | _lastSql = sql; 312 | //如果执行失败打印到前台 313 | if(!result){ 314 | NSLog(@"PYFMDB UPDATE Failed: %@",sql); 315 | } 316 | return result; 317 | } 318 | 319 | #pragma mark - field 字段设置 320 | 321 | /** 322 | * 从数组中设置要查询的字段信息 323 | * 324 | * @param arr 数组 325 | * 326 | * @return 无返回值 327 | */ 328 | - (instancetype)fieldsWithArray:(NSArray *)arr{ 329 | _fields = arr; 330 | return self; 331 | } 332 | 333 | /** 334 | * 从字符串中设置要查询的字段信息 335 | * 336 | * @param str 字符串 337 | * 338 | * @return 无返回值 339 | */ 340 | - (instancetype)fieldsWithString:(NSString *)str{ 341 | //将字符串转为数组 342 | NSArray *fields = [str componentsSeparatedByString:@","]; 343 | if ([fields count]==0) { 344 | _fields = [NSArray arrayWithObject:str]; 345 | return self; 346 | } 347 | __block NSMutableArray *result=[NSMutableArray array]; 348 | [fields enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 349 | NSString *trimobj = [obj stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 350 | [result addObject:trimobj]; 351 | }]; 352 | _fields = [NSArray arrayWithArray:result]; 353 | return self; 354 | } 355 | #pragma mark - where条件设置 356 | /** 357 | * 从字符串中设置要查询的where条件 358 | * 359 | * @param str 字符串 360 | * 361 | * @return where条件 362 | */ 363 | - (instancetype)whereWithString:(NSString *)str{ 364 | _where = str; 365 | return self; 366 | } 367 | /** 368 | * 从字典中设置要查询的where条件 369 | * 370 | * @param dict 字典 371 | * 372 | * @return where条件 373 | */ 374 | -(instancetype)whereWithDict:(NSDictionary *)dict{ 375 | NSMutableString *mutablestr = [NSMutableString string]; 376 | NSArray *allkeys = [dict allKeys]; 377 | NSMutableString *tmp = [NSMutableString string]; 378 | for (int i=0; i1) { 421 | _limit = [arr componentsJoinedByString:@","]; 422 | } else { 423 | _limit = [arr lastObject]; 424 | } 425 | return self; 426 | } 427 | /** 428 | * 从start 到 end 的limit设置 429 | * 430 | * @param start 开始位置 431 | * @param End 结束位置 432 | * 433 | * @return PYFMDB对象本身 434 | */ 435 | - (instancetype)limitWithStart:(int)start End:(int)end{ 436 | _limit = [NSString stringWithFormat:@"%d,%d",start,end]; 437 | return self; 438 | } 439 | 440 | #pragma mark - data 设置数据方法 441 | /** 442 | * 从字典添加更新的数据源 443 | * 444 | * @param dict PYFMDB对象 445 | */ 446 | - (instancetype)dataWithDict:(NSDictionary *)dict{ 447 | _data = [self filterWithDict:dict]; 448 | return self; 449 | } 450 | /** 451 | * 从数组添加更新的数据源 452 | * 453 | * @param arr 数组 454 | * 455 | * @return PYFMDB对象 456 | */ 457 | - (instancetype)dataWithArray:(NSArray *)arr{ 458 | __block NSMutableArray *dataArr = [NSMutableArray array]; 459 | if ([arr count]>0) { 460 | [arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 461 | if ([obj isKindOfClass:[NSDictionary class]]) { 462 | NSDictionary *dict = [self filterWithDict:obj]; 463 | if([dict count] > 0){ 464 | [dataArr addObject:dict]; 465 | } 466 | } 467 | }]; 468 | } 469 | _data = [NSArray arrayWithArray:dataArr]; 470 | return self; 471 | } 472 | /** 473 | * 从JSON添加更新的数据源 474 | * 475 | * @param json json数据 476 | * 477 | * @return PYFMDB对象 478 | */ 479 | -(instancetype)datawithJson:(NSData *)json{ 480 | id jsondata = [NSJSONSerialization JSONObjectWithData:json options:0 error:nil]; 481 | if([jsondata isKindOfClass:[NSDictionary class]]){ 482 | _data = [self dataWithDict:jsondata]; 483 | } 484 | if ([jsondata isKindOfClass:[NSArray class]]) { 485 | _data = [self dataWithArray:jsondata]; 486 | } 487 | return self; 488 | } 489 | 490 | #pragma mark - 数据过滤 491 | /** 492 | * 过滤非数据库表字段数据 493 | * 494 | * @param dict 字典数据 495 | * 496 | * @return 过滤后的字典数据 497 | */ 498 | - (NSDictionary *)filterWithDict:(NSDictionary *)dict{ 499 | __block NSMutableDictionary *filterDict = [NSMutableDictionary dictionary]; 500 | [[self.currentTableFields allKeys] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 501 | if ([dict objectForKey:obj]) { 502 | [filterDict addEntriesFromDictionary:[NSDictionary dictionaryWithObject:[dict objectForKey:obj] forKey:obj]]; 503 | } 504 | }]; 505 | return filterDict; 506 | } 507 | 508 | #pragma mark - 新增数据操作 509 | /** 510 | * 新增记录到数据库 511 | * 512 | * @return 是否执行sql成功 513 | */ 514 | - (bool)add{ 515 | //字典单条记录更新 516 | if ([_data isKindOfClass:[NSDictionary class]] && [_data count]>0) { 517 | NSString *keys = [NSString stringWithFormat:@"`%@`",[[_data allKeys] componentsJoinedByString:@"`,`"]]; 518 | NSString *values =[NSString stringWithFormat:@"'%@'",[[_data allValues] componentsJoinedByString:@"','"]]; 519 | NSString *sql = [NSString stringWithFormat:@"INSERT INTO `%@` (%@) values(%@);",self.currentTableName,keys,values]; 520 | return [self excuteUpdateWithSql:sql]; 521 | } 522 | //数组批量递归更新 523 | if ([_data isKindOfClass:[NSArray class]] && [_data count]>0) { 524 | __block bool alltrue = YES; 525 | [_data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 526 | if ([obj isKindOfClass:[NSDictionary class]] && ![self add:obj]) { 527 | alltrue = NO; 528 | NSLog(@"PYFMDB UPDATE FAILED:%@",self.lastSql); 529 | } 530 | }]; 531 | return alltrue; 532 | } 533 | //其他则为异常情况 534 | NSLog(@"PYFMDB ADD DATA ERROR,DATA:%@",_data); 535 | return false; 536 | } 537 | 538 | /** 539 | * 根据数据源执行新增数据操作 540 | * 541 | * @param data 数据源 542 | * 543 | * @return 是否成功执行sql 544 | */ 545 | 546 | -(bool)add:(id)data{ 547 | if ([data isKindOfClass:[NSDictionary class]]) { 548 | return [[self dataWithDict:data] add]; 549 | } 550 | if ([data isKindOfClass:[NSArray class]]) { 551 | return [[self dataWithArray:data] add]; 552 | } 553 | if ([data isKindOfClass:[NSData class]]) { 554 | return [[self datawithJson:data] add]; 555 | } 556 | NSLog(@"PYFMDB ADD DATA ERROR,DATA:%@",data); 557 | return NO; 558 | } 559 | 560 | 561 | 562 | 563 | #pragma mark - 更新数据操作 564 | /** 565 | * 更新记录到数据库 566 | * 567 | * @return 是否执行sql成功 568 | */ 569 | - (bool)save{ 570 | __block NSMutableString *setstring = [NSMutableString string]; 571 | [_data enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 572 | setstring = [NSMutableString stringWithFormat:@"%@%@",setstring,[NSString stringWithFormat:@"`%@`='%@' , ",key,obj]]; 573 | }]; 574 | NSString * tmp = [setstring stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" , "]]; 575 | NSString *sql = [NSString stringWithFormat:@"UPDATE `%@` set %@ %@",self.currentTableName,tmp,self.where]; 576 | return [self excuteUpdateWithSql:sql]; 577 | } 578 | /** 579 | * 从字典更新记录到数据库 580 | * 581 | * @param dict 字典数据 582 | * 583 | * @return 是否执行sql成功 584 | */ 585 | - (bool)save:(id)data{ 586 | if ([data isKindOfClass:[NSData class]]) { 587 | //从json导入数据 588 | [self datawithJson:data]; 589 | } 590 | if ([data isKindOfClass:[NSDictionary class]] || [data isKindOfClass:[NSMutableDictionary class]]) { 591 | //从字典导入数据 592 | [self dataWithDict:data]; 593 | } 594 | if ([data isKindOfClass:[NSArray class]] || [data isKindOfClass:[NSMutableArray class]]) { 595 | //从数组导入数据则遍历批量更新 596 | __block BOOL allsave=YES; 597 | [data enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 598 | if ([obj isKindOfClass:[NSDictionary class]]) { 599 | [self dataWithDict:obj]; 600 | if (![self save]) { 601 | allsave = NO; 602 | //打印到控制台错误信息 603 | NSLog(@"PYFMDB UPDATE FAILED:%@",self.lastSql); 604 | } 605 | } 606 | }]; 607 | return allsave; 608 | } 609 | return [self save]; 610 | } 611 | /** 612 | * 更新指定字段值 613 | * 614 | * @param value 字段值 615 | * @param field 字段名 616 | * 617 | * @return 是否执行sql成功 618 | */ 619 | - (bool)setValue:(id)value forField:(NSString *)field{ 620 | _data = [self filterWithDict:[NSDictionary dictionaryWithObject:value forKey:field]]; 621 | return [self save]; 622 | } 623 | 624 | #pragma mark - 获取数据 625 | 626 | /** 627 | * 传入字符串 获取指定字段名的值 628 | * 629 | * @param field 字段名 630 | * 631 | * @return 字段值 632 | */ 633 | -(id)getField:(NSString *)field{ 634 | NSDictionary *dict = [[self fieldsWithString:field] find]; 635 | return [[dict allValues] lastObject]; 636 | } 637 | 638 | 639 | /** 640 | * 查询单条记录 641 | * 642 | * @return 字典数据 643 | */ 644 | - (NSDictionary *)find{ 645 | [self setLimit:@"1"]; 646 | NSArray *arr = [self select]; 647 | NSDictionary *result = [NSDictionary dictionaryWithDictionary:[arr lastObject]]; 648 | return result; 649 | } 650 | /** 651 | * 查询全部结果集合 652 | * 653 | * @return 结果数组 654 | */ 655 | - (NSArray *)select{ 656 | NSString *sql = [NSString stringWithFormat:@"SELECT %@ FROM `%@` %@ %@ %@;",self.fieldsString,self.currentTableName,self.where,self.order,self.limit]; 657 | return [self excuteQueryWithSql:sql]; 658 | } 659 | 660 | #pragma mark - 删除数据 661 | /** 662 | * 删除操作 663 | * 664 | * @return 是否成功执行sql 665 | */ 666 | - (BOOL)delete{ 667 | NSString *sql = [NSString stringWithFormat:@"DELETE FROM `%@` %@",self.currentTableName,self.where]; 668 | return [self excuteUpdateWithSql:sql]; 669 | } 670 | /** 671 | * 根据where条件删除操作 672 | * 673 | * @param where where条件[支持类型:字符串或者字典] 674 | * 675 | * @return 是否成功执行sql 676 | */ 677 | - (BOOL)delete:(id)where{ 678 | if([where isKindOfClass:[NSString class]]){ 679 | return [[self whereWithString:where] delete]; 680 | } 681 | if ([where isKindOfClass:[NSDictionary class]]) { 682 | return [[self whereWithDict:where] delete]; 683 | } 684 | NSLog(@"PYFMDB WHERE CONDITIONS IS EMPTY,WHERE DATA:%@",where); 685 | return false; 686 | } 687 | 688 | #pragma mark - count统计 689 | /** 690 | * 统计查询结果集合数量 691 | * 692 | * @return 查询结果数量 693 | */ 694 | -(NSNumber *)queryCount{ 695 | [self fieldsWithString:@"COUNT(*) as tmp"]; 696 | [self setLimit:@"1"]; 697 | NSArray *result = [self select]; 698 | return [[[result lastObject] allValues] lastObject]; 699 | } 700 | 701 | #pragma mark - 设置状态 702 | /** 703 | * 清除设置的状态 704 | * 705 | * @return PYFMDB对象 706 | */ 707 | - (instancetype)clean{ 708 | _fields = nil; 709 | _where = nil; 710 | _limit = nil; 711 | _data = nil; 712 | // _prefix = nil; 713 | _order = nil; 714 | _group = nil; 715 | _cacheID = nil; 716 | _lastSql = nil; 717 | _currentTableName = nil; 718 | return self; 719 | } 720 | /** 721 | * 锁定上次设置的状态 722 | * 723 | * @return PYFMDB对象 724 | */ 725 | -(instancetype)lock{ 726 | _fields_lock = _fields; 727 | _where_lock = _where; 728 | _limit_lock = _limit; 729 | _data_lock = _data; 730 | //_prefix_lock = _prefix; 731 | _order_lock = _order; 732 | _group_lock =_group; 733 | _cacheID_lock =_cacheID; 734 | _currentTableFields_lock = _currentTableFields; 735 | _currentTableName_lock = _currentTableName; 736 | _lastSql_lock = _lastSql; 737 | return self; 738 | } 739 | /** 740 | * 重置到上一次的状态 741 | * 742 | * @return PYFMDB对象 743 | */ 744 | - (instancetype)reset{ 745 | _fields = _fields_lock; 746 | _where = _where_lock; 747 | _limit= _limit_lock; 748 | _data=_data_lock; 749 | // _prefix = _prefix_lock; 750 | _order =_order_lock; 751 | _group =_group_lock; 752 | _cacheID = _cacheID_lock; 753 | _currentTableFields = _currentTableFields_lock; 754 | _currentTableName = _currentTableName_lock; 755 | _lastSql = _lastSql_lock; 756 | return self; 757 | } 758 | #pragma mark - cache 缓存处理方法 759 | /** 760 | * 将数据缓存入文件 761 | * 762 | * @param data 数据源 763 | * @param cacheKey 缓存键名 764 | * 765 | * @return 是否成功缓存 766 | */ 767 | -(BOOL)setObject:(id)data ForCacheKey:(NSString *)cacheKey{ 768 | //记录当前状态,在cache操作后还原 769 | [[[self lock] clean] setPrefix:@""]; 770 | //选择数据表 771 | [self setCurrentTableName:@"_cache"]; 772 | //设置查询条件 773 | [self whereWithDict:@{@"cacheID":cacheKey}]; 774 | //判断是否存在,存在记录则抹掉记录并且重写 775 | if ([self queryCount]>0) { 776 | //删除记录 777 | [self delete]; 778 | } 779 | NSData *cacheData = [data isKindOfClass:[NSData class]] ? data:[NSKeyedArchiver archivedDataWithRootObject:data]; 780 | 781 | //添加数据源 782 | [self dataWithDict:@{@"cacheID":cacheKey,@"cacheData":cacheData}]; 783 | return [self add] && [self reset]; 784 | } 785 | /** 786 | * 根据缓存键名读取缓存内容 787 | * 788 | * @param cacheKey 缓存键名 789 | * 790 | * @return 缓存键值 791 | */ 792 | - (id )objectForCacheKey:(NSString *)cacheKey{ 793 | //记录当前状态,在cache操作后还原 794 | [[self lock] clean]; 795 | //选择数据表 796 | [self setCurrentTableName:@"_cache"]; 797 | //设置查询条件 798 | [self whereWithDict:@{@"cacheID":cacheKey}]; 799 | //判断是否存在,存在记录则读取缓存,不存在则返回nil 800 | if ([self queryCount]==0) { 801 | return nil; 802 | } 803 | //读取缓存内容,并根据相应的格式返回缓存的数据格式 804 | return [NSKeyedUnarchiver unarchiveObjectWithData:[self getField:@"cacheData"]]; 805 | } 806 | 807 | #pragma mark - 清空数据表 808 | 809 | /** 810 | * 清空数据表 811 | * 812 | * @param tableName 表名 813 | */ 814 | -(void)truncateTableWithTableName:(NSString *)tableName{ 815 | [self deleteTableWithDict:nil :tableName]; 816 | } 817 | /** 818 | * 公共删除方法 819 | * 820 | * @param dict 字典 821 | */ 822 | -(void)deleteTableWithDict:(NSDictionary *)dict : (NSString *)tableName{ 823 | //重置查询条件 824 | [self clean]; 825 | //选择要操作的表名 826 | [self setCurrentTableName:tableName]; 827 | //查询数据库是否存在当前待更新的数据源 828 | [self whereWithDict:dict]; 829 | if ([[self find] count]>0) { 830 | //存在则删除,dict 为空代表清空整个表 831 | dict==nil ? [self delete:@"1"]:[self delete:dict]; 832 | } 833 | //打印sql 834 | //NSLog(@"currentSql:%@",self.lastSql); 835 | } 836 | 837 | #pragma mark - 数据表是否为空 838 | /** 839 | * 数据表是否为空 840 | * 841 | * @param tableName 数据库表名 842 | * 843 | * @return bool类型值 YES =为空, NO = 不为空 844 | */ 845 | -(BOOL)isEmptyWithTableName:(NSString *)tableName{ 846 | //重置查询条件 847 | [self clean]; 848 | //选择要操作的表名 849 | [self setCurrentTableName:tableName]; 850 | return [[self find] count]==0; 851 | } 852 | 853 | #pragma mark - 数据表展示 854 | /** 855 | * 展示Table数据 856 | * 857 | * @param fields 字段,(多个字段半角逗号隔开) 858 | * @param page 当前页 859 | * @param pagesize 分页大小 860 | * @param tableName 表名 861 | * 862 | * @return 数组 863 | */ 864 | -(NSArray *)showTableWithFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andTableName:(NSString *)tableName{ 865 | return [self showTableWithFields:fields andPages:page andPageSize:pagesize andOrder:nil andTableName:tableName]; 866 | } 867 | /** 868 | * 展示Table数据 869 | * 870 | * @param page 当前页 871 | * @param pagesize 分页大小 872 | * @param tableName 表名 873 | * 874 | * @return 数组 875 | */ 876 | -(NSArray *)showTableWithPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andTableName:(NSString *)tableName{ 877 | return [self showTableWithFields:nil andPages:page andPageSize:pagesize andOrder:nil andTableName:tableName]; 878 | } 879 | 880 | 881 | /** 882 | * 展示Table数据 883 | * 884 | * @param page 当前页 885 | * @param pagesize 分页大小 886 | * @param order 排序 887 | * @param tableName 表名 888 | * 889 | * @return 数组 890 | */ 891 | -(NSArray *)showTableWithPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order andTableName:(NSString *)tableName{ 892 | return [self showTableWithFields:nil andPages:page andPageSize:pagesize andOrder:order andTableName:tableName]; 893 | } 894 | 895 | /** 896 | * 展示Table数据 897 | * 898 | * @param page 当前页 899 | * @param pagesize 分页大小 900 | * @param order 排序 901 | * @param tableName 表名 902 | * 903 | * @return 数组 904 | */ 905 | -(NSArray *)showTableWithFields:(NSString *)fields andPages:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order andTableName:(NSString *)tableName{ 906 | //重置查询条件 907 | [self clean]; 908 | //选择要操作的表名 909 | [self setCurrentTableName:tableName]; 910 | int startNum = page<=0 ? 0:(int)((page -1)*pagesize); 911 | int endNum = (int)(page*pagesize); 912 | //limit条件 913 | [self limitWithStart:startNum End:endNum]; 914 | //field条件 915 | if (![fields isEqual:nil]) { 916 | [self fieldsWithString:fields]; 917 | } 918 | //order条件 919 | if (![order isEqual:nil]) { 920 | [self setOrder:order]; 921 | } 922 | //select查询 923 | NSArray *result = [self select]; 924 | return result; 925 | 926 | } 927 | #pragma mark - 索引操作 928 | /** 929 | * 为字段创建普通索引 930 | * 931 | * @param field 字段名称 932 | * @param tableName 表名 933 | * 934 | * @return 执行是否成功 935 | */ 936 | -(bool)createIndexWithField:(NSString *)field andTableName:(NSString *)tableName{ 937 | __block NSMutableString *sql = [NSMutableString stringWithFormat:@"CREATE INDEX IF NOT EXISTS %@ ON %@%@(%@)",field,_prefix,tableName,field]; 938 | _lastSql = sql; 939 | return [self excuteUpdateWithSql:sql]; 940 | } 941 | @end 942 | -------------------------------------------------------------------------------- /PYFMDB/PYStructure.h: -------------------------------------------------------------------------------- 1 | // 2 | // PYStructure.h 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import 10 | typedef NS_ENUM(NSInteger, PYStructureType) { 11 | PYStructureTypeAutoInc = 0,//AUTO INCREAMNT && PRIMARY KEY INT 12 | PYStructureTypePrimaryInt = 1,//PRIMARY KEY INT 13 | PYStructureTypePrimaryText = 2,//PRIMARY KEY TEXT 14 | PYStructureTypeNormalInt = 3,//COMMON COLUMN KEY INT 15 | PYStructureTypeNormalText = 4,//COMMON COLUMN KEY TEXT 16 | }; 17 | @interface PYStructure : NSObject 18 | @property(nonatomic,strong)NSMutableArray *structureArray; 19 | @property(nonatomic,strong)NSDictionary *structureDictory; 20 | 21 | 22 | -(void)addWithField:(NSString *)field andType:(PYStructureType)type; 23 | -(NSArray *)fieldsArray; 24 | -(NSString *)fieldsString; 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /PYFMDB/PYStructure.m: -------------------------------------------------------------------------------- 1 | // 2 | // PYStructure.m 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "PYStructure.h" 10 | 11 | @implementation PYStructure 12 | -(void)addWithField:(NSString *)field andType:(PYStructureType)type{ 13 | NSDictionary *structure = [NSDictionary dictionary]; 14 | if (type==PYStructureTypeAutoInc) { 15 | structure = @{field:@"integer primary key autoincrement"}; 16 | } 17 | else if (type==PYStructureTypeNormalInt){ 18 | structure = @{field:@"integer not null"}; 19 | } 20 | else if (type ==PYStructureTypeNormalText){ 21 | structure = @{field:@"text not null"}; 22 | } 23 | else if(type==PYStructureTypePrimaryInt){ 24 | structure = @{field:@"integer primary key"}; 25 | } 26 | else if (type==PYStructureTypePrimaryText){ 27 | structure = @{field:@"text primary key"}; 28 | } 29 | [self.structureArray addObject:structure]; 30 | } 31 | 32 | -(NSDictionary *)structureDictory{ 33 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 34 | for (NSDictionary *dic in self.structureArray) { 35 | [dict addEntriesFromDictionary:dic]; 36 | } 37 | return [NSDictionary dictionaryWithDictionary:dict]; 38 | } 39 | 40 | 41 | 42 | -(NSMutableArray *)structureArray{ 43 | if (_structureArray) { 44 | return _structureArray; 45 | } 46 | _structureArray = [NSMutableArray array]; 47 | return _structureArray; 48 | } 49 | -(NSArray *)fieldsArray{ 50 | return [[self structureDictory] allKeys]; 51 | } 52 | -(NSString *)fieldsString{ 53 | NSString *fields = nil; 54 | for (NSString *obj in self.fieldsArray) { 55 | if (fields==nil) { 56 | fields = obj; 57 | } 58 | else{ 59 | fields = [NSString stringWithFormat:@"%@,%@",fields,obj]; 60 | } 61 | } 62 | return fields; 63 | } 64 | @end 65 | -------------------------------------------------------------------------------- /PYFMDB/PYTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // PYTable.h 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PYFMDB.h" 11 | #import "PYStructure.h" 12 | @interface PYTable : NSObject 13 | @property (nonatomic,copy) PYFMDB * db; 14 | 15 | @property(nonatomic,strong)NSString *tableName; 16 | 17 | @property(nonatomic,strong)NSString *databaseName; 18 | 19 | @property(nonatomic,strong)PYStructure *structure; 20 | 21 | @property(nonatomic,strong)NSArray *indexes; 22 | 23 | @property(nonatomic,strong)NSString *prefixUserDefaultKey; 24 | 25 | @property(nonatomic,strong)NSString *prefixBeforeKey; 26 | 27 | @property(nonatomic,strong)NSString *prefixAfterKey; 28 | 29 | 30 | 31 | -(void)truncate; 32 | 33 | -(NSUInteger)count; 34 | 35 | -(BOOL)isEmpty; 36 | 37 | -(NSString *)lastSql; 38 | 39 | -(NSString *)databasePath; 40 | 41 | #pragma mark - CREATE 42 | 43 | -(void)addFields:(NSDictionary *)fields; 44 | 45 | -(void)addFieldsIfNotExist:(NSDictionary *)fields; 46 | 47 | -(void)addOrUpdateFields:(NSDictionary *)fields andWhere:(NSString *)where; 48 | 49 | #pragma mark - UPDATE 50 | -(void)updateFields:(NSDictionary *)fields andWhere:(NSString *)where; 51 | 52 | -(void)setField:(NSString *)field andValue:(id)value andWhere:(NSString *)where; 53 | 54 | 55 | #pragma mark - DELETE 56 | 57 | -(void)deleteWithWhere:(NSString *)where; 58 | 59 | #pragma mark - READ 60 | 61 | -(id)getField:(NSString *)field andWhere:(NSString *)where; 62 | 63 | -(NSDictionary *)findWithWhere:(NSString *)where; 64 | 65 | -(NSArray *)selectAll; 66 | 67 | -(NSArray *)selectWithWhere:(NSString *)where; 68 | 69 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields; 70 | 71 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize; 72 | 73 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order; 74 | 75 | #pragma mark - HAS 76 | 77 | -(BOOL)hasWhere:(NSString *)where; 78 | 79 | -(BOOL)hasFields:(NSDictionary *)fields; 80 | 81 | #pragma mark - origin sql 82 | 83 | -(NSArray *)executeQueryWithSql:(NSString *)sql; 84 | 85 | -(BOOL)executeUpdateWithSql:(NSString *)sql; 86 | 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /PYFMDB/PYTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // PYTable.m 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "PYTable.h" 10 | #define PYTablePrefixUserDefaultKey @"PYFMDBKEY" 11 | #define PYTablePrefixBeforeKey @"" 12 | #define PYTablePrefixAfterKey @"" 13 | #define PYDataBaseName @"pyfmdb.sqlite" 14 | @class PYFMDB; 15 | @implementation PYTable 16 | -(instancetype)init{ 17 | if (self = [super init]) { 18 | //create the table 19 | if (![self.structure.structureDictory isEqual:nil]) { 20 | [self.db createTableWithDict:self.structure.structureDictory :self.tableName]; 21 | } 22 | //create indexes 23 | if (self.indexes.count >0) { 24 | for (NSString *index in self.indexes) { 25 | [self.db createIndexWithField:index andTableName:self.tableName]; 26 | } 27 | } 28 | } 29 | return self; 30 | } 31 | 32 | 33 | -(PYFMDB *)db{ 34 | if (_db) { 35 | return _db; 36 | } 37 | _db = [PYFMDB dbWithDbName:self.databaseName]; 38 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 39 | NSString *userID = [userDefaults objectForKey:self.prefixUserDefaultKey]; 40 | _db.prefix = userID==nil ? [NSString stringWithFormat:@"%@%@",self.prefixBeforeKey,self.prefixAfterKey]:[NSString stringWithFormat:@"%@%@%@",self.prefixBeforeKey,userID,self.prefixAfterKey]; 41 | return _db; 42 | } 43 | 44 | -(NSString *)databaseName{ 45 | if (_databaseName) { 46 | return _databaseName; 47 | } 48 | _databaseName = PYDataBaseName; 49 | return _databaseName; 50 | } 51 | 52 | -(NSString *)prefixAfterKey{ 53 | if (_prefixAfterKey) { 54 | return _prefixAfterKey; 55 | } 56 | _prefixAfterKey = PYTablePrefixAfterKey; 57 | return _prefixAfterKey; 58 | } 59 | 60 | -(NSString *)prefixBeforeKey{ 61 | if (_prefixBeforeKey) { 62 | return _prefixBeforeKey; 63 | } 64 | _prefixBeforeKey = PYTablePrefixBeforeKey; 65 | return _prefixBeforeKey; 66 | } 67 | 68 | -(NSString *)prefixUserDefaultKey{ 69 | if (_prefixUserDefaultKey) { 70 | return _prefixUserDefaultKey; 71 | } 72 | _prefixUserDefaultKey = PYTablePrefixUserDefaultKey; 73 | return _prefixUserDefaultKey; 74 | } 75 | 76 | -(PYStructure *)structure{ 77 | if (_structure) { 78 | return _structure; 79 | } 80 | _structure = [[PYStructure alloc] init]; 81 | return _structure; 82 | } 83 | 84 | -(void)truncate{ 85 | [self.db truncateTableWithTableName:self.tableName]; 86 | } 87 | 88 | -(NSUInteger)count{ 89 | [self.db clean]; 90 | [self.db setCurrentTableName:self.tableName]; 91 | return [[self.db select] count]; 92 | } 93 | 94 | -(BOOL)isEmpty{ 95 | if ([self count] >0) { 96 | return false; 97 | } 98 | return true; 99 | } 100 | 101 | -(NSString *)lastSql{ 102 | return self.db.lastSql; 103 | } 104 | 105 | -(NSString *)databasePath{ 106 | return self.db.dbPath; 107 | } 108 | 109 | #pragma mark - create 110 | 111 | -(void)addFields:(NSDictionary *)fields{ 112 | [self.db clean]; 113 | [self.db setCurrentTableName:self.tableName]; 114 | [self.db add:fields]; 115 | } 116 | 117 | -(void)addFieldsIfNotExist:(NSDictionary *)fields{ 118 | if (![self hasFields:fields]) { 119 | [self addFields:fields]; 120 | } 121 | } 122 | 123 | -(void)addOrUpdateFields:(NSDictionary *)fields andWhere:(NSString *)where{ 124 | [self hasWhere:where] ? [self updateFields:fields andWhere:where]: [self addFields:fields]; 125 | } 126 | 127 | #pragma mark - update 128 | -(void)updateFields:(NSDictionary *)fields andWhere:(NSString *)where{ 129 | [self.db clean]; 130 | [self.db setCurrentTableName:self.tableName]; 131 | [self.db whereWithString:where]; 132 | [self.db save:fields]; 133 | } 134 | -(void)setField:(NSString *)field andValue:(id)value andWhere:(NSString *)where{ 135 | [self updateFields:@{field:value} andWhere:where]; 136 | } 137 | 138 | #pragma mark - delete 139 | -(void)deleteWithWhere:(NSString *)where{ 140 | [self.db clean]; 141 | [self.db setCurrentTableName:self.tableName]; 142 | if (![where isEqual:nil]) { 143 | [self.db whereWithString:where]; 144 | } 145 | [self.db delete]; 146 | } 147 | #pragma mark - read 148 | -(id)getField:(NSString *)field andWhere:(NSString *)where{ 149 | NSDictionary *find = [self findWithWhere:where]; 150 | return [find objectForKey:field]; 151 | } 152 | -(NSDictionary *)findWithWhere:(NSString *)where{ 153 | [self.db clean]; 154 | [self.db setCurrentTableName:self.tableName]; 155 | if (![where isEqual:nil]) { 156 | [self.db whereWithString:where]; 157 | } 158 | [self.db fieldsWithString:self.structure.fieldsString]; 159 | return [self.db find]; 160 | } 161 | 162 | -(NSArray *)selectWithWhere:(NSString *)where{ 163 | return [self selectWithWhere:where andFields:self.structure.fieldsString andPage:0 andPageSize:0 andOrder:nil]; 164 | } 165 | -(NSArray *)selectAll{ 166 | return [self selectWithWhere:@"1"]; 167 | } 168 | 169 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields{ 170 | return [self selectWithWhere:where andFields:fields andPage:0 andPageSize:0 andOrder:nil]; 171 | } 172 | 173 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize{ 174 | return [self selectWithWhere:where andFields:fields andPage:page andPageSize:pagesize andOrder:nil]; 175 | } 176 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order{ 177 | //clean state 178 | [self.db clean]; 179 | //tablename 180 | [self.db setCurrentTableName:self.tableName]; 181 | if (pagesize >0) { 182 | int startNum = page<=0 ? 0:(int)((page -1)*pagesize); 183 | int endNum = (int)(page*pagesize); 184 | //limit 185 | [self.db limitWithStart:startNum End:endNum]; 186 | } 187 | //where 188 | if (![where isEqual:nil]) { 189 | [self.db whereWithString:where]; 190 | } 191 | //field 192 | if (![fields isEqual:nil]) { 193 | if ([fields isEqualToString:@"*"]) { 194 | [self.db fieldsWithString:self.structure.fieldsString]; 195 | } 196 | else{ 197 | [self.db fieldsWithString:fields]; 198 | } 199 | } 200 | else{ 201 | [self.db fieldsWithString:self.structure.fieldsString]; 202 | } 203 | //order 204 | if (![order isEqual:nil]) { 205 | [self.db setOrder:order]; 206 | } 207 | return [self.db select]; 208 | } 209 | 210 | #pragma mark - has 211 | 212 | -(BOOL)hasWhere:(NSString *)where{ 213 | [self.db clean]; 214 | [self.db setCurrentTableName:self.tableName]; 215 | [self.db whereWithString:where]; 216 | return [[self.db queryCount] intValue] >0; 217 | } 218 | 219 | -(BOOL)hasFields:(NSDictionary *)fields{ 220 | [self.db clean]; 221 | [self.db setCurrentTableName:self.tableName]; 222 | [self.db whereWithDict:fields]; 223 | return [[self.db queryCount] intValue] >0; 224 | } 225 | 226 | 227 | #pragma mark - origin sql 228 | -(NSArray *)executeQueryWithSql:(NSString *)sql{ 229 | return [self.db excuteQueryWithSql:sql]; 230 | } 231 | 232 | -(BOOL)executeUpdateWithSql:(NSString *)sql{ 233 | return [self.db excuteUpdateWithSql:sql]; 234 | } 235 | 236 | 237 | @end 238 | 239 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PYFMDB 2 | ========== 3 | 4 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)]() 5 | ![Pod version](http://img.shields.io/cocoapods/v/PYFMDB.svg?style=flat) 6 | [![CocoaPods](https://img.shields.io/cocoapods/metrics/doc-percent/PYFMDB.svg)]() 7 | ![Platform info](http://img.shields.io/cocoapods/p/PYFMDB.svg?style=flat) 8 | [![Language](http://img.shields.io/badge/language-OC-brightgreen.svg?style=flat 9 | )](https://en.wikipedia.org/wiki/Objective-C) 10 | [![Build Status](https://api.travis-ci.org/iterrypeng/PYFMDB.svg?branch=master)](https://travis-ci.org/iterrypeng/PYFMDB) 11 | ##More Versions 12 | * [简体中文](README_ZH.md) 13 | * [繁体中文](README_TW.md) 14 | 15 | ## Intro 16 | PYFMDB base on FMDB, it is a simple ORM! 17 | 18 | The package has three parts 19 | * `PYFMDB` ORM base on FMDB 20 | * `PYTable` Init database,Create table,simple CURD methods 21 | * `PYStructure` Define the table's structure 22 | 23 | ##Getting Started 24 | ###Import PYFMDB 25 | #### CocoaPods 26 | 27 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. 28 | To integrate PYFMDB into your Xcode project using CocoaPods, specify it in your `Podfile`: 29 | 30 | ``` ruby 31 | pod 'PYFMDB' 32 | ``` 33 | #### By Hand 34 | Copy the dirs `PYFMDB`,`FMDB` into your project 35 | 36 | Search the build-setting option `Link Binary With Libraries` and add `libsqlite3.dylib` into it like this 37 | ![](http://blog.devtang.com/images/key-value-store-setup.jpg) 38 | 39 | ###Create Table 40 | Create Table extends `PYTable`,In the demo project, I have named it "CarTable" 41 | #### Set TableName 42 | The codes from CarTable.m below 43 | ``` 44 | -(NSString *)tableName{ 45 | return @"car"; 46 | } 47 | ``` 48 | #### Set Table structure 49 | The codes from CarTable.m below 50 | ``` 51 | -(PYStructure *)structure{ 52 | PYStructure * st = [[PYStructure alloc] init]; 53 | [st addWithField:@"id" andType:PYStructureTypeAutoInc]; 54 | [st addWithField:@"name" andType:PYStructureTypeNormalText]; 55 | [st addWithField:@"wheels" andType:PYStructureTypeNormalInt]; 56 | return st; 57 | } 58 | ``` 59 | #####`PYStructureType` 60 | * PYStructureTypeAutoInc = 0,//Auto Increamnt, Primary Key, Int,Not Null 61 | * PYStructureTypePrimaryInt = 1,//Primary Key, Int,Not Null 62 | * PYStructureTypePrimaryText = 2,//Primary Key, Text,Not Null 63 | * PYStructureTypeNormalInt = 3,//Int,Not Null 64 | * PYStructureTypeNormalText = 4,//Text,Not Null 65 | 66 | ###Table methods 67 | Init Table 68 | ``` 69 | CarTable *table = [[CarTable alloc] init]; 70 | ``` 71 | ####Create 72 | Insert fields into the Table 73 | ``` 74 | NSDictionary *fields = @{@"name":@"BMW",@"wheels":@1}; 75 | [table addFields:fields]; 76 | ``` 77 | If the table has the fields,then Do Update; otherwise, Do Create; 78 | ``` 79 | NSDictionary *fields = @{@"name":@"BMW",@"wheels":@1}; 80 | [table addOrUpdateFields:fields andWhere:@"name='BMW'"]; 81 | ``` 82 | If the table has the fields, then Do Ignore; otherwise, Do Create; 83 | ``` 84 | NSDictionary *fields = @{@"name":@"BMW",@"wheels":@1}; 85 | [table addFieldsIfNotExist:fields]; 86 | ``` 87 | ####Delete 88 | Set where with one condition for delete 89 | ``` 90 | NSString *where = @"name='BMW'"; 91 | [table deleteWithWhere:where]; 92 | ``` 93 | Set where with conditions for delete 94 | ``` 95 | NSString *where = @"name='BMW' and id >=5"; 96 | [table deleteWithWhere:where]; 97 | ``` 98 | Truncate the Table 99 | ``` 100 | [table truncate]; 101 | ``` 102 | ####Update 103 | Update fields 104 | ``` 105 | NSString *where = @"name='BMW'"; 106 | NSDictionary *fields = @{@"name":@"MINI",@"wheels":@2}; 107 | [table updateFields:fields andWhere:where]; 108 | ``` 109 | Update one field 110 | ``` 111 | [table setField:@"name" andValue:@"BMW" andWhere:@"name='MINI'"]; 112 | ``` 113 | ####Read 114 | All lines,all fields 115 | ``` 116 | NSArray *results = [table selectAll]; 117 | ``` 118 | Where conditions,all fields 119 | ``` 120 | NSString *where = @"name='BMW'"; 121 | NSArray *results = [table selectWithWhere:where]; 122 | ``` 123 | Where conditions,some of the fields 124 | ``` 125 | NSString *where = @"name='BMW'"; 126 | NSString *fields = @"id,wheels"; 127 | NSArray *results = [table selectWithWhere:where andFields:fields]; 128 | ``` 129 | Where conditions,some of the fields,paging 130 | ``` 131 | NSString *where = @"name='BMW'"; 132 | NSString *fields = @"id,wheels"; 133 | //NSString *fields = @"*";//all fields 134 | NSArray *results = [table selectWithWhere:where andFields:fields andPage:1 andPageSize:10];//first page,pagesize=10 135 | ``` 136 | Where conditions,some of the fields,paging,ordering 137 | ``` 138 | NSString *where = @"name='BMW'"; 139 | NSString *fields = @"id,wheels"; 140 | //ordering has "asc","desc";one field order: id desc;some fields order: id,wheel asc 141 | NSArray *results = [table selectWithWhere:where andFields:fields andPage:1 andPageSize:10 andOrder:@"id desc"]; 142 | ``` 143 | Find one line fields 144 | ``` 145 | NSString *where = @"name='BMW'"; 146 | NSDictionary *result = [table findWithWhere:where]; 147 | ``` 148 | Find one field 149 | ``` 150 | id result = [table getField:@"name" andWhere:@"id=1"]; 151 | ``` 152 | ####Table Count 153 | ``` 154 | NSUInteger tableCount = [table count]; 155 | ``` 156 | ####IsEmpty? 157 | ``` 158 | if([table isEmpty]){ 159 | //table is empty 160 | } 161 | ``` 162 | ####Has fields? 163 | ``` 164 | NSDictionary *fields = @{@"name":@"BMW",@"wheels":@1}; 165 | if([table hasFields:fields]){ 166 | //Yes 167 | } 168 | ``` 169 | ####Has where? 170 | ``` 171 | if([table hasWhere:@"name='BMW'"]){ 172 | //Yes 173 | } 174 | ``` 175 | 176 | ####Origin Sql Support 177 | Execute query sql 178 | ``` 179 | NSString *sql = @"select * from car"; 180 | NSArray *results = [table executeQueryWithSql:sql]; 181 | ``` 182 | Execute update sql 183 | ``` 184 | NSString *sql = @"delete from car where name='BMW'"; 185 | BOOL result = [table executeUpdateWithSql:sql]; 186 | ``` 187 | 188 | ####Debug 189 | ``` 190 | NSLog(@"dbpath:%@",table.databasePath); 191 | NSLog(@"lastSql:%@",table.lastSql); 192 | NSLog(@"dbname:%@",table.databaseName); 193 | NSLog(@"tablename:%@",table.tableName); 194 | NSLog(@"table structure:%@",table.structure.structureDictory); 195 | NSLog(@"table fields:%@",table.structure.fieldsString); 196 | ``` 197 | 198 | ## Contact 199 | 200 | If you find an issue, just [open a ticket](https://github.com/iterrypeng/PYFMDB/issues/new) on it. Pull requests are warmly welcome as well. 201 | 202 | ## License 203 | 204 | PYFMDB is released under the MIT license. See LICENSE for details. 205 | 206 | -------------------------------------------------------------------------------- /README_TW.md: -------------------------------------------------------------------------------- 1 | PYFMDB 2 | ========== 3 | 4 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)]() 5 | ![Pod version](http://img.shields.io/cocoapods/v/PYFMDB.svg?style=flat) 6 | [![CocoaPods](https://img.shields.io/cocoapods/metrics/doc-percent/PYFMDB.svg)]() 7 | ![Platform info](http://img.shields.io/cocoapods/p/PYFMDB.svg?style=flat) 8 | [![Language](http://img.shields.io/badge/language-OC-brightgreen.svg?style=flat 9 | )](https://en.wikipedia.org/wiki/Objective-C) 10 | [![Build Status](https://api.travis-ci.org/iterrypeng/PYFMDB.svg?branch=master)](https://travis-ci.org/iterrypeng/PYFMDB) 11 | ##其他語言版本 12 | [English](README.md) [簡體中文](README_ZH.md) 13 | ## 前言 14 | 之前是壹直做web開發,對於做web開發的人而言壹定熟悉各種ORM,各種語言針對mysql的ORM有很多,比如PHP的各類框架yii,thinkphp,laravel,ruby語言的rails, GO語言的beego等,IOS開發則面對的數據庫是sqlite。FMDB 是基於sqlite的數據庫操作類,穩定,但用起來還是不夠簡潔,PYFMDB是基於FMDB的更高層次的數據庫操作類。 15 | ## 程序介紹 16 | `PYFMDB`分為三部分,`PYFMDB` 基於FMDB負責數據庫底層操作處理,`PYTable`是自定義Table的基類,提供基於具體數據庫表的操作,是更高層次的封裝PYFMDB,`PYStructure`是定義數據庫表結構處理類。 17 | ##快速入門 18 | ###導入PYFMDB 19 | 妳可以在 Podfile 中加入下面壹行代碼來使用PYFMDB 20 | 21 | pod 'PYFMDB' 22 | 23 | 妳也可以手動添加源碼使用本項目,將開源代碼中的`PYFMDB`和`FMDB` 目錄添加到妳的工程中,並且在工程設置的`Link Binary With Libraries`中,增加`libsqlite3.dylib`,如下圖所示: 24 | 25 | ![](http://blog.devtang.com/images/key-value-store-setup.jpg) 26 | 27 | ###創建自定義Table類 28 | 創建壹個Table類繼承`PYTable`,例如演示代碼中創建了`CarTable`類。 29 | #### 設置數據庫表名 30 | 在CarTable.m 中 重寫如下方法: 31 | ``` 32 | -(NSString *)tableName{ 33 | return @"car"; 34 | } 35 | ``` 36 | #### 設置數據庫表結構 37 | 在CarTable.m 中 重寫如下方法: 38 | ``` 39 | -(PYStructure *)structure{ 40 | PYStructure * st = [[PYStructure alloc] init]; 41 | [st addWithField:@"id" andType:PYStructureTypeAutoInc]; 42 | [st addWithField:@"name" andType:PYStructureTypeNormalText]; 43 | [st addWithField:@"wheels" andType:PYStructureTypeNormalInt]; 44 | return st; 45 | } 46 | ``` 47 | #####`PYStructureType` 48 | * PYStructureTypeAutoInc = 0,//主鍵,int類型,自增 49 | * PYStructureTypePrimaryInt = 1,//主鍵,int類型,自增 50 | * PYStructureTypePrimaryText = 2,//主鍵,text類型 51 | * PYStructureTypeNormalInt = 3,//普通列,int類型 52 | * PYStructureTypeNormalText = 4,//普通列,text類型 53 | 54 | ### 自定義Table類的使用 55 | table類可以實現針對當前table的增刪改查數據庫操作。 56 | ``` 57 | CarTable *table = [[CarTable alloc] init]; 58 | ``` 59 | ####新增數據 60 | 普通新增數據 61 | ``` 62 | NSDictionary *fields = @{@"name":@"寶馬",@"wheels":@1}; 63 | [table addFields:fields]; 64 | ``` 65 | 新增或者更新數據【判斷數據是否已存在,存在則更新數據,不存在則新增數據】 66 | ``` 67 | NSDictionary *fields = @{@"name":@"寶馬",@"wheels":@1}; 68 | [table addOrUpdateFields:fields andWhere:@"name='寶馬'"]; 69 | ``` 70 | 判斷是否已經存在數據,僅不存在數據時更新數據 71 | ``` 72 | NSDictionary *fields = @{@"name":@"寶馬",@"wheels":@1}; 73 | [table addFieldsIfNotExist:fields]; 74 | ``` 75 | ####刪除數據 76 | 指定字段刪除 77 | ``` 78 | NSString *where = @"name='寶馬'"; 79 | [table deleteWithWhere:where]; 80 | ``` 81 | 多種條件刪除 82 | ``` 83 | NSString *where = @"name='寶馬' and id >=5"; 84 | [table deleteWithWhere:where]; 85 | ``` 86 | 清空數據表 87 | ``` 88 | [table truncate]; 89 | ``` 90 | ####更新數據 91 | 更新多個字段 92 | ``` 93 | NSString *where = @"name='寶馬'"; 94 | NSDictionary *fields = @{@"name":@"奔馳",@"wheels":@2}; 95 | [table updateFields:fields andWhere:where]; 96 | ``` 97 | 更新1個字段 98 | ``` 99 | [table setField:@"name" andValue:@"奔馳" andWhere:@"name='寶馬'"]; 100 | ``` 101 | ####查詢數據 102 | 查詢表全部數據,全部字段,返回的結果為NSArray 103 | ``` 104 | NSArray *results = [table selectAll]; 105 | ``` 106 | 按條件查詢數據,全部字段,返回的結果為NSArray 107 | ``` 108 | NSString *where = @"name='寶馬'"; 109 | NSArray *results = [table selectWithWhere:where]; 110 | ``` 111 | 按條件查詢數據,指定字段,返回結果為NSArray 112 | 多個字段用半角逗號隔開 113 | ``` 114 | NSString *where = @"name='寶馬'"; 115 | NSString *fields = @"id,wheels"; 116 | NSArray *results = [table selectWithWhere:where andFields:fields]; 117 | ``` 118 | 按條件查詢數據,指定字段,設置分頁,返回結果為NSArray 119 | 要查詢全部字段時 用 * 代表查詢全部字段 120 | ``` 121 | NSString *where = @"name='寶馬'"; 122 | NSString *fields = @"id,wheels"; 123 | //NSString *fields = @"*"; 124 | NSArray *results = [table selectWithWhere:where andFields:fields andPage:1 andPageSize:10];//取第壹頁,每頁10條 125 | ``` 126 | 按條件查詢數據,指定字段,設置分頁,設置排序,返回結果為NSArray 127 | 排序中 desc 代表 降序,asc代表升序 128 | 單個字段排序 如 id desc 129 | 多個字段排序 如 id,wheel asc 130 | ``` 131 | NSString *where = @"name='寶馬'"; 132 | NSString *fields = @"id,wheels"; 133 | //NSString *fields = @"*"; 134 | NSArray *results = [table selectWithWhere:where andFields:fields andPage:1 andPageSize:10 andOrder:@"id desc"]; 135 | ``` 136 | 按條件查詢單行數據,返回結果為NSDictionary 137 | ``` 138 | NSString *where = @"name='寶馬'"; 139 | NSDictionary *result = [table findWithWhere:where]; 140 | ``` 141 | 按條件查詢單行單個字段數據,返回結果為id類型 142 | ``` 143 | id result = [table getField:@"name" andWhere:@"id=1"]; 144 | ``` 145 | ####統計表總行數 146 | ``` 147 | NSUInteger tableCount = [table count]; 148 | ``` 149 | ####判斷表是否為空 150 | ``` 151 | if([table isEmpty]){ 152 | //table is empty 153 | } 154 | ``` 155 | ####判斷數據是否存在 156 | ``` 157 | NSDictionary *fields = @{@"name":@"寶馬",@"wheels":@1}; 158 | if([table hasFields:fields]){ 159 | //數據已存在 160 | } 161 | ``` 162 | ####判斷where查詢是否有數據 163 | ``` 164 | if([table hasWhere:@"name='寶馬'"]){ 165 | //有查詢結果 166 | } 167 | ``` 168 | ####原生sql支持 169 | 執行壹個sql查詢 170 | ``` 171 | NSString *sql = @"select * from car"; 172 | NSArray *results = [table executeQueryWithSql:sql]; 173 | ``` 174 | 執行壹個sql操作,如更新,刪除,插入等 175 | ``` 176 | NSString *sql = @"delete from car where name='BMW'"; 177 | BOOL result = [table executeUpdateWithSql:sql]; 178 | ``` 179 | 180 | 181 | 182 | ####調試信息 183 | ``` 184 | NSLog(@"dbpath:%@",table.databasePath);//數據庫位置 185 | NSLog(@"lastSql:%@",table.lastSql);//最後執行的sql 186 | NSLog(@"dbname:%@",table.databaseName);//數據庫名 187 | NSLog(@"tablename:%@",table.tableName);//數據表名 188 | NSLog(@"table structure:%@",table.structure.structureDictory);//數據表結構 189 | NSLog(@"table fields:%@",table.structure.fieldsString);//數據表字段 190 | ``` 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /README_ZH.md: -------------------------------------------------------------------------------- 1 | PYFMDB 2 | ========== 3 | 4 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)]() 5 | ![Pod version](http://img.shields.io/cocoapods/v/PYFMDB.svg?style=flat) 6 | [![CocoaPods](https://img.shields.io/cocoapods/metrics/doc-percent/PYFMDB.svg)]() 7 | ![Platform info](http://img.shields.io/cocoapods/p/PYFMDB.svg?style=flat) 8 | [![Language](http://img.shields.io/badge/language-OC-brightgreen.svg?style=flat 9 | )](https://en.wikipedia.org/wiki/Objective-C) 10 | [![Build Status](https://api.travis-ci.org/iterrypeng/PYFMDB.svg?branch=master)](https://travis-ci.org/iterrypeng/PYFMDB) 11 | ##其他语言版本 12 | [English](README.md) [繁体中文](README_TW.md) 13 | ## 前言 14 | 之前是一直做web开发,对于做web开发的人而言一定熟悉各种ORM,各种语言针对mysql的ORM有很多,比如PHP的各类框架yii,thinkphp,laravel,ruby语言的rails, GO语言的beego等,IOS开发则面对的数据库是sqlite。FMDB 是基于sqlite的数据库操作类,稳定,但用起来还是不够简洁,PYFMDB是基于FMDB的更高层次的数据库操作类。 15 | ## 程序介绍 16 | `PYFMDB`分为三部分,`PYFMDB` 基于FMDB负责数据库底层操作处理,`PYTable`是自定义Table的基类,提供基于具体数据库表的操作,是更高层次的封装PYFMDB,`PYStructure`是定义数据库表结构处理类。 17 | ##快速入门 18 | ###导入PYFMDB 19 | 你可以在 Podfile 中加入下面一行代码来使用PYFMDB 20 | 21 | pod 'PYFMDB' 22 | 23 | 你也可以手动添加源码使用本项目,将开源代码中的`PYFMDB`和`FMDB` 目录添加到你的工程中,并且在工程设置的`Link Binary With Libraries`中,增加`libsqlite3.dylib`,如下图所示: 24 | 25 | ![](http://blog.devtang.com/images/key-value-store-setup.jpg) 26 | 27 | ###创建自定义Table类 28 | 创建一个Table类继承`PYTable`,例如演示代码中创建了`CarTable`类。 29 | #### 设置数据库表名 30 | 在CarTable.m 中 重写如下方法: 31 | ``` 32 | -(NSString *)tableName{ 33 | return @"car"; 34 | } 35 | ``` 36 | #### 设置数据库表结构 37 | 在CarTable.m 中 重写如下方法: 38 | ``` 39 | -(PYStructure *)structure{ 40 | PYStructure * st = [[PYStructure alloc] init]; 41 | [st addWithField:@"id" andType:PYStructureTypeAutoInc]; 42 | [st addWithField:@"name" andType:PYStructureTypeNormalText]; 43 | [st addWithField:@"wheels" andType:PYStructureTypeNormalInt]; 44 | return st; 45 | } 46 | ``` 47 | #####`PYStructureType` 48 | * PYStructureTypeAutoInc = 0,//主键,int类型,自增 49 | * PYStructureTypePrimaryInt = 1,//主键,int类型,自增 50 | * PYStructureTypePrimaryText = 2,//主键,text类型 51 | * PYStructureTypeNormalInt = 3,//普通列,int类型 52 | * PYStructureTypeNormalText = 4,//普通列,text类型 53 | 54 | ### 自定义Table类的使用 55 | table类可以实现针对当前table的增删改查数据库操作。 56 | ``` 57 | CarTable *table = [[CarTable alloc] init]; 58 | ``` 59 | ####新增数据 60 | 普通新增数据 61 | ``` 62 | NSDictionary *fields = @{@"name":@"宝马",@"wheels":@1}; 63 | [table addFields:fields]; 64 | ``` 65 | 新增或者更新数据【判断数据是否已存在,存在则更新数据,不存在则新增数据】 66 | ``` 67 | NSDictionary *fields = @{@"name":@"宝马",@"wheels":@1}; 68 | [table addOrUpdateFields:fields andWhere:@"name='宝马'"]; 69 | ``` 70 | 判断是否已经存在数据,仅不存在数据时更新数据 71 | ``` 72 | NSDictionary *fields = @{@"name":@"宝马",@"wheels":@1}; 73 | [table addFieldsIfNotExist:fields]; 74 | ``` 75 | ####删除数据 76 | 指定字段删除 77 | ``` 78 | NSString *where = @"name='宝马'"; 79 | [table deleteWithWhere:where]; 80 | ``` 81 | 多种条件删除 82 | ``` 83 | NSString *where = @"name='宝马' and id >=5"; 84 | [table deleteWithWhere:where]; 85 | ``` 86 | 清空数据表 87 | ``` 88 | [table truncate]; 89 | ``` 90 | ####更新数据 91 | 更新多个字段 92 | ``` 93 | NSString *where = @"name='宝马'"; 94 | NSDictionary *fields = @{@"name":@"奔驰",@"wheels":@2}; 95 | [table updateFields:fields andWhere:where]; 96 | ``` 97 | 更新1个字段 98 | ``` 99 | [table setField:@"name" andValue:@"奔驰" andWhere:@"name='宝马'"]; 100 | ``` 101 | ####查询数据 102 | 查询表全部数据,全部字段,返回的结果为NSArray 103 | ``` 104 | NSArray *results = [table selectAll]; 105 | ``` 106 | 按条件查询数据,全部字段,返回的结果为NSArray 107 | ``` 108 | NSString *where = @"name='宝马'"; 109 | NSArray *results = [table selectWithWhere:where]; 110 | ``` 111 | 按条件查询数据,指定字段,返回结果为NSArray 112 | 多个字段用半角逗号隔开 113 | ``` 114 | NSString *where = @"name='宝马'"; 115 | NSString *fields = @"id,wheels"; 116 | NSArray *results = [table selectWithWhere:where andFields:fields]; 117 | ``` 118 | 按条件查询数据,指定字段,设置分页,返回结果为NSArray 119 | 要查询全部字段时 用 * 代表查询全部字段 120 | ``` 121 | NSString *where = @"name='宝马'"; 122 | NSString *fields = @"id,wheels"; 123 | //NSString *fields = @"*"; 124 | NSArray *results = [table selectWithWhere:where andFields:fields andPage:1 andPageSize:10];//取第一页,每页10条 125 | ``` 126 | 按条件查询数据,指定字段,设置分页,设置排序,返回结果为NSArray 127 | 排序中 desc 代表 降序,asc代表升序 128 | 单个字段排序 如 id desc 129 | 多个字段排序 如 id,wheel asc 130 | ``` 131 | NSString *where = @"name='宝马'"; 132 | NSString *fields = @"id,wheels"; 133 | //NSString *fields = @"*"; 134 | NSArray *results = [table selectWithWhere:where andFields:fields andPage:1 andPageSize:10 andOrder:@"id desc"]; 135 | ``` 136 | 按条件查询单行数据,返回结果为NSDictionary 137 | ``` 138 | NSString *where = @"name='宝马'"; 139 | NSDictionary *result = [table findWithWhere:where]; 140 | ``` 141 | 按条件查询单行单个字段数据,返回结果为id类型 142 | ``` 143 | id result = [table getField:@"name" andWhere:@"id=1"]; 144 | ``` 145 | ####统计表总行数 146 | ``` 147 | NSUInteger tableCount = [table count]; 148 | ``` 149 | ####判断表是否为空 150 | ``` 151 | if([table isEmpty]){ 152 | //table is empty 153 | } 154 | ``` 155 | ####判断数据是否存在 156 | ``` 157 | NSDictionary *fields = @{@"name":@"宝马",@"wheels":@1}; 158 | if([table hasFields:fields]){ 159 | //数据已存在 160 | } 161 | ``` 162 | ####判断where查询是否有数据 163 | ``` 164 | if([table hasWhere:@"name='宝马'"]){ 165 | //有查询结果 166 | } 167 | ``` 168 | ####原生sql支持 169 | 执行一个sql查询 170 | ``` 171 | NSString *sql = @"select * from car"; 172 | NSArray *results = [table executeQueryWithSql:sql]; 173 | ``` 174 | 执行一个sql操作,如更新,删除,插入等 175 | ``` 176 | NSString *sql = @"delete from car where name='BMW'"; 177 | BOOL result = [table executeUpdateWithSql:sql]; 178 | ``` 179 | 180 | 181 | 182 | ####调试信息 183 | ``` 184 | NSLog(@"dbpath:%@",table.databasePath);//数据库位置 185 | NSLog(@"lastSql:%@",table.lastSql);//最后执行的sql 186 | NSLog(@"dbname:%@",table.databaseName);//数据库名 187 | NSLog(@"tablename:%@",table.tableName);//数据表名 188 | NSLog(@"table structure:%@",table.structure.structureDictory);//数据表结构 189 | NSLog(@"table fields:%@",table.structure.fieldsString);//数据表字段 190 | ``` 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /pyfmdbdemo/FMDB/FMDB.h: -------------------------------------------------------------------------------- 1 | #import "FMDatabase.h" 2 | #import "FMResultSet.h" 3 | #import "FMDatabaseAdditions.h" 4 | #import "FMDatabaseQueue.h" 5 | #import "FMDatabasePool.h" 6 | -------------------------------------------------------------------------------- /pyfmdbdemo/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 | 13 | /** Category of additions for `` class. 14 | 15 | ### See also 16 | 17 | - `` 18 | */ 19 | 20 | @interface FMDatabase (FMDatabaseAdditions) 21 | 22 | ///---------------------------------------- 23 | /// @name Return results of SQL to variable 24 | ///---------------------------------------- 25 | 26 | /** Return `int` value for query 27 | 28 | @param query The SQL query to be performed. 29 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 30 | 31 | @return `int` value. 32 | 33 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 34 | */ 35 | 36 | - (int)intForQuery:(NSString*)query, ...; 37 | 38 | /** Return `long` value for query 39 | 40 | @param query The SQL query to be performed. 41 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 42 | 43 | @return `long` value. 44 | 45 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 46 | */ 47 | 48 | - (long)longForQuery:(NSString*)query, ...; 49 | 50 | /** Return `BOOL` value for query 51 | 52 | @param query The SQL query to be performed. 53 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 54 | 55 | @return `BOOL` value. 56 | 57 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 58 | */ 59 | 60 | - (BOOL)boolForQuery:(NSString*)query, ...; 61 | 62 | /** Return `double` value for query 63 | 64 | @param query The SQL query to be performed. 65 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 66 | 67 | @return `double` value. 68 | 69 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 70 | */ 71 | 72 | - (double)doubleForQuery:(NSString*)query, ...; 73 | 74 | /** Return `NSString` value for query 75 | 76 | @param query The SQL query to be performed. 77 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 78 | 79 | @return `NSString` value. 80 | 81 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 82 | */ 83 | 84 | - (NSString*)stringForQuery:(NSString*)query, ...; 85 | 86 | /** Return `NSData` value for query 87 | 88 | @param query The SQL query to be performed. 89 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 90 | 91 | @return `NSData` value. 92 | 93 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 94 | */ 95 | 96 | - (NSData*)dataForQuery:(NSString*)query, ...; 97 | 98 | /** Return `NSDate` value for query 99 | 100 | @param query The SQL query to be performed. 101 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 102 | 103 | @return `NSDate` value. 104 | 105 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 106 | */ 107 | 108 | - (NSDate*)dateForQuery:(NSString*)query, ...; 109 | 110 | 111 | // Notice that there's no dataNoCopyForQuery:. 112 | // That would be a bad idea, because we close out the result set, and then what 113 | // happens to the data that we just didn't copy? Who knows, not I. 114 | 115 | 116 | ///-------------------------------- 117 | /// @name Schema related operations 118 | ///-------------------------------- 119 | 120 | /** Does table exist in database? 121 | 122 | @param tableName The name of the table being looked for. 123 | 124 | @return `YES` if table found; `NO` if not found. 125 | */ 126 | 127 | - (BOOL)tableExists:(NSString*)tableName; 128 | 129 | /** The schema of the database. 130 | 131 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: 132 | 133 | - `type` - The type of entity (e.g. table, index, view, or trigger) 134 | - `name` - The name of the object 135 | - `tbl_name` - The name of the table to which the object references 136 | - `rootpage` - The page number of the root b-tree page for tables and indices 137 | - `sql` - The SQL that created the entity 138 | 139 | @return `FMResultSet` of schema; `nil` on error. 140 | 141 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html) 142 | */ 143 | 144 | - (FMResultSet*)getSchema; 145 | 146 | /** The schema of the database. 147 | 148 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: 149 | 150 | PRAGMA table_info('employees') 151 | 152 | This will report: 153 | 154 | - `cid` - The column ID number 155 | - `name` - The name of the column 156 | - `type` - The data type specified for the column 157 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required) 158 | - `dflt_value` - The default value for the column 159 | - `pk` - Whether the field is part of the primary key of the table 160 | 161 | @param tableName The name of the table for whom the schema will be returned. 162 | 163 | @return `FMResultSet` of schema; `nil` on error. 164 | 165 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) 166 | */ 167 | 168 | - (FMResultSet*)getTableSchema:(NSString*)tableName; 169 | 170 | /** Test to see if particular column exists for particular table in database 171 | 172 | @param columnName The name of the column. 173 | 174 | @param tableName The name of the table. 175 | 176 | @return `YES` if column exists in table in question; `NO` otherwise. 177 | */ 178 | 179 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; 180 | 181 | /** Test to see if particular column exists for particular table in database 182 | 183 | @param columnName The name of the column. 184 | 185 | @param tableName The name of the table. 186 | 187 | @return `YES` if column exists in table in question; `NO` otherwise. 188 | 189 | @see columnExists:inTableWithName: 190 | 191 | @warning Deprecated - use `` instead. 192 | */ 193 | 194 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)); 195 | 196 | 197 | /** Validate SQL statement 198 | 199 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. 200 | 201 | @param sql The SQL statement being validated. 202 | 203 | @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. 204 | 205 | @return `YES` if validation succeeded without incident; `NO` otherwise. 206 | 207 | */ 208 | 209 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error; 210 | 211 | 212 | #if SQLITE_VERSION_NUMBER >= 3007017 213 | 214 | ///----------------------------------- 215 | /// @name Application identifier tasks 216 | ///----------------------------------- 217 | 218 | /** Retrieve application ID 219 | 220 | @return The `uint32_t` numeric value of the application ID. 221 | 222 | @see setApplicationID: 223 | */ 224 | 225 | - (uint32_t)applicationID; 226 | 227 | /** Set the application ID 228 | 229 | @param appID The `uint32_t` numeric value of the application ID. 230 | 231 | @see applicationID 232 | */ 233 | 234 | - (void)setApplicationID:(uint32_t)appID; 235 | 236 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 237 | /** Retrieve application ID string 238 | 239 | @return The `NSString` value of the application ID. 240 | 241 | @see setApplicationIDString: 242 | */ 243 | 244 | 245 | - (NSString*)applicationIDString; 246 | 247 | /** Set the application ID string 248 | 249 | @param string The `NSString` value of the application ID. 250 | 251 | @see applicationIDString 252 | */ 253 | 254 | - (void)setApplicationIDString:(NSString*)string; 255 | #endif 256 | 257 | #endif 258 | 259 | ///----------------------------------- 260 | /// @name user version identifier tasks 261 | ///----------------------------------- 262 | 263 | /** Retrieve user version 264 | 265 | @return The `uint32_t` numeric value of the user version. 266 | 267 | @see setUserVersion: 268 | */ 269 | 270 | - (uint32_t)userVersion; 271 | 272 | /** Set the user-version 273 | 274 | @param version The `uint32_t` numeric value of the user version. 275 | 276 | @see userVersion 277 | */ 278 | 279 | - (void)setUserVersion:(uint32_t)version; 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /pyfmdbdemo/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 | @interface FMDatabase (PrivateStuff) 14 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; 15 | @end 16 | 17 | @implementation FMDatabase (FMDatabaseAdditions) 18 | 19 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ 20 | va_list args; \ 21 | va_start(args, query); \ 22 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ 23 | va_end(args); \ 24 | if (![resultSet next]) { return (type)0; } \ 25 | type ret = [resultSet sel:0]; \ 26 | [resultSet close]; \ 27 | [resultSet setParentDB:nil]; \ 28 | return ret; 29 | 30 | 31 | - (NSString*)stringForQuery:(NSString*)query, ... { 32 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); 33 | } 34 | 35 | - (int)intForQuery:(NSString*)query, ... { 36 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); 37 | } 38 | 39 | - (long)longForQuery:(NSString*)query, ... { 40 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); 41 | } 42 | 43 | - (BOOL)boolForQuery:(NSString*)query, ... { 44 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); 45 | } 46 | 47 | - (double)doubleForQuery:(NSString*)query, ... { 48 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); 49 | } 50 | 51 | - (NSData*)dataForQuery:(NSString*)query, ... { 52 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); 53 | } 54 | 55 | - (NSDate*)dateForQuery:(NSString*)query, ... { 56 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); 57 | } 58 | 59 | 60 | - (BOOL)tableExists:(NSString*)tableName { 61 | 62 | tableName = [tableName lowercaseString]; 63 | 64 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; 65 | 66 | //if at least one next exists, table exists 67 | BOOL returnBool = [rs next]; 68 | 69 | //close and free object 70 | [rs close]; 71 | 72 | return returnBool; 73 | } 74 | 75 | /* 76 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 77 | check if table exist in database (patch from OZLB) 78 | */ 79 | - (FMResultSet*)getSchema { 80 | 81 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 82 | 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"]; 83 | 84 | return rs; 85 | } 86 | 87 | /* 88 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 89 | */ 90 | - (FMResultSet*)getTableSchema:(NSString*)tableName { 91 | 92 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 93 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; 94 | 95 | return rs; 96 | } 97 | 98 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { 99 | 100 | BOOL returnBool = NO; 101 | 102 | tableName = [tableName lowercaseString]; 103 | columnName = [columnName lowercaseString]; 104 | 105 | FMResultSet *rs = [self getTableSchema:tableName]; 106 | 107 | //check if column is present in table schema 108 | while ([rs next]) { 109 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { 110 | returnBool = YES; 111 | break; 112 | } 113 | } 114 | 115 | //If this is not done FMDatabase instance stays out of pool 116 | [rs close]; 117 | 118 | return returnBool; 119 | } 120 | 121 | 122 | #if SQLITE_VERSION_NUMBER >= 3007017 123 | 124 | - (uint32_t)applicationID { 125 | 126 | uint32_t r = 0; 127 | 128 | FMResultSet *rs = [self executeQuery:@"pragma application_id"]; 129 | 130 | if ([rs next]) { 131 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 132 | } 133 | 134 | [rs close]; 135 | 136 | return r; 137 | } 138 | 139 | - (void)setApplicationID:(uint32_t)appID { 140 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; 141 | FMResultSet *rs = [self executeQuery:query]; 142 | [rs next]; 143 | [rs close]; 144 | } 145 | 146 | 147 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 148 | - (NSString*)applicationIDString { 149 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); 150 | 151 | assert([s length] == 6); 152 | 153 | s = [s substringWithRange:NSMakeRange(1, 4)]; 154 | 155 | 156 | return s; 157 | 158 | } 159 | 160 | - (void)setApplicationIDString:(NSString*)s { 161 | 162 | if ([s length] != 4) { 163 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); 164 | } 165 | 166 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; 167 | } 168 | 169 | 170 | #endif 171 | 172 | #endif 173 | 174 | - (uint32_t)userVersion { 175 | uint32_t r = 0; 176 | 177 | FMResultSet *rs = [self executeQuery:@"pragma user_version"]; 178 | 179 | if ([rs next]) { 180 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 181 | } 182 | 183 | [rs close]; 184 | return r; 185 | } 186 | 187 | - (void)setUserVersion:(uint32_t)version { 188 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; 189 | FMResultSet *rs = [self executeQuery:query]; 190 | [rs next]; 191 | [rs close]; 192 | } 193 | 194 | #pragma clang diagnostic push 195 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 196 | 197 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { 198 | return [self columnExists:columnName inTableWithName:tableName]; 199 | } 200 | 201 | #pragma clang diagnostic pop 202 | 203 | 204 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { 205 | sqlite3_stmt *pStmt = NULL; 206 | BOOL validationSucceeded = YES; 207 | 208 | int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); 209 | if (rc != SQLITE_OK) { 210 | validationSucceeded = NO; 211 | if (error) { 212 | *error = [NSError errorWithDomain:NSCocoaErrorDomain 213 | code:[self lastErrorCode] 214 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] 215 | forKey:NSLocalizedDescriptionKey]]; 216 | } 217 | } 218 | 219 | sqlite3_finalize(pStmt); 220 | 221 | return validationSucceeded; 222 | } 223 | 224 | @end 225 | -------------------------------------------------------------------------------- /pyfmdbdemo/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 | #import "sqlite3.h" 11 | 12 | @class FMDatabase; 13 | 14 | /** Pool of `` objects. 15 | 16 | ### See also 17 | 18 | - `` 19 | - `` 20 | 21 | @warning Before using `FMDatabasePool`, please consider using `` instead. 22 | 23 | If you really really really know what you're doing and `FMDatabasePool` is what 24 | you really really need (ie, you're using a read only database), OK you can use 25 | it. But just be careful not to deadlock! 26 | 27 | For an example on deadlocking, search for: 28 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` 29 | in the main.m file. 30 | */ 31 | 32 | @interface FMDatabasePool : NSObject { 33 | NSString *_path; 34 | 35 | dispatch_queue_t _lockQueue; 36 | 37 | NSMutableArray *_databaseInPool; 38 | NSMutableArray *_databaseOutPool; 39 | 40 | __unsafe_unretained id _delegate; 41 | 42 | NSUInteger _maximumNumberOfDatabasesToCreate; 43 | int _openFlags; 44 | } 45 | 46 | /** Database path */ 47 | 48 | @property (atomic, retain) NSString *path; 49 | 50 | /** Delegate object */ 51 | 52 | @property (atomic, assign) id delegate; 53 | 54 | /** Maximum number of databases to create */ 55 | 56 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; 57 | 58 | /** Open flags */ 59 | 60 | @property (atomic, readonly) int openFlags; 61 | 62 | 63 | ///--------------------- 64 | /// @name Initialization 65 | ///--------------------- 66 | 67 | /** Create pool using path. 68 | 69 | @param aPath The file path of the database. 70 | 71 | @return The `FMDatabasePool` object. `nil` on error. 72 | */ 73 | 74 | + (instancetype)databasePoolWithPath:(NSString*)aPath; 75 | 76 | /** Create pool using path and specified flags 77 | 78 | @param aPath The file path of the database. 79 | @param openFlags Flags passed to the openWithFlags method of the database 80 | 81 | @return The `FMDatabasePool` object. `nil` on error. 82 | */ 83 | 84 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; 85 | 86 | /** Create pool using path. 87 | 88 | @param aPath The file path of the database. 89 | 90 | @return The `FMDatabasePool` object. `nil` on error. 91 | */ 92 | 93 | - (instancetype)initWithPath:(NSString*)aPath; 94 | 95 | /** Create pool using path and specified flags. 96 | 97 | @param aPath The file path of the database. 98 | @param openFlags Flags passed to the openWithFlags method of the database 99 | 100 | @return The `FMDatabasePool` object. `nil` on error. 101 | */ 102 | 103 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 104 | 105 | ///------------------------------------------------ 106 | /// @name Keeping track of checked in/out databases 107 | ///------------------------------------------------ 108 | 109 | /** Number of checked-in databases in pool 110 | 111 | @returns Number of databases 112 | */ 113 | 114 | - (NSUInteger)countOfCheckedInDatabases; 115 | 116 | /** Number of checked-out databases in pool 117 | 118 | @returns Number of databases 119 | */ 120 | 121 | - (NSUInteger)countOfCheckedOutDatabases; 122 | 123 | /** Total number of databases in pool 124 | 125 | @returns Number of databases 126 | */ 127 | 128 | - (NSUInteger)countOfOpenDatabases; 129 | 130 | /** Release all databases in pool */ 131 | 132 | - (void)releaseAllDatabases; 133 | 134 | ///------------------------------------------ 135 | /// @name Perform database operations in pool 136 | ///------------------------------------------ 137 | 138 | /** Synchronously perform database operations in pool. 139 | 140 | @param block The code to be run on the `FMDatabasePool` pool. 141 | */ 142 | 143 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 144 | 145 | /** Synchronously perform database operations in pool using transaction. 146 | 147 | @param block The code to be run on the `FMDatabasePool` pool. 148 | */ 149 | 150 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 151 | 152 | /** Synchronously perform database operations in pool using deferred transaction. 153 | 154 | @param block The code to be run on the `FMDatabasePool` pool. 155 | */ 156 | 157 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 158 | 159 | #if SQLITE_VERSION_NUMBER >= 3007000 160 | 161 | /** Synchronously perform database operations in pool using save point. 162 | 163 | @param block The code to be run on the `FMDatabasePool` pool. 164 | 165 | @return `NSError` object if error; `nil` if successful. 166 | 167 | @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. 168 | */ 169 | 170 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 171 | #endif 172 | 173 | @end 174 | 175 | 176 | /** FMDatabasePool delegate category 177 | 178 | This is a category that defines the protocol for the FMDatabasePool delegate 179 | */ 180 | 181 | @interface NSObject (FMDatabasePoolDelegate) 182 | 183 | /** Asks the delegate whether database should be added to the pool. 184 | 185 | @param pool The `FMDatabasePool` object. 186 | @param database The `FMDatabase` object. 187 | 188 | @return `YES` if it should add database to pool; `NO` if not. 189 | 190 | */ 191 | 192 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; 193 | 194 | /** Tells the delegate that database was added to the pool. 195 | 196 | @param pool The `FMDatabasePool` object. 197 | @param database The `FMDatabase` object. 198 | 199 | */ 200 | 201 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; 202 | 203 | @end 204 | 205 | -------------------------------------------------------------------------------- /pyfmdbdemo/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 | #import "FMDatabasePool.h" 10 | #import "FMDatabase.h" 11 | 12 | @interface FMDatabasePool() 13 | 14 | - (void)pushDatabaseBackInPool:(FMDatabase*)db; 15 | - (FMDatabase*)db; 16 | 17 | @end 18 | 19 | 20 | @implementation FMDatabasePool 21 | @synthesize path=_path; 22 | @synthesize delegate=_delegate; 23 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; 24 | @synthesize openFlags=_openFlags; 25 | 26 | 27 | + (instancetype)databasePoolWithPath:(NSString*)aPath { 28 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); 29 | } 30 | 31 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { 32 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); 33 | } 34 | 35 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 36 | 37 | self = [super init]; 38 | 39 | if (self != nil) { 40 | _path = [aPath copy]; 41 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 42 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]); 43 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); 44 | _openFlags = openFlags; 45 | } 46 | 47 | return self; 48 | } 49 | 50 | - (instancetype)initWithPath:(NSString*)aPath 51 | { 52 | // default flags for sqlite3_open 53 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 54 | } 55 | 56 | - (instancetype)init { 57 | return [self initWithPath:nil]; 58 | } 59 | 60 | 61 | - (void)dealloc { 62 | 63 | _delegate = 0x00; 64 | FMDBRelease(_path); 65 | FMDBRelease(_databaseInPool); 66 | FMDBRelease(_databaseOutPool); 67 | 68 | if (_lockQueue) { 69 | FMDBDispatchQueueRelease(_lockQueue); 70 | _lockQueue = 0x00; 71 | } 72 | #if ! __has_feature(objc_arc) 73 | [super dealloc]; 74 | #endif 75 | } 76 | 77 | 78 | - (void)executeLocked:(void (^)(void))aBlock { 79 | dispatch_sync(_lockQueue, aBlock); 80 | } 81 | 82 | - (void)pushDatabaseBackInPool:(FMDatabase*)db { 83 | 84 | if (!db) { // db can be null if we set an upper bound on the # of databases to create. 85 | return; 86 | } 87 | 88 | [self executeLocked:^() { 89 | 90 | if ([self->_databaseInPool containsObject:db]) { 91 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; 92 | } 93 | 94 | [self->_databaseInPool addObject:db]; 95 | [self->_databaseOutPool removeObject:db]; 96 | 97 | }]; 98 | } 99 | 100 | - (FMDatabase*)db { 101 | 102 | __block FMDatabase *db; 103 | 104 | 105 | [self executeLocked:^() { 106 | db = [self->_databaseInPool lastObject]; 107 | 108 | BOOL shouldNotifyDelegate = NO; 109 | 110 | if (db) { 111 | [self->_databaseOutPool addObject:db]; 112 | [self->_databaseInPool removeLastObject]; 113 | } 114 | else { 115 | 116 | if (self->_maximumNumberOfDatabasesToCreate) { 117 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; 118 | 119 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { 120 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); 121 | return; 122 | } 123 | } 124 | 125 | db = [FMDatabase databaseWithPath:self->_path]; 126 | shouldNotifyDelegate = YES; 127 | } 128 | 129 | //This ensures that the db is opened before returning 130 | #if SQLITE_VERSION_NUMBER >= 3005000 131 | BOOL success = [db openWithFlags:self->_openFlags]; 132 | #else 133 | BOOL success = [db open]; 134 | #endif 135 | if (success) { 136 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { 137 | [db close]; 138 | db = 0x00; 139 | } 140 | else { 141 | //It should not get added in the pool twice if lastObject was found 142 | if (![self->_databaseOutPool containsObject:db]) { 143 | [self->_databaseOutPool addObject:db]; 144 | 145 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { 146 | [self->_delegate databasePool:self didAddDatabase:db]; 147 | } 148 | } 149 | } 150 | } 151 | else { 152 | NSLog(@"Could not open up the database at path %@", self->_path); 153 | db = 0x00; 154 | } 155 | }]; 156 | 157 | return db; 158 | } 159 | 160 | - (NSUInteger)countOfCheckedInDatabases { 161 | 162 | __block NSUInteger count; 163 | 164 | [self executeLocked:^() { 165 | count = [self->_databaseInPool count]; 166 | }]; 167 | 168 | return count; 169 | } 170 | 171 | - (NSUInteger)countOfCheckedOutDatabases { 172 | 173 | __block NSUInteger count; 174 | 175 | [self executeLocked:^() { 176 | count = [self->_databaseOutPool count]; 177 | }]; 178 | 179 | return count; 180 | } 181 | 182 | - (NSUInteger)countOfOpenDatabases { 183 | __block NSUInteger count; 184 | 185 | [self executeLocked:^() { 186 | count = [self->_databaseOutPool count] + [self->_databaseInPool count]; 187 | }]; 188 | 189 | return count; 190 | } 191 | 192 | - (void)releaseAllDatabases { 193 | [self executeLocked:^() { 194 | [self->_databaseOutPool removeAllObjects]; 195 | [self->_databaseInPool removeAllObjects]; 196 | }]; 197 | } 198 | 199 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 200 | 201 | FMDatabase *db = [self db]; 202 | 203 | block(db); 204 | 205 | [self pushDatabaseBackInPool:db]; 206 | } 207 | 208 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 209 | 210 | BOOL shouldRollback = NO; 211 | 212 | FMDatabase *db = [self db]; 213 | 214 | if (useDeferred) { 215 | [db beginDeferredTransaction]; 216 | } 217 | else { 218 | [db beginTransaction]; 219 | } 220 | 221 | 222 | block(db, &shouldRollback); 223 | 224 | if (shouldRollback) { 225 | [db rollback]; 226 | } 227 | else { 228 | [db commit]; 229 | } 230 | 231 | [self pushDatabaseBackInPool:db]; 232 | } 233 | 234 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 235 | [self beginTransaction:YES withBlock:block]; 236 | } 237 | 238 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 239 | [self beginTransaction:NO withBlock:block]; 240 | } 241 | #if SQLITE_VERSION_NUMBER >= 3007000 242 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 243 | 244 | static unsigned long savePointIdx = 0; 245 | 246 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 247 | 248 | BOOL shouldRollback = NO; 249 | 250 | FMDatabase *db = [self db]; 251 | 252 | NSError *err = 0x00; 253 | 254 | if (![db startSavePointWithName:name error:&err]) { 255 | [self pushDatabaseBackInPool:db]; 256 | return err; 257 | } 258 | 259 | block(db, &shouldRollback); 260 | 261 | if (shouldRollback) { 262 | // We need to rollback and release this savepoint to remove it 263 | [db rollbackToSavePointWithName:name error:&err]; 264 | } 265 | [db releaseSavePointWithName:name error:&err]; 266 | 267 | [self pushDatabaseBackInPool:db]; 268 | 269 | return err; 270 | } 271 | #endif 272 | 273 | @end 274 | -------------------------------------------------------------------------------- /pyfmdbdemo/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 "sqlite3.h" 11 | 12 | @class FMDatabase; 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 | NSString *_path; 66 | dispatch_queue_t _queue; 67 | FMDatabase *_db; 68 | int _openFlags; 69 | } 70 | 71 | /** Path of database */ 72 | 73 | @property (atomic, retain) NSString *path; 74 | 75 | /** Open flags */ 76 | 77 | @property (atomic, readonly) int openFlags; 78 | 79 | ///---------------------------------------------------- 80 | /// @name Initialization, opening, and closing of queue 81 | ///---------------------------------------------------- 82 | 83 | /** Create queue using path. 84 | 85 | @param aPath The file path of the database. 86 | 87 | @return The `FMDatabaseQueue` object. `nil` on error. 88 | */ 89 | 90 | + (instancetype)databaseQueueWithPath:(NSString*)aPath; 91 | 92 | /** Create queue using path and specified flags. 93 | 94 | @param aPath The file path of the database. 95 | @param openFlags Flags passed to the openWithFlags method of the database 96 | 97 | @return The `FMDatabaseQueue` object. `nil` on error. 98 | */ 99 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; 100 | 101 | /** Create queue using path. 102 | 103 | @param aPath The file path of the database. 104 | 105 | @return The `FMDatabaseQueue` object. `nil` on error. 106 | */ 107 | 108 | - (instancetype)initWithPath:(NSString*)aPath; 109 | 110 | /** Create queue using path and specified flags. 111 | 112 | @param aPath The file path of the database. 113 | @param openFlags Flags passed to the openWithFlags method of the database 114 | 115 | @return The `FMDatabaseQueue` object. `nil` on error. 116 | */ 117 | 118 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 119 | 120 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 121 | 122 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 123 | 124 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 125 | */ 126 | 127 | + (Class)databaseClass; 128 | 129 | /** Close database used by queue. */ 130 | 131 | - (void)close; 132 | 133 | ///----------------------------------------------- 134 | /// @name Dispatching database operations to queue 135 | ///----------------------------------------------- 136 | 137 | /** Synchronously perform database operations on queue. 138 | 139 | @param block The code to be run on the queue of `FMDatabaseQueue` 140 | */ 141 | 142 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 143 | 144 | /** Synchronously perform database operations on queue, using transactions. 145 | 146 | @param block The code to be run on the queue of `FMDatabaseQueue` 147 | */ 148 | 149 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 150 | 151 | /** Synchronously perform database operations on queue, using deferred transactions. 152 | 153 | @param block The code to be run on the queue of `FMDatabaseQueue` 154 | */ 155 | 156 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 157 | 158 | ///----------------------------------------------- 159 | /// @name Dispatching database operations to queue 160 | ///----------------------------------------------- 161 | 162 | /** Synchronously perform database operations using save point. 163 | 164 | @param block The code to be run on the queue of `FMDatabaseQueue` 165 | */ 166 | 167 | #if SQLITE_VERSION_NUMBER >= 3007000 168 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. 169 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead. 170 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 171 | #endif 172 | 173 | @end 174 | 175 | -------------------------------------------------------------------------------- /pyfmdbdemo/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 | /* 13 | 14 | Note: we call [self retain]; before using dispatch_sync, just incase 15 | FMDatabaseQueue is released on another thread and we're in the middle of doing 16 | something in dispatch_sync 17 | 18 | */ 19 | 20 | /* 21 | * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. 22 | * This in turn is used for deadlock detection by seeing if inDatabase: is called on 23 | * the queue's dispatch queue, which should not happen and causes a deadlock. 24 | */ 25 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; 26 | 27 | @implementation FMDatabaseQueue 28 | 29 | @synthesize path = _path; 30 | @synthesize openFlags = _openFlags; 31 | 32 | + (instancetype)databaseQueueWithPath:(NSString*)aPath { 33 | 34 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; 35 | 36 | FMDBAutorelease(q); 37 | 38 | return q; 39 | } 40 | 41 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { 42 | 43 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; 44 | 45 | FMDBAutorelease(q); 46 | 47 | return q; 48 | } 49 | 50 | + (Class)databaseClass { 51 | return [FMDatabase class]; 52 | } 53 | 54 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 55 | 56 | self = [super init]; 57 | 58 | if (self != nil) { 59 | 60 | _db = [[[self class] databaseClass] databaseWithPath:aPath]; 61 | FMDBRetain(_db); 62 | 63 | #if SQLITE_VERSION_NUMBER >= 3005000 64 | BOOL success = [_db openWithFlags:openFlags]; 65 | #else 66 | BOOL success = [_db open]; 67 | #endif 68 | if (!success) { 69 | NSLog(@"Could not create database queue for path %@", aPath); 70 | FMDBRelease(self); 71 | return 0x00; 72 | } 73 | 74 | _path = FMDBReturnRetained(aPath); 75 | 76 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 77 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 78 | _openFlags = openFlags; 79 | } 80 | 81 | return self; 82 | } 83 | 84 | - (instancetype)initWithPath:(NSString*)aPath { 85 | 86 | // default flags for sqlite3_open 87 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 88 | } 89 | 90 | - (instancetype)init { 91 | return [self initWithPath:nil]; 92 | } 93 | 94 | 95 | - (void)dealloc { 96 | 97 | FMDBRelease(_db); 98 | FMDBRelease(_path); 99 | 100 | if (_queue) { 101 | FMDBDispatchQueueRelease(_queue); 102 | _queue = 0x00; 103 | } 104 | #if ! __has_feature(objc_arc) 105 | [super dealloc]; 106 | #endif 107 | } 108 | 109 | - (void)close { 110 | FMDBRetain(self); 111 | dispatch_sync(_queue, ^() { 112 | [self->_db close]; 113 | FMDBRelease(_db); 114 | self->_db = 0x00; 115 | }); 116 | FMDBRelease(self); 117 | } 118 | 119 | - (FMDatabase*)database { 120 | if (!_db) { 121 | _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]); 122 | 123 | #if SQLITE_VERSION_NUMBER >= 3005000 124 | BOOL success = [_db openWithFlags:_openFlags]; 125 | #else 126 | BOOL success = [_db open]; 127 | #endif 128 | if (!success) { 129 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); 130 | FMDBRelease(_db); 131 | _db = 0x00; 132 | return 0x00; 133 | } 134 | } 135 | 136 | return _db; 137 | } 138 | 139 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 140 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue 141 | * and then check it against self to make sure we're not about to deadlock. */ 142 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 143 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); 144 | 145 | FMDBRetain(self); 146 | 147 | dispatch_sync(_queue, ^() { 148 | 149 | FMDatabase *db = [self database]; 150 | block(db); 151 | 152 | if ([db hasOpenResultSets]) { 153 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); 154 | 155 | #if defined(DEBUG) && DEBUG 156 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); 157 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { 158 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; 159 | NSLog(@"query: '%@'", [rs query]); 160 | } 161 | #endif 162 | } 163 | }); 164 | 165 | FMDBRelease(self); 166 | } 167 | 168 | 169 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 170 | FMDBRetain(self); 171 | dispatch_sync(_queue, ^() { 172 | 173 | BOOL shouldRollback = NO; 174 | 175 | if (useDeferred) { 176 | [[self database] beginDeferredTransaction]; 177 | } 178 | else { 179 | [[self database] beginTransaction]; 180 | } 181 | 182 | block([self database], &shouldRollback); 183 | 184 | if (shouldRollback) { 185 | [[self database] rollback]; 186 | } 187 | else { 188 | [[self database] commit]; 189 | } 190 | }); 191 | 192 | FMDBRelease(self); 193 | } 194 | 195 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 196 | [self beginTransaction:YES withBlock:block]; 197 | } 198 | 199 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 200 | [self beginTransaction:NO withBlock:block]; 201 | } 202 | 203 | #if SQLITE_VERSION_NUMBER >= 3007000 204 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 205 | 206 | static unsigned long savePointIdx = 0; 207 | __block NSError *err = 0x00; 208 | FMDBRetain(self); 209 | dispatch_sync(_queue, ^() { 210 | 211 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 212 | 213 | BOOL shouldRollback = NO; 214 | 215 | if ([[self database] startSavePointWithName:name error:&err]) { 216 | 217 | block([self database], &shouldRollback); 218 | 219 | if (shouldRollback) { 220 | // We need to rollback and release this savepoint to remove it 221 | [[self database] rollbackToSavePointWithName:name error:&err]; 222 | } 223 | [[self database] releaseSavePointWithName:name error:&err]; 224 | 225 | } 226 | }); 227 | FMDBRelease(self); 228 | return err; 229 | } 230 | #endif 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /pyfmdbdemo/FMDB/FMResultSet.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "sqlite3.h" 3 | 4 | #ifndef __has_feature // Optional. 5 | #define __has_feature(x) 0 // Compatibility with non-clang compilers. 6 | #endif 7 | 8 | #ifndef NS_RETURNS_NOT_RETAINED 9 | #if __has_feature(attribute_ns_returns_not_retained) 10 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) 11 | #else 12 | #define NS_RETURNS_NOT_RETAINED 13 | #endif 14 | #endif 15 | 16 | @class FMDatabase; 17 | @class FMStatement; 18 | 19 | /** Represents the results of executing a query on an ``. 20 | 21 | ### See also 22 | 23 | - `` 24 | */ 25 | 26 | @interface FMResultSet : NSObject { 27 | FMDatabase *_parentDB; 28 | FMStatement *_statement; 29 | 30 | NSString *_query; 31 | NSMutableDictionary *_columnNameToIndexMap; 32 | } 33 | 34 | ///----------------- 35 | /// @name Properties 36 | ///----------------- 37 | 38 | /** Executed query */ 39 | 40 | @property (atomic, retain) NSString *query; 41 | 42 | /** `NSMutableDictionary` mapping column names to numeric index */ 43 | 44 | @property (readonly) NSMutableDictionary *columnNameToIndexMap; 45 | 46 | /** `FMStatement` used by result set. */ 47 | 48 | @property (atomic, retain) FMStatement *statement; 49 | 50 | ///------------------------------------ 51 | /// @name Creating and closing database 52 | ///------------------------------------ 53 | 54 | /** Create result set from `` 55 | 56 | @param statement A `` to be performed 57 | 58 | @param aDB A `` to be used 59 | 60 | @return A `FMResultSet` on success; `nil` on failure 61 | */ 62 | 63 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; 64 | 65 | /** Close result set */ 66 | 67 | - (void)close; 68 | 69 | - (void)setParentDB:(FMDatabase *)newDb; 70 | 71 | ///--------------------------------------- 72 | /// @name Iterating through the result set 73 | ///--------------------------------------- 74 | 75 | /** Retrieve next row for result set. 76 | 77 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 78 | 79 | @return `YES` if row successfully retrieved; `NO` if end of result set reached 80 | 81 | @see hasAnotherRow 82 | */ 83 | 84 | - (BOOL)next; 85 | 86 | /** Retrieve next row for result set. 87 | 88 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 89 | 90 | @param outErr A 'NSError' object to receive any error object (if any). 91 | 92 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached 93 | 94 | @see hasAnotherRow 95 | */ 96 | 97 | - (BOOL)nextWithError:(NSError **)outErr; 98 | 99 | /** Did the last call to `` succeed in retrieving another row? 100 | 101 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. 102 | 103 | @see next 104 | 105 | @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. 106 | */ 107 | 108 | - (BOOL)hasAnotherRow; 109 | 110 | ///--------------------------------------------- 111 | /// @name Retrieving information from result set 112 | ///--------------------------------------------- 113 | 114 | /** How many columns in result set 115 | 116 | @return Integer value of the number of columns. 117 | */ 118 | 119 | - (int)columnCount; 120 | 121 | /** Column index for column name 122 | 123 | @param columnName `NSString` value of the name of the column. 124 | 125 | @return Zero-based index for column. 126 | */ 127 | 128 | - (int)columnIndexForName:(NSString*)columnName; 129 | 130 | /** Column name for column index 131 | 132 | @param columnIdx Zero-based index for column. 133 | 134 | @return columnName `NSString` value of the name of the column. 135 | */ 136 | 137 | - (NSString*)columnNameForIndex:(int)columnIdx; 138 | 139 | /** Result set integer value for column. 140 | 141 | @param columnName `NSString` value of the name of the column. 142 | 143 | @return `int` value of the result set's column. 144 | */ 145 | 146 | - (int)intForColumn:(NSString*)columnName; 147 | 148 | /** Result set integer value for column. 149 | 150 | @param columnIdx Zero-based index for column. 151 | 152 | @return `int` value of the result set's column. 153 | */ 154 | 155 | - (int)intForColumnIndex:(int)columnIdx; 156 | 157 | /** Result set `long` value for column. 158 | 159 | @param columnName `NSString` value of the name of the column. 160 | 161 | @return `long` value of the result set's column. 162 | */ 163 | 164 | - (long)longForColumn:(NSString*)columnName; 165 | 166 | /** Result set long value for column. 167 | 168 | @param columnIdx Zero-based index for column. 169 | 170 | @return `long` value of the result set's column. 171 | */ 172 | 173 | - (long)longForColumnIndex:(int)columnIdx; 174 | 175 | /** Result set `long long int` value for column. 176 | 177 | @param columnName `NSString` value of the name of the column. 178 | 179 | @return `long long int` value of the result set's column. 180 | */ 181 | 182 | - (long long int)longLongIntForColumn:(NSString*)columnName; 183 | 184 | /** Result set `long long int` value for column. 185 | 186 | @param columnIdx Zero-based index for column. 187 | 188 | @return `long long int` value of the result set's column. 189 | */ 190 | 191 | - (long long int)longLongIntForColumnIndex:(int)columnIdx; 192 | 193 | /** Result set `unsigned long long int` value for column. 194 | 195 | @param columnName `NSString` value of the name of the column. 196 | 197 | @return `unsigned long long int` value of the result set's column. 198 | */ 199 | 200 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; 201 | 202 | /** Result set `unsigned long long int` value for column. 203 | 204 | @param columnIdx Zero-based index for column. 205 | 206 | @return `unsigned long long int` value of the result set's column. 207 | */ 208 | 209 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; 210 | 211 | /** Result set `BOOL` value for column. 212 | 213 | @param columnName `NSString` value of the name of the column. 214 | 215 | @return `BOOL` value of the result set's column. 216 | */ 217 | 218 | - (BOOL)boolForColumn:(NSString*)columnName; 219 | 220 | /** Result set `BOOL` value for column. 221 | 222 | @param columnIdx Zero-based index for column. 223 | 224 | @return `BOOL` value of the result set's column. 225 | */ 226 | 227 | - (BOOL)boolForColumnIndex:(int)columnIdx; 228 | 229 | /** Result set `double` value for column. 230 | 231 | @param columnName `NSString` value of the name of the column. 232 | 233 | @return `double` value of the result set's column. 234 | 235 | */ 236 | 237 | - (double)doubleForColumn:(NSString*)columnName; 238 | 239 | /** Result set `double` value for column. 240 | 241 | @param columnIdx Zero-based index for column. 242 | 243 | @return `double` value of the result set's column. 244 | 245 | */ 246 | 247 | - (double)doubleForColumnIndex:(int)columnIdx; 248 | 249 | /** Result set `NSString` value for column. 250 | 251 | @param columnName `NSString` value of the name of the column. 252 | 253 | @return `NSString` value of the result set's column. 254 | 255 | */ 256 | 257 | - (NSString*)stringForColumn:(NSString*)columnName; 258 | 259 | /** Result set `NSString` value for column. 260 | 261 | @param columnIdx Zero-based index for column. 262 | 263 | @return `NSString` value of the result set's column. 264 | */ 265 | 266 | - (NSString*)stringForColumnIndex:(int)columnIdx; 267 | 268 | /** Result set `NSDate` value for column. 269 | 270 | @param columnName `NSString` value of the name of the column. 271 | 272 | @return `NSDate` value of the result set's column. 273 | */ 274 | 275 | - (NSDate*)dateForColumn:(NSString*)columnName; 276 | 277 | /** Result set `NSDate` value for column. 278 | 279 | @param columnIdx Zero-based index for column. 280 | 281 | @return `NSDate` value of the result set's column. 282 | 283 | */ 284 | 285 | - (NSDate*)dateForColumnIndex:(int)columnIdx; 286 | 287 | /** Result set `NSData` value for column. 288 | 289 | This is useful when storing binary data in table (such as image or the like). 290 | 291 | @param columnName `NSString` value of the name of the column. 292 | 293 | @return `NSData` value of the result set's column. 294 | 295 | */ 296 | 297 | - (NSData*)dataForColumn:(NSString*)columnName; 298 | 299 | /** Result set `NSData` value for column. 300 | 301 | @param columnIdx Zero-based index for column. 302 | 303 | @return `NSData` value of the result set's column. 304 | */ 305 | 306 | - (NSData*)dataForColumnIndex:(int)columnIdx; 307 | 308 | /** Result set `(const unsigned char *)` value for column. 309 | 310 | @param columnName `NSString` value of the name of the column. 311 | 312 | @return `(const unsigned char *)` value of the result set's column. 313 | */ 314 | 315 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName; 316 | 317 | /** Result set `(const unsigned char *)` value for column. 318 | 319 | @param columnIdx Zero-based index for column. 320 | 321 | @return `(const unsigned char *)` value of the result set's column. 322 | */ 323 | 324 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx; 325 | 326 | /** Result set object for column. 327 | 328 | @param columnName `NSString` value of the name of the column. 329 | 330 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 331 | 332 | @see objectForKeyedSubscript: 333 | */ 334 | 335 | - (id)objectForColumnName:(NSString*)columnName; 336 | 337 | /** Result set object for column. 338 | 339 | @param columnIdx Zero-based index for column. 340 | 341 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 342 | 343 | @see objectAtIndexedSubscript: 344 | */ 345 | 346 | - (id)objectForColumnIndex:(int)columnIdx; 347 | 348 | /** Result set object for column. 349 | 350 | 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: 351 | 352 | id result = rs[@"employee_name"]; 353 | 354 | This simplified syntax is equivalent to calling: 355 | 356 | id result = [rs objectForKeyedSubscript:@"employee_name"]; 357 | 358 | which is, it turns out, equivalent to calling: 359 | 360 | id result = [rs objectForColumnName:@"employee_name"]; 361 | 362 | @param columnName `NSString` value of the name of the column. 363 | 364 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 365 | */ 366 | 367 | - (id)objectForKeyedSubscript:(NSString *)columnName; 368 | 369 | /** Result set object for column. 370 | 371 | 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: 372 | 373 | id result = rs[0]; 374 | 375 | This simplified syntax is equivalent to calling: 376 | 377 | id result = [rs objectForKeyedSubscript:0]; 378 | 379 | which is, it turns out, equivalent to calling: 380 | 381 | id result = [rs objectForColumnName:0]; 382 | 383 | @param columnIdx Zero-based index for column. 384 | 385 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 386 | */ 387 | 388 | - (id)objectAtIndexedSubscript:(int)columnIdx; 389 | 390 | /** Result set `NSData` value for column. 391 | 392 | @param columnName `NSString` value of the name of the column. 393 | 394 | @return `NSData` value of the result set's column. 395 | 396 | @warning If you are going to use this data after you iterate over the next row, or after you close the 397 | result set, make sure to make a copy of the data first (or just use ``/``) 398 | If you don't, you're going to be in a world of hurt when you try and use the data. 399 | 400 | */ 401 | 402 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED; 403 | 404 | /** Result set `NSData` value for column. 405 | 406 | @param columnIdx Zero-based index for column. 407 | 408 | @return `NSData` value of the result set's column. 409 | 410 | @warning If you are going to use this data after you iterate over the next row, or after you close the 411 | result set, make sure to make a copy of the data first (or just use ``/``) 412 | If you don't, you're going to be in a world of hurt when you try and use the data. 413 | 414 | */ 415 | 416 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; 417 | 418 | /** Is the column `NULL`? 419 | 420 | @param columnIdx Zero-based index for column. 421 | 422 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 423 | */ 424 | 425 | - (BOOL)columnIndexIsNull:(int)columnIdx; 426 | 427 | /** Is the column `NULL`? 428 | 429 | @param columnName `NSString` value of the name of the column. 430 | 431 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 432 | */ 433 | 434 | - (BOOL)columnIsNull:(NSString*)columnName; 435 | 436 | 437 | /** Returns a dictionary of the row results mapped to case sensitive keys of the column names. 438 | 439 | @returns `NSDictionary` of the row results. 440 | 441 | @warning The keys to the dictionary are case sensitive of the column names. 442 | */ 443 | 444 | - (NSDictionary*)resultDictionary; 445 | 446 | /** Returns a dictionary of the row results 447 | 448 | @see resultDictionary 449 | 450 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! 451 | */ 452 | 453 | - (NSDictionary*)resultDict __attribute__ ((deprecated)); 454 | 455 | ///----------------------------- 456 | /// @name Key value coding magic 457 | ///----------------------------- 458 | 459 | /** Performs `setValue` to yield support for key value observing. 460 | 461 | @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. 462 | 463 | */ 464 | 465 | - (void)kvcMagic:(id)object; 466 | 467 | 468 | @end 469 | 470 | -------------------------------------------------------------------------------- /pyfmdbdemo/FMDB/FMResultSet.m: -------------------------------------------------------------------------------- 1 | #import "FMResultSet.h" 2 | #import "FMDatabase.h" 3 | #import "unistd.h" 4 | 5 | @interface FMDatabase () 6 | - (void)resultSetDidClose:(FMResultSet *)resultSet; 7 | @end 8 | 9 | 10 | @implementation FMResultSet 11 | @synthesize query=_query; 12 | @synthesize statement=_statement; 13 | 14 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB { 15 | 16 | FMResultSet *rs = [[FMResultSet alloc] init]; 17 | 18 | [rs setStatement:statement]; 19 | [rs setParentDB:aDB]; 20 | 21 | NSParameterAssert(![statement inUse]); 22 | [statement setInUse:YES]; // weak reference 23 | 24 | return FMDBReturnAutoreleased(rs); 25 | } 26 | 27 | - (void)finalize { 28 | [self close]; 29 | [super finalize]; 30 | } 31 | 32 | - (void)dealloc { 33 | [self close]; 34 | 35 | FMDBRelease(_query); 36 | _query = nil; 37 | 38 | FMDBRelease(_columnNameToIndexMap); 39 | _columnNameToIndexMap = nil; 40 | 41 | #if ! __has_feature(objc_arc) 42 | [super dealloc]; 43 | #endif 44 | } 45 | 46 | - (void)close { 47 | [_statement reset]; 48 | FMDBRelease(_statement); 49 | _statement = nil; 50 | 51 | // we don't need this anymore... (i think) 52 | //[_parentDB setInUse:NO]; 53 | [_parentDB resultSetDidClose:self]; 54 | _parentDB = nil; 55 | } 56 | 57 | - (int)columnCount { 58 | return sqlite3_column_count([_statement statement]); 59 | } 60 | 61 | - (NSMutableDictionary *)columnNameToIndexMap { 62 | if (!_columnNameToIndexMap) { 63 | int columnCount = sqlite3_column_count([_statement statement]); 64 | _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; 65 | int columnIdx = 0; 66 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 67 | [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] 68 | forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; 69 | } 70 | } 71 | return _columnNameToIndexMap; 72 | } 73 | 74 | - (void)kvcMagic:(id)object { 75 | 76 | int columnCount = sqlite3_column_count([_statement statement]); 77 | 78 | int columnIdx = 0; 79 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 80 | 81 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 82 | 83 | // check for a null row 84 | if (c) { 85 | NSString *s = [NSString stringWithUTF8String:c]; 86 | 87 | [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; 88 | } 89 | } 90 | } 91 | 92 | #pragma clang diagnostic push 93 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 94 | 95 | - (NSDictionary*)resultDict { 96 | 97 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 98 | 99 | if (num_cols > 0) { 100 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 101 | 102 | NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; 103 | NSString *columnName = nil; 104 | while ((columnName = [columnNames nextObject])) { 105 | id objectValue = [self objectForColumnName:columnName]; 106 | [dict setObject:objectValue forKey:columnName]; 107 | } 108 | 109 | return FMDBReturnAutoreleased([dict copy]); 110 | } 111 | else { 112 | NSLog(@"Warning: There seem to be no columns in this set."); 113 | } 114 | 115 | return nil; 116 | } 117 | 118 | #pragma clang diagnostic pop 119 | 120 | - (NSDictionary*)resultDictionary { 121 | 122 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 123 | 124 | if (num_cols > 0) { 125 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 126 | 127 | int columnCount = sqlite3_column_count([_statement statement]); 128 | 129 | int columnIdx = 0; 130 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 131 | 132 | NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; 133 | id objectValue = [self objectForColumnIndex:columnIdx]; 134 | [dict setObject:objectValue forKey:columnName]; 135 | } 136 | 137 | return dict; 138 | } 139 | else { 140 | NSLog(@"Warning: There seem to be no columns in this set."); 141 | } 142 | 143 | return nil; 144 | } 145 | 146 | 147 | 148 | 149 | - (BOOL)next { 150 | return [self nextWithError:nil]; 151 | } 152 | 153 | - (BOOL)nextWithError:(NSError **)outErr { 154 | 155 | int rc = sqlite3_step([_statement statement]); 156 | 157 | if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { 158 | NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); 159 | NSLog(@"Database busy"); 160 | if (outErr) { 161 | *outErr = [_parentDB lastError]; 162 | } 163 | } 164 | else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { 165 | // all is well, let's return. 166 | } 167 | else if (SQLITE_ERROR == rc) { 168 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 169 | if (outErr) { 170 | *outErr = [_parentDB lastError]; 171 | } 172 | } 173 | else if (SQLITE_MISUSE == rc) { 174 | // uh oh. 175 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 176 | if (outErr) { 177 | if (_parentDB) { 178 | *outErr = [_parentDB lastError]; 179 | } 180 | else { 181 | // If 'next' or 'nextWithError' is called after the result set is closed, 182 | // we need to return the appropriate error. 183 | NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; 184 | *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage]; 185 | } 186 | 187 | } 188 | } 189 | else { 190 | // wtf? 191 | NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 192 | if (outErr) { 193 | *outErr = [_parentDB lastError]; 194 | } 195 | } 196 | 197 | 198 | if (rc != SQLITE_ROW) { 199 | [self close]; 200 | } 201 | 202 | return (rc == SQLITE_ROW); 203 | } 204 | 205 | - (BOOL)hasAnotherRow { 206 | return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; 207 | } 208 | 209 | - (int)columnIndexForName:(NSString*)columnName { 210 | columnName = [columnName lowercaseString]; 211 | 212 | NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; 213 | 214 | if (n) { 215 | return [n intValue]; 216 | } 217 | 218 | NSLog(@"Warning: I could not find the column named '%@'.", columnName); 219 | 220 | return -1; 221 | } 222 | 223 | 224 | 225 | - (int)intForColumn:(NSString*)columnName { 226 | return [self intForColumnIndex:[self columnIndexForName:columnName]]; 227 | } 228 | 229 | - (int)intForColumnIndex:(int)columnIdx { 230 | return sqlite3_column_int([_statement statement], columnIdx); 231 | } 232 | 233 | - (long)longForColumn:(NSString*)columnName { 234 | return [self longForColumnIndex:[self columnIndexForName:columnName]]; 235 | } 236 | 237 | - (long)longForColumnIndex:(int)columnIdx { 238 | return (long)sqlite3_column_int64([_statement statement], columnIdx); 239 | } 240 | 241 | - (long long int)longLongIntForColumn:(NSString*)columnName { 242 | return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; 243 | } 244 | 245 | - (long long int)longLongIntForColumnIndex:(int)columnIdx { 246 | return sqlite3_column_int64([_statement statement], columnIdx); 247 | } 248 | 249 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { 250 | return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; 251 | } 252 | 253 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { 254 | return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; 255 | } 256 | 257 | - (BOOL)boolForColumn:(NSString*)columnName { 258 | return [self boolForColumnIndex:[self columnIndexForName:columnName]]; 259 | } 260 | 261 | - (BOOL)boolForColumnIndex:(int)columnIdx { 262 | return ([self intForColumnIndex:columnIdx] != 0); 263 | } 264 | 265 | - (double)doubleForColumn:(NSString*)columnName { 266 | return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; 267 | } 268 | 269 | - (double)doubleForColumnIndex:(int)columnIdx { 270 | return sqlite3_column_double([_statement statement], columnIdx); 271 | } 272 | 273 | - (NSString*)stringForColumnIndex:(int)columnIdx { 274 | 275 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 276 | return nil; 277 | } 278 | 279 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 280 | 281 | if (!c) { 282 | // null row. 283 | return nil; 284 | } 285 | 286 | return [NSString stringWithUTF8String:c]; 287 | } 288 | 289 | - (NSString*)stringForColumn:(NSString*)columnName { 290 | return [self stringForColumnIndex:[self columnIndexForName:columnName]]; 291 | } 292 | 293 | - (NSDate*)dateForColumn:(NSString*)columnName { 294 | return [self dateForColumnIndex:[self columnIndexForName:columnName]]; 295 | } 296 | 297 | - (NSDate*)dateForColumnIndex:(int)columnIdx { 298 | 299 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 300 | return nil; 301 | } 302 | 303 | return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; 304 | } 305 | 306 | 307 | - (NSData*)dataForColumn:(NSString*)columnName { 308 | return [self dataForColumnIndex:[self columnIndexForName:columnName]]; 309 | } 310 | 311 | - (NSData*)dataForColumnIndex:(int)columnIdx { 312 | 313 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 314 | return nil; 315 | } 316 | 317 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 318 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 319 | 320 | if (dataBuffer == NULL) { 321 | return nil; 322 | } 323 | 324 | return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; 325 | } 326 | 327 | 328 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName { 329 | return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; 330 | } 331 | 332 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { 333 | 334 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 335 | return nil; 336 | } 337 | 338 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 339 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 340 | 341 | NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; 342 | 343 | return data; 344 | } 345 | 346 | 347 | - (BOOL)columnIndexIsNull:(int)columnIdx { 348 | return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; 349 | } 350 | 351 | - (BOOL)columnIsNull:(NSString*)columnName { 352 | return [self columnIndexIsNull:[self columnIndexForName:columnName]]; 353 | } 354 | 355 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { 356 | 357 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 358 | return nil; 359 | } 360 | 361 | return sqlite3_column_text([_statement statement], columnIdx); 362 | } 363 | 364 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { 365 | return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; 366 | } 367 | 368 | - (id)objectForColumnIndex:(int)columnIdx { 369 | int columnType = sqlite3_column_type([_statement statement], columnIdx); 370 | 371 | id returnValue = nil; 372 | 373 | if (columnType == SQLITE_INTEGER) { 374 | returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; 375 | } 376 | else if (columnType == SQLITE_FLOAT) { 377 | returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; 378 | } 379 | else if (columnType == SQLITE_BLOB) { 380 | returnValue = [self dataForColumnIndex:columnIdx]; 381 | } 382 | else { 383 | //default to a string for everything else 384 | returnValue = [self stringForColumnIndex:columnIdx]; 385 | } 386 | 387 | if (returnValue == nil) { 388 | returnValue = [NSNull null]; 389 | } 390 | 391 | return returnValue; 392 | } 393 | 394 | - (id)objectForColumnName:(NSString*)columnName { 395 | return [self objectForColumnIndex:[self columnIndexForName:columnName]]; 396 | } 397 | 398 | // returns autoreleased NSString containing the name of the column in the result set 399 | - (NSString*)columnNameForIndex:(int)columnIdx { 400 | return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; 401 | } 402 | 403 | - (void)setParentDB:(FMDatabase *)newDb { 404 | _parentDB = newDb; 405 | } 406 | 407 | - (id)objectAtIndexedSubscript:(int)columnIdx { 408 | return [self objectForColumnIndex:columnIdx]; 409 | } 410 | 411 | - (id)objectForKeyedSubscript:(NSString *)columnName { 412 | return [self objectForColumnName:columnName]; 413 | } 414 | 415 | 416 | @end 417 | -------------------------------------------------------------------------------- /pyfmdbdemo/PYFMDB/PYFMDB.h: -------------------------------------------------------------------------------- 1 | // 2 | // PYFMDB.h 3 | // Operations library of sqlite base on FMDB 4 | // 5 | // Created by terry on 15/3/28. 6 | // Copyright (c) 2015年 Velda. All rights reserved. 7 | // 8 | 9 | #import 10 | @class FMDatabaseQueue; 11 | @interface PYFMDB : NSObject{ 12 | //以下是因为同时重写了get和set方法,故将变量写在这里 13 | /** 14 | * 查询条件 15 | */ 16 | NSString *_limit; 17 | NSString *_where; 18 | NSString *_order; 19 | NSString *_group; 20 | /** 21 | * 缓存ID 22 | */ 23 | NSString *_cacheID; 24 | } 25 | 26 | /** 27 | * 数据库队列 28 | */ 29 | @property (nonatomic,strong) FMDatabaseQueue * queue; 30 | /** 31 | * 数据库文件名 32 | */ 33 | @property (nonatomic,copy) NSString * dbName; 34 | /** 35 | * 数据库文件名(锁定) 36 | */ 37 | @property (nonatomic,copy) NSString * dbName_lock; 38 | /** 39 | * 数据库位置 40 | */ 41 | @property (nonatomic,copy) NSString * dbPath; 42 | /** 43 | * 数据库位置(锁定) 44 | */ 45 | @property (nonatomic,copy) NSString * dbPath_lock; 46 | /** 47 | * 最后执行的sql语句 48 | */ 49 | @property (nonatomic,copy) NSString * lastSql; 50 | /** 51 | * 最后执行的sql语句(锁定) 52 | */ 53 | @property (nonatomic,copy) NSString * lastSql_lock; 54 | /** 55 | * 数据库表前缀 56 | */ 57 | @property (nonatomic,copy) NSString * prefix; 58 | /** 59 | * 数据库表前缀(锁定) 60 | */ 61 | @property (nonatomic,copy) NSString * prefix_lock; 62 | /** 63 | * 要查询出的字段(默认) 64 | */ 65 | @property (nonatomic,strong) NSArray * fields; 66 | /** 67 | * 要查询出的字段(锁定) 68 | */ 69 | @property (nonatomic,strong) NSArray * fields_lock; 70 | 71 | /** 72 | * 要查询出的字段(字符串) 73 | */ 74 | @property (nonatomic,copy) NSString * fieldsString; 75 | 76 | /** 77 | * 要查询出的字段(数组) 78 | */ 79 | @property (nonatomic,strong) NSArray * fieldsArray; 80 | /** 81 | * 当前操作的表名 82 | */ 83 | @property (nonatomic,copy) NSString * currentTableName; 84 | /** 85 | * 当前操作的表名(锁定) 86 | */ 87 | @property (nonatomic,copy) NSString * currentTableName_lock; 88 | /** 89 | * 表里的所有字段 90 | */ 91 | @property (nonatomic,strong) NSDictionary * currentTableFields; 92 | /** 93 | * 表里的所有字段(锁定) 94 | */ 95 | @property (nonatomic,strong) NSDictionary * currentTableFields_lock; 96 | /** 97 | * 要执行的查询条件(锁定) 98 | */ 99 | @property (nonatomic,copy) NSString * where_lock; 100 | 101 | /** 102 | * 待更新的数据源 103 | */ 104 | @property (nonatomic,strong) id data; 105 | /** 106 | * 待更新的数据源(锁定) 107 | */ 108 | @property (nonatomic,strong) id data_lock; 109 | /** 110 | * Order条件(锁定) 111 | */ 112 | @property (nonatomic,copy) NSString * order_lock; 113 | 114 | /** 115 | * group条件(锁定) 116 | */ 117 | @property (nonatomic,copy) NSString * group_lock; 118 | /** 119 | * 缓存标识(锁定) 120 | */ 121 | @property (nonatomic,copy) NSString * cacheID_lock; 122 | /** 123 | * 查询限制条数(锁定) 124 | */ 125 | @property (nonatomic,copy) NSString * limit_lock; 126 | 127 | /** 128 | * 静态方法初始化数据库连接 129 | * 130 | * @param dbName 数据库名 131 | * 132 | * @return PYFMDB对象 133 | */ 134 | +(instancetype)dbWithDbName:(NSString *)dbName; 135 | /** 136 | * 动态方法初始化数据库连接 137 | * 138 | * @param dbName 数据库名 139 | * 140 | * @return PYFMDB对象 141 | */ 142 | -(instancetype)initWithDbName:(NSString *)dbName; 143 | 144 | 145 | 146 | 147 | /** 148 | * 根据字典创建数据库表 149 | * 150 | * @param dict 字典 151 | * @param tablename 表名 152 | * 153 | * @return 执行是否成功 154 | */ 155 | -(bool)createTableWithDict:(NSDictionary *)dict : (NSString *)tableName; 156 | /** 157 | * 执行sql查询 158 | * 159 | * @param sql sql语句 160 | * 161 | * @return 查询结果集 162 | */ 163 | -(NSArray *)excuteQueryWithSql:(NSString *)sql; 164 | /** 165 | * 执行sql更新 166 | * 167 | * @param sql sql语句 168 | * 169 | * @return 执行是否成功 170 | */ 171 | -(bool)excuteUpdateWithSql:(NSString *)sql; 172 | 173 | /** 174 | * 从数组中设置查询的字段信息 175 | * 176 | * @param arr 数组 177 | * 178 | * @return fields数组 179 | */ 180 | -(instancetype)fieldsWithArray:(NSArray *)arr; 181 | /** 182 | * 从字符串中设置查询的字段信息 183 | * 184 | * @param str 字符串 185 | * 186 | * @return fields数组 187 | */ 188 | -(instancetype)fieldsWithString:(NSString *)str; 189 | /** 190 | * 从字符串中设置查询的where条件 191 | * 192 | * @param str 字符串 193 | * 194 | * @return where条件 195 | */ 196 | -(instancetype)whereWithString:(NSString *)str; 197 | /** 198 | * 从字典中设置查询的where条件 199 | * 200 | * @param dict 字典 201 | * 202 | * @return PYFMDB对象 203 | */ 204 | -(instancetype)whereWithDict:(NSDictionary *)dict; 205 | /** 206 | * 从字符串中设置limit条件 207 | * 208 | * @param str 字符串 209 | * 210 | * @return PYFMDB 对象 211 | */ 212 | -(instancetype)limitWithString:(NSString *)str; 213 | /** 214 | * 从数组中设置limit条件 215 | * 216 | * @param arr 数组 217 | * 218 | * @return PYFMDB对象 219 | */ 220 | -(instancetype)limitWithArray:(NSArray *)arr; 221 | /** 222 | * 从start 到 end limit限制 223 | * 224 | * @param start 开始位置 225 | * @param End 结束位置 226 | * 227 | * @return PYFMDB对象 228 | */ 229 | -(instancetype)limitWithStart:(int)start End:(int)end; 230 | /** 231 | * 查询单条记录 232 | * 233 | * @return 字典数据 234 | */ 235 | -(NSDictionary *)find; 236 | /** 237 | * 从字典添加更新数据源 238 | * 239 | * @param PYFMDB对象 240 | */ 241 | -(instancetype)dataWithDict:(NSDictionary *)dict; 242 | /** 243 | * 从数组添加更新数据源 244 | * 245 | * @param arr 数组 246 | * 247 | * @return PYFMDB对象 248 | */ 249 | -(instancetype)dataWithArray:(NSArray *)arr; 250 | /** 251 | * 从JSON中添加更新数据源 252 | * 253 | * @param json json数据 254 | * 255 | * @return PYFMDB对象 256 | */ 257 | -(instancetype)datawithJson:(NSData *)json; 258 | /** 259 | * 新增记录到数据库 260 | * 261 | * @return 是否执行sql成功 262 | */ 263 | -(bool)add; 264 | /** 265 | * 按数据源新增记录到数据库 266 | * 267 | * @param data 数据源 268 | * 269 | * @return 是否执行sql成功 270 | */ 271 | -(bool)add:(id)data; 272 | /** 273 | * 保存记录到数据库 274 | * 275 | * @return 是否执行sql成功 276 | */ 277 | -(bool)save; 278 | /** 279 | * 从数据源保存记录到数据库 280 | * 281 | * @param data 数据源 282 | * 283 | * @return 是否执行sql成功 284 | */ 285 | -(bool)save:(id)data; 286 | /** 287 | * 获取指定字段的数据值 288 | * 289 | * @param field 字段名 290 | * 291 | * @return 数据源 292 | */ 293 | -(id)getField:(NSString *)field; 294 | /** 295 | * 设置指定字段名的值 296 | * 297 | * @param value 字段值 298 | * @param field 字段名 299 | * 300 | * @return 是否成功执行sql 301 | */ 302 | -(bool)setValue: (id)value forField:(NSString *)field; 303 | /** 304 | * 查询到的数据库结果 305 | * 306 | * @return 数组 307 | */ 308 | -(NSArray *)select; 309 | /** 310 | * 过滤掉非数据库表字段 311 | * 312 | * @param dict 字典数据 313 | * 314 | * @return 过滤后字典数据 315 | */ 316 | -(NSDictionary *)filterWithDict:(NSDictionary *)dict; 317 | /** 318 | * 执行删除 319 | * 320 | * @return 是否成功执行sql 321 | */ 322 | -(BOOL)delete; 323 | /** 324 | * 根据where条件删除操作 325 | * 326 | * @param where where条件 327 | * 328 | * @return 是否成功执行sql 329 | */ 330 | -(BOOL)delete:(id)where; 331 | /** 332 | * count统计操作 333 | * 334 | * @return 查询结果集数目 335 | */ 336 | -(NSNumber *)queryCount; 337 | 338 | /** 339 | * 清除设置条件 340 | * 341 | * @return PYFMDB对象 342 | */ 343 | -(instancetype)clean; 344 | /** 345 | * 锁定上次设置条件 346 | * 347 | * @return PYFMDB对象 348 | */ 349 | -(instancetype)lock; 350 | /** 351 | * 重置到上次设置的条件 352 | * 353 | * @return PYFMDB对象 354 | */ 355 | -(instancetype)reset; 356 | /** 357 | * 重写order get方法 358 | * 359 | * @return 要排序的条件 360 | */ 361 | - (NSString *)order; 362 | /** 363 | * 设置order条件 364 | * 365 | * @param order order条件 366 | */ 367 | -(void)setOrder:(NSString *)order; 368 | /** 369 | * 数据表是否为空 370 | * 371 | * @param tableName 数据库表名 372 | * 373 | * @return bool类型值 YES =为空, NO = 不为空 374 | */ 375 | -(BOOL)isEmptyWithTableName:(NSString *)tableName; 376 | /** 377 | * 清空数据表 378 | * 379 | * @param tableName 表名 380 | */ 381 | -(void)truncateTableWithTableName:(NSString *)tableName; 382 | /** 383 | * 公共删除方法 384 | * 385 | * @param dict 字典 386 | */ 387 | -(void)deleteTableWithDict:(NSDictionary *)dict : (NSString *)tableName; 388 | /** 389 | * 展示Table数据 390 | * 391 | * @param page 当前页 392 | * @param pagesize 分页大小 393 | * @param tableName 表名 394 | * 395 | * @return 数组 396 | */ 397 | -(NSArray *)showTableWithPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andTableName:(NSString *)tableName; 398 | /** 399 | * 展示Table数据 400 | * 401 | * @param page 当前页 402 | * @param pagesize 分页大小 403 | * @param order 排序 404 | * @param tableName 表名 405 | * 406 | * @return 数组 407 | */ 408 | -(NSArray *)showTableWithPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order andTableName:(NSString *)tableName; 409 | 410 | /** 411 | * 展示Table数据 412 | * 413 | * @param fields 字段,(多个字段半角逗号隔开) 414 | * @param page 当前页 415 | * @param pagesize 分页大小 416 | * @param tableName 表名 417 | * 418 | * @return 数组 419 | */ 420 | -(NSArray *)showTableWithFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andTableName:(NSString *)tableName; 421 | 422 | 423 | /** 424 | * 展示Table数据 425 | * 426 | * @param fields 字段,(多个字段半角逗号隔开) 427 | * @param page 当前页 428 | * @param pagesize 分页大小 429 | * @param order 排序 430 | * @param tableName 表名 431 | * 432 | * @return 数组 433 | */ 434 | -(NSArray *)showTableWithFields:(NSString *)fields andPages:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order andTableName:(NSString *)tableName; 435 | #pragma mark - cache 缓存处理方法 436 | /** 437 | * 将数据缓存入文件 438 | * 439 | * @param data 数据源 440 | * @param cacheKey 缓存键名 441 | * 442 | * @return 是否成功缓存 443 | */ 444 | -(BOOL)setObject:(id)data ForCacheKey:(NSString *)cacheKey; 445 | /** 446 | * 根据缓存键名读取缓存内容 447 | * 448 | * @param cacheKey 缓存键名 449 | * 450 | * @return 缓存键值 451 | */ 452 | - (id )objectForCacheKey:(NSString *)cacheKey; 453 | #pragma mark - 索引操作 454 | /** 455 | * 为字段创建普通索引 456 | * 457 | * @param field 字段名称 458 | * @param tableName 表名 459 | * 460 | * @return 执行是否成功 461 | */ 462 | -(bool)createIndexWithField:(NSString *)field andTableName: (NSString *)tableName; 463 | @end 464 | -------------------------------------------------------------------------------- /pyfmdbdemo/PYFMDB/PYStructure.h: -------------------------------------------------------------------------------- 1 | // 2 | // PYStructure.h 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import 10 | typedef NS_ENUM(NSInteger, PYStructureType) { 11 | PYStructureTypeAutoInc = 0,//AUTO INCREAMNT && PRIMARY KEY INT 12 | PYStructureTypePrimaryInt = 1,//PRIMARY KEY INT 13 | PYStructureTypePrimaryText = 2,//PRIMARY KEY TEXT 14 | PYStructureTypeNormalInt = 3,//COMMON COLUMN KEY INT 15 | PYStructureTypeNormalText = 4,//COMMON COLUMN KEY TEXT 16 | }; 17 | @interface PYStructure : NSObject 18 | @property(nonatomic,strong)NSMutableArray *structureArray; 19 | @property(nonatomic,strong)NSDictionary *structureDictory; 20 | 21 | 22 | -(void)addWithField:(NSString *)field andType:(PYStructureType)type; 23 | -(NSArray *)fieldsArray; 24 | -(NSString *)fieldsString; 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /pyfmdbdemo/PYFMDB/PYStructure.m: -------------------------------------------------------------------------------- 1 | // 2 | // PYStructure.m 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "PYStructure.h" 10 | 11 | @implementation PYStructure 12 | -(void)addWithField:(NSString *)field andType:(PYStructureType)type{ 13 | NSDictionary *structure = [NSDictionary dictionary]; 14 | if (type==PYStructureTypeAutoInc) { 15 | structure = @{field:@"integer primary key autoincrement"}; 16 | } 17 | else if (type==PYStructureTypeNormalInt){ 18 | structure = @{field:@"integer not null"}; 19 | } 20 | else if (type ==PYStructureTypeNormalText){ 21 | structure = @{field:@"text not null"}; 22 | } 23 | else if(type==PYStructureTypePrimaryInt){ 24 | structure = @{field:@"integer primary key"}; 25 | } 26 | else if (type==PYStructureTypePrimaryText){ 27 | structure = @{field:@"text primary key"}; 28 | } 29 | [self.structureArray addObject:structure]; 30 | } 31 | 32 | -(NSDictionary *)structureDictory{ 33 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 34 | for (NSDictionary *dic in self.structureArray) { 35 | [dict addEntriesFromDictionary:dic]; 36 | } 37 | return [NSDictionary dictionaryWithDictionary:dict]; 38 | } 39 | 40 | 41 | 42 | -(NSMutableArray *)structureArray{ 43 | if (_structureArray) { 44 | return _structureArray; 45 | } 46 | _structureArray = [NSMutableArray array]; 47 | return _structureArray; 48 | } 49 | -(NSArray *)fieldsArray{ 50 | return [[self structureDictory] allKeys]; 51 | } 52 | -(NSString *)fieldsString{ 53 | NSString *fields = nil; 54 | for (NSString *obj in self.fieldsArray) { 55 | if (fields==nil) { 56 | fields = obj; 57 | } 58 | else{ 59 | fields = [NSString stringWithFormat:@"%@,%@",fields,obj]; 60 | } 61 | } 62 | return fields; 63 | } 64 | @end 65 | -------------------------------------------------------------------------------- /pyfmdbdemo/PYFMDB/PYTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // PYTable.h 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PYFMDB.h" 11 | #import "PYStructure.h" 12 | @interface PYTable : NSObject 13 | @property (nonatomic,copy) PYFMDB * db; 14 | 15 | @property(nonatomic,strong)NSString *tableName; 16 | 17 | @property(nonatomic,strong)NSString *databaseName; 18 | 19 | @property(nonatomic,strong)PYStructure *structure; 20 | 21 | @property(nonatomic,strong)NSArray *indexes; 22 | 23 | @property(nonatomic,strong)NSString *prefixUserDefaultKey; 24 | 25 | @property(nonatomic,strong)NSString *prefixBeforeKey; 26 | 27 | @property(nonatomic,strong)NSString *prefixAfterKey; 28 | 29 | 30 | 31 | -(void)truncate; 32 | 33 | -(NSUInteger)count; 34 | 35 | -(BOOL)isEmpty; 36 | 37 | -(NSString *)lastSql; 38 | 39 | -(NSString *)databasePath; 40 | 41 | #pragma mark - CREATE 42 | 43 | -(void)addFields:(NSDictionary *)fields; 44 | 45 | -(void)addFieldsIfNotExist:(NSDictionary *)fields; 46 | 47 | -(void)addOrUpdateFields:(NSDictionary *)fields andWhere:(NSString *)where; 48 | 49 | #pragma mark - UPDATE 50 | -(void)updateFields:(NSDictionary *)fields andWhere:(NSString *)where; 51 | 52 | -(void)setField:(NSString *)field andValue:(id)value andWhere:(NSString *)where; 53 | 54 | 55 | #pragma mark - DELETE 56 | 57 | -(void)deleteWithWhere:(NSString *)where; 58 | 59 | #pragma mark - READ 60 | 61 | -(id)getField:(NSString *)field andWhere:(NSString *)where; 62 | 63 | -(NSDictionary *)findWithWhere:(NSString *)where; 64 | 65 | -(NSArray *)selectAll; 66 | 67 | -(NSArray *)selectWithWhere:(NSString *)where; 68 | 69 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields; 70 | 71 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize; 72 | 73 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order; 74 | 75 | #pragma mark - HAS 76 | 77 | -(BOOL)hasWhere:(NSString *)where; 78 | 79 | -(BOOL)hasFields:(NSDictionary *)fields; 80 | 81 | #pragma mark - origin sql 82 | 83 | -(NSArray *)executeQueryWithSql:(NSString *)sql; 84 | 85 | -(BOOL)executeUpdateWithSql:(NSString *)sql; 86 | 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /pyfmdbdemo/PYFMDB/PYTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // PYTable.m 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "PYTable.h" 10 | #define PYTablePrefixUserDefaultKey @"PYFMDBKEY" 11 | #define PYTablePrefixBeforeKey @"" 12 | #define PYTablePrefixAfterKey @"" 13 | #define PYDataBaseName @"pyfmdb.sqlite" 14 | @class PYFMDB; 15 | @implementation PYTable 16 | -(instancetype)init{ 17 | if (self = [super init]) { 18 | //create the table 19 | if (![self.structure.structureDictory isEqual:nil]) { 20 | [self.db createTableWithDict:self.structure.structureDictory :self.tableName]; 21 | } 22 | //create indexes 23 | if (self.indexes.count >0) { 24 | for (NSString *index in self.indexes) { 25 | [self.db createIndexWithField:index andTableName:self.tableName]; 26 | } 27 | } 28 | } 29 | return self; 30 | } 31 | 32 | 33 | -(PYFMDB *)db{ 34 | if (_db) { 35 | return _db; 36 | } 37 | _db = [PYFMDB dbWithDbName:self.databaseName]; 38 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 39 | NSString *userID = [userDefaults objectForKey:self.prefixUserDefaultKey]; 40 | _db.prefix = userID==nil ? [NSString stringWithFormat:@"%@%@",self.prefixBeforeKey,self.prefixAfterKey]:[NSString stringWithFormat:@"%@%@%@",self.prefixBeforeKey,userID,self.prefixAfterKey]; 41 | return _db; 42 | } 43 | 44 | -(NSString *)databaseName{ 45 | if (_databaseName) { 46 | return _databaseName; 47 | } 48 | _databaseName = PYDataBaseName; 49 | return _databaseName; 50 | } 51 | 52 | -(NSString *)prefixAfterKey{ 53 | if (_prefixAfterKey) { 54 | return _prefixAfterKey; 55 | } 56 | _prefixAfterKey = PYTablePrefixAfterKey; 57 | return _prefixAfterKey; 58 | } 59 | 60 | -(NSString *)prefixBeforeKey{ 61 | if (_prefixBeforeKey) { 62 | return _prefixBeforeKey; 63 | } 64 | _prefixBeforeKey = PYTablePrefixBeforeKey; 65 | return _prefixBeforeKey; 66 | } 67 | 68 | -(NSString *)prefixUserDefaultKey{ 69 | if (_prefixUserDefaultKey) { 70 | return _prefixUserDefaultKey; 71 | } 72 | _prefixUserDefaultKey = PYTablePrefixUserDefaultKey; 73 | return _prefixUserDefaultKey; 74 | } 75 | 76 | -(PYStructure *)structure{ 77 | if (_structure) { 78 | return _structure; 79 | } 80 | _structure = [[PYStructure alloc] init]; 81 | return _structure; 82 | } 83 | 84 | -(void)truncate{ 85 | [self.db truncateTableWithTableName:self.tableName]; 86 | } 87 | 88 | -(NSUInteger)count{ 89 | [self.db clean]; 90 | [self.db setCurrentTableName:self.tableName]; 91 | return [[self.db select] count]; 92 | } 93 | 94 | -(BOOL)isEmpty{ 95 | if ([self count] >0) { 96 | return false; 97 | } 98 | return true; 99 | } 100 | 101 | -(NSString *)lastSql{ 102 | return self.db.lastSql; 103 | } 104 | 105 | -(NSString *)databasePath{ 106 | return self.db.dbPath; 107 | } 108 | 109 | #pragma mark - create 110 | 111 | -(void)addFields:(NSDictionary *)fields{ 112 | [self.db clean]; 113 | [self.db setCurrentTableName:self.tableName]; 114 | [self.db add:fields]; 115 | } 116 | 117 | -(void)addFieldsIfNotExist:(NSDictionary *)fields{ 118 | if (![self hasFields:fields]) { 119 | [self addFields:fields]; 120 | } 121 | } 122 | 123 | -(void)addOrUpdateFields:(NSDictionary *)fields andWhere:(NSString *)where{ 124 | [self hasWhere:where] ? [self updateFields:fields andWhere:where]: [self addFields:fields]; 125 | } 126 | 127 | #pragma mark - update 128 | -(void)updateFields:(NSDictionary *)fields andWhere:(NSString *)where{ 129 | [self.db clean]; 130 | [self.db setCurrentTableName:self.tableName]; 131 | [self.db whereWithString:where]; 132 | [self.db save:fields]; 133 | } 134 | -(void)setField:(NSString *)field andValue:(id)value andWhere:(NSString *)where{ 135 | [self updateFields:@{field:value} andWhere:where]; 136 | } 137 | 138 | #pragma mark - delete 139 | -(void)deleteWithWhere:(NSString *)where{ 140 | [self.db clean]; 141 | [self.db setCurrentTableName:self.tableName]; 142 | if (![where isEqual:nil]) { 143 | [self.db whereWithString:where]; 144 | } 145 | [self.db delete]; 146 | } 147 | #pragma mark - read 148 | -(id)getField:(NSString *)field andWhere:(NSString *)where{ 149 | NSDictionary *find = [self findWithWhere:where]; 150 | return [find objectForKey:field]; 151 | } 152 | -(NSDictionary *)findWithWhere:(NSString *)where{ 153 | [self.db clean]; 154 | [self.db setCurrentTableName:self.tableName]; 155 | if (![where isEqual:nil]) { 156 | [self.db whereWithString:where]; 157 | } 158 | [self.db fieldsWithString:self.structure.fieldsString]; 159 | return [self.db find]; 160 | } 161 | 162 | -(NSArray *)selectWithWhere:(NSString *)where{ 163 | return [self selectWithWhere:where andFields:self.structure.fieldsString andPage:0 andPageSize:0 andOrder:nil]; 164 | } 165 | -(NSArray *)selectAll{ 166 | return [self selectWithWhere:@"1"]; 167 | } 168 | 169 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields{ 170 | return [self selectWithWhere:where andFields:fields andPage:0 andPageSize:0 andOrder:nil]; 171 | } 172 | 173 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize{ 174 | return [self selectWithWhere:where andFields:fields andPage:page andPageSize:pagesize andOrder:nil]; 175 | } 176 | -(NSArray *)selectWithWhere:(NSString *)where andFields:(NSString *)fields andPage:(NSUInteger)page andPageSize:(NSUInteger)pagesize andOrder:(NSString *)order{ 177 | //clean state 178 | [self.db clean]; 179 | //tablename 180 | [self.db setCurrentTableName:self.tableName]; 181 | if (pagesize >0) { 182 | int startNum = page<=0 ? 0:(int)((page -1)*pagesize); 183 | int endNum = (int)(page*pagesize); 184 | //limit 185 | [self.db limitWithStart:startNum End:endNum]; 186 | } 187 | //where 188 | if (![where isEqual:nil]) { 189 | [self.db whereWithString:where]; 190 | } 191 | //field 192 | if (![fields isEqual:nil]) { 193 | if ([fields isEqualToString:@"*"]) { 194 | [self.db fieldsWithString:self.structure.fieldsString]; 195 | } 196 | else{ 197 | [self.db fieldsWithString:fields]; 198 | } 199 | } 200 | else{ 201 | [self.db fieldsWithString:self.structure.fieldsString]; 202 | } 203 | //order 204 | if (![order isEqual:nil]) { 205 | [self.db setOrder:order]; 206 | } 207 | return [self.db select]; 208 | } 209 | 210 | #pragma mark - has 211 | 212 | -(BOOL)hasWhere:(NSString *)where{ 213 | [self.db clean]; 214 | [self.db setCurrentTableName:self.tableName]; 215 | [self.db whereWithString:where]; 216 | return [[self.db queryCount] intValue] >0; 217 | } 218 | 219 | -(BOOL)hasFields:(NSDictionary *)fields{ 220 | [self.db clean]; 221 | [self.db setCurrentTableName:self.tableName]; 222 | [self.db whereWithDict:fields]; 223 | return [[self.db queryCount] intValue] >0; 224 | } 225 | 226 | 227 | #pragma mark - origin sql 228 | -(NSArray *)executeQueryWithSql:(NSString *)sql{ 229 | return [self.db excuteQueryWithSql:sql]; 230 | } 231 | 232 | -(BOOL)executeUpdateWithSql:(NSString *)sql{ 233 | return [self.db excuteUpdateWithSql:sql]; 234 | } 235 | 236 | 237 | @end 238 | 239 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 56C7F2741BE8D5900054E946 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F2731BE8D5900054E946 /* main.m */; }; 11 | 56C7F2771BE8D5900054E946 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F2761BE8D5900054E946 /* AppDelegate.m */; }; 12 | 56C7F27A1BE8D5900054E946 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F2791BE8D5900054E946 /* ViewController.m */; }; 13 | 56C7F27D1BE8D5900054E946 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 56C7F27B1BE8D5900054E946 /* Main.storyboard */; }; 14 | 56C7F27F1BE8D5900054E946 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56C7F27E1BE8D5900054E946 /* Assets.xcassets */; }; 15 | 56C7F2821BE8D5900054E946 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 56C7F2801BE8D5900054E946 /* LaunchScreen.storyboard */; }; 16 | 56C7F2981BE8D5F00054E946 /* FMDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F28B1BE8D5F00054E946 /* FMDatabase.m */; }; 17 | 56C7F2991BE8D5F00054E946 /* FMDatabaseAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F28D1BE8D5F00054E946 /* FMDatabaseAdditions.m */; }; 18 | 56C7F29A1BE8D5F00054E946 /* FMDatabasePool.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F28F1BE8D5F00054E946 /* FMDatabasePool.m */; }; 19 | 56C7F29B1BE8D5F00054E946 /* FMDatabaseQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F2911BE8D5F00054E946 /* FMDatabaseQueue.m */; }; 20 | 56C7F29C1BE8D5F00054E946 /* FMResultSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F2941BE8D5F00054E946 /* FMResultSet.m */; }; 21 | 56C7F29D1BE8D5F00054E946 /* PYFMDB.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C7F2971BE8D5F00054E946 /* PYFMDB.m */; }; 22 | 56C7F2A11BE8D7120054E946 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 56C7F2A01BE8D7120054E946 /* libsqlite3.0.tbd */; }; 23 | DEB182131C0EAB0400A9F587 /* PYTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB182121C0EAB0400A9F587 /* PYTable.m */; }; 24 | DEB182161C0EABC100A9F587 /* PYStructure.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB182151C0EABC100A9F587 /* PYStructure.m */; }; 25 | DEB182191C0F33F500A9F587 /* CarTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB182181C0F33F500A9F587 /* CarTable.m */; }; 26 | DEB182211C0F855300A9F587 /* pyfmdbdemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DEB182201C0F855300A9F587 /* pyfmdbdemoTests.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | DEB182231C0F855300A9F587 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 56C7F2671BE8D5900054E946 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 56C7F26E1BE8D5900054E946; 35 | remoteInfo = pyfmdbdemo; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 56C7F26F1BE8D5900054E946 /* pyfmdbdemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = pyfmdbdemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 56C7F2731BE8D5900054E946 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 56C7F2751BE8D5900054E946 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | 56C7F2761BE8D5900054E946 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | 56C7F2781BE8D5900054E946 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 45 | 56C7F2791BE8D5900054E946 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 46 | 56C7F27C1BE8D5900054E946 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | 56C7F27E1BE8D5900054E946 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | 56C7F2811BE8D5900054E946 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 49 | 56C7F2831BE8D5900054E946 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 56C7F28A1BE8D5F00054E946 /* FMDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMDatabase.h; sourceTree = ""; }; 51 | 56C7F28B1BE8D5F00054E946 /* FMDatabase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMDatabase.m; sourceTree = ""; }; 52 | 56C7F28C1BE8D5F00054E946 /* FMDatabaseAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMDatabaseAdditions.h; sourceTree = ""; }; 53 | 56C7F28D1BE8D5F00054E946 /* FMDatabaseAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMDatabaseAdditions.m; sourceTree = ""; }; 54 | 56C7F28E1BE8D5F00054E946 /* FMDatabasePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMDatabasePool.h; sourceTree = ""; }; 55 | 56C7F28F1BE8D5F00054E946 /* FMDatabasePool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMDatabasePool.m; sourceTree = ""; }; 56 | 56C7F2901BE8D5F00054E946 /* FMDatabaseQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMDatabaseQueue.h; sourceTree = ""; }; 57 | 56C7F2911BE8D5F00054E946 /* FMDatabaseQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMDatabaseQueue.m; sourceTree = ""; }; 58 | 56C7F2921BE8D5F00054E946 /* FMDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMDB.h; sourceTree = ""; }; 59 | 56C7F2931BE8D5F00054E946 /* FMResultSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMResultSet.h; sourceTree = ""; }; 60 | 56C7F2941BE8D5F00054E946 /* FMResultSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMResultSet.m; sourceTree = ""; }; 61 | 56C7F2961BE8D5F00054E946 /* PYFMDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYFMDB.h; sourceTree = ""; }; 62 | 56C7F2971BE8D5F00054E946 /* PYFMDB.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYFMDB.m; sourceTree = ""; }; 63 | 56C7F2A01BE8D7120054E946 /* libsqlite3.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; }; 64 | DEB182111C0EAB0400A9F587 /* PYTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYTable.h; sourceTree = ""; }; 65 | DEB182121C0EAB0400A9F587 /* PYTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYTable.m; sourceTree = ""; }; 66 | DEB182141C0EABC100A9F587 /* PYStructure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYStructure.h; sourceTree = ""; }; 67 | DEB182151C0EABC100A9F587 /* PYStructure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYStructure.m; sourceTree = ""; }; 68 | DEB182171C0F33F500A9F587 /* CarTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CarTable.h; sourceTree = ""; }; 69 | DEB182181C0F33F500A9F587 /* CarTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CarTable.m; sourceTree = ""; }; 70 | DEB1821E1C0F855300A9F587 /* pyfmdbdemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = pyfmdbdemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | DEB182201C0F855300A9F587 /* pyfmdbdemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = pyfmdbdemoTests.m; sourceTree = ""; }; 72 | DEB182221C0F855300A9F587 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | /* End PBXFileReference section */ 74 | 75 | /* Begin PBXFrameworksBuildPhase section */ 76 | 56C7F26C1BE8D5900054E946 /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | 56C7F2A11BE8D7120054E946 /* libsqlite3.0.tbd in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | DEB1821B1C0F855300A9F587 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | 56C7F2661BE8D5900054E946 = { 95 | isa = PBXGroup; 96 | children = ( 97 | 56C7F2A01BE8D7120054E946 /* libsqlite3.0.tbd */, 98 | 56C7F2891BE8D5F00054E946 /* FMDB */, 99 | 56C7F2951BE8D5F00054E946 /* PYFMDB */, 100 | 56C7F2711BE8D5900054E946 /* pyfmdbdemo */, 101 | DEB1821F1C0F855300A9F587 /* pyfmdbdemoTests */, 102 | 56C7F2701BE8D5900054E946 /* Products */, 103 | ); 104 | sourceTree = ""; 105 | }; 106 | 56C7F2701BE8D5900054E946 /* Products */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 56C7F26F1BE8D5900054E946 /* pyfmdbdemo.app */, 110 | DEB1821E1C0F855300A9F587 /* pyfmdbdemoTests.xctest */, 111 | ); 112 | name = Products; 113 | sourceTree = ""; 114 | }; 115 | 56C7F2711BE8D5900054E946 /* pyfmdbdemo */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 56C7F2751BE8D5900054E946 /* AppDelegate.h */, 119 | 56C7F2761BE8D5900054E946 /* AppDelegate.m */, 120 | 56C7F2781BE8D5900054E946 /* ViewController.h */, 121 | 56C7F2791BE8D5900054E946 /* ViewController.m */, 122 | 56C7F27B1BE8D5900054E946 /* Main.storyboard */, 123 | 56C7F27E1BE8D5900054E946 /* Assets.xcassets */, 124 | 56C7F2801BE8D5900054E946 /* LaunchScreen.storyboard */, 125 | 56C7F2831BE8D5900054E946 /* Info.plist */, 126 | 56C7F2721BE8D5900054E946 /* Supporting Files */, 127 | DEB182171C0F33F500A9F587 /* CarTable.h */, 128 | DEB182181C0F33F500A9F587 /* CarTable.m */, 129 | ); 130 | path = pyfmdbdemo; 131 | sourceTree = ""; 132 | }; 133 | 56C7F2721BE8D5900054E946 /* Supporting Files */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 56C7F2731BE8D5900054E946 /* main.m */, 137 | ); 138 | name = "Supporting Files"; 139 | sourceTree = ""; 140 | }; 141 | 56C7F2891BE8D5F00054E946 /* FMDB */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 56C7F28A1BE8D5F00054E946 /* FMDatabase.h */, 145 | 56C7F28B1BE8D5F00054E946 /* FMDatabase.m */, 146 | 56C7F28C1BE8D5F00054E946 /* FMDatabaseAdditions.h */, 147 | 56C7F28D1BE8D5F00054E946 /* FMDatabaseAdditions.m */, 148 | 56C7F28E1BE8D5F00054E946 /* FMDatabasePool.h */, 149 | 56C7F28F1BE8D5F00054E946 /* FMDatabasePool.m */, 150 | 56C7F2901BE8D5F00054E946 /* FMDatabaseQueue.h */, 151 | 56C7F2911BE8D5F00054E946 /* FMDatabaseQueue.m */, 152 | 56C7F2921BE8D5F00054E946 /* FMDB.h */, 153 | 56C7F2931BE8D5F00054E946 /* FMResultSet.h */, 154 | 56C7F2941BE8D5F00054E946 /* FMResultSet.m */, 155 | ); 156 | path = FMDB; 157 | sourceTree = ""; 158 | }; 159 | 56C7F2951BE8D5F00054E946 /* PYFMDB */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 56C7F2961BE8D5F00054E946 /* PYFMDB.h */, 163 | 56C7F2971BE8D5F00054E946 /* PYFMDB.m */, 164 | DEB182111C0EAB0400A9F587 /* PYTable.h */, 165 | DEB182121C0EAB0400A9F587 /* PYTable.m */, 166 | DEB182141C0EABC100A9F587 /* PYStructure.h */, 167 | DEB182151C0EABC100A9F587 /* PYStructure.m */, 168 | ); 169 | path = PYFMDB; 170 | sourceTree = ""; 171 | }; 172 | DEB1821F1C0F855300A9F587 /* pyfmdbdemoTests */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | DEB182201C0F855300A9F587 /* pyfmdbdemoTests.m */, 176 | DEB182221C0F855300A9F587 /* Info.plist */, 177 | ); 178 | path = pyfmdbdemoTests; 179 | sourceTree = ""; 180 | }; 181 | /* End PBXGroup section */ 182 | 183 | /* Begin PBXNativeTarget section */ 184 | 56C7F26E1BE8D5900054E946 /* pyfmdbdemo */ = { 185 | isa = PBXNativeTarget; 186 | buildConfigurationList = 56C7F2861BE8D5900054E946 /* Build configuration list for PBXNativeTarget "pyfmdbdemo" */; 187 | buildPhases = ( 188 | 56C7F26B1BE8D5900054E946 /* Sources */, 189 | 56C7F26C1BE8D5900054E946 /* Frameworks */, 190 | 56C7F26D1BE8D5900054E946 /* Resources */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | ); 196 | name = pyfmdbdemo; 197 | productName = pyfmdbdemo; 198 | productReference = 56C7F26F1BE8D5900054E946 /* pyfmdbdemo.app */; 199 | productType = "com.apple.product-type.application"; 200 | }; 201 | DEB1821D1C0F855300A9F587 /* pyfmdbdemoTests */ = { 202 | isa = PBXNativeTarget; 203 | buildConfigurationList = DEB182271C0F855300A9F587 /* Build configuration list for PBXNativeTarget "pyfmdbdemoTests" */; 204 | buildPhases = ( 205 | DEB1821A1C0F855300A9F587 /* Sources */, 206 | DEB1821B1C0F855300A9F587 /* Frameworks */, 207 | DEB1821C1C0F855300A9F587 /* Resources */, 208 | ); 209 | buildRules = ( 210 | ); 211 | dependencies = ( 212 | DEB182241C0F855300A9F587 /* PBXTargetDependency */, 213 | ); 214 | name = pyfmdbdemoTests; 215 | productName = pyfmdbdemoTests; 216 | productReference = DEB1821E1C0F855300A9F587 /* pyfmdbdemoTests.xctest */; 217 | productType = "com.apple.product-type.bundle.unit-test"; 218 | }; 219 | /* End PBXNativeTarget section */ 220 | 221 | /* Begin PBXProject section */ 222 | 56C7F2671BE8D5900054E946 /* Project object */ = { 223 | isa = PBXProject; 224 | attributes = { 225 | LastUpgradeCheck = 0710; 226 | ORGANIZATIONNAME = pengyong; 227 | TargetAttributes = { 228 | 56C7F26E1BE8D5900054E946 = { 229 | CreatedOnToolsVersion = 7.1; 230 | }; 231 | DEB1821D1C0F855300A9F587 = { 232 | CreatedOnToolsVersion = 7.1.1; 233 | TestTargetID = 56C7F26E1BE8D5900054E946; 234 | }; 235 | }; 236 | }; 237 | buildConfigurationList = 56C7F26A1BE8D5900054E946 /* Build configuration list for PBXProject "pyfmdbdemo" */; 238 | compatibilityVersion = "Xcode 3.2"; 239 | developmentRegion = English; 240 | hasScannedForEncodings = 0; 241 | knownRegions = ( 242 | en, 243 | Base, 244 | ); 245 | mainGroup = 56C7F2661BE8D5900054E946; 246 | productRefGroup = 56C7F2701BE8D5900054E946 /* Products */; 247 | projectDirPath = ""; 248 | projectRoot = ""; 249 | targets = ( 250 | 56C7F26E1BE8D5900054E946 /* pyfmdbdemo */, 251 | DEB1821D1C0F855300A9F587 /* pyfmdbdemoTests */, 252 | ); 253 | }; 254 | /* End PBXProject section */ 255 | 256 | /* Begin PBXResourcesBuildPhase section */ 257 | 56C7F26D1BE8D5900054E946 /* Resources */ = { 258 | isa = PBXResourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 56C7F2821BE8D5900054E946 /* LaunchScreen.storyboard in Resources */, 262 | 56C7F27F1BE8D5900054E946 /* Assets.xcassets in Resources */, 263 | 56C7F27D1BE8D5900054E946 /* Main.storyboard in Resources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | DEB1821C1C0F855300A9F587 /* Resources */ = { 268 | isa = PBXResourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | /* End PBXResourcesBuildPhase section */ 275 | 276 | /* Begin PBXSourcesBuildPhase section */ 277 | 56C7F26B1BE8D5900054E946 /* Sources */ = { 278 | isa = PBXSourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | 56C7F27A1BE8D5900054E946 /* ViewController.m in Sources */, 282 | 56C7F29A1BE8D5F00054E946 /* FMDatabasePool.m in Sources */, 283 | 56C7F2771BE8D5900054E946 /* AppDelegate.m in Sources */, 284 | 56C7F29B1BE8D5F00054E946 /* FMDatabaseQueue.m in Sources */, 285 | 56C7F29D1BE8D5F00054E946 /* PYFMDB.m in Sources */, 286 | DEB182131C0EAB0400A9F587 /* PYTable.m in Sources */, 287 | DEB182161C0EABC100A9F587 /* PYStructure.m in Sources */, 288 | DEB182191C0F33F500A9F587 /* CarTable.m in Sources */, 289 | 56C7F2741BE8D5900054E946 /* main.m in Sources */, 290 | 56C7F2981BE8D5F00054E946 /* FMDatabase.m in Sources */, 291 | 56C7F29C1BE8D5F00054E946 /* FMResultSet.m in Sources */, 292 | 56C7F2991BE8D5F00054E946 /* FMDatabaseAdditions.m in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | DEB1821A1C0F855300A9F587 /* Sources */ = { 297 | isa = PBXSourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | DEB182211C0F855300A9F587 /* pyfmdbdemoTests.m in Sources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | /* End PBXSourcesBuildPhase section */ 305 | 306 | /* Begin PBXTargetDependency section */ 307 | DEB182241C0F855300A9F587 /* PBXTargetDependency */ = { 308 | isa = PBXTargetDependency; 309 | target = 56C7F26E1BE8D5900054E946 /* pyfmdbdemo */; 310 | targetProxy = DEB182231C0F855300A9F587 /* PBXContainerItemProxy */; 311 | }; 312 | /* End PBXTargetDependency section */ 313 | 314 | /* Begin PBXVariantGroup section */ 315 | 56C7F27B1BE8D5900054E946 /* Main.storyboard */ = { 316 | isa = PBXVariantGroup; 317 | children = ( 318 | 56C7F27C1BE8D5900054E946 /* Base */, 319 | ); 320 | name = Main.storyboard; 321 | sourceTree = ""; 322 | }; 323 | 56C7F2801BE8D5900054E946 /* LaunchScreen.storyboard */ = { 324 | isa = PBXVariantGroup; 325 | children = ( 326 | 56C7F2811BE8D5900054E946 /* Base */, 327 | ); 328 | name = LaunchScreen.storyboard; 329 | sourceTree = ""; 330 | }; 331 | /* End PBXVariantGroup section */ 332 | 333 | /* Begin XCBuildConfiguration section */ 334 | 56C7F2841BE8D5900054E946 /* Debug */ = { 335 | isa = XCBuildConfiguration; 336 | buildSettings = { 337 | ALWAYS_SEARCH_USER_PATHS = NO; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 339 | CLANG_CXX_LIBRARY = "libc++"; 340 | CLANG_ENABLE_MODULES = YES; 341 | CLANG_ENABLE_OBJC_ARC = YES; 342 | CLANG_WARN_BOOL_CONVERSION = YES; 343 | CLANG_WARN_CONSTANT_CONVERSION = YES; 344 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 345 | CLANG_WARN_EMPTY_BODY = YES; 346 | CLANG_WARN_ENUM_CONVERSION = YES; 347 | CLANG_WARN_INT_CONVERSION = YES; 348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 349 | CLANG_WARN_UNREACHABLE_CODE = YES; 350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 351 | CODE_SIGN_IDENTITY = ""; 352 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 353 | COPY_PHASE_STRIP = NO; 354 | DEBUG_INFORMATION_FORMAT = dwarf; 355 | ENABLE_STRICT_OBJC_MSGSEND = YES; 356 | ENABLE_TESTABILITY = YES; 357 | GCC_C_LANGUAGE_STANDARD = gnu99; 358 | GCC_DYNAMIC_NO_PIC = NO; 359 | GCC_NO_COMMON_BLOCKS = YES; 360 | GCC_OPTIMIZATION_LEVEL = 0; 361 | GCC_PREPROCESSOR_DEFINITIONS = ( 362 | "DEBUG=1", 363 | "$(inherited)", 364 | ); 365 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 366 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 367 | GCC_WARN_UNDECLARED_SELECTOR = YES; 368 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 369 | GCC_WARN_UNUSED_FUNCTION = YES; 370 | GCC_WARN_UNUSED_VARIABLE = YES; 371 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 372 | MTL_ENABLE_DEBUG_INFO = YES; 373 | ONLY_ACTIVE_ARCH = YES; 374 | SDKROOT = iphoneos; 375 | }; 376 | name = Debug; 377 | }; 378 | 56C7F2851BE8D5900054E946 /* Release */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | ALWAYS_SEARCH_USER_PATHS = NO; 382 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 383 | CLANG_CXX_LIBRARY = "libc++"; 384 | CLANG_ENABLE_MODULES = YES; 385 | CLANG_ENABLE_OBJC_ARC = YES; 386 | CLANG_WARN_BOOL_CONVERSION = YES; 387 | CLANG_WARN_CONSTANT_CONVERSION = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INT_CONVERSION = YES; 392 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 393 | CLANG_WARN_UNREACHABLE_CODE = YES; 394 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 395 | CODE_SIGN_IDENTITY = ""; 396 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 397 | COPY_PHASE_STRIP = NO; 398 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 399 | ENABLE_NS_ASSERTIONS = NO; 400 | ENABLE_STRICT_OBJC_MSGSEND = YES; 401 | GCC_C_LANGUAGE_STANDARD = gnu99; 402 | GCC_NO_COMMON_BLOCKS = YES; 403 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 404 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 405 | GCC_WARN_UNDECLARED_SELECTOR = YES; 406 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 407 | GCC_WARN_UNUSED_FUNCTION = YES; 408 | GCC_WARN_UNUSED_VARIABLE = YES; 409 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 410 | MTL_ENABLE_DEBUG_INFO = NO; 411 | SDKROOT = iphoneos; 412 | VALIDATE_PRODUCT = YES; 413 | }; 414 | name = Release; 415 | }; 416 | 56C7F2871BE8D5900054E946 /* Debug */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 420 | CODE_SIGN_IDENTITY = "iPhone Developer"; 421 | INFOPLIST_FILE = pyfmdbdemo/Info.plist; 422 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 423 | PRODUCT_BUNDLE_IDENTIFIER = cn.velda.pyfmdbdemo; 424 | PRODUCT_NAME = "$(TARGET_NAME)"; 425 | }; 426 | name = Debug; 427 | }; 428 | 56C7F2881BE8D5900054E946 /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CODE_SIGN_IDENTITY = "iPhone Developer"; 433 | INFOPLIST_FILE = pyfmdbdemo/Info.plist; 434 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 435 | PRODUCT_BUNDLE_IDENTIFIER = cn.velda.pyfmdbdemo; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | }; 438 | name = Release; 439 | }; 440 | DEB182251C0F855300A9F587 /* Debug */ = { 441 | isa = XCBuildConfiguration; 442 | buildSettings = { 443 | BUNDLE_LOADER = "$(TEST_HOST)"; 444 | CODE_SIGN_IDENTITY = "iPhone Developer"; 445 | INFOPLIST_FILE = pyfmdbdemoTests/Info.plist; 446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 447 | PRODUCT_BUNDLE_IDENTIFIER = cn.velda.pyfmdbdemoTests; 448 | PRODUCT_NAME = "$(TARGET_NAME)"; 449 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pyfmdbdemo.app/pyfmdbdemo"; 450 | }; 451 | name = Debug; 452 | }; 453 | DEB182261C0F855300A9F587 /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | BUNDLE_LOADER = "$(TEST_HOST)"; 457 | CODE_SIGN_IDENTITY = "iPhone Developer"; 458 | INFOPLIST_FILE = pyfmdbdemoTests/Info.plist; 459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 460 | PRODUCT_BUNDLE_IDENTIFIER = cn.velda.pyfmdbdemoTests; 461 | PRODUCT_NAME = "$(TARGET_NAME)"; 462 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pyfmdbdemo.app/pyfmdbdemo"; 463 | }; 464 | name = Release; 465 | }; 466 | /* End XCBuildConfiguration section */ 467 | 468 | /* Begin XCConfigurationList section */ 469 | 56C7F26A1BE8D5900054E946 /* Build configuration list for PBXProject "pyfmdbdemo" */ = { 470 | isa = XCConfigurationList; 471 | buildConfigurations = ( 472 | 56C7F2841BE8D5900054E946 /* Debug */, 473 | 56C7F2851BE8D5900054E946 /* Release */, 474 | ); 475 | defaultConfigurationIsVisible = 0; 476 | defaultConfigurationName = Release; 477 | }; 478 | 56C7F2861BE8D5900054E946 /* Build configuration list for PBXNativeTarget "pyfmdbdemo" */ = { 479 | isa = XCConfigurationList; 480 | buildConfigurations = ( 481 | 56C7F2871BE8D5900054E946 /* Debug */, 482 | 56C7F2881BE8D5900054E946 /* Release */, 483 | ); 484 | defaultConfigurationIsVisible = 0; 485 | defaultConfigurationName = Release; 486 | }; 487 | DEB182271C0F855300A9F587 /* Build configuration list for PBXNativeTarget "pyfmdbdemoTests" */ = { 488 | isa = XCConfigurationList; 489 | buildConfigurations = ( 490 | DEB182251C0F855300A9F587 /* Debug */, 491 | DEB182261C0F855300A9F587 /* Release */, 492 | ); 493 | defaultConfigurationIsVisible = 0; 494 | defaultConfigurationName = Release; 495 | }; 496 | /* End XCConfigurationList section */ 497 | }; 498 | rootObject = 56C7F2671BE8D5900054E946 /* Project object */; 499 | } 500 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo.xcodeproj/xcshareddata/xcschemes/pyfmdbdemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo.xcodeproj/xcshareddata/xcschemes/pyfmdbdemoTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 66 | 67 | 73 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // pyfmdbdemo 4 | // 5 | // Created by pengyong on 15/11/3. 6 | // Copyright © 2015年 pengyong. 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 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // pyfmdbdemo 4 | // 5 | // Created by pengyong on 15/11/3. 6 | // Copyright © 2015年 pengyong. 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 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/Assets.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 | } -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/Base.lproj/LaunchScreen.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 | 28 | 29 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 27 | 38 | 49 | 60 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/CarTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // CarTable.h 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "PYTable.h" 10 | 11 | @interface CarTable : PYTable 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/CarTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // CarTable.m 3 | // pyfmdbdemo 4 | // 5 | // Created by terry peng on 15/12/2. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "CarTable.h" 10 | 11 | @implementation CarTable 12 | -(PYStructure *)structure{ 13 | PYStructure * st = [[PYStructure alloc] init]; 14 | [st addWithField:@"id" andType:PYStructureTypeAutoInc]; 15 | [st addWithField:@"name" andType:PYStructureTypeNormalText]; 16 | [st addWithField:@"wheels" andType:PYStructureTypeNormalInt]; 17 | return st; 18 | } 19 | 20 | -(NSString *)tableName{ 21 | return @"car"; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 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 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // pyfmdbdemo 4 | // 5 | // Created by pengyong on 15/11/3. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CarTable.h" 11 | @interface ViewController : UIViewController 12 | 13 | @property(nonatomic,strong) CarTable *table; 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // pyfmdbdemo 4 | // 5 | // Created by pengyong on 15/11/3. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | @interface ViewController () 11 | - (IBAction)add; 12 | - (IBAction)update; 13 | - (IBAction)delete; 14 | - (IBAction)query; 15 | - (IBAction)truncate; 16 | @end 17 | 18 | @implementation ViewController 19 | 20 | -(void)printSql{ 21 | NSLog(@"sql:%@",self.table.lastSql); 22 | } 23 | 24 | 25 | -(CarTable *)table{ 26 | if (_table) { 27 | return _table; 28 | } 29 | _table = [[CarTable alloc] init]; 30 | return _table; 31 | } 32 | - (IBAction)add { 33 | for (int i=0; i<10; i++) { 34 | NSDictionary *data = @{ 35 | @"name":@"MINI", 36 | @"wheels":@4 , 37 | }; 38 | [self.table addFields:data]; 39 | } 40 | [self printSql]; 41 | NSLog(@"table count:%lu",(unsigned long)[self.table count]); 42 | [self printSql]; 43 | } 44 | 45 | - (IBAction)update { 46 | [self.table updateFields:@{@"name":@"BMW"} andWhere:@"id > 2"]; 47 | [self printSql]; 48 | } 49 | 50 | - (IBAction)delete { 51 | 52 | [self.table deleteWithWhere:@"id>5"]; 53 | [self printSql]; 54 | 55 | } 56 | 57 | - (IBAction)query { 58 | // NSArray *result = [self.table selectWithWhere:nil andFields:@"*" andPage:1 andPageSize:5 andOrder:@"id desc"]; 59 | NSArray *result = [self.table selectAll]; 60 | NSLog(@"%@",result); 61 | [self printSql]; 62 | 63 | } 64 | 65 | - (IBAction)truncate { 66 | [self.table truncate]; 67 | } 68 | 69 | @end -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // pyfmdbdemo 4 | // 5 | // Created by pengyong on 15/11/3. 6 | // Copyright © 2015年 pengyong. 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 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemoTests/Schemes/pyfmdbdemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemoTests/Schemes/pyfmdbdemoTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /pyfmdbdemo/pyfmdbdemoTests/pyfmdbdemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // pyfmdbdemoTests.m 3 | // pyfmdbdemoTests 4 | // 5 | // Created by terry peng on 15/12/3. 6 | // Copyright © 2015年 pengyong. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CarTable.h" 11 | @interface pyfmdbdemoTests : XCTestCase 12 | @property(nonatomic,strong)CarTable *table; 13 | @end 14 | 15 | @implementation pyfmdbdemoTests 16 | 17 | -(CarTable *)table{ 18 | if (_table) { 19 | return _table; 20 | } 21 | _table = [[CarTable alloc] init]; 22 | [_table truncate]; 23 | return _table; 24 | } 25 | 26 | -(void)add{ 27 | NSDictionary *fields = @{@"name":@"BMW",@"wheels":@1}; 28 | [self.table addFields:fields]; 29 | } 30 | 31 | -(void)delete{ 32 | [self.table deleteWithWhere:@"name='BMW'"]; 33 | } 34 | 35 | -(void)testInsert{ 36 | [self add]; 37 | BOOL valid = [self.table count]==1 ? YES :NO; 38 | XCTAssertTrue(valid); 39 | } 40 | 41 | -(void)testAddOrUpdate{ 42 | [self add]; 43 | NSDictionary *fields = @{@"name":@"MINI",@"wheels":@1}; 44 | [self.table addOrUpdateFields:fields andWhere:@"name='MINI'"]; 45 | BOOL valid1 = [self.table count]==2 ? YES :NO; 46 | [self.table addOrUpdateFields:fields andWhere:@"name='BMW'"]; 47 | BOOL valid2 = [self.table count]==2 && ![self.table hasFields: @{@"name":@"BMW",@"wheels":@1}] ? YES :NO; 48 | XCTAssertTrue(valid1 && valid2); 49 | } 50 | 51 | -(void)testAddOrIgnore{ 52 | [self add]; 53 | NSDictionary *fields = @{@"name":@"MINI",@"wheels":@1}; 54 | [self.table addFieldsIfNotExist:fields]; 55 | BOOL valid1 = [self.table count]==2 ? YES :NO; 56 | [self.table addFieldsIfNotExist:@{@"name":@"BMW",@"wheels":@1}]; 57 | BOOL valid2 = [self.table count]==2 ? YES :NO; 58 | XCTAssertTrue(valid1 && valid2); 59 | } 60 | 61 | -(void)testDelete{ 62 | [self add]; 63 | [self delete]; 64 | BOOL valid = [self.table count]==0 ? YES :NO; 65 | XCTAssertTrue(valid); 66 | } 67 | 68 | -(void)testSelect{ 69 | for (int i=0; i<30; i++) { 70 | [self add]; 71 | } 72 | NSArray *result = [self.table selectAll]; 73 | BOOL valid = [result count]==30 ? YES :NO; 74 | XCTAssertTrue(valid); 75 | } 76 | 77 | -(void)testUpdate{ 78 | [self add]; 79 | [self.table updateFields:@{@"name":@"MINI"} andWhere:@"name='BMW'"]; 80 | NSString *field = (NSString *)[self.table getField:@"name" andWhere:nil]; 81 | XCTAssertTrue([field isEqualToString:@"MINI"]); 82 | } 83 | 84 | -(void)testHasWhere{ 85 | [self add]; 86 | XCTAssertTrue([self.table hasWhere:@"name='BMW'"]); 87 | } 88 | 89 | -(void)testHasFields{ 90 | [self add]; 91 | NSDictionary *fields = @{@"name":@"BMW",@"wheels":@1}; 92 | XCTAssert([self.table hasFields:fields]); 93 | } 94 | 95 | -(void)testExecuteQuery{ 96 | [self add]; 97 | NSString *sql = @"select * from car"; 98 | XCTAssert([[self.table executeQueryWithSql:sql] count] ==1); 99 | } 100 | 101 | -(void)testExecuteUpdate{ 102 | [self add]; 103 | NSString *sql = @"delete from car where name='BMW'"; 104 | XCTAssert([self.table executeUpdateWithSql:sql]); 105 | } 106 | 107 | @end 108 | --------------------------------------------------------------------------------