Fix lint issues.
This commit is contained in:
parent
03e9bbff34
commit
962d5fa45c
@ -9,13 +9,13 @@ let package = Package(
|
||||
.library(
|
||||
name: "ArticlesDatabase",
|
||||
type: .dynamic,
|
||||
targets: ["ArticlesDatabase"]),
|
||||
targets: ["ArticlesDatabase"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../RSDatabase"),
|
||||
.package(path: "../Parser"),
|
||||
.package(path: "../RSCore"),
|
||||
.package(path: "../Articles"),
|
||||
.package(path: "../Articles")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
@ -24,9 +24,9 @@ let package = Package(
|
||||
"RSCore",
|
||||
"RSDatabase",
|
||||
"Parser",
|
||||
"Articles",
|
||||
"Articles"
|
||||
],
|
||||
swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
|
@ -18,7 +18,7 @@ import Articles
|
||||
// Main thread only.
|
||||
|
||||
public typealias UnreadCountDictionary = [String: Int] // feedID: unreadCount
|
||||
public typealias UnreadCountDictionaryCompletionResult = Result<UnreadCountDictionary,DatabaseError>
|
||||
public typealias UnreadCountDictionaryCompletionResult = Result<UnreadCountDictionary, DatabaseError>
|
||||
public typealias UnreadCountDictionaryCompletionBlock = (UnreadCountDictionaryCompletionResult) -> Void
|
||||
|
||||
public typealias SingleUnreadCountResult = Result<Int, DatabaseError>
|
||||
@ -34,13 +34,13 @@ public struct ArticleChanges {
|
||||
self.updatedArticles = Set<Article>()
|
||||
self.deletedArticles = Set<Article>()
|
||||
}
|
||||
|
||||
|
||||
public init(newArticles: Set<Article>?, updatedArticles: Set<Article>?, deletedArticles: Set<Article>?) {
|
||||
self.newArticles = newArticles
|
||||
self.updatedArticles = updatedArticles
|
||||
self.deletedArticles = deletedArticles
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public typealias UpdateArticlesResult = Result<ArticleChanges, DatabaseError>
|
||||
@ -93,7 +93,7 @@ public final class ArticlesDatabase {
|
||||
public func fetchArticles(_ feedID: String) throws -> Set<Article> {
|
||||
return try articlesTable.fetchArticles(feedID)
|
||||
}
|
||||
|
||||
|
||||
public func fetchArticles(_ feedIDs: Set<String>) throws -> Set<Article> {
|
||||
return try articlesTable.fetchArticles(feedIDs)
|
||||
}
|
||||
@ -117,7 +117,7 @@ public final class ArticlesDatabase {
|
||||
public func fetchStarredArticlesCount(_ feedIDs: Set<String>) throws -> Int {
|
||||
return try articlesTable.fetchStarredArticlesCount(feedIDs)
|
||||
}
|
||||
|
||||
|
||||
public func fetchArticlesMatching(_ searchString: String, _ feedIDs: Set<String>) throws -> Set<Article> {
|
||||
return try articlesTable.fetchArticlesMatching(searchString, feedIDs)
|
||||
}
|
||||
@ -230,7 +230,7 @@ public final class ArticlesDatabase {
|
||||
public func fetchUnreadArticleIDsAsync(completion: @escaping ArticleIDsCompletionBlock) {
|
||||
articlesTable.fetchUnreadArticleIDsAsync(completion)
|
||||
}
|
||||
|
||||
|
||||
/// Fetch the articleIDs of starred articles.
|
||||
public func fetchStarredArticleIDsAsync(completion: @escaping ArticleIDsCompletionBlock) {
|
||||
articlesTable.fetchStarredArticleIDsAsync(completion)
|
||||
@ -277,7 +277,7 @@ public final class ArticlesDatabase {
|
||||
operationQueue.resume()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// MARK: - Caches
|
||||
|
||||
/// Call to free up some memory. Should be done when the app is backgrounded, for instance.
|
||||
|
@ -41,15 +41,15 @@ final class ArticlesTable: DatabaseTable {
|
||||
self.queue = queue
|
||||
self.statusesTable = StatusesTable(queue: queue)
|
||||
self.retentionStyle = retentionStyle
|
||||
|
||||
|
||||
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
||||
self.authorsLookupTable = DatabaseLookupTable(name: DatabaseTableName.authorsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.authorID, relatedTable: authorsTable, relationshipName: RelationshipName.authors)
|
||||
}
|
||||
|
||||
// MARK: - Fetching Articles for Feed
|
||||
|
||||
|
||||
func fetchArticles(_ feedID: String) throws -> Set<Article> {
|
||||
return try fetchArticles{ self.fetchArticlesForFeedID(feedID, $0) }
|
||||
return try fetchArticles { self.fetchArticlesForFeedID(feedID, $0) }
|
||||
}
|
||||
|
||||
func fetchArticlesAsync(_ feedID: String, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@ -57,7 +57,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
}
|
||||
|
||||
func fetchArticles(_ feedIDs: Set<String>) throws -> Set<Article> {
|
||||
return try fetchArticles{ self.fetchArticles(feedIDs, $0) }
|
||||
return try fetchArticles { self.fetchArticles(feedIDs, $0) }
|
||||
}
|
||||
|
||||
func fetchArticlesAsync(_ feedIDs: Set<String>, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@ -67,7 +67,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
// MARK: - Fetching Articles by articleID
|
||||
|
||||
func fetchArticles(articleIDs: Set<String>) throws -> Set<Article> {
|
||||
return try fetchArticles{ self.fetchArticles(articleIDs: articleIDs, $0) }
|
||||
return try fetchArticles { self.fetchArticles(articleIDs: articleIDs, $0) }
|
||||
}
|
||||
|
||||
func fetchArticlesAsync(articleIDs: Set<String>, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@ -77,7 +77,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
// MARK: - Fetching Unread Articles
|
||||
|
||||
func fetchUnreadArticles(_ feedIDs: Set<String>, _ limit: Int?) throws -> Set<Article> {
|
||||
return try fetchArticles{ self.fetchUnreadArticles(feedIDs, limit, $0) }
|
||||
return try fetchArticles { self.fetchUnreadArticles(feedIDs, limit, $0) }
|
||||
}
|
||||
|
||||
func fetchUnreadArticlesAsync(_ feedIDs: Set<String>, _ limit: Int?, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@ -87,7 +87,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
// MARK: - Fetching Today Articles
|
||||
|
||||
func fetchArticlesSince(_ feedIDs: Set<String>, _ cutoffDate: Date, _ limit: Int?) throws -> Set<Article> {
|
||||
return try fetchArticles{ self.fetchArticlesSince(feedIDs, cutoffDate, limit, $0) }
|
||||
return try fetchArticles { self.fetchArticlesSince(feedIDs, cutoffDate, limit, $0) }
|
||||
}
|
||||
|
||||
func fetchArticlesSinceAsync(_ feedIDs: Set<String>, _ cutoffDate: Date, _ limit: Int?, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@ -97,7 +97,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
// MARK: - Fetching Starred Articles
|
||||
|
||||
func fetchStarredArticles(_ feedIDs: Set<String>, _ limit: Int?) throws -> Set<Article> {
|
||||
return try fetchArticles{ self.fetchStarredArticles(feedIDs, limit, $0) }
|
||||
return try fetchArticles { self.fetchStarredArticles(feedIDs, limit, $0) }
|
||||
}
|
||||
|
||||
func fetchStarredArticlesAsync(_ feedIDs: Set<String>, _ limit: Int?, _ completion: @escaping ArticleSetResultBlock) {
|
||||
@ -105,15 +105,15 @@ final class ArticlesTable: DatabaseTable {
|
||||
}
|
||||
|
||||
func fetchStarredArticlesCount(_ feedIDs: Set<String>) throws -> Int {
|
||||
return try fetchArticlesCount{ self.fetchStarredArticlesCount(feedIDs, $0) }
|
||||
return try fetchArticlesCount { self.fetchStarredArticlesCount(feedIDs, $0) }
|
||||
}
|
||||
|
||||
// MARK: - Fetching Search Articles
|
||||
|
||||
func fetchArticlesMatching(_ searchString: String) throws -> Set<Article> {
|
||||
var articles: Set<Article> = Set<Article>()
|
||||
var error: DatabaseError? = nil
|
||||
|
||||
var error: DatabaseError?
|
||||
|
||||
queue.runInDatabaseSync { (databaseResult) in
|
||||
switch databaseResult {
|
||||
case .success(let database):
|
||||
@ -131,13 +131,13 @@ final class ArticlesTable: DatabaseTable {
|
||||
|
||||
func fetchArticlesMatching(_ searchString: String, _ feedIDs: Set<String>) throws -> Set<Article> {
|
||||
var articles = try fetchArticlesMatching(searchString)
|
||||
articles = articles.filter{ feedIDs.contains($0.feedID) }
|
||||
articles = articles.filter { feedIDs.contains($0.feedID) }
|
||||
return articles
|
||||
}
|
||||
|
||||
func fetchArticlesMatchingWithArticleIDs(_ searchString: String, _ articleIDs: Set<String>) throws -> Set<Article> {
|
||||
var articles = try fetchArticlesMatching(searchString)
|
||||
articles = articles.filter{ articleIDs.contains($0.articleID) }
|
||||
articles = articles.filter { articleIDs.contains($0.articleID) }
|
||||
return articles
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
let authorsNames = row.string(forColumn: DatabaseKey.authors)
|
||||
|
||||
let searchRowIDObject = row.object(forColumnName: DatabaseKey.searchRowID)
|
||||
var searchRowID: Int? = nil
|
||||
var searchRowID: Int?
|
||||
if searchRowIDObject != nil && !(searchRowIDObject is NSNull) {
|
||||
searchRowID = Int(row.longLongInt(forColumn: DatabaseKey.searchRowID))
|
||||
}
|
||||
@ -217,20 +217,20 @@ final class ArticlesTable: DatabaseTable {
|
||||
func makeDatabaseCalls(_ database: FMDatabase) {
|
||||
let articleIDs = parsedItems.articleIDs()
|
||||
|
||||
let (statusesDictionary, _) = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, false, database) //1
|
||||
let (statusesDictionary, _) = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, false, database) // 1
|
||||
assert(statusesDictionary.count == articleIDs.count)
|
||||
|
||||
let incomingArticles = Article.articlesWithParsedItems(parsedItems, feedID, self.accountID, statusesDictionary) //2
|
||||
let incomingArticles = Article.articlesWithParsedItems(parsedItems, feedID, self.accountID, statusesDictionary) // 2
|
||||
if incomingArticles.isEmpty {
|
||||
self.callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||
return
|
||||
}
|
||||
|
||||
let fetchedArticles = self.fetchArticlesForFeedID(feedID, database) //4
|
||||
let fetchedArticles = self.fetchArticlesForFeedID(feedID, database) // 4
|
||||
let fetchedArticlesDictionary = fetchedArticles.dictionary()
|
||||
|
||||
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) //5
|
||||
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) //6
|
||||
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) // 5
|
||||
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) // 6
|
||||
|
||||
// Articles to delete are 1) not starred and 2) older than 30 days and 3) no longer in feed.
|
||||
let articlesToDelete: Set<Article>
|
||||
@ -243,7 +243,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
articlesToDelete = Set<Article>()
|
||||
}
|
||||
|
||||
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, articlesToDelete, completion) //7
|
||||
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, articlesToDelete, completion) // 7
|
||||
|
||||
self.addArticlesToCache(newArticles)
|
||||
self.addArticlesToCache(updatedArticles)
|
||||
@ -299,29 +299,29 @@ final class ArticlesTable: DatabaseTable {
|
||||
articleIDs.formUnion(parsedItems.articleIDs())
|
||||
}
|
||||
|
||||
let (statusesDictionary, _) = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, read, database) //1
|
||||
let (statusesDictionary, _) = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, read, database) // 1
|
||||
assert(statusesDictionary.count == articleIDs.count)
|
||||
|
||||
let allIncomingArticles = Article.articlesWithFeedIDsAndItems(feedIDsAndItems, self.accountID, statusesDictionary) //2
|
||||
let allIncomingArticles = Article.articlesWithFeedIDsAndItems(feedIDsAndItems, self.accountID, statusesDictionary) // 2
|
||||
if allIncomingArticles.isEmpty {
|
||||
self.callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||
return
|
||||
}
|
||||
|
||||
let incomingArticles = self.filterIncomingArticles(allIncomingArticles) //3
|
||||
let incomingArticles = self.filterIncomingArticles(allIncomingArticles) // 3
|
||||
if incomingArticles.isEmpty {
|
||||
self.callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||
return
|
||||
}
|
||||
|
||||
let incomingArticleIDs = incomingArticles.articleIDs()
|
||||
let fetchedArticles = self.fetchArticles(articleIDs: incomingArticleIDs, database) //4
|
||||
let fetchedArticles = self.fetchArticles(articleIDs: incomingArticleIDs, database) // 4
|
||||
let fetchedArticlesDictionary = fetchedArticles.dictionary()
|
||||
|
||||
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) //5
|
||||
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) //6
|
||||
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) // 5
|
||||
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) // 6
|
||||
|
||||
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, nil, completion) //7
|
||||
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, nil, completion) // 7
|
||||
|
||||
self.addArticlesToCache(newArticles)
|
||||
self.addArticlesToCache(updatedArticles)
|
||||
@ -364,20 +364,20 @@ final class ArticlesTable: DatabaseTable {
|
||||
completion?(databaseError)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Unread Counts
|
||||
|
||||
|
||||
func fetchUnreadCount(_ feedIDs: Set<String>, _ since: Date, _ completion: @escaping SingleUnreadCountCompletionBlock) {
|
||||
// Get unread count for today, for instance.
|
||||
if feedIDs.isEmpty {
|
||||
completion(.success(0))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
queue.runInDatabase { databaseResult in
|
||||
|
||||
func makeDatabaseCalls(_ database: FMDatabase) {
|
||||
@ -439,7 +439,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
}
|
||||
|
||||
// MARK: - Statuses
|
||||
|
||||
|
||||
func fetchUnreadArticleIDsAsync(_ completion: @escaping ArticleIDsCompletionBlock) {
|
||||
statusesTable.fetchArticleIDsAsync(.read, false, completion)
|
||||
}
|
||||
@ -451,7 +451,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
func fetchStarredArticleIDs() throws -> Set<String> {
|
||||
return try statusesTable.fetchStarredArticleIDs()
|
||||
}
|
||||
|
||||
|
||||
func fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate(_ completion: @escaping ArticleIDsCompletionBlock) {
|
||||
statusesTable.fetchArticleIDsForStatusesWithoutArticlesNewerThan(articleCutoffDate, completion)
|
||||
}
|
||||
@ -492,7 +492,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
queue.runInTransaction { databaseResult in
|
||||
switch databaseResult {
|
||||
case .success(let database):
|
||||
let _ = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, true, database)
|
||||
_ = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, true, database)
|
||||
DispatchQueue.main.async {
|
||||
completion(nil)
|
||||
}
|
||||
@ -514,7 +514,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else {
|
||||
return
|
||||
}
|
||||
let articleIDs = resultSet.mapToSet{ $0.string(forColumn: DatabaseKey.articleID) }
|
||||
let articleIDs = resultSet.mapToSet { $0.string(forColumn: DatabaseKey.articleID) }
|
||||
if articleIDs.isEmpty {
|
||||
return
|
||||
}
|
||||
@ -591,7 +591,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
|
||||
let sql: String
|
||||
let cutoffDate: Date
|
||||
|
||||
|
||||
switch self.retentionStyle {
|
||||
case .syncSystem:
|
||||
sql = "delete from statuses where dateArrived<? and read=1 and starred=0 and articleID not in (select articleID from articles);"
|
||||
@ -622,7 +622,7 @@ final class ArticlesTable: DatabaseTable {
|
||||
guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else {
|
||||
return
|
||||
}
|
||||
let articleIDs = resultSet.mapToSet{ $0.string(forColumn: DatabaseKey.articleID) }
|
||||
let articleIDs = resultSet.mapToSet { $0.string(forColumn: DatabaseKey.articleID) }
|
||||
if articleIDs.isEmpty {
|
||||
return
|
||||
}
|
||||
@ -645,7 +645,7 @@ private extension ArticlesTable {
|
||||
|
||||
private func fetchArticles(_ fetchMethod: @escaping ArticlesFetchMethod) throws -> Set<Article> {
|
||||
var articles = Set<Article>()
|
||||
var error: DatabaseError? = nil
|
||||
var error: DatabaseError?
|
||||
queue.runInDatabaseSync { databaseResult in
|
||||
switch databaseResult {
|
||||
case .success(let database):
|
||||
@ -662,7 +662,7 @@ private extension ArticlesTable {
|
||||
|
||||
private func fetchArticlesCount(_ fetchMethod: @escaping ArticlesCountFetchMethod) throws -> Int {
|
||||
var articlesCount = 0
|
||||
var error: DatabaseError? = nil
|
||||
var error: DatabaseError?
|
||||
queue.runInDatabaseSync { databaseResult in
|
||||
switch databaseResult {
|
||||
case .success(let database):
|
||||
@ -784,7 +784,7 @@ private extension ArticlesTable {
|
||||
|
||||
func sqliteSearchString(with searchString: String) -> String {
|
||||
var s = ""
|
||||
searchString.enumerateSubstrings(in: searchString.startIndex..<searchString.endIndex, options: .byWords) { (word, range, enclosingRange, stop) in
|
||||
searchString.enumerateSubstrings(in: searchString.startIndex..<searchString.endIndex, options: .byWords) { (word, _, _, _) in
|
||||
guard let word = word else {
|
||||
return
|
||||
}
|
||||
@ -872,7 +872,7 @@ private extension ArticlesTable {
|
||||
}
|
||||
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
|
||||
}
|
||||
|
||||
|
||||
func fetchStarredArticlesCount(_ feedIDs: Set<String>, _ database: FMDatabase) -> Int {
|
||||
// select count from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1;
|
||||
if feedIDs.isEmpty {
|
||||
@ -883,43 +883,43 @@ private extension ArticlesTable {
|
||||
let whereClause = "feedID in \(placeholders) and starred=1"
|
||||
return fetchArticleCountsWithWhereClause(database, whereClause: whereClause, parameters: parameters)
|
||||
}
|
||||
|
||||
|
||||
func fetchArticlesMatching(_ searchString: String, _ feedIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {
|
||||
let articles = fetchArticlesMatching(searchString, database)
|
||||
// TODO: include the feedIDs in the SQL rather than filtering here.
|
||||
return articles.filter{ feedIDs.contains($0.feedID) }
|
||||
return articles.filter { feedIDs.contains($0.feedID) }
|
||||
}
|
||||
|
||||
func fetchArticlesMatchingWithArticleIDs(_ searchString: String, _ articleIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {
|
||||
let articles = fetchArticlesMatching(searchString, database)
|
||||
// TODO: include the articleIDs in the SQL rather than filtering here.
|
||||
return articles.filter{ articleIDs.contains($0.articleID) }
|
||||
return articles.filter { articleIDs.contains($0.articleID) }
|
||||
}
|
||||
|
||||
// MARK: - Saving Parsed Items
|
||||
|
||||
|
||||
func callUpdateArticlesCompletionBlock(_ newArticles: Set<Article>?, _ updatedArticles: Set<Article>?, _ deletedArticles: Set<Article>?, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
||||
let articleChanges = ArticleChanges(newArticles: newArticles, updatedArticles: updatedArticles, deletedArticles: deletedArticles)
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(articleChanges))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Saving New Articles
|
||||
|
||||
func findNewArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article]) -> Set<Article>? {
|
||||
let newArticles = Set(incomingArticles.filter { fetchedArticlesDictionary[$0.articleID] == nil })
|
||||
return newArticles.isEmpty ? nil : newArticles
|
||||
}
|
||||
|
||||
func findAndSaveNewArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article], _ database: FMDatabase) -> Set<Article>? { //5
|
||||
|
||||
func findAndSaveNewArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article], _ database: FMDatabase) -> Set<Article>? { // 5
|
||||
guard let newArticles = findNewArticles(incomingArticles, fetchedArticlesDictionary) else {
|
||||
return nil
|
||||
}
|
||||
self.saveNewArticles(newArticles, database)
|
||||
return newArticles
|
||||
}
|
||||
|
||||
|
||||
func saveNewArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||
saveRelatedObjectsForNewArticles(articles, database)
|
||||
|
||||
@ -936,11 +936,11 @@ private extension ArticlesTable {
|
||||
// MARK: - Updating Existing Articles
|
||||
|
||||
func articlesWithRelatedObjectChanges<T>(_ comparisonKeyPath: KeyPath<Article, Set<T>?>, _ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article]) -> Set<Article> {
|
||||
return updatedArticles.filter{ (updatedArticle) -> Bool in
|
||||
return updatedArticles.filter { (updatedArticle) -> Bool in
|
||||
if let fetchedArticle = fetchedArticles[updatedArticle.articleID] {
|
||||
return updatedArticle[keyPath: comparisonKeyPath] != fetchedArticle[keyPath: comparisonKeyPath]
|
||||
}
|
||||
assertionFailure("Expected to find matching fetched article.");
|
||||
assertionFailure("Expected to find matching fetched article.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -957,7 +957,7 @@ private extension ArticlesTable {
|
||||
}
|
||||
|
||||
func findUpdatedArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article]) -> Set<Article>? {
|
||||
let updatedArticles = incomingArticles.filter{ (incomingArticle) -> Bool in //6
|
||||
let updatedArticles = incomingArticles.filter { (incomingArticle) -> Bool in // 6
|
||||
if let existingArticle = fetchedArticlesDictionary[incomingArticle.articleID] {
|
||||
if existingArticle != incomingArticle {
|
||||
return true
|
||||
@ -968,19 +968,18 @@ private extension ArticlesTable {
|
||||
|
||||
return updatedArticles.isEmpty ? nil : updatedArticles
|
||||
}
|
||||
|
||||
func findAndSaveUpdatedArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article], _ database: FMDatabase) -> Set<Article>? { //6
|
||||
|
||||
func findAndSaveUpdatedArticles(_ incomingArticles: Set<Article>, _ fetchedArticlesDictionary: [String: Article], _ database: FMDatabase) -> Set<Article>? { // 6
|
||||
guard let updatedArticles = findUpdatedArticles(incomingArticles, fetchedArticlesDictionary) else {
|
||||
return nil
|
||||
}
|
||||
saveUpdatedArticles(Set(updatedArticles), fetchedArticlesDictionary, database)
|
||||
return updatedArticles
|
||||
}
|
||||
|
||||
|
||||
func saveUpdatedArticles(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
|
||||
saveUpdatedRelatedObjects(updatedArticles, fetchedArticles, database)
|
||||
|
||||
|
||||
for updatedArticle in updatedArticles {
|
||||
saveUpdatedArticle(updatedArticle, fetchedArticles, database)
|
||||
}
|
||||
@ -989,9 +988,9 @@ private extension ArticlesTable {
|
||||
func saveUpdatedArticle(_ updatedArticle: Article, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
|
||||
// Only update exactly what has changed in the Article (if anything).
|
||||
// Untested theory: this gets us better performance and less database fragmentation.
|
||||
|
||||
|
||||
guard let fetchedArticle = fetchedArticles[updatedArticle.articleID] else {
|
||||
assertionFailure("Expected to find matching fetched article.");
|
||||
assertionFailure("Expected to find matching fetched article.")
|
||||
saveNewArticles(Set([updatedArticle]), database)
|
||||
return
|
||||
}
|
||||
@ -1028,7 +1027,7 @@ private extension ArticlesTable {
|
||||
func filterIncomingArticles(_ articles: Set<Article>) -> Set<Article> {
|
||||
// Drop Articles that we can ignore.
|
||||
precondition(retentionStyle == .syncSystem)
|
||||
return Set(articles.filter{ !articleIsIgnorable($0) })
|
||||
return Set(articles.filter { !articleIsIgnorable($0) })
|
||||
}
|
||||
|
||||
func removeArticles(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
||||
|
@ -17,9 +17,8 @@ import Articles
|
||||
// CREATE TABLE if not EXISTS authors (authorID TEXT NOT NULL PRIMARY KEY, name TEXT, url TEXT, avatarURL TEXT, emailAddress TEXT);
|
||||
// CREATE TABLE if not EXISTS authorLookup (authorID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(authorID, articleID));
|
||||
|
||||
|
||||
final class AuthorsTable: DatabaseRelatedObjectsTable {
|
||||
|
||||
|
||||
let name: String
|
||||
let databaseIDKey = DatabaseKey.authorID
|
||||
var cache = DatabaseObjectCache()
|
||||
@ -27,7 +26,7 @@ final class AuthorsTable: DatabaseRelatedObjectsTable {
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
|
||||
|
||||
// MARK: - DatabaseRelatedObjectsTable
|
||||
|
||||
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
||||
@ -37,4 +36,3 @@ final class AuthorsTable: DatabaseRelatedObjectsTable {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import Foundation
|
||||
// MARK: - Database structure
|
||||
|
||||
struct DatabaseTableName {
|
||||
|
||||
|
||||
static let articles = "articles"
|
||||
static let authors = "authors"
|
||||
static let authorsLookup = "authorsLookup"
|
||||
@ -19,12 +19,12 @@ struct DatabaseTableName {
|
||||
}
|
||||
|
||||
struct DatabaseKey {
|
||||
|
||||
|
||||
// Shared
|
||||
static let articleID = "articleID"
|
||||
static let url = "url"
|
||||
static let title = "title"
|
||||
|
||||
|
||||
// Article
|
||||
static let feedID = "feedID"
|
||||
static let uniqueID = "uniqueID"
|
||||
@ -38,7 +38,7 @@ struct DatabaseKey {
|
||||
static let dateModified = "dateModified"
|
||||
static let authors = "authors"
|
||||
static let searchRowID = "searchRowID"
|
||||
|
||||
|
||||
// ArticleStatus
|
||||
static let read = "read"
|
||||
static let starred = "starred"
|
||||
@ -46,7 +46,7 @@ struct DatabaseKey {
|
||||
|
||||
// Tag
|
||||
static let tagName = "tagName"
|
||||
|
||||
|
||||
// Author
|
||||
static let authorID = "authorID"
|
||||
static let name = "name"
|
||||
@ -59,6 +59,6 @@ struct DatabaseKey {
|
||||
}
|
||||
|
||||
struct RelationshipName {
|
||||
|
||||
|
||||
static let authors = "authors"
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import Articles
|
||||
import Parser
|
||||
|
||||
extension Article {
|
||||
|
||||
|
||||
convenience init?(accountID: String, row: FMResultSet, status: ArticleStatus) {
|
||||
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
|
||||
assertionFailure("Expected articleID.")
|
||||
@ -61,7 +61,7 @@ extension Article {
|
||||
self.init(accountID: accountID, articleID: parsedItem.syncServiceID, feedID: feedID, uniqueID: parsedItem.uniqueID, title: parsedItem.title, contentHTML: parsedItem.contentHTML, contentText: parsedItem.contentText, url: parsedItem.url, externalURL: parsedItem.externalURL, summary: parsedItem.summary, imageURL: parsedItem.imageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, status: status)
|
||||
}
|
||||
|
||||
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: inout DatabaseDictionary) {
|
||||
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article, String?>, _ otherArticle: Article, _ key: String, _ dictionary: inout DatabaseDictionary) {
|
||||
if self[keyPath: comparisonKeyPath] != otherArticle[keyPath: comparisonKeyPath] {
|
||||
dictionary[key] = self[keyPath: comparisonKeyPath] ?? ""
|
||||
}
|
||||
@ -78,7 +78,7 @@ extension Article {
|
||||
if self == existingArticle {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
var d = DatabaseDictionary()
|
||||
if uniqueID != existingArticle.uniqueID {
|
||||
d[DatabaseKey.uniqueID] = uniqueID
|
||||
@ -132,7 +132,7 @@ extension Article {
|
||||
|
||||
static func articlesWithParsedItems(_ parsedItems: Set<ParsedItem>, _ feedID: String, _ accountID: String, _ statusesDictionary: [String: ArticleStatus]) -> Set<Article> {
|
||||
let maximumDateAllowed = _maximumDateAllowed()
|
||||
return Set(parsedItems.map{ Article(parsedItem: $0, maximumDateAllowed: maximumDateAllowed, accountID: accountID, feedID: feedID, status: statusesDictionary[$0.articleID]!) })
|
||||
return Set(parsedItems.map { Article(parsedItem: $0, maximumDateAllowed: maximumDateAllowed, accountID: accountID, feedID: feedID, status: statusesDictionary[$0.articleID]!) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ extension Article: @retroactive DatabaseObject {
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
public var databaseID: String {
|
||||
return articleID
|
||||
}
|
||||
@ -201,7 +201,7 @@ extension Set where Element == Article {
|
||||
func statuses() -> Set<ArticleStatus> {
|
||||
return Set<ArticleStatus>(map { $0.status })
|
||||
}
|
||||
|
||||
|
||||
func dictionary() -> [String: Article] {
|
||||
var d = [String: Article]()
|
||||
for article in self {
|
||||
@ -211,7 +211,7 @@ extension Set where Element == Article {
|
||||
}
|
||||
|
||||
func databaseObjects() -> [DatabaseObject] {
|
||||
return self.map{ $0 as DatabaseObject }
|
||||
return self.map { $0 as DatabaseObject }
|
||||
}
|
||||
|
||||
func databaseDictionaries() -> [DatabaseDictionary]? {
|
||||
|
@ -12,14 +12,14 @@ import RSDatabaseObjC
|
||||
import Articles
|
||||
|
||||
extension ArticleStatus {
|
||||
|
||||
|
||||
convenience init(articleID: String, dateArrived: Date, row: FMResultSet) {
|
||||
let read = row.bool(forColumn: DatabaseKey.read)
|
||||
let starred = row.bool(forColumn: DatabaseKey.starred)
|
||||
|
||||
self.init(articleID: articleID, read: read, starred: starred, dateArrived: dateArrived)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension ArticleStatus: @retroactive DatabaseObject {
|
||||
@ -32,4 +32,3 @@ extension ArticleStatus: @retroactive DatabaseObject {
|
||||
return [DatabaseKey.articleID: articleID, DatabaseKey.read: read, DatabaseKey.starred: starred, DatabaseKey.dateArrived: dateArrived]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,26 +15,26 @@ import Parser
|
||||
// MARK: - DatabaseObject
|
||||
|
||||
extension Author {
|
||||
|
||||
|
||||
init?(row: FMResultSet) {
|
||||
let authorID = row.string(forColumn: DatabaseKey.authorID)
|
||||
let name = row.string(forColumn: DatabaseKey.name)
|
||||
let url = row.string(forColumn: DatabaseKey.url)
|
||||
let avatarURL = row.string(forColumn: DatabaseKey.avatarURL)
|
||||
let emailAddress = row.string(forColumn: DatabaseKey.emailAddress)
|
||||
|
||||
|
||||
self.init(authorID: authorID, name: name, url: url, avatarURL: avatarURL, emailAddress: emailAddress)
|
||||
}
|
||||
|
||||
|
||||
init?(parsedAuthor: ParsedAuthor) {
|
||||
self.init(authorID: nil, name: parsedAuthor.name, url: parsedAuthor.url, avatarURL: parsedAuthor.avatarURL, emailAddress: parsedAuthor.emailAddress)
|
||||
}
|
||||
|
||||
|
||||
public static func authorsWithParsedAuthors(_ parsedAuthors: Set<ParsedAuthor>?) -> Set<Author>? {
|
||||
guard let parsedAuthors = parsedAuthors else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
let authors = Set(parsedAuthors.compactMap { Author(parsedAuthor: $0) })
|
||||
return authors.isEmpty ? nil: authors
|
||||
}
|
||||
@ -63,4 +63,3 @@ extension Author: @retroactive DatabaseObject {
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import RSDatabase
|
||||
import Articles
|
||||
|
||||
extension Array where Element == DatabaseObject {
|
||||
|
||||
|
||||
func asAuthors() -> Set<Author>? {
|
||||
let authors = Set(self.map { $0 as! Author })
|
||||
return authors.isEmpty ? nil : authors
|
||||
|
@ -11,7 +11,7 @@ import Parser
|
||||
import Articles
|
||||
|
||||
extension ParsedItem {
|
||||
|
||||
|
||||
var articleID: String {
|
||||
if let s = syncServiceID {
|
||||
return s
|
||||
|
@ -11,7 +11,7 @@ import RSDatabase
|
||||
import Articles
|
||||
|
||||
extension RelatedObjectsMap {
|
||||
|
||||
|
||||
func authors(for articleID: String) -> Set<Author>? {
|
||||
if let objects = self[articleID] {
|
||||
return objects.asAuthors()
|
||||
|
@ -27,7 +27,7 @@ public final class FetchAllUnreadCountsOperation: MainThreadOperation {
|
||||
init(databaseQueue: DatabaseQueue) {
|
||||
self.queue = databaseQueue
|
||||
}
|
||||
|
||||
|
||||
public func run() {
|
||||
queue.runInDatabase { databaseResult in
|
||||
if self.isCanceled {
|
||||
|
@ -22,7 +22,7 @@ final class ArticleSearchInfo: Hashable {
|
||||
let summary: String?
|
||||
let authorsNames: String?
|
||||
let searchRowID: Int?
|
||||
|
||||
|
||||
var preferredText: String {
|
||||
if let body = contentHTML, !body.isEmpty {
|
||||
return body
|
||||
@ -117,7 +117,7 @@ final class SearchTable: DatabaseTable {
|
||||
|
||||
/// Index new articles.
|
||||
func indexNewArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||
let articleSearchInfos = Set(articles.map{ ArticleSearchInfo(article: $0) })
|
||||
let articleSearchInfos = Set(articles.map { ArticleSearchInfo(article: $0) })
|
||||
performInitialIndexForArticles(articleSearchInfos, database)
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ final class StatusesTable: DatabaseTable {
|
||||
let name = DatabaseTableName.statuses
|
||||
private let cache = StatusCache()
|
||||
private let queue: DatabaseQueue
|
||||
|
||||
|
||||
init(queue: DatabaseQueue) {
|
||||
self.queue = queue
|
||||
}
|
||||
@ -35,7 +35,7 @@ final class StatusesTable: DatabaseTable {
|
||||
defer {
|
||||
if let resultSet = self.selectRowsWhere(key: DatabaseKey.articleID, inValues: Array(articleIDs), in: database) {
|
||||
let fetchedStatuses = resultSet.mapToSet(statusWithRow)
|
||||
let fetchedArticleIDs = Set(fetchedStatuses.map{ $0.articleID })
|
||||
let fetchedArticleIDs = Set(fetchedStatuses.map { $0.articleID })
|
||||
assert(fetchedArticleIDs == articleIDs)
|
||||
}
|
||||
}
|
||||
@ -46,10 +46,10 @@ final class StatusesTable: DatabaseTable {
|
||||
if articleIDsMissingCachedStatus.isEmpty {
|
||||
return (statusesDictionary(articleIDs), Set<String>())
|
||||
}
|
||||
|
||||
|
||||
// Check database.
|
||||
fetchAndCacheStatusesForArticleIDs(articleIDsMissingCachedStatus, database)
|
||||
|
||||
|
||||
let articleIDsNeedingStatus = self.articleIDsWithNoCachedStatus(articleIDs)
|
||||
if !articleIDsNeedingStatus.isEmpty {
|
||||
// Create new statuses.
|
||||
@ -79,9 +79,9 @@ final class StatusesTable: DatabaseTable {
|
||||
return nil
|
||||
}
|
||||
let articleIDs = updatedStatuses.articleIDs()
|
||||
|
||||
|
||||
self.markArticleIDs(articleIDs, statusKey, flag, database)
|
||||
|
||||
|
||||
return updatedStatuses
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ final class StatusesTable: DatabaseTable {
|
||||
func fetchStarredArticleIDs() throws -> Set<String> {
|
||||
return try fetchArticleIDs("select articleID from statuses where starred=1;")
|
||||
}
|
||||
|
||||
|
||||
func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool, _ completion: @escaping ArticleIDsCompletionBlock) {
|
||||
queue.runInDatabase { databaseResult in
|
||||
|
||||
@ -117,7 +117,7 @@ final class StatusesTable: DatabaseTable {
|
||||
return
|
||||
}
|
||||
|
||||
let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) }
|
||||
let articleIDs = resultSet.mapToSet { $0.string(forColumnIndex: 0) }
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(articleIDs))
|
||||
}
|
||||
@ -136,37 +136,36 @@ final class StatusesTable: DatabaseTable {
|
||||
|
||||
func fetchArticleIDsForStatusesWithoutArticlesNewerThan(_ cutoffDate: Date, _ completion: @escaping ArticleIDsCompletionBlock) {
|
||||
queue.runInDatabase { databaseResult in
|
||||
|
||||
|
||||
var error: DatabaseError?
|
||||
var articleIDs = Set<String>()
|
||||
|
||||
|
||||
func makeDatabaseCall(_ database: FMDatabase) {
|
||||
let sql = "select articleID from statuses s where (starred=1 or dateArrived>?) and not exists (select 1 from articles a where a.articleID = s.articleID);"
|
||||
if let resultSet = database.executeQuery(sql, withArgumentsIn: [cutoffDate]) {
|
||||
articleIDs = resultSet.mapToSet(self.articleIDWithRow)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch databaseResult {
|
||||
case .success(let database):
|
||||
makeDatabaseCall(database)
|
||||
case .failure(let databaseError):
|
||||
error = databaseError
|
||||
}
|
||||
|
||||
|
||||
if let error = error {
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(articleIDs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func fetchArticleIDs(_ sql: String) throws -> Set<String> {
|
||||
var error: DatabaseError?
|
||||
var articleIDs = Set<String>()
|
||||
@ -186,11 +185,11 @@ final class StatusesTable: DatabaseTable {
|
||||
}
|
||||
return articleIDs
|
||||
}
|
||||
|
||||
|
||||
func articleIDWithRow(_ row: FMResultSet) -> String? {
|
||||
return row.string(forColumn: DatabaseKey.articleID)
|
||||
}
|
||||
|
||||
|
||||
func statusWithRow(_ row: FMResultSet) -> ArticleStatus? {
|
||||
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
|
||||
return nil
|
||||
@ -198,7 +197,7 @@ final class StatusesTable: DatabaseTable {
|
||||
return statusWithRow(row, articleID: articleID)
|
||||
}
|
||||
|
||||
func statusWithRow(_ row: FMResultSet, articleID: String) ->ArticleStatus? {
|
||||
func statusWithRow(_ row: FMResultSet, articleID: String) -> ArticleStatus? {
|
||||
if let cachedStatus = cache[articleID] {
|
||||
return cachedStatus
|
||||
}
|
||||
@ -237,7 +236,7 @@ final class StatusesTable: DatabaseTable {
|
||||
private extension StatusesTable {
|
||||
|
||||
// MARK: - Cache
|
||||
|
||||
|
||||
func articleIDsWithNoCachedStatus(_ articleIDs: Set<String>) -> Set<String> {
|
||||
return Set(articleIDs.filter { cache[$0] == nil })
|
||||
}
|
||||
@ -253,7 +252,7 @@ private extension StatusesTable {
|
||||
let now = Date()
|
||||
let statuses = Set(articleIDs.map { ArticleStatus(articleID: $0, read: read, dateArrived: now) })
|
||||
cache.addIfNotCached(statuses)
|
||||
|
||||
|
||||
saveStatuses(statuses, database)
|
||||
}
|
||||
|
||||
@ -261,7 +260,7 @@ private extension StatusesTable {
|
||||
guard let resultSet = self.selectRowsWhere(key: DatabaseKey.articleID, inValues: Array(articleIDs), in: database) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let statuses = resultSet.mapToSet(self.statusWithRow)
|
||||
self.cache.addIfNotCached(statuses)
|
||||
}
|
||||
@ -294,10 +293,10 @@ private final class StatusCache {
|
||||
func addStatusIfNotCached(_ status: ArticleStatus) {
|
||||
addIfNotCached(Set([status]))
|
||||
}
|
||||
|
||||
|
||||
func addIfNotCached(_ statuses: Set<ArticleStatus>) {
|
||||
// Does not replace already cached statuses.
|
||||
|
||||
|
||||
for status in statuses {
|
||||
let articleID = status.articleID
|
||||
if let _ = self[articleID] {
|
||||
@ -316,5 +315,3 @@ private final class StatusCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user