Initial commit

This commit is contained in:
lianxiang
2018-08-22 11:15:52 +08:00
parent d98e20881f
commit 249bf6864e
491 changed files with 68665 additions and 7 deletions
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2012 Jianghuai Li (https://github.com/li6185377)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+86
View File
@@ -0,0 +1,86 @@
//
// LKDBProperty+KeyMapping.h
// LKDBHelper
//
// Created by LJH on 13-6-17.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import "LKDBUtils.h"
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (TableMapping)
/**
* @brief Overwrite in your models if your property names don't match your Table Column names.
also use for set create table columns.
@{ sql column name : ( model property name ) or LKDBInherit or LKDBUserCalculate}
*/
+ (nullable NSDictionary *)getTableMapping;
/***
simple set a column as "LKSQL_Mapping_UserCalculate"
column name
*/
+ (void)setUserCalculateForCN:(NSString *)columnName;
///property type name
+ (void)setUserCalculateForPTN:(NSString *)propertyTypeName;
///binding columnName to PropertyName
+ (void)setTableColumnName:(NSString *)columnName bindingPropertyName:(NSString *)propertyName;
///remove unwanted binding property
+ (void)removePropertyWithColumnName:(NSString *)columnName;
+ (void)removePropertyWithColumnNameArray:(NSArray *)columnNameArray;
@end
@interface LKDBProperty : NSObject
///保存的方式
@property (nonatomic, copy, readonly) NSString *type;
///保存到数据的 列名
@property (nonatomic, copy, readonly) NSString *sqlColumnName;
///保存到数据的类型
@property (nonatomic, copy, readonly) NSString *sqlColumnType;
///属性名
@property (nonatomic, copy, readonly) NSString *propertyName;
///属性的类型
@property (nonatomic, copy, readonly) NSString *propertyType;
///属性的Protocol
//@property(readonly,copy,nonatomic)NSString *propertyProtocol;
///creating table's column
@property (nonatomic, assign) BOOL isUnique;
@property (nonatomic, assign) BOOL isNotNull;
@property (nullable, nonatomic, copy) NSString *defaultValue;
@property (nullable, nonatomic, copy) NSString *checkValue;
@property (nonatomic, assign) NSInteger length;
- (BOOL)isUserCalculate;
@end
@interface LKModelInfos : NSObject
- (id)initWithKeyMapping:(nullable NSDictionary *)keyMapping
propertyNames:(NSArray *)propertyNames
propertyType:(NSArray *)propertyType
primaryKeys:(nullable NSArray *)primaryKeys;
@property (nonatomic, readonly) NSUInteger count;
@property (nullable, nonatomic, readonly) NSArray *primaryKeys;
- (nullable LKDBProperty *)objectWithIndex:(NSInteger)index;
- (nullable LKDBProperty *)objectWithPropertyName:(NSString *)propertyName;
- (nullable LKDBProperty *)objectWithSqlColumnName:(NSString *)columnName;
@end
NS_ASSUME_NONNULL_END
+277
View File
@@ -0,0 +1,277 @@
//
// LKDBProperty+KeyMapping.m
// LKDBHelper
//
// Created by LJH on 13-6-17.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import "LKDB+Mapping.h"
#import "NSObject+LKModel.h"
@interface LKModelInfos () {
__strong NSMutableDictionary *_proNameDic;
__strong NSMutableDictionary *_sqlNameDic;
__strong NSArray *_primaryKeys;
}
- (void)removeWithColumnName:(NSString *)columnName;
- (void)addDBPropertyWithType:(NSString *)type cname:(NSString *)column_name ctype:(NSString *)ctype pname:(NSString *)pname ptype:(NSString *)ptype;
- (void)updateProperty:(LKDBProperty *)property sqlColumnName:(NSString *)columnName;
- (void)updateProperty:(LKDBProperty *)property propertyName:(NSString *)propertyName;
@end
#pragma mark - 声明属性
@interface LKDBProperty ()
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *sqlColumnName;
@property (nonatomic, copy) NSString *sqlColumnType;
@property (nonatomic, copy) NSString *propertyName;
@property (nonatomic, copy) NSString *propertyType;
- (id)initWithType:(NSString *)type cname:(NSString *)cname ctype:(NSString *)ctype pname:(NSString *)pname ptype:(NSString *)ptype;
@end
#pragma mark - LKDBProperty
@implementation LKDBProperty
- (id)initWithType:(NSString *)type cname:(NSString *)cname ctype:(NSString *)ctype pname:(NSString *)pname ptype:(NSString *)ptype
{
self = [super init];
if (self) {
_type = [type copy];
_sqlColumnName = [cname copy];
_sqlColumnType = [ctype copy];
_propertyName = [pname copy];
_propertyType = [ptype copy];
}
return self;
}
- (void)enableUserCalculate
{
_type = LKSQL_Mapping_UserCalculate;
}
- (BOOL)isUserCalculate
{
return ([_type isEqualToString:LKSQL_Mapping_UserCalculate] || _propertyName == nil || [_propertyName isEqualToString:LKSQL_Mapping_UserCalculate]);
}
@end
#pragma mark - NSObject - TableMapping
@implementation NSObject (TableMapping)
+ (NSDictionary *)getTableMapping
{
return nil;
}
+ (void)setUserCalculateForCN:(NSString *)columnName
{
if ([LKDBUtils checkStringIsEmpty:columnName]) {
LKErrorLog(@"columnName is null");
return;
}
LKModelInfos *infos = [self getModelInfos];
LKDBProperty *property = [infos objectWithSqlColumnName:columnName];
if (property) {
[property enableUserCalculate];
} else {
[infos addDBPropertyWithType:LKSQL_Mapping_UserCalculate cname:columnName ctype:LKSQL_Type_Text pname:columnName ptype:@"NSString"];
}
}
+ (void)setUserCalculateForPTN:(NSString *)propertyTypeName
{
if ([LKDBUtils checkStringIsEmpty:propertyTypeName]) {
LKErrorLog(@"propertyTypeName is null");
return;
}
Class clazz = NSClassFromString(propertyTypeName);
LKModelInfos *infos = [self getModelInfos];
for (NSInteger i = 0; i < infos.count; i++) {
LKDBProperty *property = [infos objectWithIndex:i];
Class p_cls = NSClassFromString(property.propertyType);
BOOL isSubClass = ((p_cls && clazz) && [p_cls isSubclassOfClass:clazz]);
BOOL isNameEqual = [property.propertyType isEqualToString:propertyTypeName];
if (isSubClass || isNameEqual) {
[property enableUserCalculate];
}
}
}
+ (void)setTableColumnName:(NSString *)columnName bindingPropertyName:(NSString *)propertyName
{
if ([LKDBUtils checkStringIsEmpty:columnName] || [LKDBUtils checkStringIsEmpty:propertyName])
return;
LKModelInfos *infos = [self getModelInfos];
LKDBProperty *property = [infos objectWithPropertyName:propertyName];
if (property == nil) {
return;
}
LKDBProperty *column = [infos objectWithSqlColumnName:columnName];
if (column) {
[infos updateProperty:column propertyName:propertyName];
column.propertyType = property.propertyType;
} else if ([property.sqlColumnName isEqualToString:property.propertyName]) {
[infos updateProperty:property sqlColumnName:columnName];
} else {
[infos addDBPropertyWithType:LKSQL_Mapping_Binding cname:columnName ctype:LKSQL_Type_Text pname:propertyName ptype:property.propertyType];
}
}
+ (void)removePropertyWithColumnNameArray:(NSArray *)columnNameArray
{
LKModelInfos *infos = [self getModelInfos];
for (NSString *columnName in columnNameArray) {
[infos removeWithColumnName:columnName];
}
}
+ (void)removePropertyWithColumnName:(NSString *)columnName
{
[[self getModelInfos] removeWithColumnName:columnName];
}
@end
#pragma mark - LKModelInfos
@implementation LKModelInfos
- (id)initWithKeyMapping:(NSDictionary *)keyMapping propertyNames:(NSArray *)propertyNames propertyType:(NSArray *)propertyType primaryKeys:(NSArray *)primaryKeys
{
self = [super init];
if (self) {
_primaryKeys = [NSArray arrayWithArray:primaryKeys];
_proNameDic = [[NSMutableDictionary alloc] init];
_sqlNameDic = [[NSMutableDictionary alloc] init];
NSString *type, *column_name, *column_type, *property_name, *property_type;
if (keyMapping.count > 0) {
NSArray *sql_names = keyMapping.allKeys;
for (NSInteger i = 0; i < sql_names.count; i++) {
type = column_name = column_type = property_name = property_type = nil;
column_name = [sql_names objectAtIndex:i];
NSString *mappingValue = [keyMapping objectForKey:column_name];
//如果 设置的 属性名 是空白的 自动转成 使用ColumnName
if ([LKDBUtils checkStringIsEmpty:mappingValue]) {
NSLog(@"#ERROR sql column name %@ mapping value is empty,automatically converted LKDBInherit", column_name);
mappingValue = LKSQL_Mapping_Inherit;
}
if ([mappingValue isEqualToString:LKSQL_Mapping_UserCalculate]) {
type = LKSQL_Mapping_UserCalculate;
column_type = LKSQL_Type_Text;
} else {
if ([mappingValue isEqualToString:LKSQL_Mapping_Inherit] || [mappingValue isEqualToString:LKSQL_Mapping_Binding]) {
type = LKSQL_Mapping_Inherit;
property_name = column_name;
} else {
type = LKSQL_Mapping_Binding;
property_name = mappingValue;
}
NSUInteger index = [propertyNames indexOfObject:property_name];
NSAssert(index != NSNotFound, @"#ERROR TableMapping SQL column name %@ not fount %@ property name", column_name, property_name);
property_type = [propertyType objectAtIndex:index];
column_type = LKSQLTypeFromObjcType(property_type);
}
[self addDBPropertyWithType:type cname:column_name ctype:column_type pname:property_name ptype:property_type];
}
} else {
for (NSInteger i = 0; i < propertyNames.count; i++) {
type = LKSQL_Mapping_Inherit;
property_name = [propertyNames objectAtIndex:i];
column_name = property_name;
property_type = [propertyType objectAtIndex:i];
column_type = LKSQLTypeFromObjcType(property_type);
[self addDBPropertyWithType:type cname:column_name ctype:column_type pname:property_name ptype:property_type];
}
}
if (_primaryKeys.count == 0) {
_primaryKeys = [NSArray arrayWithObject:@"rowid"];
}
for (NSString *pkname in _primaryKeys) {
if ([pkname.lowercaseString isEqualToString:@"rowid"]) {
if ([self objectWithSqlColumnName:pkname] == nil) {
[self addDBPropertyWithType:LKSQL_Mapping_Inherit cname:pkname ctype:LKSQL_Type_Int pname:pkname ptype:@"int"];
}
}
}
}
return self;
}
- (void)addDBPropertyWithType:(NSString *)type cname:(NSString *)column_name ctype:(NSString *)ctype pname:(NSString *)pname ptype:(NSString *)ptype
{
LKDBProperty *db_property = [[LKDBProperty alloc] initWithType:type cname:column_name ctype:ctype pname:pname ptype:ptype];
if (db_property.propertyName) {
_proNameDic[db_property.propertyName] = db_property;
}
if (db_property.sqlColumnName) {
_sqlNameDic[db_property.sqlColumnName] = db_property;
}
}
- (NSArray *)primaryKeys
{
return _primaryKeys;
}
- (NSUInteger)count
{
return _sqlNameDic.count;
}
- (LKDBProperty *)objectWithIndex:(NSInteger)index
{
if (index < _sqlNameDic.count) {
id key = [_sqlNameDic.allKeys objectAtIndex:index];
return [_sqlNameDic objectForKey:key];
}
return nil;
}
- (LKDBProperty *)objectWithPropertyName:(NSString *)propertyName
{
return [_proNameDic objectForKey:propertyName];
}
- (LKDBProperty *)objectWithSqlColumnName:(NSString *)columnName
{
return [_sqlNameDic objectForKey:columnName];
}
- (void)updateProperty:(LKDBProperty *)property propertyName:(NSString *)propertyName
{
[_proNameDic removeObjectForKey:property.propertyName];
property.propertyName = propertyName;
_proNameDic[propertyName] = property;
}
- (void)updateProperty:(LKDBProperty *)property sqlColumnName:(NSString *)columnName
{
[_sqlNameDic removeObjectForKey:property.sqlColumnName];
property.sqlColumnName = columnName;
_sqlNameDic[columnName] = property;
}
- (void)removeWithColumnName:(NSString *)columnName
{
if ([LKDBUtils checkStringIsEmpty:columnName])
return;
LKDBProperty *property = [_sqlNameDic objectForKey:columnName];
if (property.propertyName) {
[_proNameDic removeObjectForKey:property.propertyName];
}
[_sqlNameDic removeObjectForKey:columnName];
}
@end
+292
View File
@@ -0,0 +1,292 @@
//
// LKDBHelper.h
// LJH
//
// Created by LJH on 12-12-6.
// Copyright (c) 2012年 LJH. All rights reserved.
//
#import "LKDB+Mapping.h"
#import "LKDBUtils.h"
#import "NSObject+LKDBHelper.h"
#import "NSObject+LKModel.h"
#import <FMDB/FMDB.h>
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LKDBHelper : NSObject
/**
* @brief Log error message, Default: NO
*/
+ (void)setLogError:(BOOL)logError;
/**
* @brief null is '' , Default: NO
*/
+ (void)setNullToEmpty:(BOOL)empty;
/**
* @brief filepath the use of : "documents/db/" + fileName + ".db"
* add to global cache with instance created
* refer: FMDatabase.h + (instancetype)databaseWithPath:(NSString *)inPath;
*/
- (instancetype)initWithDBName:(NSString *)dbname;
- (void)setDBName:(NSString *)fileName;
/**
* @brief path of database file
* refer: FMDatabase.h + (instancetype)databaseWithPath:(NSString *)inPath;
*/
- (instancetype)initWithDBPath:(NSString *)filePath;
- (void)setDBPath:(NSString *)filePath;
/**
* @brief closing a database connection and remove instance for global cache
*/
- (void)closeDB;
/**
* @brief 当数据库无操作 多少秒后 自动关闭数据库连接, 区间 [10 ~ int_max] 默认:20秒
*/
- (void)setAutoCloseDBTime:(NSInteger)time;
/**
* @brief current encryption key.
*/
@property (nullable, nonatomic, copy, readonly) NSString *encryptionKey;
/**
* @brief Set encryption key
refer: FMDatabase.h - (BOOL)setKey:(NSString *)key;
* invoking after the `LKDBHelper initialize` in YourModelClass.m `getUsingLKDBHelper` function
*/
- (BOOL)setKey:(NSString *)key;
/// Reset encryption key
- (BOOL)rekey:(NSString *)key;
/**
* @brief execute database operations synchronously,not afraid of recursive deadlock
同步执行数据库操作 可递归调用
*/
- (void)executeDB:(void (^)(FMDatabase *db))block;
- (BOOL)executeSQL:(NSString *)sql arguments:(nullable NSArray *)args;
- (nullable NSString *)executeScalarWithSQL:(NSString *)sql arguments:(nullable NSArray *)args;
/**
* @brief execute database operations synchronously in a transaction
block return the YES commit transaction returns the NO rollback transaction
同步执行数据库操作 在事务内部
block 返回 YES commit 事务 返回 NO rollback 事务
*/
- (void)executeForTransaction:(BOOL (^)(LKDBHelper *helper))block;
@end
@interface LKDBHelper (DatabaseManager)
///get table has created
- (BOOL)getTableCreatedWithClass:(Class)model;
- (BOOL)getTableCreatedWithTableName:(NSString *)tableName;
///drop all table
- (void)dropAllTable;
///drop table with entity class
- (BOOL)dropTableWithClass:(Class)modelClass;
- (BOOL)dropTableWithTableName:(NSString *)tableName;
@end
@interface LKDBHelper (DatabaseExecute)
/**
* @brief The number of rows query table
*
* @param modelClass entity class
* @param where can use NSString or NSDictionary or nil
*
* @return rows number
*/
- (NSInteger)rowCount:(Class)modelClass where:(nullable id)where;
- (void)rowCount:(Class)modelClass where:(nullable id)where callback:(void (^)(NSInteger rowCount))callback;
- (NSInteger)rowCountWithTableName:(NSString *)tableName where:(nullable id)where;
/**
* @brief query table
*
* @param params query condition
*/
- (nullable NSMutableArray *)searchWithParams:(LKDBQueryParams *)params;
/**
* @brief query table
*
* @param modelClass entity class
* @param where can use NSString or NSDictionary or nil
* @param orderBy The Sort: Ascending "name asc",Descending "name desc"
For example: @"rowid desc"x or @"rowid asc"
* @param offset Skip how many rows
* @param count Limit the number
*
* @return query finished result is an array(model instance collection)
*/
- (nullable NSMutableArray *)search:(Class)modelClass
where:(nullable id)where
orderBy:(nullable NSString *)orderBy
offset:(NSInteger)offset
count:(NSInteger)count;
/**
* query sql, query finished result is an array(model instance collection)
* you can use the "@t" replace Model TableName
* query sql use lowercase string
* 查询的sql语句 请使用小写 ,否则会不能自动获取 rowid
* example:
NSMutableArray *array = [[LKDBHelper getUsingLKDBHelper] searchWithSQL:@"select * from @t where blah blah.." toClass:[ModelClass class]];
*
*/
- (nullable NSMutableArray *)searchWithSQL:(NSString *)sql toClass:(nullable Class)modelClass;
/**
* @brief don't do any operations of the sql
*/
- (nullable NSMutableArray *)searchWithRAWSQL:(NSString *)sql toClass:(nullable Class)modelClass;
/**
* query sql, query finished result is an array(model instance collection)
* you can use the "@t" replace Model TableName and replace all ? placeholders with the va_list
* example:
NSMutableArray *array = [[LKDBHelper getUsingLKDBHelper] searc:[ModelClass class] withSQL:@"select rowid from name_table where name = ?", @"Swift"];
*
*/
- (nullable NSMutableArray *)search:(Class)modelClass withSQL:(NSString *)sql, ...;
/**
columns may NSArray or NSString if query column count == 1 return single column string array
other return models entity array
*/
- (nullable NSMutableArray *)search:(Class)modelClass
column:(nullable id)columns
where:(nullable id)where
orderBy:(nullable NSString *)orderBy
offset:(NSInteger)offset
count:(NSInteger)count;
/**
* @brief async search
*/
- (void)search:(Class)modelClass
where:(nullable id)where
orderBy:(nullable NSString *)orderBy
offset:(NSInteger)offset
count:(NSInteger)count
callback:(void (^)(NSMutableArray *_Nullable array))block;
///return first model or nil
- (nullable id)searchSingle:(Class)modelClass where:(nullable id)where orderBy:(nullable NSString *)orderBy;
/**
* @brief insert table
*
* @param model you want to insert the entity
*
* @return the inserted was successful
*/
- (BOOL)insertToDB:(NSObject *)model;
- (void)insertToDB:(NSObject *)model callback:(void (^)(BOOL result))block;
/**
* @brief insert when the entity primary key does not exist
*
* @param model you want to insert the entity
*
* @return the inserted was successful
*/
- (BOOL)insertWhenNotExists:(NSObject *)model;
- (void)insertWhenNotExists:(NSObject *)model callback:(void (^)(BOOL result))block;
/**
* @brief update table
*
* @param model you want to update the entity
* @param where can use NSString or NSDictionary or nil
when "where" is nil : update the value based on rowid column or primary key column
*
* @return the updated was successful
*/
- (BOOL)updateToDB:(NSObject *)model where:(nullable id)where;
- (void)updateToDB:(NSObject *)model where:(nullable id)where callback:(void (^)(BOOL result))block;
- (BOOL)updateToDB:(Class)modelClass set:(NSString *)sets where:(nullable id)where;
- (BOOL)updateToDBWithTableName:(NSString *)tableName set:(NSString *)sets where:(nullable id)where;
/**
* @brief delete table
*
* @param model you want to delete entity
when entity property "rowid" == 0 based on the primary key to delete
*
* @return the deleted was successful
*/
- (BOOL)deleteToDB:(NSObject *)model;
- (void)deleteToDB:(NSObject *)model callback:(void (^)(BOOL result))block;
/**
* @brief delete table with "where" constraint
*
* @param modelClass entity class
* @param where can use NSString or NSDictionary, can not is nil
*
* @return the deleted was successful
*/
- (BOOL)deleteWithClass:(Class)modelClass where:(nullable id)where;
- (void)deleteWithClass:(Class)modelClass where:(nullable id)where callback:(void (^)(BOOL result))block;
- (BOOL)deleteWithTableName:(NSString *)tableName where:(nullable id)where;
/**
* @brief entity exists?
* for primary key column
if rowid > 0 would certainly exist so we do not rowid judgment
* @param model entity
*
* @return YES: entity presence , NO: entity not exist
*/
- (BOOL)isExistsModel:(NSObject *)model;
- (BOOL)isExistsClass:(Class)modelClass where:(nullable id)where;
- (BOOL)isExistsWithTableName:(NSString *)tableName where:(nullable id)where;
/**
* @brief Clear data based on the entity class
*
* @param modelClass entity class
*/
+ (void)clearTableData:(Class)modelClass;
/**
* @brief Clear Unused Data File
if you property has UIImage or NSData, will save their data in the (documents dir)
*
* @param modelClass entity class
* @param columns UIImage or NSData Column Name
*/
+ (void)clearNoneImage:(Class)modelClass columns:(NSArray<NSString *> *)columns;
+ (void)clearNoneData:(Class)modelClass columns:(NSArray<NSString *> *)columns;
@end
@interface LKDBHelper (Deprecated_Nonfunctional)
/// you can use [LKDBHelper getUsingLKDBHelper]
#pragma mark - deprecated
+ (LKDBHelper *)sharedDBHelper __deprecated_msg("Method deprecated. Use `[Model getUsingLKDBHelper]`");
- (BOOL)createTableWithModelClass:(Class)modelClass __deprecated_msg("Now you can not call it. Will automatically determine whether you need to create");
- (void)setEncryptionKey:(NSString *)encryptionKey __deprecated_msg("Method deprecated. Use `setKey: OR resetKey:` invoking after the `LKDBHelper initialize` in YourModelClass.m `getUsingLKDBHelper` function");
#pragma mark -
@end
NS_ASSUME_NONNULL_END
File diff suppressed because it is too large Load Diff
+117
View File
@@ -0,0 +1,117 @@
//
// NSObject+LKUtils.h
// LKDBHelper
//
// Created by LJH on 13-4-15.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LKDBUtils : NSObject
// 创建文件路径所需要的文件夹
+ (BOOL)createDirectoryWithFilePath:(NSString *)filePath;
///返回根目录路径 "document"
+ (NSString *)getDocumentPath;
///返回 "document/dir/" 文件夹路径
+ (NSString *)getDirectoryForDocuments:(NSString *)dir;
///返回 "document/filename" 路径
+ (NSString *)getPathForDocuments:(NSString *)filename;
///返回 "document/dir/filename" 路径
+ (NSString *)getPathForDocuments:(NSString *)filename inDir:(NSString *)dir;
///文件是否存在
+ (BOOL)isFileExists:(NSString *)filepath;
///删除文件
+ (BOOL)deleteWithFilepath:(NSString *)filepath;
///返回该文件目录下 所有文件名
+ (nullable NSArray *)getFilenamesWithDir:(NSString *)dir;
///检测字符串是否为空
+ (BOOL)checkStringIsEmpty:(NSString *)string;
+ (nullable NSString *)getTrimStringWithString:(nullable NSString *)string;
///把Date 转换成String
+ (NSString *)stringWithDate:(NSDate *)date;
///把String 转换成Date
+ (NSDate *)dateWithString:(NSString *)str;
///单例formatter
+ (NSNumberFormatter *)numberFormatter;
@end
#ifdef DEBUG
#ifdef NSLog
#define LKErrorLog(fmt, ...) NSLog(@"#LKDBHelper ERROR:\n" fmt, ##__VA_ARGS__);
#else
#define LKErrorLog(fmt, ...) NSLog(@"\n#LKDBHelper ERROR: %s [Line %d] \n" fmt, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#endif
#else
#define LKErrorLog(...)
#endif
static NSString *const LKSQL_Type_Text = @"text";
static NSString *const LKSQL_Type_Int = @"integer";
static NSString *const LKSQL_Type_Double = @"double";
static NSString *const LKSQL_Type_Blob = @"blob";
static NSString *const LKSQL_Attribute_NotNull = @"NOT NULL";
static NSString *const LKSQL_Attribute_PrimaryKey = @"PRIMARY KEY";
static NSString *const LKSQL_Attribute_Default = @"DEFAULT";
static NSString *const LKSQL_Attribute_Unique = @"UNIQUE";
static NSString *const LKSQL_Attribute_Check = @"CHECK";
static NSString *const LKSQL_Attribute_ForeignKey = @"FOREIGN KEY";
static NSString *const LKSQL_Convert_FloatType = @"float_double_decimal";
static NSString *const LKSQL_Convert_IntType = @"int_char_short_long";
static NSString *const LKSQL_Convert_BlobType = @"";
static NSString *const LKSQL_Mapping_Inherit = @"LKDBInherit";
static NSString *const LKSQL_Mapping_Binding = @"LKDBBinding";
static NSString *const LKSQL_Mapping_UserCalculate = @"LKDBUserCalculate";
static NSString *const LKDB_TypeKey = @"DB_Type";
static NSString *const LKDB_TypeKey_Model = @"DB_Type_Model";
static NSString *const LKDB_TypeKey_JSON = @"DB_Type_JSON";
static NSString *const LKDB_TypeKey_Combo = @"DB_Type_Combo";
static NSString *const LKDB_TypeKey_Date = @"DB_Type_Date";
static NSString *const LKDB_ValueKey = @"DB_Value";
static NSString *const LKDB_TableNameKey = @"DB_TableName";
static NSString *const LKDB_ClassKey = @"DB_Class";
static NSString *const LKDB_RowIdKey = @"DB_RowId";
static NSString *const LKDB_PValueKey = @"DB_PKeyValue";
///Object-c type converted to SQLite type 把Object-c 类型 转换为sqlite 类型
extern NSString *LKSQLTypeFromObjcType(NSString *objcType);
@interface LKDBQueryParams : NSObject
///columns or array
@property (nullable, nonatomic, copy) NSString *columns;
@property (nullable, nonatomic, copy) NSArray *columnArray;
@property (nullable, nonatomic, copy) NSString *tableName;
///where or dic
@property (nullable, nonatomic, copy) NSString *where;
@property (nullable, nonatomic, copy) NSDictionary *whereDic;
@property (nullable, nonatomic, copy) NSString *groupBy;
@property (nullable, nonatomic, copy) NSString *orderBy;
@property (nonatomic, assign) NSInteger offset;
@property (nonatomic, assign) NSInteger count;
@property (nullable, nonatomic, assign) Class toClass;
@property (nullable, nonatomic, copy) void (^callback)(NSMutableArray *_Nullable results);
@end
NS_ASSUME_NONNULL_END
+241
View File
@@ -0,0 +1,241 @@
//
// NSObject+LKUtils.m
// LKDBHelper
//
// Created by LJH on 13-4-15.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import "LKDBUtils.h"
@interface LKDateFormatter : NSDateFormatter
@property (nonatomic, strong) NSRecursiveLock *lock;
@end
@implementation LKDateFormatter
- (id)init
{
self = [super init];
if (self) {
self.lock = [[NSRecursiveLock alloc] init];
self.generatesCalendarDates = YES;
self.dateStyle = NSDateFormatterNoStyle;
self.timeStyle = NSDateFormatterNoStyle;
self.AMSymbol = nil;
self.PMSymbol = nil;
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
if (locale) {
[self setLocale:locale];
}
}
return self;
}
//防止在IOS5下 多线程 格式化时间时 崩溃
- (NSDate *)dateFromString:(NSString *)string
{
[_lock lock];
NSDate *date = [super dateFromString:string];
[_lock unlock];
return date;
}
- (NSString *)stringFromDate:(NSDate *)date
{
[_lock lock];
NSString *string = [super stringFromDate:date];
[_lock unlock];
return string;
}
@end
@interface LKNumberFormatter : NSNumberFormatter
@end
@implementation LKNumberFormatter
- (NSString *)stringFromNumber:(NSNumber *)number
{
NSString *string = [number stringValue];
if (!string) {
string = [NSString stringWithFormat:@"%lf", [number doubleValue]];
}
return string;
}
- (NSNumber *)numberFromString:(NSString *)string
{
NSNumber *number = [super numberFromString:string];
if (!number) {
number = @(string.doubleValue);
}
return number;
}
@end
@implementation LKDBUtils
+ (BOOL)createDirectoryWithFilePath:(NSString *)filePath
{
NSString *dirPath = filePath.stringByDeletingLastPathComponent;
if (!dirPath) {
return NO;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir = NO;
BOOL isCreated = [fileManager fileExistsAtPath:dirPath isDirectory:&isDir];
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
NSDictionary *attributes = @{NSFileProtectionKey: NSFileProtectionNone};
#else
NSDictionary *attributes = nil;
#endif
if (!isCreated || !isDir) {
NSError *error = nil;
BOOL success = [fileManager createDirectoryAtPath:dirPath
withIntermediateDirectories:YES
attributes:attributes
error:&error];
if (!success) {
LKErrorLog(@"create dir error: %@", error.debugDescription);
/// 下个主线程继续尝试次
dispatch_async(dispatch_get_main_queue(), ^{
[fileManager createDirectoryAtPath:dirPath
withIntermediateDirectories:YES
attributes:attributes
error:nil];
});
}
return success;
} else {
/**
* @brief Disk I/O error when device is locked
* https://github.com/ccgus/fmdb/issues/262
*/
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
[fileManager setAttributes:attributes
ofItemAtPath:dirPath
error:nil];
#endif
return YES;
}
}
+ (NSString *)getDocumentPath
{
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return documentsDirectory;
#else
NSString *homePath = [[NSBundle mainBundle] resourcePath];
return homePath;
#endif
}
+ (NSString *)getDirectoryForDocuments:(NSString *)dir
{
NSString *dirPath = [[self getDocumentPath] stringByAppendingPathComponent:dir];
BOOL isDir = NO;
BOOL isCreated = [[NSFileManager defaultManager] fileExistsAtPath:dirPath isDirectory:&isDir];
if (isCreated == NO || isDir == NO) {
NSError *error = nil;
BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:&error];
if (success == NO)
NSLog(@"create dir error: %@", error.debugDescription);
}
return dirPath;
}
+ (NSString *)getPathForDocuments:(NSString *)filename
{
return [[self getDocumentPath] stringByAppendingPathComponent:filename];
}
+ (NSString *)getPathForDocuments:(NSString *)filename inDir:(NSString *)dir
{
return [[self getDirectoryForDocuments:dir] stringByAppendingPathComponent:filename];
}
+ (BOOL)isFileExists:(NSString *)filepath
{
return [[NSFileManager defaultManager] fileExistsAtPath:filepath];
}
+ (BOOL)deleteWithFilepath:(NSString *)filepath
{
return [[NSFileManager defaultManager] removeItemAtPath:filepath error:nil];
}
+ (NSArray *)getFilenamesWithDir:(NSString *)dir
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *fileList = [fileManager contentsOfDirectoryAtPath:dir error:nil];
return fileList;
}
+ (BOOL)checkStringIsEmpty:(NSString *)string
{
if (string == nil) {
return YES;
}
if ([string isKindOfClass:[NSString class]] == NO) {
return YES;
}
if (string.length == 0) {
return YES;
}
return [[self getTrimStringWithString:string] isEqualToString:@""];
}
+ (NSString *)getTrimStringWithString:(NSString *)string
{
return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
+ (NSDateFormatter *)getDBDateFormat
{
static NSDateFormatter *format;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
format = [[LKDateFormatter alloc] init];
format.dateFormat = @"yyyy-MM-dd HH:mm:ss";
});
return format;
}
+ (NSString *)stringWithDate:(NSDate *)date
{
NSDateFormatter *formatter = [self getDBDateFormat];
NSString *datestr = [formatter stringFromDate:date];
if (datestr.length > 19) {
datestr = [datestr substringToIndex:19];
}
return datestr;
}
+ (NSDate *)dateWithString:(NSString *)str
{
NSDateFormatter *formatter = [self getDBDateFormat];
NSDate *date = [formatter dateFromString:str];
return date;
}
+ (NSNumberFormatter *)numberFormatter
{
static NSNumberFormatter *numberFormatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
numberFormatter = [[LKNumberFormatter alloc] init];
});
return numberFormatter;
}
@end
inline NSString *LKSQLTypeFromObjcType(NSString *objcType)
{
if ([LKSQL_Convert_IntType rangeOfString:objcType].length > 0) {
return LKSQL_Type_Int;
}
if ([LKSQL_Convert_FloatType rangeOfString:objcType].length > 0) {
return LKSQL_Type_Double;
}
if ([LKSQL_Convert_BlobType rangeOfString:objcType].length > 0) {
return LKSQL_Type_Blob;
}
return LKSQL_Type_Text;
}
@implementation LKDBQueryParams
@end
+110
View File
@@ -0,0 +1,110 @@
//
// NSObject+LKDBHelper.h
// LKDBHelper
//
// Created by LJH on 13-6-8.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import "LKDBHelper.h"
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class LKDBHelper;
@interface NSObject (LKDBHelper_Delegate)
+ (void)dbDidCreateTable:(LKDBHelper *)helper tableName:(NSString *)tableName;
+ (void)dbDidAlterTable:(LKDBHelper *)helper tableName:(NSString *)tableName addColumns:(NSArray *)columns;
+ (BOOL)dbWillInsert:(NSObject *)entity;
+ (void)dbDidInserted:(NSObject *)entity result:(BOOL)result;
+ (BOOL)dbWillUpdate:(NSObject *)entity;
+ (void)dbDidUpdated:(NSObject *)entity result:(BOOL)result;
+ (BOOL)dbWillDelete:(NSObject *)entity;
+ (void)dbDidDeleted:(NSObject *)entity result:(BOOL)result;
///data read finish
+ (void)dbDidSeleted:(NSObject *)entity;
@end
//only simplify synchronous function
@interface NSObject (LKDBHelper_Execute)
/**
* 返回行数
*
* @param where type can NSDictionary or NSString
*
* @return row count
*/
+ (NSInteger)rowCountWithWhere:(nullable id)where, ...;
+ (NSInteger)rowCountWithWhereFormat:(nullable id)where, ...;
/**
* 搜索
*
* @param columns type can NSArray or NSString(Search for a specific column. Search only one, only to return the contents of the column collection)
* @param where where type can NSDictionary or NSString
* @param orderBy
* @param offset
* @param count
*
* @return model collection or contents of the columns collection
*/
+ (nullable NSMutableArray *)searchColumn:(nullable id)columns
where:(nullable id)where
orderBy:(nullable NSString *)orderBy
offset:(NSInteger)offset
count:(NSInteger)count;
+ (nullable NSMutableArray *)searchWithWhere:(nullable id)where
orderBy:(nullable NSString *)orderBy
offset:(NSInteger)offset
count:(NSInteger)count;
+ (nullable NSMutableArray *)searchWithWhere:(nullable id)where;
+ (nullable NSMutableArray *)searchWithSQL:(NSString *)sql;
+ (nullable id)searchSingleWithWhere:(nullable id)where
orderBy:(nullable NSString *)orderBy;
+ (BOOL)insertToDB:(NSObject *)model;
+ (BOOL)insertWhenNotExists:(NSObject *)model;
+ (BOOL)updateToDB:(NSObject *)model
where:(nullable id)where, ...;
+ (BOOL)updateToDBWithSet:(NSString *)sets
where:(nullable id)where, ...;
+ (BOOL)deleteToDB:(NSObject *)model;
+ (BOOL)deleteWithWhere:(nullable id)where, ...;
+ (BOOL)isExistsWithModel:(NSObject *)model;
- (BOOL)updateToDB;
- (BOOL)saveToDB;
- (BOOL)deleteToDB;
- (BOOL)isExistsFromDB;
///异步插入数据 async insert array completed 也是在子线程直接回调的
+ (void)insertArrayByAsyncToDB:(NSArray *)models;
+ (void)insertArrayByAsyncToDB:(NSArray *)models completed:(void (^_Nullable)(BOOL allInserted))completedBlock;
///begin translate for insert models 开始事务插入数组
+ (void)insertToDBWithArray:(NSArray *)models
filter:(void (^_Nullable)(id model, BOOL inserted, BOOL *_Nullable rollback))filter;
+ (void)insertToDBWithArray:(NSArray *)models
filter:(void (^_Nullable)(id model, BOOL inserted, BOOL *_Nullable rollback))filter
completed:(void (^_Nullable)(BOOL allInserted))completedBlock;
@end
NS_ASSUME_NONNULL_END
+234
View File
@@ -0,0 +1,234 @@
//
// NSObject+LKDBHelper.m
// LKDBHelper
//
// Created by LJH on 13-6-8.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import "NSObject+LKDBHelper.h"
@implementation NSObject (LKDBHelper_Delegate)
+ (void)dbDidCreateTable:(LKDBHelper *)helper tableName:(NSString *)tableName {}
+ (void)dbDidAlterTable:(LKDBHelper *)helper tableName:(NSString *)tableName addColumns:(NSArray *)columns {}
+ (void)dbDidInserted:(NSObject *)entity result:(BOOL)result {}
+ (void)dbDidDeleted:(NSObject *)entity result:(BOOL)result {}
+ (void)dbDidUpdated:(NSObject *)entity result:(BOOL)result {}
+ (void)dbDidSeleted:(NSObject *)entity {}
+ (BOOL)dbWillDelete:(NSObject *)entity
{
return YES;
}
+ (BOOL)dbWillInsert:(NSObject *)entity
{
return YES;
}
+ (BOOL)dbWillUpdate:(NSObject *)entity
{
return YES;
}
@end
@implementation NSObject (LKDBHelper)
#pragma mark - simplify synchronous function
+ (BOOL)checkModelClass:(NSObject *)model
{
if ([model isMemberOfClass:self])
return YES;
NSLog(@"%@ can not use %@", NSStringFromClass(self), NSStringFromClass(model.class));
return NO;
}
+ (NSInteger)rowCountWithWhereFormat:(id)where, ...
{
if ([where isKindOfClass:[NSString class]]) {
va_list list;
va_start(list, where);
where = [[NSString alloc] initWithFormat:where arguments:list];
va_end(list);
}
return [[self getUsingLKDBHelper] rowCount:self where:where];
}
+ (NSInteger)rowCountWithWhere:(id)where, ...
{
if ([where isKindOfClass:[NSString class]]) {
va_list list;
va_start(list, where);
where = [[NSString alloc] initWithFormat:where arguments:list];
va_end(list);
}
return [[self getUsingLKDBHelper] rowCount:self where:where];
}
+ (NSMutableArray *)searchColumn:(id)columns where:(id)where orderBy:(NSString *)orderBy offset:(NSInteger)offset count:(NSInteger)count
{
return [[self getUsingLKDBHelper] search:self column:columns where:where orderBy:orderBy offset:offset count:count];
}
+ (NSMutableArray *)searchWithWhere:(id)where orderBy:(NSString *)orderBy offset:(NSInteger)offset count:(NSInteger)count
{
return [[self getUsingLKDBHelper] search:self where:where orderBy:orderBy offset:offset count:count];
}
+ (NSMutableArray *)searchWithWhere:(id)where
{
return [[self getUsingLKDBHelper] search:self where:where orderBy:nil offset:0 count:0];
}
+ (NSMutableArray *)searchWithSQL:(NSString *)sql
{
return [[self getUsingLKDBHelper] searchWithSQL:sql toClass:self];
}
+ (id)searchSingleWithWhere:(id)where orderBy:(NSString *)orderBy
{
return [[self getUsingLKDBHelper] searchSingle:self where:where orderBy:orderBy];
}
+ (BOOL)insertToDB:(NSObject *)model
{
if ([self checkModelClass:model]) {
return [[self getUsingLKDBHelper] insertToDB:model];
}
return NO;
}
+ (BOOL)insertWhenNotExists:(NSObject *)model
{
if ([self checkModelClass:model]) {
return [[self getUsingLKDBHelper] insertWhenNotExists:model];
}
return NO;
}
+ (BOOL)updateToDB:(NSObject *)model where:(id)where, ...
{
if ([self checkModelClass:model]) {
if ([where isKindOfClass:[NSString class]]) {
va_list list;
va_start(list, where);
where = [[NSString alloc] initWithFormat:where arguments:list];
va_end(list);
}
return [[self getUsingLKDBHelper] updateToDB:model where:where];
}
return NO;
}
+ (BOOL)updateToDBWithSet:(NSString *)sets where:(id)where, ...
{
if ([where isKindOfClass:[NSString class]]) {
va_list list;
va_start(list, where);
where = [[NSString alloc] initWithFormat:where arguments:list];
va_end(list);
}
return [[self getUsingLKDBHelper] updateToDB:self set:sets where:where];
}
+ (BOOL)deleteToDB:(NSObject *)model
{
if ([self checkModelClass:model]) {
return [[self getUsingLKDBHelper] deleteToDB:model];
}
return NO;
}
+ (BOOL)deleteWithWhere:(id)where, ...
{
if ([where isKindOfClass:[NSString class]]) {
va_list list;
va_start(list, where);
where = [[NSString alloc] initWithFormat:where arguments:list];
va_end(list);
}
return [[self getUsingLKDBHelper] deleteWithClass:self where:where];
}
+ (BOOL)isExistsWithModel:(NSObject *)model
{
if ([self checkModelClass:model]) {
return [[self getUsingLKDBHelper] isExistsModel:model];
}
return NO;
}
- (BOOL)updateToDB
{
if (self.rowid > 0) {
return [self.class updateToDB:self where:nil];
} else {
return [self saveToDB];
}
}
- (BOOL)saveToDB
{
return [self.class insertToDB:self];
}
- (BOOL)deleteToDB
{
return [self.class deleteToDB:self];
}
- (BOOL)isExistsFromDB
{
return [self.class isExistsWithModel:self];
}
+ (void)insertArrayByAsyncToDB:(NSArray *)models
{
[self insertArrayByAsyncToDB:models completed:nil];
}
+ (void)insertArrayByAsyncToDB:(NSArray *)models completed:(void (^_Nullable)(BOOL))completedBlock
{
if (models.count > 0) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self insertToDBWithArray:models filter:nil completed:completedBlock];
});
}
}
+ (void)insertToDBWithArray:(NSArray *)models filter:(void (^)(id model, BOOL inserted, BOOL *rollback))filter
{
[self insertToDBWithArray:models filter:filter completed:nil];
}
+ (void)insertToDBWithArray:(NSArray *)models filter:(void (^)(id model, BOOL inserted, BOOL *rollback))filter completed:(void (^)(BOOL))completedBlock
{
__block BOOL allInserted = YES;
[[self getUsingLKDBHelper] executeForTransaction:^BOOL(LKDBHelper *helper) {
BOOL isRollback = NO;
for (int i = 0; i < models.count; i++) {
id obj = [models objectAtIndex:i];
BOOL inserted = [helper insertToDB:obj];
allInserted &= inserted;
if (filter) {
filter(obj, inserted, &isRollback);
}
if (isRollback) {
allInserted = NO;
break;
}
}
return (isRollback == NO);
}];
if (completedBlock) {
completedBlock(allInserted);
}
}
@end
+146
View File
@@ -0,0 +1,146 @@
//
// NSObject+LKModel.h
// LKDBHelper
//
// Created by LJH on 13-4-15.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class LKDBProperty;
@class LKModelInfos;
@class LKDBHelper;
#pragma mark - 表结构
@interface NSObject (LKTabelStructure)
/**
* overwrite in your models(option)
*
* @return # table name #
*/
+ (NSString *)getTableName;
/**
* if you set it will use it as a table name
*/
@property (nullable, nonatomic, copy) NSString *db_tableName;
/**
* the model is inserting ..
*/
@property (nonatomic, readonly) BOOL db_inserting;
/**
* sqlite comes with rowid
*/
@property (nonatomic, assign) NSInteger rowid;
/**
* overwrite in your models, if your table has primary key
* 主键列名 如果rowid<0 则跟据此名称update 和delete
* @return # column name #
*/
+ (nullable NSString *)getPrimaryKey;
/**
* multi primary key
* 联合主键
* @return
*/
+ (nullable NSArray *)getPrimaryKeyUnionArray;
/**
* overwrite in your models set column attribute
*
* @param property infos
*/
+ (void)columnAttributeWithProperty:(LKDBProperty *)property;
/**
* @brief get saved pictures and data file path,can overwirte
获取保存的 图片和数据的文件路径
*/
+ (NSString *)getDBImagePathWithName:(NSString *)filename;
+ (NSString *)getDBDataPathWithName:(NSString *)filename;
@end
#pragma mark - 表数据操作
@interface NSObject (LKTableData)
/***
* @brief overwrite in your models,return insert sqlite table data
*
*
* @return property the data after conversion
*/
- (nullable id)userGetValueForModel:(LKDBProperty *)property;
/***
* @brief overwrite in your models,return insert sqlite table data
*
* @param property will set property
* @param value sqlite value (NSString(NSData UTF8 Coding) or NSData)
*/
- (void)userSetValueForModel:(LKDBProperty *)property value:(nullable id)value;
///overwrite
+ (NSDateFormatter *)getModelDateFormatter;
//lkdbhelper use
- (nullable id)modelGetValue:(LKDBProperty *)property;
- (void)modelSetValue:(LKDBProperty *)property value:(nullable NSString *)value;
- (nullable id)singlePrimaryKeyValue;
- (BOOL)singlePrimaryKeyValueIsEmpty;
- (nullable LKDBProperty *)singlePrimaryKeyProperty;
+ (nullable NSString *)db_rowidAliasName;
@end
@interface NSObject (LKModel)
/**
* return model use LKDBHelper , default return global LKDBHelper;
*
* @return LKDBHelper
*/
+ (LKDBHelper *)getUsingLKDBHelper;
/**
* class attributes
*
* @return LKModelInfos
*/
+ (LKModelInfos *)getModelInfos;
/**
* @brief Containing the super class attributes 设置是否包含 父类 的属性
*/
+ (BOOL)isContainParent;
/**
* 当前表中的列是否包含自身的属性。
*
* @return BOOL
*/
+ (BOOL)isContainSelf;
/**
* @brief log all property 打印所有的属性名称和数据
*/
- (NSString *)printAllPropertys;
- (NSString *)printAllPropertysIsContainParent:(BOOL)containParent;
- (NSMutableString *)getAllPropertysString;
@end
NS_ASSUME_NONNULL_END
+922
View File
@@ -0,0 +1,922 @@
//
// NSObject+LKModel.m
// LKDBHelper
//
// Created by LJH on 13-4-15.
// Copyright (c) 2013年 ljh. All rights reserved.
//
#import "LKDBHelper.h"
#import "NSObject+LKModel.h"
#import <objc/runtime.h>
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#import <UIKit/UIKit.h>
#define LKDBImage UIImage
#define LKDBColor UIColor
#else
#import <AppKit/AppKit.h>
#define LKDBImage NSImage
#define LKDBColor NSColor
#endif
static char LKModelBase_Key_RowID;
static char LKModelBase_Key_TableName;
static char LKModelBase_Key_Inserting;
@interface LKDBHelper (LKDBHelper_LKModel)
+ (BOOL)nullIsEmpty;
@end
@implementation NSObject (LKModel)
+ (LKDBHelper *)getUsingLKDBHelper
{
///ios8 能获取系统类的属性了 所以没有办法判断属性数量来区分自定义类和系统类
///可能系统类的存取会不正确
static LKDBHelper *helper;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
helper = [[LKDBHelper alloc] init];
});
return helper;
}
#pragma mark Tabel Structure Function 表结构
+ (NSString *)getTableName
{
return NSStringFromClass(self);
}
+ (NSString *)getPrimaryKey
{
return @"rowid";
}
+ (NSArray *)getPrimaryKeyUnionArray
{
return nil;
}
+ (void)columnAttributeWithProperty:(LKDBProperty *)property
{
//overwrite
}
#pragma 属性
- (void)setRowid:(NSInteger)rowid
{
objc_setAssociatedObject(self, &LKModelBase_Key_RowID, [NSNumber numberWithInteger:rowid], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSInteger)rowid
{
return [objc_getAssociatedObject(self, &LKModelBase_Key_RowID) integerValue];
}
- (void)setDb_tableName:(NSString *)db_tableName
{
objc_setAssociatedObject(self, &LKModelBase_Key_TableName, db_tableName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)db_tableName
{
NSString *tableName = objc_getAssociatedObject(self, &LKModelBase_Key_TableName);
if (tableName.length == 0) {
tableName = [self.class getTableName];
}
return tableName;
}
- (BOOL)db_inserting
{
return [objc_getAssociatedObject(self, &LKModelBase_Key_Inserting) boolValue];
}
- (void)setDb_inserting:(BOOL)db_inserting
{
NSNumber *number = nil;
if (db_inserting) {
number = [NSNumber numberWithBool:YES];
}
objc_setAssociatedObject(self, &LKModelBase_Key_Inserting, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma 无关紧要的
+ (NSString *)getDBImagePathWithName:(NSString *)filename
{
NSString *dir = [NSString stringWithFormat:@"dbimg/%@", NSStringFromClass(self)];
return [LKDBUtils getPathForDocuments:filename inDir:dir];
}
+ (NSString *)getDBDataPathWithName:(NSString *)filename
{
NSString *dir = [NSString stringWithFormat:@"dbdata/%@", NSStringFromClass(self)];
return [LKDBUtils getPathForDocuments:filename inDir:dir];
}
+ (NSDictionary *)getTableMapping
{
return nil;
}
#pragma mark - Table Data Function 表数据
+ (NSDateFormatter *)getModelDateFormatter
{
return nil;
}
///get
- (id)modelGetValue:(LKDBProperty *)property
{
id value = [self valueForKey:property.propertyName];
id returnValue = value;
if (value == nil) {
return nil;
} else if ([value isKindOfClass:[NSString class]]) {
returnValue = [value copy];
} else if ([value isKindOfClass:[NSNumber class]]) {
returnValue = [[LKDBUtils numberFormatter] stringFromNumber:value];
} else if ([value isKindOfClass:[NSDate class]]) {
NSDateFormatter *formatter = [self.class getModelDateFormatter];
if (formatter) {
returnValue = [formatter stringFromDate:value];
} else {
returnValue = [LKDBUtils stringWithDate:value];
}
returnValue = [returnValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
} else if ([value isKindOfClass:[LKDBColor class]]) {
LKDBColor *color = value;
CGFloat r, g, b, a;
[color getRed:&r green:&g blue:&b alpha:&a];
returnValue = [NSString stringWithFormat:@"%.3f,%.3f,%.3f,%.3f", r, g, b, a];
} else if ([value isKindOfClass:[NSValue class]]) {
NSString *columnType = property.propertyType;
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
if ([columnType isEqualToString:@"CGRect"]) {
returnValue = NSStringFromCGRect([value CGRectValue]);
} else if ([columnType isEqualToString:@"CGPoint"]) {
returnValue = NSStringFromCGPoint([value CGPointValue]);
} else if ([columnType isEqualToString:@"CGSize"]) {
returnValue = NSStringFromCGSize([value CGSizeValue]);
} else if ([columnType isEqualToString:@"_NSRange"]) {
returnValue = NSStringFromRange([value rangeValue]);
}
#else
if ([columnType hasSuffix:@"Rect"]) {
returnValue = NSStringFromRect([value rectValue]);
} else if ([columnType hasSuffix:@"Point"]) {
returnValue = NSStringFromPoint([value pointValue]);
} else if ([columnType hasSuffix:@"Size"]) {
returnValue = NSStringFromSize([value sizeValue]);
} else if ([columnType hasSuffix:@"Range"]) {
returnValue = NSStringFromRange([value rangeValue]);
}
#endif
} else if ([value isKindOfClass:[LKDBImage class]]) {
long random = arc4random();
long date = [[NSDate date] timeIntervalSince1970];
NSString *filename = [NSString stringWithFormat:@"img%ld%ld", date & 0xFFFFF, random & 0xFFF];
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
NSData *datas = UIImageJPEGRepresentation(value, 1);
#else
[value lockFocus];
NSBitmapImageRep *srcImageRep = [NSBitmapImageRep imageRepWithData:[value TIFFRepresentation]];
NSData *datas = [srcImageRep representationUsingType:NSJPEGFileType properties:@{}];
[value unlockFocus];
#endif
[datas writeToFile:[self.class getDBImagePathWithName:filename]
atomically:YES];
returnValue = filename;
} else if ([value isKindOfClass:[NSData class]]) {
long random = arc4random();
long date = [[NSDate date] timeIntervalSince1970];
NSString *filename = [NSString stringWithFormat:@"data%ld%ld", date & 0xFFFFF, random & 0xFFF];
[value writeToFile:[self.class getDBDataPathWithName:filename] atomically:YES];
returnValue = filename;
} else if ([value isKindOfClass:[NSURL class]]) {
returnValue = [value absoluteString];
} else {
if ([value isKindOfClass:[NSArray class]]) {
returnValue = [self db_jsonObjectFromArray:value];
} else if ([value isKindOfClass:[NSDictionary class]]) {
returnValue = [self db_jsonObjectFromDictionary:value];
} else {
returnValue = [self db_jsonObjectFromModel:value];
}
returnValue = [self db_jsonStringFromObject:returnValue];
}
return returnValue;
}
///set
- (void)modelSetValue:(LKDBProperty *)property value:(NSString *)value
{
///参试获取属性的Class
Class columnClass = NSClassFromString(property.propertyType);
id modelValue = nil;
if (columnClass == nil) {
///当找不到 class 时,就是 基础类型 int,float CGRect 之类的
NSString *columnType = property.propertyType;
if ([LKSQL_Convert_FloatType rangeOfString:columnType].location != NSNotFound) {
if (value) {
modelValue = [[LKDBUtils numberFormatter] numberFromString:value];
}
} else if ([LKSQL_Convert_IntType rangeOfString:columnType].location != NSNotFound) {
if (value) {
modelValue = [[LKDBUtils numberFormatter] numberFromString:value];
}
}
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
else if ([columnType isEqualToString:@"CGRect"]) {
if (value) {
CGRect rect = CGRectFromString(value);
modelValue = [NSValue valueWithCGRect:rect];
} else {
modelValue = [NSValue valueWithCGRect:CGRectZero];
}
} else if ([columnType isEqualToString:@"CGPoint"]) {
if (value) {
CGPoint point = CGPointFromString(value);
modelValue = [NSValue valueWithCGPoint:point];
} else {
modelValue = [NSValue valueWithCGPoint:CGPointZero];
}
} else if ([columnType isEqualToString:@"CGSize"]) {
if (value) {
CGSize size = CGSizeFromString(value);
modelValue = [NSValue valueWithCGSize:size];
} else {
modelValue = [NSValue valueWithCGSize:CGSizeZero];
}
} else if ([columnType isEqualToString:@"_NSRange"]) {
if (value) {
NSRange range = NSRangeFromString(value);
modelValue = [NSValue valueWithRange:range];
} else {
modelValue = [NSValue valueWithRange:NSMakeRange(0, 0)];
}
}
#else
else if ([columnType hasSuffix:@"Rect"]) {
if (value) {
NSRect rect = NSRectFromString(value);
modelValue = [NSValue valueWithRect:rect];
} else {
modelValue = [NSValue valueWithRect:NSZeroRect];
}
} else if ([columnType hasSuffix:@"Point"]) {
if (value) {
NSPoint point = NSPointFromString(value);
modelValue = [NSValue valueWithPoint:point];
} else {
modelValue = [NSValue valueWithPoint:NSZeroPoint];
}
} else if ([columnType hasSuffix:@"Size"]) {
if (value) {
NSSize size = NSSizeFromString(value);
modelValue = [NSValue valueWithSize:size];
} else {
modelValue = [NSValue valueWithSize:NSZeroSize];
}
} else if ([columnType hasSuffix:@"Range"]) {
if (value) {
NSRange range = NSRangeFromString(value);
modelValue = [NSValue valueWithRange:range];
} else {
modelValue = [NSValue valueWithRange:NSMakeRange(0, 0)];
}
}
#endif
///如果都没有值 默认给个0
if (modelValue == nil) {
modelValue = @0;
}
} else if (!value || ![value isKindOfClass:[NSString class]]) {
//不继续遍历
} else if ([columnClass isSubclassOfClass:[NSString class]]) {
if (![LKDBHelper nullIsEmpty] || value.length > 0) {
modelValue = [columnClass stringWithString:value];
}
} else if ([columnClass isSubclassOfClass:[NSNumber class]]) {
modelValue = [[LKDBUtils numberFormatter] numberFromString:value];
} else if ([columnClass isSubclassOfClass:[NSDate class]]) {
NSString *datestr = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSDateFormatter *formatter = [self.class getModelDateFormatter];
if (formatter) {
modelValue = [formatter dateFromString:datestr];
} else {
modelValue = [LKDBUtils dateWithString:datestr];
}
} else if ([columnClass isSubclassOfClass:[LKDBColor class]]) {
NSString *colorString = value;
NSArray *array = [colorString componentsSeparatedByString:@","];
float r, g, b, a;
r = [[array objectAtIndex:0] floatValue];
g = [[array objectAtIndex:1] floatValue];
b = [[array objectAtIndex:2] floatValue];
a = [[array objectAtIndex:3] floatValue];
modelValue = [LKDBColor colorWithRed:r green:g blue:b alpha:a];
} else if ([columnClass isSubclassOfClass:[LKDBImage class]]) {
NSString *filename = value;
NSString *filepath = [self.class getDBImagePathWithName:filename];
if ([LKDBUtils isFileExists:filepath]) {
modelValue = [[LKDBImage alloc] initWithContentsOfFile:filepath];
}
} else if ([columnClass isSubclassOfClass:[NSData class]]) {
NSString *filename = value;
NSString *filepath = [self.class getDBDataPathWithName:filename];
if ([LKDBUtils isFileExists:filepath]) {
modelValue = [NSData dataWithContentsOfFile:filepath];
}
} else if ([columnClass isSubclassOfClass:[NSURL class]]) {
NSString *urlString = value;
modelValue = [NSURL URLWithString:urlString];
} else {
modelValue = [self db_modelWithJsonValue:value];
BOOL isValid = NO;
if ([modelValue isKindOfClass:[NSArray class]] && [columnClass isSubclassOfClass:[NSArray class]]) {
isValid = YES;
modelValue = [columnClass arrayWithArray:modelValue];
} else if ([modelValue isKindOfClass:[NSDictionary class]] && [columnClass isSubclassOfClass:[NSDictionary class]]) {
isValid = YES;
modelValue = [columnClass dictionaryWithDictionary:modelValue];
} else if ([modelValue isKindOfClass:columnClass]) {
isValid = YES;
}
///如果类型不对 则设置为空
if (!isValid) {
modelValue = nil;
}
}
[self setValue:modelValue forKey:property.propertyName];
}
#pragma mark - 对 model NSArray NSDictionary 进行支持
- (id)db_jsonObjectFromDictionary:(NSDictionary *)dic
{
if ([NSJSONSerialization isValidJSONObject:dic]) {
NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_JSON, LKDB_ValueKey: dic};
return bomb;
} else {
NSMutableDictionary *toDic = [NSMutableDictionary dictionary];
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
id jsonObject = [self db_jsonObjectWithObject:obj];
if (jsonObject) {
toDic[key] = jsonObject;
}
}];
if (toDic.count) {
NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_Combo, LKDB_ValueKey: toDic};
return bomb;
}
}
return nil;
}
- (id)db_jsonObjectFromArray:(NSArray *)array
{
if ([NSJSONSerialization isValidJSONObject:array]) {
NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_JSON, LKDB_ValueKey: array};
return bomb;
} else {
NSMutableArray *toArray = [NSMutableArray array];
NSInteger count = array.count;
for (NSInteger i = 0; i < count; i++) {
id obj = [array objectAtIndex:i];
id jsonObject = [self db_jsonObjectWithObject:obj];
if (jsonObject) {
[toArray addObject:jsonObject];
}
}
if (toArray.count) {
NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_Combo, LKDB_ValueKey: toArray};
return bomb;
}
}
return nil;
}
///目前只支持 model、NSString、NSNumber 简单类型
- (id)db_jsonObjectWithObject:(id)obj
{
id jsonObject = nil;
if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
jsonObject = obj;
} else if ([obj isKindOfClass:[NSDate class]]) {
NSString *dateString = nil;
NSDateFormatter *formatter = [self.class getModelDateFormatter];
if (formatter) {
dateString = [formatter stringFromDate:obj];
} else {
dateString = [LKDBUtils stringWithDate:obj];
}
dateString = [dateString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (dateString.length > 0) {
jsonObject = @{LKDB_TypeKey: LKDB_TypeKey_Date, LKDB_ValueKey: dateString};
}
} else if ([obj isKindOfClass:[NSArray class]]) {
jsonObject = [self db_jsonObjectFromArray:obj];
} else if ([obj isKindOfClass:[NSDictionary class]]) {
jsonObject = [self db_jsonObjectFromDictionary:obj];
} else {
jsonObject = [self db_jsonObjectFromModel:obj];
}
if (jsonObject == nil) {
jsonObject = [obj description];
}
return jsonObject;
}
- (id)db_jsonObjectFromModel:(NSObject *)model
{
Class clazz = model.class;
NSDictionary *jsonObject = nil;
if (model.rowid > 0) {
[model updateToDB];
jsonObject = [self db_readInfoWithModel:model class:clazz];
} else {
if (model.db_inserting == NO && [clazz getModelInfos].count > 0) {
BOOL success = [model saveToDB];
if (success) {
jsonObject = [self db_readInfoWithModel:model class:clazz];
}
} else {
NSAssert(NO, @"目前LKDB 还不支持 循环引用。 比如 A 持有 B, B 持有 A,这种的存储");
}
}
return jsonObject;
}
- (NSDictionary *)db_readInfoWithModel:(NSObject *)model class:(Class)clazz
{
NSMutableDictionary *jsonObject = [NSMutableDictionary dictionary];
if (!model.db_tableName) {
NSAssert(NO, @"none table name");
return nil;
}
if (!NSStringFromClass(clazz)) {
NSAssert(NO, @"none class");
return nil;
}
jsonObject[LKDB_TypeKey] = LKDB_TypeKey_Model;
jsonObject[LKDB_TableNameKey] = model.db_tableName;
jsonObject[LKDB_ClassKey] = NSStringFromClass(clazz);
jsonObject[LKDB_RowIdKey] = @(model.rowid);
NSDictionary *dic = [model db_getPrimaryKeysValues];
if (dic.count > 0 && [NSJSONSerialization isValidJSONObject:dic]) {
jsonObject[LKDB_PValueKey] = dic;
}
return jsonObject;
}
- (NSString *)db_jsonStringFromObject : (NSObject *)jsonObject
{
if (jsonObject && [NSJSONSerialization isValidJSONObject:jsonObject]) {
NSData *data = [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:nil];
if (data.length > 0) {
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return jsonString;
}
}
return nil;
}
- (id)db_modelWithJsonValue:(id)value
{
NSData *jsonData = nil;
if ([value isKindOfClass:[NSString class]]) {
jsonData = [value dataUsingEncoding:NSUTF8StringEncoding];
} else if ([value isKindOfClass:[NSData class]]) {
jsonData = value;
}
if (jsonData.length > 0) {
NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
return [self db_objectWithDictionary:jsonDic];
}
return nil;
}
- (id)db_objectWithArray:(NSArray *)array
{
NSMutableArray *toArray = nil;
NSInteger count = array.count;
for (NSInteger i = 0; i < count; i++) {
id value = [array objectAtIndex:i];
if ([value isKindOfClass:[NSDictionary class]]) {
value = [self db_objectWithDictionary:value];
} else if ([value isKindOfClass:[NSArray class]]) {
value = [self db_objectWithArray:value];
}
if (value) {
if (toArray == nil) {
toArray = [NSMutableArray array];
}
[toArray addObject:value];
}
}
return toArray;
}
- (id)db_objectWithDictionary:(NSDictionary *)dic
{
if (dic.count == 0) {
return nil;
}
NSString *type = [dic objectForKey:LKDB_TypeKey];
if (type) {
if ([type isEqualToString:LKDB_TypeKey_Model]) {
Class clazz = NSClassFromString([dic objectForKey:LKDB_ClassKey]);
NSInteger rowid = [[dic objectForKey:LKDB_RowIdKey] integerValue];
NSString *tableName = [dic objectForKey:LKDB_TableNameKey];
NSString *where = nil;
NSString *rowCountWhere = [NSString stringWithFormat:@"select count(rowid) from %@ where rowid=%ld limit 1", tableName, (long)rowid];
NSInteger result = [[[clazz getUsingLKDBHelper] executeScalarWithSQL:rowCountWhere arguments:nil] integerValue];
if (result > 0) {
where = [NSString stringWithFormat:@"select rowid,* from %@ where rowid=%ld limit 1", tableName, (long)rowid];
} else {
NSDictionary *pv = [dic objectForKey:LKDB_PValueKey];
if (pv.count > 0) {
BOOL isNeedAddDot = NO;
NSMutableString *sb = [NSMutableString stringWithFormat:@"select rowid,* from %@ where", tableName];
NSArray *allKeys = pv.allKeys;
for (NSString *key in allKeys) {
id obj = [pv objectForKey:key];
if (isNeedAddDot) {
[sb appendString:@" and"];
}
[sb appendFormat:@" %@ = '%@'", key, obj];
isNeedAddDot = YES;
}
[sb appendString:@" limit 1"];
where = [NSString stringWithString:sb];
}
}
if (where) {
NSArray *array = [[clazz getUsingLKDBHelper] searchWithSQL:where toClass:clazz];
if (array.count > 0) {
NSObject *result = [array objectAtIndex:0];
result.db_tableName = tableName;
return result;
}
}
} else if ([type isEqualToString:LKDB_TypeKey_JSON]) {
id value = [dic objectForKey:LKDB_ValueKey];
return value;
} else if ([type isEqualToString:LKDB_TypeKey_Combo]) {
id value = [dic objectForKey:LKDB_ValueKey];
if ([value isKindOfClass:[NSArray class]]) {
return [self db_objectWithArray:value];
} else if ([value isKindOfClass:[NSDictionary class]]) {
return [self db_objectWithDictionary:value];
} else {
return value;
}
} else if ([type isEqualToString:LKDB_TypeKey_Date]) {
NSString *datestr = [dic objectForKey:LKDB_ValueKey];
NSDateFormatter *formatter = [self.class getModelDateFormatter];
if (formatter) {
return [formatter dateFromString:datestr];
} else {
return [LKDBUtils dateWithString:datestr];
}
}
} else {
NSMutableDictionary *toDic = [NSMutableDictionary dictionary];
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) {
id saveObj = value;
if ([value isKindOfClass:[NSArray class]]) {
saveObj = [self db_objectWithArray:value];
} else if ([value isKindOfClass:[NSDictionary class]]) {
saveObj = [self db_objectWithDictionary:value];
}
if (saveObj) {
toDic[key] = saveObj;
}
}];
return toDic;
}
return nil;
}
#pragma mark - your can overwrite
- (void)setNilValueForKey:(NSString *)key
{
NSLog(@"nil 这种设置到了 int 等基础类型中");
}
- (id)valueForUndefinedKey:(NSString *)key
{
NSLog(@"你有get方法没实现,key:%@", key);
return nil;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
NSLog(@"你有set方法没实现,key:%@", key);
}
#pragma mark -
- (void)userSetValueForModel:(LKDBProperty *)property value:(id)value
{
}
- (id)userGetValueForModel:(LKDBProperty *)property
{
return nil;
}
- (NSDictionary *)db_getPrimaryKeysValues
{
LKModelInfos *infos = [self.class getModelInfos];
NSArray *array = infos.primaryKeys;
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[array enumerateObjectsUsingBlock:^(NSString *pname, NSUInteger idx, BOOL *_Nonnull stop) {
LKDBProperty *property = [infos objectWithSqlColumnName:pname];
id value = nil;
if ([property.type isEqualToString:LKSQL_Mapping_UserCalculate]) {
value = [self userGetValueForModel:property];
} else {
value = [self modelGetValue:property];
}
if (value) {
dic[property.sqlColumnName] = value;
}
}];
return dic;
}
//主键值 是否为空
- (BOOL)singlePrimaryKeyValueIsEmpty
{
LKDBProperty *property = [self singlePrimaryKeyProperty];
if (property) {
id pkvalue = [self singlePrimaryKeyValue];
if ([property.sqlColumnType isEqualToString:LKSQL_Type_Int]) {
if ([pkvalue isKindOfClass:[NSString class]]) {
if ([LKDBUtils checkStringIsEmpty:pkvalue])
return YES;
if ([pkvalue integerValue] == 0)
return YES;
return NO;
}
if ([pkvalue isKindOfClass:[NSNumber class]]) {
if ([pkvalue integerValue] == 0)
return YES;
else
return NO;
}
return YES;
} else {
return (pkvalue == nil);
}
}
return NO;
}
- (LKDBProperty *)singlePrimaryKeyProperty
{
LKModelInfos *infos = [self.class getModelInfos];
if (infos.primaryKeys.count == 1) {
NSString *name = [infos.primaryKeys objectAtIndex:0];
return [infos objectWithSqlColumnName:name];
}
return nil;
}
- (id)singlePrimaryKeyValue
{
LKDBProperty *property = [self singlePrimaryKeyProperty];
if (property) {
if ([property.type isEqualToString:LKSQL_Mapping_UserCalculate]) {
return [self userGetValueForModel:property];
} else {
return [self modelGetValue:property];
}
}
return nil;
}
+ (NSString *)db_rowidAliasName
{
LKModelInfos *infos = [self getModelInfos];
if (infos.primaryKeys.count == 1) {
NSString *primaryType = [infos objectWithSqlColumnName:[infos.primaryKeys lastObject]].sqlColumnType;
if ([primaryType isEqualToString:LKSQL_Type_Int]) {
return [infos.primaryKeys lastObject];
}
}
return nil;
}
#pragma mark - get model property info
+ (LKModelInfos *)getModelInfos
{
static __strong NSMutableDictionary *oncePropertyDic;
static __strong NSRecursiveLock *lock;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
lock = [[NSRecursiveLock alloc] init];
oncePropertyDic = [[NSMutableDictionary alloc] initWithCapacity:8];
});
LKModelInfos *infos;
[lock lock];
NSString *className = NSStringFromClass(self);
infos = [oncePropertyDic objectForKey:className];
if (infos == nil) {
NSMutableArray *pronames = [NSMutableArray array];
NSMutableArray *protypes = [NSMutableArray array];
NSDictionary *keymapping = [self getTableMapping];
if ([self isContainSelf] && self != [NSObject class]) {
[self getSelfPropertys:pronames protypes:protypes];
}
NSArray *pkArray = [self getPrimaryKeyUnionArray];
if (pkArray.count == 0) {
pkArray = nil;
NSString *pk = [self getPrimaryKey];
if ([LKDBUtils checkStringIsEmpty:pk] == NO) {
pkArray = [NSArray arrayWithObject:pk];
}
}
if ([self isContainParent] && [self superclass] != [NSObject class]) {
LKModelInfos *superInfos = [[self superclass] getModelInfos];
for (NSInteger i = 0; i < superInfos.count; i++) {
LKDBProperty *db_p = [superInfos objectWithIndex:i];
if (db_p.propertyName && db_p.propertyType && [db_p.propertyName isEqualToString:@"rowid"] == NO) {
[pronames addObject:db_p.propertyName];
[protypes addObject:db_p.propertyType];
}
}
}
if (pronames.count > 0) {
infos = [[LKModelInfos alloc] initWithKeyMapping:keymapping propertyNames:pronames propertyType:protypes primaryKeys:pkArray];
} else {
infos = [[LKModelInfos alloc] init];
}
oncePropertyDic[className] = infos;
}
[lock unlock];
return infos;
}
+ (BOOL)isContainParent
{
return NO;
}
+ (BOOL)isContainSelf
{
return YES;
}
/**
* @brief 获取自身的属性
*
* @param pronames 保存属性名称
* @param protypes 保存属性类型
*/
+ (void)getSelfPropertys:(NSMutableArray *)pronames protypes:(NSMutableArray *)protypes
{
unsigned int outCount = 0, i = 0;
objc_property_t *properties = class_copyPropertyList(self, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
//取消rowid 的插入 //子类 已重载的属性 取消插入
if (propertyName.length == 0 || [propertyName isEqualToString:@"rowid"] ||
[pronames indexOfObject:propertyName] != NSNotFound) {
continue;
}
NSString *propertyType = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
///过滤只读属性
if ([propertyType rangeOfString:@",R,"].length > 0 || [propertyType hasSuffix:@",R"]) {
NSString *firstWord = [[propertyName substringToIndex:1] uppercaseString];
NSString *otherWord = [propertyName substringFromIndex:1];
NSString *setMethodString = [NSString stringWithFormat:@"set%@%@:", firstWord, otherWord];
SEL setSEL = NSSelectorFromString(setMethodString);
///有set方法就不过滤了
if ([self instancesRespondToSelector:setSEL] == NO) {
continue;
}
}
/*
c char
i int
l long
s short
d double
f float
@ id //指针 对象
... BOOL 获取到的表示 方式是 char
.... ^i 表示 int * 一般都不会用到
*/
NSString *propertyClassName = nil;
if ([propertyType hasPrefix:@"T@"]) {
NSRange range = [propertyType rangeOfString:@","];
if (range.location > 4 && range.location <= propertyType.length) {
range = NSMakeRange(3, range.location - 4);
propertyClassName = [propertyType substringWithRange:range];
if ([propertyClassName hasSuffix:@">"]) {
NSRange categoryRange = [propertyClassName rangeOfString:@"<"];
if (categoryRange.length > 0) {
propertyClassName = [propertyClassName substringToIndex:categoryRange.location];
}
}
}
} else if ([propertyType hasPrefix:@"T{"]) {
NSRange range = [propertyType rangeOfString:@"="];
if (range.location > 2 && range.location <= propertyType.length) {
range = NSMakeRange(2, range.location - 2);
propertyClassName = [propertyType substringWithRange:range];
}
} else {
propertyType = [propertyType lowercaseString];
if ([propertyType hasPrefix:@"ti"] || [propertyType hasPrefix:@"tb"]) {
propertyClassName = @"int";
} else if ([propertyType hasPrefix:@"tf"]) {
propertyClassName = @"float";
} else if ([propertyType hasPrefix:@"td"]) {
propertyClassName = @"double";
} else if ([propertyType hasPrefix:@"tl"] || [propertyType hasPrefix:@"tq"]) {
propertyClassName = @"long";
} else if ([propertyType hasPrefix:@"tc"]) {
propertyClassName = @"char";
} else if ([propertyType hasPrefix:@"ts"]) {
propertyClassName = @"short";
}
}
if ([LKDBUtils checkStringIsEmpty:propertyClassName]) {
///没找到具体的属性就放弃
continue;
}
///添加属性
[pronames addObject:propertyName];
[protypes addObject:propertyClassName];
}
free(properties);
if ([self isContainParent] && [self superclass] != [NSObject class]) {
[[self superclass] getSelfPropertys:pronames protypes:protypes];
}
}
#pragma mark - log all property
- (NSMutableString *)getAllPropertysString
{
Class clazz = [self class];
NSMutableString *sb = [NSMutableString stringWithFormat:@"\n <%@> :\n", NSStringFromClass(clazz)];
[sb appendFormat:@"rowid : %ld\n", (long)self.rowid];
[self mutableString:sb appendPropertyStringWithClass:clazz containParent:YES];
return sb;
}
- (NSString *)printAllPropertys
{
return [self printAllPropertysIsContainParent:NO];
}
- (NSString *)printAllPropertysIsContainParent:(BOOL)containParent
{
#ifdef DEBUG
Class clazz = [self class];
NSMutableString *sb = [NSMutableString stringWithFormat:@"\n <%@> :\n", NSStringFromClass(clazz)];
[sb appendFormat:@"rowid : %ld\n", (long)self.rowid];
[self mutableString:sb appendPropertyStringWithClass:clazz containParent:containParent];
NSLog(@"%@", sb);
return sb;
#else
return @"";
#endif
}
- (void)mutableString:(NSMutableString *)sb appendPropertyStringWithClass:(Class)clazz containParent:(BOOL)containParent
{
if (clazz == [NSObject class]) {
return;
}
unsigned int outCount = 0, i = 0;
objc_property_t *properties = class_copyPropertyList(clazz, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
[sb appendFormat:@" %@ : %@ \n", propertyName, [self valueForKey:propertyName]];
}
free(properties);
if (containParent) {
[self mutableString:sb appendPropertyStringWithClass:clazz.superclass containParent:containParent];
}
}
@end
+277
View File
@@ -0,0 +1,277 @@
LKDBHelper
====================================
this is sqlite ORM (an automatic database operation) <br>
thread-safe and not afraid of recursive deadlock
QQ群号 113767274 有什么问题或者改进的地方大家一起讨论
简书:不定时更新 [http://www.jianshu.com/users/376b950a20ec](http://www.jianshu.com/users/376b950a20ec/latest_articles)
# Big Upgrade 2.0
Supported __NSArray__,__NSDictionary__, __ModelClass__, __NSNumber__, __NSString__, __NSDate__, __NSData__, __UIColor__, __UIImage__, __CGRect__, __CGPoint__, __CGSize__, __NSRange__, __int__,__char__,__float__, __double__, __long__.. attribute to insert and select automation.
全面支持 __NSArray__,__NSDictionary__, __ModelClass__, __NSNumber__, __NSString__, __NSDate__, __NSData__, __UIColor__, __UIImage__, __CGRect__, __CGPoint__, __CGSize__, __NSRange__, __int__,__char__,__float__, __double__, __long__.. 等属性的自动化操作(插入和查询)
------------------------------------
Requirements
====================================
* iOS 4.3+
* ARC only
* FMDB(https://github.com/ccgus/fmdb)
## Adding to your project
If you are using CocoaPods, then, just add this line to your PodFile<br>
```objective-c
pod 'LKDBHelper'
```
If you are using Encryption, Order can not be wrong<br>
```objective-c
pod 'FMDB/SQLCipher'
pod 'LKDBHelper'
```
@property(strong,nonatomic)NSString* encryptionKey;
## Basic usage
1. Create a new Objective-C class for your data model
```objective-c
@interface LKTest : NSObject
@property(copy,nonatomic)NSString* name;
@property NSUInteger age;
@property BOOL isGirl;
@property(strong,nonatomic)LKTestForeign* address;
@property(strong,nonatomic)NSArray* blah;
@property(strong,nonatomic)NSDictionary* hoho;
@property char like;
...
```
2. in the *.m file, overwirte getTableName function (option)
```objective-c
+(NSString *)getTableName
{
return @"LKTestTable";
}
```
3. in the *.m file, overwirte callback function (option)
```objective-c
@interface NSObject(LKDBHelper_Delegate)
+(void)dbDidCreateTable:(LKDBHelper*)helper tableName:(NSString*)tableName;
+(void)dbDidAlterTable:(LKDBHelper*)helper tableName:(NSString*)tableName addColumns:(NSArray*)columns;
+(BOOL)dbWillInsert:(NSObject*)entity;
+(void)dbDidInserted:(NSObject*)entity result:(BOOL)result;
+(BOOL)dbWillUpdate:(NSObject*)entity;
+(void)dbDidUpdated:(NSObject*)entity result:(BOOL)result;
+(BOOL)dbWillDelete:(NSObject*)entity;
+(void)dbDidDeleted:(NSObject*)entity result:(BOOL)result;
///data read finish
+(void)dbDidSeleted:(NSObject*)entity;
@end
```
4. Initialize your model with data and insert to database
```objective-c
LKTestForeign* foreign = [[LKTestForeign alloc]init];
foreign.address = @":asdasdasdsadasdsdas";
foreign.postcode = 123341;
foreign.addid = 213214;
//插入数据 insert table row
LKTest* test = [[LKTest alloc]init];
test.name = @"zhan san";
test.age = 16;
//外键 foreign key
test.address = foreign;
test.blah = @[@"1",@"2",@"3"];
test.blah = @[@"0",@[@1],@{@"2":@2},foreign];
test.hoho = @{@"array":test.blah,@"foreign":foreign,@"normal":@123456,@"date":[NSDate date]};
//同步 插入第一条 数据 Insert the first
[test saveToDB];
//or
//[globalHelper insertToDB:test];
```
5. select 、 delete 、 update 、 isExists 、 rowCount ...
```objective-c
select:
NSMutableArray* array = [LKTest searchWithWhere:nil orderBy:nil offset:0 count:100];
for (id obj in arraySync) {
addText(@"%@",[obj printAllPropertys]);
}
delete:
[LKTest deleteToDB:test];
update:
test.name = "rename";
[LKTest updateToDB:test where:nil];
isExists:
[LKTest isExistsWithModel:test];
rowCount:
[LKTest rowCountWithWhere:nil];
```
6. Description of parameters "where"
```objective-c
For example:
single: @"rowid = 1" or @{@"rowid":@1}
more: @"rowid = 1 and sex = 0" or @{@"rowid":@1,@"sex":@0}
when where is "or" type , such as @"rowid = 1 or sex = 0"
you only use NSString
array: @"rowid in (1,2,3)" or @{@"rowid":@[@1,@2,@3]}
composite: @"rowid in (1,2,3) and sex=0 " or @{@"rowid":@[@1,@2,@3],@"sex":@0}
If you want to be judged , only use NSString
For example: @"date >= '2013-04-01 00:00:00'"
```
## table mapping
overwirte getTableMapping Function (option)
```objective-c
+(NSDictionary *)getTableMapping
{
//return nil
return @{@"name":LKSQLInherit,
@"MyAge":@"age",
@"img":LKSQLInherit,
@"MyDate":@"date",
@"color":LKSQLInherit,
@"address":LKSQLUserCalculate};
}
```
## table update (option)
```objective-c
+(void)dbDidAlterTable:(LKDBHelper *)helper tableName:(NSString *)tableName addColumns:(NSArray *)columns
{
for (int i=0; i<columns.count; i++)
{
LKDBProperty* p = [columns objectAtIndex:i];
if([p.propertyName isEqualToString:@"error"])
{
[helper executeDB:^(FMDatabase *db) {
NSString* sql = [NSString stringWithFormat:@"update %@ set error = name",tableName];
[db executeUpdate:sql];
}];
}
}
}
```
## set column attribute (option)
```objective-c
+(void)columnAttributeWithProperty:(LKDBProperty *)property
{
if([property.sqlColumnName isEqualToString:@"MyAge"])
{
property.defaultValue = @"15";
}
if([property.propertyName isEqualToString:@"date"])
{
property.isUnique = YES;
property.checkValue = @"MyDate > '2000-01-01 00:00:00'";
property.length = 30;
}
}
```
## demo screenshot
![demo screenshot](https://github.com/li6185377/LKDBHelper-SQLite-ORM/raw/master/screenshot/Snip20130620_8.png)
<br>table test data<br>
![](https://github.com/li6185377/LKDBHelper-SQLite-ORM/raw/master/screenshot/Snip20130620_6.png)
<br>foreign key data<br>
![](https://github.com/li6185377/LKDBHelper-SQLite-ORM/raw/master/screenshot/Snip20130620_7.png)
----------
# Use in swift
Remember to override the class function `getTableName` for model.
Change-log
==========
**Version 1.1** @ 2012-6-20
- automatic table mapping
- support optional columns
- support column attribute settings
- you can return column content
**Version 1.0** @ 2013-5-19
- overwrite and rename LKDBHelper
- property type support: UIColor,NSDate,UIImage,NSData,CGRect,CGSize,CGPoint,int,float,double,NSString,short,char,bool,NSInterger..
- fix a recursive deadlock.
- rewrite the asynchronous operation -
- thread-safe
- various bug modified optimize cache to improve performance
- test and demos
- bug fixes, speed improvements
**Version 0.0.1** @ 2012-10-1
- Initial release with LKDAOBase
-------
License
=======
This code is distributed under the terms and conditions of the MIT license.
-------
Contribution guidelines
=======
* if you are fixing a bug you discovered, please add also a unit test so I know how exactly to reproduce the bug before merging
-------
Contributors
=======
Author: Jianghuai Li
Contributors: waiting for you to join