Skip to content

Commit 5f44724

Browse files
committed
wip
1 parent d8ac3d0 commit 5f44724

13 files changed

Lines changed: 3069 additions & 9 deletions
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//
2+
// QueryHistoryManager.swift
3+
// OpenTable
4+
//
5+
// Thread-safe coordinator for query history and bookmarks
6+
// Communicates via NotificationCenter (NOT ObservableObject)
7+
//
8+
9+
import Foundation
10+
11+
/// Notification names for query history updates
12+
extension Notification.Name {
13+
static let queryHistoryDidUpdate = Notification.Name("queryHistoryDidUpdate")
14+
static let queryBookmarksDidUpdate = Notification.Name("queryBookmarksDidUpdate")
15+
}
16+
17+
/// Thread-safe manager for query history and bookmarks
18+
/// NOT an ObservableObject - uses NotificationCenter for UI communication
19+
final class QueryHistoryManager {
20+
static let shared = QueryHistoryManager()
21+
22+
private let storage = QueryHistoryStorage.shared
23+
24+
private init() {
25+
// Perform cleanup on initialization (app launch)
26+
storage.cleanup()
27+
}
28+
29+
// MARK: - History Capture
30+
31+
/// Record a query execution (non-blocking background write)
32+
func recordQuery(
33+
query: String,
34+
connectionId: UUID,
35+
databaseName: String,
36+
executionTime: TimeInterval,
37+
rowCount: Int,
38+
wasSuccessful: Bool,
39+
errorMessage: String? = nil
40+
) {
41+
let entry = QueryHistoryEntry(
42+
query: query,
43+
connectionId: connectionId,
44+
databaseName: databaseName,
45+
executionTime: executionTime,
46+
rowCount: rowCount,
47+
wasSuccessful: wasSuccessful,
48+
errorMessage: errorMessage
49+
)
50+
51+
// Background write (non-blocking)
52+
storage.addHistory(entry) { success in
53+
if success {
54+
// Notify UI to refresh on main thread
55+
DispatchQueue.main.async {
56+
NotificationCenter.default.post(
57+
name: .queryHistoryDidUpdate,
58+
object: nil
59+
)
60+
}
61+
}
62+
}
63+
}
64+
65+
// MARK: - History Retrieval
66+
67+
/// Fetch history entries (synchronous - safe for UI)
68+
func fetchHistory(
69+
limit: Int = 100,
70+
offset: Int = 0,
71+
connectionId: UUID? = nil,
72+
searchText: String? = nil,
73+
dateFilter: DateFilter = .all
74+
) -> [QueryHistoryEntry] {
75+
return storage.fetchHistory(
76+
limit: limit,
77+
offset: offset,
78+
connectionId: connectionId,
79+
searchText: searchText,
80+
dateFilter: dateFilter
81+
)
82+
}
83+
84+
/// Search queries using FTS5 full-text search
85+
func searchQueries(_ text: String) -> [QueryHistoryEntry] {
86+
guard !text.trimmingCharacters(in: .whitespaces).isEmpty else {
87+
return fetchHistory()
88+
}
89+
return storage.fetchHistory(searchText: text)
90+
}
91+
92+
/// Delete a history entry
93+
func deleteHistory(id: UUID) -> Bool {
94+
let success = storage.deleteHistory(id: id)
95+
if success {
96+
NotificationCenter.default.post(name: .queryHistoryDidUpdate, object: nil)
97+
}
98+
return success
99+
}
100+
101+
/// Get total history count
102+
func getHistoryCount() -> Int {
103+
return storage.getHistoryCount()
104+
}
105+
106+
// MARK: - Bookmarks
107+
108+
/// Save a new bookmark
109+
func saveBookmark(
110+
name: String,
111+
query: String,
112+
connectionId: UUID? = nil,
113+
tags: [String] = [],
114+
notes: String? = nil
115+
) -> Bool {
116+
let bookmark = QueryBookmark(
117+
name: name,
118+
query: query,
119+
connectionId: connectionId,
120+
tags: tags,
121+
notes: notes
122+
)
123+
124+
let success = storage.addBookmark(bookmark)
125+
if success {
126+
NotificationCenter.default.post(name: .queryBookmarksDidUpdate, object: nil)
127+
}
128+
return success
129+
}
130+
131+
/// Save bookmark from history entry
132+
func saveBookmarkFromHistory(_ entry: QueryHistoryEntry, name: String) -> Bool {
133+
return saveBookmark(
134+
name: name,
135+
query: entry.query,
136+
connectionId: entry.connectionId
137+
)
138+
}
139+
140+
/// Update an existing bookmark
141+
func updateBookmark(_ bookmark: QueryBookmark) -> Bool {
142+
let success = storage.updateBookmark(bookmark)
143+
if success {
144+
NotificationCenter.default.post(name: .queryBookmarksDidUpdate, object: nil)
145+
}
146+
return success
147+
}
148+
149+
/// Update bookmark's last used timestamp
150+
func markBookmarkUsed(id: UUID) {
151+
if var bookmark = fetchBookmarks().first(where: { $0.id == id }) {
152+
bookmark.lastUsedAt = Date()
153+
_ = storage.updateBookmark(bookmark)
154+
}
155+
}
156+
157+
/// Fetch bookmarks with optional filters
158+
func fetchBookmarks(searchText: String? = nil, tag: String? = nil) -> [QueryBookmark] {
159+
return storage.fetchBookmarks(searchText: searchText, tag: tag)
160+
}
161+
162+
/// Delete a bookmark
163+
func deleteBookmark(id: UUID) -> Bool {
164+
let success = storage.deleteBookmark(id: id)
165+
if success {
166+
NotificationCenter.default.post(name: .queryBookmarksDidUpdate, object: nil)
167+
}
168+
return success
169+
}
170+
171+
// MARK: - Cleanup
172+
173+
/// Manually trigger cleanup (normally runs automatically)
174+
func cleanup() {
175+
storage.cleanup()
176+
}
177+
}

0 commit comments

Comments
 (0)