diff --git a/DB/Sources/DB/Content/ContentDatabase+Migration.swift b/DB/Sources/DB/Content/ContentDatabase+Migration.swift new file mode 100644 index 0000000..d845e73 --- /dev/null +++ b/DB/Sources/DB/Content/ContentDatabase+Migration.swift @@ -0,0 +1,136 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import GRDB + +extension ContentDatabase { + var migrator: DatabaseMigrator { + var migrator = DatabaseMigrator() + + migrator.registerMigration("0.1.0") { db in + try db.create(table: "accountRecord") { t in + t.column("id", .text).primaryKey(onConflict: .replace) + t.column("username", .text).notNull() + t.column("acct", .text).notNull() + t.column("displayName", .text).notNull() + t.column("locked", .boolean).notNull() + t.column("createdAt", .date).notNull() + t.column("followersCount", .integer).notNull() + t.column("followingCount", .integer).notNull() + t.column("statusesCount", .integer).notNull() + t.column("note", .text).notNull() + t.column("url", .text).notNull() + t.column("avatar", .text).notNull() + t.column("avatarStatic", .text).notNull() + t.column("header", .text).notNull() + t.column("headerStatic", .text).notNull() + t.column("fields", .blob).notNull() + t.column("emojis", .blob).notNull() + t.column("bot", .boolean).notNull() + t.column("discoverable", .boolean) + t.column("movedId", .text).references("accountRecord", column: "id") + } + + try db.create(table: "statusRecord") { t in + t.column("id", .text).primaryKey(onConflict: .replace) + t.column("uri", .text).notNull() + t.column("createdAt", .datetime).notNull() + t.column("accountId", .text).notNull().references("accountRecord", column: "id") + t.column("content", .text).notNull() + t.column("visibility", .text).notNull() + t.column("sensitive", .boolean).notNull() + t.column("spoilerText", .text).notNull() + t.column("mediaAttachments", .blob).notNull() + t.column("mentions", .blob).notNull() + t.column("tags", .blob).notNull() + t.column("emojis", .blob).notNull() + t.column("reblogsCount", .integer).notNull() + t.column("favouritesCount", .integer).notNull() + t.column("repliesCount", .integer).notNull() + t.column("application", .blob) + t.column("url", .text) + t.column("inReplyToId", .text) + t.column("inReplyToAccountId", .text) + t.column("reblogId", .text).references("statusRecord", column: "id") + t.column("poll", .blob) + t.column("card", .blob) + t.column("language", .text) + t.column("text", .text) + t.column("favourited", .boolean).notNull() + t.column("reblogged", .boolean).notNull() + t.column("muted", .boolean).notNull() + t.column("bookmarked", .boolean).notNull() + t.column("pinned", .boolean) + } + + try db.create(table: "timeline") { t in + t.column("id", .text).primaryKey(onConflict: .replace) + t.column("listTitle", .text).indexed().collate(.localizedCaseInsensitiveCompare) + } + + try db.create(table: "timelineStatusJoin") { t in + t.column("timelineId", .text).indexed().notNull() + .references("timeline", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("statusId", .text).indexed().notNull() + .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + + t.primaryKey(["timelineId", "statusId"], onConflict: .replace) + } + + try db.create(table: "filter") { t in + t.column("id", .text).primaryKey(onConflict: .replace) + t.column("phrase", .text).notNull() + t.column("context", .blob).notNull() + t.column("expiresAt", .date).indexed() + t.column("irreversible", .boolean).notNull() + t.column("wholeWord", .boolean).notNull() + } + + try db.create(table: "statusContextJoin") { t in + t.column("parentId", .text).indexed().notNull() + .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("statusId", .text).indexed().notNull() + .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("section", .text).indexed().notNull() + t.column("index", .integer).notNull() + + t.primaryKey(["parentId", "statusId"], onConflict: .replace) + } + + try db.create(table: "accountPinnedStatusJoin") { t in + t.column("accountId", .text).indexed().notNull() + .references("accountRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("statusId", .text).indexed().notNull() + .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("index", .integer).notNull() + + t.primaryKey(["accountId", "statusId"], onConflict: .replace) + } + + try db.create(table: "accountStatusJoin") { t in + t.column("accountId", .text).indexed().notNull() + .references("accountRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("statusId", .text).indexed().notNull() + .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("collection", .text).indexed().notNull() + + t.primaryKey(["accountId", "statusId", "collection"], onConflict: .replace) + } + + try db.create(table: "accountList") { t in + t.column("id", .text).primaryKey(onConflict: .replace) + } + + try db.create(table: "accountListJoin") { t in + t.column("accountId", .text).indexed().notNull() + .references("accountRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("listId", .text).indexed().notNull() + .references("accountList", column: "id", onDelete: .cascade, onUpdate: .cascade) + t.column("index", .integer).notNull() + + t.primaryKey(["accountId", "listId"], onConflict: .replace) + } + } + + return migrator + } +} diff --git a/DB/Sources/DB/Content/ContentDatabase.swift b/DB/Sources/DB/Content/ContentDatabase.swift index d5d2ee9..746ceae 100644 --- a/DB/Sources/DB/Content/ContentDatabase.swift +++ b/DB/Sources/DB/Content/ContentDatabase.swift @@ -7,7 +7,6 @@ import Keychain import Mastodon import Secrets -// swiftlint:disable file_length public struct ContentDatabase { private let databaseWriter: DatabaseWriter @@ -294,137 +293,6 @@ private extension ContentDatabase { try FileManager.default.databaseDirectoryURL(name: identityID.uuidString) } - private var migrator: DatabaseMigrator { - var migrator = DatabaseMigrator() - - migrator.registerMigration("0.1.0") { db in - try db.create(table: "accountRecord") { t in - t.column("id", .text).primaryKey(onConflict: .replace) - t.column("username", .text).notNull() - t.column("acct", .text).notNull() - t.column("displayName", .text).notNull() - t.column("locked", .boolean).notNull() - t.column("createdAt", .date).notNull() - t.column("followersCount", .integer).notNull() - t.column("followingCount", .integer).notNull() - t.column("statusesCount", .integer).notNull() - t.column("note", .text).notNull() - t.column("url", .text).notNull() - t.column("avatar", .text).notNull() - t.column("avatarStatic", .text).notNull() - t.column("header", .text).notNull() - t.column("headerStatic", .text).notNull() - t.column("fields", .blob).notNull() - t.column("emojis", .blob).notNull() - t.column("bot", .boolean).notNull() - t.column("discoverable", .boolean) - t.column("movedId", .text).references("accountRecord", column: "id") - } - - try db.create(table: "statusRecord") { t in - t.column("id", .text).primaryKey(onConflict: .replace) - t.column("uri", .text).notNull() - t.column("createdAt", .datetime).notNull() - t.column("accountId", .text).notNull().references("accountRecord", column: "id") - t.column("content", .text).notNull() - t.column("visibility", .text).notNull() - t.column("sensitive", .boolean).notNull() - t.column("spoilerText", .text).notNull() - t.column("mediaAttachments", .blob).notNull() - t.column("mentions", .blob).notNull() - t.column("tags", .blob).notNull() - t.column("emojis", .blob).notNull() - t.column("reblogsCount", .integer).notNull() - t.column("favouritesCount", .integer).notNull() - t.column("repliesCount", .integer).notNull() - t.column("application", .blob) - t.column("url", .text) - t.column("inReplyToId", .text) - t.column("inReplyToAccountId", .text) - t.column("reblogId", .text).references("statusRecord", column: "id") - t.column("poll", .blob) - t.column("card", .blob) - t.column("language", .text) - t.column("text", .text) - t.column("favourited", .boolean).notNull() - t.column("reblogged", .boolean).notNull() - t.column("muted", .boolean).notNull() - t.column("bookmarked", .boolean).notNull() - t.column("pinned", .boolean) - } - - try db.create(table: "timeline") { t in - t.column("id", .text).primaryKey(onConflict: .replace) - t.column("listTitle", .text).indexed().collate(.localizedCaseInsensitiveCompare) - } - - try db.create(table: "timelineStatusJoin") { t in - t.column("timelineId", .text).indexed().notNull() - .references("timeline", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("statusId", .text).indexed().notNull() - .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - - t.primaryKey(["timelineId", "statusId"], onConflict: .replace) - } - - try db.create(table: "filter") { t in - t.column("id", .text).primaryKey(onConflict: .replace) - t.column("phrase", .text).notNull() - t.column("context", .blob).notNull() - t.column("expiresAt", .date).indexed() - t.column("irreversible", .boolean).notNull() - t.column("wholeWord", .boolean).notNull() - } - - try db.create(table: "statusContextJoin") { t in - t.column("parentId", .text).indexed().notNull() - .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("statusId", .text).indexed().notNull() - .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("section", .text).indexed().notNull() - t.column("index", .integer).notNull() - - t.primaryKey(["parentId", "statusId"], onConflict: .replace) - } - - try db.create(table: "accountPinnedStatusJoin") { t in - t.column("accountId", .text).indexed().notNull() - .references("accountRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("statusId", .text).indexed().notNull() - .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("index", .integer).notNull() - - t.primaryKey(["accountId", "statusId"], onConflict: .replace) - } - - try db.create(table: "accountStatusJoin") { t in - t.column("accountId", .text).indexed().notNull() - .references("accountRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("statusId", .text).indexed().notNull() - .references("statusRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("collection", .text).indexed().notNull() - - t.primaryKey(["accountId", "statusId", "collection"], onConflict: .replace) - } - - try db.create(table: "accountList") { t in - t.column("id", .text).primaryKey(onConflict: .replace) - } - - try db.create(table: "accountListJoin") { t in - t.column("accountId", .text).indexed().notNull() - .references("accountRecord", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("listId", .text).indexed().notNull() - .references("accountList", column: "id", onDelete: .cascade, onUpdate: .cascade) - t.column("index", .integer).notNull() - - t.primaryKey(["accountId", "listId"], onConflict: .replace) - } - } - - return migrator - } - func clean() throws { try databaseWriter.write { try Timeline.deleteAll($0) @@ -434,4 +302,3 @@ private extension ContentDatabase { } } } -// swiftlint:enable file_length diff --git a/DB/Sources/DB/Identity/IdentityDatabase+Migration.swift b/DB/Sources/DB/Identity/IdentityDatabase+Migration.swift new file mode 100644 index 0000000..57088ad --- /dev/null +++ b/DB/Sources/DB/Identity/IdentityDatabase+Migration.swift @@ -0,0 +1,47 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import GRDB + +extension IdentityDatabase { + var migrator: DatabaseMigrator { + var migrator = DatabaseMigrator() + + migrator.registerMigration("0.1.0") { db in + try db.create(table: "instance", ifNotExists: true) { t in + t.column("uri", .text).primaryKey(onConflict: .replace) + t.column("streamingAPI", .text) + t.column("title", .text) + t.column("thumbnail", .text) + } + + try db.create(table: "identityRecord", ifNotExists: true) { t in + t.column("id", .text).primaryKey(onConflict: .replace) + t.column("url", .text).notNull() + t.column("authenticated", .boolean).notNull() + t.column("pending", .boolean).notNull() + t.column("lastUsedAt", .datetime).notNull() + t.column("instanceURI", .text) + .references("instance", column: "uri") + t.column("preferences", .blob).notNull() + t.column("pushSubscriptionAlerts", .blob).notNull() + t.column("lastRegisteredDeviceToken", .blob) + } + + try db.create(table: "account", ifNotExists: true) { t in + t.column("id", .text).primaryKey(onConflict: .replace) + t.column("identityID", .text).notNull() + .references("identityRecord", column: "id", onDelete: .cascade) + t.column("username", .text).notNull() + t.column("displayName", .text).notNull() + t.column("url", .text).notNull() + t.column("avatar", .text).notNull() + t.column("avatarStatic", .text).notNull() + t.column("header", .text).notNull() + t.column("headerStatic", .text).notNull() + t.column("emojis", .blob).notNull() + } + } + + return migrator + } +} diff --git a/DB/Sources/DB/Identity/IdentityDatabase.swift b/DB/Sources/DB/Identity/IdentityDatabase.swift index 0ece2b0..907e9fa 100644 --- a/DB/Sources/DB/Identity/IdentityDatabase.swift +++ b/DB/Sources/DB/Identity/IdentityDatabase.swift @@ -230,46 +230,4 @@ private extension IdentityDatabase { .updateAll($0, IdentityRecord.Columns.preferences.set(to: data)) } } - - private var migrator: DatabaseMigrator { - var migrator = DatabaseMigrator() - - migrator.registerMigration("0.1.0") { db in - try db.create(table: "instance", ifNotExists: true) { t in - t.column("uri", .text).primaryKey(onConflict: .replace) - t.column("streamingAPI", .text) - t.column("title", .text) - t.column("thumbnail", .text) - } - - try db.create(table: "identityRecord", ifNotExists: true) { t in - t.column("id", .text).primaryKey(onConflict: .replace) - t.column("url", .text).notNull() - t.column("authenticated", .boolean).notNull() - t.column("pending", .boolean).notNull() - t.column("lastUsedAt", .datetime).notNull() - t.column("instanceURI", .text) - .references("instance", column: "uri") - t.column("preferences", .blob).notNull() - t.column("pushSubscriptionAlerts", .blob).notNull() - t.column("lastRegisteredDeviceToken", .blob) - } - - try db.create(table: "account", ifNotExists: true) { t in - t.column("id", .text).primaryKey(onConflict: .replace) - t.column("identityID", .text).notNull() - .references("identityRecord", column: "id", onDelete: .cascade) - t.column("username", .text).notNull() - t.column("displayName", .text).notNull() - t.column("url", .text).notNull() - t.column("avatar", .text).notNull() - t.column("avatarStatic", .text).notNull() - t.column("header", .text).notNull() - t.column("headerStatic", .text).notNull() - t.column("emojis", .blob).notNull() - } - } - - return migrator - } }