GiGaMaskTime/Pods/LKDBHelper/LKDBHelper/Helper/NSObject+LKModel.m

923 lines
33 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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