// // DatabaseHelper.swift // MTP2_iOS // // Created by zhongyuan on 2018/6/9. // Copyright © 2018年 zhongyuan.All rights reserved. // import UIKit import CoreData enum DataBaseError: Error { case NoFindUser case NoFindSelfGoods } /// Database Helper class DatabaseHelper { // MARK: - 属性列表 /// 全局单例 static let appDelegate = UIApplication.shared.delegate as! AppDelegate // MARK: - 生命周期 static func firstOpenInitialData() { /// 判断是否第一次运行 if !UserDefaultsUtils.isFirstOpen() { return } /// 初始化可能与登录相关的错误码 var errorCodeInfos = [MoErrorInfo]() errorCodeInfos.append(MoErrorInfo(description: "账号或密码不匹配", errorcode: "1003", errorid: 1003, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "无效账号", errorcode: "1004", errorid: 1004, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "账号类型不匹配", errorcode: "1005", errorid: 1005, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "账号不在线", errorcode: "1006", errorid: 1006, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "操作权限不够", errorcode: "1007", errorid: 1007, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "会员无账户在线", errorcode: "1008", errorid: 1008, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "账户在别处登录", errorcode: "1009", errorid: 1009, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "值为空", errorcode: "1010", errorid: 1010, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "登录账户已经存在", errorcode: "1011", errorid: 1011, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "软件版本过低不能登录", errorcode: "1012", errorid: 1012, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "IP地址不在允许范围内", errorcode: "1013", errorid: 1013, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) errorCodeInfos.append(MoErrorInfo(description: "地址查询错误,请稍候重试", errorcode: "1025", errorid: 1025, modulecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", operatecode: "ERR_ORDERWRTRADE_FIXEDPRICE_PRICE_INVALID", rownumber: "")) try? updateErrorInfos(errorInfos: errorCodeInfos) } // MARK: - 账户相关 /// 获取指定用户id的本地用户信息对象 /// /// - Parameter userID: 用户id /// - Returns: 用户信息对象 static func getUser(loginID: String) throws -> UserEntity? { let fetchRequest: NSFetchRequest = UserEntity.fetchRequest() fetchRequest.predicate = NSPredicate(format: "loginID == %@", loginID) let result = try DatabaseHelper.appDelegate.backGroundObjectContext.fetch(fetchRequest) return result.count != 0 ? result[0] : nil } /// 获取所有保存的用户信息 /// /// - Parameter type: 类型,0为实盘(默认值);1为模拟盘 /// - Returns: 用户信息数组 /// - Throws: 数据库操作错误 static func getUsers() throws -> [UserEntity]? { let fetchRequest: NSFetchRequest = UserEntity.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "loginDate", ascending: false)] let result = try DatabaseHelper.appDelegate.backGroundObjectContext.fetch(fetchRequest) return result.count != 0 ? result : nil } /// - Parameters: /// - userID: 用户id /// - loginID: 登录id /// - type: 类型,0为实盘(默认值);1为模拟盘 /// - Throws: 数据库操作错误 static func addUser(userID: UInt32, loginID: String, _ loginDate: Date = Date()) throws { if let userEntity = try getUser(loginID: loginID) { userEntity.loginDate = loginDate } else { guard let userEntity = NSEntityDescription.insertNewObject(forEntityName: "UserEntity", into: DatabaseHelper.appDelegate.backGroundObjectContext) as? UserEntity else { return } userEntity.userID = Int64(Int32(userID)) userEntity.loginID = loginID userEntity.loginDate = loginDate } DatabaseHelper.appDelegate.backGroundObjectContext.perform { if DatabaseHelper.appDelegate.backGroundObjectContext.hasChanges { try? DatabaseHelper.appDelegate.backGroundObjectContext.save() } } } /// 删除用户信息 /// - Parameter loginID: loginID static func deleteUser(loginID: String) throws { do { if let userEntity = try getUser(loginID: loginID) { DatabaseHelper.appDelegate.backGroundObjectContext.perform { DatabaseHelper.appDelegate.backGroundObjectContext.delete(appDelegate.backGroundObjectContext.object(with: userEntity.objectID)) if DatabaseHelper.appDelegate.backGroundObjectContext.hasChanges { try? DatabaseHelper.appDelegate.backGroundObjectContext.save() } } } } catch { throw DataBaseError.NoFindUser } } // MARK: - 错误码、枚举相关 static func updateErrorInfos(errorInfos: [MoErrorInfo]) throws { /// 数据为空不做任何处理 if errorInfos.count <= 0 { return } appDelegate.backGroundObjectContext.perform { for moErrorInfo in errorInfos { if try! getError(errorcode: moErrorInfo.errorcode) == nil { /// FIXME: 可能会报 EXC_BAD_ACCESS guard let entity = NSEntityDescription.insertNewObject(forEntityName: "ErrorCodeEntity", into: appDelegate.backGroundObjectContext) as? ErrorCodeEntity else { return } entity.errordesc = moErrorInfo.description entity.rownumber = moErrorInfo.rownumber entity.operatecode = moErrorInfo.operatecode entity.errorid = Int64(moErrorInfo.errorid) entity.errorcode = moErrorInfo.errorcode } } if appDelegate.backGroundObjectContext.hasChanges { try? appDelegate.backGroundObjectContext.save() } } } /// 移出所有错误码信息 /// - Throws: Throws static func deleteAllErrorInfos() throws { let fetchRequest = NSFetchRequest(entityName: "ErrorCodeEntity") let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) try appDelegate.backGroundObjectContext.execute(batchDeleteRequest) } /// 获取对应的错误码信息 /// - Parameter errorCode: errorCode /// - Throws: Throws /// - Returns: ErrorCodeEntity static func getError(errorcode: String) throws -> ErrorCodeEntity? { let fetchRequest: NSFetchRequest = ErrorCodeEntity.fetchRequest() fetchRequest.predicate = NSPredicate(format: "errorcode == %@", errorcode) let result = try appDelegate.backGroundObjectContext.fetch(fetchRequest) return result.count != 0 ? result[0] : nil } /// 获取所有得错误码信息 /// - Parameter divisions: divisions static func getAllErrorInfos() throws -> [ErrorCodeEntity] { let fetchRequest: NSFetchRequest = ErrorCodeEntity.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "errorid", ascending: true)] let errors = (try? appDelegate.backGroundObjectContext.fetch(fetchRequest)) ?? [] return errors } /// 添加枚举到数据库 /// - Parameter enumInfos: enumInfos /// - Throws: throws static func addEnumInfos(enumInfos: [MoEnum]) throws { /// 异常 if enumInfos.count <= 0 { return } appDelegate.backGroundObjectContext.perform { for enumInfo in enumInfos { /// FIXME: 可能会报 EXC_BAD_ACCESS guard let enumEntity = NSEntityDescription.insertNewObject(forEntityName: "EnumEntity", into: appDelegate.backGroundObjectContext) as? EnumEntity else { return } enumEntity.setupWith(enumInfo: enumInfo) } if appDelegate.backGroundObjectContext.hasChanges { try? appDelegate.backGroundObjectContext.save() } } } /// 移出所有的枚举信息 /// - Throws: Throws static func deleteAllEnumInfos() throws { let fetchRequest = NSFetchRequest(entityName: "EnumEntity") let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) try appDelegate.backGroundObjectContext.execute(batchDeleteRequest) } /// 获取特定的枚举信息 /// - Parameter autoid: autoid /// - Throws: Throws /// - Returns: EnumEntity static func getEnumInfo(autoid: Int16) throws -> EnumEntity? { let fetchRequest: NSFetchRequest = EnumEntity.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "autoid", ascending: true)] fetchRequest.predicate = NSPredicate(format: "autoid == %d", autoid) let result = try appDelegate.backGroundObjectContext.fetch(fetchRequest) /// 执行回调 return result.count != 0 ? result[0] : nil } /// 获取特定的枚举信息 /// - Parameter enumdiccode: autoid /// - Throws: Throws /// - Returns: EnumEntity static func getEnumInfo(enumdiccode: String?) throws -> [MoEnum]? { let fetchRequest: NSFetchRequest = EnumEntity.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "autoid", ascending: true)] if let code = enumdiccode { fetchRequest.predicate = NSPredicate(format: "enumdiccode == %@", code) } let result = try appDelegate.backGroundObjectContext.fetch(fetchRequest) /// 执行回调 return result.count != 0 ? result.compactMap({ $0.toMoEnum() }) : nil } // MARK: - 区域信息 /// 添加区域信息到数据库 /// - Parameter divisions: divisions static func addDivisions(_ divisions: [MoDivisions]) throws { /// 异常 if divisions.count <= 0 { return } /// 先移出所有的地区区域信息 try deleteAllDivisions() appDelegate.backGroundObjectContext.perform { for info in divisions { /// 可能会报 EXC_BAD_ACCESS guard let cityEntity = NSEntityDescription.insertNewObject(forEntityName: "CityEntity", into: appDelegate.backGroundObjectContext) as? CityEntity else { return } cityEntity.setupWith(division: info) } if appDelegate.backGroundObjectContext.hasChanges { try? appDelegate.backGroundObjectContext.save() } } } /// 移出所有的区域信息 /// - Throws: Throws static func deleteAllDivisions() throws { let fetchRequest = NSFetchRequest(entityName: "CityEntity") let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) try appDelegate.backGroundObjectContext.execute(batchDeleteRequest) } /// 获取所有的区域信息 /// - Parameter divisions: divisions static func getAllDivisions() throws -> [MoDivisions] { let fetchRequest: NSFetchRequest = CityEntity.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "autoid", ascending: true)] let citys = try appDelegate.backGroundObjectContext.fetch(fetchRequest) let divisions = citys.compactMap({ $0.toDivisions() }) return divisions } // MARK: - 商品相关 static func insertGoodsInfos(_ goodsInfos: [MoGoodsInfo]) throws { /// 先移出商品 do { for goods in goodsInfos { let exist = try? getGoodsInfo(ById: goods.goodsid) if exist ?? false { removeGoodsInfo(goods.goodsid) } } } appDelegate.backGroundObjectContext.performAndWait { do { for obj in goodsInfos { guard let goodsInfoEntity = NSEntityDescription.insertNewObject(forEntityName: "GoodsInfoEntity", into: appDelegate.backGroundObjectContext) as? GoodsInfoEntity else { continue } goodsInfoEntity.setupWith(goodsInfo: obj) } if appDelegate.backGroundObjectContext.hasChanges { try appDelegate.backGroundObjectContext.save() } else { dPrint("商品本地化失败") } } catch { fatalError("商品数据插入失败") } } } /// 判断指定商品信息是否存在 /// /// - Parameter Id: 商品ID /// - Returns: yes: 存在 no: 不存在 /// - Throws: static func getGoodsInfo(ById Id: Int) throws -> Bool { let fetchRequest: NSFetchRequest = GoodsInfoEntity.fetchRequest() fetchRequest.predicate = NSPredicate(format: "goodsid == %ld", Int32(Id)) let count = try appDelegate.backGroundObjectContext.count(for: fetchRequest) return count > 0 } /// 获取所有商品信息 /// /// - Returns: 所有保存的商品信息 /// - Throws: static func getGoodsInfo() throws -> [MoGoodsInfo] { let fetchRequest: NSFetchRequest = GoodsInfoEntity.fetchRequest() fetchRequest.sortDescriptors = [NSSortDescriptor(key: "goodsid", ascending: true)] let goodsInfos = try appDelegate.backGroundObjectContext.fetch(fetchRequest) let moGoodsInfos = goodsInfos.compactMap({ $0.toMoGoodsInfo() }) return moGoodsInfos } /// 判断本地数据库是否有数据 /// /// - Returns: yes: 存在 no: 不存在 /// - Throws: static func goodsInfoIsExist() -> Bool { let fetchRequest: NSFetchRequest = GoodsInfoEntity.fetchRequest() do { let count = try appDelegate.backGroundObjectContext.count(for: fetchRequest) return count > 0 } catch { fatalError() } } /// 根据查询条件获取符合条件的商品 /// /// - Parameter searchCondition: 查询条件 /// - Returns: 符合条件的商品 /// - Throws: static func getGoodsInfo(ByCondition searchCondition: String) throws -> [MoGoodsInfo] { guard !searchCondition.isEmpty else { return [] } let fetchRequest: NSFetchRequest = GoodsInfoEntity.fetchRequest() if RegularUtils.checkNumber(with: searchCondition) { let regularString = ".*\(searchCondition).*" fetchRequest.predicate = NSPredicate(format: "searchCondition MATCHES %@", regularString) } else { var regularString = ".*" for s in searchCondition.uppercased() { regularString.append(s) regularString.append(".*") } fetchRequest.predicate = NSPredicate(format: "searchCondition MATCHES %@", regularString) } /// 排序 fetchRequest.sortDescriptors = [NSSortDescriptor(key: "goodscode", ascending: true)] let goodsInfos = try appDelegate.backGroundObjectContext.fetch(fetchRequest) let moGoodsInfos = goodsInfos.compactMap({ $0.toMoGoodsInfo() }) return moGoodsInfos } /// 删除所有的商品数据信息 static func removeAllGoodsInfo() { /// 获取上下文对象 let viewContext = appDelegate.persistentContainer.viewContext /// 获取实例 let entity = NSFetchRequest(entityName: "GoodsInfoEntity") let deleteRequest = NSBatchDeleteRequest(fetchRequest: entity) let _ = try? viewContext.persistentStoreCoordinator?.execute(deleteRequest, with: viewContext) appDelegate.backGroundObjectContext.perform { if appDelegate.backGroundObjectContext.hasChanges { do { _ = try? viewContext.persistentStoreCoordinator?.execute(deleteRequest, with: viewContext) } } } } /// 删除所有的商品数据信息 static func removeGoodsInfo(_ goodsid: Int) { /// 获取上下文对象 let viewContext = appDelegate.persistentContainer.viewContext /// 获取实例 let fetchRequest = NSFetchRequest(entityName: "GoodsInfoEntity") fetchRequest.predicate = NSPredicate(format: "goodsid == %ld", Int64(goodsid)) let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) let _ = try? viewContext.persistentStoreCoordinator?.execute(deleteRequest, with: viewContext) appDelegate.backGroundObjectContext.perform { if appDelegate.backGroundObjectContext.hasChanges { do { _ = try? viewContext.persistentStoreCoordinator?.execute(deleteRequest, with: viewContext) } } } } /// 根据goodsid获取对应的商品数据 /// - Parameter goodsid: goodsid static func getMoGoodsInfo(where goodsids: [Int]) throws -> [MoGoodsInfo]? { /// 获取商品数据 var goodsInfo: [MoGoodsInfo] = [] let fetchRequest: NSFetchRequest = GoodsInfoEntity.fetchRequest() for goodsid in goodsids { fetchRequest.predicate = NSPredicate(format: "goodsid == %ld", Int64(goodsid)) let goodsInfos = try appDelegate.backGroundObjectContext.fetch(fetchRequest) if goodsInfos.count != 0 { goodsInfo.append(goodsInfos[0].toMoGoodsInfo()) } } return goodsInfo } }