This commit is contained in:
Justin Mazzocchi 2020-09-04 19:05:15 -07:00
parent 703dbfdf3c
commit 51e6a41bd3
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
13 changed files with 132 additions and 128 deletions

View file

@ -4,7 +4,7 @@ import Foundation
import GRDB
import Mastodon
struct StoredAccount: Codable, Hashable {
struct AccountRecord: Codable, Hashable {
let id: String
let username: String
let acct: String
@ -27,7 +27,7 @@ struct StoredAccount: Codable, Hashable {
let movedId: String?
}
extension StoredAccount: FetchableRecord, PersistableRecord {
extension AccountRecord: FetchableRecord, PersistableRecord {
static func databaseJSONDecoder(for column: String) -> JSONDecoder {
MastodonDecoder()
}
@ -37,8 +37,8 @@ extension StoredAccount: FetchableRecord, PersistableRecord {
}
}
extension StoredAccount {
static let moved = belongsTo(StoredAccount.self, key: "moved")
extension AccountRecord {
static let moved = belongsTo(AccountRecord.self, key: "moved")
init(account: Account) {
id = account.id

View file

@ -5,13 +5,13 @@ import GRDB
import Mastodon
struct AccountResult: Codable, Hashable, FetchableRecord {
let account: StoredAccount
let moved: StoredAccount?
let account: AccountRecord
let moved: AccountRecord?
}
extension QueryInterfaceRequest where RowDecoder == StoredAccount {
extension QueryInterfaceRequest where RowDecoder == AccountRecord {
var accountResultRequest: AnyFetchRequest<AccountResult> {
AnyFetchRequest(including(optional: StoredAccount.moved))
AnyFetchRequest(including(optional: AccountRecord.moved))
.asRequest(of: AccountResult.self)
}
}

View file

@ -133,13 +133,13 @@ public extension ContentDatabase {
ValueObservation.tracking(timeline.statuses.fetchAll)
.removeDuplicates()
.publisher(in: databaseQueue)
.map { [$0.map(Status.init(statusResult:))] }
.map { [$0.map(Status.init(result:))] }
.eraseToAnyPublisher()
}
func contextObservation(parentID: String) -> AnyPublisher<[[Status]], Error> {
ValueObservation.tracking { db -> [[StatusResult]] in
guard let parent = try StoredStatus.filter(Column("id") == parentID).statusResultRequest.fetchOne(db) else {
guard let parent = try StatusRecord.filter(Column("id") == parentID).statusResultRequest.fetchOne(db) else {
return [[]]
}
@ -150,7 +150,7 @@ public extension ContentDatabase {
}
.removeDuplicates()
.publisher(in: databaseQueue)
.map { $0.map { $0.map(Status.init(statusResult:)) } }
.map { $0.map { $0.map(Status.init(result:)) } }
.eraseToAnyPublisher()
}
@ -193,7 +193,7 @@ private extension ContentDatabase {
var migrator = DatabaseMigrator()
migrator.registerMigration("createStatuses") { db in
try db.create(table: "storedAccount", ifNotExists: true) { t in
try db.create(table: "accountRecord", ifNotExists: true) { t in
t.column("id", .text).notNull().primaryKey(onConflict: .replace)
t.column("username", .text).notNull()
t.column("acct", .text).notNull()
@ -213,14 +213,14 @@ private extension ContentDatabase {
t.column("emojis", .blob).notNull()
t.column("bot", .boolean).notNull()
t.column("discoverable", .boolean)
t.column("movedId", .text).indexed().references("storedAccount", column: "id")
t.column("movedId", .text).indexed().references("accountRecord", column: "id")
}
try db.create(table: "storedStatus", ifNotExists: true) { t in
try db.create(table: "statusRecord", ifNotExists: true) { t in
t.column("id", .text).notNull().primaryKey(onConflict: .replace)
t.column("uri", .text).notNull()
t.column("createdAt", .datetime).notNull()
t.column("accountId", .text).indexed().notNull().references("storedAccount", column: "id")
t.column("accountId", .text).indexed().notNull().references("accountRecord", column: "id")
t.column("content", .text).notNull()
t.column("visibility", .text).notNull()
t.column("sensitive", .boolean).notNull()
@ -236,7 +236,7 @@ private extension ContentDatabase {
t.column("url", .text)
t.column("inReplyToId", .text)
t.column("inReplyToAccountId", .text)
t.column("reblogId", .text).indexed().references("storedStatus", column: "id")
t.column("reblogId", .text).indexed().references("statusRecord", column: "id")
t.column("poll", .blob)
t.column("card", .blob)
t.column("language", .text)
@ -261,7 +261,7 @@ private extension ContentDatabase {
t.column("statusId", .text)
.indexed()
.notNull()
.references("storedStatus", column: "id", onDelete: .cascade, onUpdate: .cascade)
.references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade)
t.primaryKey(["timelineId", "statusId"], onConflict: .replace)
}
@ -270,11 +270,11 @@ private extension ContentDatabase {
t.column("parentId", .text)
.indexed()
.notNull()
.references("storedStatus", column: "id", onDelete: .cascade, onUpdate: .cascade)
.references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade)
t.column("statusId", .text)
.indexed()
.notNull()
.references("storedStatus", column: "id", onDelete: .cascade, onUpdate: .cascade)
.references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade)
t.column("section", .text).notNull()
t.column("index", .integer).notNull()

View file

@ -14,5 +14,5 @@ struct StatusContextJoin: Codable, FetchableRecord, PersistableRecord {
let section: Section
let index: Int
static let status = belongsTo(StoredStatus.self, using: ForeignKey([Column("statusId")]))
static let status = belongsTo(StatusRecord.self, using: ForeignKey([Column("statusId")]))
}

View file

@ -4,7 +4,7 @@ import Foundation
import GRDB
import Mastodon
struct StoredStatus: Codable, Hashable {
struct StatusRecord: Codable, Hashable {
let id: String
let uri: String
let createdAt: Date
@ -36,7 +36,7 @@ struct StoredStatus: Codable, Hashable {
let pinned: Bool?
}
extension StoredStatus: FetchableRecord, PersistableRecord {
extension StatusRecord: FetchableRecord, PersistableRecord {
static func databaseJSONDecoder(for column: String) -> JSONDecoder {
MastodonDecoder()
}
@ -46,31 +46,31 @@ extension StoredStatus: FetchableRecord, PersistableRecord {
}
}
extension StoredStatus {
static let account = belongsTo(StoredAccount.self, key: "account", using: ForeignKey([Column("accountId")]))
static let accountMoved = hasOne(StoredAccount.self,
extension StatusRecord {
static let account = belongsTo(AccountRecord.self, key: "account", using: ForeignKey([Column("accountId")]))
static let accountMoved = hasOne(AccountRecord.self,
through: Self.account,
using: StoredAccount.moved,
using: AccountRecord.moved,
key: "accountMoved")
static let reblogAccount = hasOne(StoredAccount.self,
static let reblogAccount = hasOne(AccountRecord.self,
through: Self.reblog,
using: Self.account,
key: "reblogAccount")
static let reblogAccountMoved = hasOne(StoredAccount.self,
static let reblogAccountMoved = hasOne(AccountRecord.self,
through: Self.reblogAccount,
using: StoredAccount.moved,
using: AccountRecord.moved,
key: "reblogAccountMoved")
static let reblog = belongsTo(StoredStatus.self, key: "reblog")
static let reblog = belongsTo(StatusRecord.self, key: "reblog")
static let ancestorJoins = hasMany(StatusContextJoin.self, using: ForeignKey([Column("parentID")]))
.filter(Column("section") == StatusContextJoin.Section.ancestors.rawValue)
.order(Column("index"))
static let descendantJoins = hasMany(StatusContextJoin.self, using: ForeignKey([Column("parentID")]))
.filter(Column("section") == StatusContextJoin.Section.descendants.rawValue)
.order(Column("index"))
static let ancestors = hasMany(StoredStatus.self,
static let ancestors = hasMany(StatusRecord.self,
through: ancestorJoins,
using: StatusContextJoin.status)
static let descendants = hasMany(StoredStatus.self,
static let descendants = hasMany(StatusRecord.self,
through: descendantJoins,
using: StatusContextJoin.status)

View file

@ -5,12 +5,12 @@ import GRDB
import Mastodon
struct StatusResult: Codable, Hashable, FetchableRecord {
let account: StoredAccount
let accountMoved: StoredAccount?
let status: StoredStatus
let reblogAccount: StoredAccount?
let reblogAccountMoved: StoredAccount?
let reblog: StoredStatus?
let account: AccountRecord
let accountMoved: AccountRecord?
let status: StatusRecord
let reblogAccount: AccountRecord?
let reblogAccountMoved: AccountRecord?
let reblog: StatusRecord?
}
extension StatusResult {
@ -25,13 +25,13 @@ extension StatusResult {
}
}
extension QueryInterfaceRequest where RowDecoder == StoredStatus {
extension QueryInterfaceRequest where RowDecoder == StatusRecord {
var statusResultRequest: AnyFetchRequest<StatusResult> {
AnyFetchRequest(including(required: StoredStatus.account)
.including(optional: StoredStatus.accountMoved)
.including(optional: StoredStatus.reblogAccount)
.including(optional: StoredStatus.reblogAccountMoved)
.including(optional: StoredStatus.reblog))
AnyFetchRequest(including(required: StatusRecord.account)
.including(optional: StatusRecord.accountMoved)
.including(optional: StatusRecord.reblogAccount)
.including(optional: StatusRecord.reblogAccountMoved)
.including(optional: StatusRecord.reblog))
.asRequest(of: StatusResult.self)
}
}

View file

@ -7,5 +7,5 @@ struct TimelineStatusJoin: Codable, FetchableRecord, PersistableRecord {
let timelineId: String
let statusId: String
static let status = belongsTo(StoredStatus.self)
static let status = belongsTo(StatusRecord.self)
}

View file

@ -7,42 +7,44 @@ import Mastodon
extension Account {
func save(_ db: Database) throws {
if let moved = moved {
try StoredAccount(account: moved).save(db)
try AccountRecord(account: moved).save(db)
}
try StoredAccount(account: self).save(db)
try AccountRecord(account: self).save(db)
}
convenience init(accountResult: AccountResult) {
convenience init(result: AccountResult) {
var moved: Account?
if let movedResult = accountResult.moved {
moved = Self(storedAccount: movedResult, moved: nil)
if let movedRecord = result.moved {
moved = Self(record: movedRecord, moved: nil)
}
self.init(storedAccount: accountResult.account, moved: moved)
self.init(record: result.account, moved: moved)
}
}
convenience init(storedAccount: StoredAccount, moved: Account?) {
self.init(id: storedAccount.id,
username: storedAccount.username,
acct: storedAccount.acct,
displayName: storedAccount.displayName,
locked: storedAccount.locked,
createdAt: storedAccount.createdAt,
followersCount: storedAccount.followersCount,
followingCount: storedAccount.followingCount,
statusesCount: storedAccount.statusesCount,
note: storedAccount.note,
url: storedAccount.url,
avatar: storedAccount.avatar,
avatarStatic: storedAccount.avatarStatic,
header: storedAccount.header,
headerStatic: storedAccount.headerStatic,
fields: storedAccount.fields,
emojis: storedAccount.emojis,
bot: storedAccount.bot,
discoverable: storedAccount.discoverable,
private extension Account {
convenience init(record: AccountRecord, moved: Account?) {
self.init(id: record.id,
username: record.username,
acct: record.acct,
displayName: record.displayName,
locked: record.locked,
createdAt: record.createdAt,
followersCount: record.followersCount,
followingCount: record.followingCount,
statusesCount: record.statusesCount,
note: record.note,
url: record.url,
avatar: record.avatar,
avatarStatic: record.avatarStatic,
header: record.header,
headerStatic: record.headerStatic,
fields: record.fields,
emojis: record.emojis,
bot: record.bot,
discoverable: record.discoverable,
moved: moved)
}
}

View file

@ -10,54 +10,56 @@ extension Status {
if let reblog = reblog {
try reblog.account.save(db)
try StoredStatus(status: reblog).save(db)
try StatusRecord(status: reblog).save(db)
}
try StoredStatus(status: self).save(db)
try StatusRecord(status: self).save(db)
}
convenience init(statusResult: StatusResult) {
convenience init(result: StatusResult) {
var reblog: Status?
if let reblogResult = statusResult.reblog, let reblogAccount = statusResult.reblogAccountResult {
reblog = Status(storedStatus: reblogResult, account: Account(accountResult: reblogAccount), reblog: nil)
if let reblogResult = result.reblog, let reblogAccountResult = result.reblogAccountResult {
reblog = Status(record: reblogResult, account: Account(result: reblogAccountResult), reblog: nil)
}
self.init(storedStatus: statusResult.status,
account: Account(accountResult: statusResult.accountResult),
self.init(record: result.status,
account: Account(result: result.accountResult),
reblog: reblog)
}
}
convenience init(storedStatus: StoredStatus, account: Account, reblog: Status?) {
private extension Status {
convenience init(record: StatusRecord, account: Account, reblog: Status?) {
self.init(
id: storedStatus.id,
uri: storedStatus.uri,
createdAt: storedStatus.createdAt,
id: record.id,
uri: record.uri,
createdAt: record.createdAt,
account: account,
content: storedStatus.content,
visibility: storedStatus.visibility,
sensitive: storedStatus.sensitive,
spoilerText: storedStatus.spoilerText,
mediaAttachments: storedStatus.mediaAttachments,
mentions: storedStatus.mentions,
tags: storedStatus.tags,
emojis: storedStatus.emojis,
reblogsCount: storedStatus.reblogsCount,
favouritesCount: storedStatus.favouritesCount,
repliesCount: storedStatus.repliesCount,
application: storedStatus.application,
url: storedStatus.url,
inReplyToId: storedStatus.inReplyToId,
inReplyToAccountId: storedStatus.inReplyToAccountId,
content: record.content,
visibility: record.visibility,
sensitive: record.sensitive,
spoilerText: record.spoilerText,
mediaAttachments: record.mediaAttachments,
mentions: record.mentions,
tags: record.tags,
emojis: record.emojis,
reblogsCount: record.reblogsCount,
favouritesCount: record.favouritesCount,
repliesCount: record.repliesCount,
application: record.application,
url: record.url,
inReplyToId: record.inReplyToId,
inReplyToAccountId: record.inReplyToAccountId,
reblog: reblog,
poll: storedStatus.poll,
card: storedStatus.card,
language: storedStatus.language,
text: storedStatus.text,
favourited: storedStatus.favourited,
reblogged: storedStatus.reblogged,
muted: storedStatus.muted,
bookmarked: storedStatus.bookmarked,
pinned: storedStatus.pinned)
poll: record.poll,
card: record.card,
language: record.language,
text: record.text,
favourited: record.favourited,
reblogged: record.reblogged,
muted: record.muted,
bookmarked: record.bookmarked,
pinned: record.pinned)
}
}

View file

@ -36,7 +36,7 @@ extension Timeline: FetchableRecord, PersistableRecord {
extension Timeline {
static let statusJoins = hasMany(TimelineStatusJoin.self)
static let statuses = hasMany(
StoredStatus.self,
StatusRecord.self,
through: statusJoins,
using: TimelineStatusJoin.status)
.order(Column("createdAt").desc)

View file

@ -39,7 +39,7 @@ public struct IdentityDatabase {
public extension IdentityDatabase {
func createIdentity(id: UUID, url: URL) -> AnyPublisher<Never, Error> {
databaseQueue.writePublisher(
updates: StoredIdentity(
updates: IdentityRecord(
id: id,
url: url,
lastUsedAt: Date(),
@ -53,14 +53,14 @@ public extension IdentityDatabase {
}
func deleteIdentity(id: UUID) -> AnyPublisher<Never, Error> {
databaseQueue.writePublisher(updates: StoredIdentity.filter(Column("id") == id).deleteAll)
databaseQueue.writePublisher(updates: IdentityRecord.filter(Column("id") == id).deleteAll)
.ignoreOutput()
.eraseToAnyPublisher()
}
func updateLastUsedAt(identityID: UUID) -> AnyPublisher<Never, Error> {
databaseQueue.writePublisher {
try StoredIdentity
try IdentityRecord
.filter(Column("id") == identityID)
.updateAll($0, Column("lastUsedAt").set(to: Date()))
}
@ -76,7 +76,7 @@ public extension IdentityDatabase {
title: instance.title,
thumbnail: instance.thumbnail)
.save($0)
try StoredIdentity
try IdentityRecord
.filter(Column("id") == identityID)
.updateAll($0, Column("instanceURI").set(to: instance.uri))
}
@ -105,9 +105,9 @@ public extension IdentityDatabase {
func updatePreferences(_ preferences: Identity.Preferences,
forIdentityID identityID: UUID) -> AnyPublisher<Never, Error> {
databaseQueue.writePublisher {
let data = try StoredIdentity.databaseJSONEncoder(for: "preferences").encode(preferences)
let data = try IdentityRecord.databaseJSONEncoder(for: "preferences").encode(preferences)
try StoredIdentity
try IdentityRecord
.filter(Column("id") == identityID)
.updateAll($0, Column("preferences").set(to: data))
}
@ -119,14 +119,14 @@ public extension IdentityDatabase {
deviceToken: String? = nil,
forIdentityID identityID: UUID) -> AnyPublisher<Never, Error> {
databaseQueue.writePublisher {
let data = try StoredIdentity.databaseJSONEncoder(for: "pushSubscriptionAlerts").encode(alerts)
let data = try IdentityRecord.databaseJSONEncoder(for: "pushSubscriptionAlerts").encode(alerts)
try StoredIdentity
try IdentityRecord
.filter(Column("id") == identityID)
.updateAll($0, Column("pushSubscriptionAlerts").set(to: data))
if let deviceToken = deviceToken {
try StoredIdentity
try IdentityRecord
.filter(Column("id") == identityID)
.updateAll($0, Column("lastRegisteredDeviceToken").set(to: deviceToken))
}
@ -137,10 +137,10 @@ public extension IdentityDatabase {
func identityObservation(id: UUID) -> AnyPublisher<Identity, Error> {
ValueObservation.tracking(
StoredIdentity
IdentityRecord
.filter(Column("id") == id)
.including(optional: StoredIdentity.instance)
.including(optional: StoredIdentity.account)
.including(optional: IdentityRecord.instance)
.including(optional: IdentityRecord.account)
.asRequest(of: IdentityResult.self)
.fetchOne)
.removeDuplicates()
@ -174,7 +174,7 @@ public extension IdentityDatabase {
}
func mostRecentlyUsedIdentityIDObservation() -> AnyPublisher<UUID?, Error> {
ValueObservation.tracking(StoredIdentity.select(Column("id")).order(Column("lastUsedAt").desc).fetchOne)
ValueObservation.tracking(IdentityRecord.select(Column("id")).order(Column("lastUsedAt").desc).fetchOne)
.removeDuplicates()
.publisher(in: databaseQueue, scheduling: .immediate)
.eraseToAnyPublisher()
@ -194,10 +194,10 @@ private extension IdentityDatabase {
private static let name = "Identity"
private static func identitiesRequest() -> QueryInterfaceRequest<IdentityResult> {
StoredIdentity
IdentityRecord
.order(Column("lastUsedAt").desc)
.including(optional: StoredIdentity.instance)
.including(optional: StoredIdentity.account)
.including(optional: IdentityRecord.instance)
.including(optional: IdentityRecord.account)
.asRequest(of: IdentityResult.self)
}
@ -212,7 +212,7 @@ private extension IdentityDatabase {
t.column("thumbnail", .text)
}
try db.create(table: "storedIdentity", ifNotExists: true) { t in
try db.create(table: "identityRecord", ifNotExists: true) { t in
t.column("id", .text).notNull().primaryKey(onConflict: .replace)
t.column("url", .text).notNull()
t.column("lastUsedAt", .datetime).notNull()
@ -229,7 +229,7 @@ private extension IdentityDatabase {
t.column("identityID", .text)
.notNull()
.indexed()
.references("storedIdentity", column: "id", onDelete: .cascade)
.references("identityRecord", column: "id", onDelete: .cascade)
t.column("username", .text).notNull()
t.column("displayName", .text).notNull()
t.column("url", .text).notNull()

View file

@ -4,7 +4,7 @@ import Foundation
import GRDB
import Mastodon
struct StoredIdentity: Codable, Hashable, FetchableRecord, PersistableRecord {
struct IdentityRecord: Codable, Hashable, FetchableRecord, PersistableRecord {
let id: UUID
let url: URL
let lastUsedAt: Date
@ -14,7 +14,7 @@ struct StoredIdentity: Codable, Hashable, FetchableRecord, PersistableRecord {
let pushSubscriptionAlerts: PushSubscription.Alerts
}
extension StoredIdentity {
extension IdentityRecord {
static let instance = belongsTo(Identity.Instance.self, key: "instance")
static let account = hasOne(Identity.Account.self, key: "account")

View file

@ -5,7 +5,7 @@ import GRDB
import Mastodon
struct IdentityResult: Codable, Hashable, FetchableRecord {
let identity: StoredIdentity
let identity: IdentityRecord
let instance: Identity.Instance?
let account: Identity.Account?
let pushSubscriptionAlerts: PushSubscription.Alerts