Remove references to tags. Fix #259.
This commit is contained in:
parent
fb9a1d610c
commit
fcda565d91
|
@ -575,7 +575,6 @@
|
||||||
849A975F1ED9EB95007D329B /* Sidebar */,
|
849A975F1ED9EB95007D329B /* Sidebar */,
|
||||||
849A97681ED9EBC8007D329B /* Timeline */,
|
849A97681ED9EBC8007D329B /* Timeline */,
|
||||||
849A977C1ED9EC42007D329B /* Detail */,
|
849A977C1ED9EC42007D329B /* Detail */,
|
||||||
849A97811ED9EC63007D329B /* Status Bar */,
|
|
||||||
849A97551ED9EAC3007D329B /* Add Feed */,
|
849A97551ED9EAC3007D329B /* Add Feed */,
|
||||||
849A97411ED9EAA9007D329B /* Add Folder */,
|
849A97411ED9EAA9007D329B /* Add Folder */,
|
||||||
84AFBB3A1FBE76D800BA41CF /* PanicButton */,
|
84AFBB3A1FBE76D800BA41CF /* PanicButton */,
|
||||||
|
@ -728,14 +727,6 @@
|
||||||
path = Detail;
|
path = Detail;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
849A97811ED9EC63007D329B /* Status Bar */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
name = "Status Bar";
|
|
||||||
path = StatusBar;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
849A97861ED9ECEF007D329B /* Article Styles */ = {
|
849A97861ED9ECEF007D329B /* Article Styles */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
|
@ -325,7 +325,7 @@ class TimelineViewController: NSViewController, KeyboardDelegate, UndoableComman
|
||||||
let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
|
let longTitle = "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
|
||||||
let prototypeID = "prototype"
|
let prototypeID = "prototype"
|
||||||
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
|
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, userDeleted: false, dateArrived: Date())
|
||||||
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, tags: nil, attachments: nil, status: status)
|
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, feedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, attachments: nil, status: status)
|
||||||
|
|
||||||
let prototypeCellData = TimelineCellData(article: prototypeArticle, appearance: cellAppearance, showFeedName: false, favicon: nil, avatar: nil, featuredImage: nil)
|
let prototypeCellData = TimelineCellData(article: prototypeArticle, appearance: cellAppearance, showFeedName: false, favicon: nil, avatar: nil, featuredImage: nil)
|
||||||
let height = timelineCellHeight(100, cellData: prototypeCellData, appearance: cellAppearance)
|
let height = timelineCellHeight(100, cellData: prototypeCellData, appearance: cellAppearance)
|
||||||
|
|
|
@ -25,12 +25,11 @@ public struct Article: Hashable {
|
||||||
public let datePublished: Date?
|
public let datePublished: Date?
|
||||||
public let dateModified: Date?
|
public let dateModified: Date?
|
||||||
public let authors: Set<Author>?
|
public let authors: Set<Author>?
|
||||||
public let tags: Set<String>?
|
|
||||||
public let attachments: Set<Attachment>?
|
public let attachments: Set<Attachment>?
|
||||||
public let status: ArticleStatus
|
public let status: ArticleStatus
|
||||||
public let hashValue: Int
|
public let hashValue: Int
|
||||||
|
|
||||||
public init(accountID: String, articleID: String?, feedID: String, uniqueID: String, title: String?, contentHTML: String?, contentText: String?, url: String?, externalURL: String?, summary: String?, imageURL: String?, bannerImageURL: String?, datePublished: Date?, dateModified: Date?, authors: Set<Author>?, tags: Set<String>?, attachments: Set<Attachment>?, status: ArticleStatus) {
|
public init(accountID: String, articleID: String?, feedID: String, uniqueID: String, title: String?, contentHTML: String?, contentText: String?, url: String?, externalURL: String?, summary: String?, imageURL: String?, bannerImageURL: String?, datePublished: Date?, dateModified: Date?, authors: Set<Author>?, attachments: Set<Attachment>?, status: ArticleStatus) {
|
||||||
|
|
||||||
self.accountID = accountID
|
self.accountID = accountID
|
||||||
self.feedID = feedID
|
self.feedID = feedID
|
||||||
|
@ -46,7 +45,6 @@ public struct Article: Hashable {
|
||||||
self.datePublished = datePublished
|
self.datePublished = datePublished
|
||||||
self.dateModified = dateModified
|
self.dateModified = dateModified
|
||||||
self.authors = authors
|
self.authors = authors
|
||||||
self.tags = tags
|
|
||||||
self.attachments = attachments
|
self.attachments = attachments
|
||||||
self.status = status
|
self.status = status
|
||||||
|
|
||||||
|
@ -67,7 +65,7 @@ public struct Article: Hashable {
|
||||||
|
|
||||||
public static func ==(lhs: Article, rhs: Article) -> Bool {
|
public static func ==(lhs: Article, rhs: Article) -> Bool {
|
||||||
|
|
||||||
return lhs.hashValue == rhs.hashValue && lhs.articleID == rhs.articleID && lhs.accountID == rhs.accountID && lhs.feedID == rhs.feedID && lhs.uniqueID == rhs.uniqueID && lhs.title == rhs.title && lhs.contentHTML == rhs.contentHTML && lhs.url == rhs.url && lhs.externalURL == rhs.externalURL && lhs.summary == rhs.summary && lhs.imageURL == rhs.imageURL && lhs.bannerImageURL == rhs.bannerImageURL && lhs.datePublished == rhs.datePublished && lhs.authors == rhs.authors && lhs.tags == rhs.tags && lhs.attachments == rhs.attachments
|
return lhs.hashValue == rhs.hashValue && lhs.articleID == rhs.articleID && lhs.accountID == rhs.accountID && lhs.feedID == rhs.feedID && lhs.uniqueID == rhs.uniqueID && lhs.title == rhs.title && lhs.contentHTML == rhs.contentHTML && lhs.url == rhs.url && lhs.externalURL == rhs.externalURL && lhs.summary == rhs.summary && lhs.imageURL == rhs.imageURL && lhs.bannerImageURL == rhs.bannerImageURL && lhs.datePublished == rhs.datePublished && lhs.authors == rhs.authors && lhs.attachments == rhs.attachments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ final class ArticlesTable: DatabaseTable {
|
||||||
private let statusesTable: StatusesTable
|
private let statusesTable: StatusesTable
|
||||||
private let authorsLookupTable: DatabaseLookupTable
|
private let authorsLookupTable: DatabaseLookupTable
|
||||||
private let attachmentsLookupTable: DatabaseLookupTable
|
private let attachmentsLookupTable: DatabaseLookupTable
|
||||||
private let tagsLookupTable: DatabaseLookupTable
|
|
||||||
|
|
||||||
// TODO: update articleCutoffDate as time passes and based on user preferences.
|
// TODO: update articleCutoffDate as time passes and based on user preferences.
|
||||||
private var articleCutoffDate = NSDate.rs_dateWithNumberOfDays(inThePast: 3 * 31)!
|
private var articleCutoffDate = NSDate.rs_dateWithNumberOfDays(inThePast: 3 * 31)!
|
||||||
|
@ -36,9 +35,6 @@ final class ArticlesTable: DatabaseTable {
|
||||||
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
||||||
self.authorsLookupTable = DatabaseLookupTable(name: DatabaseTableName.authorsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.authorID, relatedTable: authorsTable, relationshipName: RelationshipName.authors)
|
self.authorsLookupTable = DatabaseLookupTable(name: DatabaseTableName.authorsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.authorID, relatedTable: authorsTable, relationshipName: RelationshipName.authors)
|
||||||
|
|
||||||
let tagsTable = TagsTable(name: DatabaseTableName.tags)
|
|
||||||
self.tagsLookupTable = DatabaseLookupTable(name: DatabaseTableName.tags, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.tagName, relatedTable: tagsTable, relationshipName: RelationshipName.tags)
|
|
||||||
|
|
||||||
let attachmentsTable = AttachmentsTable(name: DatabaseTableName.attachments)
|
let attachmentsTable = AttachmentsTable(name: DatabaseTableName.attachments)
|
||||||
self.attachmentsLookupTable = DatabaseLookupTable(name: DatabaseTableName.attachmentsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.attachmentID, relatedTable: attachmentsTable, relationshipName: RelationshipName.attachments)
|
self.attachmentsLookupTable = DatabaseLookupTable(name: DatabaseTableName.attachmentsLookup, objectIDKey: DatabaseKey.articleID, relatedObjectIDKey: DatabaseKey.attachmentID, relatedTable: attachmentsTable, relationshipName: RelationshipName.attachments)
|
||||||
}
|
}
|
||||||
|
@ -265,25 +261,23 @@ private extension ArticlesTable {
|
||||||
|
|
||||||
let authorsMap = authorsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
let authorsMap = authorsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
||||||
let attachmentsMap = attachmentsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
let attachmentsMap = attachmentsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
||||||
let tagsMap = tagsLookupTable.fetchRelatedObjects(for: articleIDs, in: database)
|
|
||||||
|
|
||||||
// 3. Create articles with related objects.
|
// 3. Create articles with related objects.
|
||||||
|
|
||||||
let articles = databaseArticles.map { (databaseArticle) -> Article in
|
let articles = databaseArticles.map { (databaseArticle) -> Article in
|
||||||
return articleWithDatabaseArticle(databaseArticle, authorsMap, attachmentsMap, tagsMap)
|
return articleWithDatabaseArticle(databaseArticle, authorsMap, attachmentsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Set(articles)
|
return Set(articles)
|
||||||
}
|
}
|
||||||
|
|
||||||
func articleWithDatabaseArticle(_ databaseArticle: DatabaseArticle, _ authorsMap: RelatedObjectsMap?, _ attachmentsMap: RelatedObjectsMap?, _ tagsMap: RelatedObjectsMap?) -> Article {
|
func articleWithDatabaseArticle(_ databaseArticle: DatabaseArticle, _ authorsMap: RelatedObjectsMap?, _ attachmentsMap: RelatedObjectsMap?) -> Article {
|
||||||
|
|
||||||
let articleID = databaseArticle.articleID
|
let articleID = databaseArticle.articleID
|
||||||
let authors = authorsMap?.authors(for: articleID)
|
let authors = authorsMap?.authors(for: articleID)
|
||||||
let attachments = attachmentsMap?.attachments(for: articleID)
|
let attachments = attachmentsMap?.attachments(for: articleID)
|
||||||
let tags = tagsMap?.tags(for: articleID)
|
|
||||||
|
|
||||||
return Article(databaseArticle: databaseArticle, accountID: accountID, authors: authors, attachments: attachments, tags: tags)
|
return Article(databaseArticle: databaseArticle, accountID: accountID, authors: authors, attachments: attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDatabaseArticles(with resultSet: FMResultSet) -> Set<DatabaseArticle> {
|
func makeDatabaseArticles(with resultSet: FMResultSet) -> Set<DatabaseArticle> {
|
||||||
|
@ -425,7 +419,6 @@ private extension ArticlesTable {
|
||||||
|
|
||||||
authorsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
authorsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
||||||
attachmentsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
attachmentsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
||||||
tagsLookupTable.saveRelatedObjects(for: databaseObjects, in: database)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Update Existing Articles
|
// MARK: Update Existing Articles
|
||||||
|
@ -451,7 +444,6 @@ private extension ArticlesTable {
|
||||||
|
|
||||||
func saveUpdatedRelatedObjects(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
|
func saveUpdatedRelatedObjects(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
|
||||||
|
|
||||||
updateRelatedObjects(\Article.tags, updatedArticles, fetchedArticles, tagsLookupTable, database)
|
|
||||||
updateRelatedObjects(\Article.authors, updatedArticles, fetchedArticles, authorsLookupTable, database)
|
updateRelatedObjects(\Article.authors, updatedArticles, fetchedArticles, authorsLookupTable, database)
|
||||||
updateRelatedObjects(\Article.attachments, updatedArticles, fetchedArticles, attachmentsLookupTable, database)
|
updateRelatedObjects(\Article.attachments, updatedArticles, fetchedArticles, attachmentsLookupTable, database)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ struct DatabaseTableName {
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let authorsLookup = "authorsLookup"
|
static let authorsLookup = "authorsLookup"
|
||||||
static let statuses = "statuses"
|
static let statuses = "statuses"
|
||||||
static let tags = "tags"
|
|
||||||
static let attachments = "attachments"
|
static let attachments = "attachments"
|
||||||
static let attachmentsLookup = "attachmentsLookup"
|
static let attachmentsLookup = "attachmentsLookup"
|
||||||
}
|
}
|
||||||
|
@ -40,7 +39,6 @@ struct DatabaseKey {
|
||||||
static let datePublished = "datePublished"
|
static let datePublished = "datePublished"
|
||||||
static let dateModified = "dateModified"
|
static let dateModified = "dateModified"
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let tags = "tags"
|
|
||||||
static let attachments = "attachments"
|
static let attachments = "attachments"
|
||||||
|
|
||||||
// ArticleStatus
|
// ArticleStatus
|
||||||
|
@ -68,6 +66,5 @@ struct DatabaseKey {
|
||||||
struct RelationshipName {
|
struct RelationshipName {
|
||||||
|
|
||||||
static let authors = "authors"
|
static let authors = "authors"
|
||||||
static let tags = "tags"
|
|
||||||
static let attachments = "attachments"
|
static let attachments = "attachments"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,11 @@ CREATE TABLE if not EXISTS statuses (articleID TEXT NOT NULL PRIMARY KEY, read B
|
||||||
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 authors (authorID TEXT NOT NULL PRIMARY KEY, name TEXT, url TEXT, avatarURL TEXT, emailAddress TEXT);
|
||||||
CREATE TABLE if not EXISTS authorsLookup (authorID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(authorID, articleID));
|
CREATE TABLE if not EXISTS authorsLookup (authorID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(authorID, articleID));
|
||||||
|
|
||||||
CREATE TABLE if not EXISTS tags(tagName TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(tagName, articleID));
|
|
||||||
|
|
||||||
CREATE TABLE if not EXISTS attachments(attachmentID TEXT NOT NULL PRIMARY KEY, url TEXT NOT NULL, mimeType TEXT, title TEXT, sizeInBytes INTEGER, durationInSeconds INTEGER);
|
CREATE TABLE if not EXISTS attachments(attachmentID TEXT NOT NULL PRIMARY KEY, url TEXT NOT NULL, mimeType TEXT, title TEXT, sizeInBytes INTEGER, durationInSeconds INTEGER);
|
||||||
CREATE TABLE if not EXISTS attachmentsLookup(attachmentID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(attachmentID, articleID));
|
CREATE TABLE if not EXISTS attachmentsLookup(attachmentID TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(attachmentID, articleID));
|
||||||
|
|
||||||
CREATE INDEX if not EXISTS articles_feedID_index on articles (feedID);
|
CREATE INDEX if not EXISTS articles_feedID_index on articles (feedID);
|
||||||
|
|
||||||
CREATE INDEX if not EXISTS tags_tagName_index on tags (tagName COLLATE NOCASE);
|
|
||||||
|
|
||||||
CREATE INDEX if not EXISTS statuses_read_index on statuses (read);
|
CREATE INDEX if not EXISTS statuses_read_index on statuses (read);
|
||||||
CREATE INDEX if not EXISTS statuses_starred_index on statuses (starred);
|
CREATE INDEX if not EXISTS statuses_starred_index on statuses (starred);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@ public final class Database {
|
||||||
let createStatementsPath = Bundle(for: type(of: self)).path(forResource: "CreateStatements", ofType: "sql")!
|
let createStatementsPath = Bundle(for: type(of: self)).path(forResource: "CreateStatements", ofType: "sql")!
|
||||||
let createStatements = try! NSString(contentsOfFile: createStatementsPath, encoding: String.Encoding.utf8.rawValue)
|
let createStatements = try! NSString(contentsOfFile: createStatementsPath, encoding: String.Encoding.utf8.rawValue)
|
||||||
queue.createTables(usingStatements: createStatements as String)
|
queue.createTables(usingStatements: createStatements as String)
|
||||||
|
queue.update { (database) in
|
||||||
|
database.executeStatements("DROP TABLE if EXISTS tags;DROP INDEX if EXISTS tags_tagName_index;")
|
||||||
|
}
|
||||||
queue.vacuumIfNeeded()
|
queue.vacuumIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846FB36A1F4A937B00EAB81D /* Feed+Database.swift */; };
|
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846FB36A1F4A937B00EAB81D /* Feed+Database.swift */; };
|
||||||
848AD2961F58A91E004FB0EC /* UnreadCountDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */; };
|
848AD2961F58A91E004FB0EC /* UnreadCountDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */; };
|
||||||
84BB4BA21F119C5400858766 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84BB4B981F119C4900858766 /* RSCore.framework */; };
|
84BB4BA21F119C5400858766 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84BB4B981F119C4900858766 /* RSCore.framework */; };
|
||||||
84BB4BA91F11A32800858766 /* TagsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BB4BA81F11A32800858766 /* TagsTable.swift */; };
|
|
||||||
84D0DEA11F4A429800073503 /* String+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D0DEA01F4A429800073503 /* String+Database.swift */; };
|
|
||||||
84E156EA1F0AB80500F8CC05 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E156E91F0AB80500F8CC05 /* Database.swift */; };
|
84E156EA1F0AB80500F8CC05 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E156E91F0AB80500F8CC05 /* Database.swift */; };
|
||||||
84E156EC1F0AB80E00F8CC05 /* ArticlesTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E156EB1F0AB80E00F8CC05 /* ArticlesTable.swift */; };
|
84E156EC1F0AB80E00F8CC05 /* ArticlesTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E156EB1F0AB80E00F8CC05 /* ArticlesTable.swift */; };
|
||||||
84E156EE1F0AB81400F8CC05 /* StatusesTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E156ED1F0AB81400F8CC05 /* StatusesTable.swift */; };
|
84E156EE1F0AB81400F8CC05 /* StatusesTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E156ED1F0AB81400F8CC05 /* StatusesTable.swift */; };
|
||||||
|
@ -134,8 +132,6 @@
|
||||||
846FB36A1F4A937B00EAB81D /* Feed+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Feed+Database.swift"; path = "Extensions/Feed+Database.swift"; sourceTree = "<group>"; };
|
846FB36A1F4A937B00EAB81D /* Feed+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Feed+Database.swift"; path = "Extensions/Feed+Database.swift"; sourceTree = "<group>"; };
|
||||||
848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountDictionary.swift; sourceTree = "<group>"; };
|
848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountDictionary.swift; sourceTree = "<group>"; };
|
||||||
84BB4B8F1F119C4900858766 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
84BB4B8F1F119C4900858766 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
||||||
84BB4BA81F11A32800858766 /* TagsTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsTable.swift; sourceTree = "<group>"; };
|
|
||||||
84D0DEA01F4A429800073503 /* String+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "String+Database.swift"; path = "Extensions/String+Database.swift"; sourceTree = "<group>"; };
|
|
||||||
84E156E81F0AB75600F8CC05 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
84E156E81F0AB75600F8CC05 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
84E156E91F0AB80500F8CC05 /* Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
|
84E156E91F0AB80500F8CC05 /* Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
|
||||||
84E156EB1F0AB80E00F8CC05 /* ArticlesTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticlesTable.swift; sourceTree = "<group>"; };
|
84E156EB1F0AB80E00F8CC05 /* ArticlesTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArticlesTable.swift; sourceTree = "<group>"; };
|
||||||
|
@ -180,7 +176,6 @@
|
||||||
843577151F744FC800F460AE /* DatabaseArticle.swift */,
|
843577151F744FC800F460AE /* DatabaseArticle.swift */,
|
||||||
84E156ED1F0AB81400F8CC05 /* StatusesTable.swift */,
|
84E156ED1F0AB81400F8CC05 /* StatusesTable.swift */,
|
||||||
84F20F8E1F180D8700D8E682 /* AuthorsTable.swift */,
|
84F20F8E1F180D8700D8E682 /* AuthorsTable.swift */,
|
||||||
84BB4BA81F11A32800858766 /* TagsTable.swift */,
|
|
||||||
840405CE1F1A963700DF0296 /* AttachmentsTable.swift */,
|
840405CE1F1A963700DF0296 /* AttachmentsTable.swift */,
|
||||||
8461462A1F0AC44100870CB3 /* Extensions */,
|
8461462A1F0AC44100870CB3 /* Extensions */,
|
||||||
84E156EF1F0AB81F00F8CC05 /* CreateStatements.sql */,
|
84E156EF1F0AB81F00F8CC05 /* CreateStatements.sql */,
|
||||||
|
@ -228,7 +223,6 @@
|
||||||
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */,
|
845580791F0AF67D003CCFA1 /* ArticleStatus+Database.swift */,
|
||||||
84F20F901F1810DD00D8E682 /* Author+Database.swift */,
|
84F20F901F1810DD00D8E682 /* Author+Database.swift */,
|
||||||
8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */,
|
8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */,
|
||||||
84D0DEA01F4A429800073503 /* String+Database.swift */,
|
|
||||||
842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */,
|
842889FF1F6A3C4400395871 /* DatabaseObject+Database.swift */,
|
||||||
84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */,
|
84288A011F6A3D8000395871 /* RelatedObjectsMap+Database.swift */,
|
||||||
);
|
);
|
||||||
|
@ -481,14 +475,12 @@
|
||||||
files = (
|
files = (
|
||||||
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */,
|
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */,
|
||||||
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */,
|
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */,
|
||||||
84D0DEA11F4A429800073503 /* String+Database.swift in Sources */,
|
|
||||||
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
|
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
|
||||||
848AD2961F58A91E004FB0EC /* UnreadCountDictionary.swift in Sources */,
|
848AD2961F58A91E004FB0EC /* UnreadCountDictionary.swift in Sources */,
|
||||||
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
|
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
|
||||||
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
|
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
|
||||||
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */,
|
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */,
|
||||||
84288A021F6A3D8000395871 /* RelatedObjectsMap+Database.swift in Sources */,
|
84288A021F6A3D8000395871 /* RelatedObjectsMap+Database.swift in Sources */,
|
||||||
84BB4BA91F11A32800858766 /* TagsTable.swift in Sources */,
|
|
||||||
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */,
|
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */,
|
||||||
84F20F8F1F180D8700D8E682 /* AuthorsTable.swift in Sources */,
|
84F20F8F1F180D8700D8E682 /* AuthorsTable.swift in Sources */,
|
||||||
84288A001F6A3C4400395871 /* DatabaseObject+Database.swift in Sources */,
|
84288A001F6A3C4400395871 /* DatabaseObject+Database.swift in Sources */,
|
||||||
|
|
|
@ -12,12 +12,6 @@ import Data
|
||||||
|
|
||||||
extension Array where Element == DatabaseObject {
|
extension Array where Element == DatabaseObject {
|
||||||
|
|
||||||
func asTags() -> Set<String>? {
|
|
||||||
|
|
||||||
let tags = Set(self.map { $0 as! String })
|
|
||||||
return tags.isEmpty ? nil : tags
|
|
||||||
}
|
|
||||||
|
|
||||||
func asAuthors() -> Set<Author>? {
|
func asAuthors() -> Set<Author>? {
|
||||||
|
|
||||||
let authors = Set(self.map { $0 as! Author })
|
let authors = Set(self.map { $0 as! Author })
|
||||||
|
|
|
@ -13,9 +13,9 @@ import RSParser
|
||||||
|
|
||||||
extension Article {
|
extension Article {
|
||||||
|
|
||||||
init(databaseArticle: DatabaseArticle, accountID: String, authors: Set<Author>?, attachments: Set<Attachment>?, tags: Set<String>?) {
|
init(databaseArticle: DatabaseArticle, accountID: String, authors: Set<Author>?, attachments: Set<Attachment>?) {
|
||||||
|
|
||||||
self.init(accountID: accountID, articleID: databaseArticle.articleID, feedID: databaseArticle.feedID, uniqueID: databaseArticle.uniqueID, title: databaseArticle.title, contentHTML: databaseArticle.contentHTML, contentText: databaseArticle.contentText, url: databaseArticle.url, externalURL: databaseArticle.externalURL, summary: databaseArticle.summary, imageURL: databaseArticle.imageURL, bannerImageURL: databaseArticle.bannerImageURL, datePublished: databaseArticle.datePublished, dateModified: databaseArticle.dateModified, authors: authors, tags: tags, attachments: attachments, status: databaseArticle.status)
|
self.init(accountID: accountID, articleID: databaseArticle.articleID, feedID: databaseArticle.feedID, uniqueID: databaseArticle.uniqueID, title: databaseArticle.title, contentHTML: databaseArticle.contentHTML, contentText: databaseArticle.contentText, url: databaseArticle.url, externalURL: databaseArticle.externalURL, summary: databaseArticle.summary, imageURL: databaseArticle.imageURL, bannerImageURL: databaseArticle.bannerImageURL, datePublished: databaseArticle.datePublished, dateModified: databaseArticle.dateModified, authors: authors, attachments: attachments, status: databaseArticle.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(parsedItem: ParsedItem, accountID: String, feedID: String, status: ArticleStatus) {
|
init(parsedItem: ParsedItem, accountID: String, feedID: String, status: ArticleStatus) {
|
||||||
|
@ -23,7 +23,7 @@ extension Article {
|
||||||
let authors = Author.authorsWithParsedAuthors(parsedItem.authors)
|
let authors = Author.authorsWithParsedAuthors(parsedItem.authors)
|
||||||
let attachments = Attachment.attachmentsWithParsedAttachments(parsedItem.attachments)
|
let attachments = Attachment.attachmentsWithParsedAttachments(parsedItem.attachments)
|
||||||
|
|
||||||
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, status: status)
|
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, attachments: attachments, status: status)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: NSMutableDictionary) {
|
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: NSMutableDictionary) {
|
||||||
|
@ -120,8 +120,6 @@ extension Article: DatabaseObject {
|
||||||
switch name {
|
switch name {
|
||||||
case RelationshipName.authors:
|
case RelationshipName.authors:
|
||||||
return databaseObjectArray(with: authors)
|
return databaseObjectArray(with: authors)
|
||||||
case RelationshipName.tags:
|
|
||||||
return databaseObjectArray(with: tags)
|
|
||||||
case RelationshipName.attachments:
|
case RelationshipName.attachments:
|
||||||
return databaseObjectArray(with: attachments)
|
return databaseObjectArray(with: attachments)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
//
|
|
||||||
// String+Database.swift
|
|
||||||
// Database
|
|
||||||
//
|
|
||||||
// Created by Brent Simmons on 8/20/17.
|
|
||||||
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import RSDatabase
|
|
||||||
|
|
||||||
// A tag is a String.
|
|
||||||
// Extending tag to conform to DatabaseObject means extending String to conform to DatabaseObject.
|
|
||||||
|
|
||||||
extension String: DatabaseObject {
|
|
||||||
|
|
||||||
public func databaseDictionary() -> NSDictionary? {
|
|
||||||
|
|
||||||
preconditionFailure("databaseDictionary() called for a tag: this should never happen.")
|
|
||||||
}
|
|
||||||
|
|
||||||
public var databaseID: String {
|
|
||||||
get {
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,4 @@ extension RelatedObjectsMap {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tags(for articleID: String) -> Set<String>? {
|
|
||||||
|
|
||||||
if let objects = self[articleID] {
|
|
||||||
return objects.asTags()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
//
|
|
||||||
// TagsManager.swift
|
|
||||||
// Database
|
|
||||||
//
|
|
||||||
// Created by Brent Simmons on 7/8/17.
|
|
||||||
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import RSDatabase
|
|
||||||
import Data
|
|
||||||
|
|
||||||
// Article->tags is a many-to-many relationship.
|
|
||||||
// Since a tag is just a String, the tags table and the lookup table are the same table.
|
|
||||||
// All the heavy lifting is done in DatabaseLookupTable.
|
|
||||||
//
|
|
||||||
// CREATE TABLE if not EXISTS tags(tagName TEXT NOT NULL, articleID TEXT NOT NULL, PRIMARY KEY(tagName, articleID));
|
|
||||||
// CREATE INDEX if not EXISTS tags_tagName_index on tags (tagName COLLATE NOCASE);
|
|
||||||
|
|
||||||
final class TagsTable: DatabaseRelatedObjectsTable {
|
|
||||||
|
|
||||||
let name: String
|
|
||||||
let databaseIDKey = DatabaseKey.tagName
|
|
||||||
let cache = DatabaseObjectCache() // Unused, but protocol requires it
|
|
||||||
|
|
||||||
init(name: String) {
|
|
||||||
|
|
||||||
self.name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: DatabaseTable Methods
|
|
||||||
|
|
||||||
func fetchObjectsWithIDs(_ databaseIDs: Set<String>, in database: FMDatabase) -> [DatabaseObject]? {
|
|
||||||
|
|
||||||
// A tag is a string, and it is its own databaseID.
|
|
||||||
return databaseIDs.map{ $0 as DatabaseObject }
|
|
||||||
}
|
|
||||||
|
|
||||||
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
|
||||||
|
|
||||||
return nil //unused
|
|
||||||
}
|
|
||||||
|
|
||||||
func save(_ objects: [DatabaseObject], in database: FMDatabase) {
|
|
||||||
|
|
||||||
// Nothing to do, since tags are saved in the lookup table, not in a separate table.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
// Protocol for a database table for related objects — authors, tags, and attachments in Evergreen, for instance.
|
// Protocol for a database table for related objects — authors and attachments in Evergreen, for instance.
|
||||||
|
|
||||||
public protocol DatabaseRelatedObjectsTable: DatabaseTable {
|
public protocol DatabaseRelatedObjectsTable: DatabaseTable {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue