mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
5.1 KiB
Swift
111 lines
5.1 KiB
Swift
3 years ago
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||
|
|
||
|
import GRDB
|
||
|
import SessionUtilitiesKit
|
||
|
|
||
|
public struct MentionInfo: FetchableRecord, Decodable {
|
||
|
fileprivate static let threadVariantKey: SQL = SQL(stringLiteral: CodingKeys.threadVariant.stringValue)
|
||
|
fileprivate static let openGroupServerKey: SQL = SQL(stringLiteral: CodingKeys.openGroupServer.stringValue)
|
||
|
fileprivate static let openGroupRoomTokenKey: SQL = SQL(stringLiteral: CodingKeys.openGroupRoomToken.stringValue)
|
||
|
|
||
|
fileprivate static let profileString: String = CodingKeys.profile.stringValue
|
||
|
|
||
|
public let profile: Profile
|
||
|
public let threadVariant: SessionThread.Variant
|
||
|
public let openGroupServer: String?
|
||
|
public let openGroupRoomToken: String?
|
||
|
}
|
||
|
|
||
|
public extension MentionInfo {
|
||
|
static func query(
|
||
|
userPublicKey: String,
|
||
|
threadId: String,
|
||
|
threadVariant: SessionThread.Variant,
|
||
|
targetPrefix: SessionId.Prefix,
|
||
|
pattern: FTS5Pattern?
|
||
|
) -> AdaptedFetchRequest<SQLRequest<MentionInfo>>? {
|
||
|
guard threadVariant != .contact || userPublicKey != threadId else { return nil }
|
||
|
|
||
|
let profile: TypedTableAlias<Profile> = TypedTableAlias()
|
||
|
let interaction: TypedTableAlias<Interaction> = TypedTableAlias()
|
||
|
let openGroup: TypedTableAlias<OpenGroup> = TypedTableAlias()
|
||
|
|
||
|
let prefixLiteral: SQL = SQL(stringLiteral: "\(targetPrefix.rawValue)%")
|
||
|
let profileFullTextSearch: SQL = SQL(stringLiteral: Profile.fullTextSearchTableName)
|
||
|
|
||
|
/// **Note:** The `\(MentionInfo.profileKey).*` value **MUST** be first
|
||
|
let limitSQL: SQL? = (threadVariant == .openGroup ? SQL("LIMIT 20") : nil)
|
||
|
|
||
|
let request: SQLRequest<MentionInfo> = {
|
||
|
guard let pattern: FTS5Pattern = pattern else {
|
||
|
return """
|
||
|
SELECT
|
||
|
\(Profile.self).*,
|
||
|
MAX(\(interaction[.timestampMs])), -- Want the newest interaction (for sorting)
|
||
|
\(SQL("\(threadVariant) AS \(MentionInfo.threadVariantKey)")),
|
||
|
\(openGroup[.server]) AS \(MentionInfo.openGroupServerKey),
|
||
|
\(openGroup[.roomToken]) AS \(MentionInfo.openGroupRoomTokenKey)
|
||
|
|
||
|
FROM \(Profile.self)
|
||
|
JOIN \(Interaction.self) ON (
|
||
|
\(SQL("\(interaction[.threadId]) = \(threadId)")) AND
|
||
|
\(interaction[.authorId]) = \(profile[.id])
|
||
|
)
|
||
|
LEFT JOIN \(OpenGroup.self) ON \(SQL("\(openGroup[.threadId]) = \(threadId)"))
|
||
|
|
||
|
WHERE (
|
||
|
\(SQL("\(profile[.id]) != \(userPublicKey)")) AND (
|
||
|
\(SQL("\(threadVariant) != \(SessionThread.Variant.openGroup)")) OR
|
||
|
\(SQL("\(profile[.id]) LIKE '\(prefixLiteral)'"))
|
||
|
)
|
||
|
)
|
||
|
GROUP BY \(profile[.id])
|
||
|
ORDER BY \(interaction[.timestampMs].desc)
|
||
|
\(limitSQL ?? "")
|
||
|
"""
|
||
|
}
|
||
|
|
||
|
// If we do have a search patern then use FTS
|
||
|
let matchLiteral: SQL = SQL(stringLiteral: "\(Profile.Columns.nickname.name):\(pattern.rawPattern) OR \(Profile.Columns.name.name):\(pattern.rawPattern)")
|
||
|
|
||
|
return """
|
||
|
SELECT
|
||
|
\(Profile.self).*,
|
||
|
MAX(\(interaction[.timestampMs])), -- Want the newest interaction (for sorting)
|
||
|
\(SQL("\(threadVariant) AS \(MentionInfo.threadVariantKey)")),
|
||
|
\(openGroup[.server]) AS \(MentionInfo.openGroupServerKey),
|
||
|
\(openGroup[.roomToken]) AS \(MentionInfo.openGroupRoomTokenKey)
|
||
|
|
||
|
FROM \(profileFullTextSearch)
|
||
|
JOIN \(Profile.self) ON (
|
||
|
\(Profile.self).rowid = \(profileFullTextSearch).rowid AND
|
||
|
\(SQL("\(profile[.id]) != \(userPublicKey)")) AND (
|
||
|
\(SQL("\(threadVariant) != \(SessionThread.Variant.openGroup)")) OR
|
||
|
\(SQL("\(profile[.id]) LIKE '\(prefixLiteral)'"))
|
||
|
)
|
||
|
)
|
||
|
JOIN \(Interaction.self) ON (
|
||
|
\(SQL("\(interaction[.threadId]) = \(threadId)")) AND
|
||
|
\(interaction[.authorId]) = \(profile[.id])
|
||
|
)
|
||
|
LEFT JOIN \(OpenGroup.self) ON \(SQL("\(openGroup[.threadId]) = \(threadId)"))
|
||
|
|
||
|
WHERE \(profileFullTextSearch) MATCH '\(matchLiteral)'
|
||
|
GROUP BY \(profile[.id])
|
||
|
ORDER BY \(interaction[.timestampMs].desc)
|
||
|
\(limitSQL ?? "")
|
||
|
"""
|
||
|
}()
|
||
|
|
||
|
return request.adapted { db in
|
||
|
let adapters = try splittingRowAdapters(columnCounts: [
|
||
|
Profile.numberOfSelectedColumns(db)
|
||
|
])
|
||
|
|
||
|
return ScopeAdapter([
|
||
|
MentionInfo.profileString: adapters[0]
|
||
|
])
|
||
|
}
|
||
|
}
|
||
|
}
|