From f0eea4917966eb92d1e1b8c9f13be00539fa9379 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Tue, 19 Sep 2017 13:36:13 -0700 Subject: [PATCH] Start working of moving from stubArticles to article dictionaries. --- Frameworks/Database/ArticlesTable.swift | 81 ++++++++++++++++--- .../Extensions/Article+Database.swift | 39 ++++++--- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/Frameworks/Database/ArticlesTable.swift b/Frameworks/Database/ArticlesTable.swift index 0f81a0a42..6218e1576 100644 --- a/Frameworks/Database/ArticlesTable.swift +++ b/Frameworks/Database/ArticlesTable.swift @@ -162,28 +162,89 @@ private extension ArticlesTable { // Then fetch the related objects, given the set of articleIDs. // Then create set of Articles *with* related objects and return it. - let stubArticles = makeStubArticles(with: resultSet) - if stubArticles.isEmpty { - return stubArticles + let articleDictionaries = makeArticleDictionaries(with: resultSet) + if articleDictionaries.isEmpty { + return Set
() } // Fetch related objects. - let articleIDs = stubArticles.articleIDs() + let articleIDs = articleDictionaries.map { $0[DatabaseKey.articleID] } let authorsMap = authorsLookupTable.fetchRelatedObjects(for: articleIDs, in: database) let attachmentsMap = attachmentsLookupTable.fetchRelatedObjects(for: articleIDs, in: database) let tagsMap = tagsLookupTable.fetchRelatedObjects(for: articleIDs, in: database) - - if authorsMap == nil && attachmentsMap == nil && tagsMap == nil { - return stubArticles - } - + + // TODO: get statusesDictionary from statusesTable + // Create articles with related objects. - let articles = Set(stubArticles.map { articleWithAttachedRelatedObjects($0, authorsMap, attachmentsMap, tagsMap) }) + let articles = Set(articleDictionaries.flatMap { articleWithDictionary($0, authorsMap, attachmentsMap, tagsMap) }) return articles } + func articleWithDictionary(_ articleDictionary: [String: Any], _ authorsMap: RelatedObjectsMap?, _ attachmentsMap: RelatedObjectsMap?, _ tagsMap: RelatedObjectsMap?) -> Article? { + + let articleID = articleDictionary[DatabaseKey.articleID]! + let status = articleDictionary[statusKey]! + let authors = authorsMap?.authors(for: articleID) + let attachments = attachmentsMap?.attachments(for: articleID) + let tags = tagsMap?.tags(for: articleID) + + return Author(dictionary: articleDictionary, status: status, accountID: accountID, authors: authors, attachments: attachments, tags: tags) + } + + func makeArticleDictionaries(with resultSet: FMResultSet) -> Set<[String: Any]> { + + let dictionaries = resultSet.mapToSet{ (row) -> [String: Any]? in + + // 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. + + guard let status = statusesTable.statusWithRow(resultSet) else { + assertionFailure("Expected status.") + return nil + } + + guard let let articleID = row.string(forColumn: DatabaseKey.articleID) else { + return nil + } + guard let feedID = row.string(forColumn: DatabaseKey.feedID) else { + return nil + } + guard let uniqueID = row.string(forColumn: DatabaseKey.uniqueID) else { + return nil + } + + var d = [String: Any]() + + d[statusKey] = status + d[DatabaseKey.articleID] = articleID + d[DatabaseKey.feedID] = feedID + d[DatabaseKey.uniqueID] = uniqueID + + if let title = row.string(forColumn: DatabaseKey.title) { + d[DatabaseKey.title] = title + } + + // TODO +// let contentHTML = row.string(forColumn: DatabaseKey.contentHTML) +// let contentText = row.string(forColumn: DatabaseKey.contentText) +// let url = row.string(forColumn: DatabaseKey.url) +// let externalURL = row.string(forColumn: DatabaseKey.externalURL) +// let summary = row.string(forColumn: DatabaseKey.summary) +// let imageURL = row.string(forColumn: DatabaseKey.imageURL) +// let bannerImageURL = row.string(forColumn: DatabaseKey.bannerImageURL) +// let datePublished = row.date(forColumn: DatabaseKey.datePublished) +// let dateModified = row.date(forColumn: DatabaseKey.dateModified) +// let accountInfo: AccountInfo? = nil // TODO +// + return d + } + resultSet.close() + + return dictionaries + } + func makeStubArticles(with resultSet: FMResultSet) -> Set
{ var stubArticles = Set
() diff --git a/Frameworks/Database/Extensions/Article+Database.swift b/Frameworks/Database/Extensions/Article+Database.swift index e4b22298f..940c9e905 100644 --- a/Frameworks/Database/Extensions/Article+Database.swift +++ b/Frameworks/Database/Extensions/Article+Database.swift @@ -38,6 +38,27 @@ extension Article { self.init(accountID: accountID, articleID: articleID, feedID: feedID, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo, status: status) } + init?(dictionary: [String: Any], accountID: String, status: ArticleStatus, authors: Set?, attachments: Set?, tags: Set?) { + + guard let articleID = dictionary[DatabaseKey.articleID], let feedID = dictionary[DatabaseKey.feedID], let uniqueID = dictionary[DatabaseKey.uniqueID] else { + return nil + } + + let title = dictionary[DatabaseKey.title] as? String + let contentHTML = dictionary[DatabaseKey.contentHTML] as? String + let contentText = dictionary[DatabaseKey.contentText] as? String + let url = dictionary[DatabaseKey.url] as? String + let externalURL = dictionary[DatabaseKey.externalURL] as? String + let summary = dictionary[DatabaseKey.summary] as? String + let imageURL = dictionary[DatabaseKey.imageURL] as? String + let bannerImageURL = dictionary[DatabaseKey.bannerImageURL] as? String + let datePublished = dictionary[DatabaseKey.datePublished] as? Date + let dateModified = dictionary[DatabaseKey.dateModified]? as? Date + let accountInfo: AccountInfo? = nil // TODO + + self.init(accountID: accountID, articleID: articleID, feedID: feedID, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo, status: status) + } + init(parsedItem: ParsedItem, accountID: String, feedID: String, status: ArticleStatus) { let authors = Author.authorsWithParsedAuthors(parsedItem.authors) @@ -46,15 +67,15 @@ 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, bannerImageURL: parsedItem.bannerImageURL, datePublished: parsedItem.datePublished, dateModified: parsedItem.dateModified, authors: authors, tags: parsedItem.tags, attachments: attachments, accountInfo: nil, status: status) } - func articleByAttaching(_ authors: Set?, _ attachments: Set?, _ tags: Set?) -> Article { - - if authors == nil && attachments == nil && tags == nil { - return self - } - - return Article(accountID: accountID, articleID: articleID, feedID: feedID, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo, status: status) - } - +// func articleByAttaching(_ authors: Set?, _ attachments: Set?, _ tags: Set?) -> Article { +// +// if authors == nil && attachments == nil && tags == nil { +// return self +// } +// +// return Article(accountID: accountID, articleID: articleID, feedID: feedID, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo, status: status) +// } + private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath, _ otherArticle: Article, _ key: String, _ dictionary: NSMutableDictionary) { if self[keyPath: comparisonKeyPath] != otherArticle[keyPath: comparisonKeyPath] {