mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-02 20:16:54 +01:00
Cache statuses when fetching articles — since articles are fetched using a join statement with the statuses table.
This commit is contained in:
parent
80c8a848e9
commit
72cfc84001
@ -166,26 +166,15 @@ private extension ArticlesTable {
|
|||||||
|
|
||||||
// MARK: Fetching
|
// MARK: Fetching
|
||||||
|
|
||||||
func articleWithRow(_ row: FMResultSet) -> Article? {
|
|
||||||
|
|
||||||
guard let article = Article(row: row, accountID: accountID) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: the row is a result of a JOIN query with the statuses table,
|
|
||||||
// so we can get the status at the same time and avoid additional database lookups.
|
|
||||||
|
|
||||||
// article.status = statusesTable.statusWithRow(row)
|
|
||||||
return article
|
|
||||||
}
|
|
||||||
|
|
||||||
func articlesWithResultSet(_ resultSet: FMResultSet, _ database: FMDatabase) -> Set<Article> {
|
func articlesWithResultSet(_ resultSet: FMResultSet, _ database: FMDatabase) -> Set<Article> {
|
||||||
|
|
||||||
// Create set of stub Articles without related objects.
|
// Create set of stub Articles without related objects.
|
||||||
// Then fetch the related objects, given the set of articleIDs.
|
// Then fetch the related objects, given the set of articleIDs.
|
||||||
// Then create set of Articles *with* related objects and return it.
|
// Then create set of Articles *with* related objects and return it.
|
||||||
|
|
||||||
|
let (stubArticles, statuses) = stubArticlesAndStatuses(with: resultSet)
|
||||||
|
|
||||||
let stubArticles = resultSet.mapToSet(articleWithRow)
|
statusesTable.addIfNotCached(statuses)
|
||||||
if stubArticles.isEmpty {
|
if stubArticles.isEmpty {
|
||||||
return stubArticles
|
return stubArticles
|
||||||
}
|
}
|
||||||
@ -202,23 +191,44 @@ private extension ArticlesTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create articles with related objects.
|
// Create articles with related objects.
|
||||||
|
|
||||||
var articles = Set<Article>()
|
let articles = Set(stubArticles.map { articleWithAttachedRelatedObjects($0, authorsMap, attachmentsMap, tagsMap) })
|
||||||
for stubArticle in articles {
|
|
||||||
|
|
||||||
let articleID = stubArticle.articleID
|
|
||||||
|
|
||||||
let authors = authorsMap?.authors(for: articleID)
|
|
||||||
let attachments = attachmentsMap?.attachments(for: articleID)
|
|
||||||
let tags = tagsMap?.tags(for: articleID)
|
|
||||||
|
|
||||||
let realArticle = stubArticle.articleByAttaching(authors, attachments, tags)
|
|
||||||
articles.insert(realArticle)
|
|
||||||
}
|
|
||||||
|
|
||||||
return articles
|
return articles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stubArticlesAndStatuses(with resultSet: FMResultSet) -> (Set<Article>, Set<ArticleStatus>) {
|
||||||
|
|
||||||
|
var stubArticles = Set<Article>()
|
||||||
|
var statuses = Set<ArticleStatus>()
|
||||||
|
|
||||||
|
// Note: the resultSet is a result of a JOIN query with the statuses table,
|
||||||
|
// so we can get the statuses at the same time and avoid additional database lookups.
|
||||||
|
|
||||||
|
while resultSet.next() {
|
||||||
|
if let stubArticle = Article(row: resultSet, accountID: accountID) {
|
||||||
|
stubArticles.insert(stubArticle)
|
||||||
|
}
|
||||||
|
if let status = statusesTable.statusWithRow(resultSet) {
|
||||||
|
statuses.insert(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultSet.close()
|
||||||
|
|
||||||
|
return (stubArticles, statuses)
|
||||||
|
}
|
||||||
|
|
||||||
|
func articleWithAttachedRelatedObjects(_ stubArticle: Article, _ authorsMap: RelatedObjectsMap?, _ attachmentsMap: RelatedObjectsMap?, _ tagsMap: RelatedObjectsMap?) -> Article {
|
||||||
|
|
||||||
|
let articleID = stubArticle.articleID
|
||||||
|
|
||||||
|
let authors = authorsMap?.authors(for: articleID)
|
||||||
|
let attachments = attachmentsMap?.attachments(for: articleID)
|
||||||
|
let tags = tagsMap?.tags(for: articleID)
|
||||||
|
|
||||||
|
let realArticle = stubArticle.articleByAttaching(authors, attachments, tags)
|
||||||
|
return realArticle
|
||||||
|
}
|
||||||
|
|
||||||
func fetchArticlesWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject], withLimits: Bool) -> Set<Article> {
|
func fetchArticlesWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject], withLimits: Bool) -> Set<Article> {
|
||||||
|
|
||||||
// Don’t fetch articles that shouldn’t appear in the UI. The rules:
|
// Don’t fetch articles that shouldn’t appear in the UI. The rules:
|
||||||
|
@ -27,7 +27,9 @@ final class StatusesTable: DatabaseTable {
|
|||||||
|
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Cache
|
||||||
|
|
||||||
func cachedStatus(for articleID: String) -> ArticleStatus? {
|
func cachedStatus(for articleID: String) -> ArticleStatus? {
|
||||||
|
|
||||||
assert(Thread.isMainThread)
|
assert(Thread.isMainThread)
|
||||||
@ -35,6 +37,22 @@ final class StatusesTable: DatabaseTable {
|
|||||||
return cache[articleID]
|
return cache[articleID]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addIfNotCached(_ statuses: Set<ArticleStatus>) {
|
||||||
|
|
||||||
|
if statuses.isEmpty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if Thread.isMainThread {
|
||||||
|
self.cache.addIfNotCached(statuses)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.cache.addIfNotCached(statuses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Creating/Updating
|
// MARK: Creating/Updating
|
||||||
|
|
||||||
func ensureStatusesForArticleIDs(_ articleIDs: Set<String>, _ completion: @escaping StatusesCompletionBlock) {
|
func ensureStatusesForArticleIDs(_ articleIDs: Set<String>, _ completion: @escaping StatusesCompletionBlock) {
|
||||||
@ -71,11 +89,6 @@ final class StatusesTable: DatabaseTable {
|
|||||||
|
|
||||||
updateRowsWithValue(NSNumber(value: flag), valueKey: statusKey, whereKey: DatabaseKey.articleID, matches: Array(articleIDs), database: database)
|
updateRowsWithValue(NSNumber(value: flag), valueKey: statusKey, whereKey: DatabaseKey.articleID, matches: Array(articleIDs), database: database)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private
|
|
||||||
|
|
||||||
private extension StatusesTable {
|
|
||||||
|
|
||||||
// MARK: Fetching
|
// MARK: Fetching
|
||||||
|
|
||||||
@ -91,6 +104,11 @@ private extension StatusesTable {
|
|||||||
let articleStatus = ArticleStatus(articleID: articleID, dateArrived: dateArrived, row: row)
|
let articleStatus = ArticleStatus(articleID: articleID, dateArrived: dateArrived, row: row)
|
||||||
return articleStatus
|
return articleStatus
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private extension StatusesTable {
|
||||||
|
|
||||||
// MARK: Cache
|
// MARK: Cache
|
||||||
|
|
||||||
|
13
ToDo.opml
13
ToDo.opml
@ -6,12 +6,12 @@
|
|||||||
</editor> -->
|
</editor> -->
|
||||||
<title>ToDo</title>
|
<title>ToDo</title>
|
||||||
<dateCreated>Tue, 12 Sep 2017 20:15:17 GMT</dateCreated>
|
<dateCreated>Tue, 12 Sep 2017 20:15:17 GMT</dateCreated>
|
||||||
<expansionState>11,16,17,20,24,29,31,34,37,39,40,44,49,52,54,56,58,67,72,78,83</expansionState>
|
<expansionState>11,16,17,20,24,29,31,34,37,39,40,44,48,51,53,55,57,66,71,77,82</expansionState>
|
||||||
<vertScrollState>59</vertScrollState>
|
<vertScrollState>0</vertScrollState>
|
||||||
<windowTop>248</windowTop>
|
<windowTop>523</windowTop>
|
||||||
<windowLeft>30</windowLeft>
|
<windowLeft>40</windowLeft>
|
||||||
<windowRight>762</windowRight>
|
<windowRight>772</windowRight>
|
||||||
<windowBottom>1007</windowBottom>
|
<windowBottom>1282</windowBottom>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<outline text="App">
|
<outline text="App">
|
||||||
@ -72,7 +72,6 @@
|
|||||||
<outline text="mark articles"/>
|
<outline text="mark articles"/>
|
||||||
<outline text="Delete old articles"/>
|
<outline text="Delete old articles"/>
|
||||||
<outline text="Update cutoff date periodically"/>
|
<outline text="Update cutoff date periodically"/>
|
||||||
<outline text="Do something with statuses on fetching articles"/>
|
|
||||||
</outline>
|
</outline>
|
||||||
<outline text="StatusesTable">
|
<outline text="StatusesTable">
|
||||||
<outline text="Update cached statuses on marking"/>
|
<outline text="Update cached statuses on marking"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user