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()
self.appCoordinator.start()
}, 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 {
self.stateSubject.onNext(AppState.needToOnboard)
}
}, onError: { (error) in
print(error)
})
.disposed(by: self.disposeBag)
if self.injectionBag.accountService.accounts.isEmpty {
self.stateSubject.onNext(AppState.needToOnboard)
} else {
self.stateSubject.onNext(AppState.allSet)
}
}
// 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 {
jamiDB = try Connection("\(path)/" + jamiDBName)
} catch {
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 {
ringDB = try Connection("\(path)/" + dbName)
let accountDb = try Connection("\(path)/" + "\(account).db")
accountDb.userVersion = dbVersion
connections[account] = accountDb
return accountDb
} catch {
ringDB = nil
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,10 +22,10 @@ import SQLite
typealias Interaction = (
id: Int64,
accountID: Int64,
authorID: Int64,
conversationID: Int64,
author: String?,
conversation: Int64,
timestamp: Int64,
duration: Int64,
body: String,
type: String,
status: String,
......@@ -35,11 +35,11 @@ typealias Interaction = (
final class InteractionDataHelper {
let table = RingDB.instance.tableInteractionss
let table = Table("interactions")
let id = Expression<Int64>("id")
let accountId = Expression<Int64>("account_id")
let authorId = Expression<Int64>("author_id")
let conversationId = Expression<Int64>("conversation_id")
let author = Expression<String?>("author")
let duration = Expression<Int64>("duration")
let conversation = Expression<Int64>("conversation")
let timestamp = Expression<Int64>("timestamp")
let body = Expression<String>("body")
let type = Expression<String>("type")
......@@ -47,43 +47,93 @@ final class InteractionDataHelper {
let daemonId = Expression<String>("daemon_id")
let incoming = Expression<Bool>("incoming")
func createTable() throws {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
//foreign keys references
let tableProfiles = Table("profiles")
let tableConversations = Table("conversations")
let uri = Expression<String>("uri")
//migrations from legacy db
let authorId = Expression<Int64>("author_id")
let conversationId = Expression<Int64>("conversation_id")
func migrateToDBForAccount (from oldDB: Connection,
to newDB: Connection,
accountProfileId: Int64,
contactsMap: [Int64: String]) throws {
let items = try oldDB.prepare(table)
for item in items {
let uri: String? = (contactsMap[item[authorId]] != nil) ? "ring:" + contactsMap[item[authorId]]! : nil
let migrationData = self.migrateMessageBody(body: item[body], type: item[type])
let query = table.insert(id <- item[id],
author <- uri,
conversation <- item[conversationId],
timestamp <- item[timestamp],
duration <- migrationData.duration,
body <- migrationData.body,
type <- item[type],
status <- item[status],
daemonId <- item[daemonId],
incoming <- item[incoming])
try newDB.run(query)
}
}
func migrateMessageBody(body: String, type: String) -> (body: String, duration: Int64) {
switch type {
case InteractionType.call.rawValue:
//check if have call duration
if let index = body.firstIndex(of: "-") {
let timeIndex = body.index(index, offsetBy: 2)
let durationString = body.suffix(from: timeIndex)
let time = String(durationString).convertToSeconds()
let messageBody = String(body.prefix(upTo: index))
if messageBody.contains(GeneratedMessageType.incomingCall.rawValue) {
return(GeneratedMessage.incomingCall.toString(), time)
} else {
return(GeneratedMessage.outgoingCall.toString(), time)
}
} else if body == GeneratedMessageType.missedIncomingCall.rawValue {
return(GeneratedMessage.missedIncomingCall.toString(), 0)
} else {
return(GeneratedMessage.missedOutgoingCall.toString(), 0)
}
case InteractionType.contact.rawValue:
if body == GeneratedMessageType.contactAdded.rawValue {
return(GeneratedMessage.contactAdded.toString(), 0)
} else {
return(GeneratedMessage.invitationReceived.toString(), 0)
}
default:
return (body, 0)
}
}
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, primaryKey: .autoincrement)
table.column(accountId)
table.column(authorId)
table.column(conversationId)
table.column(author)
table.column(conversation)
table.column(timestamp)
table.column(duration)
table.column(body)
table.column(type)
table.column(status)
table.column(daemonId)
table.column(incoming)
table.foreignKey(accountId,
references: RingDB.instance.tableProfiles, id, delete: .noAction)
table.foreignKey(authorId,
references: RingDB.instance.tableProfiles, id, delete: .noAction)
table.foreignKey(conversationId,
references: RingDB.instance.tableConversations, id, delete: .noAction)
table.foreignKey(author,
references: tableProfiles, uri, delete: .noAction)
table.foreignKey(conversation,
references: tableConversations, id, delete: .noAction)
})
} catch _ {
print("Table already exists")
}
}
func insert(item: Interaction) -> Int64? {
guard let dataBase = RingDB.instance.ringDB else {
return nil
}
let query = table.insert(accountId <- item.accountID,
authorId <- item.authorID,
conversationId <- item.conversationID,
func insert(item: Interaction, dataBase: Connection) -> Int64? {
let query = table.insert(duration <- item.duration,
author <- item.author,
conversation <- item.conversation,
timestamp <- item.timestamp,
body <- item.body,
type <- item.type,
......@@ -101,12 +151,9 @@ final class InteractionDataHelper {
}
}
func delete (item: Interaction) -> Bool {
guard let dataBase = RingDB.instance.ringDB else {
return false
}
let profileId = item.id
let query = table.filter(id == profileId)
func delete (item: Interaction, dataBase: Connection) -> Bool {
let interactionId = item.id
let query = table.filter(id == interactionId)
do {
let deletedRows = try dataBase.run(query.delete())
guard deletedRows == 1 else {
......@@ -118,18 +165,15 @@ final class InteractionDataHelper {
}
}
func selectInteraction (interactionId: Int64) throws -> Interaction? {
guard let dataBase = RingDB.instance.ringDB else {
throw DataAccessError.datastoreConnectionError
}
func selectInteraction (interactionId: Int64, dataBase: Connection) throws -> Interaction? {
let query = table.filter(id == interactionId)
let items = try dataBase.prepare(query)
for item in items {
return Interaction(id: item[id],
accountID: item[accountId],
authorID: item[authorId],
conversationID: item[conversationId],
author: item[author],
conversation: item[conversation],
timestamp: item[timestamp],
duration: item[duration],
body: item[body],
type: item[type],
status: item