Skip to content
Snippets Groups Projects
Commit c9c29db4 authored by Bruno Muniz's avatar Bruno Muniz :apple:
Browse files

Removed database old package files

parent 32a363d5
No related branches found
No related tags found
2 merge requests!40v1.1.2b166,!38Using new database structure
import GRDB
import Models
extension Contact: Persistable {
public enum Column: String, ColumnExpression {
case id
case photo
case email
case phone
case userId
case status
case username
case isRecent
case nickname
case marshaled
case createdAt
}
public mutating func didInsert(with rowID: Int64, for column: String?) {
id = rowID
}
public static func query(_ request: Request) -> QueryInterfaceRequest<Contact> {
switch request {
case .all:
return Contact.all()
case .isRecent:
return Contact
.filter(Column.isRecent == true)
.order(Column.createdAt.desc)
case .verificationInProgress:
return Contact.filter(Column.status == Contact.Status.verificationInProgress.rawValue)
case .failed:
return Contact.filter(
Column.status == Contact.Status.requestFailed.rawValue ||
Column.status == Contact.Status.confirmationFailed.rawValue
)
case .requested:
return Contact.filter(
Column.status == Contact.Status.requested.rawValue ||
Column.status == Contact.Status.requesting.rawValue
)
case .received:
return Contact.filter(
Column.status == Contact.Status.hidden.rawValue ||
Column.status == Contact.Status.verified.rawValue ||
Column.status == Contact.Status.verificationFailed.rawValue ||
Column.status == Contact.Status.verificationInProgress.rawValue
)
case .friends: return Contact.filter(Column.status == Contact.Status.friend.rawValue)
case let .withUserId(data): return Contact.filter(Column.userId == data)
case let .withUserIds(ids): return Contact.filter(ids.contains(Contact.Column.userId))
case let .withUsername(username): return Contact.filter(Column.username.like("\(username)%"))
}
}
}
import GRDB
import Models
extension FileTransfer: Persistable {
public enum Column: String, ColumnExpression {
case id
case tid
case contact
case fileName
case fileType
case isIncoming
}
public mutating func didInsert(with rowID: Int64, for column: String?) {
id = rowID
}
public static func query(_ request: Request) -> QueryInterfaceRequest<FileTransfer> {
switch request {
case .withTID(let transferId):
return FileTransfer.filter(Column.tid == transferId)
case .withContactId(let contactId):
return FileTransfer.filter(Column.contact == contactId)
}
}
}
import GRDB
import Models
extension Group: Persistable {
static let members = hasMany(GroupMember.self)
public enum Column: String, ColumnExpression {
case id
case name
case leader
case groupId
case status
case serialize
case createdAt
case accepted // Deprecated
}
public mutating func didInsert(with rowID: Int64, for column: String?) {
id = rowID
}
public static func query(_ request: Request) -> QueryInterfaceRequest<Group> {
switch request {
case .withGroupId(let id):
return Group.filter(Column.groupId == id)
case .accepted:
return Group.filter(Column.status == Group.Status.participating.rawValue)
case .pending:
return Group.filter(
Column.status == Group.Status.pending.rawValue ||
Column.status == Group.Status.hidden.rawValue
)
}
}
}
import GRDB
import Models
extension GroupChatInfo: Requestable {
public static func query(_ request: Request) -> QueryInterfaceRequest<GroupChatInfo> {
let lastMessageRequest = GroupMessage
.annotated(with: max(GroupMessage.Column.timestamp))
.group(GroupMessage.Column.groupId)
let lastMessageCTE = CommonTableExpression<GroupMessage>(
named: "lastMessage",
request: lastMessageRequest
)
let lastMessage = Group.association(to: lastMessageCTE) { group, lastMessage in
lastMessage[GroupMessage.Column.groupId] == group[Group.Column.groupId]
}.order(GroupMessage.Column.timestamp.desc)
switch request {
case .fromGroup(let groupId):
return Group
.filter(Group.Column.status == Group.Status.participating.rawValue)
.filter(Group.Column.groupId == groupId)
.with(lastMessageCTE)
.including(optional: lastMessage)
.including(all: Group.members.forKey("members"))
.asRequest(of: Self.self)
case .accepted:
return Group
.filter(Group.Column.status == Group.Status.participating.rawValue)
.with(lastMessageCTE)
.including(optional: lastMessage)
.including(all: Group.members.forKey("members"))
.asRequest(of: Self.self)
}
}
}
import GRDB
import Models
extension GroupMember: Persistable {
public enum Column: String, ColumnExpression {
case id
case photo
case status
case userId
case groupId
case username
}
public mutating func didInsert(with rowID: Int64, for column: String?) {
id = rowID
}
public static func query(_ request: Request) -> QueryInterfaceRequest<GroupMember> {
switch request {
case .all:
return GroupMember.all()
case let .withUserId(userId):
return GroupMember.filter(Column.userId == userId)
case .fromGroup(let groupId):
return GroupMember.filter(Column.groupId == groupId)
case .strangers:
return GroupMember.filter(
Column.status == GroupMember.Status.pendingUsername.rawValue
)
}
}
}
import GRDB
import Models
extension GroupMessage: Persistable {
public enum Column: String, ColumnExpression {
case id
case sender
case status
case unread
case payload
case groupId
case uniqueId
case roundURL
case timestamp
case roundId
}
public mutating func didInsert(with rowID: Int64, for column: String?) {
id = rowID
}
public static func query(_ request: Request) -> QueryInterfaceRequest<GroupMessage> {
switch request {
case let .withUniqueId(id):
return GroupMessage.filter(Column.uniqueId == id)
case let .id(id):
return GroupMessage.filter(Column.id == id)
case let .fromGroup(id):
return GroupMessage.filter(Column.groupId == id).order(Column.timestamp.asc)
case let .unreadsFromGroup(id):
return GroupMessage.filter(Column.groupId == id).filter(Column.unread == true)
case .sending:
return GroupMessage.filter(Column.status == GroupMessage.Status.sending.rawValue)
}
}
}
import GRDB
import Models
extension Message: Persistable {
public enum Column: String, ColumnExpression {
case id
case report
case sender
case unread
case status
case payload
case roundURL
case receiver
case uniqueId
case timestamp
}
public mutating func didInsert(with rowID: Int64, for column: String?) {
id = rowID
}
public static func query(_ request: Request) -> QueryInterfaceRequest<Message> {
switch request {
case let .withUniqueId(id):
return Message.filter(Column.uniqueId == id)
case let .unreadsFromContactId(id):
return Message
.filter(Column.sender == id || Column.receiver == id)
.filter(Column.unread == true)
case let .latestOnesFromContactIds(ids):
return Message
.annotated(with: Column.timestamp)
.filter(ids.contains(Column.sender) || ids.contains(Column.receiver))
case let .withId(id):
return Message.filter(Column.id == id)
case let .withContact(id):
return Message.filter(Column.sender == id || Column.receiver == id)
case .sending:
return Message.filter(Column.status == Message.Status.sending.rawValue)
case .sendingAttachment:
return Message.filter(Column.status == Message.Status.sendingAttachment.rawValue)
}
}
}
import GRDB
import Models
extension SingleChatInfo: Requestable {
public static func query(_ request: Request) -> QueryInterfaceRequest<SingleChatInfo> {
let lastMessageRequest = Message
.annotated(with: max(Message.Column.timestamp))
.group(Message.Column.sender || Message.Column.receiver)
let lastMessageCTE = CommonTableExpression<Message>(
named: "lastMessage",
request: lastMessageRequest
)
let lastMessage = Contact.association(to: lastMessageCTE) { contact, lastMessage in
lastMessage[Message.Column.sender] == contact[Contact.Column.userId] ||
lastMessage[Message.Column.receiver] == contact[Contact.Column.userId]
}.order(Message.Column.timestamp.desc)
switch request {
case .all:
return Contact.with(lastMessageCTE)
.including(required: lastMessage)
.asRequest(of: Self.self)
}
}
}
import GRDB
import Models
import Combine
import Foundation
public protocol Requestable: FetchableRecord {
associatedtype Request
static func query(_ request: Request) -> QueryInterfaceRequest<Self>
}
public protocol Persistable: Requestable & MutablePersistableRecord & Identifiable {
var id: Int64? { get }
}
public protocol DatabaseManager {
func drop()
func setup() throws
func updateAll<T>(_ type: T.Type,
_ request: T.Request,
with: [ColumnAssignment]) throws where T: Persistable
@discardableResult func save<T>(_ model: T) throws -> T where T: Persistable
func update<T>(_ model: T) throws where T: Persistable
func delete<T>(_ model: T) throws where T: Persistable
func fetch<T>(_ request: T.Request) throws -> [T] where T: Requestable
func fetch<T>(withId id: Int64) throws -> T? where T: Persistable
func publisher<T>(fetch request: T.Request) -> AnyPublisher<[T], Error> where T: Requestable
func delete<T>(_ type: T.Type, _ request: T.Request) throws where T: Persistable
}
public extension DatabaseManager {
func publisher<T: Requestable>(
fetch type: T.Type,
_ request: T.Request
) -> AnyPublisher<[T], Error> {
publisher(fetch: request)
}
}
public final class GRDBDatabaseManager {
var databaseQueue: DatabaseQueue!
public init() {}
}
extension GRDBDatabaseManager: DatabaseManager {
public func drop() {
try? databaseQueue.write { db in
try db.drop(table: Contact.databaseTableName)
try db.drop(table: Message.databaseTableName)
try db.drop(table: Group.databaseTableName)
try db.drop(table: GroupMember.databaseTableName)
try db.drop(table: GroupMessage.databaseTableName)
}
}
public func updateAll<T>(_ type: T.Type,
_ request: T.Request,
with assignments: [ColumnAssignment]) throws where T : Persistable {
_ = try databaseQueue.write {
try T.query(request).updateAll($0, assignments)
}
}
public func save<T: Persistable>(_ model: T) throws -> T {
try databaseQueue.write { db in
var model = model
if model.id == nil {
try model.insert(db)
} else {
try model.update(db)
}
return model
}
}
public func update<T>(_ model: T) throws where T: Persistable {
try databaseQueue.write { try model.update($0) }
}
public func fetch<T>(withId id: Int64) throws -> T? where T: Persistable {
try databaseQueue.read { db in
try T.fetchOne(db, key: id)
}
}
public func fetch<T>(_ request: T.Request) throws -> [T] where T: Requestable {
try databaseQueue.read { db in
try T.query(request).fetchAll(db)
}
}
public func publisher<T>(fetch request: T.Request) -> AnyPublisher<[T], Error> where T: Requestable {
ValueObservation.tracking {
try T.query(request).fetchAll($0)
}.publisher(in: databaseQueue, scheduling: .immediate)
.eraseToAnyPublisher()
}
public func delete<T>(_ model: T) throws where T: Persistable {
_ = try databaseQueue.write {
try model.delete($0)
}
}
public func delete<T>(_ type: T.Type, _ request: T.Request) throws where T: Persistable {
_ = try databaseQueue.write {
try T.query(request).deleteAll($0)
}
}
public func setup() throws {
var migrator = DatabaseMigrator()
let oldPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
.appending("/xxmessenger.sqlite")
let url = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: "group.elixxir.messenger")!
.appendingPathComponent("database")
.appendingPathExtension("sqlite")
if FileManager.default.fileExists(atPath: oldPath) && !FileManager.default.fileExists(atPath: url.path) {
do {
try FileManager.default.moveItem(atPath: oldPath, toPath: url.path)
} catch {
fatalError("Couldn't migrate database from old path to new one: \(error.localizedDescription)")
}
}
databaseQueue = try DatabaseQueue(path: url.path)
try FileManager.default.setAttributes([
.protectionKey : FileProtectionType.completeUntilFirstUserAuthentication
], ofItemAtPath: url.path)
migrator.registerMigration("v1") { db in
try db.create(table: Contact.databaseTableName, ifNotExists: true) { table in
table.autoIncrementedPrimaryKey(Contact.Column.id.rawValue, onConflict: .replace)
table.column(Contact.Column.photo.rawValue, .blob)
table.column(Contact.Column.email.rawValue, .text)
table.column(Contact.Column.phone.rawValue, .text)
table.column(Contact.Column.nickname.rawValue, .text)
table.column(Contact.Column.createdAt.rawValue, .datetime)
table.column(Contact.Column.userId.rawValue, .blob).unique()
table.column(Contact.Column.username.rawValue, .text).notNull()
table.column(Contact.Column.status.rawValue, .integer).notNull()
table.column(Contact.Column.marshaled.rawValue, .blob).notNull()
}
try db.create(table: Message.databaseTableName, ifNotExists: true) { table in
table.autoIncrementedPrimaryKey(Message.Column.id.rawValue, onConflict: .replace)
table.column(Message.Column.report.rawValue, .blob)
table.column(Message.Column.uniqueId.rawValue, .blob)
table.column(Message.Column.sender.rawValue, .blob).notNull()
table.column(Message.Column.payload.rawValue, .text).notNull()
table.column(Message.Column.receiver.rawValue, .blob).notNull()
table.column(Message.Column.roundURL.rawValue, .text)
table.column(Message.Column.status.rawValue, .integer).notNull()
table.column(Message.Column.unread.rawValue, .boolean).notNull()
table.column(Message.Column.timestamp.rawValue, .integer).notNull()
}
try db.create(table: Group.databaseTableName, ifNotExists: true) { table in
table.autoIncrementedPrimaryKey(Group.Column.id.rawValue, onConflict: .replace)
table.column(Group.Column.groupId.rawValue, .blob).unique()
table.column(Group.Column.name.rawValue, .text).notNull()
table.column(Group.Column.leader.rawValue, .blob).notNull()
table.column(Group.Column.serialize.rawValue, .blob).notNull()
table.column(Group.Column.accepted.rawValue, .boolean).notNull()
}
try db.create(table: GroupMember.databaseTableName, ifNotExists: true) { table in
table.autoIncrementedPrimaryKey(GroupMember.Column.id.rawValue, onConflict: .replace)
table.column(GroupMember.Column.userId.rawValue, .blob).notNull()
table.column(GroupMember.Column.username.rawValue, .text).notNull()
table.column(GroupMember.Column.photo.rawValue, .blob)
table.column(GroupMember.Column.status.rawValue, .integer).notNull()
table.column(GroupMember.Column.groupId.rawValue, .blob).notNull()
.references(
Group.databaseTableName,
column: Group.Column.groupId.rawValue,
onDelete: .cascade,
deferred: true
)
}
try db.create(table: GroupMessage.databaseTableName, ifNotExists: true) { table in
table.autoIncrementedPrimaryKey(GroupMessage.Column.id.rawValue, onConflict: .replace)
table.column(GroupMessage.Column.uniqueId.rawValue, .blob)
table.column(GroupMessage.Column.roundId.rawValue, .integer)
table.column(GroupMessage.Column.groupId.rawValue, .blob).notNull()
table.column(GroupMessage.Column.sender.rawValue, .blob).notNull()
table.column(GroupMessage.Column.roundURL.rawValue, .text)
table.column(GroupMessage.Column.payload.rawValue, .text).notNull()
table.column(GroupMessage.Column.status.rawValue, .integer).notNull()
table.column(GroupMessage.Column.unread.rawValue, .boolean).notNull()
table.column(GroupMessage.Column.timestamp.rawValue, .integer).notNull()
}
try db.create(table: FileTransfer.databaseTableName, ifNotExists: true) { table in
table.autoIncrementedPrimaryKey(FileTransfer.Column.id.rawValue, onConflict: .replace)
table.column(FileTransfer.Column.tid.rawValue, .blob).notNull()
table.column(FileTransfer.Column.contact.rawValue, .blob).notNull()
table.column(FileTransfer.Column.fileName.rawValue, .text).notNull()
table.column(FileTransfer.Column.fileType.rawValue, .text).notNull()
table.column(FileTransfer.Column.isIncoming.rawValue, .boolean).notNull()
}
}
migrator.registerMigration("v1: Updating contact/group requests UI") { db in
try db.create(table: "temp_\(Group.databaseTableName)") { table in
table.autoIncrementedPrimaryKey(Group.Column.id.rawValue, onConflict: .replace)
table.column(Group.Column.groupId.rawValue, .blob).unique()
table.column(Group.Column.name.rawValue, .text).notNull()
table.column(Group.Column.leader.rawValue, .blob).notNull()
table.column(Group.Column.serialize.rawValue, .blob).notNull()
table.column(Group.Column.status.rawValue, .integer).notNull()
table.column(Group.Column.createdAt.rawValue, .datetime).notNull()
}
let oldRows = try Row.fetchCursor(db, sql: "SELECT * FROM \(Group.databaseTableName)")
while let row = try oldRows.next() {
let status: Group.Status
if row["accepted"] == true {
status = .participating
} else {
status = .pending
}
try db.execute(
sql: "INSERT INTO temp_\(Group.databaseTableName) (id, groupId, name, leader, serialize, status, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?)",
arguments:
[row["id"],
row["groupId"],
row["name"],
row["leader"],
row["serialize"],
status.rawValue,
Date()
])
}
try db.drop(table: Group.databaseTableName)
try db.rename(table: "temp_\(Group.databaseTableName)", to: Group.databaseTableName)
}
migrator.registerMigration("v2") { db in
try db.alter(table: Contact.databaseTableName) { table in
table.add(column: Contact.Column.isRecent.rawValue, .boolean)
}
try Contact.updateAll(db, Contact.Column.isRecent.set(to: false))
}
try migrator.migrate(databaseQueue)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment