923 lines
33 KiB
Objective-C
923 lines
33 KiB
Objective-C
//
|
||
// 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
|