Skip to content

Commit 518b8e7

Browse files
committed
MatrixRoomState
1 parent b9bfe92 commit 518b8e7

File tree

4 files changed

+121
-14
lines changed

4 files changed

+121
-14
lines changed

Sources/MatrixSQLiteStore/MatrixSQLiteStore.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import GRDB
44
import MatrixClient
55
import MatrixCore
66

7+
@available(swift, introduced: 5.5)
8+
@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
79
public struct MatrixSQLiteStore {
810
var dbWriter: DatabaseWriter
911

@@ -17,6 +19,9 @@ public struct MatrixSQLiteStore {
1719
try migrate()
1820
}
1921

22+
/// Create a database in memory, useful to feed previews with data.
23+
///
24+
/// This uses a `DatabaseQueue`, therefore a not advised for production use.
2025
public static func inMemory() -> Self {
2126
try! MatrixSQLiteStore(DatabaseQueue())
2227
}
@@ -47,7 +52,7 @@ public struct MatrixSQLiteStore {
4752

4853
migrator.registerMigration("createRoomsAndMessages") { db in
4954
try db.create(table: "room_state") { t in
50-
t.column("event_id", .text).notNull().primaryKey()
55+
t.column("event_id", .text).notNull().primaryKey().unique(onConflict: .replace)
5156
t.column("room_id", .text).notNull().indexed()
5257
t.column("type", .text).notNull()
5358
t.column("state_key", .text)

Sources/MatrixSQLiteStore/RoomState.swift

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,45 @@ import MatrixClient
1212
import MatrixCore
1313

1414
public struct MatrixRoomState: MatrixStoreRoomState {
15+
public init(roomId: String, event: MatrixStateEvent) throws {
16+
guard let eventId = event.eventID,
17+
let sender = event.sender
18+
else {
19+
throw MatrixCodableStateEventType.StateTypeError.missingTypes
20+
}
21+
self.eventId = eventId
22+
self.roomId = roomId
23+
stateKey = event.stateKey
24+
// self.sender = sender
25+
_content = event
26+
}
27+
1528
public var eventId: String
1629
public var roomId: String
1730

1831
public var stateKey: String
1932

33+
public var sender: MatrixFullUserIdentifier? {
34+
_content.sender
35+
}
36+
2037
// TODO: custom type in MatrixClient?
21-
public var contentType: String
38+
public var contentType: String {
39+
type(of: content).type
40+
}
2241

2342
// TODO: some event type?
24-
@MatrixCodableStateEventType
25-
public var content: MatrixStateEventType
43+
// @MatrixCodableStateEventType
44+
private var _content: MatrixStateEvent
45+
46+
public var content: MatrixStateEventType {
47+
get {
48+
_content.content
49+
}
50+
set {
51+
_content.content = newValue
52+
}
53+
}
2654
}
2755

2856
extension MatrixRoomState: Codable, FetchableRecord, PersistableRecord, Equatable, Hashable {
@@ -50,14 +78,21 @@ extension MatrixRoomState: Codable, FetchableRecord, PersistableRecord, Equatabl
5078
case content
5179
}
5280

81+
enum Columns {
82+
static let eventId = Column(CodingKeys.eventId)
83+
static let roomId = Column(CodingKeys.roomId)
84+
static let contentType = Column(CodingKeys.contentType)
85+
static let stateKey = Column(CodingKeys.stateKey)
86+
static let content = Column(CodingKeys.content)
87+
}
88+
5389
public init(from decoder: Decoder) throws {
5490
let container = try decoder.container(keyedBy: CodingKeys.self)
5591
eventId = try container.decode(String.self, forKey: .eventId)
5692
roomId = try container.decode(String.self, forKey: .roomId)
5793
stateKey = try container.decode(String.self, forKey: .stateKey)
58-
contentType = try container.decode(String.self, forKey: .contentType)
5994

60-
_content = try MatrixCodableStateEventType(from: container.superDecoder(forKey: .content), typeID: contentType)
95+
_content = try container.decode(MatrixStateEvent.self, forKey: .content)
6196
}
6297

6398
public func encode(to encoder: Encoder) throws {
@@ -67,7 +102,7 @@ extension MatrixRoomState: Codable, FetchableRecord, PersistableRecord, Equatabl
67102
try container.encode(stateKey, forKey: .stateKey)
68103
try container.encode(contentType, forKey: .contentType)
69104

70-
try _content.encode(to: encoder)
105+
try container.encode(_content, forKey: .content)
71106
}
72107

73108
/* public static func databaseJSONEncoder(for column: String) -> JSONEncoder {
@@ -98,13 +133,21 @@ public extension MatrixSQLiteStore {
98133

99134
func addRoomState(state: MatrixRoomState) async throws {
100135
try await dbWriter.write { db in
136+
try? db.execute(
137+
sql: "DELETE FROM \"\(MatrixRoomState.databaseTableName)\" INDEXED BY \"room_state_type_key_index\" WHERE room_id = ? AND type = ? AND state_key = ?",
138+
arguments: [state.roomId, state.contentType, state.stateKey]
139+
)
101140
try state.insert(db)
102141
}
103142
}
104143

105144
func getRoomState(roomId: String) async throws -> [RoomState] {
106145
try await dbWriter.read { db in
107-
try RoomState.fetchAll(db, sql: "SELECT * FROM room_state WHERE room_id = ?", arguments: [roomId])
146+
try RoomState.fetchAll(
147+
db,
148+
sql: "SELECT * FROM room_state INDEXED BY room_state_on_room_id WHERE room_id = ?",
149+
arguments: [roomId]
150+
)
108151
}
109152
}
110153

@@ -134,6 +177,7 @@ public extension MatrixSQLiteStore {
134177
}
135178
}
136179

180+
/// - Throws: An error of type ``DatabaseError``
137181
func getRoomState(roomId: String, stateType: String, stateKey: String) async throws -> [RoomState] {
138182
try await dbWriter.read { db in
139183
try RoomState.fetchAll(

Tests/MatrixSQLiteStoreTests/MatrixAccountInfoTests.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ class AccountInfoTests: XCTestCase {
1515
let dbQueue = DatabaseQueue()
1616
let store = try MatrixSQLiteStore(dbQueue)
1717

18-
let id = MatrixUserIdentifier(rawValue: "@test:example.com")!
18+
let id = MatrixFullUserIdentifier(string: "@test:example.com")!
1919
let data = MatrixSQLAccountInfo(
2020
name: "test",
2121
mxID: id,
2222
homeServer: MatrixHomeserver(string: "https://example.com")!,
23-
accessToken: "secret"
23+
accessToken: "secret",
24+
deviceID: "test"
2425
)
2526

2627
defer {
@@ -40,11 +41,23 @@ class AccountInfoTests: XCTestCase {
4041
let store = try MatrixSQLiteStore(dbQueue)
4142
let homeserver = MatrixHomeserver(string: "https://example.com")!
4243

43-
let id1 = MatrixUserIdentifier(locapart: "test1", domain: "example.com")
44-
let data1 = MatrixSQLAccountInfo(name: "test1", mxID: id1, homeServer: homeserver, accessToken: "secret2")
44+
let id1 = MatrixFullUserIdentifier(localpart: "test1", domain: "example.com")
45+
let data1 = MatrixSQLAccountInfo(
46+
name: "test1",
47+
mxID: id1,
48+
homeServer: homeserver,
49+
accessToken: "secret2",
50+
deviceID: "test"
51+
)
4552

46-
let id2 = MatrixUserIdentifier(locapart: "test2", domain: "example.com")
47-
let data2 = MatrixSQLAccountInfo(name: "test2", mxID: id2, homeServer: homeserver, accessToken: "secret2")
53+
let id2 = MatrixFullUserIdentifier(localpart: "test2", domain: "example.com")
54+
let data2 = MatrixSQLAccountInfo(
55+
name: "test2",
56+
mxID: id2,
57+
homeServer: homeserver,
58+
accessToken: "secret2",
59+
deviceID: "test"
60+
)
4861

4962
defer {
5063
try! data1.deleteFromKeychain()
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//
2+
// RoomStateTests.swift
3+
//
4+
//
5+
// Created by Finn Behrens on 25.04.22.
6+
//
7+
8+
import GRDB
9+
import MatrixClient
10+
@testable import MatrixSQLiteStore
11+
import XCTest
12+
13+
class RoomStateTests: XCTestCase {
14+
func testExample() async throws {
15+
let dbQueue = try DatabasePool(path: "/tmp/test.sqlite")
16+
// let dbQueue = DatabaseQueue()
17+
let store = try MatrixSQLiteStore(dbQueue)
18+
19+
let inSender = MatrixFullUserIdentifier(localpart: "user", domain: "example.com")
20+
let inContent = MatrixRoomCreateEvent(creator: inSender, roomVersion: "1")
21+
let inEvent = MatrixStateEvent(
22+
eventID: "!event:example.com",
23+
stateKey: "",
24+
sender: inSender,
25+
content: inContent
26+
)
27+
let inData = try MatrixSQLiteStore.RoomState(roomId: "!room:example.com", event: inEvent)
28+
29+
try await store.addRoomState(state: inData)
30+
31+
let state = try await store.getRoomState(eventId: "!event:example.com")
32+
XCTAssertNotNil(state)
33+
34+
guard let content = state?.content as? MatrixRoomCreateEvent else {
35+
XCTFail("content not of type MatrixRoomCreateEvent")
36+
return
37+
}
38+
XCTAssertEqual(content.creator, inContent.creator)
39+
XCTAssertEqual(content.federate, inContent.federate)
40+
XCTAssertEqual(content.roomType, inContent.roomType)
41+
XCTAssertEqual(content.roomVersion, inContent.roomVersion)
42+
XCTAssertEqual(content.predecessor, inContent.predecessor)
43+
XCTAssertEqual(state?.sender, inSender)
44+
}
45+
}

0 commit comments

Comments
 (0)