Commit 5e8d8b81 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk

database: migrate to database for account

New database is created per account. It contains:
- profiles table
- conversations table
- interaction table
- account profile. This table has only one row and store account
avatar and alias

Database file named by account id.

Database content also was changed:
- contact uri stored in canonical format, so it is unique for SIP
contacts
- generated messages stored in a format that allows localizations.

Change-Id: Id7803ab797ac937d63155870fc5c8edf94119bbd
parent 0ea39d4d
......@@ -85,7 +85,7 @@
04399B151D1C341A00E99CD9 /* libyaml-cpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04399AE31D1C341A00E99CD9 /* libyaml-cpp.a */; };
0586C94B1F684DF600613517 /* UIImage+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0586C94A1F684DF600613517 /* UIImage+Helpers.swift */; };
0E0FF1A71FC38070003898C2 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E0FF1A61FC38070003898C2 /* SQLite.framework */; };
0E0FF1AA1FC3843E003898C2 /* RingDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0FF1A91FC3843E003898C2 /* RingDB.swift */; };
0E0FF1AA1FC3843E003898C2 /* DBContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0FF1A91FC3843E003898C2 /* DBContainer.swift */; };
0E0FF1AF1FC38CBC003898C2 /* ProfileDataHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0FF1AE1FC38CBC003898C2 /* ProfileDataHelper.swift */; };
0E0FF1B51FC3947B003898C2 /* DBManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0FF1B41FC3947B003898C2 /* DBManager.swift */; };
0E0FF1B71FC398B3003898C2 /* ConversationDataHepler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0FF1B61FC398B3003898C2 /* ConversationDataHepler.swift */; };
......@@ -394,7 +394,7 @@
04399AE31D1C341A00E99CD9 /* libyaml-cpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libyaml-cpp.a"; path = "../fat/lib/libyaml-cpp.a"; sourceTree = "<group>"; };
0586C94A1F684DF600613517 /* UIImage+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Helpers.swift"; sourceTree = "<group>"; };
0E0FF1A61FC38070003898C2 /* SQLite.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SQLite.framework; path = Carthage/Build/iOS/SQLite.framework; sourceTree = "<group>"; };
0E0FF1A91FC3843E003898C2 /* RingDB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RingDB.swift; sourceTree = "<group>"; };
0E0FF1A91FC3843E003898C2 /* DBContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBContainer.swift; sourceTree = "<group>"; };
0E0FF1AE1FC38CBC003898C2 /* ProfileDataHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileDataHelper.swift; sourceTree = "<group>"; };
0E0FF1B41FC3947B003898C2 /* DBManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBManager.swift; sourceTree = "<group>"; };
0E0FF1B61FC398B3003898C2 /* ConversationDataHepler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationDataHepler.swift; sourceTree = "<group>"; };
......@@ -1049,7 +1049,7 @@
isa = PBXGroup;
children = (
0E0FF1AB1FC38BD1003898C2 /* DBHelpers */,
0E0FF1A91FC3843E003898C2 /* RingDB.swift */,
0E0FF1A91FC3843E003898C2 /* DBContainer.swift */,
0E0FF1B41FC3947B003898C2 /* DBManager.swift */,
);
path = Database;
......@@ -1901,7 +1901,7 @@
1A2D18E51F29197100B2C785 /* MessageAccessoryView.swift in Sources */,
0E0FF1B91FC398C5003898C2 /* InteractionDataHelper.swift in Sources */,
0EE1B54E1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift in Sources */,
0E0FF1AA1FC3843E003898C2 /* RingDB.swift in Sources */,
0E0FF1AA1FC3843E003898C2 /* DBContainer.swift in Sources */,
56308BA71EA00E5700660275 /* NameRegistrationResponse.m in Sources */,
1A3CA32D1F13DA7200283748 /* Chameleon+Ring.swift in Sources */,
0ED2B6FC1F96A158001572F0 /* LinkNewDeviceViewController.swift in Sources */,
......
......@@ -33,20 +33,37 @@ import PushKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
let dBManager = DBManager(profileHepler: ProfileDataHelper(),
conversationHelper: ConversationDataHelper(),
interactionHepler: InteractionDataHelper(),
dbConnections: DBContainer())
private let daemonService = DaemonService(dRingAdaptor: DRingAdapter())
private let accountService = AccountsService(withAccountAdapter: AccountAdapter())
private let nameService = NameService(withNameRegistrationAdapter: NameRegistrationAdapter())
private let conversationsService = ConversationsService(withMessageAdapter: MessagesAdapter())
private let contactsService = ContactsService(withContactsAdapter: ContactsAdapter())
private let presenceService = PresenceService(withPresenceAdapter: PresenceAdapter())
private let callService = CallsService(withCallsAdapter: CallsAdapter())
private let videoService = VideoService(withVideoAdapter: VideoAdapter())
private let audioService = AudioService(withAudioAdapter: AudioAdapter())
private let dataTransferService = DataTransferService(withDataTransferAdapter: DataTransferAdapter())
private let networkService = NetworkService()
private let profileService = ProfilesService()
private var conversationManager: ConversationsManager?
private var interactionsManager: GeneratedInteractionsManager?
private lazy var callService: CallsService = {
CallsService(withCallsAdapter: CallsAdapter(), dbManager: self.dBManager)
}()
private lazy var accountService: AccountsService = {
AccountsService(withAccountAdapter: AccountAdapter(), dbManager: self.dBManager)
}()
private lazy var contactsService: ContactsService = {
ContactsService(withContactsAdapter: ContactsAdapter(), dbManager: self.dBManager)
}()
private lazy var profileService: ProfilesService = {
ProfilesService(dbManager: self.dBManager)
}()
private lazy var dataTransferService: DataTransferService = {
DataTransferService(withDataTransferAdapter: DataTransferAdapter(),
dbManager: self.dBManager)
}()
private lazy var conversationsService: ConversationsService = {
ConversationsService(withMessageAdapter: MessagesAdapter(), dbManager: self.dBManager)
}()
private let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
......@@ -72,6 +89,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
fileprivate let disposeBag = DisposeBag()
// swiftlint:disable function_body_length
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// ignore sigpipe
......@@ -131,7 +149,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
nameService: self.nameService,
dataTransferService: self.dataTransferService,
callService: self.callService)
self.startDB()
self.accountService
.sharedResponseStream
......@@ -163,23 +180,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
})
.disposed(by: disposeBag)
self.accountService.loadAccounts().subscribe { [unowned self] (_) in
self.window?.rootViewController = self.appCoordinator.rootViewController
self.window?.makeKeyAndVisible()
self.accountService.initialAccountsLoading().subscribe(onCompleted: {
self.appCoordinator.start()
guard let currentAccount = self.accountService.currentAccount else {
self.log.error("Can't get current account!")
return
}
self.contactsService.loadContacts(withAccount: currentAccount)
self.contactsService.loadContactRequests(withAccount: currentAccount)
self.presenceService.subscribeBuddies(withAccount: currentAccount, withContacts: self.contactsService.contacts.value)
self.presenceService.subscribeBuddies(withAccount: currentAccount,
withContacts: self.contactsService.contacts.value)
if let ringID = AccountModelHelper(withAccount: currentAccount).ringId {
self.conversationManager?
.prepareConversationsForAccount(accountId: currentAccount.id, accountUri: ringID)
}
}.disposed(by: self.disposeBag)
self.window?.rootViewController = self.appCoordinator.rootViewController
self.window?.makeKeyAndVisible()
}, onError: { _ in
self.appCoordinator.start()
let time = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: time) {
self.appCoordinator.showDatabaseError()
}
}).disposed(by: self.disposeBag)
self.voipRegistry.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(registerVoipNotifications),
name: NSNotification.Name(rawValue: NotificationName.enablePushNotifications.rawValue),
......@@ -236,20 +260,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
}
}
private func startDB() {
do {
let dbManager = DBManager(profileHepler: ProfileDataHelper(),
conversationHelper: ConversationDataHelper(),
interactionHepler: InteractionDataHelper())
try dbManager.start()
} catch {
let time = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: time) {
self.appCoordinator.showDatabaseError()
}
}
}
// swiftlint:disable cyclomatic_complexity
func updateNotificationAvailability() {
let enabled = LocalNotificationsHelper.isEnabled()
......
......@@ -61,11 +61,11 @@ class CallViewModel: Stateable, ViewModel {
// data for ViewController binding
lazy var contactImageData: Observable<Data?>? = {
guard let call = self.call else {
guard let call = self.call, let account = self.accountService.currentAccount else {
return nil
}
return self.profileService.getProfile(ringId: call.participantRingId,
createIfNotexists: true)
createIfNotexists: true, accountId: account.id)
.filter({ profile in
guard let photo = profile.photo else {
return false
......
......@@ -246,6 +246,23 @@ internal enum L10n {
internal static let readableStatusSuccess = L10n.tr("Localizable", "dataTransfer.readableStatusSuccess")
}
internal enum GeneratedMessage {
/// Contact added
internal static let contactAdded = L10n.tr("Localizable", "generatedMessage.contactAdded")
/// Incoming call
internal static let incomingCall = L10n.tr("Localizable", "generatedMessage.incomingCall")
/// Invitation accepted
internal static let invitationAccepted = L10n.tr("Localizable", "generatedMessage.invitationAccepted")
/// Invitation received
internal static let invitationReceived = L10n.tr("Localizable", "generatedMessage.invitationReceived")
/// Missed incoming call
internal static let missedIncomingCall = L10n.tr("Localizable", "generatedMessage.missedIncomingCall")
/// Missed outgoing call
internal static let missedOutgoingCall = L10n.tr("Localizable", "generatedMessage.missedOutgoingCall")
/// Outgoing call
internal static let outgoingCall = L10n.tr("Localizable", "generatedMessage.outgoingCall")
}
internal enum Global {
/// Invitations
internal static let contactRequestsTabBarTitle = L10n.tr("Localizable", "global.contactRequestsTabBarTitle")
......
......@@ -97,7 +97,8 @@ class ContactViewModel: ViewModel, Stateable {
})
.disposed(by: self.disposeBag)
self.profileService.getProfile(ringId: conversation.recipientRingId,
createIfNotexists: false)
createIfNotexists: false,
accountId: conversation.accountId)
.subscribe(onNext: { [unowned self] profile in
if let alias = profile.alias, !alias.isEmpty {
self.displayName.value = alias
......
......@@ -97,21 +97,11 @@ final class AppCoordinator: Coordinator, StateableResponsive {
/// Handles the switch between the three supported screens.
private func dispatchApplication() {
self.injectionBag.accountService
.loadAccounts()
.map({ (accounts) -> Bool in
return !accounts.isEmpty
})
.subscribe(onSuccess: { [unowned self] (hasAccounts) in
if hasAccounts {
self.stateSubject.onNext(AppState.allSet)
} else {
if self.injectionBag.accountService.accounts.isEmpty {
self.stateSubject.onNext(AppState.needToOnboard)
} else {
self.stateSubject.onNext(AppState.allSet)
}
}, onError: { (error) in
print(error)
})
.disposed(by: self.disposeBag)
}
// MARK: - Private methods
......
......@@ -23,30 +23,102 @@ import SwiftyBeaver
enum DataAccessError: Error {
case datastoreConnectionError
case databaseMigrationError
case databaseError
}
final class RingDB {
static let instance = RingDB()
let ringDB: Connection?
final class DBContainer {
var jamiDB: Connection?
private var connections = [String: Connection?]()
private let log = SwiftyBeaver.self
private let dbName = "ring.db"
private let jamiDBName = "ring.db"
private let path: String
private let dbVersion = 1
//tables
var tableProfiles = Table("profiles")
var tableConversations = Table("conversations")
var tableInteractionss = Table("interactions")
private init() {
let path = NSSearchPathForDirectoriesInDomains(
init() {
path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
}
func getJamiDB() -> Connection? {
if jamiDB != nil {
return jamiDB
}
do {
ringDB = try Connection("\(path)/" + dbName)
jamiDB = try Connection("\(path)/" + jamiDBName)
} catch {
ringDB = nil
jamiDB = nil
log.error("Unable to open database")
}
return jamiDB
}
func removeJamiDB() {
self.removeDBNamed(dbName: jamiDBName)
}
func removeDBForAccount(account: String) {
self.removeDBNamed(dbName: "\(account).db")
}
func forAccount(account: String) -> Connection? {
if connections[account] != nil {
return connections[account] ?? nil
}
do {
let accountDb = try Connection("\(path)/" + "\(account).db")
accountDb.userVersion = dbVersion
connections[account] = accountDb
return accountDb
} catch {
log.error("Unable to open database")
return nil
}
}
func isDBExistsFor(account: String) -> Bool {
let url = NSURL(fileURLWithPath: path)
if let pathComponent = url.appendingPathComponent("/" + "\(account).db") {
let filePath = pathComponent.path
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath) {
return false
} else {
return true
}
} else {
return true
}
}
private func removeDBNamed(dbName: String) {
let url = NSURL(fileURLWithPath: path)
guard let pathComponent = url
.appendingPathComponent("/" + dbName) else {
return
}
let filePath = pathComponent.path
let filemManager = FileManager.default
do {
let fileURL = NSURL(fileURLWithPath: filePath)
try filemManager.removeItem(at: fileURL as URL)
print("old database deleted")
} catch {
print("Error on delete old database!!!")
}
}
}
extension Connection {
public var userVersion: Int? {
get {
if let version = try? scalar("PRAGMA user_version"),
let intVersion = version as? Int64 {return Int(intVersion)}
return nil
}
set {
if let version = newValue {_ = try? run("PRAGMA user_version = \(version)")}
}
}
}
......@@ -22,37 +22,50 @@ import SQLite
typealias Conversation = (
id: Int64,
participantID: Int64
participant: String
)
final class ConversationDataHelper {
let table = RingDB.instance.tableConversations
let table = Table("conversations")
let id = Expression<Int64>("id")
let participantId = Expression<Int64>("participant_id")
let participant = Expression<String>("participant")
// reference foreign key
let tableProfiles = Table("profiles")
let uri = Expression<String>("uri")
func createTable() throws {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
// to migrate from legacy db
let participantId = Expression<Int64>("participant_id")
func migrateToDBForAccount(from oldDB: Connection,
to newDB: Connection,
accountProfileId: Int64,
contactsMap: [Int64: String]) throws {
let query = table.filter(accountProfileId != participantId)
let items = try oldDB.prepare(query)
for item in items {
if let uri = contactsMap[item[participantId]] {
let query = table.insert(id <- item[id],
participant <- "ring:" + uri)
try newDB.run(query)
}
}
}
func createTable(accountDb: Connection) {
do {
try dataBase.run(table.create(ifNotExists: true) { table in
try accountDb.run(table.create(ifNotExists: true) { table in
table.column(id)
table.column(participantId)
table.foreignKey(participantId, references: RingDB.instance.tableProfiles, id, delete: .noAction)
table.column(participant)
table.foreignKey(participant, references: tableProfiles, uri, delete: .noAction)
})
} catch _ {
print("Table already exists")
}
}
func insert(item: Conversation) -> Bool {
guard let dataBase = RingDB.instance.ringDB else {
return false
}
func insert(item: Conversation, dataBase: Connection) -> Bool {
let query = table.insert(id <- item.id,
participantId <- item.participantID)
participant <- item.participant)
do {
let rowId = try dataBase.run(query)
guard rowId > 0 else {
......@@ -64,10 +77,7 @@ final class ConversationDataHelper {
}
}
func delete (item: Conversation) -> Bool {
guard let dataBase = RingDB.instance.ringDB else {
return false
}
func delete (item: Conversation, dataBase: Connection) -> Bool {
let conversationId = item.id
let query = table.filter(id == conversationId)
do {
......@@ -81,48 +91,36 @@ final class ConversationDataHelper {
}
}
func selectConversations (conversationId: Int64) throws -> [Conversation]? {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
}
func selectConversations (conversationId: Int64, dataBase: Connection) throws -> [Conversation]? {
let query = table.filter(id == conversationId)
var conversations = [Conversation]()
let items = try dataBase.prepare(query)
for item in items {
conversations.append(Conversation(id: item[id], participantID: item[participantId]))
conversations.append(Conversation(id: item[id], participant: item[participant]))
}
return conversations
}
func selectAll() throws -> [Conversation]? {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
}
func selectAll(dataBase: Connection) throws -> [Conversation]? {
var conversations = [Conversation]()
let items = try dataBase.prepare(table)
for item in items {
conversations.append(Conversation(id: item[id], participantID: item[participantId]))
conversations.append(Conversation(id: item[id], participant: item[participant]))
}
return conversations
}
func selectConversationsForProfile(profileId: Int64) throws -> [Conversation]? {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
}
func selectConversationsForProfile(profileUri: String, dataBase: Connection) throws -> [Conversation]? {
var conversations = [Conversation]()
let query = table.filter(participantId == profileId)
let query = table.filter(participant == profileUri)
let items = try dataBase.prepare(query)
for item in items {
conversations.append(Conversation(id: item[id], participantID: item[participantId]))
conversations.append(Conversation(id: item[id], participant: item[participant]))
}
return conversations
}
func deleteConversations(conversationID: Int64) -> Bool {
guard let dataBase = RingDB.instance.ringDB else {
return false
}
func deleteConversations(conversationID: Int64, dataBase: Connection) -> Bool {
let query = table.filter(id == conversationID)
do {
if try dataBase.run(query.delete()) > 0 {
......
......@@ -22,52 +22,122 @@ import SQLite
import SwiftyBeaver
typealias Profile = (
id: Int64,
uri: String,
alias: String?,
photo: String?,
type: String,
status: String
type: String
)
final class ProfileDataHelper {
let table = RingDB.instance.tableProfiles
let id = Expression<Int64>("id")
let contactsProfileTable = Table("profiles")
let accountProfileTable = Table("account_profile")
let uri = Expression<String>("uri")
let alias = Expression<String?>("alias")
let photo = Expression<String?>("photo")
let type = Expression<String>("type")
let status = Expression<String>("status")
private let log = SwiftyBeaver.self
func createTable() throws {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
//migrate from legacy db
let id = Expression<Int64>("id")
func getLegacyProfileID(profileURI: String, dataBase: Connection) throws -> Int64? {
let query = contactsProfileTable.filter(uri == profileURI)
let items = try dataBase.prepare(query)
for item in items {
return item[id]
}
return nil
}
func getLegacyProfiles(accountURI: String,
accountId: String,
database: Connection) throws -> [Int64: String] {
let query = contactsProfileTable.filter(accountId != uri && accountURI != uri)
let items = try database.prepare(query)
var profiles = [Int64: String]()
for item in items {
profiles[item[id]] = item[uri]
}
return profiles
}
func migrateToDBForAccount (from oldDB: Connection,
to newDB: Connection,
jamiId: String,
accountId: String) throws {
// migrate account profile
// get account profile, it should be only one
let accountQuery = contactsProfileTable.filter(uri == jamiId)
let items = try oldDB.prepare(accountQuery)
for item in items {
let query = accountProfileTable.insert(alias <- item[alias],
photo <- item[photo])
try newDB.run(query)
}
//migrate contacts rofiles
let contactQuery = contactsProfileTable.filter((uri != jamiId) && (uri != accountId))
let rows = try oldDB.prepare(contactQuery)
for row in rows {
let query = contactsProfileTable.insert(uri <- "ring:" + row[uri],
alias <- row[alias],
photo <- row[photo],
type <- row[type])
try newDB.run(query)
}
}
func createAccountTable(accountDb: Connection) {
do {
try dataBase.run(table.create(ifNotExists: true) { table in
table.column(id, primaryKey: .autoincrement)
table.column(uri)
try accountDb.run(accountProfileTable.create(ifNotExists: true) { table in
table.column(alias)
table.column(photo)
table.column(type)
table.column(status)
})
} catch _ {
log.error("Table exists")
print("Table already exists")
}
}
func insert(item: Profile) -> Bool {
guard let dataBase = RingDB.instance.ringDB else {
func updateAccountProfile(accountAlias: String?, accountPhoto: String?, dataBase: Connection) -> Bool {
do {
if try dataBase.pluck(accountProfileTable) != nil {
try dataBase.run(accountProfileTable.update(alias <- accountAlias,
photo <- accountPhoto))
} else {
try dataBase.run(accountProfileTable.insert(alias <- accountAlias,
photo <- accountPhoto))
}
return true
} catch {
return false
}
}
let query = table.insert(uri <- item.uri,
func getAccountProfile(dataBase: Connection) -> AccountProfile? {
do {
guard let row = try dataBase.pluck(accountProfileTable) else { return nil}
return (row[alias], row[photo])
} catch {
return nil
}
}
func createContactsTable(accountDb: Connection) {
do {
try accountDb.run(contactsProfileTable.create(ifNotExists: true) { table in
table.column(uri, unique: true)
table.column(alias)
table.column(photo)
table.column(type)
})
try accountDb.run(contactsProfileTable.createIndex(uri))
} catch _ {
print("Table already exists")
}
}
func insert(item: Profile, dataBase: Connection) -> Bool {
let query = contactsProfileTable.insert(uri <- item.uri,
alias <- item.alias,
photo <- item.photo,
type <- item.type,
status <- item.status)
type <- item.type)
do {
let rowId = try dataBase.run(query)
guard rowId > 0 else {
......@@ -77,15 +147,11 @@ final class ProfileDataHelper {
} catch _ {
return false
}
}
func delete(item: Profile) -> Bool {
guard let dataBase = RingDB.instance.ringDB else {
return false
}
let profileId = item.id
let query = table.filter(id == profileId)
func delete(item: Profile, dataBase: Connection) -> Bool {
let profileUri = item.uri
let query = contactsProfileTable.filter(uri == profileUri)
do {
let deletedRows = try dataBase.run(query.delete())
guard deletedRows == 1 else {
......@@ -97,63 +163,39 @@ final class ProfileDataHelper {
}
}
func selectProfile(profileId: Int64) throws -> Profile? {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
}
let query = table.filter(id == profileId)
let items = try dataBase.prepare(query)
for item in items {
return Profile(id: item[id], uri: item[uri], alias: item[alias],
photo: item[photo], type: item[type], status: item[status])
}
return nil
}
func selectAll() throws -> [Profile]? {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
}
func selectAll(dataBase: Connection) throws -> [Profile]? {
var profiles = [Profile]()
let items = try dataBase.prepare(table)
let items = try dataBase.prepare(contactsProfileTable)
for item in items {