diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000000..e1eea1d6b9
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PushToFCM/package-lock.json b/PushToFCM/package-lock.json
index 616145b944..3c090d9576 100644
--- a/PushToFCM/package-lock.json
+++ b/PushToFCM/package-lock.json
@@ -2737,9 +2737,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "version": "7.5.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
+ "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -5386,9 +5386,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "version": "7.5.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
+ "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"requires": {
"lru-cache": "^6.0.0"
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 009914c849..e431da56cf 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -94,4 +94,17 @@
# databinding
-dontwarn androidx.databinding.**
-keep class androidx.databinding.** { *; }
--keep class * extends androidx.databinding.DataBinderMapper
\ No newline at end of file
+-keep class * extends androidx.databinding.DataBinderMapper
+
+# glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep class * extends com.bumptech.glide.module.AppGlideModule {
+ (...);
+}
+-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
+ **[] $VALUES;
+ public *;
+}
+-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
+ *** rewind();
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d7f2597e66..16405e8b1b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -128,7 +128,10 @@
-
+
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/MiApplication.kt b/app/src/main/java/jp/panta/misskeyandroidclient/MiApplication.kt
index 910cc53461..7bf1f55b00 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/MiApplication.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/MiApplication.kt
@@ -25,9 +25,8 @@ import net.pantasystem.milktea.model.account.ClientIdRepository
import net.pantasystem.milktea.model.notes.NoteDataSource
import net.pantasystem.milktea.worker.SyncNodeInfoCacheWorker
import net.pantasystem.milktea.worker.drive.CleanupUnusedDriveCacheWorker
+import net.pantasystem.milktea.worker.emoji.cache.CacheCustomEmojiImageWorker
import net.pantasystem.milktea.worker.filter.SyncMastodonFilterWorker
-import net.pantasystem.milktea.worker.instance.ScheduleAuthInstancesPostWorker
-import net.pantasystem.milktea.worker.instance.SyncInstanceInfoWorker
import net.pantasystem.milktea.worker.meta.SyncMetaWorker
import net.pantasystem.milktea.worker.sw.RegisterAllSubscriptionRegistration
import net.pantasystem.milktea.worker.user.SyncLoggedInUserInfoWorker
@@ -142,12 +141,6 @@ class MiApplication : Application(), Configuration.Provider {
}
}
- applicationScope.launch {
- noteDataSource.clear().onFailure {
- logger.error("NoteDataSourceの初期化に失敗", it)
- }
- }
-
FirebaseAnalytics.getInstance(this).setUserId(
clientIdRepository.getOrCreate().clientId
)
@@ -198,21 +191,27 @@ class MiApplication : Application(), Configuration.Provider {
ExistingPeriodicWorkPolicy.REPLACE,
SyncLoggedInUserInfoWorker.createPeriodicWorkRequest(),
)
+// enqueueUniquePeriodicWork(
+// "scheduleAuthInstancePostWorker",
+// ExistingPeriodicWorkPolicy.REPLACE,
+// ScheduleAuthInstancesPostWorker.createPeriodicWorkRequest(),
+// )
+// enqueueUniquePeriodicWork(
+// "syncInstanceInfoWorker",
+// ExistingPeriodicWorkPolicy.REPLACE,
+// SyncInstanceInfoWorker.createPeriodicWorkRequest(),
+// )
enqueueUniquePeriodicWork(
- "scheduleAuthInstancePostWorker",
- ExistingPeriodicWorkPolicy.REPLACE,
- ScheduleAuthInstancesPostWorker.createPeriodicWorkRequest(),
- )
- enqueueUniquePeriodicWork(
- "syncInstanceInfoWorker",
+ "syncMastodonWordFilter",
ExistingPeriodicWorkPolicy.REPLACE,
- SyncInstanceInfoWorker.createPeriodicWorkRequest(),
+ SyncMastodonFilterWorker.createPeriodicWorkerRequest(),
)
enqueueUniquePeriodicWork(
- "syncMastodonWordFilter",
+ "cacheEmojiImages",
ExistingPeriodicWorkPolicy.REPLACE,
- SyncMastodonFilterWorker.createPeriodicWorkerRequest(),
+ CacheCustomEmojiImageWorker.createPeriodicWorkRequest(),
)
+
enqueue(
SyncRenoteMutesWorker.createOneTimeWorkRequest()
)
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/ThemeUtil.kt b/app/src/main/java/jp/panta/misskeyandroidclient/ThemeUtil.kt
index 7e13d02438..441f1dd06c 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/ThemeUtil.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/ThemeUtil.kt
@@ -29,6 +29,7 @@ fun Activity.setTheme() {
Theme.Black -> setTheme(R.style.AppThemeBlack)
Theme.Bread -> setTheme(R.style.AppThemeBread)
Theme.White -> setTheme(R.style.AppTheme)
+ Theme.ElephantDark -> setTheme(R.style.AppThemeMastodonDark)
}
}
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/di/module/EmojiModule.kt b/app/src/main/java/jp/panta/misskeyandroidclient/di/module/EmojiModule.kt
index d6f4b4e0e8..f509679d55 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/di/module/EmojiModule.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/di/module/EmojiModule.kt
@@ -5,12 +5,8 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import jp.panta.misskeyandroidclient.impl.CheckEmojiAndroidImpl
-import kotlinx.coroutines.CoroutineScope
-import net.pantasystem.milktea.common.Logger
import net.pantasystem.milktea.data.infrastructure.DataBase
-import net.pantasystem.milktea.data.infrastructure.emoji.Utf8EmojiRepositoryImpl
import net.pantasystem.milktea.data.infrastructure.emoji.Utf8EmojisDAO
-import net.pantasystem.milktea.model.emoji.UtfEmojiRepository
import net.pantasystem.milktea.model.notes.reaction.CheckEmoji
import javax.inject.Singleton
@@ -21,24 +17,23 @@ object EmojiModule {
@Singleton
@Provides
fun provideCheckEmoji(
- utfEmojiRepository: UtfEmojiRepository
): CheckEmoji {
- return CheckEmojiAndroidImpl(utfEmojiRepository)
+ return CheckEmojiAndroidImpl()
}
- @Singleton
- @Provides
- fun provideUtf8EmojiRepository(
- coroutineScope: CoroutineScope,
- loggerFactory: Logger.Factory,
- emojisDAO: Utf8EmojisDAO,
- ): UtfEmojiRepository {
- return Utf8EmojiRepositoryImpl(
- coroutineScope = coroutineScope,
- loggerFactory = loggerFactory,
- utf8EmojisDAO = emojisDAO
- )
- }
+// @Singleton
+// @Provides
+// fun provideUtf8EmojiRepository(
+// coroutineScope: CoroutineScope,
+// loggerFactory: Logger.Factory,
+// emojisDAO: Utf8EmojisDAO,
+// ): UtfEmojiRepository {
+// return Utf8EmojiRepositoryImpl(
+// coroutineScope = coroutineScope,
+// loggerFactory = loggerFactory,
+// utf8EmojisDAO = emojisDAO
+// )
+// }
@Singleton
@Provides
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/di/module/ObjectBoxModule.kt b/app/src/main/java/jp/panta/misskeyandroidclient/di/module/ObjectBoxModule.kt
index e140a3bd10..a75c4504dc 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/di/module/ObjectBoxModule.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/di/module/ObjectBoxModule.kt
@@ -7,7 +7,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.objectbox.BoxStore
-import net.pantasystem.milktea.data.infrastructure.notes.impl.db.MyObjectBox
+import net.pantasystem.milktea.data.infrastructure.emoji.MyObjectBox
import javax.inject.Singleton
@Module
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/impl/CheckEmojiAndroidImpl.kt b/app/src/main/java/jp/panta/misskeyandroidclient/impl/CheckEmojiAndroidImpl.kt
index 6827e98a04..5fa3e1dcf7 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/impl/CheckEmojiAndroidImpl.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/impl/CheckEmojiAndroidImpl.kt
@@ -1,11 +1,9 @@
package jp.panta.misskeyandroidclient.impl
-import net.pantasystem.milktea.model.emoji.UtfEmojiRepository
import net.pantasystem.milktea.model.notes.reaction.CheckEmoji
import javax.inject.Inject
class CheckEmojiAndroidImpl @Inject constructor(
- private val utf8EmojiRepository: UtfEmojiRepository
) : CheckEmoji {
override suspend fun checkEmoji(char: CharSequence): Boolean {
// return (EmojiCompat.get()?.hasEmojiGlyph(char) ?: false) || utf8EmojiRepository.exists(char)
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/ui/PageableFragmentFactoryImpl.kt b/app/src/main/java/jp/panta/misskeyandroidclient/ui/PageableFragmentFactoryImpl.kt
index f6dd1cd1b6..6997edb4e1 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/ui/PageableFragmentFactoryImpl.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/ui/PageableFragmentFactoryImpl.kt
@@ -19,10 +19,10 @@ class PageableFragmentFactoryImpl @Inject constructor(): PageableFragmentFactory
NoteDetailFragment.newInstance(page)
}
is Pageable.Notification ->{
- NotificationFragment()
+ NotificationFragment.newInstance(page.attachedAccountId ?: page.accountId)
}
is Pageable.Gallery -> {
- return GalleryPostsFragment.newInstance(pageable, page.accountId)
+ return GalleryPostsFragment.newInstance(pageable, page.attachedAccountId ?: page.accountId)
}
else ->{
TimelineFragment.newInstance(page)
@@ -57,10 +57,10 @@ class PageableFragmentFactoryImpl @Inject constructor(): PageableFragmentFactory
NoteDetailFragment.newInstance(pageable.noteId, accountId)
}
is Pageable.Notification ->{
- NotificationFragment()
+ NotificationFragment.newInstance(accountId)
}
is Pageable.Gallery -> {
- return GalleryPostsFragment.newInstance(pageable, null)
+ return GalleryPostsFragment.newInstance(pageable, accountId)
}
else ->{
TimelineFragment.newInstance(pageable, accountId)
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/FabClickHandler.kt b/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/FabClickHandler.kt
index 6e6c3c0c95..271792bfd5 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/FabClickHandler.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/FabClickHandler.kt
@@ -9,6 +9,7 @@ import net.pantasystem.milktea.common_viewmodel.CurrentPageableTimelineViewModel
import net.pantasystem.milktea.common_viewmodel.SuitableType
import net.pantasystem.milktea.common_viewmodel.suitableType
import net.pantasystem.milktea.gallery.GalleryPostsActivity
+import net.pantasystem.milktea.model.account.page.Pageable
import net.pantasystem.milktea.model.channel.Channel
import net.pantasystem.milktea.note.NoteEditorActivity
@@ -20,14 +21,28 @@ internal class FabClickHandler(
fun onClicked() {
activity.apply {
- when(val type = currentPageableTimelineViewModel.currentType.value) {
+ when (val type = currentPageableTimelineViewModel.currentType.value) {
CurrentPageType.Account -> {
- AccountSwitchingDialog().show(activity.supportFragmentManager, "AccountSwitchingDialog")
+ AccountSwitchingDialog().show(
+ activity.supportFragmentManager,
+ "AccountSwitchingDialog"
+ )
}
is CurrentPageType.Page -> {
when (val suitableType = type.pageable.suitableType()) {
is SuitableType.Other -> {
- startActivity(Intent(this, NoteEditorActivity::class.java))
+ val text = when (val pageable = type.pageable) {
+ is Pageable.SearchByTag -> "#${pageable.tag}"
+ is Pageable.Mastodon.HashTagTimeline -> "#${pageable.hashtag}"
+ else -> ""
+ }
+ startActivity(
+ NoteEditorActivity.newBundle(
+ this,
+ accountId = type.accountId,
+ text = text
+ )
+ )
}
is SuitableType.Gallery -> {
val intent = Intent(this, GalleryPostsActivity::class.java)
@@ -35,11 +50,11 @@ internal class FabClickHandler(
startActivity(intent)
}
is SuitableType.Channel -> {
- val accountId = accountStore.currentAccountId!!
+ val accountId = type.accountId ?: accountStore.currentAccountId!!
startActivity(
NoteEditorActivity.newBundle(
this,
- channelId = Channel.Id(accountId, suitableType.channelId)
+ channelId = Channel.Id(accountId, suitableType.channelId),
)
)
}
diff --git a/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/MainActivityEventHandler.kt b/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/MainActivityEventHandler.kt
index 6e7c13de60..6ea93a33d7 100644
--- a/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/MainActivityEventHandler.kt
+++ b/app/src/main/java/jp/panta/misskeyandroidclient/ui/main/MainActivityEventHandler.kt
@@ -77,7 +77,7 @@ internal class MainActivityEventHandler(
private fun collectCrashlyticsCollectionState() {
lifecycleScope.launch {
- lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
mainViewModel.isShowFirebaseCrashlytics.collect {
if (it) {
ConfirmCrashlyticsDialog().show(
@@ -92,7 +92,7 @@ internal class MainActivityEventHandler(
private fun collectConfirmGoogleAnalyticsState() {
lifecycleScope.launch {
- lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
mainViewModel.isShowGoogleAnalyticsDialog.collect {
if (it) {
ConfirmGoogleAnalyticsDialog().show(
@@ -156,14 +156,14 @@ internal class MainActivityEventHandler(
lifecycleOwner.whenResumed {
// NOTE: 通知音を再生する
mainViewModel.newNotifications.collect {
- if (ringtone.isPlaying) {
+ if (ringtone?.isPlaying == true) {
ringtone.stop()
}
if (
configStore.configState.value.isEnableNotificationSound
&& audioManager.ringerMode == AudioManager.RINGER_MODE_NORMAL
) {
- ringtone.play()
+ ringtone?.play()
}
}
}
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/api/notes/NoteDTOTest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/api/notes/NoteDTOTest.kt
index 99939d8fda..0ee686862d 100644
--- a/app/src/test/java/jp/panta/misskeyandroidclient/api/notes/NoteDTOTest.kt
+++ b/app/src/test/java/jp/panta/misskeyandroidclient/api/notes/NoteDTOTest.kt
@@ -3,10 +3,10 @@ package jp.panta.misskeyandroidclient.api.notes
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
+import net.pantasystem.milktea.api.misskey.emoji.CustomEmojiNetworkDTO
import net.pantasystem.milktea.api.misskey.emoji.EmojisType
import net.pantasystem.milktea.api.misskey.emoji.TestNoteObject
import net.pantasystem.milktea.api.misskey.notes.NoteDTO
-import net.pantasystem.milktea.model.emoji.Emoji
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
@@ -869,7 +869,7 @@ class NoteDTOTest {
[{"name": "hoge", "url": "https://example.com"}]
""".trimIndent()
val result = builder.decodeFromString(json1)
- Assertions.assertEquals(EmojisType.TypeArray(listOf(Emoji(name = "hoge", url = "https://example.com"))), result)
+ Assertions.assertEquals(EmojisType.TypeArray(listOf(CustomEmojiNetworkDTO(name = "hoge", url = "https://example.com"))), result)
}
@@ -896,7 +896,7 @@ class NoteDTOTest {
""".trimIndent()
val result = builder.decodeFromString(json1)
Assertions.assertEquals(TestNoteObject(EmojisType.TypeArray(
- listOf(Emoji(name = "hoge", url = "https://example.com"))
+ listOf(CustomEmojiNetworkDTO(name = "hoge", url = "https://example.com"))
)), result)
}
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/model/account/AccountTest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/model/account/AccountTest.kt
index fae657a15f..63b5459202 100644
--- a/app/src/test/java/jp/panta/misskeyandroidclient/model/account/AccountTest.kt
+++ b/app/src/test/java/jp/panta/misskeyandroidclient/model/account/AccountTest.kt
@@ -282,4 +282,17 @@ class AccountTest {
)
Assertions.assertEquals("mk.iaia.moe", account.getHost())
}
+
+ @Test
+ fun getAcct() {
+ val account = Account(
+ remoteId = "",
+ instanceDomain = "https://calc.panta.systems",
+ userName = "Panta",
+ instanceType = Account.InstanceType.MISSKEY,
+ token = ""
+ )
+ val actual = account.getAcct()
+ Assertions.assertEquals("@Panta@calc.panta.systems", actual)
+ }
}
\ No newline at end of file
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/DirectoryPathTest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/DirectoryPathTest.kt
deleted file mode 100644
index 95686722ba..0000000000
--- a/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/DirectoryPathTest.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-package jp.panta.misskeyandroidclient.model.drive
-
-
-import net.pantasystem.milktea.model.drive.Directory
-import net.pantasystem.milktea.model.drive.DirectoryPath
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-
-class DirectoryPathTest {
- @Test
- fun testPush() {
- val root = Directory(
- "root",
- "",
- "",
- 0,
- 0,
- null,
- null
- )
- var directoryPath = DirectoryPath(
- path = listOf(
- root
- )
- )
- directoryPath = directoryPath.push(root.copy(
- parent = root,
- parentId = root.id,
- id = "sub1"
- ))
- assertEquals("sub1", directoryPath.path.last().id)
-
- }
-
- @Test
- fun testPop() {
- val root = Directory(
- "root",
- "",
- "",
- 0,
- 0,
- null,
- null
- )
- var directoryPath = DirectoryPath(
- path = listOf(
- root
- )
- )
- val dirs = listOf("sub1", "sub2", "sub3", "sub4")
- directoryPath = dirs.fold(directoryPath) { acc, s ->
- acc.push(root.copy(id = s, parent = acc.path.last(), parentId = acc.path.last().id))
- }
- directoryPath = directoryPath.pop()
- assertEquals("sub3", directoryPath.path.last().id)
-
- directoryPath = directoryPath.pop()
- assertEquals("sub2", directoryPath.path.last().id)
-
- directoryPath = directoryPath.pop()
- assertEquals("sub1", directoryPath.path.last().id)
- }
-
- @Test
- fun testPopUntil() {
- val root = Directory(
- "root",
- "",
- "",
- 0,
- 0,
- null,
- null
- )
- var directoryPath = DirectoryPath(
- path = listOf(
- root
- )
- )
- val dirs = listOf("sub1", "sub2", "sub3", "sub4")
- directoryPath = dirs.fold(directoryPath) { acc, s ->
- acc.push(root.copy(id = s, parent = acc.path.last(), parentId = acc.path.last().id))
- }
-
- val dir = directoryPath.path[1]
- directoryPath = directoryPath.popUntil(dir)
- assertEquals(dir.id, directoryPath.path.last().id)
- }
-
-
- @Test
- fun testClear() {
- val root = Directory(
- "root",
- "",
- "",
- 0,
- 0,
- null,
- null
- )
- var directoryPath = DirectoryPath(
- path = listOf(
- root
- )
- )
- val dirs = listOf("sub1", "sub2", "sub3", "sub4")
- directoryPath = dirs.fold(directoryPath) { acc, s ->
- acc.push(root.copy(id = s, parent = acc.path.last(), parentId = acc.path.last().id))
- }
- directoryPath = directoryPath.clear()
- assertEquals(0, directoryPath.path.size)
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/DriveStoreTest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/DriveStoreTest.kt
deleted file mode 100644
index fa9ccef371..0000000000
--- a/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/DriveStoreTest.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package jp.panta.misskeyandroidclient.model.drive
-
-
-import net.pantasystem.milktea.app_store.drive.DriveState
-import net.pantasystem.milktea.app_store.drive.DriveStore
-import net.pantasystem.milktea.model.drive.Directory
-import net.pantasystem.milktea.model.drive.DirectoryPath
-import net.pantasystem.milktea.model.drive.FileProperty
-import net.pantasystem.milktea.model.drive.SelectedFilePropertyIds
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.Test
-
-class DriveStoreTest {
-
- @Test
- fun testToggleSelect() {
-
- val driveStore = DriveStore(
- DriveState(
- accountId = 0L,
- selectedFilePropertyIds = SelectedFilePropertyIds(4, emptySet()),
- path = DirectoryPath(emptyList())
- )
- )
- driveStore.toggleSelect(FileProperty.Id(0L, "fileA"))
- assertEquals(setOf(FileProperty.Id(0L, "fileA")), driveStore.state.value.selectedFilePropertyIds?.selectedIds)
- driveStore.toggleSelect(FileProperty.Id(0L, "fileB"))
- driveStore.toggleSelect(FileProperty.Id(0L, "fileC"))
- driveStore.toggleSelect(FileProperty.Id(0L, "fileD"))
- assertEquals(
- setOf(
- FileProperty.Id(0L, "fileA"),
- FileProperty.Id(0L, "fileB"),
- FileProperty.Id(0L, "fileC"),
- FileProperty.Id(0L, "fileD")
- ),
- driveStore.state.value.selectedFilePropertyIds?.selectedIds
- )
-
- driveStore.toggleSelect(FileProperty.Id(0L, "fileE"))
-
- // NOTE: 最大サイズを超えて追加できないことを確認している
- assertEquals(
- setOf(
- FileProperty.Id(0L, "fileA"),
- FileProperty.Id(0L, "fileB"),
- FileProperty.Id(0L, "fileC"),
- FileProperty.Id(0L, "fileD")
- ),
- driveStore.state.value.selectedFilePropertyIds?.selectedIds
- )
-
- driveStore.toggleSelect(FileProperty.Id(0L, "fileD"))
- assertEquals(
- setOf(
- FileProperty.Id(0L, "fileA"),
- FileProperty.Id(0L, "fileB"),
- FileProperty.Id(0L, "fileC"),
- ),
- driveStore.state.value.selectedFilePropertyIds?.selectedIds
- )
- }
-
- @Test
- fun testSelect() {
- val driveStore = DriveStore(
- DriveState(
- accountId = 0L,
- selectedFilePropertyIds = SelectedFilePropertyIds(4, emptySet()),
- path = DirectoryPath(emptyList())
- )
- )
- driveStore.select(FileProperty.Id(0L, "fileA"))
- assertEquals(setOf(FileProperty.Id(0L, "fileA")), driveStore.state.value.selectedFilePropertyIds?.selectedIds)
-
- }
-
- @Test
- fun testDeselect() {
- val driveStore = DriveStore(
- DriveState(
- accountId = 0L,
- selectedFilePropertyIds = SelectedFilePropertyIds(
- 4,
- setOf(
- FileProperty.Id(0L, "fileA"),
- FileProperty.Id(0L, "fileB"),
- FileProperty.Id(0L, "fileC"),
- FileProperty.Id(0L, "fileD")
- )
- ),
- path = DirectoryPath(emptyList())
- )
- )
- val fileIds = listOf("fileA", "fileB", "fileC", "fileD")
- fileIds.forEach {
- driveStore.deselect(FileProperty.Id(0L, it))
- }
- assertTrue(
- driveStore.state.value.selectedFilePropertyIds?.selectedIds.isNullOrEmpty()
- )
- }
-
- @Test
- fun testPop() {
- val directories = listOf("dir1", "dir2", "dir3", "dir4", "di5")
- val root = Directory(
- "root",
- "",
- "",
- 0,
- 0,
- null,
- null
- )
- val driveStore = DriveStore(
- DriveState(
- accountId = 0L,
- selectedFilePropertyIds = null,
- path = DirectoryPath(listOf(root))
- )
- )
- directories.forEach {
- val parent = driveStore.state.value.path.path.last()
- driveStore.push(
- root.copy(
- parent = parent,
- parentId = parent.id,
- id = it,
- name = "${it}name"
- )
- )
- }
- directories.reversed().forEach {
- assertEquals(it, driveStore.state.value.path.path.last().id)
- assertTrue(driveStore.pop())
- }
-
- }
-
-
-}
\ No newline at end of file
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/SelectedFilePropertyIdsTest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/SelectedFilePropertyIdsTest.kt
deleted file mode 100644
index 095485f58b..0000000000
--- a/app/src/test/java/jp/panta/misskeyandroidclient/model/drive/SelectedFilePropertyIdsTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package jp.panta.misskeyandroidclient.model.drive
-
-import net.pantasystem.milktea.model.drive.FileProperty
-import net.pantasystem.milktea.model.drive.SelectedFilePropertyIds
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.Assertions.*
-
-class SelectedFilePropertyIdsTest {
-
- @Test
- fun testAddAndCopy_WhenNew() {
- val s = SelectedFilePropertyIds(4, emptySet())
- val addId = FileProperty.Id(0, "a01")
- val s2 = s.addAndCopy(addId)
- assertEquals(addId, s2.selectedIds.first())
- }
-
- @Test
- fun testAddAndCopy_WhenDuplicate() {
- val s = SelectedFilePropertyIds(4, emptySet())
- val addId = FileProperty.Id(0, "a01")
- val s2 = s.addAndCopy(addId).addAndCopy(addId.copy())
- assertEquals(1, s2.selectedIds.size)
- }
-
- @Test
- fun testAddAndCopy_WhenMany() {
- val s = SelectedFilePropertyIds(5, emptySet())
- val addId = FileProperty.Id(0, "a01")
- val s2 = s.addAndCopy(addId).addAndCopy(addId.copy(fileId = "a02"))
- .addAndCopy(addId.copy(fileId = "a03"))
- .addAndCopy(addId.copy(fileId = "a04"))
- .addAndCopy(addId.copy(fileId = "a05"))
- assertEquals(5, s2.selectedIds.size)
- }
-
-
- @Test
- fun testRemoveAndCopy_WhenNormal() {
- val s = SelectedFilePropertyIds(4, emptySet())
- val addId = FileProperty.Id(0, "a01")
- val s2 = s.removeAndCopy(addId)
- assertEquals(0, s2.selectedIds.size)
- }
-
- @Test
- fun testRemoveAndCopy_WhenMany() {
- val removeId = FileProperty.Id(0, "a01")
-
- val s = SelectedFilePropertyIds(5, selectedIds = setOf(removeId, removeId.copy(fileId = "02"), removeId.copy(fileId = "03"), removeId.copy(fileId = "04")))
-
- assertEquals(s.selectedIds.size - 1, s.removeAndCopy(removeId).selectedIds.size)
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/streaming/channel/ChannelAPITest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/streaming/channel/ChannelAPITest.kt
index 3bc70fbea8..50556fb8cb 100644
--- a/app/src/test/java/jp/panta/misskeyandroidclient/streaming/channel/ChannelAPITest.kt
+++ b/app/src/test/java/jp/panta/misskeyandroidclient/streaming/channel/ChannelAPITest.kt
@@ -26,7 +26,7 @@ class ChannelAPITest {
val wssURL = "wss://misskey.io/streaming"
val logger = TestLogger.Factory()
val socket =
- SocketImpl(wssURL, logger, DefaultOkHttpClientProvider())
+ SocketImpl(wssURL, {false}, logger, DefaultOkHttpClientProvider())
socket.blockingConnect()
var count = 0
@@ -51,7 +51,7 @@ class ChannelAPITest {
val wssURL = "wss://misskey.io/streaming"
val logger = TestLogger.Factory()
val socket =
- SocketImpl(wssURL, logger, DefaultOkHttpClientProvider())
+ SocketImpl(wssURL, {false}, logger, DefaultOkHttpClientProvider())
val channelAPI = ChannelAPI(socket, logger)
runBlocking {
diff --git a/app/src/test/java/jp/panta/misskeyandroidclient/streaming/network/SocketImplTest.kt b/app/src/test/java/jp/panta/misskeyandroidclient/streaming/network/SocketImplTest.kt
index 6b60bbbe09..8f71de1e52 100644
--- a/app/src/test/java/jp/panta/misskeyandroidclient/streaming/network/SocketImplTest.kt
+++ b/app/src/test/java/jp/panta/misskeyandroidclient/streaming/network/SocketImplTest.kt
@@ -20,7 +20,7 @@ class SocketImplTest {
fun testBlockingConnect() {
val wssURL = "wss://misskey.io/streaming"
val logger = TestLogger.Factory()
- val socket = SocketImpl(wssURL, logger, DefaultOkHttpClientProvider())
+ val socket = SocketImpl(wssURL, {false} ,logger, DefaultOkHttpClientProvider())
runBlocking {
socket.blockingConnect()
assertEquals(socket.state(), Socket.State.Connected)
@@ -33,7 +33,7 @@ class SocketImplTest {
val wssURL = "wss://misskey.io/streaming"
val logger = TestLogger.Factory()
- val socket = SocketImpl(wssURL, logger, DefaultOkHttpClientProvider())
+ val socket = SocketImpl(wssURL, {false}, logger, DefaultOkHttpClientProvider())
runBlocking {
@@ -55,7 +55,7 @@ class SocketImplTest {
val wssURL = "wss://misskey.io/streaming"
val logger = TestLogger.Factory()
val socket =
- SocketImpl(wssURL, logger, DefaultOkHttpClientProvider())
+ SocketImpl(wssURL, {false}, logger, DefaultOkHttpClientProvider())
runBlocking {
diff --git a/app/src/test/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecordTest.kt b/app/src/test/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecordTest.kt
index 72fcb8817a..cc8746f909 100644
--- a/app/src/test/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecordTest.kt
+++ b/app/src/test/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecordTest.kt
@@ -294,7 +294,8 @@ internal class NoteRecordTest {
id = Channel.Id(0L, "ch1"),
name = "name1",
),
- isAcceptingOnlyLikeReaction = false
+ isAcceptingOnlyLikeReaction = false,
+ isNotAcceptingSensitiveReaction = true,
)
)
record.applyModel(note)
@@ -310,6 +311,10 @@ internal class NoteRecordTest {
"name1",
record.misskeyChannelName
)
+ Assertions.assertEquals(
+ true,
+ record.misskeyIsNotAcceptingSensitiveReaction
+ )
}
@Test
@@ -361,7 +366,7 @@ internal class NoteRecordTest {
mastodonPureText = "test note",
mastodonIsReactionAvailable = true,
myReactions = mutableListOf("like"),
- maxReactionsPerAccount = 3
+ maxReactionsPerAccount = 3,
)
val expectedNote = Note(
id = Note.Id(accountId = 1, noteId = "note-id"),
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/MastodonAPI.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/MastodonAPI.kt
index d6b88b461a..aacb02aef8 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/MastodonAPI.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/MastodonAPI.kt
@@ -27,6 +27,8 @@ import net.pantasystem.milktea.api.mastodon.search.SearchResponse
import net.pantasystem.milktea.api.mastodon.status.CreateStatus
import net.pantasystem.milktea.api.mastodon.status.ScheduledStatus
import net.pantasystem.milktea.api.mastodon.status.TootStatusDTO
+import net.pantasystem.milktea.api.mastodon.suggestion.SuggestionDTO
+import net.pantasystem.milktea.api.mastodon.tag.MastodonTagDTO
import retrofit2.Response
import retrofit2.http.*
@@ -78,7 +80,7 @@ interface MastodonAPI {
suspend fun getHomeTimeline(
@Query("min_id") minId: String? = null,
@Query("max_id") maxId: String? = null,
- @Query("visibilities[]", encoded = true) visibilities: List? = null
+ @Query("visibilities[]", encoded = true) visibilities: List? = null,
): Response>
@GET("api/v1/timelines/list/{listId}")
@@ -100,7 +102,7 @@ interface MastodonAPI {
@Query("min_id") minId: String? = null,
@Query("max_id") maxId: String? = null,
@Query("since_id") sinceId: String? = null,
- @Query("limit") limit: Int = 40
+ @Query("limit") limit: Int = 40,
): Response>
@GET("api/v1/accounts/{accountId}/following")
@@ -109,7 +111,7 @@ interface MastodonAPI {
@Query("min_id") minId: String? = null,
@Query("max_id") maxId: String? = null,
@Query("since_id") sinceId: String? = null,
- @Query("limit") limit: Int = 40
+ @Query("limit") limit: Int = 40,
): Response>
@GET("api/v1/accounts/{accountId}")
@@ -120,7 +122,7 @@ interface MastodonAPI {
@Query(
"id[]",
encoded = true
- ) ids: List
+ ) ids: List,
): Response>
@POST("api/v1/accounts/{accountId}/follow")
@@ -132,13 +134,13 @@ interface MastodonAPI {
@PUT("api/v1/statuses/{statusId}/emoji_reactions/{emoji}")
suspend fun reaction(
@Path("statusId") statusId: String,
- @Path("emoji") emoji: String
+ @Path("emoji") emoji: String,
): Response
@DELETE("api/v1/statuses/{statusId}/emoji_reactions/{emoji}")
suspend fun deleteReaction(
@Path("statusId") statusId: String,
- @Path("emoji") emoji: String
+ @Path("emoji") emoji: String,
): Response
@POST("api/v1/statuses/{statusId}/emoji_unreaction")
@@ -159,13 +161,13 @@ interface MastodonAPI {
@GET("api/v1/favourites")
suspend fun getFavouriteStatuses(
@Query("min_id") minId: String? = null,
- @Query("max_id") maxId: String? = null
+ @Query("max_id") maxId: String? = null,
): Response>
@POST("api/v1/accounts/{accountId}/mute")
suspend fun muteAccount(
@Path("accountId") accountId: String,
- @Body body: MuteAccountRequest
+ @Body body: MuteAccountRequest,
): Response
@POST("api/v1/accounts/{accountId}/unmute")
@@ -191,7 +193,7 @@ interface MastodonAPI {
@POST("api/v1/statuses")
suspend fun createStatus(
- @Body body: CreateStatus
+ @Body body: CreateStatus,
): Response
@POST("api/v1/status")
@@ -209,7 +211,7 @@ interface MastodonAPI {
@POST("api/v1/polls/{pollId}/votes")
suspend fun voteOnPoll(
@Path("pollId") pollId: String,
- @Field("choices[]", encoded = true) choices: List
+ @Field("choices[]", encoded = true) choices: List,
): Response
@POST("api/v1/statuses/{statusId}/mute")
@@ -245,27 +247,37 @@ interface MastodonAPI {
suspend fun getList(@Path("listId") listId: String): Response
@POST("api/v1/lists/{listId}/accounts")
- suspend fun addAccountsToList(@Path("listId") listId: String, @Body body: AddAccountsToList): Response
+ suspend fun addAccountsToList(
+ @Path("listId") listId: String,
+ @Body body: AddAccountsToList,
+ ): Response
@DELETE("api/v1/lists/{listId}/accounts")
- suspend fun removeAccountsFromList(@Path("listId") listId: String, @Body body: RemoveAccountsFromList): Response
+ suspend fun removeAccountsFromList(
+ @Path("listId") listId: String,
+ @Body body: RemoveAccountsFromList,
+ ): Response
@GET("api/v1/lists/{listId}")
suspend fun getAccountsInList(
@Path("listId") listId: String,
@Query("max_id") maxId: String? = null,
- @Query("min_id") minId: String? = null
+ @Query("min_id") minId: String? = null,
): Response>
@GET("api/v1/statuses/{statusId}/context")
suspend fun getStatusesContext(@Path("statusId") statusId: String): Response
@PUT("api/v1/media/{mediaId}")
- suspend fun updateMediaAttachment(@Path("mediaId") mediaId: String, @Body body: UpdateMediaAttachment): Response
+ suspend fun updateMediaAttachment(
+ @Path("mediaId") mediaId: String,
+ @Body body: UpdateMediaAttachment,
+ ): Response
@GET("api/v2/search")
suspend fun search(
@Query("q") q: String,
+ @Query("type") type: String? = null,
@Query("resolve") resolve: Boolean = true,
@Query("following") following: Boolean = false,
@Query("account_id") accountId: String? = null,
@@ -273,7 +285,7 @@ interface MastodonAPI {
@Query("max_id") maxId: String? = null,
@Query("min_id") minId: String? = null,
@Query("limit") limit: Int? = null,
- @Query("offset") offset: Int? = null
+ @Query("offset") offset: Int? = null,
): Response
@POST("api/v1/follow_requests/{accountId}/authorize")
@@ -283,16 +295,19 @@ interface MastodonAPI {
suspend fun rejectFollowRequest(@Path("accountId") accountId: String): Response
@GET("api/v1/follow_requests")
- suspend fun getFollowRequests(@Query("max_id") maxId: String? = null, @Query("min_id") minId: String? = null): Response>
+ suspend fun getFollowRequests(
+ @Query("max_id") maxId: String? = null,
+ @Query("min_id") minId: String? = null,
+ ): Response>
@GET("api/v1/markers")
suspend fun getMarkers(
- @Query("timeline[]", encoded = true) timeline: List
+ @Query("timeline[]", encoded = true) timeline: List,
): Response
@POST("api/v1/markers")
suspend fun saveMarkers(
- @Body markers: SaveMarkersRequest
+ @Body markers: SaveMarkersRequest,
): Response
@GET("api/v1/filters")
@@ -303,4 +318,29 @@ interface MastodonAPI {
@GET("api/v1/instance/rules")
suspend fun getRules(): Response>
+
+ @GET("api/v1/statuses/{id}/reblogged_by")
+ suspend fun getRebloggedBy(
+ @Path("id") id: String,
+ @Query("max_id") maxId: String? = null,
+ @Query("since_id") sinceId: String? = null,
+ @Query("min_id") minId: String? = null,
+ ): Response>
+
+ @GET("api/v1/trends/statuses")
+ suspend fun getTrendStatuses(
+ @Query("limit") limit: Int? = null,
+ @Query("offset") offset: Int? = null,
+ ): Response>
+
+ @GET("api/v1/trends/tags")
+ suspend fun getTagTrends(
+ @Query("limit") limit: Int? = null,
+ @Query("offset") offset: Int? = null,
+ ): Response>
+
+ @GET("api/v2/suggestions")
+ suspend fun getSuggestionUsers(
+ @Query("limit") limit: Int? = null
+ ): Response>
}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/apps/App.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/apps/App.kt
index 1c07324d7b..858d743af1 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/apps/App.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/apps/App.kt
@@ -43,6 +43,16 @@ data class App(
redirectUri = redirectUri,
)
}
+
+ fun toPleromaModel() : AppType.Pleroma {
+ return AppType.Pleroma(
+ id = id,
+ name = name,
+ clientSecret = clientSecret,
+ clientId = clientId,
+ redirectUri = redirectUri,
+ )
+ }
}
@Serializable
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/emojis/TootEmojiDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/emojis/TootEmojiDTO.kt
index ce47c2a05b..0295f60a67 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/emojis/TootEmojiDTO.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/emojis/TootEmojiDTO.kt
@@ -19,14 +19,26 @@ data class TootEmojiDTO(
val category: String? = null,
@SerialName("visible_in_picker")
- val visibleInPicker: Boolean = true
+ val visibleInPicker: Boolean = true,
+
+ @SerialName("width")
+ val width: Int? = null,
+
+ @SerialName("height")
+ val height: Int? = null,
+
+ @SerialName("aliases")
+ val aliases: List? = null,
) {
- fun toEmoji(): Emoji {
+ fun toEmoji(cachePath: String? = null): Emoji {
return Emoji(
name = shortcode,
url = url,
category = category,
+ aspectRatio = if (width == null || height == null) null else (width.toFloat() / height),
+ cachePath = cachePath,
+ aliases = aliases?.filterNotNull(),
)
}
}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/instance/Instance.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/instance/Instance.kt
index 989a330a78..ec085add62 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/instance/Instance.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/instance/Instance.kt
@@ -28,6 +28,12 @@ data class Instance(
@SerialName("fedibird_capabilities")
val fedibirdCapabilities: List? = null,
+
+ @SerialName("pleroma")
+ val pleroma: Pleroma? = null,
+
+ @SerialName("feature_quote")
+ val featureQuote: Boolean? = null,
) {
@Serializable
data class Configuration(
@@ -68,4 +74,15 @@ data class Instance(
data class Urls(
@SerialName("streaming_api") val streamingApi: String
)
+
+ @Serializable
+ data class Pleroma(
+ @SerialName("metadata") val metadata: Metadata,
+
+ ) {
+ @Serializable
+ data class Metadata(
+ @SerialName("features") val features: List,
+ )
+ }
}
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/search/SearchResponse.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/search/SearchResponse.kt
index 2cccd0b307..7c3367c676 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/search/SearchResponse.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/search/SearchResponse.kt
@@ -3,6 +3,7 @@ package net.pantasystem.milktea.api.mastodon.search
import kotlinx.serialization.SerialName
import net.pantasystem.milktea.api.mastodon.accounts.MastodonAccountDTO
import net.pantasystem.milktea.api.mastodon.status.TootStatusDTO
+import net.pantasystem.milktea.api.mastodon.tag.MastodonTagDTO
@kotlinx.serialization.Serializable
data class SearchResponse(
@@ -11,4 +12,7 @@ data class SearchResponse(
@SerialName("statuses")
val statuses: List,
+
+ @SerialName("hashtags")
+ val hashtags: List,
)
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/CreateStatus.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/CreateStatus.kt
index 85dd324c76..40adfc0bd4 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/CreateStatus.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/CreateStatus.kt
@@ -30,7 +30,10 @@ data class CreateStatus(
val language: String? = null,
@SerialName("scheduled_at")
- val scheduledAt: Instant? = null
+ val scheduledAt: Instant? = null,
+
+ @SerialName("quote_id")
+ val quoteId: String? = null,
) {
@kotlinx.serialization.Serializable
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootPreviewCardDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootPreviewCardDTO.kt
index ba272df154..687f650c4b 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootPreviewCardDTO.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootPreviewCardDTO.kt
@@ -17,29 +17,29 @@ data class TootPreviewCardDTO(
val description: String,
@SerialName("author_name")
- val authorName: String,
+ val authorName: String? = null,
@SerialName("author_url")
- val authorUrl: String,
+ val authorUrl: String? = null,
@SerialName("provider_url")
val providerUrl: String,
@SerialName("html")
- val html: String,
+ val html: String? = null,
@SerialName("width")
- val width: Int,
+ val width: Int? = null,
@SerialName("height")
- val height: Int,
+ val height: Int? = null,
@SerialName("image")
val image: String?,
@SerialName("embed_url")
- val embedUrl: String?,
+ val embedUrl: String? = null,
@SerialName("blurhash")
- val blurhash: String?
+ val blurhash: String? = null,
)
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootStatusDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootStatusDTO.kt
index 6ea7badc8e..94e3cd8e27 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootStatusDTO.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/status/TootStatusDTO.kt
@@ -178,6 +178,12 @@ data class TootStatusDTO(
@SerialName("static_url")
val staticUrl: String? = null,
+
+ @SerialName("width")
+ val width: Float? = null,
+
+ @SerialName("height")
+ val height: Float? = null,
) {
val isCustomEmoji = url != null || staticUrl != null
@@ -191,7 +197,7 @@ data class TootStatusDTO(
name
}
- fun getEmoji(): Emoji? {
+ fun getEmoji(cachePath: String? = null): Emoji? {
if (!isCustomEmoji) {
return null
}
@@ -203,6 +209,12 @@ data class TootStatusDTO(
},
url = url,
host = domain,
+ aspectRatio = if (width == null || height == null) {
+ null
+ } else {
+ width / height
+ },
+ cachePath = cachePath,
)
}
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/suggestion/SuggestionDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/suggestion/SuggestionDTO.kt
new file mode 100644
index 0000000000..1677c4a5cd
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/suggestion/SuggestionDTO.kt
@@ -0,0 +1,13 @@
+package net.pantasystem.milktea.api.mastodon.suggestion
+
+import kotlinx.serialization.SerialName
+import net.pantasystem.milktea.api.mastodon.accounts.MastodonAccountDTO
+
+@kotlinx.serialization.Serializable
+data class SuggestionDTO(
+ @SerialName("source")
+ val source: String,
+
+ @SerialName("account")
+ val account: MastodonAccountDTO
+)
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/tag/MastodonTagDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/tag/MastodonTagDTO.kt
new file mode 100644
index 0000000000..1dfb09cb79
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/mastodon/tag/MastodonTagDTO.kt
@@ -0,0 +1,26 @@
+package net.pantasystem.milktea.api.mastodon.tag
+
+import kotlinx.serialization.SerialName
+import net.pantasystem.milktea.model.hashtag.HashTag
+
+@kotlinx.serialization.Serializable
+data class MastodonTagDTO(
+ @SerialName("name") val name: String,
+ @SerialName("url") val url: String,
+ @SerialName("history") val history: List,
+) {
+ @kotlinx.serialization.Serializable
+ data class History(
+ @SerialName("day") val day: Long,
+ @SerialName("uses") val uses: Int,
+ @SerialName("accounts") val accounts: Int,
+ )
+
+ fun toModel(): HashTag {
+ return HashTag(
+ name,
+ history.sumOf { it.uses },
+ history.map { it.uses }
+ )
+ }
+}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/InstanceInfosAPI.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/InstanceInfosAPI.kt
index f5fd6c370c..9866e36d3e 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/InstanceInfosAPI.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/InstanceInfosAPI.kt
@@ -3,19 +3,25 @@ package net.pantasystem.milktea.api.misskey
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
-import net.pantasystem.milktea.api.misskey.infos.InstanceInfosResponse
+import net.pantasystem.milktea.api.misskey.infos.SimpleInstanceInfo
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.http.GET
+import retrofit2.http.Query
import javax.inject.Inject
import javax.inject.Singleton
interface InstanceInfosAPI {
- @GET("instances.json")
- suspend fun getInstances(): Response
+ @GET("instances")
+ suspend fun getInstances(
+ @Query("name") name: String? = null,
+ @Query("limit") limit: Int? = null,
+ @Query("offset") offset: Int? = null,
+ @Query("lang") lang: String? = null,
+ ): Response>
}
@Singleton
@@ -26,12 +32,15 @@ class InstanceInfoAPIBuilder @Inject constructor(val okHttpClientProvider: OkHtt
@OptIn(ExperimentalSerializationApi::class)
private val retrofitBuilder by lazy {
Retrofit.Builder()
- .baseUrl("https://instanceapp.misskey.page")
+ .baseUrl("https://milktea-instance-suggestions.milktea.workers.dev")
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.client(okHttpClientProvider.get())
.build()
}
+
+
fun build(): InstanceInfosAPI {
return retrofitBuilder.create(InstanceInfosAPI::class.java)
}
+
}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPI.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPI.kt
index 28197fefff..c45df94dd4 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPI.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPI.kt
@@ -1,5 +1,6 @@
package net.pantasystem.milktea.api.misskey
+import kotlinx.serialization.json.JsonObject
import net.pantasystem.milktea.api.misskey.ap.ApResolveRequest
import net.pantasystem.milktea.api.misskey.ap.ApResolveResult
import net.pantasystem.milktea.api.misskey.app.CreateApp
@@ -7,7 +8,6 @@ import net.pantasystem.milktea.api.misskey.auth.App
import net.pantasystem.milktea.api.misskey.clip.*
import net.pantasystem.milktea.api.misskey.drive.*
import net.pantasystem.milktea.api.misskey.favorite.Favorite
-import net.pantasystem.milktea.api.misskey.hashtag.RequestHashTagList
import net.pantasystem.milktea.api.misskey.hashtag.SearchHashtagRequest
import net.pantasystem.milktea.api.misskey.list.*
import net.pantasystem.milktea.api.misskey.messaging.MessageAction
@@ -23,10 +23,12 @@ import net.pantasystem.milktea.api.misskey.notes.translation.Translate
import net.pantasystem.milktea.api.misskey.notes.translation.TranslationResult
import net.pantasystem.milktea.api.misskey.notification.NotificationDTO
import net.pantasystem.milktea.api.misskey.notification.NotificationRequest
+import net.pantasystem.milktea.api.misskey.online.user.OnlineUserCount
import net.pantasystem.milktea.api.misskey.register.Subscription
import net.pantasystem.milktea.api.misskey.register.UnSubscription
import net.pantasystem.milktea.api.misskey.register.WebClientBaseRequest
import net.pantasystem.milktea.api.misskey.register.WebClientRegistries
+import net.pantasystem.milktea.api.misskey.trend.HashtagTrend
import net.pantasystem.milktea.api.misskey.users.*
import net.pantasystem.milktea.api.misskey.users.renote.mute.CreateRenoteMuteRequest
import net.pantasystem.milktea.api.misskey.users.renote.mute.DeleteRenoteMuteRequest
@@ -34,8 +36,6 @@ import net.pantasystem.milktea.api.misskey.users.renote.mute.RenoteMuteDTO
import net.pantasystem.milktea.api.misskey.users.renote.mute.RenoteMutesRequest
import net.pantasystem.milktea.api.misskey.users.report.ReportDTO
import net.pantasystem.milktea.api.misskey.v13.EmojisResponse
-import net.pantasystem.milktea.model.drive.Directory
-import net.pantasystem.milktea.model.hashtag.HashTag
import net.pantasystem.milktea.model.instance.Meta
import net.pantasystem.milktea.model.instance.RequestMeta
import net.pantasystem.milktea.model.messaging.RequestMessageHistory
@@ -153,7 +153,7 @@ interface MisskeyAPI {
suspend fun showNote(@Body requestNote: NoteRequest): Response
@POST("api/notes/children")
- suspend fun children(@Body noteRequest: NoteRequest): Response>
+ suspend fun children(@Body req: GetNoteChildrenRequest): Response>
@POST("api/notes/conversation")
suspend fun conversation(@Body noteRequest: NoteRequest): Response>
@@ -198,7 +198,7 @@ interface MisskeyAPI {
suspend fun getFiles(@Body fileRequest: RequestFile): Response>
@POST("api/drive/files/update")
- suspend fun updateFile(@Body updateFileRequest: UpdateFileDTO): Response
+ suspend fun updateFile(@Body updateFileRequest: JsonObject): Response
@POST("api/drive/files/delete")
suspend fun deleteFile(@Body req: DeleteFileDTO): Response
@@ -207,10 +207,13 @@ interface MisskeyAPI {
suspend fun showFile(@Body req: ShowFile) : Response
@POST("api/drive/folders")
- suspend fun getFolders(@Body folderRequest: RequestFolder): Response>
+ suspend fun getFolders(@Body folderRequest: RequestFolder): Response>
@POST("api/drive/folders/create")
- suspend fun createFolder(@Body createFolder: CreateFolder): Response
+ suspend fun createFolder(@Body createFolder: CreateFolder): Response
+
+ @POST("api/drive/folders/show")
+ suspend fun showFolder(@Body req: ShowFolderRequest): Response
//meta
@@ -240,8 +243,6 @@ interface MisskeyAPI {
@POST("api/mute/delete")
suspend fun unmuteUser(@Body requestUser: RequestUser): Response
- @POST("api/hashtags/list")
- suspend fun getHashTagList(@Body requestHashTagList: RequestHashTagList): Response>
@POST("api/sw/register")
suspend fun swRegister(@Body subscription: Subscription) : Response
@@ -318,4 +319,10 @@ interface MisskeyAPI {
@POST("api/renote-mute/delete")
suspend fun deleteRenoteMute(@Body req: DeleteRenoteMuteRequest): Response
+
+ @POST("api/hashtags/trend")
+ suspend fun getTrendingHashtags(@Body body: EmptyRequest): Response>
+
+ @POST("api/get-online-users-count")
+ suspend fun getOnlineUsersCount(@Body body: EmptyRequest): Response
}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPIServiceBuilder.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPIServiceBuilder.kt
index de04dfe15d..dc9e7822db 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPIServiceBuilder.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/MisskeyAPIServiceBuilder.kt
@@ -85,10 +85,10 @@ class MisskeyAPIServiceBuilder @Inject constructor(
val diff = retrofit.create(MisskeyAPIV10Diff::class.java)
return MisskeyAPIV10(build(baseUrl), diff)
}
- version.isInRange(Version.Major.V_11) || version.isInRange(Version.Major.V_12) || version.isInRange(Version.Major.V_13) ->{
+ version >= Version("11") ->{
val baseAPI = build(baseUrl)
val misskeyAPIV11Diff = retrofit.create(MisskeyAPIV11Diff::class.java)
- if(version.isInRange(Version.Major.V_12) || version.isInRange(Version.Major.V_13)){
+ if(version >= Version("12")){
val misskeyAPI12DiffImpl = retrofit.create(MisskeyAPIV12Diff::class.java)
if(version >= Version("12.75.0")) {
val misskeyAPIV1275Diff = retrofit.create(MisskeyAPIV1275Diff::class.java)
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/auth/App.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/auth/App.kt
index 6b21d74dfd..adb51e6145 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/auth/App.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/auth/App.kt
@@ -47,6 +47,10 @@ fun AppType.Companion.fromDTO(app: net.pantasystem.milktea.api.mastodon.apps.App
return app.toModel()
}
+fun AppType.Companion.fromPleromaDTO(app: net.pantasystem.milktea.api.mastodon.apps.App): AppType {
+ return app.toPleromaModel()
+}
+
fun AppType.Mastodon.generateAuthUrl(baseURL: String, scope: String): String {
val encodedClientId = URLEncoder.encode(clientId, "utf-8")
val encodedRedirectUri = URLEncoder.encode(redirectUri, "utf-8")
@@ -55,6 +59,14 @@ fun AppType.Mastodon.generateAuthUrl(baseURL: String, scope: String): String {
return "$baseURL/oauth/authorize?client_id=${encodedClientId}&redirect_uri=$encodedRedirectUri&response_type=$encodedResponseType&scope=$encodedScope"
}
+fun AppType.Pleroma.generateAuthUrl(baseURL: String, scope: String): String {
+ val encodedClientId = URLEncoder.encode(clientId, "utf-8")
+ val encodedRedirectUri = URLEncoder.encode(redirectUri, "utf-8")
+ val encodedResponseType = URLEncoder.encode("code", "utf-8")
+ val encodedScope = URLEncoder.encode(scope, "utf-8")
+ return "$baseURL/oauth/authorize?client_id=${encodedClientId}&redirect_uri=$encodedRedirectUri&response_type=$encodedResponseType&scope=$encodedScope"
+}
+
/**
* @param scope アプリ作成時に指定したscope
* @param code redirectUrl+codeで帰ってきたコード
@@ -69,3 +81,14 @@ fun AppType.Mastodon.createObtainToken(scope: String, code: String): ObtainToken
grantType = "authorization_code"
)
}
+
+fun AppType.Pleroma.createObtainToken(scope: String, code: String): ObtainToken {
+ return ObtainToken(
+ clientId = clientId,
+ clientSecret = clientSecret,
+ scope = scope,
+ redirectUri = redirectUri,
+ code = code,
+ grantType = "authorization_code"
+ )
+}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/DirectoryNetworkDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/DirectoryNetworkDTO.kt
new file mode 100644
index 0000000000..e9d401b753
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/DirectoryNetworkDTO.kt
@@ -0,0 +1,38 @@
+package net.pantasystem.milktea.api.misskey.drive
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.drive.Directory
+import net.pantasystem.milktea.model.drive.DirectoryId
+
+@Serializable
+data class DirectoryNetworkDTO(
+ @SerialName("id") val id: String,
+ @SerialName("createdAt") val createdAt: String,
+ @SerialName("name") val name: String,
+ @SerialName("foldersCount") val foldersCount: Int? = null,
+ @SerialName("filesCount") val filesCount: Int? = null,
+ @SerialName("parentId") val parentId: String? = null,
+ @SerialName("parent") val parent: DirectoryNetworkDTO? = null
+) {
+ fun toModel(account: Account): Directory {
+ return Directory(
+ id = DirectoryId(
+ accountId = account.accountId,
+ directoryId = id
+ ),
+ createdAt = createdAt,
+ name = name,
+ foldersCount = foldersCount,
+ filesCount = filesCount,
+ parentId = parentId?.let {
+ DirectoryId(
+ accountId = account.accountId,
+ directoryId = it
+ )
+ },
+ parent = parent?.toModel(account)
+ )
+ }
+}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/ShowFolderRequest.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/ShowFolderRequest.kt
new file mode 100644
index 0000000000..45cd0061b3
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/ShowFolderRequest.kt
@@ -0,0 +1,10 @@
+package net.pantasystem.milktea.api.misskey.drive
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class ShowFolderRequest(
+ @SerialName("i") val i: String,
+ @SerialName("folderId") val folderId: String,
+)
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/UpdateFileDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/UpdateFileDTO.kt
index 8ca341d85e..9d89676c79 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/UpdateFileDTO.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/drive/UpdateFileDTO.kt
@@ -1,39 +1,75 @@
package net.pantasystem.milktea.api.misskey.drive
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.buildJsonObject
import net.pantasystem.milktea.model.drive.UpdateFileProperty
+import net.pantasystem.milktea.model.drive.ValueType
-@Serializable
-data class UpdateFileDTO(
- @SerialName("i")
- val i: String,
-
- @SerialName("fileId")
- val fileId: String,
-
- @SerialName("folderId")
- val folderId: String?,
-
- @SerialName("name")
- val name: String,
-
- @SerialName("comment")
- val comment: String?,
-
- @SerialName("isSensitive")
- val isSensitive: Boolean,
-) {
- companion object
-}
-
-fun UpdateFileDTO.Companion.from(token: String, model: UpdateFileProperty): UpdateFileDTO {
- return UpdateFileDTO(
- i = token,
- comment = model.comment,
- fileId = model.fileId.fileId,
- folderId = model.folderId,
- isSensitive = model.isSensitive,
- name = model.name
- )
+//@Serializable
+//data class UpdateFileDTO(
+// @SerialName("i")
+// val i: String,
+//
+// @SerialName("fileId")
+// val fileId: String,
+//
+// @SerialName("folderId")
+// val folderId: String?,
+//
+// @SerialName("name")
+// val name: String,
+//
+// @SerialName("comment")
+// val comment: String?,
+//
+// @SerialName("isSensitive")
+// val isSensitive: Boolean,
+//) {
+// companion object
+//}
+
+//fun UpdateFileDTO.Companion.from(token: String, model: UpdateFileProperty): UpdateFileDTO {
+// return UpdateFileDTO(
+// i = token,
+// comment = model.comment,
+// fileId = model.fileId.fileId,
+// folderId = model.folderId,
+// isSensitive = model.isSensitive,
+// name = model.name
+// )
+//}
+
+@OptIn(ExperimentalSerializationApi::class)
+fun UpdateFileProperty.toJsonObject(token: String): JsonObject {
+ return buildJsonObject {
+ put("i", JsonPrimitive(token))
+ put("fileId", JsonPrimitive(fileId.fileId))
+
+ when(val v = comment) {
+ is ValueType.Empty -> put("comment", JsonPrimitive(null))
+ is ValueType.Some -> put("comment", JsonPrimitive(v.value))
+ null -> Unit
+ }
+
+ when(val v = folderId) {
+ is ValueType.Empty -> put("folderId", JsonPrimitive(null))
+ is ValueType.Some -> put("folderId", JsonPrimitive(v.value))
+ null -> Unit
+ }
+
+ when(val v = name) {
+ is ValueType.Empty -> put("name", JsonPrimitive(null))
+ is ValueType.Some -> put("name", JsonPrimitive(v.value))
+ null -> Unit
+ }
+
+ when(val v = isSensitive) {
+ is ValueType.Empty -> put("isSensitive", JsonPrimitive(null))
+ is ValueType.Some -> put("isSensitive", JsonPrimitive(v.value))
+ null -> Unit
+ }
+
+ }
}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/CustomEmojiNetworkDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/CustomEmojiNetworkDTO.kt
new file mode 100644
index 0000000000..f45b7ca2b0
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/CustomEmojiNetworkDTO.kt
@@ -0,0 +1,33 @@
+package net.pantasystem.milktea.api.misskey.emoji
+
+import kotlinx.serialization.SerialName
+import net.pantasystem.milktea.model.emoji.Emoji
+
+@kotlinx.serialization.Serializable
+data class CustomEmojiNetworkDTO(
+ @SerialName("id") val id: String? = null,
+ @SerialName("name") val name: String,
+ @SerialName("host") val host: String? = null,
+ @SerialName("url") val url: String? = null,
+ @SerialName("uri") val uri: String? = null,
+ @SerialName("type") val type: String? = null,
+ @SerialName("category") val category: String? = null,
+ @SerialName("aliases") val aliases: List? = null,
+ @SerialName("width") val width: Int? = null,
+ @SerialName("height") val height: Int? = null,
+) {
+ fun toModel(aspectRatio: Float? = null, cachePath: String? = null): Emoji {
+ return Emoji(
+ id = id,
+ name = name,
+ host = host,
+ url = url,
+ uri = uri,
+ type = type,
+ category = category,
+ aliases = aliases,
+ aspectRatio = aspectRatio ?: if (width == null || height == null || height <= 0) null else width.toFloat() / height,
+ cachePath = cachePath,
+ )
+ }
+}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/EmojisType.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/EmojisType.kt
index d48a324834..d76952c13b 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/EmojisType.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/emoji/EmojisType.kt
@@ -12,13 +12,12 @@ import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonContentPolymorphicSerializer
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
-import net.pantasystem.milktea.model.emoji.Emoji
@kotlinx.serialization.Serializable(with = CustomEmojisTypeSerializer::class)
sealed interface EmojisType {
@kotlinx.serialization.Serializable(with = TypeArraySerializer::class)
- data class TypeArray(val emojis: List) : EmojisType
+ data class TypeArray(val emojis: List) : EmojisType
@kotlinx.serialization.Serializable(with = TypeObjectSerializer::class)
data class TypeObject(val emojis: Map) : EmojisType
@@ -61,7 +60,7 @@ object TypeObjectSerializer : KSerializer {
}
class TypeArraySerializer : KSerializer {
- private val listSerializer = ListSerializer(Emoji.serializer())
+ private val listSerializer = ListSerializer(CustomEmojiNetworkDTO.serializer())
override val descriptor: SerialDescriptor = listSerializer.descriptor
override fun deserialize(decoder: Decoder): EmojisType.TypeArray {
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/InstanceInfosResponse.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/InstanceInfosResponse.kt
index e924f98ac0..d2af153e47 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/InstanceInfosResponse.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/InstanceInfosResponse.kt
@@ -1,15 +1,11 @@
package net.pantasystem.milktea.api.misskey.infos
-import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import net.pantasystem.milktea.api.activitypub.NodeInfoDTO
import net.pantasystem.milktea.model.instance.Meta
@kotlinx.serialization.Serializable
data class InstanceInfosResponse(
- @SerialName("date")
- val date: Instant,
-
@SerialName("instancesInfos")
val instancesInfos: List
) {
@@ -27,8 +23,8 @@ data class InstanceInfosResponse(
@SerialName("url")
val url: String,
- @SerialName("value")
- val value: Double,
+// @SerialName("value")
+// val value: Double,
@SerialName("meta")
val meta: Meta,
@@ -44,13 +40,13 @@ data class InstanceInfosResponse(
@SerialName("isAlive")
val isAlive: Boolean,
- @SerialName("banner")
- val banner: Boolean,
-
- @SerialName("icon")
- val icon: Boolean,
+// @SerialName("banner")
+// val banner: Boolean,
- @SerialName("background")
- val background: Boolean
+// @SerialName("icon")
+// val icon: Boolean,
+//
+// @SerialName("background")
+// val background: Boolean
)
}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/SimpleInstanceInfo.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/SimpleInstanceInfo.kt
new file mode 100644
index 0000000000..56b866aedb
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/infos/SimpleInstanceInfo.kt
@@ -0,0 +1,12 @@
+package net.pantasystem.milktea.api.misskey.infos
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class SimpleInstanceInfo(
+ @SerialName("url") val url: String,
+ @SerialName("name") val name: String,
+ @SerialName("description") val description: String? = null,
+ @SerialName("iconUrl") val iconUrl: String? = null,
+)
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/GetNoteChildrenRequest.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/GetNoteChildrenRequest.kt
new file mode 100644
index 0000000000..f339287cdc
--- /dev/null
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/GetNoteChildrenRequest.kt
@@ -0,0 +1,11 @@
+package net.pantasystem.milktea.api.misskey.notes
+
+import kotlinx.serialization.SerialName
+
+@kotlinx.serialization.Serializable
+data class GetNoteChildrenRequest(
+ @SerialName("i") val i: String,
+ @SerialName("noteId") val noteId: String,
+ @SerialName("limit") val limit: Int,
+ @SerialName("depth") val depth: Int,
+)
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/NoteDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/NoteDTO.kt
index 730bd4c0bf..a7ae62dfea 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/NoteDTO.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/notes/NoteDTO.kt
@@ -6,11 +6,11 @@ import kotlinx.datetime.serializers.InstantIso8601Serializer
import kotlinx.serialization.SerialName
import net.pantasystem.milktea.api.misskey.auth.App
import net.pantasystem.milktea.api.misskey.drive.FilePropertyDTO
+import net.pantasystem.milktea.api.misskey.emoji.CustomEmojiNetworkDTO
import net.pantasystem.milktea.api.misskey.emoji.CustomEmojisTypeSerializer
import net.pantasystem.milktea.api.misskey.emoji.EmojisType
import net.pantasystem.milktea.api.misskey.users.UserDTO
import net.pantasystem.milktea.common.serializations.EnumIgnoreUnknownSerializer
-import net.pantasystem.milktea.model.emoji.Emoji
import java.io.Serializable
@kotlinx.serialization.Serializable
@@ -126,15 +126,15 @@ data class NoteDTO(
EmojisType.None -> emptyList()
is EmojisType.TypeArray -> emojis.emojis
is EmojisType.TypeObject -> emojis.emojis.map {
- Emoji(name = it.key, url = it.value)
+ CustomEmojiNetworkDTO(name = it.key, url = it.value)
}
null -> emptyList()
}
- val emojiList: List = when(rawEmojis) {
+ val emojiList: List = when(rawEmojis) {
EmojisType.None -> emptyList()
is EmojisType.TypeArray -> rawEmojis.emojis
is EmojisType.TypeObject -> (rawEmojis.emojis).map {
- Emoji(name = it.key, url = it.value, uri = it.value)
+ CustomEmojiNetworkDTO(name = it.key, url = it.value, uri = it.value)
}
null -> emptyList()
} + reactionEmojiList
@@ -155,4 +155,6 @@ object NoteVisibilityTypeSerializer : EnumIgnoreUnknownSerializer,
+ @SerialName("usersCount") val usersCount: Int,
+) {
+ fun toModel(): HashTag {
+ return HashTag(
+ tag,
+ usersCount,
+ chart
+ )
+ }
+}
\ No newline at end of file
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/RequestUser.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/RequestUser.kt
index de14b78a15..10da1540d6 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/RequestUser.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/RequestUser.kt
@@ -3,7 +3,7 @@ package net.pantasystem.milktea.api.misskey.users
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
-import net.pantasystem.milktea.model.user.query.FindUsersQuery
+import net.pantasystem.milktea.model.user.query.FindUsersQuery4Misskey
@Serializable
data class RequestUser(
@@ -52,7 +52,7 @@ data class RequestUser(
}
-fun RequestUser.Companion.from(query: FindUsersQuery, i: String): RequestUser {
+fun RequestUser.Companion.from(query: FindUsersQuery4Misskey, i: String): RequestUser {
return RequestUser(
i = i,
origin = query.origin?.origin,
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/UserDTO.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/UserDTO.kt
index 739aaecc76..68518962c9 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/UserDTO.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/users/UserDTO.kt
@@ -4,10 +4,10 @@ package net.pantasystem.milktea.api.misskey.users
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.serialization.SerialName
+import net.pantasystem.milktea.api.misskey.emoji.CustomEmojiNetworkDTO
import net.pantasystem.milktea.api.misskey.emoji.CustomEmojisTypeSerializer
import net.pantasystem.milktea.api.misskey.emoji.EmojisType
import net.pantasystem.milktea.api.misskey.notes.NoteDTO
-import net.pantasystem.milktea.model.emoji.Emoji
import java.io.Serializable
/**
@@ -141,11 +141,11 @@ data class UserDTO(
val themeColor: String? = null,
)
- val emojiList: List? = when(rawEmojis) {
+ val emojiList: List? = when(rawEmojis) {
EmojisType.None -> null
is EmojisType.TypeArray -> rawEmojis.emojis
is EmojisType.TypeObject -> rawEmojis.emojis.map {
- Emoji(name = it.key, url = it.value, uri = it.value)
+ CustomEmojiNetworkDTO(name = it.key, url = it.value, uri = it.value)
}
null -> null
}
diff --git a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/v13/EmojisResponse.kt b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/v13/EmojisResponse.kt
index b121eacb45..e4bdb3813e 100644
--- a/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/v13/EmojisResponse.kt
+++ b/modules/api/src/main/java/net/pantasystem/milktea/api/misskey/v13/EmojisResponse.kt
@@ -1,10 +1,10 @@
package net.pantasystem.milktea.api.misskey.v13
import kotlinx.serialization.SerialName
-import net.pantasystem.milktea.model.emoji.Emoji
+import net.pantasystem.milktea.api.misskey.emoji.CustomEmojiNetworkDTO
@kotlinx.serialization.Serializable
data class EmojisResponse(
@SerialName("emojis")
- val emojis: List
+ val emojis: List
)
\ No newline at end of file
diff --git a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/events.kt b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/events.kt
index 93888a3cbc..ad2646a81d 100644
--- a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/events.kt
+++ b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/events.kt
@@ -256,6 +256,14 @@ sealed class ChannelBody : StreamingEvent(){
override val id: String
) : Main()
+ @Serializable
+ @SerialName("reply")
+ data class Reply(
+ @SerialName("id")
+ override val id: String,
+ @SerialName("body")
+ val body: NoteDTO
+ ) : Main()
}
}
diff --git a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/mastodon/Event.kt b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/mastodon/Event.kt
index 1f31d08f0f..30b087909c 100644
--- a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/mastodon/Event.kt
+++ b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/mastodon/Event.kt
@@ -37,7 +37,9 @@ data class EmojiReaction(
@SerialName("static_url") val staticUrl: String? = null,
@SerialName("domain") val domain: String? = null,
@SerialName("account_ids") val accountIds: List,
- @SerialName("status_id") val statusId: String
+ @SerialName("status_id") val statusId: String,
+ @SerialName("width") val width: Int? = null,
+ @SerialName("height") val height: Int? = null,
) {
val isCustomEmoji: Boolean = url != null || staticUrl != null
val reaction = if (isCustomEmoji) {
@@ -51,7 +53,7 @@ data class EmojiReaction(
}
- fun toEmoji(): Emoji? {
+ fun toEmoji(cachePath: String? = null): Emoji? {
if (!isCustomEmoji) {
return null
}
@@ -64,6 +66,8 @@ data class EmojiReaction(
},
url = url,
host = domain,
+ aspectRatio = if (width == null || height == null) null else (width.toFloat() / height),
+ cachePath = cachePath,
)
}
diff --git a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/network/SocketImpl.kt b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/network/SocketImpl.kt
index c170181c44..a803392006 100644
--- a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/network/SocketImpl.kt
+++ b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/network/SocketImpl.kt
@@ -3,19 +3,28 @@ package net.pantasystem.milktea.api_streaming.network
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import net.pantasystem.milktea.api.misskey.OkHttpClientProvider
-import net.pantasystem.milktea.api_streaming.*
+import net.pantasystem.milktea.api_streaming.PollingJob
+import net.pantasystem.milktea.api_streaming.Socket
+import net.pantasystem.milktea.api_streaming.SocketMessageEventListener
+import net.pantasystem.milktea.api_streaming.SocketStateEventListener
+import net.pantasystem.milktea.api_streaming.StreamingEvent
import net.pantasystem.milktea.common.Logger
import net.pantasystem.milktea.common.runCancellableCatching
-import okhttp3.*
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import okhttp3.WebSocket
+import okhttp3.WebSocketListener
import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class SocketImpl(
val url: String,
+ var isRequirePingPong: () -> Boolean,
loggerFactory: Logger.Factory,
- okHttpClientProvider: OkHttpClientProvider
- ) : Socket {
+ okHttpClientProvider: OkHttpClientProvider,
+) : Socket {
val logger = loggerFactory.create("SocketImpl")
private val okHttpClient: OkHttpClient = okHttpClientProvider
@@ -269,7 +278,8 @@ class SocketImpl(
super.onMessage(webSocket, text)
runCancellableCatching {
pollingJob.onReceive(text)
- }.onSuccess {
+ }
+ if (text.lowercase() == "pong") {
return
}
val e = runCancellableCatching { json.decodeFromString(text) }.onFailure { t ->
@@ -305,7 +315,9 @@ class SocketImpl(
synchronized(this@SocketImpl) {
pollingJob.cancel()
pollingJob = PollingJob(this@SocketImpl).also {
- it.startPolling(4000, 900, 12000)
+ if (isRequirePingPong()) {
+ it.startPolling(4000, 900, 12000)
+ }
}
mState = Socket.State.Connected
}
diff --git a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/pollings.kt b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/pollings.kt
index 1ee0fab532..eb6a2d49de 100644
--- a/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/pollings.kt
+++ b/modules/api_streaming/src/main/java/net/pantasystem/milktea/api_streaming/pollings.kt
@@ -1,12 +1,19 @@
package net.pantasystem.milktea.api_streaming
import android.util.Log
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withTimeout
import kotlinx.datetime.Clock
const val TTL_COUNT = 3
@@ -40,7 +47,7 @@ internal class PollingJob(
try {
val pong = withTimeout(timeout) {
pongs.first {
- it == "pong"
+ it.isNotBlank()
}
}
val resTime = Clock.System.now()
@@ -64,11 +71,7 @@ internal class PollingJob(
}
fun onReceive(msg: String) {
- if (msg.lowercase() == "pong") {
- pongs.tryEmit(msg)
- } else {
- throw IllegalArgumentException()
- }
+ pongs.tryEmit(msg)
}
fun cancel() {
diff --git a/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveDirectoryPagingStore.kt b/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveDirectoryPagingStore.kt
index d0bd9855d4..9193ca08a8 100644
--- a/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveDirectoryPagingStore.kt
+++ b/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveDirectoryPagingStore.kt
@@ -7,7 +7,7 @@ import net.pantasystem.milktea.model.drive.Directory
interface DriveDirectoryPagingStore {
val state: Flow>>
- suspend fun loadPrevious()
+ suspend fun loadPrevious(): Result
suspend fun clear()
suspend fun setAccount(account: Account?)
suspend fun setCurrentDirectory(directory: Directory?)
diff --git a/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveStore.kt b/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveStore.kt
deleted file mode 100644
index 726da4b27e..0000000000
--- a/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/DriveStore.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-package net.pantasystem.milktea.app_store.drive
-
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import net.pantasystem.milktea.common.runCancellableCatching
-import net.pantasystem.milktea.model.account.Account
-import net.pantasystem.milktea.model.drive.Directory
-import net.pantasystem.milktea.model.drive.DirectoryPath
-import net.pantasystem.milktea.model.drive.FileProperty
-import net.pantasystem.milktea.model.drive.SelectedFilePropertyIds
-
-
-data class DriveState (
- val path: DirectoryPath,
- val accountId: Long?,
- val selectedFilePropertyIds: SelectedFilePropertyIds?
-) {
- val isSelectMode: Boolean get() = selectedFilePropertyIds != null
-}
-
-class DriveStore(
- iniState: DriveState
-) {
-
- private val _state = MutableStateFlow(iniState)
- val state: StateFlow get() = _state
-
-
-
- fun toggleSelect(id: FileProperty.Id) : Boolean {
- val ds = this.state.value
- if(ds.selectedFilePropertyIds == null) {
- return false
- }
- return if(ds.selectedFilePropertyIds.exists(id)) {
- deselect(id)
- }else{
- select(id)
- }
- }
-
- fun select(id: FileProperty.Id) : Boolean {
- return runCancellableCatching {
- this._state.value = this.state.value.let {
- it.copy(selectedFilePropertyIds = it.selectedFilePropertyIds?.addAndCopy(id))
- }
- }.isSuccess
- }
-
- fun deselect(id: FileProperty.Id) : Boolean {
- return runCancellableCatching {
- this._state.value = this.state.value.let {
- it.copy(selectedFilePropertyIds = it.selectedFilePropertyIds?.removeAndCopy(id))
- }
- }.isSuccess
- }
-
-
- fun pop() : Boolean{
- val s = this.state.value
- val p = s.path.pop()
- this._state.value = s.copy(path = p)
- return p != s.path
- }
-
- fun popUntil(directory: Directory?) {
- val s = this.state.value
- this._state.value = s.copy(path = s.path.popUntil(directory))
- }
-
- fun push(directory: Directory) {
- val s = this.state.value
- this._state.value = s.copy(path = s.path.push(directory))
- }
-
-
- fun setAccount(account: Account) {
- if(this.state.value.accountId == account.accountId) {
- return
- }
- this._state.value = this.state.value.copy(
- accountId = account.accountId,
- selectedFilePropertyIds = this.state.value.selectedFilePropertyIds?.clearSelectedIdsAndCopy(),
- path = this.state.value.path.clear()
- )
-
- }
-}
\ No newline at end of file
diff --git a/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/FilePropertyPagingStore.kt b/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/FilePropertyPagingStore.kt
index 587ee31005..3fa8bf89e9 100644
--- a/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/FilePropertyPagingStore.kt
+++ b/modules/app_store/src/main/java/net/pantasystem/milktea/app_store/drive/FilePropertyPagingStore.kt
@@ -10,7 +10,7 @@ interface FilePropertyPagingStore {
val state: Flow>>
val isLoading: Boolean
- suspend fun loadPrevious()
+ suspend fun loadPrevious(): Result
suspend fun clear()
suspend fun setCurrentDirectory(directory: Directory?)
suspend fun setCurrentAccount(account: Account?)
diff --git a/modules/common/src/main/java/net/pantasystem/milktea/common/coroutines/Throttle.kt b/modules/common/src/main/java/net/pantasystem/milktea/common/coroutines/Throttle.kt
new file mode 100644
index 0000000000..818882f2df
--- /dev/null
+++ b/modules/common/src/main/java/net/pantasystem/milktea/common/coroutines/Throttle.kt
@@ -0,0 +1,13 @@
+package net.pantasystem.milktea.common.coroutines
+
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.transform
+
+fun Flow.throttleLatest(delayMillis: Long): Flow = this
+ .conflate()
+ .transform {
+ emit(it)
+ delay(delayMillis)
+ }
\ No newline at end of file
diff --git a/modules/common/src/main/java/net/pantasystem/milktea/common/glide/MiGlideModule.kt b/modules/common/src/main/java/net/pantasystem/milktea/common/glide/MiGlideModule.kt
index ff1ff0fd39..599b7efbe8 100644
--- a/modules/common/src/main/java/net/pantasystem/milktea/common/glide/MiGlideModule.kt
+++ b/modules/common/src/main/java/net/pantasystem/milktea/common/glide/MiGlideModule.kt
@@ -13,6 +13,7 @@ import com.github.penfeizhou.animation.decode.FrameSeqDecoder
import net.pantasystem.milktea.common.glide.apng.ByteBufferApngDecoder
import net.pantasystem.milktea.common.glide.apng.FrameSeqDecoderBitmapTranscoder
import net.pantasystem.milktea.common.glide.apng.FrameSeqDecoderDrawableTranscoder
+import net.pantasystem.milktea.common.glide.apng.StreamApngDecoder
import net.pantasystem.milktea.common.glide.blurhash.*
import net.pantasystem.milktea.common.glide.svg.SvgBitmapTransCoder
import net.pantasystem.milktea.common.glide.svg.SvgDecoder
@@ -24,8 +25,10 @@ import java.nio.ByteBuffer
class MiGlideModule : AppGlideModule(){
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
+ val decoder = ByteBufferApngDecoder()
registry
- .prepend(ByteBuffer::class.java, FrameSeqDecoder::class.java, ByteBufferApngDecoder())
+ .prepend(InputStream::class.java, FrameSeqDecoder::class.java, StreamApngDecoder(decoder))
+ .prepend(ByteBuffer::class.java, FrameSeqDecoder::class.java, decoder)
.register(FrameSeqDecoder::class.java, Drawable::class.java, FrameSeqDecoderDrawableTranscoder())
.register(FrameSeqDecoder::class.java, Bitmap::class.java, FrameSeqDecoderBitmapTranscoder(glide))
.register(SVG::class.java, BitmapDrawable::class.java, SvgBitmapTransCoder(context))
diff --git a/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/ApngDecoder.kt b/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/ApngDecoder.kt
index 6a5e15787e..61ca051dbf 100644
--- a/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/ApngDecoder.kt
+++ b/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/ApngDecoder.kt
@@ -1,6 +1,5 @@
package net.pantasystem.milktea.common.glide.apng
-import android.util.Log
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.ResourceDecoder
import com.bumptech.glide.load.engine.Resource
@@ -10,7 +9,6 @@ import com.github.penfeizhou.animation.decode.FrameSeqDecoder
import com.github.penfeizhou.animation.io.ByteBufferReader
import com.github.penfeizhou.animation.loader.ByteBufferLoader
import com.github.penfeizhou.animation.loader.Loader
-import okhttp3.internal.toHexString
import java.nio.ByteBuffer
@@ -37,18 +35,14 @@ class ByteBufferApngDecoder : ResourceDecoder>
}
override fun handles(source: ByteBuffer, options: Options): Boolean {
- Log.d("ByteBufferApngDecoder", "apng decoder on decode")
val byteBufferArray = ByteArray(8)
source.get(byteBufferArray, 0, 4)
val header = ByteBuffer.wrap(byteBufferArray).long ushr 32
if (header != PNG) {
- Log.d("ByteBufferApngDecoder", "is not png:${header.toHexString()}")
return false
}
- val result = APNGParser.isAPNG(ByteBufferReader(source))
- Log.d("ByteBufferApngDecoder", "handlers isApng:$result")
- return result
+ return APNGParser.isAPNG(ByteBufferReader(source))
}
diff --git a/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/StreamApngDecoder.kt b/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/StreamApngDecoder.kt
new file mode 100644
index 0000000000..cd3bb78cff
--- /dev/null
+++ b/modules/common/src/main/java/net/pantasystem/milktea/common/glide/apng/StreamApngDecoder.kt
@@ -0,0 +1,58 @@
+package net.pantasystem.milktea.common.glide.apng
+
+import com.bumptech.glide.load.Options
+import com.bumptech.glide.load.ResourceDecoder
+import com.bumptech.glide.load.engine.Resource
+import com.github.penfeizhou.animation.apng.decode.APNGParser
+import com.github.penfeizhou.animation.decode.FrameSeqDecoder
+import com.github.penfeizhou.animation.io.StreamReader
+import java.io.ByteArrayOutputStream
+import java.io.IOException
+import java.io.InputStream
+import java.nio.ByteBuffer
+
+class StreamApngDecoder(
+ val byteBufferApngDecoder: ByteBufferApngDecoder,
+) : ResourceDecoder> {
+ override fun decode(
+ source: InputStream,
+ width: Int,
+ height: Int,
+ options: Options,
+ ): Resource>? {
+ val data = inputStreamToBytes(source) ?: return null
+ val byteBuffer = ByteBuffer.wrap(data)
+ return byteBufferApngDecoder.decode(byteBuffer, width, height, options)
+ }
+
+ override fun handles(source: InputStream, options: Options): Boolean {
+ val headerBytes = ByteArray(8)
+ val bytesRead = source.read(headerBytes)
+ // ファイルが8バイト未満の場合、それは有効なPNGではない
+ if (bytesRead < 8) {
+ return false
+ }
+
+ val header = ByteBuffer.wrap(headerBytes).long ushr 32
+ if (header != PNG) {
+ return false
+ }
+ return APNGParser.isAPNG(StreamReader(source))
+ }
+
+ private fun inputStreamToBytes(`is`: InputStream): ByteArray? {
+ val bufferSize = 16384
+ val buffer = ByteArrayOutputStream(bufferSize)
+ try {
+ var nRead: Int
+ val data = ByteArray(bufferSize)
+ while (`is`.read(data).also { nRead = it } != -1) {
+ buffer.write(data, 0, nRead)
+ }
+ buffer.flush()
+ } catch (e: IOException) {
+ return null
+ }
+ return buffer.toByteArray()
+ }
+}
\ No newline at end of file
diff --git a/modules/common/src/main/java/net/pantasystem/milktea/common/state_helper.kt b/modules/common/src/main/java/net/pantasystem/milktea/common/state_helper.kt
index 2b5c39f5c4..d9eff075a6 100644
--- a/modules/common/src/main/java/net/pantasystem/milktea/common/state_helper.kt
+++ b/modules/common/src/main/java/net/pantasystem/milktea/common/state_helper.kt
@@ -1,5 +1,10 @@
package net.pantasystem.milktea.common
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+
sealed class ResultState(val content: StateContent) {
class Fixed(content: StateContent) : ResultState(content)
@@ -127,4 +132,16 @@ sealed class PageableState(val content: StateContent) {
}
}
-}
\ No newline at end of file
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+fun Flow>.convert(converter: suspend (T?) -> Flow): Flow> {
+ return flatMapLatest { state ->
+ val content = (state.content as? StateContent.Exist)?.rawContent
+ converter(content).map { convertTo ->
+ state.convert {
+ convertTo
+ }
+ }
+ }
+}
diff --git a/modules/common/src/main/java/net/pantasystem/milktea/common/text/UrlPatternChecker.kt b/modules/common/src/main/java/net/pantasystem/milktea/common/text/UrlPatternChecker.kt
new file mode 100644
index 0000000000..c62c43adf8
--- /dev/null
+++ b/modules/common/src/main/java/net/pantasystem/milktea/common/text/UrlPatternChecker.kt
@@ -0,0 +1,9 @@
+package net.pantasystem.milktea.common.text
+
+object UrlPatternChecker {
+ private val urlPattern = Regex("""(https?)(://)([-_.!~*'()\[\]a-zA-Z0-9;/?:@&=+${'$'},%#]+)""")
+ fun isMatch(text: String): Boolean {
+ return urlPattern.matches(text)
+ }
+
+}
\ No newline at end of file
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/ElementType.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/ElementType.kt
index 52544ab375..9fcc49e964 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/ElementType.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/ElementType.kt
@@ -21,7 +21,10 @@ enum class ElementType(val elementClass: ElementClass) {
TEXT(ElementClass.TEXT),
EMOJI(ElementClass.EMOJI),
MENTION(ElementClass.LINK),
- HASH_TAG(ElementClass.LINK)
+ HASH_TAG(ElementClass.LINK),
+ FnX2(ElementClass.STANDARD),
+ FnX3(ElementClass.STANDARD),
+ FnX4(ElementClass.STANDARD),
}
enum class ElementClass(val weight: Int){
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMContract.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMContract.kt
index 1db7708722..ba496645f8 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMContract.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMContract.kt
@@ -16,4 +16,10 @@ object MFMContract {
"motion" to TagType.MOTION,
"jump" to TagType.JUMP*/
)
+
+ val fnTypeTagNameMap = mapOf(
+ "x2" to ElementType.FnX2,
+ "x3" to ElementType.FnX3,
+ "x4" to ElementType.FnX4
+ )
}
\ No newline at end of file
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMParser.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMParser.kt
index bd560b7609..ff8db37585 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMParser.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/mfm/MFMParser.kt
@@ -1,5 +1,6 @@
package net.pantasystem.milktea.common_android.mfm
+import android.util.Log
import jp.panta.misskeyandroidclient.mfm.*
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common_android.emoji.V13EmojiUrlResolver
@@ -28,6 +29,8 @@ object MFMParser {
private val idPattern = Pattern.compile("""^([a-zA-Z0-9]+)$""")
+ private val fnPattern = Pattern.compile("""\A\$\[([a-z\d]+) (.+?)]""", Pattern.DOTALL)
+
fun parse(
text: String?,
@@ -116,13 +119,14 @@ object MFMParser {
'>' to listOf(::parseQuote), //引用
'*' to listOf(::parseTypeStar), // 横伸縮対称揺れ, 太字
'【' to listOf(::parseTitle),//タイトル
+ '$' to listOf(::parseFn),
'[' to listOf(::parseSearch, ::parseLink, ::parseTitle),
'?' to listOf(::parseLink),
'S' to listOf(::parseSearch),
':' to listOf(::parseEmoji),
'@' to listOf(::parseMention),
'#' to listOf(::parseHashTag),
- 'h' to listOf(::parseUrl)
+ 'h' to listOf(::parseUrl),
)
@@ -251,6 +255,30 @@ object MFMParser {
}
}
+ private fun parseFn(): Node? {
+ Log.d("parseFn", "parseFn: ${sourceText.substring(position, parent.insideEnd)}")
+ // $[x2 任意のテキスト]みたいのをParseする
+ val matcher = fnPattern.matcher(sourceText.substring(position, parent.insideEnd))
+
+ if (!matcher.find()) {
+ return null
+ }
+ val tagName = matcher.nullableGroup(1).also {
+ Log.d("parseFn", "parseFn: $it, ${matcher.nullableGroup(0)}")
+ } ?: return null
+ val tag = MFMContract.fnTypeTagNameMap[tagName] ?: return null
+ if (parent.elementType.elementClass.weight < tag.elementClass.weight) {
+ return null
+ }
+ return Node(
+ start = position,
+ end = position + matcher.end(),
+ insideStart = position + tagName.length + 3,
+ insideEnd = position + matcher.end(2),
+ elementType = tag
+ )
+ }
+
private fun parseStrike(): Node? {
val pattern = Pattern.compile("""\A~~(.+?)~~""", Pattern.DOTALL)
val matcher = pattern.matcher(sourceText.substring(position, parent.insideEnd))
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/FontSizeHelper.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/FontSizeHelper.kt
new file mode 100644
index 0000000000..dbb07fe8a3
--- /dev/null
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/FontSizeHelper.kt
@@ -0,0 +1,18 @@
+package net.pantasystem.milktea.common_android.ui
+
+import android.util.TypedValue
+import android.widget.TextView
+
+object FontSizeHelper {
+ fun TextView.setMemoFontPxSize(fontSize: Float) {
+ if (this.textSize == fontSize) {
+ return
+ }
+ this.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
+ }
+
+ fun TextView.setMemoFontSpSize(fontSize: Float) {
+ val baseHeightPx = context.resources.displayMetrics.scaledDensity * fontSize
+ setMemoFontPxSize(baseHeightPx)
+ }
+}
\ No newline at end of file
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/CustomEmojiDecorator.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/CustomEmojiDecorator.kt
index 8d11cc06e7..2c87fce59c 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/CustomEmojiDecorator.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/CustomEmojiDecorator.kt
@@ -2,14 +2,14 @@ package net.pantasystem.milktea.common_android.ui.text
import android.text.SpannableStringBuilder
import android.text.Spanned
+import android.text.style.RelativeSizeSpan
import android.widget.TextView
import net.pantasystem.milktea.common.glide.GlideApp
import net.pantasystem.milktea.model.emoji.CustomEmojiParsedResult
import net.pantasystem.milktea.model.emoji.CustomEmojiParser
import net.pantasystem.milktea.model.emoji.Emoji
import net.pantasystem.milktea.model.emoji.EmojiResolvedType
-import net.pantasystem.milktea.model.instance.HostWithVersion
-import kotlin.math.min
+import kotlin.math.max
class CustomEmojiDecorator {
@@ -31,13 +31,17 @@ class CustomEmojiDecorator {
text,
)
result.emojis.filter {
- HostWithVersion.isOverV13(accountHost) || it.result is EmojiResolvedType.Resolved
+ it.result is EmojiResolvedType.Resolved
}.map {
- val span = DrawableEmojiSpan(emojiAdapter, it.result.getUrl(accountHost))
+ val span = DrawableEmojiSpan(
+ emojiAdapter,
+ it.result.getUrl(accountHost),
+ (it.result as? EmojiResolvedType.Resolved)?.emoji?.aspectRatio
+ )
GlideApp.with(view)
.asDrawable()
.load(it.result.getUrl(accountHost))
- .override(min(view.textSize.toInt(), 640))
+ .override(view.textSize.toInt())
.into(span.target)
builder.setSpan(span, it.start, it.end, 0)
}
@@ -52,12 +56,16 @@ class CustomEmojiDecorator {
val builder = SpannableStringBuilder(result.text)
result.emojis.filter {
- HostWithVersion.isOverV13(accountHost) || it.result is EmojiResolvedType.Resolved
+ it.result is EmojiResolvedType.Resolved
}.map {
- val span = DrawableEmojiSpan(emojiAdapter, it.result.getUrl(accountHost))
+ val span = DrawableEmojiSpan(
+ emojiAdapter,
+ it.result.getUrl(accountHost),
+ (it.result as? EmojiResolvedType.Resolved)?.emoji?.aspectRatio
+ )
GlideApp.with(view)
.asDrawable()
- .override(min(view.textSize.toInt(), 640))
+ .override(view.textSize.toInt())
.load(it.result.getUrl(accountHost))
.into(span.target)
builder.setSpan(span, it.start, it.end, 0)
@@ -67,21 +75,39 @@ class CustomEmojiDecorator {
return builder
}
- fun decorate(spanned: Spanned, accountHost: String?, result: CustomEmojiParsedResult, view: TextView): Spanned {
+ fun decorate(
+ spanned: Spanned,
+ accountHost: String?,
+ result: CustomEmojiParsedResult,
+ view: TextView,
+ customEmojiScale: Float = 1f,
+ ): Spanned {
val emojiAdapter = EmojiAdapter(view)
val builder = SpannableStringBuilder(spanned)
result.emojis.filter {
- HostWithVersion.isOverV13(accountHost) || it.result is EmojiResolvedType.Resolved
+ it.result is EmojiResolvedType.Resolved
}.map {
- val span = DrawableEmojiSpan(emojiAdapter, it.result.getUrl(accountHost))
+ val aspectRatio = (it.result as? EmojiResolvedType.Resolved)?.emoji?.aspectRatio
+ val span = DrawableEmojiSpan(
+ emojiAdapter,
+ it.result.getUrl(accountHost),
+ aspectRatio,
+ )
+ val height = max(view.textSize * 0.75f, 10f)
+ val width = when(aspectRatio) {
+ null -> height
+ else -> height * aspectRatio
+ }
+
GlideApp.with(view)
.asDrawable()
.load(it.result.getUrl(accountHost))
- .override(min(view.textSize.toInt(), 640))
+ .override((width * customEmojiScale).toInt(), (height * customEmojiScale).toInt())
.into(span.target)
builder.setSpan(span, it.start, it.end, 0)
+ builder.setSpan(RelativeSizeSpan(customEmojiScale), it.start, it.end, 0)
}
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DateFormatHelper.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DateFormatHelper.kt
index 9d9f8b5dcc..029ba181eb 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DateFormatHelper.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DateFormatHelper.kt
@@ -34,20 +34,28 @@ object DateFormatHelper {
- @BindingAdapter("elapsedTime")
+ @BindingAdapter("elapsedTime", "isDisplayTimestampsAsAbsoluteDates")
@JvmStatic
- fun TextView.setElapsedTime(elapsedTime: Instant?) {
+ fun TextView.setElapsedTime(elapsedTime: Instant?, isDisplayTimestampsAsAbsoluteDates: Boolean?) {
- this.text = GetElapsedTimeStringSource(
- SimpleElapsedTime(
- elapsedTime ?: Clock.System.now()
+ this.text = if (isDisplayTimestampsAsAbsoluteDates == true) {
+ SimpleDateFormat.getDateTimeInstance().format(
+ elapsedTime?.let {
+ Date(it.toEpochMilliseconds())
+ } ?: Date()
)
- ).getString(context)
+ } else {
+ GetElapsedTimeStringSource(
+ SimpleElapsedTime(
+ elapsedTime ?: Clock.System.now()
+ )
+ ).getString(context)
+ }
}
- @BindingAdapter("elapsedTime", "visibility")
+ @BindingAdapter("elapsedTime", "visibility", "isDisplayTimestampsAsAbsoluteDates")
@JvmStatic
- fun TextView.setElapsedTimeAndVisibility(elapsedTime: Instant?, visibility: Visibility?) {
+ fun TextView.setElapsedTimeAndVisibility(elapsedTime: Instant?, visibility: Visibility?, isDisplayTimestampsAsAbsoluteDates: Boolean?) {
val visibilityIcon = when(visibility ?: Visibility.Public(false)) {
is Visibility.Followers -> R.drawable.ic_lock_black_24dp
is Visibility.Home -> R.drawable.ic_home_black_24dp
@@ -57,11 +65,19 @@ object DateFormatHelper {
Visibility.Mutual -> R.drawable.ic_sync_alt_24px
Visibility.Personal -> R.drawable.ic_person_black_24dp
}
- val text = GetElapsedTimeStringSource(
- SimpleElapsedTime(
- elapsedTime ?: Clock.System.now()
+ val text = if (isDisplayTimestampsAsAbsoluteDates == true) {
+ SimpleDateFormat.getDateTimeInstance().format(
+ elapsedTime?.let {
+ Date(it.toEpochMilliseconds())
+ } ?: Date()
)
- ).getString(context)
+ } else {
+ GetElapsedTimeStringSource(
+ SimpleElapsedTime(
+ elapsedTime ?: Clock.System.now()
+ )
+ ).getString(context)
+ }
this.text = if (visibilityIcon == null) {
text
@@ -87,4 +103,37 @@ object DateFormatHelper {
val javaDate = Date(date.toEpochMilliseconds())
this.text = SimpleDateFormat.getDateTimeInstance().format(javaDate)
}
+
+ @BindingAdapter("createdAt", "visibility")
+ @JvmStatic
+ fun TextView.setCreatedAtWithVisibility(createdAt: Instant?, visibility: Visibility?) {
+ val date = createdAt ?: Clock.System.now()
+ val javaDate = Date(date.toEpochMilliseconds())
+ val visibilityIcon = when(visibility ?: Visibility.Public(false)) {
+ is Visibility.Followers -> R.drawable.ic_lock_black_24dp
+ is Visibility.Home -> R.drawable.ic_home_black_24dp
+ is Visibility.Public -> null
+ is Visibility.Specified -> R.drawable.ic_email_black_24dp
+ is Visibility.Limited -> R.drawable.ic_groups
+ Visibility.Mutual -> R.drawable.ic_sync_alt_24px
+ Visibility.Personal -> R.drawable.ic_person_black_24dp
+ }
+ val text = SimpleDateFormat.getDateTimeInstance().format(javaDate)
+
+ this.text = if (visibilityIcon == null) {
+ text
+ } else {
+ val target = "visibility $text"
+ SpannableStringBuilder(target).apply {
+ val drawable = ContextCompat.getDrawable(context, visibilityIcon)
+ drawable?.setTint(currentTextColor)
+ val span = DrawableEmojiSpan(EmojiAdapter(this@setCreatedAtWithVisibility), visibilityIcon)
+ setSpan(span, 0, "visibility".length,0)
+ GlideApp.with(this@setCreatedAtWithVisibility)
+ .load(drawable)
+ .override(min(textSize.toInt(), 640))
+ .into(span.target)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DrawableEmojiSpan.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DrawableEmojiSpan.kt
index a646bd97b3..ed29aa55b9 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DrawableEmojiSpan.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/DrawableEmojiSpan.kt
@@ -9,12 +9,15 @@ import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.github.penfeizhou.animation.apng.APNGDrawable
-class DrawableEmojiSpan(var adapter: EmojiAdapter?, k: Any?) : EmojiSpan(k){
+class DrawableEmojiSpan(
+ var adapter: EmojiAdapter?,
+ k: Any?,
+ aspectRatio: Float? = null,
+ emojiScale: Float = 1f,
+) : EmojiSpan(k, aspectRatio = aspectRatio, emojiScale = emojiScale) {
//val weakReference: WeakReference = WeakReference(view)
-
-
// /**
// * invalidateSelfによって呼び出されるコールバックを実装することによって
// * invalidateSelfが呼び出されたときに自信のview.invalidateを呼び出し再描画をする
@@ -74,11 +77,11 @@ class DrawableEmojiSpan(var adapter: EmojiAdapter?, k: Any?) : EmojiSpan(k
}
private class DrawableEmojiTarget(
- val span: DrawableEmojiSpan
+ val span: DrawableEmojiSpan,
) : CustomTarget() {
override fun onResourceReady(
resource: Drawable,
- transition: Transition?
+ transition: Transition?,
) {
span.imageDrawable = resource
@@ -118,6 +121,7 @@ private class DrawableEmojiTarget(
}
}
}
+
override fun onLoadCleared(placeholder: Drawable?) {
}
diff --git a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/EmojiSpan.kt b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/EmojiSpan.kt
index 7051004efd..4313e74d16 100644
--- a/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/EmojiSpan.kt
+++ b/modules/common_android/src/main/java/net/pantasystem/milktea/common_android/ui/text/EmojiSpan.kt
@@ -7,20 +7,26 @@ import android.text.TextPaint
import android.text.style.ReplacementSpan
import kotlin.math.min
-abstract class EmojiSpan(val key: T) : ReplacementSpan(){
+/**
+ * @param key 画像の種別を識別するためのキー値で、画像のURLなどが入る
+ * @param aspectRatio 画像の比率が入る
+ */
+abstract class EmojiSpan(val key: T, val aspectRatio: Float? = null, val emojiScale: Float = 1f) : ReplacementSpan(){
companion object {
+ /**
+ * 変数keyに対応するDrawableの画像サイズをここに保持している。
+ */
private val drawableSizeCache = mutableMapOf()
}
var imageDrawable: Drawable? = null
+
/**
- * imageDrawableにDrawableが代入されている時にupdateImageDrawableSizeが呼び出されるとここに絵文字のサイズが代入される。
- * 画像は縦横比が異なることがあるので、それぞれの高さが代入される。
+ * 文字サイズなどのスケールに応じて画像サイズをDrawableに反映したorしてないの状態
+ * 反映済みの場合はtrueが入り、そうでない場合はfalseが入る
*/
- private var textHeight: Int = 0
- private var textWidth: Int = 0
private var isSizeComputed = false
/**
@@ -37,54 +43,29 @@ abstract class EmojiSpan(val key: T) : ReplacementSpan(){
end: Int,
fm: Paint.FontMetricsInt?
): Int {
- val drawable = imageDrawable
- val size = key?.let {
- drawableSizeCache[key]
- } ?: drawable?.let {
- EmojiSizeCache(
- intrinsicHeight = it.intrinsicHeight,
- intrinsicWidth = it.intrinsicWidth
- )
- }
- key?.run {
- drawableSizeCache[key] ?: drawable?.let {
- EmojiSizeCache(
- intrinsicHeight = it.intrinsicHeight,
- intrinsicWidth = it.intrinsicWidth
- )
- }
- }
+ val textHeight = paint.textSize
+
+ val size = calculateEmojiSize(textHeight * emojiScale)
val metrics = paint.fontMetricsInt
if (fm != null) {
- fm.top = metrics.top
+ fm.top = metrics.top - (textHeight * emojiScale - textHeight).toInt()
fm.ascent = metrics.ascent
fm.descent = metrics.descent
fm.bottom = metrics.bottom
}
+ // NOTE: 画像のサイズが不明かつ初めてサイズを取得しようとした時は暫定的なサイズを返す
if (size == null || beforeTextSize != 0) {
- beforeTextSize = (paint.textSize * 1.2).toInt()
+ beforeTextSize = (paint.textSize * emojiScale).toInt()
return beforeTextSize
}
- key?.run {
- drawableSizeCache[key] = size
- }
+ // NOTE: 暫定的なサイズではない場合はbeforeTextSizeを0にする必要性がある
beforeTextSize = 0
- val textHeight = paint.textSize
- val imageWidth = size.intrinsicWidth
- val imageHeight = size.intrinsicHeight
-
- // 画像がテキストの高さよりも大きい場合、画像をテキストと同じ高さに縮小する
- val scale = if (imageHeight > textHeight) {
- textHeight / imageHeight.toFloat()
- } else {
- 1.0f
- }
+ val imageWidth = size.first
- // テキストの高さに合わせた画像の幅
- return (imageWidth * scale).toInt()
+ return imageWidth.toInt()
}
override fun updateDrawState(ds: TextPaint) {
@@ -118,43 +99,82 @@ abstract class EmojiSpan(val key: T) : ReplacementSpan(){
}
+ /**
+ * サイズが大きな画像をGPUのメモリに展開してしまうと、
+ * GPUに負荷がかかりフレーム落ちの原因につながる可能性があるので、
+ * Drawableのサイズを必要なサイズにリサイズを行う処理
+ */
private fun updateImageDrawableSize(paint: Paint) {
+ val emojiHeight = min((paint.textSize * emojiScale).toInt(), 128)
+ val size = calculateEmojiSize(min((paint.textSize * emojiScale), 128f))
+ val imageWidth = size?.first ?: -1f
+ val imageHeight = size?.second?: -1f
+
+ // 計算された画像サイズが適切なものかチェックする
+ val unknownEmojiSize = imageWidth <= 0 || imageHeight <= 0
+
+ // 画像サイズが暫定的なサイズかつ、暫定的なサイズと画像のサイズが一致しない場合は処理を終了する
+ if (beforeTextSize != 0 && beforeTextSize != emojiHeight || unknownEmojiSize) {
+ if (!isSizeComputed) {
+ beforeTextSize = emojiHeight
+ imageDrawable?.setBounds(0, 0, emojiHeight, emojiHeight)
+ isSizeComputed = imageDrawable != null
+ }
+ return
+ }
+
+ if (!isSizeComputed) {
+ isSizeComputed = imageDrawable != null
+ imageDrawable?.setBounds(0, 0, imageWidth.toInt(), imageHeight.toInt())
+ }
+ }
+
+ private fun calculateEmojiSize(textSize: Float): Pair? {
val drawable = imageDrawable
val size = key?.let {
drawableSizeCache[key]
} ?: drawable?.let {
+ // NOTE: drawableSizeCacheに画像のサイズが登録されていない場合は、drawableからサイズを取得する
EmojiSizeCache(
- intrinsicWidth = it.intrinsicWidth,
- intrinsicHeight = it.intrinsicHeight
+ intrinsicHeight = it.intrinsicHeight,
+ intrinsicWidth = it.intrinsicWidth
)
- } ?: return
+ } ?: aspectRatio?.let {
+ // NOTE: drawableが読み込まれていない状態の時は、文字の高さと画像の比率から横幅のサイズを取得する
+ EmojiSizeCache(
+ intrinsicHeight = textSize.toInt(),
+ intrinsicWidth = (textSize * aspectRatio).toInt()
+ )
+ }
+
+ // NOTE: keyが存在しかつdrawableが存在する場合は、drawableSizeCacheを更新する
+ key?.run {
+ drawableSizeCache[key] ?: drawable?.let {
+ EmojiSizeCache(
+ intrinsicHeight = it.intrinsicHeight,
+ intrinsicWidth = it.intrinsicWidth
+ )
+ }
+ }
+
+ // NOTE: 画像のサイズが不明なときはnullを返す
+ if (size == null) {
+ return null
+ }
key?.run {
drawableSizeCache[key] = size
}
+
val imageWidth = size.intrinsicWidth
val imageHeight = size.intrinsicHeight
- val emojiHeight = min((paint.textSize).toInt(), 640)
- val unknownEmojiSize = imageWidth <= 0 || imageHeight <= 0
- if (beforeTextSize != 0 && beforeTextSize != emojiHeight || unknownEmojiSize) {
- if (!isSizeComputed) {
- beforeTextSize = emojiHeight
- imageDrawable?.setBounds(0, 0, emojiHeight, emojiHeight)
- isSizeComputed = true
- }
- return
- }
-
- val ratio = imageWidth.toFloat() / imageHeight.toFloat()
+ // 画像がテキストの高さよりも大きい場合、画像をテキストと同じ高さに縮小する
+ val scale = textSize / imageHeight
- val scaledImageWidth = (emojiHeight * ratio).toInt()
+ // テキストの高さに合わせた画像の幅
+ val width = imageWidth * scale
- if (!isSizeComputed) {
- textHeight = emojiHeight
- textWidth = scaledImageWidth
- isSizeComputed = true
- imageDrawable?.setBounds(0, 0, scaledImageWidth, emojiHeight)
- }
+ return width to textSize
}
}
diff --git a/modules/common_android_ui/build.gradle b/modules/common_android_ui/build.gradle
index a6b79368d6..67730c85ff 100644
--- a/modules/common_android_ui/build.gradle
+++ b/modules/common_android_ui/build.gradle
@@ -98,5 +98,6 @@ dependencies {
implementation libs.coil.compose
testImplementation libs.junit.jupiter.api
testRuntimeOnly libs.junit.jupiter.engine
+ implementation libs.flexbox
}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/StringSourceHelper.kt b/modules/common_android_ui/src/main/java/StringSourceHelper.kt
new file mode 100644
index 0000000000..c8707804c9
--- /dev/null
+++ b/modules/common_android_ui/src/main/java/StringSourceHelper.kt
@@ -0,0 +1,8 @@
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import net.pantasystem.milktea.common_android.resource.StringSource
+
+@Composable
+fun getStringFromStringSource(src: StringSource): String {
+ return src.getString(LocalContext.current)
+}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/BindingProvider.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/BindingProvider.kt
index a944299219..a22785597b 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/BindingProvider.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/BindingProvider.kt
@@ -9,6 +9,7 @@ import net.pantasystem.milktea.app_store.setting.SettingStore
import net.pantasystem.milktea.common_navigation.MediaNavigation
import net.pantasystem.milktea.common_navigation.SearchNavigation
import net.pantasystem.milktea.common_navigation.UserDetailNavigation
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioStore
import net.pantasystem.milktea.model.emoji.CustomEmojiRepository
import net.pantasystem.milktea.model.instance.MetaRepository
import net.pantasystem.milktea.model.setting.ColorSettingStore
@@ -32,4 +33,6 @@ interface BindingProvider {
fun customEmojiRepository(): CustomEmojiRepository
fun colorSettingStore(): ColorSettingStore
+
+ fun customEmojiAspectRatioStore(): CustomEmojiAspectRatioStore
}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/DecorateTextHelper.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/DecorateTextHelper.kt
index f10b9d915f..648c63d488 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/DecorateTextHelper.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/DecorateTextHelper.kt
@@ -20,6 +20,7 @@ import net.pantasystem.milktea.common_android.mfm.MFMParser
import net.pantasystem.milktea.common_android.mfm.Root
import net.pantasystem.milktea.common_android.ui.text.CustomEmojiDecorator
import net.pantasystem.milktea.common_android.ui.text.DrawableEmojiSpan
+import net.pantasystem.milktea.common_navigation.SearchNavType
import net.pantasystem.milktea.common_navigation.UserDetailNavigationArgs
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.emoji.Emoji
@@ -70,20 +71,38 @@ object DecorateTextHelper {
}
}
- @BindingAdapter("textTypeSource")
+ @BindingAdapter("textTypeSource", "customEmojiScale")
@JvmStatic
- fun TextView.decorate(textType: TextType?) {
+ fun TextView.decorate(textType: TextType?, customEmojiScale: Float?) {
textType ?: return
stopDrawableAnimations(this)
+
+ val emojiScale = customEmojiScale ?: 1.0f
when (textType) {
is TextType.Mastodon -> {
- this.text = CustomEmojiDecorator().decorate(
+ val decoratedText = CustomEmojiDecorator().decorate(
textType.html.spanned,
textType.html.accountHost,
textType.html.parserResult,
- this
+ this,
+ emojiScale,
)
+ this.text = decoratedText
this.movementMethod = ClickListenableLinkMovementMethod { url ->
+
+ // NOTE: クリックしたURLを探している
+ val urlSpans = decoratedText.getSpans(0, decoratedText.length, URLSpan::class.java)
+ var textHashTag: CharSequence? = null
+ for (urlSpan in urlSpans) {
+ val start = decoratedText.getSpanStart(urlSpan)
+ val end = decoratedText.getSpanEnd(urlSpan)
+ val spannedText = decoratedText.subSequence(start, end)
+ if (spannedText.isNotEmpty() && spannedText[0] == '#') {
+ if (urlSpan.url == url) {
+ textHashTag = spannedText
+ }
+ }
+ }
val tag = textType.tags.firstOrNull {
it.url == url || it.url == url.lowercase()
}
@@ -98,9 +117,18 @@ object DecorateTextHelper {
)
when {
tag != null -> {
- // FIXME: タグの場合うまく動作しないケースがある
- // 原因としてTagオブジェクトに入っているURLとHTML上に表示されているURLが異なるから
- false
+ val intent = navigationEntryPoint.searchNavigation().newIntent(SearchNavType.ResultScreen(
+ searchWord = "#${tag.name}"
+ ))
+ context.startActivity(intent)
+ true
+ }
+ textHashTag != null -> {
+ val intent = navigationEntryPoint.searchNavigation().newIntent(SearchNavType.ResultScreen(
+ searchWord = textHashTag.toString()
+ ))
+ context.startActivity(intent)
+ true
}
mention != null -> {
val intent = navigationEntryPoint
@@ -116,7 +144,7 @@ object DecorateTextHelper {
}
is TextType.Misskey -> {
this.movementMethod = LinkMovementMethod.getInstance()
- this.text = MFMDecorator.decorate(this, textType.lazyDecorateResult)
+ this.text = MFMDecorator.decorate(this, textType.lazyDecorateResult, emojiScale)
}
}
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/MFMDecorator.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/MFMDecorator.kt
index 4998031cc7..dfcb9d6513 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/MFMDecorator.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/MFMDecorator.kt
@@ -5,22 +5,37 @@ import android.app.SearchManager
import android.content.Intent
import android.graphics.Color
import android.graphics.Typeface
-import android.graphics.drawable.Drawable
import android.net.Uri
-import android.text.*
-import android.text.style.*
+import android.text.Layout
+import android.text.SpannableString
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.SpannedString
+import android.text.style.AlignmentSpan
+import android.text.style.BackgroundColorSpan
+import android.text.style.ClickableSpan
+import android.text.style.ForegroundColorSpan
+import android.text.style.QuoteSpan
+import android.text.style.RelativeSizeSpan
+import android.text.style.StrikethroughSpan
+import android.text.style.StyleSpan
import android.util.Log
import android.view.View
import android.widget.TextView
-import com.bumptech.glide.load.DataSource
-import com.bumptech.glide.load.engine.GlideException
-import com.bumptech.glide.request.RequestListener
-import com.bumptech.glide.request.target.Target
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.internal.managers.FragmentComponentManager
-import jp.panta.misskeyandroidclient.mfm.*
+import jp.panta.misskeyandroidclient.mfm.EmojiElement
+import jp.panta.misskeyandroidclient.mfm.HashTag
+import jp.panta.misskeyandroidclient.mfm.Mention
+import jp.panta.misskeyandroidclient.mfm.Node
+import jp.panta.misskeyandroidclient.mfm.Search
+import jp.panta.misskeyandroidclient.mfm.Text
import net.pantasystem.milktea.common.glide.GlideApp
-import net.pantasystem.milktea.common_android.mfm.*
+import net.pantasystem.milktea.common_android.mfm.Element
+import net.pantasystem.milktea.common_android.mfm.ElementType
+import net.pantasystem.milktea.common_android.mfm.Leaf
+import net.pantasystem.milktea.common_android.mfm.Link
+import net.pantasystem.milktea.common_android.mfm.Root
import net.pantasystem.milktea.common_android.ui.Activities
import net.pantasystem.milktea.common_android.ui.putActivity
import net.pantasystem.milktea.common_android.ui.text.DrawableEmojiSpan
@@ -39,8 +54,8 @@ object MFMDecorator {
fun decorate(
textView: TextView,
lazyDecorateResult: LazyDecorateResult?,
+ customEmojiScale: Float = 1f,
skipEmojis: SkipEmojiHolder = SkipEmojiHolder(),
- retryCounter: Int = 0,
): Spanned? {
lazyDecorateResult ?: return null
val emojiAdapter = EmojiAdapter(textView)
@@ -51,7 +66,7 @@ object MFMDecorator {
lazyDecorateResult,
skipEmojis,
emojiAdapter,
- retryCounter,
+ customEmojiScale,
).decorate()
}
@@ -268,6 +283,15 @@ object MFMDecorator {
ElementType.SMALL -> {
setSpan(RelativeSizeSpan(0.6F))
}
+ ElementType.FnX2 -> {
+ setSpan(RelativeSizeSpan(2.0F))
+ }
+ ElementType.FnX3 -> {
+ setSpan(RelativeSizeSpan(3.0F))
+ }
+ ElementType.FnX4 -> {
+ setSpan(RelativeSizeSpan(4.0F))
+ }
ElementType.ROOT -> {
}
@@ -283,11 +307,11 @@ object MFMDecorator {
}
class LazyEmojiDecorator(
- val textView: WeakReference,
- val lazyDecorateResult: LazyDecorateResult,
- val skipEmojis: SkipEmojiHolder,
- val emojiAdapter: EmojiAdapter,
- val retryCounter: Int,
+ private val textView: WeakReference,
+ private val lazyDecorateResult: LazyDecorateResult,
+ private val skipEmojis: SkipEmojiHolder,
+ private val emojiAdapter: EmojiAdapter,
+ private val customEmojiScale: Float,
) {
private val spannableString = SpannableString(lazyDecorateResult.spanned)
@@ -308,44 +332,22 @@ object MFMDecorator {
return
}
textView.get()?.let { textView ->
- val emojiSpan = DrawableEmojiSpan(emojiAdapter, emojiElement.emoji.url)
+ val emojiSpan = DrawableEmojiSpan(emojiAdapter, emojiElement.emoji.url, emojiElement.emoji.aspectRatio)
spannableString.setSpan(emojiSpan, skippedEmoji.start, skippedEmoji.end, 0)
+ spannableString.setSpan(RelativeSizeSpan(customEmojiScale), skippedEmoji.start, skippedEmoji.end, 0)
+ val height = max(textView.textSize * 0.75f, 10f)
+ val width = when(val aspectRatio = emojiElement.emoji.aspectRatio) {
+ null -> height
+ else -> height * aspectRatio
+ }
GlideApp.with(textView)
- .load(emojiElement.emoji.url)
- .override(max(textView.textSize.toInt(), 10))
- .addListener(object : RequestListener {
- override fun onLoadFailed(
- e: GlideException?,
- model: Any?,
- target: Target?,
- isFirstResource: Boolean
- ): Boolean {
- val t = this@LazyEmojiDecorator.textView.get()
- if (t != null && !skipEmojis.contains(emojiElement.emoji) && t.getTag(R.id.TEXT_VIEW_MFM_TAG_ID) == lazyDecorateResult.sourceText) {
- if (retryCounter < 100) {
-
- t.text = decorate(
- t,
- lazyDecorateResult = lazyDecorateResult,
- skipEmojis = skipEmojis.add(emojiElement.emoji),
- retryCounter + 1
- )
- }
- }
-
- return false
- }
-
- override fun onResourceReady(
- resource: Drawable?,
- model: Any?,
- target: Target?,
- dataSource: DataSource?,
- isFirstResource: Boolean
- ): Boolean {
- return false
- }
- })
+ .load(emojiElement.emoji.cachePath)
+ .error(
+ GlideApp.with(textView)
+ .load(emojiElement.emoji.url ?: emojiElement.emoji.uri)
+ .override((width * customEmojiScale).toInt(), (height * customEmojiScale).toInt())
+ )
+ .override((width * customEmojiScale).toInt(), (height * customEmojiScale).toInt())
.into(emojiSpan.target)
}
}
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/ReactionViewHelper.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/ReactionViewHelper.kt
index 41cdceb0ac..2405b975e0 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/ReactionViewHelper.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/ReactionViewHelper.kt
@@ -83,9 +83,20 @@ object ReactionViewHelper {
if (emoji != null) {
//Log.d("ReactionViewHelper", "カスタム絵文字を発見した: ${emoji}")
- GlideApp.with(reactionImageView.context)
- .load(emoji.url ?: emoji.uri)
- .into(reactionImageView)
+ if (emoji.cachePath == null) {
+ GlideApp.with(reactionImageView.context)
+ .load(emoji.url ?: emoji.uri)
+ .into(reactionImageView)
+ } else {
+ GlideApp.with(reactionImageView.context)
+ .load(emoji.cachePath)
+ .error(
+ GlideApp.with(reactionImageView.context)
+ .load(emoji.url ?: emoji.uri)
+ )
+ .into(reactionImageView)
+ }
+
reactionImageView.setMemoVisibility(View.VISIBLE)
reactionStringView.setMemoVisibility(View.GONE)
return
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/TextType.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/TextType.kt
index 8c321c28b8..116b182efa 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/TextType.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/TextType.kt
@@ -36,7 +36,7 @@ fun getTextType(account: Account, note: NoteRelation, instanceEmojis: Map {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
note.note.text?.let {
val option = note.note.type as? Note.Type.Mastodon
TextType.Mastodon(
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/page/PageTypeHelper.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/page/PageTypeHelper.kt
index 5f378889de..6e17c7e309 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/page/PageTypeHelper.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/page/PageTypeHelper.kt
@@ -36,12 +36,14 @@ object PageTypeHelper{
MASTODON_LOCAL_TIMELINE -> context.getString(R.string.local_timeline)
MASTODON_PUBLIC_TIMELINE -> context.getString(R.string.global_timeline)
MASTODON_HOME_TIMELINE -> context.getString(R.string.home_timeline)
- MASTODON_HASHTAG_TIMELINE -> context.getString(R.string.tag)
MASTODON_LIST_TIMELINE -> context.getString(R.string.list)
MASTODON_USER_TIMELINE -> context.getString(R.string.user)
CALCKEY_RECOMMENDED_TIMELINE -> context.getString(R.string.calckey_recomended_timeline)
CLIP_NOTES -> context.getString(R.string.clip)
MASTODON_BOOKMARK_TIMELINE -> context.getString(R.string.bookmark)
+ MASTODON_SEARCH_TIMELINE -> context.getString(R.string.search)
+ MASTODON_TAG_TIMELINE -> context.getString(R.string.tag)
+ MASTODON_TREND_TIMELINE -> context.getString(R.string.featured)
}
}
}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModel.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModel.kt
index b49b3ab73a..18dee58253 100644
--- a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModel.kt
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModel.kt
@@ -15,7 +15,6 @@ import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.account.SignOutUseCase
import net.pantasystem.milktea.model.account.page.Page
import net.pantasystem.milktea.model.instance.InstanceInfoService
-import net.pantasystem.milktea.model.instance.InstanceInfoType
import net.pantasystem.milktea.model.instance.SyncMetaExecutor
import net.pantasystem.milktea.model.user.User
import net.pantasystem.milktea.model.user.UserDataSource
@@ -26,69 +25,28 @@ import javax.inject.Inject
@Suppress("UNCHECKED_CAST")
@HiltViewModel
class AccountViewModel @Inject constructor(
+ loggerFactory: Logger.Factory,
+ instanceInfoService: InstanceInfoService,
private val accountStore: AccountStore,
private val userDataSource: UserDataSource,
- loggerFactory: Logger.Factory,
private val userRepository: UserRepository,
- private val instanceInfoService: InstanceInfoService,
private val signOutUseCase: SignOutUseCase,
private val syncMetaExecutor: SyncMetaExecutor,
) : ViewModel() {
-
private val logger = loggerFactory.create("AccountViewModel")
- private val users = accountStore.observeAccounts.flatMapLatest { accounts ->
- val flows = accounts.map {
- userDataSource.observe(User.Id(it.accountId, it.remoteId)).flowOn(Dispatchers.IO)
- }
- combine(flows) {
- it.toList()
- }
- }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
-
- private val metaList = accountStore.observeAccounts.flatMapLatest { accounts ->
- val flows = accounts.map {
- instanceInfoService.observe(it.normalizedInstanceUri).flowOn(Dispatchers.IO)
- }
- combine(flows) {
- it.toList()
- }
- }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
-
- private val accountWithUserList = combine(
- accountStore.observeAccounts,
- users,
+ private val uiStateHelper = AccountViewModelUiStateHelper(
accountStore.observeCurrentAccount,
- metaList,
- ) { accounts, users, current, metaList ->
- val userMap = users.associateBy {
- it.id.accountId
- }
- val metaMap = metaList.filterNotNull().associateBy {
- it.uri
- }
- accounts.map {
- AccountInfo(
- it,
- userMap[it.accountId],
- metaMap[it.normalizedInstanceUri],
- current?.accountId == it.accountId
- )
- }
- }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
+ accountStore,
+ userDataSource,
+ instanceInfoService,
+ viewModelScope
+ )
- val uiState = combine(
- accountStore.observeCurrentAccount,
- accountWithUserList
- ) { current, accounts ->
- AccountViewModelUiState(
- currentAccount = current,
- accounts = accounts
- )
- }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), AccountViewModelUiState())
+ val uiState = uiStateHelper.uiState
val currentAccount =
accountStore.observeCurrentAccount.stateIn(viewModelScope, SharingStarted.Lazily, null)
@@ -96,19 +54,35 @@ class AccountViewModel @Inject constructor(
userDataSource.observe(User.Id(account.accountId, account.remoteId)).map {
it as? User.Detail
}
- }.flowOn(Dispatchers.IO).stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
+ }.flowOn(Dispatchers.IO).stateIn(
+ viewModelScope,
+ SharingStarted.WhileSubscribed(5_000),
+ null,
+ )
- private val _switchAccountEvent = MutableSharedFlow(extraBufferCapacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val _switchAccountEvent = MutableSharedFlow(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
val switchAccountEvent = _switchAccountEvent.asSharedFlow()
- private val _showFollowersEvent = MutableSharedFlow(extraBufferCapacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val _showFollowersEvent = MutableSharedFlow(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
val showFollowersEvent = _showFollowersEvent.asSharedFlow()
- private val _showFollowingsEvent = MutableSharedFlow(extraBufferCapacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val _showFollowingsEvent = MutableSharedFlow(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
val showFollowingsEvent = _showFollowingsEvent.asSharedFlow()
- private val _showProfileEvent = MutableSharedFlow(extraBufferCapacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val _showProfileEvent = MutableSharedFlow(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
val showProfileEvent = _showProfileEvent.asSharedFlow()
@@ -172,32 +146,6 @@ class AccountViewModel @Inject constructor(
}
}
- fun removePage(page: Page) {
- viewModelScope.launch {
- try {
- accountStore.removePage(page)
- } catch (e: Throwable) {
- logger.error("pageの削除に失敗", e = e)
- }
- }
- }
}
-data class AccountInfo(
- val account: Account,
- val user: User?,
- val instanceMeta: InstanceInfoType?,
- val isCurrentAccount: Boolean
-)
-
-data class AccountViewModelUiState(
- val currentAccount: Account? = null,
- val accounts: List = emptyList(),
-) {
- val currentAccountInfo: AccountInfo? by lazy {
- accounts.firstOrNull {
- it.account.accountId == currentAccount?.accountId
- }
- }
-}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModelUiState.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModelUiState.kt
new file mode 100644
index 0000000000..116357272f
--- /dev/null
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModelUiState.kt
@@ -0,0 +1,44 @@
+package net.pantasystem.milktea.common_android_ui.account.viewmodel
+
+import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.instance.InstanceInfoType
+import net.pantasystem.milktea.model.user.User
+
+data class AccountInfo(
+ val account: Account,
+ val user: User?,
+ val instanceMeta: InstanceInfoType?,
+ val isCurrentAccount: Boolean,
+)
+
+data class AccountViewModelUiState(
+ val currentAccount: Account? = null,
+ val accounts: List = emptyList(),
+) {
+ val currentAccountInfo: AccountInfo? by lazy {
+ accounts.firstOrNull {
+ it.account.accountId == currentAccount?.accountId
+ }
+ }
+}
+
+fun List.toAccountInfoList(
+ currentAccount: Account?,
+ instanceInfoList: List,
+ users: List,
+): List {
+ val userMap = users.associateBy {
+ it.id.accountId
+ }
+ val metaMap = instanceInfoList.filterNotNull().associateBy {
+ it.uri
+ }
+ return map {
+ AccountInfo(
+ it,
+ userMap[it.accountId],
+ metaMap[it.normalizedInstanceUri],
+ currentAccount?.accountId == it.accountId
+ )
+ }
+}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModelUiStateHelper.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModelUiStateHelper.kt
new file mode 100644
index 0000000000..57ceec9f2d
--- /dev/null
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/account/viewmodel/AccountViewModelUiStateHelper.kt
@@ -0,0 +1,60 @@
+package net.pantasystem.milktea.common_android_ui.account.viewmodel
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.*
+import net.pantasystem.milktea.app_store.account.AccountStore
+import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.instance.InstanceInfoService
+import net.pantasystem.milktea.model.user.User
+import net.pantasystem.milktea.model.user.UserDataSource
+
+class AccountViewModelUiStateHelper(
+ currentAccountFlow: Flow,
+ accountStore: AccountStore,
+ private val userDataSource: UserDataSource,
+ private val instanceInfoService: InstanceInfoService,
+ viewModelScope: CoroutineScope,
+) {
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private val users = accountStore.observeAccounts.flatMapLatest { accounts ->
+ val flows = accounts.map {
+ userDataSource.observe(User.Id(it.accountId, it.remoteId)).flowOn(Dispatchers.IO)
+ }
+ combine(flows) {
+ it.toList()
+ }
+ }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private val metaList = accountStore.observeAccounts.flatMapLatest { accounts ->
+ val flows = accounts.map {
+ instanceInfoService.observe(it.normalizedInstanceUri).flowOn(Dispatchers.IO)
+ }
+ combine(flows) {
+ it.toList()
+ }
+ }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
+
+ private val accountWithUserList = combine(
+ accountStore.observeAccounts,
+ users,
+ currentAccountFlow,
+ metaList,
+ ) { accounts, users, current, metaList ->
+ accounts.toAccountInfoList(current, metaList, users)
+ }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
+
+ val uiState = combine(
+ currentAccountFlow,
+ accountWithUserList
+ ) { current, accounts ->
+ AccountViewModelUiState(
+ currentAccount = current,
+ accounts = accounts
+ )
+ }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), AccountViewModelUiState())
+
+}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/tab/TabViewCompositeClickListener.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/tab/TabViewCompositeClickListener.kt
new file mode 100644
index 0000000000..3fa171f83f
--- /dev/null
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/tab/TabViewCompositeClickListener.kt
@@ -0,0 +1,32 @@
+package net.pantasystem.milktea.common_android_ui.tab
+
+
+import com.google.android.material.tabs.TabLayout
+import java.util.*
+
+class TabViewCompositeClickListener(private val mTabLayout: TabLayout) {
+
+ private val listeners: MutableList<(tab: TabLayout.Tab, position: Int) -> Unit> = ArrayList()
+
+ fun addListener(listener: (tab: TabLayout.Tab, position: Int) -> Unit) {
+ listeners.add(listener)
+ }
+
+ fun removeListener(listener: (tab: TabLayout.Tab, position: Int) -> Unit) {
+ listeners.remove(listener)
+ }
+
+ fun build() {
+ for (i in 0 until mTabLayout.tabCount) {
+ mTabLayout.getTabAt(i)!!.view.setOnClickListener {
+ for (listener in listeners) {
+ listener(mTabLayout.getTabAt(i)!!, i)
+ }
+ }
+ }
+ }
+
+ fun getListeners(): List<(tab: TabLayout.Tab, position: Int) -> Unit> {
+ return listeners
+ }
+}
\ No newline at end of file
diff --git a/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/tab/TabbedFlexboxListMediator.kt b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/tab/TabbedFlexboxListMediator.kt
new file mode 100644
index 0000000000..9ecdca03c1
--- /dev/null
+++ b/modules/common_android_ui/src/main/java/net/pantasystem/milktea/common_android_ui/tab/TabbedFlexboxListMediator.kt
@@ -0,0 +1,240 @@
+package net.pantasystem.milktea.common_android_ui.tab
+
+
+import androidx.recyclerview.widget.LinearSmoothScroller
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.SmoothScroller
+import com.google.android.flexbox.FlexboxLayoutManager
+import com.google.android.material.tabs.TabLayout
+import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
+
+/**
+ * This class is made to provide the ability to sync between RecyclerView's specific items with
+ * TabLayout tabs.
+ *
+ * @param mRecyclerView The RecyclerView that is going to be synced with the TabLayout
+ * @param mTabLayout The TabLayout that is going to be synced with the RecyclerView specific
+ * items.
+ * @param mIndices The indices of the RecyclerView's items that is going to be playing a
+ * role of "check points" for the syncing operation.
+ * @param mIsSmoothScroll Defines the ability of smooth scroll when clicking the tabs of the
+ * TabLayout.
+ */
+class TabbedFlexboxListMediator(
+ private val mRecyclerView: RecyclerView,
+ private val mTabLayout: TabLayout,
+ private var mIndices: List,
+ private var mIsSmoothScroll: Boolean = false
+) {
+
+ private var mIsAttached = false
+
+ private var mRecyclerState = RecyclerView.SCROLL_STATE_IDLE
+ private var mTabClickFlag = false
+
+ private val smoothScroller: SmoothScroller =
+ object : LinearSmoothScroller(mRecyclerView.context) {
+ override fun getVerticalSnapPreference(): Int {
+ return SNAP_TO_START
+ }
+ }
+
+ private var tabViewCompositeClickListener: TabViewCompositeClickListener =
+ TabViewCompositeClickListener(mTabLayout)
+
+ /**
+ * Calling this method will ensure that the data that has been provided to the mediator is
+ * valid for use, and start syncing between the the RecyclerView and the TabLayout.
+ *
+ * Call this method when you have:
+ * 1- provided a RecyclerView Adapter,
+ * 2- provided a TabLayout with the appropriate number of tabs,
+ * 3- provided indices of the recyclerview items that you are syncing the tabs with. (You
+ * need to be providing indices of at most the number of Tabs inflated in the TabLayout.)
+ */
+ fun attach() {
+ mRecyclerView.adapter
+ ?: throw RuntimeException("Cannot attach with no Adapter provided to RecyclerView")
+
+ if (mTabLayout.tabCount == 0)
+ throw RuntimeException("Cannot attach with no tabs provided to TabLayout")
+
+ if (mIndices.size > mTabLayout.tabCount)
+ throw RuntimeException("Cannot attach using more indices than the available tabs")
+
+ notifyIndicesChanged()
+ mIsAttached = true
+ }
+
+ /**
+ * Calling this method will ensure to stop the synchronization between the RecyclerView and
+ * the TabLayout.
+ */
+
+ fun detach() {
+ clearListeners()
+ mIsAttached = false
+ }
+
+ /**
+ * This method will ensure that the synchronization is up-to-date with the data provided.
+ */
+ private fun reAttach() {
+ detach()
+ attach()
+ }
+
+ /**
+ * Calling this method will
+ */
+ fun updateMediatorWithNewIndices(newIndices: List): TabbedFlexboxListMediator {
+ mIndices = newIndices
+
+ if (mIsAttached) {
+ reAttach()
+ }
+
+ return this
+ }
+
+ /**
+ * This method will ensure that any listeners that have been added by the mediator will be
+ * removed, including the one listener from
+ * @see TabbedListMediator#addOnViewOfTabClickListener((TabLayout.Tab, int) -> Unit)
+ */
+
+ private fun clearListeners() {
+ mRecyclerView.clearOnScrollListeners()
+ for (i in 0 until mTabLayout.tabCount) {
+ mTabLayout.getTabAt(i)!!.view.setOnClickListener(null)
+ }
+ for (i in tabViewCompositeClickListener.getListeners().indices) {
+ tabViewCompositeClickListener.getListeners().toMutableList().removeAt(i)
+ }
+ mTabLayout.removeOnTabSelectedListener(onTabSelectedListener)
+ mRecyclerView.removeOnScrollListener(onScrollListener)
+ }
+
+ /**
+ * This method will attach the listeners required to make the synchronization possible.
+ */
+
+ private fun notifyIndicesChanged() {
+ tabViewCompositeClickListener.addListener { _, _ -> mTabClickFlag = true }
+ tabViewCompositeClickListener.build()
+ mTabLayout.addOnTabSelectedListener(onTabSelectedListener)
+ mRecyclerView.addOnScrollListener(onScrollListener)
+ }
+
+ private val onTabSelectedListener = object : OnTabSelectedListener {
+ override fun onTabSelected(tab: TabLayout.Tab) {
+
+ if (!mTabClickFlag) return
+
+ val position = tab.position
+
+ if (mIsSmoothScroll) {
+ smoothScroller.targetPosition = mIndices[position]
+ mRecyclerView.layoutManager?.startSmoothScroll(smoothScroller)
+ } else {
+// (mRecyclerView.layoutManager as FlexboxLayoutManager?)?.scrollToPositionWithOffset(
+// mIndices[position],
+// 0
+// )
+ (mRecyclerView.layoutManager as FlexboxLayoutManager?)?.scrollToPosition(mIndices[position])
+ mTabClickFlag = false
+ }
+ }
+
+ override fun onTabUnselected(tab: TabLayout.Tab) {}
+ override fun onTabReselected(tab: TabLayout.Tab) {}
+ }
+
+ private val onScrollListener = object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ mRecyclerState = newState
+ if (mIsSmoothScroll && newState == RecyclerView.SCROLL_STATE_IDLE) {
+ mTabClickFlag = false
+ }
+ }
+
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ super.onScrolled(recyclerView, dx, dy)
+ if (mTabClickFlag) {
+ return
+ }
+
+ val flexboxLayoutManager: FlexboxLayoutManager =
+ recyclerView.layoutManager as FlexboxLayoutManager?
+ ?: throw RuntimeException("No FlexboxLayoutManager attached to the RecyclerView.")
+
+ var itemPosition =
+ flexboxLayoutManager.findFirstCompletelyVisibleItemPosition()
+
+ if (itemPosition == -1) {
+ itemPosition =
+ flexboxLayoutManager.findFirstVisibleItemPosition()
+ }
+
+ if (mRecyclerState == RecyclerView.SCROLL_STATE_DRAGGING
+ || mRecyclerState == RecyclerView.SCROLL_STATE_SETTLING
+ ) {
+ for (i in mIndices.indices) {
+ if (itemPosition == mIndices[i]) {
+ if (!mTabLayout.getTabAt(i)!!.isSelected) {
+ mTabLayout.getTabAt(i)!!.select()
+ }
+ if (flexboxLayoutManager.findLastCompletelyVisibleItemPosition() == mIndices[mIndices.size - 1]) {
+ if (!mTabLayout.getTabAt(mIndices.size - 1)!!.isSelected) {
+ mTabLayout.getTabAt(mIndices.size - 1)!!.select()
+ }
+ return
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the state of the mediator, either attached or not.
+ */
+
+ fun isAttached(): Boolean {
+ return mIsAttached
+ }
+
+ /**
+ * @return the state of the mediator, is smooth scrolling or not.
+ */
+
+ fun isSmoothScroll(): Boolean {
+ return mIsSmoothScroll
+ }
+
+ /**
+ * @param smooth sets up the mediator with smooth scrolling
+ */
+
+ fun setSmoothScroll(smooth: Boolean) {
+ mIsSmoothScroll = smooth
+ }
+
+ /**
+ * @param listener the listener the will applied on "the view" of the tab. This method is useful
+ * when attaching a click listener on the tabs of the TabLayout.
+ * Note that this method is REQUIRED in case of the need of adding a click listener on the view
+ * of a tab layout. Since the mediator uses a click flag @see TabbedListMediator#mTabClickFlag
+ * it's taking the place of the normal on click listener, and thus the need of the composite click
+ * listener pattern, so adding listeners should be done using this method.
+ */
+
+ fun addOnViewOfTabClickListener(
+ listener: (tab: TabLayout.Tab, position: Int) -> Unit
+ ) {
+ tabViewCompositeClickListener.addListener(listener)
+ if (mIsAttached) {
+ notifyIndicesChanged()
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/common_compose/src/main/res/values-ja-rJP/strings.xml b/modules/common_compose/src/main/res/values-ja-rJP/strings.xml
index 45f1e7dce2..ff2a96983f 100644
--- a/modules/common_compose/src/main/res/values-ja-rJP/strings.xml
+++ b/modules/common_compose/src/main/res/values-ja-rJP/strings.xml
@@ -15,4 +15,6 @@
秒前
ファイル名を変更
キャプションを編集
+ インスタンス
+ %d人がオンライン
\ No newline at end of file
diff --git a/modules/common_compose/src/main/res/values-zh/strings.xml b/modules/common_compose/src/main/res/values-zh/strings.xml
index f7be2b65d8..70e668a0bc 100644
--- a/modules/common_compose/src/main/res/values-zh/strings.xml
+++ b/modules/common_compose/src/main/res/values-zh/strings.xml
@@ -15,4 +15,6 @@
秒
重新命名文件
编辑标题
+ Instance
+ %d poeple online
\ No newline at end of file
diff --git a/modules/common_compose/src/main/res/values/strings.xml b/modules/common_compose/src/main/res/values/strings.xml
index 1d6e3fb0d4..e5b8a0e579 100644
--- a/modules/common_compose/src/main/res/values/strings.xml
+++ b/modules/common_compose/src/main/res/values/strings.xml
@@ -16,4 +16,6 @@
S
Edit name
Edit caption
+ Instance
+ %d poeple online
\ No newline at end of file
diff --git a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/AntennaNavigation.kt b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/AntennaNavigation.kt
index 97ce3c9aed..c1cee00a69 100644
--- a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/AntennaNavigation.kt
+++ b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/AntennaNavigation.kt
@@ -1,4 +1,9 @@
package net.pantasystem.milktea.common_navigation
-interface AntennaNavigation : ActivityNavigation {
-}
\ No newline at end of file
+interface AntennaNavigation : ActivityNavigation {
+}
+
+data class AntennaNavigationArgs(
+ val specifiedAccountId: Long? = null,
+ val addTabToAccountId: Long? = null,
+)
\ No newline at end of file
diff --git a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ChannelNavigation.kt b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ChannelNavigation.kt
index 21ac8749d6..7dc2ce54be 100644
--- a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ChannelNavigation.kt
+++ b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ChannelNavigation.kt
@@ -2,6 +2,10 @@ package net.pantasystem.milktea.common_navigation
import net.pantasystem.milktea.model.channel.Channel
-interface ChannelNavigation : ActivityNavigation
+interface ChannelNavigation : ActivityNavigation
+data class ChannelNavigationArgs(
+ val specifiedAccountId: Long? = null,
+ val addTabToAccountId: Long? = null,
+)
interface ChannelDetailNavigation : ActivityNavigation
\ No newline at end of file
diff --git a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ClipNavigation.kt b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ClipNavigation.kt
index 4af8083901..efcbac65c1 100644
--- a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ClipNavigation.kt
+++ b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/ClipNavigation.kt
@@ -6,7 +6,8 @@ interface ClipListNavigation : ActivityNavigation
data class ClipListNavigationArgs(
val accountId: Long? = null,
- val mode: Mode = Mode.View
+ val mode: Mode = Mode.View,
+ val addTabToAccountId: Long? = null,
) {
enum class Mode {
AddToTab,
diff --git a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchAndSelectUserNavigation.kt b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchAndSelectUserNavigation.kt
index 7f27a22fda..997aa856f9 100644
--- a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchAndSelectUserNavigation.kt
+++ b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchAndSelectUserNavigation.kt
@@ -18,7 +18,8 @@ interface SearchAndSelectUserNavigation : ActivityNavigation = emptyList()
+ val selectedUserIds: List = emptyList(),
+ val accountId: Long? = null,
)
data class ChangedDiffResult(
diff --git a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchNavigation.kt b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchNavigation.kt
index bfb073938b..f6e4a7a061 100644
--- a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchNavigation.kt
+++ b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/SearchNavigation.kt
@@ -4,7 +4,17 @@ interface SearchNavigation : ActivityNavigation
sealed interface SearchNavType {
val searchWord: String?
- data class ResultScreen(override val searchWord: String) : SearchNavType
- data class SearchScreen(override val searchWord: String? = null) : SearchNavType
+ val acct: String?
+ val accountId: Long?
+
+ data class ResultScreen(
+ override val searchWord: String, override val acct: String? = null,
+ override val accountId: Long? = null,
+ ) : SearchNavType
+
+ data class SearchScreen(
+ override val searchWord: String? = null, override val acct: String? = null,
+ override val accountId: Long? = null,
+ ) : SearchNavType
}
\ No newline at end of file
diff --git a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/UserListNavigation.kt b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/UserListNavigation.kt
index 060bbbf682..6733b25e02 100644
--- a/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/UserListNavigation.kt
+++ b/modules/common_navigation/src/main/java/net/pantasystem/milktea/common_navigation/UserListNavigation.kt
@@ -4,4 +4,8 @@ import net.pantasystem.milktea.model.user.User
interface UserListNavigation : ActivityNavigation
-data class UserListArgs(val userId: User.Id? = null)
\ No newline at end of file
+data class UserListArgs(
+ val userId: User.Id? = null,
+ val specifiedAccountId: Long? = null,
+ val addTabToAccountId: Long? = null,
+)
\ No newline at end of file
diff --git a/modules/common_resource/src/main/res/menu/activity_user_menu.xml b/modules/common_resource/src/main/res/menu/activity_user_menu.xml
index 79be38839e..491a0b5d4a 100644
--- a/modules/common_resource/src/main/res/menu/activity_user_menu.xml
+++ b/modules/common_resource/src/main/res/menu/activity_user_menu.xml
@@ -2,6 +2,10 @@
ダーク
パンケーキ
+ ダーク(🐘)
+
MediaActivity
Dummy Button
DUMMY\nCONTENT
- 回覧注意
+ 閲覧注意
サムネイル
メディアを再生する
@@ -237,7 +239,7 @@
編集
削除
- タブ名を編集
+ タブを編集
タイムラインをバックグラウンドで更新する(消費電力大)
%sさんにフォローリクエストが承認されました
@@ -267,7 +269,7 @@
成功しました
失敗しました
- Explore Fediverse
+ Fediverse
見つける
人気ユーザー
最近投稿したユーザー
@@ -338,7 +340,7 @@
説明
画像を選択
ドライブから画像を選択
- 端末から画像を選択
+ ドライブから画像を選択
ノートの作成に成功しました
センシティブ
@@ -457,6 +459,12 @@
リノート非表示ユーザ
ブックマーク
+ FediverseライフにMilkteaはいかが?
+ 寄付
+ プライバシーポリシー
+ 利用規約
+
+
アプリケーション名
Milktea
@@ -565,6 +573,10 @@
自動更新を有効にする
ログインしてください
ファイルが添付されたノートのみ表示する
+ Milkteaについて
+ ソースコード(GitHub)
+ 絵文字ピッカー
+ 絵文字の表示サイズ
@@ -582,6 +594,21 @@
無期限
リモートで表示
フォローされています
+ ノートコンテンツ文字サイズ(%fsp)
+ ノートヘッダー文字サイズ(%fsp)
+ ノートリアクション件数表示の絵文字および文字サイズ(%fsp, %fps)
+ ノートの本文中のカスタム絵文字の倍率(%f倍)
+ おすすめユーザ
+ %d人が投稿
+ 引用として添付しますか?
+ 下書き投稿を選択
+ スクロール位置を保持する
+ 投稿のみ
+ タイムスタンプを絶対表示にする
+ キャッシュ設定
+ ノートのキャッシュ
+ カスタム絵文字のキャッシュ
+ ここにファイルを移動
diff --git a/modules/common_resource/src/main/res/values-zh/strings.xml b/modules/common_resource/src/main/res/values-zh/strings.xml
index 7bd408d7b3..3e541a09dc 100644
--- a/modules/common_resource/src/main/res/values-zh/strings.xml
+++ b/modules/common_resource/src/main/res/values-zh/strings.xml
@@ -8,7 +8,7 @@
设置
主页
- 相册
+ 图库
幻灯片放映
工具
分享
@@ -16,8 +16,8 @@
搜索
通知
消息
- 用户身份验证
- 选中的实例
+ 登陆
+ 选择的实例
关注中
@@ -29,7 +29,6 @@
自定义表情
设置
-
默认回复行为
@@ -44,8 +43,8 @@
选项卡设置
添加搜索
保存设置
- 已添加
- 从下方添加
+ 已选中
+ 可选
热门
@@ -69,9 +68,9 @@
媒体
关注
- 在时间线上显示本地转帖
- 在时间线上显示被转帖的帖子
- 在时间线上显示你的转帖
+ 显示本地转发
+ 显示被转发的帖子
+ 显示你的转发
自动加载时间线
时间线
@@ -79,7 +78,7 @@
即使实例停止也自动加载时间轴
同步
- 同步中
+ 同步
删除帖子
隐藏已删除的帖子
@@ -90,6 +89,7 @@
黑色
暗色
薄饼
+ 大象暗色
媒体活动
虚拟按钮
@@ -108,7 +108,7 @@
被 %s 提及
被 %s 回应
被 %s 转帖
- 收到来自 %s 的关注请求
+ 来自 %s 的关注请求
投票结束
有什么新鲜事?
@@ -235,7 +235,7 @@
在后台更新时间线
- 编辑选项卡名称
+ 编辑选项卡名称
关注请求已被 %s 接受
确认删除
@@ -316,9 +316,9 @@
本地
添加用户列表
编辑帖文
- 相册收藏按钮
+ 图库收藏按钮
流行趋势
- 相册
+ 图库
我的帖文
我喜欢的
WebSocket 错误
@@ -326,7 +326,7 @@
已连接
关闭中…
已关闭
- 创建相册
+ 创建图库
标题
描述
选择图片
@@ -394,8 +394,8 @@
已成功创建计划帖子
帐户
切换帐号
- 静音线程
- 取消静音线程
+ 屏蔽帖子列表
+ 取消屏蔽帖子列表
@@ -403,21 +403,21 @@
编辑标题
输入标题
- 帖子和回复
+ 帖子与回复
其他
最近使用
- %1$d个字符
+ %1$d 个字符
%1$d 个文件
投票
删除书签
- 添加到书签
- 自我限制
- 圆圈
+ 添加书签
+ 仅自己
+ 限制
相互关注
推荐的
被 %s 收藏
- 发布者 %s
- 夹子
+ 由 %s 发布
+ 便签
服务器错误
你是人类吗?
@@ -429,11 +429,11 @@
显示更多反应
从设备中选择文件
不能附加超过 %d 个文件
- 报名
+ 注册
让我们从Milktea开始Misskey
- 报名
+ 注册
登入
- 找服务器
+ 寻找服务器
下一个
注册屏幕将出现在您的浏览器中
在笔记中显示水平分隔线
@@ -449,11 +449,17 @@
点击加载图片
按照要求
无内容
- Mute Renotes
- Unmute renotes
- 远程静音
+ 屏蔽转发
+ 取消屏蔽转发
+ 转发屏蔽
书签
+ 你想要带有联邦宇宙的Milktea吗?
+ 捐款
+ 隐私政策
+ 服务条款
+
+
应用名称
Milktea
成功创建应用
@@ -464,7 +470,7 @@
实例 URL
https://
正在等待您的同意
- 已同意的
+ 已同意
正在等待同意
验证 URL
将身份验证 URL 复制到剪贴板。
@@ -473,7 +479,7 @@
使用 WebView 打开
我同意服务条款
我同意隐私政策
- 我明白Mastodon相关的功能仍处于alpha阶段,可能存在尚未实现或无法工作的功能,我同意不对开发人员负责
+ 我明白Mastodon相关的功能仍处于alpha阶段,可能存在尚未实现或无法工作的功能,我同意不让开发人员负责。
%d 人
@@ -496,8 +502,8 @@
敏感内容
选择图片
- 从设备中选取图片
- 从网盘中选取图片
+ 从设备中选取
+ 从网盘中选取
@@ -524,7 +530,7 @@
超时
重新认证
- 展開
+ 展开
%1$s 不允许大于 %2$s 的附件。要继续吗?
取消附件
继续
@@ -541,40 +547,60 @@
没有通知
- Mark as all read notifications
+ 标记所有通知为已读
- 客户端关键字静音
+ 客户端关键字屏蔽
用空格分隔会产生 AND 规范,用换行符分隔会产生 OR 规范。\n关键字周围的斜线使其成为正则表达式。
从网络导入反应
导入反应
覆盖保存
通知音
启用应用内通知音
- 自動更新
- 在后台不更新时间线
- 不要在后台捕捉笔记
+ 自动更新
+ 不在后台更新时间线
+ 不在后台获取帖子
启用自动更新
请登录
- Only Media
+ 仅媒体
+ 关于Milktea
+ 源代码(GitHub)
+ 表情选择器
+ 表情显示大小
+
生日: %s
注册于 %s
确认
- 您确定要拉黑 %s 吗?
-
- 15 分钟后
- 30 分钟后
- 1 小时后
- 1 天后
- 1 周后
- 1 个月后
- 无限期
+ 您确定要屏蔽 %s 吗?
+
+ 15 分钟
+ 30 分钟
+ 1 小时
+ 1 天
+ 1 周
+ 1 个月
+ 永久
远程查看
正在关注你
+ 帖子内容字体大小(%fsp)
+ 帖子标题字体大小(%fsp)
+ 帖子反应计数字体大小(%fsp,%fps)
+ 自定义表情符号放大倍率(%fX)
+ 建议
+ %d 人发帖
+ 作为引用帖子附加?
+ 选择草稿帖子
+ 记住滚动位置
+ 仅发帖
+ 以绝对日期显示时间戳
+ 缓存设置
+ 帖子缓存
+ 自定义表情缓存
+ 将文件移至此处
\ No newline at end of file
diff --git a/modules/common_resource/src/main/res/values/strings.xml b/modules/common_resource/src/main/res/values/strings.xml
index cf1264bc93..cc41ac65e7 100644
--- a/modules/common_resource/src/main/res/values/strings.xml
+++ b/modules/common_resource/src/main/res/values/strings.xml
@@ -91,6 +91,7 @@
AMOLED
Dark
Pancake
+ Elephant Dark
MediaActivity
Dummy Button
@@ -237,7 +238,7 @@
Update timeline in background
- Edit tab name
+ Edit tab
Follow request accepted by %s
Poll ended
@@ -266,7 +267,7 @@
Success
Failure
- Explore the Fediverse
+ Fediverse
Explore
Trending users
Users with recent activity
@@ -447,6 +448,12 @@
Renote mutes
Bookmark
+ Would you like Milktea with Fediverse?
+ Donation
+ Privacy policy
+ Terms of service
+
+
App name
Milktea
@@ -559,6 +566,15 @@
Enable automatic updates
Please login
Only Media
+ About Milktea
+ Source code(GitHub)
+ Note content font size(%fsp)
+ Note header font size(%fsp)
+ Note reaction counter font size(%fsp, %fsp)
+ Magnification for custom emoji in text(%fX)
+ Emoji picker
+ Emoji display size
+
@@ -576,6 +592,18 @@
Indefinite perio
View remotely
Follows you
+ Suggestions
+
+ %d people posting
+ Attach as a quote post?
+ Select draft post
+ Remember scroll position
+ Post only
+ Display timestamps as absolute dates
+ Cache settings
+ Note cache
+ Custom emoji cache
+ Move files here
diff --git a/modules/common_resource/src/main/res/values/themes.xml b/modules/common_resource/src/main/res/values/themes.xml
index 6ca77467ee..cd27387f42 100644
--- a/modules/common_resource/src/main/res/values/themes.xml
+++ b/modules/common_resource/src/main/res/values/themes.xml
@@ -102,4 +102,21 @@
+
+
\ No newline at end of file
diff --git a/modules/common_viewmodel/src/main/java/net/pantasystem/milktea/common_viewmodel/CurrentPageableTimelineViewModel.kt b/modules/common_viewmodel/src/main/java/net/pantasystem/milktea/common_viewmodel/CurrentPageableTimelineViewModel.kt
index 6759d52608..5b4848fa13 100644
--- a/modules/common_viewmodel/src/main/java/net/pantasystem/milktea/common_viewmodel/CurrentPageableTimelineViewModel.kt
+++ b/modules/common_viewmodel/src/main/java/net/pantasystem/milktea/common_viewmodel/CurrentPageableTimelineViewModel.kt
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import net.pantasystem.milktea.model.account.page.Pageable
import javax.inject.Inject
@@ -34,12 +35,16 @@ class CurrentPageableTimelineViewModel @Inject constructor(
) : ViewModel() {
private val _currentType = MutableStateFlow(
- CurrentPageType.Page(Pageable.HomeTimeline()))
+ CurrentPageType.Page(null, Pageable.HomeTimeline()))
val currentType: StateFlow = _currentType
- fun setCurrentPageable(pageable: Pageable) {
- _currentType.value = CurrentPageType.Page(pageable)
+
+ private val _currentAccountId = MutableStateFlow(null)
+ val currentAccountId = _currentAccountId.asStateFlow()
+
+ fun setCurrentPageable(accountId: Long?, pageable: Pageable) {
+ _currentType.value = CurrentPageType.Page(accountId, pageable)
}
fun setCurrentPageType(type: CurrentPageType) {
@@ -49,6 +54,6 @@ class CurrentPageableTimelineViewModel @Inject constructor(
}
sealed interface CurrentPageType {
- data class Page(val pageable: Pageable) : CurrentPageType
+ data class Page(val accountId: Long?, val pageable: Pageable) : CurrentPageType
object Account : CurrentPageType
}
\ No newline at end of file
diff --git a/modules/data/objectbox-models/default.json b/modules/data/objectbox-models/default.json
index e3b0ef778e..fe8cd113fa 100644
--- a/modules/data/objectbox-models/default.json
+++ b/modules/data/objectbox-models/default.json
@@ -5,7 +5,7 @@
"entities": [
{
"id": "1:4355718382021751829",
- "lastPropertyId": "51:1047146758580551890",
+ "lastPropertyId": "54:1696546822899785376",
"name": "NoteRecord",
"properties": [
{
@@ -271,14 +271,231 @@
"id": "51:1047146758580551890",
"name": "maxReactionsPerAccount",
"type": 5
+ },
+ {
+ "id": "52:3207491205296200689",
+ "name": "customEmojiAspectRatioMap",
+ "type": 13
+ },
+ {
+ "id": "53:5101199550893785799",
+ "name": "misskeyIsNotAcceptingSensitiveReaction",
+ "type": 1
+ },
+ {
+ "id": "54:1696546822899785376",
+ "name": "customEmojiUrlAndCachePathMap",
+ "type": 13
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "2:2221534449032746185",
+ "lastPropertyId": "4:3861751215772392457",
+ "name": "ThreadRecord",
+ "properties": [
+ {
+ "id": "1:6898596592219565017",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:2473069054411856439",
+ "name": "targetNoteId",
+ "type": 9
+ },
+ {
+ "id": "3:2251620119095233921",
+ "name": "accountId",
+ "type": 6
+ },
+ {
+ "id": "4:3861751215772392457",
+ "name": "targetNoteIdAndAccountId",
+ "indexId": "5:7310482946990627063",
+ "type": 9,
+ "flags": 2080
+ }
+ ],
+ "relations": [
+ {
+ "id": "1:5368363319508289421",
+ "name": "ancestors",
+ "targetId": "1:4355718382021751829"
+ },
+ {
+ "id": "2:5971800600708341253",
+ "name": "descendants",
+ "targetId": "1:4355718382021751829"
+ }
+ ]
+ },
+ {
+ "id": "3:1672123969377209864",
+ "lastPropertyId": "6:7634221281760726222",
+ "name": "ReactionUsersRecord",
+ "properties": [
+ {
+ "id": "1:676934433640553584",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:8038701529227730420",
+ "name": "accountId",
+ "indexId": "6:6489830746707304657",
+ "type": 6,
+ "flags": 8
+ },
+ {
+ "id": "3:2163943456333549192",
+ "name": "noteId",
+ "indexId": "7:7445768282858324655",
+ "type": 9,
+ "flags": 2048
+ },
+ {
+ "id": "4:2143810341282238420",
+ "name": "accountIdAndNoteIdAndReaction",
+ "indexId": "8:2235427975397612884",
+ "type": 9,
+ "flags": 2080
+ },
+ {
+ "id": "5:1292188942965914799",
+ "name": "reaction",
+ "type": 9
+ },
+ {
+ "id": "6:7634221281760726222",
+ "name": "accountIds",
+ "type": 30
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "4:5892387857597582401",
+ "lastPropertyId": "3:5250934048025398662",
+ "name": "CustomEmojiAspectRatioRecord",
+ "properties": [
+ {
+ "id": "1:27795029384995044",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:6142530143329153194",
+ "name": "uri",
+ "indexId": "9:4038966684149214552",
+ "type": 9,
+ "flags": 2080
+ },
+ {
+ "id": "3:5250934048025398662",
+ "name": "aspectRatio",
+ "type": 7
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "5:192241672526547352",
+ "lastPropertyId": "4:2544401018528846153",
+ "name": "ImageCacheRecord",
+ "properties": [
+ {
+ "id": "1:6002315150189198372",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:7274049216628202631",
+ "name": "sourceUrl",
+ "indexId": "10:5291013203713667470",
+ "type": 9,
+ "flags": 2080
+ },
+ {
+ "id": "3:3858052356230995928",
+ "name": "cachePath",
+ "type": 9
+ },
+ {
+ "id": "4:2544401018528846153",
+ "name": "cachedAt",
+ "type": 6
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "6:5418605338436881136",
+ "lastPropertyId": "9:4598656151033408118",
+ "name": "CustomEmojiRecord",
+ "properties": [
+ {
+ "id": "1:271785103207869909",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:6655539627519293459",
+ "name": "serverId",
+ "type": 9
+ },
+ {
+ "id": "3:211101382978291231",
+ "name": "name",
+ "indexId": "11:3813410665521821846",
+ "type": 9,
+ "flags": 2048
+ },
+ {
+ "id": "4:7927231724161011575",
+ "name": "emojiHost",
+ "indexId": "12:6383965324106330542",
+ "type": 9,
+ "flags": 2048
+ },
+ {
+ "id": "5:2060901050158269776",
+ "name": "url",
+ "type": 9
+ },
+ {
+ "id": "6:1468865394375722898",
+ "name": "uri",
+ "type": 9
+ },
+ {
+ "id": "7:3770123434781396120",
+ "name": "type",
+ "type": 9
+ },
+ {
+ "id": "8:8187355251103755613",
+ "name": "category",
+ "type": 9
+ },
+ {
+ "id": "9:4598656151033408118",
+ "name": "aliases",
+ "type": 30
}
],
"relations": []
}
],
- "lastEntityId": "1:4355718382021751829",
- "lastIndexId": "4:873220635513493863",
- "lastRelationId": "0:0",
+ "lastEntityId": "6:5418605338436881136",
+ "lastIndexId": "12:6383965324106330542",
+ "lastRelationId": "2:5971800600708341253",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
diff --git a/modules/data/objectbox-models/default.json.bak b/modules/data/objectbox-models/default.json.bak
index 5d9cab48aa..6e3ebf6f4e 100644
--- a/modules/data/objectbox-models/default.json.bak
+++ b/modules/data/objectbox-models/default.json.bak
@@ -5,7 +5,7 @@
"entities": [
{
"id": "1:4355718382021751829",
- "lastPropertyId": "50:4252978610725343033",
+ "lastPropertyId": "54:1696546822899785376",
"name": "NoteRecord",
"properties": [
{
@@ -266,14 +266,232 @@
"id": "50:4252978610725343033",
"name": "myReactions",
"type": 30
+ },
+ {
+ "id": "51:1047146758580551890",
+ "name": "maxReactionsPerAccount",
+ "type": 5
+ },
+ {
+ "id": "52:3207491205296200689",
+ "name": "customEmojiAspectRatioMap",
+ "type": 13
+ },
+ {
+ "id": "53:5101199550893785799",
+ "name": "misskeyIsNotAcceptingSensitiveReaction",
+ "type": 1
+ },
+ {
+ "id": "54:1696546822899785376",
+ "name": "customEmojiUrlAndCachePathMap",
+ "type": 13
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "2:2221534449032746185",
+ "lastPropertyId": "4:3861751215772392457",
+ "name": "ThreadRecord",
+ "properties": [
+ {
+ "id": "1:6898596592219565017",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:2473069054411856439",
+ "name": "targetNoteId",
+ "type": 9
+ },
+ {
+ "id": "3:2251620119095233921",
+ "name": "accountId",
+ "type": 6
+ },
+ {
+ "id": "4:3861751215772392457",
+ "name": "targetNoteIdAndAccountId",
+ "indexId": "5:7310482946990627063",
+ "type": 9,
+ "flags": 2080
+ }
+ ],
+ "relations": [
+ {
+ "id": "1:5368363319508289421",
+ "name": "ancestors",
+ "targetId": "1:4355718382021751829"
+ },
+ {
+ "id": "2:5971800600708341253",
+ "name": "descendants",
+ "targetId": "1:4355718382021751829"
+ }
+ ]
+ },
+ {
+ "id": "3:1672123969377209864",
+ "lastPropertyId": "6:7634221281760726222",
+ "name": "ReactionUsersRecord",
+ "properties": [
+ {
+ "id": "1:676934433640553584",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:8038701529227730420",
+ "name": "accountId",
+ "indexId": "6:6489830746707304657",
+ "type": 6,
+ "flags": 8
+ },
+ {
+ "id": "3:2163943456333549192",
+ "name": "noteId",
+ "indexId": "7:7445768282858324655",
+ "type": 9,
+ "flags": 2048
+ },
+ {
+ "id": "4:2143810341282238420",
+ "name": "accountIdAndNoteIdAndReaction",
+ "indexId": "8:2235427975397612884",
+ "type": 9,
+ "flags": 2080
+ },
+ {
+ "id": "5:1292188942965914799",
+ "name": "reaction",
+ "type": 9
+ },
+ {
+ "id": "6:7634221281760726222",
+ "name": "accountIds",
+ "type": 30
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "4:5892387857597582401",
+ "lastPropertyId": "3:5250934048025398662",
+ "name": "CustomEmojiAspectRatioRecord",
+ "properties": [
+ {
+ "id": "1:27795029384995044",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:6142530143329153194",
+ "name": "uri",
+ "indexId": "9:4038966684149214552",
+ "type": 9,
+ "flags": 2080
+ },
+ {
+ "id": "3:5250934048025398662",
+ "name": "aspectRatio",
+ "type": 7
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "5:192241672526547352",
+ "lastPropertyId": "4:2544401018528846153",
+ "name": "ImageCacheRecord",
+ "properties": [
+ {
+ "id": "1:6002315150189198372",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:7274049216628202631",
+ "name": "sourceUrl",
+ "indexId": "10:5291013203713667470",
+ "type": 9,
+ "flags": 2080
+ },
+ {
+ "id": "3:3858052356230995928",
+ "name": "cachePath",
+ "type": 9
+ },
+ {
+ "id": "4:2544401018528846153",
+ "name": "cachedAt",
+ "type": 6
+ }
+ ],
+ "relations": []
+ },
+ {
+ "id": "6:5418605338436881136",
+ "lastPropertyId": "9:4598656151033408118",
+ "name": "CustomEmojiRecord",
+ "properties": [
+ {
+ "id": "1:271785103207869909",
+ "name": "id",
+ "type": 6,
+ "flags": 1
+ },
+ {
+ "id": "2:6655539627519293459",
+ "name": "serverId",
+ "type": 9
+ },
+ {
+ "id": "3:211101382978291231",
+ "name": "name",
+ "type": 9
+ },
+ {
+ "id": "4:7927231724161011575",
+ "name": "emojiHost",
+ "type": 9
+ },
+ {
+ "id": "5:2060901050158269776",
+ "name": "url",
+ "type": 9
+ },
+ {
+ "id": "6:1468865394375722898",
+ "name": "uri",
+ "type": 9
+ },
+ {
+ "id": "7:3770123434781396120",
+ "name": "type",
+ "type": 9
+ },
+ {
+ "id": "8:8187355251103755613",
+ "name": "category",
+ "type": 9
+ },
+ {
+ "id": "9:4598656151033408118",
+ "name": "aliases",
+ "type": 30
}
],
"relations": []
}
],
- "lastEntityId": "1:4355718382021751829",
- "lastIndexId": "4:873220635513493863",
- "lastRelationId": "0:0",
+ "lastEntityId": "6:5418605338436881136",
+ "lastIndexId": "10:5291013203713667470",
+ "lastRelationId": "2:5971800600708341253",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
diff --git a/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/44.json b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/44.json
new file mode 100644
index 0000000000..15326bb361
--- /dev/null
+++ b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/44.json
@@ -0,0 +1,3854 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 44,
+ "identityHash": "8a4611b8efe95f3974bd13cef6b9205c",
+ "entities": [
+ {
+ "tableName": "connection_information",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT NOT NULL, `instanceBaseUrl` TEXT NOT NULL, `encryptedI` TEXT NOT NULL, `viaName` TEXT, `createdAt` TEXT NOT NULL, `isDirect` INTEGER NOT NULL, `updatedAt` TEXT NOT NULL, PRIMARY KEY(`accountId`, `encryptedI`, `instanceBaseUrl`), FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceBaseUrl",
+ "columnName": "instanceBaseUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedI",
+ "columnName": "encryptedI",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viaName",
+ "columnName": "viaName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDirect",
+ "columnName": "isDirect",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "encryptedI",
+ "instanceBaseUrl"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "reaction_history",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "reaction_user_setting",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`reaction`, `instance_domain`))",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "reaction",
+ "instance_domain"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT, `title` TEXT NOT NULL, `pageNumber` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `global_timeline_with_files` INTEGER, `global_timeline_type` TEXT, `local_timeline_with_files` INTEGER, `local_timeline_exclude_nsfw` INTEGER, `local_timeline_type` TEXT, `hybrid_timeline_withFiles` INTEGER, `hybrid_timeline_includeLocalRenotes` INTEGER, `hybrid_timeline_includeMyRenotes` INTEGER, `hybrid_timeline_includeRenotedMyRenotes` INTEGER, `hybrid_timeline_type` TEXT, `home_timeline_withFiles` INTEGER, `home_timeline_includeLocalRenotes` INTEGER, `home_timeline_includeMyRenotes` INTEGER, `home_timeline_includeRenotedMyRenotes` INTEGER, `home_timeline_type` TEXT, `user_list_timeline_listId` TEXT, `user_list_timeline_withFiles` INTEGER, `user_list_timeline_includeLocalRenotes` INTEGER, `user_list_timeline_includeMyRenotes` INTEGER, `user_list_timeline_includeRenotedMyRenotes` INTEGER, `user_list_timeline_type` TEXT, `mention_following` INTEGER, `mention_visibility` TEXT, `mention_type` TEXT, `show_noteId` TEXT, `show_type` TEXT, `tag_tag` TEXT, `tag_reply` INTEGER, `tag_renote` INTEGER, `tag_withFiles` INTEGER, `tag_poll` INTEGER, `tag_type` TEXT, `featured_offset` INTEGER, `featured_type` TEXT, `notification_following` INTEGER, `notification_markAsRead` INTEGER, `notification_type` TEXT, `user_userId` TEXT, `user_includeReplies` INTEGER, `user_includeMyRenotes` INTEGER, `user_withFiles` INTEGER, `user_type` TEXT, `search_query` TEXT, `search_host` TEXT, `search_userId` TEXT, `search_type` TEXT, `favorite_type` TEXT, `antenna_antennaId` TEXT, `antenna_type` TEXT, FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageNumber",
+ "columnName": "pageNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.withFiles",
+ "columnName": "global_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.type",
+ "columnName": "global_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.withFiles",
+ "columnName": "local_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.excludeNsfw",
+ "columnName": "local_timeline_exclude_nsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.type",
+ "columnName": "local_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.withFiles",
+ "columnName": "hybrid_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeLocalRenotes",
+ "columnName": "hybrid_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeMyRenotes",
+ "columnName": "hybrid_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeRenotedMyRenotes",
+ "columnName": "hybrid_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.type",
+ "columnName": "hybrid_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.withFiles",
+ "columnName": "home_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeLocalRenotes",
+ "columnName": "home_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeMyRenotes",
+ "columnName": "home_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeRenotedMyRenotes",
+ "columnName": "home_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.type",
+ "columnName": "home_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.listId",
+ "columnName": "user_list_timeline_listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.withFiles",
+ "columnName": "user_list_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeLocalRenotes",
+ "columnName": "user_list_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeMyRenotes",
+ "columnName": "user_list_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeRenotedMyRenotes",
+ "columnName": "user_list_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.type",
+ "columnName": "user_list_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.following",
+ "columnName": "mention_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.visibility",
+ "columnName": "mention_visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.type",
+ "columnName": "mention_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.noteId",
+ "columnName": "show_noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.type",
+ "columnName": "show_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.tag",
+ "columnName": "tag_tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.reply",
+ "columnName": "tag_reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.renote",
+ "columnName": "tag_renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.withFiles",
+ "columnName": "tag_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.poll",
+ "columnName": "tag_poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.type",
+ "columnName": "tag_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.offset",
+ "columnName": "featured_offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.type",
+ "columnName": "featured_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.following",
+ "columnName": "notification_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.markAsRead",
+ "columnName": "notification_markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.type",
+ "columnName": "notification_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.userId",
+ "columnName": "user_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeReplies",
+ "columnName": "user_includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeMyRenotes",
+ "columnName": "user_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.withFiles",
+ "columnName": "user_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.type",
+ "columnName": "user_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.query",
+ "columnName": "search_query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.host",
+ "columnName": "search_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.userId",
+ "columnName": "search_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.type",
+ "columnName": "search_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "favorite.type",
+ "columnName": "favorite_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.antennaId",
+ "columnName": "antenna_antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.type",
+ "columnName": "antenna_type",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "poll_choice_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`choice` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`choice`, `weight`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "choice",
+ "columnName": "choice",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "choice",
+ "weight",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_poll_choice_table_draft_note_id_choice",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id",
+ "choice"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_poll_choice_table_draft_note_id_choice` ON `${TABLE_NAME}` (`draft_note_id`, `choice`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, PRIMARY KEY(`userId`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_id_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_id_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL DEFAULT 'name none', `remote_file_id` TEXT, `file_path` TEXT, `is_sensitive` INTEGER, `type` TEXT, `thumbnailUrl` TEXT, `draft_note_id` INTEGER NOT NULL, `folder_id` TEXT, `file_id` INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'name none'"
+ },
+ {
+ "fieldPath": "remoteFileId",
+ "columnName": "remote_file_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileId",
+ "columnName": "file_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "file_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_table_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_table_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_note_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `visibility` TEXT NOT NULL, `text` TEXT, `cw` TEXT, `viaMobile` INTEGER, `localOnly` INTEGER, `noExtractMentions` INTEGER, `noExtractHashtags` INTEGER, `noExtractEmojis` INTEGER, `replyId` TEXT, `renoteId` TEXT, `channelId` TEXT, `scheduleWillPostAt` TEXT, `draft_note_id` INTEGER PRIMARY KEY AUTOINCREMENT, `isSensitive` INTEGER, `multiple` INTEGER, `expiresAt` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cw",
+ "columnName": "cw",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "viaMobile",
+ "columnName": "viaMobile",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localOnly",
+ "columnName": "localOnly",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractMentions",
+ "columnName": "noExtractMentions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractHashtags",
+ "columnName": "noExtractHashtags",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractEmojis",
+ "columnName": "noExtractEmojis",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "replyId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "renoteId",
+ "columnName": "renoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "scheduleWillPostAt",
+ "columnName": "scheduleWillPostAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.multiple",
+ "columnName": "multiple",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_note_table_accountId_text",
+ "unique": false,
+ "columnNames": [
+ "accountId",
+ "text"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_note_table_accountId_text` ON `${TABLE_NAME}` (`accountId`, `text`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "url_preview",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `icon` TEXT, `description` TEXT, `thumbnail` TEXT, `siteName` TEXT, PRIMARY KEY(`url`))",
+ "fields": [
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnail",
+ "columnName": "thumbnail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "siteName",
+ "columnName": "siteName",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "url"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "account_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `userName` TEXT NOT NULL, `encryptedToken` TEXT NOT NULL, `instanceType` TEXT NOT NULL DEFAULT 'misskey', `accountId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedToken",
+ "columnName": "encryptedToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceType",
+ "columnName": "instanceType",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'misskey'"
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_account_table_remoteId",
+ "unique": false,
+ "columnNames": [
+ "remoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_remoteId` ON `${TABLE_NAME}` (`remoteId`)"
+ },
+ {
+ "name": "index_account_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_account_table_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_userName` ON `${TABLE_NAME}` (`userName`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `title` TEXT NOT NULL, `weight` INTEGER NOT NULL, `pageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `withFiles` INTEGER, `excludeNsfw` INTEGER, `includeLocalRenotes` INTEGER, `includeMyRenotes` INTEGER, `includeRenotedMyRenotes` INTEGER, `listId` TEXT, `following` INTEGER, `visibility` TEXT, `noteId` TEXT, `tag` TEXT, `reply` INTEGER, `renote` INTEGER, `poll` INTEGER, `offset` INTEGER, `markAsRead` INTEGER, `userId` TEXT, `includeReplies` INTEGER, `query` TEXT, `host` TEXT, `antennaId` TEXT, `channelId` TEXT, `clipId` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageId",
+ "columnName": "pageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.withFiles",
+ "columnName": "withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.excludeNsfw",
+ "columnName": "excludeNsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeLocalRenotes",
+ "columnName": "includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeMyRenotes",
+ "columnName": "includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeRenotedMyRenotes",
+ "columnName": "includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.listId",
+ "columnName": "listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.following",
+ "columnName": "following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.reply",
+ "columnName": "reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.renote",
+ "columnName": "renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.poll",
+ "columnName": "poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.offset",
+ "columnName": "offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.markAsRead",
+ "columnName": "markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeReplies",
+ "columnName": "includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.query",
+ "columnName": "query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.antennaId",
+ "columnName": "antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.clipId",
+ "columnName": "clipId",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "pageId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_table_weight",
+ "unique": false,
+ "columnNames": [
+ "weight"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_weight` ON `${TABLE_NAME}` (`weight`)"
+ },
+ {
+ "name": "index_page_table_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "meta_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `bannerUrl` TEXT, `cacheRemoteFiles` INTEGER, `description` TEXT, `disableGlobalTimeline` INTEGER, `disableLocalTimeline` INTEGER, `disableRegistration` INTEGER, `driveCapacityPerLocalUserMb` INTEGER, `driveCapacityPerRemoteUserMb` INTEGER, `enableDiscordIntegration` INTEGER, `enableEmail` INTEGER, `enableEmojiReaction` INTEGER, `enableGithubIntegration` INTEGER, `enableRecaptcha` INTEGER, `enableServiceWorker` INTEGER, `enableTwitterIntegration` INTEGER, `errorImageUrl` TEXT, `feedbackUrl` TEXT, `iconUrl` TEXT, `maintainerEmail` TEXT, `maintainerName` TEXT, `mascotImageUrl` TEXT, `maxNoteTextLength` INTEGER, `name` TEXT, `recaptchaSiteKey` TEXT, `secure` INTEGER, `swPublicKey` TEXT, `toSUrl` TEXT, `version` TEXT NOT NULL, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cacheRemoteFiles",
+ "columnName": "cacheRemoteFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableGlobalTimeline",
+ "columnName": "disableGlobalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableLocalTimeline",
+ "columnName": "disableLocalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableRegistration",
+ "columnName": "disableRegistration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerLocalUserMb",
+ "columnName": "driveCapacityPerLocalUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerRemoteUserMb",
+ "columnName": "driveCapacityPerRemoteUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableDiscordIntegration",
+ "columnName": "enableDiscordIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmail",
+ "columnName": "enableEmail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmojiReaction",
+ "columnName": "enableEmojiReaction",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableGithubIntegration",
+ "columnName": "enableGithubIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableRecaptcha",
+ "columnName": "enableRecaptcha",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableServiceWorker",
+ "columnName": "enableServiceWorker",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableTwitterIntegration",
+ "columnName": "enableTwitterIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "errorImageUrl",
+ "columnName": "errorImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "feedbackUrl",
+ "columnName": "feedbackUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerEmail",
+ "columnName": "maintainerEmail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerName",
+ "columnName": "maintainerName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mascotImageUrl",
+ "columnName": "mascotImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxNoteTextLength",
+ "columnName": "maxNoteTextLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recaptchaSiteKey",
+ "columnName": "recaptchaSiteKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secure",
+ "columnName": "secure",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "swPublicKey",
+ "columnName": "swPublicKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "toSUrl",
+ "columnName": "toSUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "emoji_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `host` TEXT, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` TEXT, PRIMARY KEY(`name`, `instanceDomain`), FOREIGN KEY(`instanceDomain`) REFERENCES `meta_table`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_emoji_table_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "meta_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "emoji_alias_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alias` TEXT NOT NULL, `name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, PRIMARY KEY(`alias`, `name`, `instanceDomain`), FOREIGN KEY(`name`, `instanceDomain`) REFERENCES `emoji_table`(`name`, `instanceDomain`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "alias",
+ "columnName": "alias",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "alias",
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_alias_table_name_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_alias_table_name_instanceDomain` ON `${TABLE_NAME}` (`name`, `instanceDomain`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "emoji_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "name",
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "name",
+ "instanceDomain"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "unread_notifications_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, PRIMARY KEY(`accountId`, `notificationId`), FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nicknames",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`nickname` TEXT NOT NULL, `username` TEXT NOT NULL, `host` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "nickname",
+ "columnName": "nickname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_nicknames_username_host",
+ "unique": true,
+ "columnNames": [
+ "username",
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_nicknames_username_host` ON `${TABLE_NAME}` (`username`, `host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "utf8_emojis_by_amio",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`codes` TEXT NOT NULL, `name` TEXT NOT NULL, `char` TEXT NOT NULL, PRIMARY KEY(`codes`))",
+ "fields": [
+ {
+ "fieldPath": "codes",
+ "columnName": "codes",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charCode",
+ "columnName": "char",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "codes"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "drive_file_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `relatedAccountId` INTEGER NOT NULL, `createdAt` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `md5` TEXT, `size` INTEGER, `url` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `thumbnailUrl` TEXT, `folderId` TEXT, `userId` TEXT, `comment` TEXT, `blurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`relatedAccountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "relatedAccountId",
+ "columnName": "relatedAccountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "md5",
+ "columnName": "md5",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folderId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blurhash",
+ "columnName": "blurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_drive_file_v1_serverId_relatedAccountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_drive_file_v1_serverId_relatedAccountId` ON `${TABLE_NAME}` (`serverId`, `relatedAccountId`)"
+ },
+ {
+ "name": "index_drive_file_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_drive_file_v1_relatedAccountId",
+ "unique": false,
+ "columnNames": [
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_relatedAccountId` ON `${TABLE_NAME}` (`relatedAccountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "relatedAccountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`draftNoteId` INTEGER NOT NULL, `filePropertyId` INTEGER, `localFileId` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`filePropertyId`) REFERENCES `drive_file_v1`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`localFileId`) REFERENCES `draft_local_file_v2_table`(`localFileId`) ON UPDATE NO ACTION ON DELETE SET NULL )",
+ "fields": [
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draftNoteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePropertyId",
+ "columnName": "filePropertyId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId",
+ "unique": true,
+ "columnNames": [
+ "draftNoteId",
+ "filePropertyId",
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId` ON `${TABLE_NAME}` (`draftNoteId`, `filePropertyId`, `localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_draftNoteId",
+ "unique": false,
+ "columnNames": [
+ "draftNoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId` ON `${TABLE_NAME}` (`draftNoteId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_localFileId",
+ "unique": false,
+ "columnNames": [
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_localFileId` ON `${TABLE_NAME}` (`localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_filePropertyId",
+ "unique": false,
+ "columnNames": [
+ "filePropertyId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_filePropertyId` ON `${TABLE_NAME}` (`filePropertyId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "drive_file_v1",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "filePropertyId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "draft_local_file_v2_table",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "localFileId"
+ ],
+ "referencedColumns": [
+ "localFileId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_local_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `file_path` TEXT NOT NULL, `is_sensitive` INTEGER, `type` TEXT NOT NULL, `thumbnailUrl` TEXT, `folder_id` TEXT, `file_size` INTEGER, `comment` TEXT, `localFileId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "file_size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "localFileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "group_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `ownerId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_v1_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_group_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_group_v1_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_v1_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group_member_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`groupId`) REFERENCES `group_v1`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_member_v1_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_member_v1_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_group_member_v1_groupId_userId",
+ "unique": true,
+ "columnNames": [
+ "groupId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_member_v1_groupId_userId` ON `${TABLE_NAME}` (`groupId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group_v1",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `userName` TEXT NOT NULL, `name` TEXT, `avatarUrl` TEXT, `isCat` INTEGER, `isBot` INTEGER, `host` TEXT NOT NULL, `isSameHost` INTEGER NOT NULL, `avatarBlurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "avatarUrl",
+ "columnName": "avatarUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCat",
+ "columnName": "isCat",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isBot",
+ "columnName": "isBot",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSameHost",
+ "columnName": "isSameHost",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarBlurhash",
+ "columnName": "avatarBlurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_serverId_accountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_serverId_accountId` ON `${TABLE_NAME}` (`serverId`, `accountId`)"
+ },
+ {
+ "name": "index_user_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_userName` ON `${TABLE_NAME}` (`userName`)"
+ },
+ {
+ "name": "index_user_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_host",
+ "unique": false,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_detailed_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_detailed_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_detailed_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_emoji",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_emoji_name_userId",
+ "unique": true,
+ "columnNames": [
+ "name",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_emoji_name_userId` ON `${TABLE_NAME}` (`name`, `userId`)"
+ },
+ {
+ "name": "index_user_emoji_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_emoji_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pinned_note_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`noteId` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pinned_note_id_noteId_userId",
+ "unique": true,
+ "columnNames": [
+ "noteId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_pinned_note_id_noteId_userId` ON `${TABLE_NAME}` (`noteId`, `userId`)"
+ },
+ {
+ "name": "index_pinned_note_id_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pinned_note_id_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`faviconUrl` TEXT, `iconUrl` TEXT, `name` TEXT, `softwareName` TEXT, `softwareVersion` TEXT, `themeColor` TEXT, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "faviconUrl",
+ "columnName": "faviconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareName",
+ "columnName": "softwareName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareVersion",
+ "columnName": "softwareVersion",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_instance_info_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_instance_info_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_profile_field",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `value` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_profile_field_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_profile_field_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "word_filter_regex_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pattern` TEXT NOT NULL, `parentId` INTEGER NOT NULL, PRIMARY KEY(`parentId`), FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "pattern",
+ "columnName": "pattern",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "parentId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_regex_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_regex_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_word_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`word` TEXT NOT NULL, `parentId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "word",
+ "columnName": "word",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_word_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_word_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_list_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_user_list_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list_member",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userListId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userListId`) REFERENCES `user_list`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userListId",
+ "columnName": "userListId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_member_userListId",
+ "unique": false,
+ "columnNames": [
+ "userListId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_member_userListId` ON `${TABLE_NAME}` (`userListId`)"
+ },
+ {
+ "name": "index_user_list_member_userListId_userId",
+ "unique": true,
+ "columnNames": [
+ "userListId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_member_userListId_userId` ON `${TABLE_NAME}` (`userListId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user_list",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userListId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "instance_info_v1_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `host` TEXT NOT NULL, `name` TEXT, `description` TEXT, `clientMaxBodyByteSize` INTEGER, `iconUrl` TEXT, `themeColor` TEXT, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "clientMaxBodyByteSize",
+ "columnName": "clientMaxBodyByteSize",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_instance_info_v1_table_host",
+ "unique": true,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_instance_info_v1_table_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "search_histories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `keyword` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keyword",
+ "columnName": "keyword",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_search_histories_keyword_accountId",
+ "unique": true,
+ "columnNames": [
+ "keyword",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_search_histories_keyword_accountId` ON `${TABLE_NAME}` (`keyword`, `accountId`)"
+ },
+ {
+ "name": "index_search_histories_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_search_histories_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_info_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_info_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_info_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_related_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_related_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_related_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nodeinfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `nodeInfoVersion` TEXT NOT NULL, `name` TEXT NOT NULL, `version` TEXT NOT NULL, PRIMARY KEY(`host`))",
+ "fields": [
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nodeInfoVersion",
+ "columnName": "nodeInfoVersion",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "host"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `email` TEXT NOT NULL, `version` TEXT NOT NULL, `urls_streamingApi` TEXT, `configuration_statuses_maxCharacters` INTEGER, `configuration_statuses_maxMediaAttachments` INTEGER, `configuration_polls_maxOptions` INTEGER, `configuration_polls_maxCharactersPerOption` INTEGER, `configuration_polls_minExpiration` INTEGER, `configuration_polls_maxExpiration` INTEGER, `configuration_emoji_reactions_myReactions` INTEGER, `configuration_emoji_reactions_maxReactionsPerAccount` INTEGER, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "urls.streamingApi",
+ "columnName": "urls_streamingApi",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxCharacters",
+ "columnName": "configuration_statuses_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxMediaAttachments",
+ "columnName": "configuration_statuses_maxMediaAttachments",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxOptions",
+ "columnName": "configuration_polls_maxOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxCharactersPerOption",
+ "columnName": "configuration_polls_maxCharactersPerOption",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.minExpiration",
+ "columnName": "configuration_polls_minExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxExpiration",
+ "columnName": "configuration_polls_maxExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactions",
+ "columnName": "configuration_emoji_reactions_myReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactionsPerAccount",
+ "columnName": "configuration_emoji_reactions_maxReactionsPerAccount",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emojis",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT, `name` TEXT NOT NULL, `emojiHost` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiHost",
+ "columnName": "emojiHost",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emojis_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_name` ON `${TABLE_NAME}` (`name`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost",
+ "unique": false,
+ "columnNames": [
+ "emojiHost"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost` ON `${TABLE_NAME}` (`emojiHost`)"
+ },
+ {
+ "name": "index_custom_emojis_category",
+ "unique": false,
+ "columnNames": [
+ "category"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_category` ON `${TABLE_NAME}` (`category`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost_name",
+ "unique": true,
+ "columnNames": [
+ "emojiHost",
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost_name` ON `${TABLE_NAME}` (`emojiHost`, `name`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emoji_aliases",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`emojiId` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`emojiId`, `value`), FOREIGN KEY(`emojiId`) REFERENCES `custom_emojis`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "emojiId",
+ "columnName": "emojiId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emoji_aliases_emojiId_value",
+ "unique": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emoji_aliases_emojiId_value` ON `${TABLE_NAME}` (`emojiId`, `value`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "custom_emojis",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "emojiId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "notification_json_cache_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, `json` TEXT NOT NULL, `key` TEXT, `weight` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `notificationId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "json",
+ "columnName": "json",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_notification_json_cache_v1_key",
+ "unique": false,
+ "columnNames": [
+ "key"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_json_cache_v1_key` ON `${TABLE_NAME}` (`key`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_word_filters_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `filterId` TEXT NOT NULL, `phrase` TEXT NOT NULL, `wholeWord` INTEGER NOT NULL, `expiresAt` TEXT, `irreversible` INTEGER NOT NULL, `isContextHome` INTEGER NOT NULL, `isContextNotifications` INTEGER NOT NULL, `isContextPublic` INTEGER NOT NULL, `isContextThread` INTEGER NOT NULL, `isContextAccount` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `filterId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filterId",
+ "columnName": "filterId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phrase",
+ "columnName": "phrase",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wholeWord",
+ "columnName": "wholeWord",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "irreversible",
+ "columnName": "irreversible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextHome",
+ "columnName": "isContextHome",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextNotifications",
+ "columnName": "isContextNotifications",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextPublic",
+ "columnName": "isContextPublic",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextThread",
+ "columnName": "isContextThread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextAccount",
+ "columnName": "isContextAccount",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "filterId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "renote_mute_users",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `postedAt` TEXT, PRIMARY KEY(`userId`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "postedAt",
+ "columnName": "postedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_renote_mute_users_postedAt",
+ "unique": false,
+ "columnNames": [
+ "postedAt"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_postedAt` ON `${TABLE_NAME}` (`postedAt`)"
+ },
+ {
+ "name": "index_renote_mute_users_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_fedibird_capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_mastodon_instance_fedibird_capabilities_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_mastodon_instance_fedibird_capabilities_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pleroma_metadata_features",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pleroma_metadata_features_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pleroma_metadata_features_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [
+ {
+ "viewName": "user_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select user.*, nicknames.nickname from user left join nicknames on user.userName = nicknames.username and user.host = nicknames.host"
+ },
+ {
+ "viewName": "group_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.groupId, u.id as userId, u.avatarUrl, u.serverId from group_member_v1 as m \n inner join group_v1 as g\n inner join user as u\n on m.groupId = g.id\n and m.userId = u.serverId\n and g.accountId = u.accountId"
+ },
+ {
+ "viewName": "user_list_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.userListId, u.id as userId, u.avatarUrl, u.serverId from user_list_member as m \n inner join user_list as ul\n inner join user as u\n on m.userListId = ul.id\n and m.userId = u.serverId\n and ul.accountId = u.accountId"
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8a4611b8efe95f3974bd13cef6b9205c')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/45.json b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/45.json
new file mode 100644
index 0000000000..f950dc199d
--- /dev/null
+++ b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/45.json
@@ -0,0 +1,3872 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 45,
+ "identityHash": "6422cba92843d6010b114ced1b08f79c",
+ "entities": [
+ {
+ "tableName": "connection_information",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT NOT NULL, `instanceBaseUrl` TEXT NOT NULL, `encryptedI` TEXT NOT NULL, `viaName` TEXT, `createdAt` TEXT NOT NULL, `isDirect` INTEGER NOT NULL, `updatedAt` TEXT NOT NULL, PRIMARY KEY(`accountId`, `encryptedI`, `instanceBaseUrl`), FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceBaseUrl",
+ "columnName": "instanceBaseUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedI",
+ "columnName": "encryptedI",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viaName",
+ "columnName": "viaName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDirect",
+ "columnName": "isDirect",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "encryptedI",
+ "instanceBaseUrl"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "reaction_history",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `accountId` INTEGER, `target_post_id` TEXT, `target_user_id` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetPostId",
+ "columnName": "target_post_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetUserId",
+ "columnName": "target_user_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "reaction_user_setting",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`reaction`, `instance_domain`))",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "reaction",
+ "instance_domain"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT, `title` TEXT NOT NULL, `pageNumber` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `global_timeline_with_files` INTEGER, `global_timeline_type` TEXT, `local_timeline_with_files` INTEGER, `local_timeline_exclude_nsfw` INTEGER, `local_timeline_type` TEXT, `hybrid_timeline_withFiles` INTEGER, `hybrid_timeline_includeLocalRenotes` INTEGER, `hybrid_timeline_includeMyRenotes` INTEGER, `hybrid_timeline_includeRenotedMyRenotes` INTEGER, `hybrid_timeline_type` TEXT, `home_timeline_withFiles` INTEGER, `home_timeline_includeLocalRenotes` INTEGER, `home_timeline_includeMyRenotes` INTEGER, `home_timeline_includeRenotedMyRenotes` INTEGER, `home_timeline_type` TEXT, `user_list_timeline_listId` TEXT, `user_list_timeline_withFiles` INTEGER, `user_list_timeline_includeLocalRenotes` INTEGER, `user_list_timeline_includeMyRenotes` INTEGER, `user_list_timeline_includeRenotedMyRenotes` INTEGER, `user_list_timeline_type` TEXT, `mention_following` INTEGER, `mention_visibility` TEXT, `mention_type` TEXT, `show_noteId` TEXT, `show_type` TEXT, `tag_tag` TEXT, `tag_reply` INTEGER, `tag_renote` INTEGER, `tag_withFiles` INTEGER, `tag_poll` INTEGER, `tag_type` TEXT, `featured_offset` INTEGER, `featured_type` TEXT, `notification_following` INTEGER, `notification_markAsRead` INTEGER, `notification_type` TEXT, `user_userId` TEXT, `user_includeReplies` INTEGER, `user_includeMyRenotes` INTEGER, `user_withFiles` INTEGER, `user_type` TEXT, `search_query` TEXT, `search_host` TEXT, `search_userId` TEXT, `search_type` TEXT, `favorite_type` TEXT, `antenna_antennaId` TEXT, `antenna_type` TEXT, FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageNumber",
+ "columnName": "pageNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.withFiles",
+ "columnName": "global_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.type",
+ "columnName": "global_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.withFiles",
+ "columnName": "local_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.excludeNsfw",
+ "columnName": "local_timeline_exclude_nsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.type",
+ "columnName": "local_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.withFiles",
+ "columnName": "hybrid_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeLocalRenotes",
+ "columnName": "hybrid_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeMyRenotes",
+ "columnName": "hybrid_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeRenotedMyRenotes",
+ "columnName": "hybrid_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.type",
+ "columnName": "hybrid_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.withFiles",
+ "columnName": "home_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeLocalRenotes",
+ "columnName": "home_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeMyRenotes",
+ "columnName": "home_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeRenotedMyRenotes",
+ "columnName": "home_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.type",
+ "columnName": "home_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.listId",
+ "columnName": "user_list_timeline_listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.withFiles",
+ "columnName": "user_list_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeLocalRenotes",
+ "columnName": "user_list_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeMyRenotes",
+ "columnName": "user_list_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeRenotedMyRenotes",
+ "columnName": "user_list_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.type",
+ "columnName": "user_list_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.following",
+ "columnName": "mention_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.visibility",
+ "columnName": "mention_visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.type",
+ "columnName": "mention_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.noteId",
+ "columnName": "show_noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.type",
+ "columnName": "show_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.tag",
+ "columnName": "tag_tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.reply",
+ "columnName": "tag_reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.renote",
+ "columnName": "tag_renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.withFiles",
+ "columnName": "tag_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.poll",
+ "columnName": "tag_poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.type",
+ "columnName": "tag_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.offset",
+ "columnName": "featured_offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.type",
+ "columnName": "featured_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.following",
+ "columnName": "notification_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.markAsRead",
+ "columnName": "notification_markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.type",
+ "columnName": "notification_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.userId",
+ "columnName": "user_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeReplies",
+ "columnName": "user_includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeMyRenotes",
+ "columnName": "user_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.withFiles",
+ "columnName": "user_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.type",
+ "columnName": "user_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.query",
+ "columnName": "search_query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.host",
+ "columnName": "search_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.userId",
+ "columnName": "search_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.type",
+ "columnName": "search_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "favorite.type",
+ "columnName": "favorite_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.antennaId",
+ "columnName": "antenna_antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.type",
+ "columnName": "antenna_type",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "poll_choice_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`choice` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`choice`, `weight`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "choice",
+ "columnName": "choice",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "choice",
+ "weight",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_poll_choice_table_draft_note_id_choice",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id",
+ "choice"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_poll_choice_table_draft_note_id_choice` ON `${TABLE_NAME}` (`draft_note_id`, `choice`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, PRIMARY KEY(`userId`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_id_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_id_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL DEFAULT 'name none', `remote_file_id` TEXT, `file_path` TEXT, `is_sensitive` INTEGER, `type` TEXT, `thumbnailUrl` TEXT, `draft_note_id` INTEGER NOT NULL, `folder_id` TEXT, `file_id` INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'name none'"
+ },
+ {
+ "fieldPath": "remoteFileId",
+ "columnName": "remote_file_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileId",
+ "columnName": "file_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "file_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_table_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_table_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_note_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `visibility` TEXT NOT NULL, `text` TEXT, `cw` TEXT, `viaMobile` INTEGER, `localOnly` INTEGER, `noExtractMentions` INTEGER, `noExtractHashtags` INTEGER, `noExtractEmojis` INTEGER, `replyId` TEXT, `renoteId` TEXT, `channelId` TEXT, `scheduleWillPostAt` TEXT, `draft_note_id` INTEGER PRIMARY KEY AUTOINCREMENT, `isSensitive` INTEGER, `multiple` INTEGER, `expiresAt` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cw",
+ "columnName": "cw",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "viaMobile",
+ "columnName": "viaMobile",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localOnly",
+ "columnName": "localOnly",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractMentions",
+ "columnName": "noExtractMentions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractHashtags",
+ "columnName": "noExtractHashtags",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractEmojis",
+ "columnName": "noExtractEmojis",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "replyId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "renoteId",
+ "columnName": "renoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "scheduleWillPostAt",
+ "columnName": "scheduleWillPostAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.multiple",
+ "columnName": "multiple",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_note_table_accountId_text",
+ "unique": false,
+ "columnNames": [
+ "accountId",
+ "text"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_note_table_accountId_text` ON `${TABLE_NAME}` (`accountId`, `text`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "url_preview",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `icon` TEXT, `description` TEXT, `thumbnail` TEXT, `siteName` TEXT, PRIMARY KEY(`url`))",
+ "fields": [
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnail",
+ "columnName": "thumbnail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "siteName",
+ "columnName": "siteName",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "url"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "account_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `userName` TEXT NOT NULL, `encryptedToken` TEXT NOT NULL, `instanceType` TEXT NOT NULL DEFAULT 'misskey', `accountId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedToken",
+ "columnName": "encryptedToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceType",
+ "columnName": "instanceType",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'misskey'"
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_account_table_remoteId",
+ "unique": false,
+ "columnNames": [
+ "remoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_remoteId` ON `${TABLE_NAME}` (`remoteId`)"
+ },
+ {
+ "name": "index_account_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_account_table_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_userName` ON `${TABLE_NAME}` (`userName`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `title` TEXT NOT NULL, `weight` INTEGER NOT NULL, `pageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `withFiles` INTEGER, `excludeNsfw` INTEGER, `includeLocalRenotes` INTEGER, `includeMyRenotes` INTEGER, `includeRenotedMyRenotes` INTEGER, `listId` TEXT, `following` INTEGER, `visibility` TEXT, `noteId` TEXT, `tag` TEXT, `reply` INTEGER, `renote` INTEGER, `poll` INTEGER, `offset` INTEGER, `markAsRead` INTEGER, `userId` TEXT, `includeReplies` INTEGER, `query` TEXT, `host` TEXT, `antennaId` TEXT, `channelId` TEXT, `clipId` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageId",
+ "columnName": "pageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.withFiles",
+ "columnName": "withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.excludeNsfw",
+ "columnName": "excludeNsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeLocalRenotes",
+ "columnName": "includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeMyRenotes",
+ "columnName": "includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeRenotedMyRenotes",
+ "columnName": "includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.listId",
+ "columnName": "listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.following",
+ "columnName": "following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.reply",
+ "columnName": "reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.renote",
+ "columnName": "renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.poll",
+ "columnName": "poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.offset",
+ "columnName": "offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.markAsRead",
+ "columnName": "markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeReplies",
+ "columnName": "includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.query",
+ "columnName": "query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.antennaId",
+ "columnName": "antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.clipId",
+ "columnName": "clipId",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "pageId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_table_weight",
+ "unique": false,
+ "columnNames": [
+ "weight"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_weight` ON `${TABLE_NAME}` (`weight`)"
+ },
+ {
+ "name": "index_page_table_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "meta_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `bannerUrl` TEXT, `cacheRemoteFiles` INTEGER, `description` TEXT, `disableGlobalTimeline` INTEGER, `disableLocalTimeline` INTEGER, `disableRegistration` INTEGER, `driveCapacityPerLocalUserMb` INTEGER, `driveCapacityPerRemoteUserMb` INTEGER, `enableDiscordIntegration` INTEGER, `enableEmail` INTEGER, `enableEmojiReaction` INTEGER, `enableGithubIntegration` INTEGER, `enableRecaptcha` INTEGER, `enableServiceWorker` INTEGER, `enableTwitterIntegration` INTEGER, `errorImageUrl` TEXT, `feedbackUrl` TEXT, `iconUrl` TEXT, `maintainerEmail` TEXT, `maintainerName` TEXT, `mascotImageUrl` TEXT, `maxNoteTextLength` INTEGER, `name` TEXT, `recaptchaSiteKey` TEXT, `secure` INTEGER, `swPublicKey` TEXT, `toSUrl` TEXT, `version` TEXT NOT NULL, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cacheRemoteFiles",
+ "columnName": "cacheRemoteFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableGlobalTimeline",
+ "columnName": "disableGlobalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableLocalTimeline",
+ "columnName": "disableLocalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableRegistration",
+ "columnName": "disableRegistration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerLocalUserMb",
+ "columnName": "driveCapacityPerLocalUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerRemoteUserMb",
+ "columnName": "driveCapacityPerRemoteUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableDiscordIntegration",
+ "columnName": "enableDiscordIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmail",
+ "columnName": "enableEmail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmojiReaction",
+ "columnName": "enableEmojiReaction",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableGithubIntegration",
+ "columnName": "enableGithubIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableRecaptcha",
+ "columnName": "enableRecaptcha",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableServiceWorker",
+ "columnName": "enableServiceWorker",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableTwitterIntegration",
+ "columnName": "enableTwitterIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "errorImageUrl",
+ "columnName": "errorImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "feedbackUrl",
+ "columnName": "feedbackUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerEmail",
+ "columnName": "maintainerEmail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerName",
+ "columnName": "maintainerName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mascotImageUrl",
+ "columnName": "mascotImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxNoteTextLength",
+ "columnName": "maxNoteTextLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recaptchaSiteKey",
+ "columnName": "recaptchaSiteKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secure",
+ "columnName": "secure",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "swPublicKey",
+ "columnName": "swPublicKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "toSUrl",
+ "columnName": "toSUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "emoji_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `host` TEXT, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` TEXT, PRIMARY KEY(`name`, `instanceDomain`), FOREIGN KEY(`instanceDomain`) REFERENCES `meta_table`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_emoji_table_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "meta_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "emoji_alias_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alias` TEXT NOT NULL, `name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, PRIMARY KEY(`alias`, `name`, `instanceDomain`), FOREIGN KEY(`name`, `instanceDomain`) REFERENCES `emoji_table`(`name`, `instanceDomain`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "alias",
+ "columnName": "alias",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "alias",
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_alias_table_name_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_alias_table_name_instanceDomain` ON `${TABLE_NAME}` (`name`, `instanceDomain`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "emoji_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "name",
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "name",
+ "instanceDomain"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "unread_notifications_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, PRIMARY KEY(`accountId`, `notificationId`), FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nicknames",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`nickname` TEXT NOT NULL, `username` TEXT NOT NULL, `host` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "nickname",
+ "columnName": "nickname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_nicknames_username_host",
+ "unique": true,
+ "columnNames": [
+ "username",
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_nicknames_username_host` ON `${TABLE_NAME}` (`username`, `host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "utf8_emojis_by_amio",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`codes` TEXT NOT NULL, `name` TEXT NOT NULL, `char` TEXT NOT NULL, PRIMARY KEY(`codes`))",
+ "fields": [
+ {
+ "fieldPath": "codes",
+ "columnName": "codes",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charCode",
+ "columnName": "char",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "codes"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "drive_file_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `relatedAccountId` INTEGER NOT NULL, `createdAt` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `md5` TEXT, `size` INTEGER, `url` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `thumbnailUrl` TEXT, `folderId` TEXT, `userId` TEXT, `comment` TEXT, `blurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`relatedAccountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "relatedAccountId",
+ "columnName": "relatedAccountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "md5",
+ "columnName": "md5",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folderId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blurhash",
+ "columnName": "blurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_drive_file_v1_serverId_relatedAccountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_drive_file_v1_serverId_relatedAccountId` ON `${TABLE_NAME}` (`serverId`, `relatedAccountId`)"
+ },
+ {
+ "name": "index_drive_file_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_drive_file_v1_relatedAccountId",
+ "unique": false,
+ "columnNames": [
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_relatedAccountId` ON `${TABLE_NAME}` (`relatedAccountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "relatedAccountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`draftNoteId` INTEGER NOT NULL, `filePropertyId` INTEGER, `localFileId` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`filePropertyId`) REFERENCES `drive_file_v1`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`localFileId`) REFERENCES `draft_local_file_v2_table`(`localFileId`) ON UPDATE NO ACTION ON DELETE SET NULL )",
+ "fields": [
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draftNoteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePropertyId",
+ "columnName": "filePropertyId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId",
+ "unique": true,
+ "columnNames": [
+ "draftNoteId",
+ "filePropertyId",
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId` ON `${TABLE_NAME}` (`draftNoteId`, `filePropertyId`, `localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_draftNoteId",
+ "unique": false,
+ "columnNames": [
+ "draftNoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId` ON `${TABLE_NAME}` (`draftNoteId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_localFileId",
+ "unique": false,
+ "columnNames": [
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_localFileId` ON `${TABLE_NAME}` (`localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_filePropertyId",
+ "unique": false,
+ "columnNames": [
+ "filePropertyId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_filePropertyId` ON `${TABLE_NAME}` (`filePropertyId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "drive_file_v1",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "filePropertyId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "draft_local_file_v2_table",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "localFileId"
+ ],
+ "referencedColumns": [
+ "localFileId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_local_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `file_path` TEXT NOT NULL, `is_sensitive` INTEGER, `type` TEXT NOT NULL, `thumbnailUrl` TEXT, `folder_id` TEXT, `file_size` INTEGER, `comment` TEXT, `localFileId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "file_size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "localFileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "group_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `ownerId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_v1_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_group_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_group_v1_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_v1_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group_member_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`groupId`) REFERENCES `group_v1`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_member_v1_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_member_v1_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_group_member_v1_groupId_userId",
+ "unique": true,
+ "columnNames": [
+ "groupId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_member_v1_groupId_userId` ON `${TABLE_NAME}` (`groupId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group_v1",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `userName` TEXT NOT NULL, `name` TEXT, `avatarUrl` TEXT, `isCat` INTEGER, `isBot` INTEGER, `host` TEXT NOT NULL, `isSameHost` INTEGER NOT NULL, `avatarBlurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "avatarUrl",
+ "columnName": "avatarUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCat",
+ "columnName": "isCat",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isBot",
+ "columnName": "isBot",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSameHost",
+ "columnName": "isSameHost",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarBlurhash",
+ "columnName": "avatarBlurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_serverId_accountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_serverId_accountId` ON `${TABLE_NAME}` (`serverId`, `accountId`)"
+ },
+ {
+ "name": "index_user_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_userName` ON `${TABLE_NAME}` (`userName`)"
+ },
+ {
+ "name": "index_user_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_host",
+ "unique": false,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_detailed_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_detailed_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_detailed_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_emoji",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_emoji_name_userId",
+ "unique": true,
+ "columnNames": [
+ "name",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_emoji_name_userId` ON `${TABLE_NAME}` (`name`, `userId`)"
+ },
+ {
+ "name": "index_user_emoji_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_emoji_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pinned_note_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`noteId` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pinned_note_id_noteId_userId",
+ "unique": true,
+ "columnNames": [
+ "noteId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_pinned_note_id_noteId_userId` ON `${TABLE_NAME}` (`noteId`, `userId`)"
+ },
+ {
+ "name": "index_pinned_note_id_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pinned_note_id_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`faviconUrl` TEXT, `iconUrl` TEXT, `name` TEXT, `softwareName` TEXT, `softwareVersion` TEXT, `themeColor` TEXT, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "faviconUrl",
+ "columnName": "faviconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareName",
+ "columnName": "softwareName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareVersion",
+ "columnName": "softwareVersion",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_instance_info_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_instance_info_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_profile_field",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `value` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_profile_field_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_profile_field_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "word_filter_regex_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pattern` TEXT NOT NULL, `parentId` INTEGER NOT NULL, PRIMARY KEY(`parentId`), FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "pattern",
+ "columnName": "pattern",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "parentId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_regex_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_regex_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_word_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`word` TEXT NOT NULL, `parentId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "word",
+ "columnName": "word",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_word_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_word_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_list_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_user_list_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list_member",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userListId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userListId`) REFERENCES `user_list`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userListId",
+ "columnName": "userListId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_member_userListId",
+ "unique": false,
+ "columnNames": [
+ "userListId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_member_userListId` ON `${TABLE_NAME}` (`userListId`)"
+ },
+ {
+ "name": "index_user_list_member_userListId_userId",
+ "unique": true,
+ "columnNames": [
+ "userListId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_member_userListId_userId` ON `${TABLE_NAME}` (`userListId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user_list",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userListId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "instance_info_v1_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `host` TEXT NOT NULL, `name` TEXT, `description` TEXT, `clientMaxBodyByteSize` INTEGER, `iconUrl` TEXT, `themeColor` TEXT, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "clientMaxBodyByteSize",
+ "columnName": "clientMaxBodyByteSize",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_instance_info_v1_table_host",
+ "unique": true,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_instance_info_v1_table_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "search_histories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `keyword` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keyword",
+ "columnName": "keyword",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_search_histories_keyword_accountId",
+ "unique": true,
+ "columnNames": [
+ "keyword",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_search_histories_keyword_accountId` ON `${TABLE_NAME}` (`keyword`, `accountId`)"
+ },
+ {
+ "name": "index_search_histories_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_search_histories_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_info_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_info_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_info_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_related_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_related_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_related_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nodeinfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `nodeInfoVersion` TEXT NOT NULL, `name` TEXT NOT NULL, `version` TEXT NOT NULL, PRIMARY KEY(`host`))",
+ "fields": [
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nodeInfoVersion",
+ "columnName": "nodeInfoVersion",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "host"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `email` TEXT NOT NULL, `version` TEXT NOT NULL, `urls_streamingApi` TEXT, `configuration_statuses_maxCharacters` INTEGER, `configuration_statuses_maxMediaAttachments` INTEGER, `configuration_polls_maxOptions` INTEGER, `configuration_polls_maxCharactersPerOption` INTEGER, `configuration_polls_minExpiration` INTEGER, `configuration_polls_maxExpiration` INTEGER, `configuration_emoji_reactions_myReactions` INTEGER, `configuration_emoji_reactions_maxReactionsPerAccount` INTEGER, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "urls.streamingApi",
+ "columnName": "urls_streamingApi",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxCharacters",
+ "columnName": "configuration_statuses_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxMediaAttachments",
+ "columnName": "configuration_statuses_maxMediaAttachments",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxOptions",
+ "columnName": "configuration_polls_maxOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxCharactersPerOption",
+ "columnName": "configuration_polls_maxCharactersPerOption",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.minExpiration",
+ "columnName": "configuration_polls_minExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxExpiration",
+ "columnName": "configuration_polls_maxExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactions",
+ "columnName": "configuration_emoji_reactions_myReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactionsPerAccount",
+ "columnName": "configuration_emoji_reactions_maxReactionsPerAccount",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emojis",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT, `name` TEXT NOT NULL, `emojiHost` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiHost",
+ "columnName": "emojiHost",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emojis_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_name` ON `${TABLE_NAME}` (`name`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost",
+ "unique": false,
+ "columnNames": [
+ "emojiHost"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost` ON `${TABLE_NAME}` (`emojiHost`)"
+ },
+ {
+ "name": "index_custom_emojis_category",
+ "unique": false,
+ "columnNames": [
+ "category"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_category` ON `${TABLE_NAME}` (`category`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost_name",
+ "unique": true,
+ "columnNames": [
+ "emojiHost",
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost_name` ON `${TABLE_NAME}` (`emojiHost`, `name`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emoji_aliases",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`emojiId` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`emojiId`, `value`), FOREIGN KEY(`emojiId`) REFERENCES `custom_emojis`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "emojiId",
+ "columnName": "emojiId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emoji_aliases_emojiId_value",
+ "unique": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emoji_aliases_emojiId_value` ON `${TABLE_NAME}` (`emojiId`, `value`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "custom_emojis",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "emojiId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "notification_json_cache_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, `json` TEXT NOT NULL, `key` TEXT, `weight` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `notificationId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "json",
+ "columnName": "json",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_notification_json_cache_v1_key",
+ "unique": false,
+ "columnNames": [
+ "key"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_json_cache_v1_key` ON `${TABLE_NAME}` (`key`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_word_filters_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `filterId` TEXT NOT NULL, `phrase` TEXT NOT NULL, `wholeWord` INTEGER NOT NULL, `expiresAt` TEXT, `irreversible` INTEGER NOT NULL, `isContextHome` INTEGER NOT NULL, `isContextNotifications` INTEGER NOT NULL, `isContextPublic` INTEGER NOT NULL, `isContextThread` INTEGER NOT NULL, `isContextAccount` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `filterId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filterId",
+ "columnName": "filterId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phrase",
+ "columnName": "phrase",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wholeWord",
+ "columnName": "wholeWord",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "irreversible",
+ "columnName": "irreversible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextHome",
+ "columnName": "isContextHome",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextNotifications",
+ "columnName": "isContextNotifications",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextPublic",
+ "columnName": "isContextPublic",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextThread",
+ "columnName": "isContextThread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextAccount",
+ "columnName": "isContextAccount",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "filterId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "renote_mute_users",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `postedAt` TEXT, PRIMARY KEY(`userId`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "postedAt",
+ "columnName": "postedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_renote_mute_users_postedAt",
+ "unique": false,
+ "columnNames": [
+ "postedAt"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_postedAt` ON `${TABLE_NAME}` (`postedAt`)"
+ },
+ {
+ "name": "index_renote_mute_users_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_fedibird_capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_mastodon_instance_fedibird_capabilities_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_mastodon_instance_fedibird_capabilities_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pleroma_metadata_features",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pleroma_metadata_features_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pleroma_metadata_features_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [
+ {
+ "viewName": "user_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select user.*, nicknames.nickname from user left join nicknames on user.userName = nicknames.username and user.host = nicknames.host"
+ },
+ {
+ "viewName": "group_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.groupId, u.id as userId, u.avatarUrl, u.serverId from group_member_v1 as m \n inner join group_v1 as g\n inner join user as u\n on m.groupId = g.id\n and m.userId = u.serverId\n and g.accountId = u.accountId"
+ },
+ {
+ "viewName": "user_list_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.userListId, u.id as userId, u.avatarUrl, u.serverId from user_list_member as m \n inner join user_list as ul\n inner join user as u\n on m.userListId = ul.id\n and m.userId = u.serverId\n and ul.accountId = u.accountId"
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6422cba92843d6010b114ced1b08f79c')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/46.json b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/46.json
new file mode 100644
index 0000000000..1ca2f02793
--- /dev/null
+++ b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/46.json
@@ -0,0 +1,3878 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 46,
+ "identityHash": "f18c4b30fd0c11030b4bf1914d5a046f",
+ "entities": [
+ {
+ "tableName": "connection_information",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT NOT NULL, `instanceBaseUrl` TEXT NOT NULL, `encryptedI` TEXT NOT NULL, `viaName` TEXT, `createdAt` TEXT NOT NULL, `isDirect` INTEGER NOT NULL, `updatedAt` TEXT NOT NULL, PRIMARY KEY(`accountId`, `encryptedI`, `instanceBaseUrl`), FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceBaseUrl",
+ "columnName": "instanceBaseUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedI",
+ "columnName": "encryptedI",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viaName",
+ "columnName": "viaName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDirect",
+ "columnName": "isDirect",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "encryptedI",
+ "instanceBaseUrl"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "reaction_history",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `accountId` INTEGER, `target_post_id` TEXT, `target_user_id` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetPostId",
+ "columnName": "target_post_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetUserId",
+ "columnName": "target_user_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "reaction_user_setting",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`reaction`, `instance_domain`))",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "reaction",
+ "instance_domain"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT, `title` TEXT NOT NULL, `pageNumber` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `global_timeline_with_files` INTEGER, `global_timeline_type` TEXT, `local_timeline_with_files` INTEGER, `local_timeline_exclude_nsfw` INTEGER, `local_timeline_type` TEXT, `hybrid_timeline_withFiles` INTEGER, `hybrid_timeline_includeLocalRenotes` INTEGER, `hybrid_timeline_includeMyRenotes` INTEGER, `hybrid_timeline_includeRenotedMyRenotes` INTEGER, `hybrid_timeline_type` TEXT, `home_timeline_withFiles` INTEGER, `home_timeline_includeLocalRenotes` INTEGER, `home_timeline_includeMyRenotes` INTEGER, `home_timeline_includeRenotedMyRenotes` INTEGER, `home_timeline_type` TEXT, `user_list_timeline_listId` TEXT, `user_list_timeline_withFiles` INTEGER, `user_list_timeline_includeLocalRenotes` INTEGER, `user_list_timeline_includeMyRenotes` INTEGER, `user_list_timeline_includeRenotedMyRenotes` INTEGER, `user_list_timeline_type` TEXT, `mention_following` INTEGER, `mention_visibility` TEXT, `mention_type` TEXT, `show_noteId` TEXT, `show_type` TEXT, `tag_tag` TEXT, `tag_reply` INTEGER, `tag_renote` INTEGER, `tag_withFiles` INTEGER, `tag_poll` INTEGER, `tag_type` TEXT, `featured_offset` INTEGER, `featured_type` TEXT, `notification_following` INTEGER, `notification_markAsRead` INTEGER, `notification_type` TEXT, `user_userId` TEXT, `user_includeReplies` INTEGER, `user_includeMyRenotes` INTEGER, `user_withFiles` INTEGER, `user_type` TEXT, `search_query` TEXT, `search_host` TEXT, `search_userId` TEXT, `search_type` TEXT, `favorite_type` TEXT, `antenna_antennaId` TEXT, `antenna_type` TEXT, FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageNumber",
+ "columnName": "pageNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.withFiles",
+ "columnName": "global_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.type",
+ "columnName": "global_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.withFiles",
+ "columnName": "local_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.excludeNsfw",
+ "columnName": "local_timeline_exclude_nsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.type",
+ "columnName": "local_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.withFiles",
+ "columnName": "hybrid_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeLocalRenotes",
+ "columnName": "hybrid_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeMyRenotes",
+ "columnName": "hybrid_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeRenotedMyRenotes",
+ "columnName": "hybrid_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.type",
+ "columnName": "hybrid_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.withFiles",
+ "columnName": "home_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeLocalRenotes",
+ "columnName": "home_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeMyRenotes",
+ "columnName": "home_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeRenotedMyRenotes",
+ "columnName": "home_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.type",
+ "columnName": "home_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.listId",
+ "columnName": "user_list_timeline_listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.withFiles",
+ "columnName": "user_list_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeLocalRenotes",
+ "columnName": "user_list_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeMyRenotes",
+ "columnName": "user_list_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeRenotedMyRenotes",
+ "columnName": "user_list_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.type",
+ "columnName": "user_list_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.following",
+ "columnName": "mention_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.visibility",
+ "columnName": "mention_visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.type",
+ "columnName": "mention_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.noteId",
+ "columnName": "show_noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.type",
+ "columnName": "show_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.tag",
+ "columnName": "tag_tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.reply",
+ "columnName": "tag_reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.renote",
+ "columnName": "tag_renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.withFiles",
+ "columnName": "tag_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.poll",
+ "columnName": "tag_poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.type",
+ "columnName": "tag_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.offset",
+ "columnName": "featured_offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.type",
+ "columnName": "featured_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.following",
+ "columnName": "notification_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.markAsRead",
+ "columnName": "notification_markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.type",
+ "columnName": "notification_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.userId",
+ "columnName": "user_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeReplies",
+ "columnName": "user_includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeMyRenotes",
+ "columnName": "user_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.withFiles",
+ "columnName": "user_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.type",
+ "columnName": "user_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.query",
+ "columnName": "search_query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.host",
+ "columnName": "search_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.userId",
+ "columnName": "search_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.type",
+ "columnName": "search_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "favorite.type",
+ "columnName": "favorite_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.antennaId",
+ "columnName": "antenna_antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.type",
+ "columnName": "antenna_type",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "poll_choice_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`choice` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`choice`, `weight`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "choice",
+ "columnName": "choice",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "choice",
+ "weight",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_poll_choice_table_draft_note_id_choice",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id",
+ "choice"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_poll_choice_table_draft_note_id_choice` ON `${TABLE_NAME}` (`draft_note_id`, `choice`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, PRIMARY KEY(`userId`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_id_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_id_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL DEFAULT 'name none', `remote_file_id` TEXT, `file_path` TEXT, `is_sensitive` INTEGER, `type` TEXT, `thumbnailUrl` TEXT, `draft_note_id` INTEGER NOT NULL, `folder_id` TEXT, `file_id` INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'name none'"
+ },
+ {
+ "fieldPath": "remoteFileId",
+ "columnName": "remote_file_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileId",
+ "columnName": "file_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "file_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_table_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_table_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_note_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `visibility` TEXT NOT NULL, `text` TEXT, `cw` TEXT, `viaMobile` INTEGER, `localOnly` INTEGER, `noExtractMentions` INTEGER, `noExtractHashtags` INTEGER, `noExtractEmojis` INTEGER, `replyId` TEXT, `renoteId` TEXT, `channelId` TEXT, `scheduleWillPostAt` TEXT, `draft_note_id` INTEGER PRIMARY KEY AUTOINCREMENT, `isSensitive` INTEGER, `multiple` INTEGER, `expiresAt` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cw",
+ "columnName": "cw",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "viaMobile",
+ "columnName": "viaMobile",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localOnly",
+ "columnName": "localOnly",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractMentions",
+ "columnName": "noExtractMentions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractHashtags",
+ "columnName": "noExtractHashtags",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractEmojis",
+ "columnName": "noExtractEmojis",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "replyId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "renoteId",
+ "columnName": "renoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "scheduleWillPostAt",
+ "columnName": "scheduleWillPostAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.multiple",
+ "columnName": "multiple",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_note_table_accountId_text",
+ "unique": false,
+ "columnNames": [
+ "accountId",
+ "text"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_note_table_accountId_text` ON `${TABLE_NAME}` (`accountId`, `text`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "url_preview",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `icon` TEXT, `description` TEXT, `thumbnail` TEXT, `siteName` TEXT, PRIMARY KEY(`url`))",
+ "fields": [
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnail",
+ "columnName": "thumbnail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "siteName",
+ "columnName": "siteName",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "url"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "account_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `userName` TEXT NOT NULL, `encryptedToken` TEXT NOT NULL, `instanceType` TEXT NOT NULL DEFAULT 'misskey', `accountId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedToken",
+ "columnName": "encryptedToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceType",
+ "columnName": "instanceType",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'misskey'"
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_account_table_remoteId",
+ "unique": false,
+ "columnNames": [
+ "remoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_remoteId` ON `${TABLE_NAME}` (`remoteId`)"
+ },
+ {
+ "name": "index_account_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_account_table_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_userName` ON `${TABLE_NAME}` (`userName`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `title` TEXT NOT NULL, `weight` INTEGER NOT NULL, `pageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `withFiles` INTEGER, `excludeNsfw` INTEGER, `includeLocalRenotes` INTEGER, `includeMyRenotes` INTEGER, `includeRenotedMyRenotes` INTEGER, `listId` TEXT, `following` INTEGER, `visibility` TEXT, `noteId` TEXT, `tag` TEXT, `reply` INTEGER, `renote` INTEGER, `poll` INTEGER, `offset` INTEGER, `markAsRead` INTEGER, `userId` TEXT, `includeReplies` INTEGER, `query` TEXT, `host` TEXT, `antennaId` TEXT, `channelId` TEXT, `clipId` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageId",
+ "columnName": "pageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.withFiles",
+ "columnName": "withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.excludeNsfw",
+ "columnName": "excludeNsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeLocalRenotes",
+ "columnName": "includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeMyRenotes",
+ "columnName": "includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeRenotedMyRenotes",
+ "columnName": "includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.listId",
+ "columnName": "listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.following",
+ "columnName": "following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.reply",
+ "columnName": "reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.renote",
+ "columnName": "renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.poll",
+ "columnName": "poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.offset",
+ "columnName": "offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.markAsRead",
+ "columnName": "markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeReplies",
+ "columnName": "includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.query",
+ "columnName": "query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.antennaId",
+ "columnName": "antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.clipId",
+ "columnName": "clipId",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "pageId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_table_weight",
+ "unique": false,
+ "columnNames": [
+ "weight"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_weight` ON `${TABLE_NAME}` (`weight`)"
+ },
+ {
+ "name": "index_page_table_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "meta_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `bannerUrl` TEXT, `cacheRemoteFiles` INTEGER, `description` TEXT, `disableGlobalTimeline` INTEGER, `disableLocalTimeline` INTEGER, `disableRegistration` INTEGER, `driveCapacityPerLocalUserMb` INTEGER, `driveCapacityPerRemoteUserMb` INTEGER, `enableDiscordIntegration` INTEGER, `enableEmail` INTEGER, `enableEmojiReaction` INTEGER, `enableGithubIntegration` INTEGER, `enableRecaptcha` INTEGER, `enableServiceWorker` INTEGER, `enableTwitterIntegration` INTEGER, `errorImageUrl` TEXT, `feedbackUrl` TEXT, `iconUrl` TEXT, `maintainerEmail` TEXT, `maintainerName` TEXT, `mascotImageUrl` TEXT, `maxNoteTextLength` INTEGER, `name` TEXT, `recaptchaSiteKey` TEXT, `secure` INTEGER, `swPublicKey` TEXT, `toSUrl` TEXT, `version` TEXT NOT NULL, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cacheRemoteFiles",
+ "columnName": "cacheRemoteFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableGlobalTimeline",
+ "columnName": "disableGlobalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableLocalTimeline",
+ "columnName": "disableLocalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableRegistration",
+ "columnName": "disableRegistration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerLocalUserMb",
+ "columnName": "driveCapacityPerLocalUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerRemoteUserMb",
+ "columnName": "driveCapacityPerRemoteUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableDiscordIntegration",
+ "columnName": "enableDiscordIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmail",
+ "columnName": "enableEmail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmojiReaction",
+ "columnName": "enableEmojiReaction",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableGithubIntegration",
+ "columnName": "enableGithubIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableRecaptcha",
+ "columnName": "enableRecaptcha",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableServiceWorker",
+ "columnName": "enableServiceWorker",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableTwitterIntegration",
+ "columnName": "enableTwitterIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "errorImageUrl",
+ "columnName": "errorImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "feedbackUrl",
+ "columnName": "feedbackUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerEmail",
+ "columnName": "maintainerEmail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerName",
+ "columnName": "maintainerName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mascotImageUrl",
+ "columnName": "mascotImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxNoteTextLength",
+ "columnName": "maxNoteTextLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recaptchaSiteKey",
+ "columnName": "recaptchaSiteKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secure",
+ "columnName": "secure",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "swPublicKey",
+ "columnName": "swPublicKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "toSUrl",
+ "columnName": "toSUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "emoji_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `host` TEXT, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` TEXT, PRIMARY KEY(`name`, `instanceDomain`), FOREIGN KEY(`instanceDomain`) REFERENCES `meta_table`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_emoji_table_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "meta_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "emoji_alias_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alias` TEXT NOT NULL, `name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, PRIMARY KEY(`alias`, `name`, `instanceDomain`), FOREIGN KEY(`name`, `instanceDomain`) REFERENCES `emoji_table`(`name`, `instanceDomain`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "alias",
+ "columnName": "alias",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "alias",
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_alias_table_name_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_alias_table_name_instanceDomain` ON `${TABLE_NAME}` (`name`, `instanceDomain`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "emoji_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "name",
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "name",
+ "instanceDomain"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "unread_notifications_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, PRIMARY KEY(`accountId`, `notificationId`), FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nicknames",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`nickname` TEXT NOT NULL, `username` TEXT NOT NULL, `host` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "nickname",
+ "columnName": "nickname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_nicknames_username_host",
+ "unique": true,
+ "columnNames": [
+ "username",
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_nicknames_username_host` ON `${TABLE_NAME}` (`username`, `host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "utf8_emojis_by_amio",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`codes` TEXT NOT NULL, `name` TEXT NOT NULL, `char` TEXT NOT NULL, PRIMARY KEY(`codes`))",
+ "fields": [
+ {
+ "fieldPath": "codes",
+ "columnName": "codes",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charCode",
+ "columnName": "char",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "codes"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "drive_file_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `relatedAccountId` INTEGER NOT NULL, `createdAt` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `md5` TEXT, `size` INTEGER, `url` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `thumbnailUrl` TEXT, `folderId` TEXT, `userId` TEXT, `comment` TEXT, `blurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`relatedAccountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "relatedAccountId",
+ "columnName": "relatedAccountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "md5",
+ "columnName": "md5",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folderId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blurhash",
+ "columnName": "blurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_drive_file_v1_serverId_relatedAccountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_drive_file_v1_serverId_relatedAccountId` ON `${TABLE_NAME}` (`serverId`, `relatedAccountId`)"
+ },
+ {
+ "name": "index_drive_file_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_drive_file_v1_relatedAccountId",
+ "unique": false,
+ "columnNames": [
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_relatedAccountId` ON `${TABLE_NAME}` (`relatedAccountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "relatedAccountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`draftNoteId` INTEGER NOT NULL, `filePropertyId` INTEGER, `localFileId` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`filePropertyId`) REFERENCES `drive_file_v1`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`localFileId`) REFERENCES `draft_local_file_v2_table`(`localFileId`) ON UPDATE NO ACTION ON DELETE SET NULL )",
+ "fields": [
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draftNoteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePropertyId",
+ "columnName": "filePropertyId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId",
+ "unique": true,
+ "columnNames": [
+ "draftNoteId",
+ "filePropertyId",
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId` ON `${TABLE_NAME}` (`draftNoteId`, `filePropertyId`, `localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_draftNoteId",
+ "unique": false,
+ "columnNames": [
+ "draftNoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId` ON `${TABLE_NAME}` (`draftNoteId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_localFileId",
+ "unique": false,
+ "columnNames": [
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_localFileId` ON `${TABLE_NAME}` (`localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_filePropertyId",
+ "unique": false,
+ "columnNames": [
+ "filePropertyId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_filePropertyId` ON `${TABLE_NAME}` (`filePropertyId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "drive_file_v1",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "filePropertyId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "draft_local_file_v2_table",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "localFileId"
+ ],
+ "referencedColumns": [
+ "localFileId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_local_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `file_path` TEXT NOT NULL, `is_sensitive` INTEGER, `type` TEXT NOT NULL, `thumbnailUrl` TEXT, `folder_id` TEXT, `file_size` INTEGER, `comment` TEXT, `localFileId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "file_size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "localFileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "group_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `ownerId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_v1_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_group_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_group_v1_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_v1_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group_member_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`groupId`) REFERENCES `group_v1`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_member_v1_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_member_v1_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_group_member_v1_groupId_userId",
+ "unique": true,
+ "columnNames": [
+ "groupId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_member_v1_groupId_userId` ON `${TABLE_NAME}` (`groupId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group_v1",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `userName` TEXT NOT NULL, `name` TEXT, `avatarUrl` TEXT, `isCat` INTEGER, `isBot` INTEGER, `host` TEXT NOT NULL, `isSameHost` INTEGER NOT NULL, `avatarBlurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "avatarUrl",
+ "columnName": "avatarUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCat",
+ "columnName": "isCat",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isBot",
+ "columnName": "isBot",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSameHost",
+ "columnName": "isSameHost",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarBlurhash",
+ "columnName": "avatarBlurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_serverId_accountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_serverId_accountId` ON `${TABLE_NAME}` (`serverId`, `accountId`)"
+ },
+ {
+ "name": "index_user_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_userName` ON `${TABLE_NAME}` (`userName`)"
+ },
+ {
+ "name": "index_user_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_host",
+ "unique": false,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_detailed_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_detailed_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_detailed_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_emoji",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `userId` INTEGER NOT NULL, `aspectRatio` REAL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "aspectRatio",
+ "columnName": "aspectRatio",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_emoji_name_userId",
+ "unique": true,
+ "columnNames": [
+ "name",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_emoji_name_userId` ON `${TABLE_NAME}` (`name`, `userId`)"
+ },
+ {
+ "name": "index_user_emoji_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_emoji_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pinned_note_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`noteId` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pinned_note_id_noteId_userId",
+ "unique": true,
+ "columnNames": [
+ "noteId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_pinned_note_id_noteId_userId` ON `${TABLE_NAME}` (`noteId`, `userId`)"
+ },
+ {
+ "name": "index_pinned_note_id_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pinned_note_id_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`faviconUrl` TEXT, `iconUrl` TEXT, `name` TEXT, `softwareName` TEXT, `softwareVersion` TEXT, `themeColor` TEXT, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "faviconUrl",
+ "columnName": "faviconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareName",
+ "columnName": "softwareName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareVersion",
+ "columnName": "softwareVersion",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_instance_info_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_instance_info_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_profile_field",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `value` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_profile_field_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_profile_field_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "word_filter_regex_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pattern` TEXT NOT NULL, `parentId` INTEGER NOT NULL, PRIMARY KEY(`parentId`), FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "pattern",
+ "columnName": "pattern",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "parentId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_regex_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_regex_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_word_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`word` TEXT NOT NULL, `parentId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "word",
+ "columnName": "word",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_word_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_word_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_list_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_user_list_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list_member",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userListId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userListId`) REFERENCES `user_list`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userListId",
+ "columnName": "userListId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_member_userListId",
+ "unique": false,
+ "columnNames": [
+ "userListId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_member_userListId` ON `${TABLE_NAME}` (`userListId`)"
+ },
+ {
+ "name": "index_user_list_member_userListId_userId",
+ "unique": true,
+ "columnNames": [
+ "userListId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_member_userListId_userId` ON `${TABLE_NAME}` (`userListId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user_list",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userListId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "instance_info_v1_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `host` TEXT NOT NULL, `name` TEXT, `description` TEXT, `clientMaxBodyByteSize` INTEGER, `iconUrl` TEXT, `themeColor` TEXT, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "clientMaxBodyByteSize",
+ "columnName": "clientMaxBodyByteSize",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_instance_info_v1_table_host",
+ "unique": true,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_instance_info_v1_table_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "search_histories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `keyword` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keyword",
+ "columnName": "keyword",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_search_histories_keyword_accountId",
+ "unique": true,
+ "columnNames": [
+ "keyword",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_search_histories_keyword_accountId` ON `${TABLE_NAME}` (`keyword`, `accountId`)"
+ },
+ {
+ "name": "index_search_histories_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_search_histories_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_info_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_info_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_info_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_related_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_related_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_related_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nodeinfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `nodeInfoVersion` TEXT NOT NULL, `name` TEXT NOT NULL, `version` TEXT NOT NULL, PRIMARY KEY(`host`))",
+ "fields": [
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nodeInfoVersion",
+ "columnName": "nodeInfoVersion",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "host"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `email` TEXT NOT NULL, `version` TEXT NOT NULL, `urls_streamingApi` TEXT, `configuration_statuses_maxCharacters` INTEGER, `configuration_statuses_maxMediaAttachments` INTEGER, `configuration_polls_maxOptions` INTEGER, `configuration_polls_maxCharactersPerOption` INTEGER, `configuration_polls_minExpiration` INTEGER, `configuration_polls_maxExpiration` INTEGER, `configuration_emoji_reactions_myReactions` INTEGER, `configuration_emoji_reactions_maxReactionsPerAccount` INTEGER, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "urls.streamingApi",
+ "columnName": "urls_streamingApi",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxCharacters",
+ "columnName": "configuration_statuses_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxMediaAttachments",
+ "columnName": "configuration_statuses_maxMediaAttachments",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxOptions",
+ "columnName": "configuration_polls_maxOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxCharactersPerOption",
+ "columnName": "configuration_polls_maxCharactersPerOption",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.minExpiration",
+ "columnName": "configuration_polls_minExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxExpiration",
+ "columnName": "configuration_polls_maxExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactions",
+ "columnName": "configuration_emoji_reactions_myReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactionsPerAccount",
+ "columnName": "configuration_emoji_reactions_maxReactionsPerAccount",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emojis",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT, `name` TEXT NOT NULL, `emojiHost` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiHost",
+ "columnName": "emojiHost",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emojis_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_name` ON `${TABLE_NAME}` (`name`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost",
+ "unique": false,
+ "columnNames": [
+ "emojiHost"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost` ON `${TABLE_NAME}` (`emojiHost`)"
+ },
+ {
+ "name": "index_custom_emojis_category",
+ "unique": false,
+ "columnNames": [
+ "category"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_category` ON `${TABLE_NAME}` (`category`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost_name",
+ "unique": true,
+ "columnNames": [
+ "emojiHost",
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost_name` ON `${TABLE_NAME}` (`emojiHost`, `name`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emoji_aliases",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`emojiId` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`emojiId`, `value`), FOREIGN KEY(`emojiId`) REFERENCES `custom_emojis`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "emojiId",
+ "columnName": "emojiId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emoji_aliases_emojiId_value",
+ "unique": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emoji_aliases_emojiId_value` ON `${TABLE_NAME}` (`emojiId`, `value`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "custom_emojis",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "emojiId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "notification_json_cache_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, `json` TEXT NOT NULL, `key` TEXT, `weight` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `notificationId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "json",
+ "columnName": "json",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_notification_json_cache_v1_key",
+ "unique": false,
+ "columnNames": [
+ "key"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_json_cache_v1_key` ON `${TABLE_NAME}` (`key`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_word_filters_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `filterId` TEXT NOT NULL, `phrase` TEXT NOT NULL, `wholeWord` INTEGER NOT NULL, `expiresAt` TEXT, `irreversible` INTEGER NOT NULL, `isContextHome` INTEGER NOT NULL, `isContextNotifications` INTEGER NOT NULL, `isContextPublic` INTEGER NOT NULL, `isContextThread` INTEGER NOT NULL, `isContextAccount` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `filterId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filterId",
+ "columnName": "filterId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phrase",
+ "columnName": "phrase",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wholeWord",
+ "columnName": "wholeWord",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "irreversible",
+ "columnName": "irreversible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextHome",
+ "columnName": "isContextHome",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextNotifications",
+ "columnName": "isContextNotifications",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextPublic",
+ "columnName": "isContextPublic",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextThread",
+ "columnName": "isContextThread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextAccount",
+ "columnName": "isContextAccount",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "filterId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "renote_mute_users",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `postedAt` TEXT, PRIMARY KEY(`userId`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "postedAt",
+ "columnName": "postedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_renote_mute_users_postedAt",
+ "unique": false,
+ "columnNames": [
+ "postedAt"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_postedAt` ON `${TABLE_NAME}` (`postedAt`)"
+ },
+ {
+ "name": "index_renote_mute_users_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_fedibird_capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_mastodon_instance_fedibird_capabilities_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_mastodon_instance_fedibird_capabilities_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pleroma_metadata_features",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pleroma_metadata_features_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pleroma_metadata_features_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [
+ {
+ "viewName": "user_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select user.*, nicknames.nickname from user left join nicknames on user.userName = nicknames.username and user.host = nicknames.host"
+ },
+ {
+ "viewName": "group_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.groupId, u.id as userId, u.avatarUrl, u.serverId from group_member_v1 as m \n inner join group_v1 as g\n inner join user as u\n on m.groupId = g.id\n and m.userId = u.serverId\n and g.accountId = u.accountId"
+ },
+ {
+ "viewName": "user_list_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.userListId, u.id as userId, u.avatarUrl, u.serverId from user_list_member as m \n inner join user_list as ul\n inner join user as u\n on m.userListId = ul.id\n and m.userId = u.serverId\n and ul.accountId = u.accountId"
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f18c4b30fd0c11030b4bf1914d5a046f')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/47.json b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/47.json
new file mode 100644
index 0000000000..60f75a0d6b
--- /dev/null
+++ b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/47.json
@@ -0,0 +1,3884 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 47,
+ "identityHash": "74b428945f0dd11983704517d6b662a3",
+ "entities": [
+ {
+ "tableName": "connection_information",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT NOT NULL, `instanceBaseUrl` TEXT NOT NULL, `encryptedI` TEXT NOT NULL, `viaName` TEXT, `createdAt` TEXT NOT NULL, `isDirect` INTEGER NOT NULL, `updatedAt` TEXT NOT NULL, PRIMARY KEY(`accountId`, `encryptedI`, `instanceBaseUrl`), FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceBaseUrl",
+ "columnName": "instanceBaseUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedI",
+ "columnName": "encryptedI",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viaName",
+ "columnName": "viaName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDirect",
+ "columnName": "isDirect",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "encryptedI",
+ "instanceBaseUrl"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "reaction_history",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `accountId` INTEGER, `target_post_id` TEXT, `target_user_id` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetPostId",
+ "columnName": "target_post_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetUserId",
+ "columnName": "target_user_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "reaction_user_setting",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`reaction`, `instance_domain`))",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "reaction",
+ "instance_domain"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT, `title` TEXT NOT NULL, `pageNumber` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `global_timeline_with_files` INTEGER, `global_timeline_type` TEXT, `local_timeline_with_files` INTEGER, `local_timeline_exclude_nsfw` INTEGER, `local_timeline_type` TEXT, `hybrid_timeline_withFiles` INTEGER, `hybrid_timeline_includeLocalRenotes` INTEGER, `hybrid_timeline_includeMyRenotes` INTEGER, `hybrid_timeline_includeRenotedMyRenotes` INTEGER, `hybrid_timeline_type` TEXT, `home_timeline_withFiles` INTEGER, `home_timeline_includeLocalRenotes` INTEGER, `home_timeline_includeMyRenotes` INTEGER, `home_timeline_includeRenotedMyRenotes` INTEGER, `home_timeline_type` TEXT, `user_list_timeline_listId` TEXT, `user_list_timeline_withFiles` INTEGER, `user_list_timeline_includeLocalRenotes` INTEGER, `user_list_timeline_includeMyRenotes` INTEGER, `user_list_timeline_includeRenotedMyRenotes` INTEGER, `user_list_timeline_type` TEXT, `mention_following` INTEGER, `mention_visibility` TEXT, `mention_type` TEXT, `show_noteId` TEXT, `show_type` TEXT, `tag_tag` TEXT, `tag_reply` INTEGER, `tag_renote` INTEGER, `tag_withFiles` INTEGER, `tag_poll` INTEGER, `tag_type` TEXT, `featured_offset` INTEGER, `featured_type` TEXT, `notification_following` INTEGER, `notification_markAsRead` INTEGER, `notification_type` TEXT, `user_userId` TEXT, `user_includeReplies` INTEGER, `user_includeMyRenotes` INTEGER, `user_withFiles` INTEGER, `user_type` TEXT, `search_query` TEXT, `search_host` TEXT, `search_userId` TEXT, `search_type` TEXT, `favorite_type` TEXT, `antenna_antennaId` TEXT, `antenna_type` TEXT, FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageNumber",
+ "columnName": "pageNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.withFiles",
+ "columnName": "global_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.type",
+ "columnName": "global_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.withFiles",
+ "columnName": "local_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.excludeNsfw",
+ "columnName": "local_timeline_exclude_nsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.type",
+ "columnName": "local_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.withFiles",
+ "columnName": "hybrid_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeLocalRenotes",
+ "columnName": "hybrid_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeMyRenotes",
+ "columnName": "hybrid_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeRenotedMyRenotes",
+ "columnName": "hybrid_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.type",
+ "columnName": "hybrid_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.withFiles",
+ "columnName": "home_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeLocalRenotes",
+ "columnName": "home_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeMyRenotes",
+ "columnName": "home_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeRenotedMyRenotes",
+ "columnName": "home_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.type",
+ "columnName": "home_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.listId",
+ "columnName": "user_list_timeline_listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.withFiles",
+ "columnName": "user_list_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeLocalRenotes",
+ "columnName": "user_list_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeMyRenotes",
+ "columnName": "user_list_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeRenotedMyRenotes",
+ "columnName": "user_list_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.type",
+ "columnName": "user_list_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.following",
+ "columnName": "mention_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.visibility",
+ "columnName": "mention_visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.type",
+ "columnName": "mention_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.noteId",
+ "columnName": "show_noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.type",
+ "columnName": "show_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.tag",
+ "columnName": "tag_tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.reply",
+ "columnName": "tag_reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.renote",
+ "columnName": "tag_renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.withFiles",
+ "columnName": "tag_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.poll",
+ "columnName": "tag_poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.type",
+ "columnName": "tag_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.offset",
+ "columnName": "featured_offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.type",
+ "columnName": "featured_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.following",
+ "columnName": "notification_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.markAsRead",
+ "columnName": "notification_markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.type",
+ "columnName": "notification_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.userId",
+ "columnName": "user_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeReplies",
+ "columnName": "user_includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeMyRenotes",
+ "columnName": "user_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.withFiles",
+ "columnName": "user_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.type",
+ "columnName": "user_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.query",
+ "columnName": "search_query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.host",
+ "columnName": "search_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.userId",
+ "columnName": "search_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.type",
+ "columnName": "search_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "favorite.type",
+ "columnName": "favorite_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.antennaId",
+ "columnName": "antenna_antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.type",
+ "columnName": "antenna_type",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "poll_choice_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`choice` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`choice`, `weight`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "choice",
+ "columnName": "choice",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "choice",
+ "weight",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_poll_choice_table_draft_note_id_choice",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id",
+ "choice"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_poll_choice_table_draft_note_id_choice` ON `${TABLE_NAME}` (`draft_note_id`, `choice`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, PRIMARY KEY(`userId`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_id_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_id_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL DEFAULT 'name none', `remote_file_id` TEXT, `file_path` TEXT, `is_sensitive` INTEGER, `type` TEXT, `thumbnailUrl` TEXT, `draft_note_id` INTEGER NOT NULL, `folder_id` TEXT, `file_id` INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'name none'"
+ },
+ {
+ "fieldPath": "remoteFileId",
+ "columnName": "remote_file_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileId",
+ "columnName": "file_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "file_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_table_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_table_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_note_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `visibility` TEXT NOT NULL, `text` TEXT, `cw` TEXT, `viaMobile` INTEGER, `localOnly` INTEGER, `noExtractMentions` INTEGER, `noExtractHashtags` INTEGER, `noExtractEmojis` INTEGER, `replyId` TEXT, `renoteId` TEXT, `channelId` TEXT, `scheduleWillPostAt` TEXT, `draft_note_id` INTEGER PRIMARY KEY AUTOINCREMENT, `isSensitive` INTEGER, `multiple` INTEGER, `expiresAt` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cw",
+ "columnName": "cw",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "viaMobile",
+ "columnName": "viaMobile",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localOnly",
+ "columnName": "localOnly",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractMentions",
+ "columnName": "noExtractMentions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractHashtags",
+ "columnName": "noExtractHashtags",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractEmojis",
+ "columnName": "noExtractEmojis",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "replyId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "renoteId",
+ "columnName": "renoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "scheduleWillPostAt",
+ "columnName": "scheduleWillPostAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.multiple",
+ "columnName": "multiple",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_note_table_accountId_text",
+ "unique": false,
+ "columnNames": [
+ "accountId",
+ "text"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_note_table_accountId_text` ON `${TABLE_NAME}` (`accountId`, `text`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "url_preview",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `icon` TEXT, `description` TEXT, `thumbnail` TEXT, `siteName` TEXT, PRIMARY KEY(`url`))",
+ "fields": [
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnail",
+ "columnName": "thumbnail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "siteName",
+ "columnName": "siteName",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "url"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "account_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `userName` TEXT NOT NULL, `encryptedToken` TEXT NOT NULL, `instanceType` TEXT NOT NULL DEFAULT 'misskey', `accountId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedToken",
+ "columnName": "encryptedToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceType",
+ "columnName": "instanceType",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'misskey'"
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_account_table_remoteId",
+ "unique": false,
+ "columnNames": [
+ "remoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_remoteId` ON `${TABLE_NAME}` (`remoteId`)"
+ },
+ {
+ "name": "index_account_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_account_table_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_userName` ON `${TABLE_NAME}` (`userName`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `title` TEXT NOT NULL, `weight` INTEGER NOT NULL, `isSavePagePosition` INTEGER, `pageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `withFiles` INTEGER, `excludeNsfw` INTEGER, `includeLocalRenotes` INTEGER, `includeMyRenotes` INTEGER, `includeRenotedMyRenotes` INTEGER, `listId` TEXT, `following` INTEGER, `visibility` TEXT, `noteId` TEXT, `tag` TEXT, `reply` INTEGER, `renote` INTEGER, `poll` INTEGER, `offset` INTEGER, `markAsRead` INTEGER, `userId` TEXT, `includeReplies` INTEGER, `query` TEXT, `host` TEXT, `antennaId` TEXT, `channelId` TEXT, `clipId` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSavePagePosition",
+ "columnName": "isSavePagePosition",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageId",
+ "columnName": "pageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.withFiles",
+ "columnName": "withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.excludeNsfw",
+ "columnName": "excludeNsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeLocalRenotes",
+ "columnName": "includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeMyRenotes",
+ "columnName": "includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeRenotedMyRenotes",
+ "columnName": "includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.listId",
+ "columnName": "listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.following",
+ "columnName": "following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.reply",
+ "columnName": "reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.renote",
+ "columnName": "renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.poll",
+ "columnName": "poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.offset",
+ "columnName": "offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.markAsRead",
+ "columnName": "markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeReplies",
+ "columnName": "includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.query",
+ "columnName": "query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.antennaId",
+ "columnName": "antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.clipId",
+ "columnName": "clipId",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "pageId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_table_weight",
+ "unique": false,
+ "columnNames": [
+ "weight"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_weight` ON `${TABLE_NAME}` (`weight`)"
+ },
+ {
+ "name": "index_page_table_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "meta_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `bannerUrl` TEXT, `cacheRemoteFiles` INTEGER, `description` TEXT, `disableGlobalTimeline` INTEGER, `disableLocalTimeline` INTEGER, `disableRegistration` INTEGER, `driveCapacityPerLocalUserMb` INTEGER, `driveCapacityPerRemoteUserMb` INTEGER, `enableDiscordIntegration` INTEGER, `enableEmail` INTEGER, `enableEmojiReaction` INTEGER, `enableGithubIntegration` INTEGER, `enableRecaptcha` INTEGER, `enableServiceWorker` INTEGER, `enableTwitterIntegration` INTEGER, `errorImageUrl` TEXT, `feedbackUrl` TEXT, `iconUrl` TEXT, `maintainerEmail` TEXT, `maintainerName` TEXT, `mascotImageUrl` TEXT, `maxNoteTextLength` INTEGER, `name` TEXT, `recaptchaSiteKey` TEXT, `secure` INTEGER, `swPublicKey` TEXT, `toSUrl` TEXT, `version` TEXT NOT NULL, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cacheRemoteFiles",
+ "columnName": "cacheRemoteFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableGlobalTimeline",
+ "columnName": "disableGlobalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableLocalTimeline",
+ "columnName": "disableLocalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableRegistration",
+ "columnName": "disableRegistration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerLocalUserMb",
+ "columnName": "driveCapacityPerLocalUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerRemoteUserMb",
+ "columnName": "driveCapacityPerRemoteUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableDiscordIntegration",
+ "columnName": "enableDiscordIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmail",
+ "columnName": "enableEmail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmojiReaction",
+ "columnName": "enableEmojiReaction",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableGithubIntegration",
+ "columnName": "enableGithubIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableRecaptcha",
+ "columnName": "enableRecaptcha",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableServiceWorker",
+ "columnName": "enableServiceWorker",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableTwitterIntegration",
+ "columnName": "enableTwitterIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "errorImageUrl",
+ "columnName": "errorImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "feedbackUrl",
+ "columnName": "feedbackUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerEmail",
+ "columnName": "maintainerEmail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerName",
+ "columnName": "maintainerName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mascotImageUrl",
+ "columnName": "mascotImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxNoteTextLength",
+ "columnName": "maxNoteTextLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recaptchaSiteKey",
+ "columnName": "recaptchaSiteKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secure",
+ "columnName": "secure",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "swPublicKey",
+ "columnName": "swPublicKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "toSUrl",
+ "columnName": "toSUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "emoji_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `host` TEXT, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` TEXT, PRIMARY KEY(`name`, `instanceDomain`), FOREIGN KEY(`instanceDomain`) REFERENCES `meta_table`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_emoji_table_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "meta_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "emoji_alias_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alias` TEXT NOT NULL, `name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, PRIMARY KEY(`alias`, `name`, `instanceDomain`), FOREIGN KEY(`name`, `instanceDomain`) REFERENCES `emoji_table`(`name`, `instanceDomain`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "alias",
+ "columnName": "alias",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "alias",
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_alias_table_name_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_alias_table_name_instanceDomain` ON `${TABLE_NAME}` (`name`, `instanceDomain`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "emoji_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "name",
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "name",
+ "instanceDomain"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "unread_notifications_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, PRIMARY KEY(`accountId`, `notificationId`), FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nicknames",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`nickname` TEXT NOT NULL, `username` TEXT NOT NULL, `host` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "nickname",
+ "columnName": "nickname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_nicknames_username_host",
+ "unique": true,
+ "columnNames": [
+ "username",
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_nicknames_username_host` ON `${TABLE_NAME}` (`username`, `host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "utf8_emojis_by_amio",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`codes` TEXT NOT NULL, `name` TEXT NOT NULL, `char` TEXT NOT NULL, PRIMARY KEY(`codes`))",
+ "fields": [
+ {
+ "fieldPath": "codes",
+ "columnName": "codes",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charCode",
+ "columnName": "char",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "codes"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "drive_file_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `relatedAccountId` INTEGER NOT NULL, `createdAt` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `md5` TEXT, `size` INTEGER, `url` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `thumbnailUrl` TEXT, `folderId` TEXT, `userId` TEXT, `comment` TEXT, `blurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`relatedAccountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "relatedAccountId",
+ "columnName": "relatedAccountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "md5",
+ "columnName": "md5",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folderId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blurhash",
+ "columnName": "blurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_drive_file_v1_serverId_relatedAccountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_drive_file_v1_serverId_relatedAccountId` ON `${TABLE_NAME}` (`serverId`, `relatedAccountId`)"
+ },
+ {
+ "name": "index_drive_file_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_drive_file_v1_relatedAccountId",
+ "unique": false,
+ "columnNames": [
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_relatedAccountId` ON `${TABLE_NAME}` (`relatedAccountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "relatedAccountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`draftNoteId` INTEGER NOT NULL, `filePropertyId` INTEGER, `localFileId` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`filePropertyId`) REFERENCES `drive_file_v1`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`localFileId`) REFERENCES `draft_local_file_v2_table`(`localFileId`) ON UPDATE NO ACTION ON DELETE SET NULL )",
+ "fields": [
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draftNoteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePropertyId",
+ "columnName": "filePropertyId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId",
+ "unique": true,
+ "columnNames": [
+ "draftNoteId",
+ "filePropertyId",
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId` ON `${TABLE_NAME}` (`draftNoteId`, `filePropertyId`, `localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_draftNoteId",
+ "unique": false,
+ "columnNames": [
+ "draftNoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId` ON `${TABLE_NAME}` (`draftNoteId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_localFileId",
+ "unique": false,
+ "columnNames": [
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_localFileId` ON `${TABLE_NAME}` (`localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_filePropertyId",
+ "unique": false,
+ "columnNames": [
+ "filePropertyId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_filePropertyId` ON `${TABLE_NAME}` (`filePropertyId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "drive_file_v1",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "filePropertyId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "draft_local_file_v2_table",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "localFileId"
+ ],
+ "referencedColumns": [
+ "localFileId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_local_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `file_path` TEXT NOT NULL, `is_sensitive` INTEGER, `type` TEXT NOT NULL, `thumbnailUrl` TEXT, `folder_id` TEXT, `file_size` INTEGER, `comment` TEXT, `localFileId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "file_size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "localFileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "group_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `ownerId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_v1_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_group_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_group_v1_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_v1_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group_member_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`groupId`) REFERENCES `group_v1`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_member_v1_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_member_v1_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_group_member_v1_groupId_userId",
+ "unique": true,
+ "columnNames": [
+ "groupId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_member_v1_groupId_userId` ON `${TABLE_NAME}` (`groupId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group_v1",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `userName` TEXT NOT NULL, `name` TEXT, `avatarUrl` TEXT, `isCat` INTEGER, `isBot` INTEGER, `host` TEXT NOT NULL, `isSameHost` INTEGER NOT NULL, `avatarBlurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "avatarUrl",
+ "columnName": "avatarUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCat",
+ "columnName": "isCat",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isBot",
+ "columnName": "isBot",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSameHost",
+ "columnName": "isSameHost",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarBlurhash",
+ "columnName": "avatarBlurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_serverId_accountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_serverId_accountId` ON `${TABLE_NAME}` (`serverId`, `accountId`)"
+ },
+ {
+ "name": "index_user_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_userName` ON `${TABLE_NAME}` (`userName`)"
+ },
+ {
+ "name": "index_user_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_host",
+ "unique": false,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_detailed_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_detailed_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_detailed_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_emoji",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `userId` INTEGER NOT NULL, `aspectRatio` REAL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "aspectRatio",
+ "columnName": "aspectRatio",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_emoji_name_userId",
+ "unique": true,
+ "columnNames": [
+ "name",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_emoji_name_userId` ON `${TABLE_NAME}` (`name`, `userId`)"
+ },
+ {
+ "name": "index_user_emoji_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_emoji_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pinned_note_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`noteId` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pinned_note_id_noteId_userId",
+ "unique": true,
+ "columnNames": [
+ "noteId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_pinned_note_id_noteId_userId` ON `${TABLE_NAME}` (`noteId`, `userId`)"
+ },
+ {
+ "name": "index_pinned_note_id_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pinned_note_id_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`faviconUrl` TEXT, `iconUrl` TEXT, `name` TEXT, `softwareName` TEXT, `softwareVersion` TEXT, `themeColor` TEXT, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "faviconUrl",
+ "columnName": "faviconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareName",
+ "columnName": "softwareName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareVersion",
+ "columnName": "softwareVersion",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_instance_info_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_instance_info_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_profile_field",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `value` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_profile_field_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_profile_field_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "word_filter_regex_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pattern` TEXT NOT NULL, `parentId` INTEGER NOT NULL, PRIMARY KEY(`parentId`), FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "pattern",
+ "columnName": "pattern",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "parentId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_regex_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_regex_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_word_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`word` TEXT NOT NULL, `parentId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "word",
+ "columnName": "word",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_word_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_word_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_list_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_user_list_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list_member",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userListId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userListId`) REFERENCES `user_list`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userListId",
+ "columnName": "userListId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_member_userListId",
+ "unique": false,
+ "columnNames": [
+ "userListId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_member_userListId` ON `${TABLE_NAME}` (`userListId`)"
+ },
+ {
+ "name": "index_user_list_member_userListId_userId",
+ "unique": true,
+ "columnNames": [
+ "userListId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_member_userListId_userId` ON `${TABLE_NAME}` (`userListId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user_list",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userListId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "instance_info_v1_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `host` TEXT NOT NULL, `name` TEXT, `description` TEXT, `clientMaxBodyByteSize` INTEGER, `iconUrl` TEXT, `themeColor` TEXT, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "clientMaxBodyByteSize",
+ "columnName": "clientMaxBodyByteSize",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_instance_info_v1_table_host",
+ "unique": true,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_instance_info_v1_table_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "search_histories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `keyword` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keyword",
+ "columnName": "keyword",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_search_histories_keyword_accountId",
+ "unique": true,
+ "columnNames": [
+ "keyword",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_search_histories_keyword_accountId` ON `${TABLE_NAME}` (`keyword`, `accountId`)"
+ },
+ {
+ "name": "index_search_histories_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_search_histories_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_info_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_info_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_info_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_related_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_related_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_related_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nodeinfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `nodeInfoVersion` TEXT NOT NULL, `name` TEXT NOT NULL, `version` TEXT NOT NULL, PRIMARY KEY(`host`))",
+ "fields": [
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nodeInfoVersion",
+ "columnName": "nodeInfoVersion",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "host"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `email` TEXT NOT NULL, `version` TEXT NOT NULL, `urls_streamingApi` TEXT, `configuration_statuses_maxCharacters` INTEGER, `configuration_statuses_maxMediaAttachments` INTEGER, `configuration_polls_maxOptions` INTEGER, `configuration_polls_maxCharactersPerOption` INTEGER, `configuration_polls_minExpiration` INTEGER, `configuration_polls_maxExpiration` INTEGER, `configuration_emoji_reactions_myReactions` INTEGER, `configuration_emoji_reactions_maxReactionsPerAccount` INTEGER, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "urls.streamingApi",
+ "columnName": "urls_streamingApi",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxCharacters",
+ "columnName": "configuration_statuses_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxMediaAttachments",
+ "columnName": "configuration_statuses_maxMediaAttachments",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxOptions",
+ "columnName": "configuration_polls_maxOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxCharactersPerOption",
+ "columnName": "configuration_polls_maxCharactersPerOption",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.minExpiration",
+ "columnName": "configuration_polls_minExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxExpiration",
+ "columnName": "configuration_polls_maxExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactions",
+ "columnName": "configuration_emoji_reactions_myReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactionsPerAccount",
+ "columnName": "configuration_emoji_reactions_maxReactionsPerAccount",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emojis",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT, `name` TEXT NOT NULL, `emojiHost` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiHost",
+ "columnName": "emojiHost",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emojis_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_name` ON `${TABLE_NAME}` (`name`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost",
+ "unique": false,
+ "columnNames": [
+ "emojiHost"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost` ON `${TABLE_NAME}` (`emojiHost`)"
+ },
+ {
+ "name": "index_custom_emojis_category",
+ "unique": false,
+ "columnNames": [
+ "category"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_category` ON `${TABLE_NAME}` (`category`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost_name",
+ "unique": true,
+ "columnNames": [
+ "emojiHost",
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost_name` ON `${TABLE_NAME}` (`emojiHost`, `name`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emoji_aliases",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`emojiId` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`emojiId`, `value`), FOREIGN KEY(`emojiId`) REFERENCES `custom_emojis`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "emojiId",
+ "columnName": "emojiId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emoji_aliases_emojiId_value",
+ "unique": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emoji_aliases_emojiId_value` ON `${TABLE_NAME}` (`emojiId`, `value`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "custom_emojis",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "emojiId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "notification_json_cache_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, `json` TEXT NOT NULL, `key` TEXT, `weight` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `notificationId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "json",
+ "columnName": "json",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_notification_json_cache_v1_key",
+ "unique": false,
+ "columnNames": [
+ "key"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_json_cache_v1_key` ON `${TABLE_NAME}` (`key`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_word_filters_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `filterId` TEXT NOT NULL, `phrase` TEXT NOT NULL, `wholeWord` INTEGER NOT NULL, `expiresAt` TEXT, `irreversible` INTEGER NOT NULL, `isContextHome` INTEGER NOT NULL, `isContextNotifications` INTEGER NOT NULL, `isContextPublic` INTEGER NOT NULL, `isContextThread` INTEGER NOT NULL, `isContextAccount` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `filterId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filterId",
+ "columnName": "filterId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phrase",
+ "columnName": "phrase",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wholeWord",
+ "columnName": "wholeWord",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "irreversible",
+ "columnName": "irreversible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextHome",
+ "columnName": "isContextHome",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextNotifications",
+ "columnName": "isContextNotifications",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextPublic",
+ "columnName": "isContextPublic",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextThread",
+ "columnName": "isContextThread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextAccount",
+ "columnName": "isContextAccount",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "filterId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "renote_mute_users",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `postedAt` TEXT, PRIMARY KEY(`userId`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "postedAt",
+ "columnName": "postedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_renote_mute_users_postedAt",
+ "unique": false,
+ "columnNames": [
+ "postedAt"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_postedAt` ON `${TABLE_NAME}` (`postedAt`)"
+ },
+ {
+ "name": "index_renote_mute_users_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_fedibird_capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_mastodon_instance_fedibird_capabilities_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_mastodon_instance_fedibird_capabilities_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pleroma_metadata_features",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pleroma_metadata_features_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pleroma_metadata_features_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [
+ {
+ "viewName": "user_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select user.*, nicknames.nickname from user left join nicknames on user.userName = nicknames.username and user.host = nicknames.host"
+ },
+ {
+ "viewName": "group_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.groupId, u.id as userId, u.avatarUrl, u.serverId from group_member_v1 as m \n inner join group_v1 as g\n inner join user as u\n on m.groupId = g.id\n and m.userId = u.serverId\n and g.accountId = u.accountId"
+ },
+ {
+ "viewName": "user_list_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.userListId, u.id as userId, u.avatarUrl, u.serverId from user_list_member as m \n inner join user_list as ul\n inner join user as u\n on m.userListId = ul.id\n and m.userId = u.serverId\n and ul.accountId = u.accountId"
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '74b428945f0dd11983704517d6b662a3')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/48.json b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/48.json
new file mode 100644
index 0000000000..515f397243
--- /dev/null
+++ b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/48.json
@@ -0,0 +1,3890 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 48,
+ "identityHash": "eeb4c81798aaf018955eae65753e8534",
+ "entities": [
+ {
+ "tableName": "connection_information",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT NOT NULL, `instanceBaseUrl` TEXT NOT NULL, `encryptedI` TEXT NOT NULL, `viaName` TEXT, `createdAt` TEXT NOT NULL, `isDirect` INTEGER NOT NULL, `updatedAt` TEXT NOT NULL, PRIMARY KEY(`accountId`, `encryptedI`, `instanceBaseUrl`), FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceBaseUrl",
+ "columnName": "instanceBaseUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedI",
+ "columnName": "encryptedI",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viaName",
+ "columnName": "viaName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDirect",
+ "columnName": "isDirect",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "encryptedI",
+ "instanceBaseUrl"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "reaction_history",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `accountId` INTEGER, `target_post_id` TEXT, `target_user_id` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetPostId",
+ "columnName": "target_post_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetUserId",
+ "columnName": "target_user_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "reaction_user_setting",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`reaction`, `instance_domain`))",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "reaction",
+ "instance_domain"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT, `title` TEXT NOT NULL, `pageNumber` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `global_timeline_with_files` INTEGER, `global_timeline_type` TEXT, `local_timeline_with_files` INTEGER, `local_timeline_exclude_nsfw` INTEGER, `local_timeline_type` TEXT, `hybrid_timeline_withFiles` INTEGER, `hybrid_timeline_includeLocalRenotes` INTEGER, `hybrid_timeline_includeMyRenotes` INTEGER, `hybrid_timeline_includeRenotedMyRenotes` INTEGER, `hybrid_timeline_type` TEXT, `home_timeline_withFiles` INTEGER, `home_timeline_includeLocalRenotes` INTEGER, `home_timeline_includeMyRenotes` INTEGER, `home_timeline_includeRenotedMyRenotes` INTEGER, `home_timeline_type` TEXT, `user_list_timeline_listId` TEXT, `user_list_timeline_withFiles` INTEGER, `user_list_timeline_includeLocalRenotes` INTEGER, `user_list_timeline_includeMyRenotes` INTEGER, `user_list_timeline_includeRenotedMyRenotes` INTEGER, `user_list_timeline_type` TEXT, `mention_following` INTEGER, `mention_visibility` TEXT, `mention_type` TEXT, `show_noteId` TEXT, `show_type` TEXT, `tag_tag` TEXT, `tag_reply` INTEGER, `tag_renote` INTEGER, `tag_withFiles` INTEGER, `tag_poll` INTEGER, `tag_type` TEXT, `featured_offset` INTEGER, `featured_type` TEXT, `notification_following` INTEGER, `notification_markAsRead` INTEGER, `notification_type` TEXT, `user_userId` TEXT, `user_includeReplies` INTEGER, `user_includeMyRenotes` INTEGER, `user_withFiles` INTEGER, `user_type` TEXT, `search_query` TEXT, `search_host` TEXT, `search_userId` TEXT, `search_type` TEXT, `favorite_type` TEXT, `antenna_antennaId` TEXT, `antenna_type` TEXT, FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageNumber",
+ "columnName": "pageNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.withFiles",
+ "columnName": "global_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.type",
+ "columnName": "global_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.withFiles",
+ "columnName": "local_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.excludeNsfw",
+ "columnName": "local_timeline_exclude_nsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.type",
+ "columnName": "local_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.withFiles",
+ "columnName": "hybrid_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeLocalRenotes",
+ "columnName": "hybrid_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeMyRenotes",
+ "columnName": "hybrid_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeRenotedMyRenotes",
+ "columnName": "hybrid_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.type",
+ "columnName": "hybrid_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.withFiles",
+ "columnName": "home_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeLocalRenotes",
+ "columnName": "home_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeMyRenotes",
+ "columnName": "home_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeRenotedMyRenotes",
+ "columnName": "home_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.type",
+ "columnName": "home_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.listId",
+ "columnName": "user_list_timeline_listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.withFiles",
+ "columnName": "user_list_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeLocalRenotes",
+ "columnName": "user_list_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeMyRenotes",
+ "columnName": "user_list_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeRenotedMyRenotes",
+ "columnName": "user_list_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.type",
+ "columnName": "user_list_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.following",
+ "columnName": "mention_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.visibility",
+ "columnName": "mention_visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.type",
+ "columnName": "mention_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.noteId",
+ "columnName": "show_noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.type",
+ "columnName": "show_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.tag",
+ "columnName": "tag_tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.reply",
+ "columnName": "tag_reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.renote",
+ "columnName": "tag_renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.withFiles",
+ "columnName": "tag_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.poll",
+ "columnName": "tag_poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.type",
+ "columnName": "tag_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.offset",
+ "columnName": "featured_offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.type",
+ "columnName": "featured_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.following",
+ "columnName": "notification_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.markAsRead",
+ "columnName": "notification_markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.type",
+ "columnName": "notification_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.userId",
+ "columnName": "user_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeReplies",
+ "columnName": "user_includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeMyRenotes",
+ "columnName": "user_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.withFiles",
+ "columnName": "user_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.type",
+ "columnName": "user_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.query",
+ "columnName": "search_query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.host",
+ "columnName": "search_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.userId",
+ "columnName": "search_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.type",
+ "columnName": "search_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "favorite.type",
+ "columnName": "favorite_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.antennaId",
+ "columnName": "antenna_antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.type",
+ "columnName": "antenna_type",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "poll_choice_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`choice` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`choice`, `weight`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "choice",
+ "columnName": "choice",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "choice",
+ "weight",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_poll_choice_table_draft_note_id_choice",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id",
+ "choice"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_poll_choice_table_draft_note_id_choice` ON `${TABLE_NAME}` (`draft_note_id`, `choice`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, PRIMARY KEY(`userId`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_id_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_id_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL DEFAULT 'name none', `remote_file_id` TEXT, `file_path` TEXT, `is_sensitive` INTEGER, `type` TEXT, `thumbnailUrl` TEXT, `draft_note_id` INTEGER NOT NULL, `folder_id` TEXT, `file_id` INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'name none'"
+ },
+ {
+ "fieldPath": "remoteFileId",
+ "columnName": "remote_file_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileId",
+ "columnName": "file_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "file_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_table_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_table_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_note_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `visibility` TEXT NOT NULL, `text` TEXT, `cw` TEXT, `viaMobile` INTEGER, `localOnly` INTEGER, `noExtractMentions` INTEGER, `noExtractHashtags` INTEGER, `noExtractEmojis` INTEGER, `replyId` TEXT, `renoteId` TEXT, `channelId` TEXT, `scheduleWillPostAt` TEXT, `draft_note_id` INTEGER PRIMARY KEY AUTOINCREMENT, `isSensitive` INTEGER, `multiple` INTEGER, `expiresAt` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cw",
+ "columnName": "cw",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "viaMobile",
+ "columnName": "viaMobile",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localOnly",
+ "columnName": "localOnly",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractMentions",
+ "columnName": "noExtractMentions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractHashtags",
+ "columnName": "noExtractHashtags",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractEmojis",
+ "columnName": "noExtractEmojis",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "replyId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "renoteId",
+ "columnName": "renoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "scheduleWillPostAt",
+ "columnName": "scheduleWillPostAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.multiple",
+ "columnName": "multiple",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_note_table_accountId_text",
+ "unique": false,
+ "columnNames": [
+ "accountId",
+ "text"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_note_table_accountId_text` ON `${TABLE_NAME}` (`accountId`, `text`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "url_preview",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `icon` TEXT, `description` TEXT, `thumbnail` TEXT, `siteName` TEXT, PRIMARY KEY(`url`))",
+ "fields": [
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnail",
+ "columnName": "thumbnail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "siteName",
+ "columnName": "siteName",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "url"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "account_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `userName` TEXT NOT NULL, `encryptedToken` TEXT NOT NULL, `instanceType` TEXT NOT NULL DEFAULT 'misskey', `accountId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedToken",
+ "columnName": "encryptedToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceType",
+ "columnName": "instanceType",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'misskey'"
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_account_table_remoteId",
+ "unique": false,
+ "columnNames": [
+ "remoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_remoteId` ON `${TABLE_NAME}` (`remoteId`)"
+ },
+ {
+ "name": "index_account_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_account_table_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_userName` ON `${TABLE_NAME}` (`userName`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `title` TEXT NOT NULL, `weight` INTEGER NOT NULL, `isSavePagePosition` INTEGER, `attachedAccountId` INTEGER, `pageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `withFiles` INTEGER, `excludeNsfw` INTEGER, `includeLocalRenotes` INTEGER, `includeMyRenotes` INTEGER, `includeRenotedMyRenotes` INTEGER, `listId` TEXT, `following` INTEGER, `visibility` TEXT, `noteId` TEXT, `tag` TEXT, `reply` INTEGER, `renote` INTEGER, `poll` INTEGER, `offset` INTEGER, `markAsRead` INTEGER, `userId` TEXT, `includeReplies` INTEGER, `query` TEXT, `host` TEXT, `antennaId` TEXT, `channelId` TEXT, `clipId` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSavePagePosition",
+ "columnName": "isSavePagePosition",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachedAccountId",
+ "columnName": "attachedAccountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageId",
+ "columnName": "pageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.withFiles",
+ "columnName": "withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.excludeNsfw",
+ "columnName": "excludeNsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeLocalRenotes",
+ "columnName": "includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeMyRenotes",
+ "columnName": "includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeRenotedMyRenotes",
+ "columnName": "includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.listId",
+ "columnName": "listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.following",
+ "columnName": "following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.reply",
+ "columnName": "reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.renote",
+ "columnName": "renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.poll",
+ "columnName": "poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.offset",
+ "columnName": "offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.markAsRead",
+ "columnName": "markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeReplies",
+ "columnName": "includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.query",
+ "columnName": "query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.antennaId",
+ "columnName": "antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.clipId",
+ "columnName": "clipId",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "pageId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_table_weight",
+ "unique": false,
+ "columnNames": [
+ "weight"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_weight` ON `${TABLE_NAME}` (`weight`)"
+ },
+ {
+ "name": "index_page_table_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "meta_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `bannerUrl` TEXT, `cacheRemoteFiles` INTEGER, `description` TEXT, `disableGlobalTimeline` INTEGER, `disableLocalTimeline` INTEGER, `disableRegistration` INTEGER, `driveCapacityPerLocalUserMb` INTEGER, `driveCapacityPerRemoteUserMb` INTEGER, `enableDiscordIntegration` INTEGER, `enableEmail` INTEGER, `enableEmojiReaction` INTEGER, `enableGithubIntegration` INTEGER, `enableRecaptcha` INTEGER, `enableServiceWorker` INTEGER, `enableTwitterIntegration` INTEGER, `errorImageUrl` TEXT, `feedbackUrl` TEXT, `iconUrl` TEXT, `maintainerEmail` TEXT, `maintainerName` TEXT, `mascotImageUrl` TEXT, `maxNoteTextLength` INTEGER, `name` TEXT, `recaptchaSiteKey` TEXT, `secure` INTEGER, `swPublicKey` TEXT, `toSUrl` TEXT, `version` TEXT NOT NULL, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cacheRemoteFiles",
+ "columnName": "cacheRemoteFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableGlobalTimeline",
+ "columnName": "disableGlobalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableLocalTimeline",
+ "columnName": "disableLocalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableRegistration",
+ "columnName": "disableRegistration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerLocalUserMb",
+ "columnName": "driveCapacityPerLocalUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerRemoteUserMb",
+ "columnName": "driveCapacityPerRemoteUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableDiscordIntegration",
+ "columnName": "enableDiscordIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmail",
+ "columnName": "enableEmail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmojiReaction",
+ "columnName": "enableEmojiReaction",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableGithubIntegration",
+ "columnName": "enableGithubIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableRecaptcha",
+ "columnName": "enableRecaptcha",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableServiceWorker",
+ "columnName": "enableServiceWorker",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableTwitterIntegration",
+ "columnName": "enableTwitterIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "errorImageUrl",
+ "columnName": "errorImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "feedbackUrl",
+ "columnName": "feedbackUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerEmail",
+ "columnName": "maintainerEmail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerName",
+ "columnName": "maintainerName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mascotImageUrl",
+ "columnName": "mascotImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxNoteTextLength",
+ "columnName": "maxNoteTextLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recaptchaSiteKey",
+ "columnName": "recaptchaSiteKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secure",
+ "columnName": "secure",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "swPublicKey",
+ "columnName": "swPublicKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "toSUrl",
+ "columnName": "toSUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "emoji_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `host` TEXT, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` TEXT, PRIMARY KEY(`name`, `instanceDomain`), FOREIGN KEY(`instanceDomain`) REFERENCES `meta_table`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_emoji_table_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "meta_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "emoji_alias_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alias` TEXT NOT NULL, `name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, PRIMARY KEY(`alias`, `name`, `instanceDomain`), FOREIGN KEY(`name`, `instanceDomain`) REFERENCES `emoji_table`(`name`, `instanceDomain`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "alias",
+ "columnName": "alias",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "alias",
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_alias_table_name_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_alias_table_name_instanceDomain` ON `${TABLE_NAME}` (`name`, `instanceDomain`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "emoji_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "name",
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "name",
+ "instanceDomain"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "unread_notifications_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, PRIMARY KEY(`accountId`, `notificationId`), FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nicknames",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`nickname` TEXT NOT NULL, `username` TEXT NOT NULL, `host` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "nickname",
+ "columnName": "nickname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_nicknames_username_host",
+ "unique": true,
+ "columnNames": [
+ "username",
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_nicknames_username_host` ON `${TABLE_NAME}` (`username`, `host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "utf8_emojis_by_amio",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`codes` TEXT NOT NULL, `name` TEXT NOT NULL, `char` TEXT NOT NULL, PRIMARY KEY(`codes`))",
+ "fields": [
+ {
+ "fieldPath": "codes",
+ "columnName": "codes",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charCode",
+ "columnName": "char",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "codes"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "drive_file_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `relatedAccountId` INTEGER NOT NULL, `createdAt` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `md5` TEXT, `size` INTEGER, `url` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `thumbnailUrl` TEXT, `folderId` TEXT, `userId` TEXT, `comment` TEXT, `blurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`relatedAccountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "relatedAccountId",
+ "columnName": "relatedAccountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "md5",
+ "columnName": "md5",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folderId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blurhash",
+ "columnName": "blurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_drive_file_v1_serverId_relatedAccountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_drive_file_v1_serverId_relatedAccountId` ON `${TABLE_NAME}` (`serverId`, `relatedAccountId`)"
+ },
+ {
+ "name": "index_drive_file_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_drive_file_v1_relatedAccountId",
+ "unique": false,
+ "columnNames": [
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_relatedAccountId` ON `${TABLE_NAME}` (`relatedAccountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "relatedAccountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`draftNoteId` INTEGER NOT NULL, `filePropertyId` INTEGER, `localFileId` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`filePropertyId`) REFERENCES `drive_file_v1`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`localFileId`) REFERENCES `draft_local_file_v2_table`(`localFileId`) ON UPDATE NO ACTION ON DELETE SET NULL )",
+ "fields": [
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draftNoteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePropertyId",
+ "columnName": "filePropertyId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId",
+ "unique": true,
+ "columnNames": [
+ "draftNoteId",
+ "filePropertyId",
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId` ON `${TABLE_NAME}` (`draftNoteId`, `filePropertyId`, `localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_draftNoteId",
+ "unique": false,
+ "columnNames": [
+ "draftNoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId` ON `${TABLE_NAME}` (`draftNoteId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_localFileId",
+ "unique": false,
+ "columnNames": [
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_localFileId` ON `${TABLE_NAME}` (`localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_filePropertyId",
+ "unique": false,
+ "columnNames": [
+ "filePropertyId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_filePropertyId` ON `${TABLE_NAME}` (`filePropertyId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "drive_file_v1",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "filePropertyId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "draft_local_file_v2_table",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "localFileId"
+ ],
+ "referencedColumns": [
+ "localFileId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_local_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `file_path` TEXT NOT NULL, `is_sensitive` INTEGER, `type` TEXT NOT NULL, `thumbnailUrl` TEXT, `folder_id` TEXT, `file_size` INTEGER, `comment` TEXT, `localFileId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "file_size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "localFileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "group_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `ownerId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_v1_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_group_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_group_v1_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_v1_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group_member_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`groupId`) REFERENCES `group_v1`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_member_v1_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_member_v1_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_group_member_v1_groupId_userId",
+ "unique": true,
+ "columnNames": [
+ "groupId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_member_v1_groupId_userId` ON `${TABLE_NAME}` (`groupId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group_v1",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `userName` TEXT NOT NULL, `name` TEXT, `avatarUrl` TEXT, `isCat` INTEGER, `isBot` INTEGER, `host` TEXT NOT NULL, `isSameHost` INTEGER NOT NULL, `avatarBlurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "avatarUrl",
+ "columnName": "avatarUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCat",
+ "columnName": "isCat",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isBot",
+ "columnName": "isBot",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSameHost",
+ "columnName": "isSameHost",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarBlurhash",
+ "columnName": "avatarBlurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_serverId_accountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_serverId_accountId` ON `${TABLE_NAME}` (`serverId`, `accountId`)"
+ },
+ {
+ "name": "index_user_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_userName` ON `${TABLE_NAME}` (`userName`)"
+ },
+ {
+ "name": "index_user_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_host",
+ "unique": false,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_detailed_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_detailed_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_detailed_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_emoji",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `userId` INTEGER NOT NULL, `aspectRatio` REAL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "aspectRatio",
+ "columnName": "aspectRatio",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_emoji_name_userId",
+ "unique": true,
+ "columnNames": [
+ "name",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_emoji_name_userId` ON `${TABLE_NAME}` (`name`, `userId`)"
+ },
+ {
+ "name": "index_user_emoji_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_emoji_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pinned_note_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`noteId` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pinned_note_id_noteId_userId",
+ "unique": true,
+ "columnNames": [
+ "noteId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_pinned_note_id_noteId_userId` ON `${TABLE_NAME}` (`noteId`, `userId`)"
+ },
+ {
+ "name": "index_pinned_note_id_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pinned_note_id_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`faviconUrl` TEXT, `iconUrl` TEXT, `name` TEXT, `softwareName` TEXT, `softwareVersion` TEXT, `themeColor` TEXT, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "faviconUrl",
+ "columnName": "faviconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareName",
+ "columnName": "softwareName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareVersion",
+ "columnName": "softwareVersion",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_instance_info_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_instance_info_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_profile_field",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `value` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_profile_field_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_profile_field_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "word_filter_regex_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pattern` TEXT NOT NULL, `parentId` INTEGER NOT NULL, PRIMARY KEY(`parentId`), FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "pattern",
+ "columnName": "pattern",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "parentId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_regex_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_regex_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_word_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`word` TEXT NOT NULL, `parentId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "word",
+ "columnName": "word",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_word_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_word_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_list_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_user_list_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list_member",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userListId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userListId`) REFERENCES `user_list`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userListId",
+ "columnName": "userListId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_member_userListId",
+ "unique": false,
+ "columnNames": [
+ "userListId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_member_userListId` ON `${TABLE_NAME}` (`userListId`)"
+ },
+ {
+ "name": "index_user_list_member_userListId_userId",
+ "unique": true,
+ "columnNames": [
+ "userListId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_member_userListId_userId` ON `${TABLE_NAME}` (`userListId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user_list",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userListId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "instance_info_v1_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `host` TEXT NOT NULL, `name` TEXT, `description` TEXT, `clientMaxBodyByteSize` INTEGER, `iconUrl` TEXT, `themeColor` TEXT, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "clientMaxBodyByteSize",
+ "columnName": "clientMaxBodyByteSize",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_instance_info_v1_table_host",
+ "unique": true,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_instance_info_v1_table_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "search_histories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `keyword` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keyword",
+ "columnName": "keyword",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_search_histories_keyword_accountId",
+ "unique": true,
+ "columnNames": [
+ "keyword",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_search_histories_keyword_accountId` ON `${TABLE_NAME}` (`keyword`, `accountId`)"
+ },
+ {
+ "name": "index_search_histories_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_search_histories_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_info_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_info_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_info_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_related_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_related_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_related_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nodeinfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `nodeInfoVersion` TEXT NOT NULL, `name` TEXT NOT NULL, `version` TEXT NOT NULL, PRIMARY KEY(`host`))",
+ "fields": [
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nodeInfoVersion",
+ "columnName": "nodeInfoVersion",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "host"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `email` TEXT NOT NULL, `version` TEXT NOT NULL, `urls_streamingApi` TEXT, `configuration_statuses_maxCharacters` INTEGER, `configuration_statuses_maxMediaAttachments` INTEGER, `configuration_polls_maxOptions` INTEGER, `configuration_polls_maxCharactersPerOption` INTEGER, `configuration_polls_minExpiration` INTEGER, `configuration_polls_maxExpiration` INTEGER, `configuration_emoji_reactions_myReactions` INTEGER, `configuration_emoji_reactions_maxReactionsPerAccount` INTEGER, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "urls.streamingApi",
+ "columnName": "urls_streamingApi",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxCharacters",
+ "columnName": "configuration_statuses_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxMediaAttachments",
+ "columnName": "configuration_statuses_maxMediaAttachments",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxOptions",
+ "columnName": "configuration_polls_maxOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxCharactersPerOption",
+ "columnName": "configuration_polls_maxCharactersPerOption",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.minExpiration",
+ "columnName": "configuration_polls_minExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxExpiration",
+ "columnName": "configuration_polls_maxExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactions",
+ "columnName": "configuration_emoji_reactions_myReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactionsPerAccount",
+ "columnName": "configuration_emoji_reactions_maxReactionsPerAccount",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emojis",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT, `name` TEXT NOT NULL, `emojiHost` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiHost",
+ "columnName": "emojiHost",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emojis_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_name` ON `${TABLE_NAME}` (`name`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost",
+ "unique": false,
+ "columnNames": [
+ "emojiHost"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost` ON `${TABLE_NAME}` (`emojiHost`)"
+ },
+ {
+ "name": "index_custom_emojis_category",
+ "unique": false,
+ "columnNames": [
+ "category"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_category` ON `${TABLE_NAME}` (`category`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost_name",
+ "unique": true,
+ "columnNames": [
+ "emojiHost",
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost_name` ON `${TABLE_NAME}` (`emojiHost`, `name`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emoji_aliases",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`emojiId` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`emojiId`, `value`), FOREIGN KEY(`emojiId`) REFERENCES `custom_emojis`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "emojiId",
+ "columnName": "emojiId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emoji_aliases_emojiId_value",
+ "unique": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emoji_aliases_emojiId_value` ON `${TABLE_NAME}` (`emojiId`, `value`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "custom_emojis",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "emojiId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "notification_json_cache_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, `json` TEXT NOT NULL, `key` TEXT, `weight` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `notificationId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "json",
+ "columnName": "json",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_notification_json_cache_v1_key",
+ "unique": false,
+ "columnNames": [
+ "key"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_json_cache_v1_key` ON `${TABLE_NAME}` (`key`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_word_filters_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `filterId` TEXT NOT NULL, `phrase` TEXT NOT NULL, `wholeWord` INTEGER NOT NULL, `expiresAt` TEXT, `irreversible` INTEGER NOT NULL, `isContextHome` INTEGER NOT NULL, `isContextNotifications` INTEGER NOT NULL, `isContextPublic` INTEGER NOT NULL, `isContextThread` INTEGER NOT NULL, `isContextAccount` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `filterId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filterId",
+ "columnName": "filterId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phrase",
+ "columnName": "phrase",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wholeWord",
+ "columnName": "wholeWord",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "irreversible",
+ "columnName": "irreversible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextHome",
+ "columnName": "isContextHome",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextNotifications",
+ "columnName": "isContextNotifications",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextPublic",
+ "columnName": "isContextPublic",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextThread",
+ "columnName": "isContextThread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextAccount",
+ "columnName": "isContextAccount",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "filterId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "renote_mute_users",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `postedAt` TEXT, PRIMARY KEY(`userId`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "postedAt",
+ "columnName": "postedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_renote_mute_users_postedAt",
+ "unique": false,
+ "columnNames": [
+ "postedAt"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_postedAt` ON `${TABLE_NAME}` (`postedAt`)"
+ },
+ {
+ "name": "index_renote_mute_users_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_fedibird_capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_mastodon_instance_fedibird_capabilities_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_mastodon_instance_fedibird_capabilities_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pleroma_metadata_features",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pleroma_metadata_features_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pleroma_metadata_features_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [
+ {
+ "viewName": "user_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select user.*, nicknames.nickname from user left join nicknames on user.userName = nicknames.username and user.host = nicknames.host"
+ },
+ {
+ "viewName": "group_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.groupId, u.id as userId, u.avatarUrl, u.serverId from group_member_v1 as m \n inner join group_v1 as g\n inner join user as u\n on m.groupId = g.id\n and m.userId = u.serverId\n and g.accountId = u.accountId"
+ },
+ {
+ "viewName": "user_list_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.userListId, u.id as userId, u.avatarUrl, u.serverId from user_list_member as m \n inner join user_list as ul\n inner join user as u\n on m.userListId = ul.id\n and m.userId = u.serverId\n and ul.accountId = u.accountId"
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'eeb4c81798aaf018955eae65753e8534')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/49.json b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/49.json
new file mode 100644
index 0000000000..b0c0a18c56
--- /dev/null
+++ b/modules/data/schemas/net.pantasystem.milktea.data.infrastructure.DataBase/49.json
@@ -0,0 +1,3896 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 49,
+ "identityHash": "7c3ef2be31e3b6dce800a3325846e63d",
+ "entities": [
+ {
+ "tableName": "connection_information",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT NOT NULL, `instanceBaseUrl` TEXT NOT NULL, `encryptedI` TEXT NOT NULL, `viaName` TEXT, `createdAt` TEXT NOT NULL, `isDirect` INTEGER NOT NULL, `updatedAt` TEXT NOT NULL, PRIMARY KEY(`accountId`, `encryptedI`, `instanceBaseUrl`), FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceBaseUrl",
+ "columnName": "instanceBaseUrl",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedI",
+ "columnName": "encryptedI",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "viaName",
+ "columnName": "viaName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isDirect",
+ "columnName": "isDirect",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "encryptedI",
+ "instanceBaseUrl"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "reaction_history",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `accountId` INTEGER, `target_post_id` TEXT, `target_user_id` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT)",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetPostId",
+ "columnName": "target_post_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "targetUserId",
+ "columnName": "target_user_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "Account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "reaction_user_setting",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `instance_domain` TEXT NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`reaction`, `instance_domain`))",
+ "fields": [
+ {
+ "fieldPath": "reaction",
+ "columnName": "reaction",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instance_domain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "reaction",
+ "instance_domain"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` TEXT, `title` TEXT NOT NULL, `pageNumber` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `global_timeline_with_files` INTEGER, `global_timeline_type` TEXT, `local_timeline_with_files` INTEGER, `local_timeline_exclude_nsfw` INTEGER, `local_timeline_type` TEXT, `hybrid_timeline_withFiles` INTEGER, `hybrid_timeline_includeLocalRenotes` INTEGER, `hybrid_timeline_includeMyRenotes` INTEGER, `hybrid_timeline_includeRenotedMyRenotes` INTEGER, `hybrid_timeline_type` TEXT, `home_timeline_withFiles` INTEGER, `home_timeline_includeLocalRenotes` INTEGER, `home_timeline_includeMyRenotes` INTEGER, `home_timeline_includeRenotedMyRenotes` INTEGER, `home_timeline_type` TEXT, `user_list_timeline_listId` TEXT, `user_list_timeline_withFiles` INTEGER, `user_list_timeline_includeLocalRenotes` INTEGER, `user_list_timeline_includeMyRenotes` INTEGER, `user_list_timeline_includeRenotedMyRenotes` INTEGER, `user_list_timeline_type` TEXT, `mention_following` INTEGER, `mention_visibility` TEXT, `mention_type` TEXT, `show_noteId` TEXT, `show_type` TEXT, `tag_tag` TEXT, `tag_reply` INTEGER, `tag_renote` INTEGER, `tag_withFiles` INTEGER, `tag_poll` INTEGER, `tag_type` TEXT, `featured_offset` INTEGER, `featured_type` TEXT, `notification_following` INTEGER, `notification_markAsRead` INTEGER, `notification_type` TEXT, `user_userId` TEXT, `user_includeReplies` INTEGER, `user_includeMyRenotes` INTEGER, `user_withFiles` INTEGER, `user_type` TEXT, `search_query` TEXT, `search_host` TEXT, `search_userId` TEXT, `search_type` TEXT, `favorite_type` TEXT, `antenna_antennaId` TEXT, `antenna_type` TEXT, FOREIGN KEY(`accountId`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageNumber",
+ "columnName": "pageNumber",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.withFiles",
+ "columnName": "global_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "globalTimeline.type",
+ "columnName": "global_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.withFiles",
+ "columnName": "local_timeline_with_files",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.excludeNsfw",
+ "columnName": "local_timeline_exclude_nsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localTimeline.type",
+ "columnName": "local_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.withFiles",
+ "columnName": "hybrid_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeLocalRenotes",
+ "columnName": "hybrid_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeMyRenotes",
+ "columnName": "hybrid_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.includeRenotedMyRenotes",
+ "columnName": "hybrid_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hybridTimeline.type",
+ "columnName": "hybrid_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.withFiles",
+ "columnName": "home_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeLocalRenotes",
+ "columnName": "home_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeMyRenotes",
+ "columnName": "home_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.includeRenotedMyRenotes",
+ "columnName": "home_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "homeTimeline.type",
+ "columnName": "home_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.listId",
+ "columnName": "user_list_timeline_listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.withFiles",
+ "columnName": "user_list_timeline_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeLocalRenotes",
+ "columnName": "user_list_timeline_includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeMyRenotes",
+ "columnName": "user_list_timeline_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.includeRenotedMyRenotes",
+ "columnName": "user_list_timeline_includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userListTimeline.type",
+ "columnName": "user_list_timeline_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.following",
+ "columnName": "mention_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.visibility",
+ "columnName": "mention_visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mention.type",
+ "columnName": "mention_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.noteId",
+ "columnName": "show_noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "show.type",
+ "columnName": "show_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.tag",
+ "columnName": "tag_tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.reply",
+ "columnName": "tag_reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.renote",
+ "columnName": "tag_renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.withFiles",
+ "columnName": "tag_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.poll",
+ "columnName": "tag_poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "searchByTag.type",
+ "columnName": "tag_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.offset",
+ "columnName": "featured_offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "featured.type",
+ "columnName": "featured_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.following",
+ "columnName": "notification_following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.markAsRead",
+ "columnName": "notification_markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notification.type",
+ "columnName": "notification_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.userId",
+ "columnName": "user_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeReplies",
+ "columnName": "user_includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.includeMyRenotes",
+ "columnName": "user_includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.withFiles",
+ "columnName": "user_withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userTimeline.type",
+ "columnName": "user_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.query",
+ "columnName": "search_query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.host",
+ "columnName": "search_host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.userId",
+ "columnName": "search_userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "search.type",
+ "columnName": "search_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "favorite.type",
+ "columnName": "favorite_type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.antennaId",
+ "columnName": "antenna_antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "antenna.type",
+ "columnName": "antenna_type",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "Account",
+ "onDelete": "NO ACTION",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "poll_choice_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`choice` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, `weight` INTEGER NOT NULL, PRIMARY KEY(`choice`, `weight`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "choice",
+ "columnName": "choice",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "choice",
+ "weight",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_poll_choice_table_draft_note_id_choice",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id",
+ "choice"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_poll_choice_table_draft_note_id_choice` ON `${TABLE_NAME}` (`draft_note_id`, `choice`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `draft_note_id` INTEGER NOT NULL, PRIMARY KEY(`userId`, `draft_note_id`), FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_id_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_id_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL DEFAULT 'name none', `remote_file_id` TEXT, `file_path` TEXT, `is_sensitive` INTEGER, `type` TEXT, `thumbnailUrl` TEXT, `draft_note_id` INTEGER NOT NULL, `folder_id` TEXT, `file_id` INTEGER PRIMARY KEY AUTOINCREMENT, FOREIGN KEY(`draft_note_id`) REFERENCES `draft_note_table`(`draft_note_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'name none'"
+ },
+ {
+ "fieldPath": "remoteFileId",
+ "columnName": "remote_file_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileId",
+ "columnName": "file_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "file_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_table_draft_note_id",
+ "unique": false,
+ "columnNames": [
+ "draft_note_id"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_table_draft_note_id` ON `${TABLE_NAME}` (`draft_note_id`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "draft_note_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "draft_note_id"
+ ],
+ "referencedColumns": [
+ "draft_note_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_note_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `visibility` TEXT NOT NULL, `text` TEXT, `cw` TEXT, `viaMobile` INTEGER, `localOnly` INTEGER, `noExtractMentions` INTEGER, `noExtractHashtags` INTEGER, `noExtractEmojis` INTEGER, `replyId` TEXT, `renoteId` TEXT, `channelId` TEXT, `scheduleWillPostAt` TEXT, `draft_note_id` INTEGER PRIMARY KEY AUTOINCREMENT, `isSensitive` INTEGER, `multiple` INTEGER, `expiresAt` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "text",
+ "columnName": "text",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cw",
+ "columnName": "cw",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "viaMobile",
+ "columnName": "viaMobile",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localOnly",
+ "columnName": "localOnly",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractMentions",
+ "columnName": "noExtractMentions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractHashtags",
+ "columnName": "noExtractHashtags",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "noExtractEmojis",
+ "columnName": "noExtractEmojis",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "replyId",
+ "columnName": "replyId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "renoteId",
+ "columnName": "renoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "scheduleWillPostAt",
+ "columnName": "scheduleWillPostAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draft_note_id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.multiple",
+ "columnName": "multiple",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "poll.expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "draft_note_id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_note_table_accountId_text",
+ "unique": false,
+ "columnNames": [
+ "accountId",
+ "text"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_note_table_accountId_text` ON `${TABLE_NAME}` (`accountId`, `text`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "url_preview",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `icon` TEXT, `description` TEXT, `thumbnail` TEXT, `siteName` TEXT, PRIMARY KEY(`url`))",
+ "fields": [
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "thumbnail",
+ "columnName": "thumbnail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "siteName",
+ "columnName": "siteName",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "url"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "account_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `userName` TEXT NOT NULL, `encryptedToken` TEXT NOT NULL, `instanceType` TEXT NOT NULL DEFAULT 'misskey', `accountId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "encryptedToken",
+ "columnName": "encryptedToken",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceType",
+ "columnName": "instanceType",
+ "affinity": "TEXT",
+ "notNull": true,
+ "defaultValue": "'misskey'"
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_account_table_remoteId",
+ "unique": false,
+ "columnNames": [
+ "remoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_remoteId` ON `${TABLE_NAME}` (`remoteId`)"
+ },
+ {
+ "name": "index_account_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_account_table_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_account_table_userName` ON `${TABLE_NAME}` (`userName`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "page_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `title` TEXT NOT NULL, `weight` INTEGER NOT NULL, `isSavePagePosition` INTEGER, `attachedAccountId` INTEGER, `pageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `withFiles` INTEGER, `excludeNsfw` INTEGER, `includeLocalRenotes` INTEGER, `includeMyRenotes` INTEGER, `includeRenotedMyRenotes` INTEGER, `listId` TEXT, `following` INTEGER, `visibility` TEXT, `noteId` TEXT, `tag` TEXT, `reply` INTEGER, `renote` INTEGER, `poll` INTEGER, `offset` INTEGER, `markAsRead` INTEGER, `userId` TEXT, `includeReplies` INTEGER, `query` TEXT, `host` TEXT, `antennaId` TEXT, `channelId` TEXT, `clipId` TEXT)",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSavePagePosition",
+ "columnName": "isSavePagePosition",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "attachedAccountId",
+ "columnName": "attachedAccountId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageId",
+ "columnName": "pageId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "pageParams.withFiles",
+ "columnName": "withFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.excludeNsfw",
+ "columnName": "excludeNsfw",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeLocalRenotes",
+ "columnName": "includeLocalRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeMyRenotes",
+ "columnName": "includeMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeRenotedMyRenotes",
+ "columnName": "includeRenotedMyRenotes",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.listId",
+ "columnName": "listId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.following",
+ "columnName": "following",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.visibility",
+ "columnName": "visibility",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.tag",
+ "columnName": "tag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.reply",
+ "columnName": "reply",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.renote",
+ "columnName": "renote",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.poll",
+ "columnName": "poll",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.offset",
+ "columnName": "offset",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.markAsRead",
+ "columnName": "markAsRead",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.includeReplies",
+ "columnName": "includeReplies",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.query",
+ "columnName": "query",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.antennaId",
+ "columnName": "antennaId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.channelId",
+ "columnName": "channelId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "pageParams.clipId",
+ "columnName": "clipId",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "pageId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_page_table_weight",
+ "unique": false,
+ "columnNames": [
+ "weight"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_weight` ON `${TABLE_NAME}` (`weight`)"
+ },
+ {
+ "name": "index_page_table_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_page_table_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "meta_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `bannerUrl` TEXT, `cacheRemoteFiles` INTEGER, `description` TEXT, `disableGlobalTimeline` INTEGER, `disableLocalTimeline` INTEGER, `disableRegistration` INTEGER, `driveCapacityPerLocalUserMb` INTEGER, `driveCapacityPerRemoteUserMb` INTEGER, `enableDiscordIntegration` INTEGER, `enableEmail` INTEGER, `enableEmojiReaction` INTEGER, `enableGithubIntegration` INTEGER, `enableRecaptcha` INTEGER, `enableServiceWorker` INTEGER, `enableTwitterIntegration` INTEGER, `errorImageUrl` TEXT, `feedbackUrl` TEXT, `iconUrl` TEXT, `maintainerEmail` TEXT, `maintainerName` TEXT, `mascotImageUrl` TEXT, `maxNoteTextLength` INTEGER, `name` TEXT, `recaptchaSiteKey` TEXT, `secure` INTEGER, `swPublicKey` TEXT, `toSUrl` TEXT, `version` TEXT NOT NULL, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cacheRemoteFiles",
+ "columnName": "cacheRemoteFiles",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableGlobalTimeline",
+ "columnName": "disableGlobalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableLocalTimeline",
+ "columnName": "disableLocalTimeline",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "disableRegistration",
+ "columnName": "disableRegistration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerLocalUserMb",
+ "columnName": "driveCapacityPerLocalUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveCapacityPerRemoteUserMb",
+ "columnName": "driveCapacityPerRemoteUserMb",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableDiscordIntegration",
+ "columnName": "enableDiscordIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmail",
+ "columnName": "enableEmail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableEmojiReaction",
+ "columnName": "enableEmojiReaction",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableGithubIntegration",
+ "columnName": "enableGithubIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableRecaptcha",
+ "columnName": "enableRecaptcha",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableServiceWorker",
+ "columnName": "enableServiceWorker",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "enableTwitterIntegration",
+ "columnName": "enableTwitterIntegration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "errorImageUrl",
+ "columnName": "errorImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "feedbackUrl",
+ "columnName": "feedbackUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerEmail",
+ "columnName": "maintainerEmail",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maintainerName",
+ "columnName": "maintainerName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "mascotImageUrl",
+ "columnName": "mascotImageUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "maxNoteTextLength",
+ "columnName": "maxNoteTextLength",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "recaptchaSiteKey",
+ "columnName": "recaptchaSiteKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "secure",
+ "columnName": "secure",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "swPublicKey",
+ "columnName": "swPublicKey",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "toSUrl",
+ "columnName": "toSUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "emoji_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, `host` TEXT, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` TEXT, PRIMARY KEY(`name`, `instanceDomain`), FOREIGN KEY(`instanceDomain`) REFERENCES `meta_table`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_table_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_instanceDomain` ON `${TABLE_NAME}` (`instanceDomain`)"
+ },
+ {
+ "name": "index_emoji_table_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_table_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "meta_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "emoji_alias_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alias` TEXT NOT NULL, `name` TEXT NOT NULL, `instanceDomain` TEXT NOT NULL, PRIMARY KEY(`alias`, `name`, `instanceDomain`), FOREIGN KEY(`name`, `instanceDomain`) REFERENCES `emoji_table`(`name`, `instanceDomain`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "alias",
+ "columnName": "alias",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "instanceDomain",
+ "columnName": "instanceDomain",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "alias",
+ "name",
+ "instanceDomain"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_emoji_alias_table_name_instanceDomain",
+ "unique": false,
+ "columnNames": [
+ "name",
+ "instanceDomain"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_emoji_alias_table_name_instanceDomain` ON `${TABLE_NAME}` (`name`, `instanceDomain`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "emoji_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "name",
+ "instanceDomain"
+ ],
+ "referencedColumns": [
+ "name",
+ "instanceDomain"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "unread_notifications_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, PRIMARY KEY(`accountId`, `notificationId`), FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nicknames",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`nickname` TEXT NOT NULL, `username` TEXT NOT NULL, `host` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "nickname",
+ "columnName": "nickname",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "username",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_nicknames_username_host",
+ "unique": true,
+ "columnNames": [
+ "username",
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_nicknames_username_host` ON `${TABLE_NAME}` (`username`, `host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "utf8_emojis_by_amio",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`codes` TEXT NOT NULL, `name` TEXT NOT NULL, `char` TEXT NOT NULL, PRIMARY KEY(`codes`))",
+ "fields": [
+ {
+ "fieldPath": "codes",
+ "columnName": "codes",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "charCode",
+ "columnName": "char",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "codes"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "drive_file_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `relatedAccountId` INTEGER NOT NULL, `createdAt` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `md5` TEXT, `size` INTEGER, `url` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `thumbnailUrl` TEXT, `folderId` TEXT, `userId` TEXT, `comment` TEXT, `blurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`relatedAccountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "relatedAccountId",
+ "columnName": "relatedAccountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "md5",
+ "columnName": "md5",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "isSensitive",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folderId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "blurhash",
+ "columnName": "blurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_drive_file_v1_serverId_relatedAccountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_drive_file_v1_serverId_relatedAccountId` ON `${TABLE_NAME}` (`serverId`, `relatedAccountId`)"
+ },
+ {
+ "name": "index_drive_file_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_drive_file_v1_relatedAccountId",
+ "unique": false,
+ "columnNames": [
+ "relatedAccountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_drive_file_v1_relatedAccountId` ON `${TABLE_NAME}` (`relatedAccountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "relatedAccountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`draftNoteId` INTEGER NOT NULL, `filePropertyId` INTEGER, `localFileId` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`filePropertyId`) REFERENCES `drive_file_v1`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`localFileId`) REFERENCES `draft_local_file_v2_table`(`localFileId`) ON UPDATE NO ACTION ON DELETE SET NULL )",
+ "fields": [
+ {
+ "fieldPath": "draftNoteId",
+ "columnName": "draftNoteId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePropertyId",
+ "columnName": "filePropertyId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId",
+ "unique": true,
+ "columnNames": [
+ "draftNoteId",
+ "filePropertyId",
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId_filePropertyId_localFileId` ON `${TABLE_NAME}` (`draftNoteId`, `filePropertyId`, `localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_draftNoteId",
+ "unique": false,
+ "columnNames": [
+ "draftNoteId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_draftNoteId` ON `${TABLE_NAME}` (`draftNoteId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_localFileId",
+ "unique": false,
+ "columnNames": [
+ "localFileId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_localFileId` ON `${TABLE_NAME}` (`localFileId`)"
+ },
+ {
+ "name": "index_draft_file_v2_table_filePropertyId",
+ "unique": false,
+ "columnNames": [
+ "filePropertyId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_draft_file_v2_table_filePropertyId` ON `${TABLE_NAME}` (`filePropertyId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "drive_file_v1",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "filePropertyId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ },
+ {
+ "table": "draft_local_file_v2_table",
+ "onDelete": "SET NULL",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "localFileId"
+ ],
+ "referencedColumns": [
+ "localFileId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "draft_local_file_v2_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `file_path` TEXT NOT NULL, `is_sensitive` INTEGER, `type` TEXT NOT NULL, `thumbnailUrl` TEXT, `folder_id` TEXT, `file_size` INTEGER, `comment` TEXT, `localFileId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filePath",
+ "columnName": "file_path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSensitive",
+ "columnName": "is_sensitive",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "thumbnailUrl",
+ "columnName": "thumbnailUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "folderId",
+ "columnName": "folder_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "file_size",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "comment",
+ "columnName": "comment",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "localFileId",
+ "columnName": "localFileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "localFileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "group_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `ownerId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "ownerId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_v1_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_group_v1_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_v1_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_group_v1_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_v1_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group_member_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`groupId`) REFERENCES `group_v1`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_member_v1_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_member_v1_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_group_member_v1_groupId_userId",
+ "unique": true,
+ "columnNames": [
+ "groupId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_group_member_v1_groupId_userId` ON `${TABLE_NAME}` (`groupId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group_v1",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `userName` TEXT NOT NULL, `name` TEXT, `avatarUrl` TEXT, `isCat` INTEGER, `isBot` INTEGER, `host` TEXT NOT NULL, `isSameHost` INTEGER NOT NULL, `avatarBlurhash` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userName",
+ "columnName": "userName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "avatarUrl",
+ "columnName": "avatarUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isCat",
+ "columnName": "isCat",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isBot",
+ "columnName": "isBot",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isSameHost",
+ "columnName": "isSameHost",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "avatarBlurhash",
+ "columnName": "avatarBlurhash",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_serverId_accountId",
+ "unique": true,
+ "columnNames": [
+ "serverId",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_serverId_accountId` ON `${TABLE_NAME}` (`serverId`, `accountId`)"
+ },
+ {
+ "name": "index_user_userName",
+ "unique": false,
+ "columnNames": [
+ "userName"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_userName` ON `${TABLE_NAME}` (`userName`)"
+ },
+ {
+ "name": "index_user_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_host",
+ "unique": false,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_detailed_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_detailed_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_detailed_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_emoji",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `userId` INTEGER NOT NULL, `aspectRatio` REAL, `cachePath` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "aspectRatio",
+ "columnName": "aspectRatio",
+ "affinity": "REAL",
+ "notNull": false
+ },
+ {
+ "fieldPath": "cachePath",
+ "columnName": "cachePath",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_emoji_name_userId",
+ "unique": true,
+ "columnNames": [
+ "name",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_emoji_name_userId` ON `${TABLE_NAME}` (`name`, `userId`)"
+ },
+ {
+ "name": "index_user_emoji_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_emoji_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pinned_note_id",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`noteId` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "noteId",
+ "columnName": "noteId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pinned_note_id_noteId_userId",
+ "unique": true,
+ "columnNames": [
+ "noteId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_pinned_note_id_noteId_userId` ON `${TABLE_NAME}` (`noteId`, `userId`)"
+ },
+ {
+ "name": "index_pinned_note_id_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pinned_note_id_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`faviconUrl` TEXT, `iconUrl` TEXT, `name` TEXT, `softwareName` TEXT, `softwareVersion` TEXT, `themeColor` TEXT, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "faviconUrl",
+ "columnName": "faviconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareName",
+ "columnName": "softwareName",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "softwareVersion",
+ "columnName": "softwareVersion",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_instance_info_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_instance_info_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_profile_field",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `value` TEXT NOT NULL, `userId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_profile_field_userId",
+ "unique": false,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_profile_field_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "word_filter_regex_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pattern` TEXT NOT NULL, `parentId` INTEGER NOT NULL, PRIMARY KEY(`parentId`), FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "pattern",
+ "columnName": "pattern",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "parentId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_regex_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_regex_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "word_filter_word_condition",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`word` TEXT NOT NULL, `parentId` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`parentId`) REFERENCES `word_filter_condition`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "word",
+ "columnName": "word",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_word_filter_word_condition_parentId",
+ "unique": false,
+ "columnNames": [
+ "parentId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_word_filter_word_condition_parentId` ON `${TABLE_NAME}` (`parentId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "word_filter_condition",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "parentId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ },
+ {
+ "name": "index_user_list_serverId",
+ "unique": false,
+ "columnNames": [
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_serverId` ON `${TABLE_NAME}` (`serverId`)"
+ },
+ {
+ "name": "index_user_list_accountId_serverId",
+ "unique": true,
+ "columnNames": [
+ "accountId",
+ "serverId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_accountId_serverId` ON `${TABLE_NAME}` (`accountId`, `serverId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_list_member",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userListId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`userListId`) REFERENCES `user_list`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "userListId",
+ "columnName": "userListId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_list_member_userListId",
+ "unique": false,
+ "columnNames": [
+ "userListId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_user_list_member_userListId` ON `${TABLE_NAME}` (`userListId`)"
+ },
+ {
+ "name": "index_user_list_member_userListId_userId",
+ "unique": true,
+ "columnNames": [
+ "userListId",
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_list_member_userListId_userId` ON `${TABLE_NAME}` (`userListId`, `userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user_list",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userListId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "instance_info_v1_table",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `host` TEXT NOT NULL, `name` TEXT, `description` TEXT, `clientMaxBodyByteSize` INTEGER, `iconUrl` TEXT, `themeColor` TEXT, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "clientMaxBodyByteSize",
+ "columnName": "clientMaxBodyByteSize",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "iconUrl",
+ "columnName": "iconUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "themeColor",
+ "columnName": "themeColor",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_instance_info_v1_table_host",
+ "unique": true,
+ "columnNames": [
+ "host"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_instance_info_v1_table_host` ON `${TABLE_NAME}` (`host`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "search_histories",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `keyword` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account_table`(`accountId`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "keyword",
+ "columnName": "keyword",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_search_histories_keyword_accountId",
+ "unique": true,
+ "columnNames": [
+ "keyword",
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_search_histories_keyword_accountId` ON `${TABLE_NAME}` (`keyword`, `accountId`)"
+ },
+ {
+ "name": "index_search_histories_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_search_histories_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "account_table",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "accountId"
+ ],
+ "referencedColumns": [
+ "accountId"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_info_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`description` TEXT, `followersCount` INTEGER, `followingCount` INTEGER, `hostLower` TEXT, `notesCount` INTEGER, `bannerUrl` TEXT, `url` TEXT, `isLocked` INTEGER NOT NULL, `birthday` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `publicReactions` INTEGER, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followersCount",
+ "columnName": "followersCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "followingCount",
+ "columnName": "followingCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "hostLower",
+ "columnName": "hostLower",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "notesCount",
+ "columnName": "notesCount",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "bannerUrl",
+ "columnName": "bannerUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isLocked",
+ "columnName": "isLocked",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "birthday",
+ "columnName": "birthday",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "updatedAt",
+ "columnName": "updatedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "publicReactions",
+ "columnName": "publicReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_info_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_info_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_related_state",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`isFollowing` INTEGER NOT NULL, `isFollower` INTEGER NOT NULL, `isBlocking` INTEGER NOT NULL, `isMuting` INTEGER NOT NULL, `hasPendingFollowRequestFromYou` INTEGER NOT NULL, `hasPendingFollowRequestToYou` INTEGER NOT NULL, `userId` INTEGER NOT NULL, PRIMARY KEY(`userId`), FOREIGN KEY(`userId`) REFERENCES `user`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "isFollowing",
+ "columnName": "isFollowing",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isFollower",
+ "columnName": "isFollower",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isBlocking",
+ "columnName": "isBlocking",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isMuting",
+ "columnName": "isMuting",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestFromYou",
+ "columnName": "hasPendingFollowRequestFromYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hasPendingFollowRequestToYou",
+ "columnName": "hasPendingFollowRequestToYou",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_user_related_state_userId",
+ "unique": true,
+ "columnNames": [
+ "userId"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_user_related_state_userId` ON `${TABLE_NAME}` (`userId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "user",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "userId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "nodeinfo",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`host` TEXT NOT NULL, `nodeInfoVersion` TEXT NOT NULL, `name` TEXT NOT NULL, `version` TEXT NOT NULL, PRIMARY KEY(`host`))",
+ "fields": [
+ {
+ "fieldPath": "host",
+ "columnName": "host",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "nodeInfoVersion",
+ "columnName": "nodeInfoVersion",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "host"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_info",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `email` TEXT NOT NULL, `version` TEXT NOT NULL, `urls_streamingApi` TEXT, `configuration_statuses_maxCharacters` INTEGER, `configuration_statuses_maxMediaAttachments` INTEGER, `configuration_polls_maxOptions` INTEGER, `configuration_polls_maxCharactersPerOption` INTEGER, `configuration_polls_minExpiration` INTEGER, `configuration_polls_maxExpiration` INTEGER, `configuration_emoji_reactions_myReactions` INTEGER, `configuration_emoji_reactions_maxReactionsPerAccount` INTEGER, PRIMARY KEY(`uri`))",
+ "fields": [
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "email",
+ "columnName": "email",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "version",
+ "columnName": "version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "urls.streamingApi",
+ "columnName": "urls_streamingApi",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxCharacters",
+ "columnName": "configuration_statuses_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.statuses.maxMediaAttachments",
+ "columnName": "configuration_statuses_maxMediaAttachments",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxOptions",
+ "columnName": "configuration_polls_maxOptions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxCharactersPerOption",
+ "columnName": "configuration_polls_maxCharactersPerOption",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.minExpiration",
+ "columnName": "configuration_polls_minExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.polls.maxExpiration",
+ "columnName": "configuration_polls_maxExpiration",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactions",
+ "columnName": "configuration_emoji_reactions_myReactions",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "configuration.emojiReactions.maxReactionsPerAccount",
+ "columnName": "configuration_emoji_reactions_maxReactionsPerAccount",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emojis",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT, `name` TEXT NOT NULL, `emojiHost` TEXT NOT NULL, `url` TEXT, `uri` TEXT, `type` TEXT, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "serverId",
+ "columnName": "serverId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "emojiHost",
+ "columnName": "emojiHost",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "category",
+ "columnName": "category",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emojis_name",
+ "unique": false,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_name` ON `${TABLE_NAME}` (`name`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost",
+ "unique": false,
+ "columnNames": [
+ "emojiHost"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost` ON `${TABLE_NAME}` (`emojiHost`)"
+ },
+ {
+ "name": "index_custom_emojis_category",
+ "unique": false,
+ "columnNames": [
+ "category"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emojis_category` ON `${TABLE_NAME}` (`category`)"
+ },
+ {
+ "name": "index_custom_emojis_emojiHost_name",
+ "unique": true,
+ "columnNames": [
+ "emojiHost",
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_custom_emojis_emojiHost_name` ON `${TABLE_NAME}` (`emojiHost`, `name`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "custom_emoji_aliases",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`emojiId` INTEGER NOT NULL, `value` TEXT NOT NULL, PRIMARY KEY(`emojiId`, `value`), FOREIGN KEY(`emojiId`) REFERENCES `custom_emojis`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "emojiId",
+ "columnName": "emojiId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "value",
+ "columnName": "value",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_custom_emoji_aliases_emojiId_value",
+ "unique": false,
+ "columnNames": [
+ "emojiId",
+ "value"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_custom_emoji_aliases_emojiId_value` ON `${TABLE_NAME}` (`emojiId`, `value`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "custom_emojis",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "emojiId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "notification_json_cache_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `notificationId` TEXT NOT NULL, `json` TEXT NOT NULL, `key` TEXT, `weight` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `notificationId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "notificationId",
+ "columnName": "notificationId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "json",
+ "columnName": "json",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "key",
+ "columnName": "key",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "weight",
+ "columnName": "weight",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "notificationId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_notification_json_cache_v1_key",
+ "unique": false,
+ "columnNames": [
+ "key"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_notification_json_cache_v1_key` ON `${TABLE_NAME}` (`key`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_word_filters_v1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `filterId` TEXT NOT NULL, `phrase` TEXT NOT NULL, `wholeWord` INTEGER NOT NULL, `expiresAt` TEXT, `irreversible` INTEGER NOT NULL, `isContextHome` INTEGER NOT NULL, `isContextNotifications` INTEGER NOT NULL, `isContextPublic` INTEGER NOT NULL, `isContextThread` INTEGER NOT NULL, `isContextAccount` INTEGER NOT NULL, PRIMARY KEY(`accountId`, `filterId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filterId",
+ "columnName": "filterId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "phrase",
+ "columnName": "phrase",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wholeWord",
+ "columnName": "wholeWord",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expiresAt",
+ "columnName": "expiresAt",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "irreversible",
+ "columnName": "irreversible",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextHome",
+ "columnName": "isContextHome",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextNotifications",
+ "columnName": "isContextNotifications",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextPublic",
+ "columnName": "isContextPublic",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextThread",
+ "columnName": "isContextThread",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isContextAccount",
+ "columnName": "isContextAccount",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountId",
+ "filterId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "renote_mute_users",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `userId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `postedAt` TEXT, PRIMARY KEY(`userId`, `accountId`))",
+ "fields": [
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "userId",
+ "columnName": "userId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "createdAt",
+ "columnName": "createdAt",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "postedAt",
+ "columnName": "postedAt",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "userId",
+ "accountId"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_renote_mute_users_postedAt",
+ "unique": false,
+ "columnNames": [
+ "postedAt"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_postedAt` ON `${TABLE_NAME}` (`postedAt`)"
+ },
+ {
+ "name": "index_renote_mute_users_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_renote_mute_users_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "mastodon_instance_fedibird_capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_mastodon_instance_fedibird_capabilities_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_mastodon_instance_fedibird_capabilities_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "pleroma_metadata_features",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `uri` TEXT NOT NULL, PRIMARY KEY(`uri`, `type`), FOREIGN KEY(`uri`) REFERENCES `mastodon_instance_info`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uri",
+ "columnName": "uri",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "uri",
+ "type"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_pleroma_metadata_features_uri",
+ "unique": false,
+ "columnNames": [
+ "uri"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_pleroma_metadata_features_uri` ON `${TABLE_NAME}` (`uri`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "mastodon_instance_info",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "uri"
+ ],
+ "referencedColumns": [
+ "uri"
+ ]
+ }
+ ]
+ }
+ ],
+ "views": [
+ {
+ "viewName": "user_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select user.*, nicknames.nickname from user left join nicknames on user.userName = nicknames.username and user.host = nicknames.host"
+ },
+ {
+ "viewName": "group_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.groupId, u.id as userId, u.avatarUrl, u.serverId from group_member_v1 as m \n inner join group_v1 as g\n inner join user as u\n on m.groupId = g.id\n and m.userId = u.serverId\n and g.accountId = u.accountId"
+ },
+ {
+ "viewName": "user_list_member_view",
+ "createSql": "CREATE VIEW `${VIEW_NAME}` AS select m.userListId, u.id as userId, u.avatarUrl, u.serverId from user_list_member as m \n inner join user_list as ul\n inner join user as u\n on m.userListId = ul.id\n and m.userId = u.serverId\n and ul.accountId = u.accountId"
+ }
+ ],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7c3ef2be31e3b6dce800a3325846e63d')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/DatabaseMigrationTest.kt b/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/DatabaseMigrationTest.kt
index 279e0311bb..ca85ddff30 100644
--- a/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/DatabaseMigrationTest.kt
+++ b/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/DatabaseMigrationTest.kt
@@ -215,4 +215,50 @@ class DatabaseMigrationTest {
helper.createDatabase(testDb, 42)
helper.runMigrationsAndValidate(testDb, 43, true)
}
+
+ @Test
+ @Throws(IOException::class)
+ fun migrate43To44() {
+ helper.createDatabase(testDb, 43)
+ helper.runMigrationsAndValidate(testDb, 44, true)
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun migrate44To45() {
+ helper.createDatabase(testDb, 44)
+ helper.runMigrationsAndValidate(testDb, 45, true)
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun migrate45To46() {
+ helper.createDatabase(testDb, 45)
+ helper.runMigrationsAndValidate(testDb, 46, true)
+
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun migrate46To47() {
+ helper.createDatabase(testDb, 46)
+ helper.runMigrationsAndValidate(testDb, 47, true)
+
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun migrate47To48() {
+ helper.createDatabase(testDb, 47)
+ helper.runMigrationsAndValidate(testDb, 48, true)
+
+ }
+
+ @Test
+ @Throws(IOException::class)
+ fun migrate48To49() {
+ helper.createDatabase(testDb, 48)
+ helper.runMigrationsAndValidate(testDb, 49, true)
+
+ }
}
\ No newline at end of file
diff --git a/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImplTest.kt b/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImplTest.kt
deleted file mode 100644
index ef6c5cba50..0000000000
--- a/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImplTest.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package net.pantasystem.milktea.data.infrastructure.emoji
-
-import android.content.Context
-import androidx.room.Room
-import androidx.test.core.app.ApplicationProvider
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.runBlocking
-import net.pantasystem.milktea.data.infrastructure.DataBase
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Test
-
-class Utf8EmojiRepositoryImplTest {
-
- lateinit var database: DataBase
-
- @Before
- fun setup() {
-
- val context = ApplicationProvider.getApplicationContext()
- database = Room.inMemoryDatabaseBuilder(context, DataBase::class.java).build()
- }
-
- @Test
- fun exists() {
- val job = Job()
- val utf8EmojiRepositoryImpl = Utf8EmojiRepositoryImpl(
- CoroutineScope(job),
- null,
- Dispatchers.Default,
- database.utf8EmojiDAO()
- )
- runBlocking {
- Assert.assertNotEquals(0, utf8EmojiRepositoryImpl.findAll().size)
- Assert.assertTrue(setOf("㊙️", "㊙︎").contains("㊙︎"))
-
-
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("㊙️"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("㊙︎"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("‼︎"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("‼️"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("♀"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("あ"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("a"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("c"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("1"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("2"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists(" "))
-
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("3"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("\uD83E\uDD7A"))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists(" harunon "))
- Assert.assertFalse(utf8EmojiRepositoryImpl.exists("鶏"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("☕️"))
- Assert.assertTrue(utf8EmojiRepositoryImpl.exists("\uD83D\uDCA2"))
-
-
- }
-
- job.cancel()
- }
-}
\ No newline at end of file
diff --git a/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/emoji/delegate/CustomEmojiUpInsertDelegateTest.kt b/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/emoji/delegate/CustomEmojiUpInsertDelegateTest.kt
deleted file mode 100644
index 7825a92ab8..0000000000
--- a/modules/data/src/androidTest/java/net/pantasystem/milktea/data/infrastructure/emoji/delegate/CustomEmojiUpInsertDelegateTest.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-package net.pantasystem.milktea.data.infrastructure.emoji.delegate
-
-import android.content.Context
-import androidx.room.Room
-import androidx.test.core.app.ApplicationProvider
-import kotlinx.coroutines.runBlocking
-import net.pantasystem.milktea.data.infrastructure.DataBase
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiAliasRecord
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiDAO
-import net.pantasystem.milktea.data.infrastructure.emoji.db.toRecord
-import net.pantasystem.milktea.model.emoji.Emoji
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Test
-
-class CustomEmojiUpInsertDelegateTest {
-
- private lateinit var dao: CustomEmojiDAO
-
- @Before
- fun setup() {
- val context = ApplicationProvider.getApplicationContext()
- val database = Room.inMemoryDatabaseBuilder(context, DataBase::class.java).build()
- dao = database.customEmojiDao()
- }
-
- @Test
- fun giveNotExistsData() = runBlocking {
- val emojis = listOf(
- Emoji(
- name = "test1",
- aliases = listOf("a", "b", "c")
- ),
- Emoji(
- name = "test2",
- aliases = listOf("a2`", "b2", "c2")
- ),
- Emoji(
- name = "test3",
- aliases = listOf("a3", "b3", "c3", "d4")
- ),
- Emoji(
- name = "test4",
- aliases = listOf("")
- )
- )
-
- val delegate = CustomEmojiUpInsertDelegate(dao)
- delegate("misskey.pantasystem.com", emojis)
-
- val actual = dao.findBy("misskey.pantasystem.com").map {
- it.toModel()
- }
-
- val expect = emojis.map { emoji ->
- emoji.copy(
- aliases = emoji.aliases?.filterNot {
- it.isBlank()
- }
- )
- }
- Assert.assertEquals(
- expect,
- actual
- )
- }
-
- @Test
- fun giveExistsData() = runBlocking {
- val existsData = listOf(
- Emoji(
- name = "test1",
- aliases = listOf("a", "b", "c")
- ),
- Emoji(
- name = "test2",
- aliases = listOf("a2`", "b2", "c2")
- ),
- )
-
- val emojis = listOf(
- Emoji(
- name = "test1",
- aliases = listOf("a", "b", "c")
- ),
- Emoji(
- name = "test2",
- aliases = listOf("a2`", "b2", "c2", "updated-alias")
- ),
- Emoji(
- name = "test3",
- aliases = listOf("a3", "b3", "c3", "d4")
- ),
- Emoji(
- name = "test4",
- aliases = listOf("")
- )
- )
-
- val ids = dao.insertAll(existsData.map { it.toRecord("misskey.pantasystem.com") })
- ids.mapIndexed { index, l ->
- existsData[index].aliases?.map {
- CustomEmojiAliasRecord(l, it)
- }?.let {
- dao.insertAliases(it)
- }
-
- }
-
- val delegate = CustomEmojiUpInsertDelegate(dao)
- delegate("misskey.pantasystem.com", emojis)
-
- val actual = dao.findBy("misskey.pantasystem.com").map {
- it.toModel()
- }
-
- val expect = emojis.map { emoji ->
- emoji.copy(
- aliases = emoji.aliases?.filterNot {
- it.isBlank()
- }
- )
- }
- Assert.assertEquals(
- expect,
- actual
- )
- }
-
-}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/converters/NoteDTOEntityConverter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/converters/NoteDTOEntityConverter.kt
index f15c1f6fc9..b4821880af 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/converters/NoteDTOEntityConverter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/converters/NoteDTOEntityConverter.kt
@@ -7,6 +7,8 @@ import net.pantasystem.milktea.api.misskey.notes.ReactionAcceptanceType
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.channel.Channel
import net.pantasystem.milktea.model.drive.FileProperty
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
+import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.notes.Note
import net.pantasystem.milktea.model.notes.Visibility
import net.pantasystem.milktea.model.notes.poll.Poll
@@ -16,9 +18,25 @@ import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class NoteDTOEntityConverter @Inject constructor() {
+class NoteDTOEntityConverter @Inject constructor(
+ private val customEmojiAspectRatioDataSource: CustomEmojiAspectRatioDataSource,
+ private val imageCacheRepository: ImageCacheRepository,
+) {
suspend fun convert(noteDTO: NoteDTO, account: Account): Note {
+ val emojis = (noteDTO.emojiList + (noteDTO.reactionEmojiList))
+ val aspects = customEmojiAspectRatioDataSource.findIn(emojis.mapNotNull {
+ it.url ?: it.uri
+ }).getOrElse {
+ emptyList()
+ }.associate {
+ it.uri to it.aspectRatio
+ }
+ val fileCaches = imageCacheRepository.findBySourceUrls(emojis.mapNotNull {
+ it.url ?: it.uri
+ }).associateBy {
+ it.sourceUrl
+ }
val visibility = Visibility(
noteDTO.visibility ?: NoteVisibilityType.Public,
isLocalOnly = noteDTO.localOnly ?: false,
@@ -37,7 +55,9 @@ class NoteDTOEntityConverter @Inject constructor() {
viaMobile = noteDTO.viaMobile,
visibility = visibility,
localOnly = noteDTO.localOnly,
- emojis = noteDTO.emojiList + (noteDTO.reactionEmojiList),
+ emojis = emojis.map {
+ it.toModel(aspects[it.url ?: it.uri], fileCaches[it.url ?: it.uri]?.cachePath)
+ },
app = null,
fileIds = noteDTO.fileIds?.map { FileProperty.Id(account.accountId, it) },
poll = noteDTO.poll?.toPoll(),
@@ -66,11 +86,18 @@ class NoteDTOEntityConverter @Inject constructor() {
name = it.name
)
},
- isAcceptingOnlyLikeReaction = when(noteDTO.reactionAcceptance){
+ isAcceptingOnlyLikeReaction = when (noteDTO.reactionAcceptance) {
ReactionAcceptanceType.LikeOnly4Remote -> noteDTO.uri != null
ReactionAcceptanceType.LikeOnly -> true
+ ReactionAcceptanceType.NonSensitiveOnly -> false
+ ReactionAcceptanceType.NonSensitiveOnly4LocalOnly4Remote -> false
null -> false
},
+ isNotAcceptingSensitiveReaction = when (noteDTO.reactionAcceptance) {
+ ReactionAcceptanceType.NonSensitiveOnly -> true
+ ReactionAcceptanceType.NonSensitiveOnly4LocalOnly4Remote -> true
+ else -> false
+ },
),
maxReactionsPerAccount = 1
)
@@ -96,8 +123,12 @@ fun PollDTO?.toPoll(): Poll? {
@Throws(IllegalArgumentException::class)
-fun Visibility(type: NoteVisibilityType, isLocalOnly: Boolean, visibleUserIds: List? = null): Visibility {
- return when(type){
+fun Visibility(
+ type: NoteVisibilityType,
+ isLocalOnly: Boolean,
+ visibleUserIds: List? = null,
+): Visibility {
+ return when (type) {
NoteVisibilityType.Public -> Visibility.Public(isLocalOnly)
NoteVisibilityType.Followers -> Visibility.Followers(isLocalOnly)
NoteVisibilityType.Home -> Visibility.Home(isLocalOnly)
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/converters/TootDTOEntityConverter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/converters/TootDTOEntityConverter.kt
index f5a81b308c..5156f6cc78 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/converters/TootDTOEntityConverter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/converters/TootDTOEntityConverter.kt
@@ -5,6 +5,7 @@ import net.pantasystem.milktea.common.Logger
import net.pantasystem.milktea.data.infrastructure.toPoll
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.drive.FileProperty
+import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.instance.MastodonInstanceInfoRepository
import net.pantasystem.milktea.model.nodeinfo.NodeInfo
import net.pantasystem.milktea.model.nodeinfo.NodeInfoRepository
@@ -18,6 +19,7 @@ import javax.inject.Singleton
class TootDTOEntityConverter @Inject constructor(
private val instanceInfoRepository: MastodonInstanceInfoRepository,
private val nodeInfoRepository: NodeInfoRepository,
+ private val imageCacheRepository: ImageCacheRepository,
private val loggerFactory: Logger.Factory,
) {
@@ -34,6 +36,15 @@ class TootDTOEntityConverter @Inject constructor(
}
.getOrNull()?.isReactionAvailable
?: false) || nodeInfo?.type is NodeInfo.SoftwareType.Mastodon.Fedibird
+
+ val urls = (statusDTO.emojiReactions?.mapNotNull {
+ it.url
+ }?: emptyList()) + (statusDTO.emojiReactions?.mapNotNull {
+ it.url
+ }?: emptyList())
+ val imageCaches = imageCacheRepository.findBySourceUrls(urls).associateBy {
+ it.sourceUrl
+ }
return with(statusDTO) {
Note(
id = Note.Id(account.accountId, id),
@@ -53,9 +64,9 @@ class TootDTOEntityConverter @Inject constructor(
),
localOnly = null,
emojis = emojis.map {
- it.toEmoji()
+ it.toEmoji(imageCaches[it.url]?.cachePath)
} + (emojiReactions?.mapNotNull {
- it.getEmoji()
+ it.getEmoji(imageCaches[it.url]?.cachePath)
} ?: emptyList()),
app = null,
reactionCounts = emojiReactions?.map {
@@ -79,7 +90,7 @@ class TootDTOEntityConverter @Inject constructor(
FileProperty.Id(account.accountId, it.id)
},
poll = poll.toPoll(),
- maxReactionsPerAccount = instanceInfoResult.getOrNull()?.configuration?.emojiReactions?.maxReactionsPerAccount ?: 0,
+ maxReactionsPerAccount = instanceInfoResult.getOrNull()?.maxReactionsPerAccount ?: 0,
type = Note.Type.Mastodon(
favorited = favourited,
reblogged = reblogged,
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/converters/UserDTOEntityConverter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/converters/UserDTOEntityConverter.kt
index 8f351987c7..39f4307475 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/converters/UserDTOEntityConverter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/converters/UserDTOEntityConverter.kt
@@ -2,13 +2,22 @@ package net.pantasystem.milktea.data.converters
import net.pantasystem.milktea.api.misskey.users.UserDTO
import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
+import net.pantasystem.milktea.model.emoji.CustomEmojiParser
+import net.pantasystem.milktea.model.emoji.CustomEmojiRepository
+import net.pantasystem.milktea.model.emoji.EmojiResolvedType
+import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.notes.Note
import net.pantasystem.milktea.model.user.User
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class UserDTOEntityConverter @Inject constructor() {
+class UserDTOEntityConverter @Inject constructor(
+ private val customEmojiRepository: CustomEmojiRepository,
+ private val customEmojiAspectRatioDataSource: CustomEmojiAspectRatioDataSource,
+ private val imageCacheRepository: ImageCacheRepository,
+) {
suspend fun convert(account: Account, userDTO: UserDTO, isDetail: Boolean = false): User {
val instanceInfo = userDTO.instance?.let {
@@ -21,11 +30,41 @@ class UserDTOEntityConverter @Inject constructor() {
themeColor = it.themeColor
)
}
+
+ val urls = userDTO.emojiList?.mapNotNull {
+ it.url ?: it.uri
+ } ?: emptyList()
+ val aspects = customEmojiAspectRatioDataSource.findIn(urls).getOrElse {
+ emptyList()
+ }.associateBy {
+ it.uri
+ }
+ val fileCaches = imageCacheRepository.findBySourceUrls(urls).associateBy {
+ it.sourceUrl
+ }
+
+ var emojis = userDTO.emojiList?.map {
+ it.toModel(
+ aspects[it.url ?: it.uri]?.aspectRatio,
+ cachePath = fileCaches[it.url ?: it.uri]?.cachePath
+ )
+ } ?: emptyList()
+ emojis = (emojis + CustomEmojiParser.parse(
+ userDTO.host ?: account.getHost(),
+ emojis,
+ userDTO.name ?: userDTO.userName,
+ customEmojiRepository.getAndConvertToMap(account.getHost()),
+ ).emojis.mapNotNull {
+ (it.result as? EmojiResolvedType.Resolved)?.emoji
+ }).distinctBy {
+ it.name to it.host to it.url to it.uri
+ }
+
if (isDetail) {
return User.Detail(
id = User.Id(account.accountId, userDTO.id),
avatarUrl = userDTO.avatarUrl,
- emojis = userDTO.emojiList ?: emptyList(),
+ emojis = emojis,
isBot = userDTO.isBot,
isCat = userDTO.isCat,
name = userDTO.name,
@@ -52,7 +91,7 @@ class UserDTOEntityConverter @Inject constructor() {
updatedAt = userDTO.updatedAt,
fields = userDTO.fields?.map {
User.Field(it.name, it.value)
- }?: emptyList(),
+ } ?: emptyList(),
isPublicReactions = userDTO.publicReactions ?: false,
),
related = User.Related(
@@ -60,7 +99,8 @@ class UserDTOEntityConverter @Inject constructor() {
isFollower = userDTO.isFollowed ?: false,
isBlocking = userDTO.isBlocking ?: false,
isMuting = userDTO.isMuted ?: false,
- hasPendingFollowRequestFromYou = userDTO.hasPendingFollowRequestFromYou ?: false,
+ hasPendingFollowRequestFromYou = userDTO.hasPendingFollowRequestFromYou
+ ?: false,
hasPendingFollowRequestToYou = userDTO.hasPendingFollowRequestToYou ?: false,
)
)
@@ -68,7 +108,7 @@ class UserDTOEntityConverter @Inject constructor() {
return User.Simple(
id = User.Id(account.accountId, userDTO.id),
avatarUrl = userDTO.avatarUrl,
- emojis = userDTO.emojiList ?: emptyList(),
+ emojis = emojis,
isBot = userDTO.isBot,
isCat = userDTO.isCat,
name = userDTO.name,
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/CustomEmojiModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/CustomEmojiModule.kt
index d24771d86c..e112265cf7 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/CustomEmojiModule.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/CustomEmojiModule.kt
@@ -6,7 +6,9 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import net.pantasystem.milktea.data.infrastructure.emoji.CustomEmojiApiAdapter
import net.pantasystem.milktea.data.infrastructure.emoji.CustomEmojiApiAdapterImpl
+import net.pantasystem.milktea.data.infrastructure.emoji.CustomEmojiAspectRatioDataSourceImpl
import net.pantasystem.milktea.data.infrastructure.emoji.CustomEmojiRepositoryImpl
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
import net.pantasystem.milktea.model.emoji.CustomEmojiRepository
import javax.inject.Singleton
@@ -20,4 +22,8 @@ abstract class CustomEmojiModule {
@Singleton
@Binds
internal abstract fun bindCustomEmojiRepository(impl: CustomEmojiRepositoryImpl): CustomEmojiRepository
+
+ @Singleton
+ @Binds
+ internal abstract fun bindAspectRatioDataSource(impl: CustomEmojiAspectRatioDataSourceImpl): CustomEmojiAspectRatioDataSource
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/DbModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/DbModule.kt
index 91b97e78f7..75d7d1bae7 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/DbModule.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/DbModule.kt
@@ -10,7 +10,6 @@ import dagger.hilt.components.SingletonComponent
import net.pantasystem.milktea.data.infrastructure.*
import net.pantasystem.milktea.data.infrastructure.account.db.AccountDAO
import net.pantasystem.milktea.data.infrastructure.drive.DriveFileRecordDao
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiDAO
import net.pantasystem.milktea.data.infrastructure.group.GroupDao
import net.pantasystem.milktea.data.infrastructure.instance.db.InstanceInfoDao
import net.pantasystem.milktea.data.infrastructure.instance.db.MastodonInstanceInfoDAO
@@ -118,10 +117,6 @@ object DbModule {
@Singleton
fun provideMastodonInfoDao(db: DataBase): MastodonInstanceInfoDAO = db.mastodonInstanceInfoDao()
- @Provides
- @Singleton
- fun provideCustomEmojiDao(db: DataBase): CustomEmojiDAO = db.customEmojiDao()
-
@Provides
@Singleton
fun provideNotificationJsonCacheDao(db: DataBase) = db.notificationJsonCacheRecordDAO()
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ImageCacheBindModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ImageCacheBindModule.kt
new file mode 100644
index 0000000000..10314d9f7e
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ImageCacheBindModule.kt
@@ -0,0 +1,18 @@
+package net.pantasystem.milktea.data.di.module
+
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import net.pantasystem.milktea.data.infrastructure.image.ImageCacheRepositoryImpl
+import net.pantasystem.milktea.model.image.ImageCacheRepository
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class ImageCacheBindModule {
+
+ @Binds
+ @Singleton
+ abstract fun bindImageCacheRepository(impl: ImageCacheRepositoryImpl): ImageCacheRepository
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/InstanceInfoModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/InstanceInfoModule.kt
index c65e4615b4..264c1f013c 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/InstanceInfoModule.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/InstanceInfoModule.kt
@@ -5,20 +5,24 @@ import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import net.pantasystem.milktea.data.infrastructure.instance.FeatureEnablesImpl
-import net.pantasystem.milktea.data.infrastructure.instance.InstanceInfoRepositoryImpl
+import net.pantasystem.milktea.data.infrastructure.instance.online.user.count.OnlineUserCountRepositoryImpl
import net.pantasystem.milktea.model.instance.FeatureEnables
-import net.pantasystem.milktea.model.instance.InstanceInfoRepository
+import net.pantasystem.milktea.model.instance.online.user.count.OnlineUserCountRepository
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
abstract class InstanceInfoBindModule {
+// @Binds
+// @Singleton
+// abstract fun bindInstanceInfoRepository(impl: InstanceInfoRepositoryImpl): InstanceInfoRepository
+
@Binds
@Singleton
- abstract fun bindInstanceInfoRepository(impl: InstanceInfoRepositoryImpl): InstanceInfoRepository
+ abstract fun bindFeatureEnables(impl: FeatureEnablesImpl): FeatureEnables
@Binds
@Singleton
- abstract fun bindFeatureEnables(impl: FeatureEnablesImpl): FeatureEnables
+ abstract fun bindOnlineUserCountRepository(impl: OnlineUserCountRepositoryImpl): OnlineUserCountRepository
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/NoteModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/NoteModule.kt
index d5306ff874..6c9058f036 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/NoteModule.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/NoteModule.kt
@@ -1,25 +1,25 @@
package net.pantasystem.milktea.data.di.module
+import android.content.Context
import dagger.Binds
import dagger.Module
+import dagger.Provides
import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import net.pantasystem.milktea.app_store.notes.NoteTranslationStore
import net.pantasystem.milktea.app_store.notes.TimelineStore
-import net.pantasystem.milktea.data.infrastructure.notes.NoteStreamingImpl
-import net.pantasystem.milktea.data.infrastructure.notes.NoteTranslationStoreImpl
-import net.pantasystem.milktea.data.infrastructure.notes.TimelineStoreImpl
+import net.pantasystem.milktea.common.getPreferences
+import net.pantasystem.milktea.data.infrastructure.notes.*
import net.pantasystem.milktea.data.infrastructure.notes.draft.DraftNoteRepositoryImpl
import net.pantasystem.milktea.data.infrastructure.notes.impl.DraftNoteServiceImpl
import net.pantasystem.milktea.data.infrastructure.notes.impl.NoteRepositoryImpl
import net.pantasystem.milktea.data.infrastructure.notes.impl.ObjectBoxNoteDataSource
import net.pantasystem.milktea.data.infrastructure.notes.renote.RenotesPagingServiceImpl
-import net.pantasystem.milktea.model.notes.NoteDataSource
-import net.pantasystem.milktea.model.notes.NoteRepository
-import net.pantasystem.milktea.model.notes.NoteStreaming
+import net.pantasystem.milktea.model.notes.*
import net.pantasystem.milktea.model.notes.draft.DraftNoteRepository
import net.pantasystem.milktea.model.notes.draft.DraftNoteService
-import net.pantasystem.milktea.model.notes.renote.RenotesPagingService
+import net.pantasystem.milktea.model.notes.repost.RenotesPagingService
import javax.inject.Singleton
@Module
@@ -54,6 +54,24 @@ abstract class NoteBindModule{
@Singleton
abstract fun provideDraftNoteRepository(impl: DraftNoteRepositoryImpl): DraftNoteRepository
+ @Binds
+ @Singleton
+ abstract fun bindReplyStreaming(impl: ReplyStreamingImpl): ReplyStreaming
+
+}
+
+@Module
+@InstallIn(SingletonComponent::class)
+object NoteProvideModule {
+ @Provides
+ @Singleton
+ fun provideTimelineScrollPositionRepository(
+ @ApplicationContext context: Context
+ ): TimelineScrollPositionRepository {
+ return TimelineScrollPositionRepositoryImpl(
+ context.getPreferences()
+ )
+ }
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ReactionModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ReactionModule.kt
index 06207ac85a..59c219d280 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ReactionModule.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/ReactionModule.kt
@@ -5,32 +5,26 @@ import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import net.pantasystem.milktea.data.infrastructure.emoji.UserEmojiConfigRepositoryImpl
-import net.pantasystem.milktea.data.infrastructure.notes.reaction.impl.InMemoryReactionHistoryDataSource
-import net.pantasystem.milktea.data.infrastructure.notes.reaction.impl.ReactionHistoryPaginatorImpl
+import net.pantasystem.milktea.data.infrastructure.notes.reaction.impl.ReactionUserRepositoryImpl
import net.pantasystem.milktea.data.infrastructure.notes.reaction.impl.history.ReactionHistoryRepositoryImpl
import net.pantasystem.milktea.model.emoji.UserEmojiConfigRepository
-import net.pantasystem.milktea.model.notes.reaction.ReactionHistoryDataSource
-import net.pantasystem.milktea.model.notes.reaction.ReactionHistoryPaginator
+import net.pantasystem.milktea.model.notes.reaction.ReactionUserRepository
import net.pantasystem.milktea.model.notes.reaction.history.ReactionHistoryRepository
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
abstract class ReactionModule {
-
- @Binds
- @Singleton
- abstract fun bindReactionHistoryDataSource(ds: InMemoryReactionHistoryDataSource): ReactionHistoryDataSource
-
+
@Binds
@Singleton
- abstract fun bindReactionHistoryPaging(impl: ReactionHistoryPaginatorImpl.Factory): ReactionHistoryPaginator.Factory
+ abstract fun bindReactionHistoryRepository(impl: ReactionHistoryRepositoryImpl): ReactionHistoryRepository
@Binds
@Singleton
- abstract fun bindReactionHistoryRepository(impl: ReactionHistoryRepositoryImpl): ReactionHistoryRepository
+ abstract fun bindUserEmojiConfigRepository(impl: UserEmojiConfigRepositoryImpl): UserEmojiConfigRepository
@Binds
@Singleton
- abstract fun bindUserEmojiConfigRepository(impl: UserEmojiConfigRepositoryImpl): UserEmojiConfigRepository
+ abstract fun bindReactionUserRepository(impl: ReactionUserRepositoryImpl): ReactionUserRepository
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/SocketModule.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/SocketModule.kt
index 85ab2ff232..0d7f5b1286 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/SocketModule.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/di/module/SocketModule.kt
@@ -19,7 +19,9 @@ import net.pantasystem.milktea.data.streaming.SocketWithAccountProvider
import net.pantasystem.milktea.data.streaming.StreamingAPIProvider
import net.pantasystem.milktea.data.streaming.impl.SocketWithAccountProviderImpl
import net.pantasystem.milktea.model.account.AccountRepository
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
import net.pantasystem.milktea.model.emoji.EmojiEventHandler
+import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.notes.NoteCaptureAPIAdapter
import net.pantasystem.milktea.model.notes.NoteDataSource
import net.pantasystem.milktea.model.notification.NotificationStreaming
@@ -76,6 +78,8 @@ object SocketModule {
noteDataSource: NoteDataSource,
noteDataSourceAdder: NoteDataSourceAdder,
streamingAPIProvider: StreamingAPIProvider,
+ customEmojiAspectRatioDataSource: CustomEmojiAspectRatioDataSource,
+ imageCacheRepository: ImageCacheRepository,
): NoteCaptureAPIAdapter {
return NoteCaptureAPIAdapterImpl(
accountRepository = accountRepository,
@@ -86,6 +90,8 @@ object SocketModule {
dispatcher = Dispatchers.IO,
noteDataSourceAdder = noteDataSourceAdder,
streamingAPIProvider = streamingAPIProvider,
+ customEmojiAspectRatioDataSource = customEmojiAspectRatioDataSource,
+ imageCacheRepository = imageCacheRepository,
)
}
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/DataBase.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/DataBase.kt
index 5b044769fe..e4361ba66b 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/DataBase.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/DataBase.kt
@@ -18,7 +18,6 @@ import net.pantasystem.milktea.data.infrastructure.drive.DriveFileRecordDao
import net.pantasystem.milktea.data.infrastructure.emoji.Utf8EmojiDTO
import net.pantasystem.milktea.data.infrastructure.emoji.Utf8EmojisDAO
import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiAliasRecord
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiDAO
import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiRecord
import net.pantasystem.milktea.data.infrastructure.filter.db.MastodonFilterDao
import net.pantasystem.milktea.data.infrastructure.filter.db.MastodonWordFilterRecord
@@ -114,8 +113,10 @@ import net.pantasystem.milktea.data.infrastructure.user.renote.mute.db.RenoteMut
RenoteMuteRecord::class,
FedibirdCapabilitiesRecord::class,
+
+ PleromaMetadataFeatures::class,
],
- version = 43,
+ version = 49,
exportSchema = true,
autoMigrations = [
AutoMigration(from = 11, to = 12),
@@ -150,6 +151,12 @@ import net.pantasystem.milktea.data.infrastructure.user.renote.mute.db.RenoteMut
AutoMigration(from = 40, to = 41),
AutoMigration(from = 41, to = 42),
AutoMigration(from = 42, to = 43),
+ AutoMigration(from = 43, to = 44),
+ AutoMigration(from = 44, to = 45),
+ AutoMigration(from = 45, to = 46),
+ AutoMigration(from = 46, to = 47),
+ AutoMigration(from = 47, to = 48),
+ AutoMigration(from = 48, to = 49),
],
views = [UserView::class, GroupMemberView::class, UserListMemberView::class]
)
@@ -207,7 +214,7 @@ abstract class DataBase : RoomDatabase() {
abstract fun mastodonInstanceInfoDao(): MastodonInstanceInfoDAO
- abstract fun customEmojiDao(): CustomEmojiDAO
+// abstract fun customEmojiDao(): CustomEmojiDAO
abstract fun notificationJsonCacheRecordDAO(): NotificationJsonCacheRecordDAO
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/TootEntityConverters.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/TootEntityConverters.kt
index bc53de1b20..989dd5161a 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/TootEntityConverters.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/TootEntityConverters.kt
@@ -238,6 +238,19 @@ fun Instance.toModel(): MastodonInstanceInfo {
}
)
},
- fedibirdCapabilities = fedibirdCapabilities,
+ fedibirdCapabilities = fedibirdCapabilities?.let {
+ it + listOfNotNull(
+ if (featureQuote == true) "feature_quote" else null,
+ )
+ },
+ pleroma = pleroma?.let { pleroma ->
+ MastodonInstanceInfo.Pleroma(
+ metadata = pleroma.metadata.let { m ->
+ MastodonInstanceInfo.Pleroma.Metadata(
+ features = m.features
+ )
+ }
+ )
+ }
)
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/SignOutUseCaseImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/SignOutUseCaseImpl.kt
index e0be0efc39..541d2ca833 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/SignOutUseCaseImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/SignOutUseCaseImpl.kt
@@ -26,7 +26,7 @@ class SignOutUseCaseImpl @Inject constructor(
subscriptionUnRegistration
.unregister(account.accountId)
}
- Account.InstanceType.MASTODON -> {}
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {}
}
}.mapCancellableCatching {
accountRepository.delete(account)
@@ -40,7 +40,7 @@ class SignOutUseCaseImpl @Inject constructor(
socketWithAccountProvider.get(account.accountId)?.disconnect()
}
}
- Account.InstanceType.MASTODON -> {}
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {}
}
}.mapCancellableCatching {
accountStore.initialize()
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/converter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/converter.kt
index 0bc5cc9cce..0cd51344fa 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/converter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/converter.kt
@@ -27,6 +27,19 @@ fun AccessToken.Mastodon.newAccount(
)
}
+fun AccessToken.Pleroma.newAccount(
+ instanceDomain: String
+): Account {
+ return Account(
+ remoteId = this.account.id,
+ userName = this.account.username,
+ instanceDomain = instanceDomain,
+ token = accessToken,
+ instanceType = Account.InstanceType.PLEROMA,
+ pages = emptyList()
+ )
+}
+
fun AccessToken.MisskeyIdAndPassword.newAccount(instanceDomain: String): Account {
return this.user.newAccount(
instanceDomain,
@@ -45,6 +58,9 @@ fun AccessToken.newAccount(instanceDomain: String): Account {
is AccessToken.MisskeyIdAndPassword -> {
this.newAccount(instanceDomain)
}
+ is AccessToken.Pleroma -> {
+ this.newAccount(instanceDomain)
+ }
}
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/db/AccountRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/db/AccountRecord.kt
index 1eabfb36f6..59e6af5f0c 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/db/AccountRecord.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/db/AccountRecord.kt
@@ -111,6 +111,7 @@ class AccountInstanceTypeConverter {
return when (type) {
Account.InstanceType.MISSKEY -> "misskey"
Account.InstanceType.MASTODON -> "mastodon"
+ Account.InstanceType.PLEROMA -> "pleroma"
}
}
@@ -120,6 +121,7 @@ class AccountInstanceTypeConverter {
return when (type) {
"misskey" -> Account.InstanceType.MISSKEY
"mastodon" -> Account.InstanceType.MASTODON
+ "pleroma" -> Account.InstanceType.PLEROMA
else -> throw IllegalArgumentException("未知のアカウント種別です")
}
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/page/db/PageRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/page/db/PageRecord.kt
index 0b2a217179..6f9bb30691 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/page/db/PageRecord.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/account/page/db/PageRecord.kt
@@ -19,6 +19,12 @@ data class PageRecord(
@Embedded val pageParams: PageRecordParams,
+ @ColumnInfo(name = "isSavePagePosition")
+ val isSavePagePosition: Boolean? = false,
+
+ @ColumnInfo(name = "attachedAccountId")
+ val attachedAccountId: Long? = null,
+
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "pageId")
var pageId: Long
@@ -31,6 +37,8 @@ data class PageRecord(
title = page.title,
weight = page.weight,
pageParams = PageRecordParams.from(page.pageParams),
+ isSavePagePosition = page.isSavePagePosition,
+ attachedAccountId = page.attachedAccountId,
pageId = page.pageId
)
}
@@ -42,7 +50,9 @@ data class PageRecord(
title = title,
weight = weight,
pageParams = pageParams.toParams(),
- pageId = pageId
+ pageId = pageId,
+ attachedAccountId = attachedAccountId,
+ isSavePagePosition = isSavePagePosition ?: false
)
}
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/ap/ApResolverRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/ap/ApResolverRepositoryImpl.kt
index 98475abe1d..76897b20e7 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/ap/ApResolverRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/ap/ApResolverRepositoryImpl.kt
@@ -53,7 +53,7 @@ class ApResolverRepositoryImpl @Inject constructor(
}
}
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).search(
q = uri,
resolve = true
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/Authorization.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/Authorization.kt
index eb1c96179a..cdf5915ae4 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/Authorization.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/Authorization.kt
@@ -43,6 +43,16 @@ sealed interface Authorization {
}
}
+ data class Pleroma(
+ override val instanceBaseURL: String,
+ val client: AppType.Pleroma,
+ val scope: String
+ ) : Waiting4UserAuthorization {
+ override fun generateAuthUrl(): String {
+ return client.generateAuthUrl(instanceBaseURL, scope)
+ }
+ }
+
}
@@ -74,5 +84,12 @@ fun Authorization.Waiting4UserAuthorization.Companion.from(state: TemporarilyAut
viaName = state.viaName
)
}
+ is TemporarilyAuthState.Pleroma -> {
+ Authorization.Waiting4UserAuthorization.Pleroma(
+ client = state.app,
+ instanceBaseURL = state.instanceDomain,
+ scope = state.scope
+ )
+ }
}
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/AccessToken.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/AccessToken.kt
index 2b8b7de42b..525af29fd4 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/AccessToken.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/AccessToken.kt
@@ -27,6 +27,14 @@ sealed interface AccessToken {
val createdAt: Long,
val account: MastodonAccountDTO
) : AccessToken
+
+ data class Pleroma(
+ override val accessToken: String,
+ val tokenType: String,
+ val scope: String,
+ val createdAt: Long,
+ val account: MastodonAccountDTO
+ ) : AccessToken
}
@@ -46,4 +54,14 @@ fun MastodonAccessToken.toModel(account: MastodonAccountDTO) : AccessToken.Masto
scope = scope,
account = account
)
+}
+
+fun MastodonAccessToken.toPleromaModel(account: MastodonAccountDTO): AccessToken.Pleroma {
+ return AccessToken.Pleroma(
+ accessToken = accessToken,
+ tokenType = tokenType,
+ createdAt = createdAt,
+ scope = scope,
+ account = account
+ )
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthBridge.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthBridge.kt
index b031736200..f3ccddf713 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthBridge.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthBridge.kt
@@ -23,6 +23,13 @@ sealed interface TemporarilyAuthState {
val scope: String,
) : TemporarilyAuthState
+
+ data class Pleroma(
+ override val instanceDomain: String,
+ override val enabledDateEnd: Date,
+ val app: AppType.Pleroma,
+ val scope: String,
+ ) : TemporarilyAuthState
}
fun AppType.Misskey.createAuth(instanceDomain: String, session: Session, timeLimit: Date = Date(System.currentTimeMillis() + 3600 * 1000)): TemporarilyAuthState.Misskey {
@@ -43,4 +50,13 @@ fun AppType.Mastodon.createAuth(instanceDomain: String, scope: String, timeLimit
enabledDateEnd = timeLimit,
app = this
)
+}
+
+fun AppType.Pleroma.createAuth(instanceDomain: String, scope: String, timeLimit: Date = Date(System.currentTimeMillis() + 3600 * 1000)): TemporarilyAuthState.Pleroma {
+ return TemporarilyAuthState.Pleroma(
+ scope = scope,
+ instanceDomain = instanceDomain,
+ enabledDateEnd = timeLimit,
+ app = this
+ )
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthStore.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthStore.kt
index 996b10644e..3e2cc95a3d 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthStore.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/auth/custom/CustomAuthStore.kt
@@ -63,6 +63,20 @@ class CustomAuthStore(private val sharedPreferences: SharedPreferences){
apply()
}
}
+ is TemporarilyAuthState.Pleroma -> {
+ sharedPreferences.edit().apply {
+ putString(MASTODON_SCOPE, customAuthBridge.scope)
+ putString(INSTANCE_DOMAIN, customAuthBridge.instanceDomain)
+ putString(REDIRECT_URI, customAuthBridge.app.redirectUri)
+
+ putLong(ENABLED_DATE_END, customAuthBridge.enabledDateEnd.time)
+ putString(MASTODON_APP_CLIENT_ID, customAuthBridge.app.clientId)
+ putString(MASTODON_APP_CLIENT_SECRET, customAuthBridge.app.clientSecret)
+ putString(MASTODON_APP_ID, customAuthBridge.app.id)
+ putString(MASTODON_APP_NAME, customAuthBridge.app.name)
+ putString(TYPE, "pleroma")
+ }.apply()
+ }
}
@@ -107,6 +121,20 @@ class CustomAuthStore(private val sharedPreferences: SharedPreferences){
scope = it.getString(MASTODON_SCOPE, null)?: return null
)
}
+ "pleroma" -> {
+ TemporarilyAuthState.Pleroma(
+ app = AppType.Pleroma(
+ clientId = it.getString(MASTODON_APP_CLIENT_ID, null)?: return null,
+ clientSecret = it.getString(MASTODON_APP_CLIENT_SECRET, null)?: return null,
+ redirectUri = it.getString(REDIRECT_URI, null)?: return null,
+ id = it.getString(MASTODON_APP_ID, null)?: return null,
+ name = it.getString(MASTODON_APP_NAME, null)?: return null,
+ ),
+ instanceDomain = instanceDomain,
+ enabledDateEnd = enabledDate,
+ scope = it.getString(MASTODON_SCOPE, null)?: return null
+ )
+ }
else -> null
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryPagingStoreImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryPagingStoreImpl.kt
index b8b4df21d4..951da27bc7 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryPagingStoreImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryPagingStoreImpl.kt
@@ -4,14 +4,23 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex
import net.pantasystem.milktea.api.misskey.drive.RequestFolder
-import net.pantasystem.milktea.common.*
-import net.pantasystem.milktea.common.paginator.*
+import net.pantasystem.milktea.app_store.drive.DriveDirectoryPagingStore
+import net.pantasystem.milktea.common.Encryption
+import net.pantasystem.milktea.common.PageableState
+import net.pantasystem.milktea.common.StateContent
+import net.pantasystem.milktea.common.paginator.EntityConverter
+import net.pantasystem.milktea.common.paginator.IdGetter
+import net.pantasystem.milktea.common.paginator.PaginationState
+import net.pantasystem.milktea.common.paginator.PreviousLoader
+import net.pantasystem.milktea.common.paginator.PreviousPagingController
+import net.pantasystem.milktea.common.paginator.StateLocker
+import net.pantasystem.milktea.common.runCancellableCatching
+import net.pantasystem.milktea.common.throwIfHasError
import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.account.AccountRepository
import net.pantasystem.milktea.model.account.UnauthorizedException
import net.pantasystem.milktea.model.drive.Directory
-import net.pantasystem.milktea.app_store.drive.DriveDirectoryPagingStore
import javax.inject.Inject
class DriveDirectoryPagingStoreImpl @Inject constructor(
@@ -41,8 +50,8 @@ class DriveDirectoryPagingStoreImpl @Inject constructor(
pagingImpl.setState(PageableState.Fixed(StateContent.NotExist()))
}
- override suspend fun loadPrevious() {
- controller.loadPrevious()
+ override suspend fun loadPrevious(): Result {
+ return controller.loadPrevious()
}
override suspend fun setAccount(account: Account?) {
@@ -100,20 +109,29 @@ class DriveDirectoryPagingImpl(
}
override suspend fun getSinceId(): String? {
- return (_state.value.content as? StateContent.Exist)?.rawContent?.firstOrNull()?.id
+ return (_state.value.content as? StateContent.Exist)?.rawContent?.firstOrNull()?.id?.directoryId
}
override suspend fun getUntilId(): String? {
- return (_state.value.content as? StateContent.Exist)?.rawContent?.lastOrNull()?.id
+ return (_state.value.content as? StateContent.Exist)?.rawContent?.lastOrNull()?.id?.directoryId
}
override suspend fun loadPrevious(): Result> {
return runCancellableCatching {
val account = account ?: throw UnauthorizedException()
misskeyAPIProvider.get(account)
- .getFolders(RequestFolder(i = account.token, untilId = getUntilId(), folderId = directory?.id))
+ .getFolders(
+ RequestFolder(
+ i = account.token,
+ untilId = getUntilId(),
+ folderId = directory?.id?.directoryId
+ )
+ )
.throwIfHasError()
.body()!!
+ .map {
+ it.toModel(account)
+ }
}
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryRepositoryImpl.kt
index 8e0a72e41e..ed6944a924 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveDirectoryRepositoryImpl.kt
@@ -3,6 +3,7 @@ package net.pantasystem.milktea.data.infrastructure.drive
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import net.pantasystem.milktea.api.misskey.drive.CreateFolder
+import net.pantasystem.milktea.api.misskey.drive.ShowFolderRequest
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common.throwIfHasError
import net.pantasystem.milktea.common_android.hilt.IODispatcher
@@ -10,6 +11,7 @@ import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
import net.pantasystem.milktea.model.account.AccountRepository
import net.pantasystem.milktea.model.drive.CreateDirectory
import net.pantasystem.milktea.model.drive.Directory
+import net.pantasystem.milktea.model.drive.DirectoryId
import net.pantasystem.milktea.model.drive.DriveDirectoryRepository
import javax.inject.Inject
@@ -28,8 +30,23 @@ class DriveDirectoryRepositoryImpl @Inject constructor(
i = account.token,
name = createDirectory.directoryName,
parentId = createDirectory.parentId
- )).throwIfHasError().body()!!
+ )).throwIfHasError().body()!!.toModel(account)
}
}
}
+
+ override suspend fun findOne(id: DirectoryId): Result = runCancellableCatching {
+ withContext(ioDispatcher) {
+ val account = accountRepository.get(id.accountId).getOrThrow()
+ val api = misskeyAPIProvider.get(account)
+ api.showFolder(
+ ShowFolderRequest(
+ i = account.token,
+ folderId = id.directoryId
+ )
+ ).throwIfHasError().body()!!.toModel(account)
+ }
+ }
+
+
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveFileRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveFileRepositoryImpl.kt
index 7ab435fa25..ca9391af04 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveFileRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/DriveFileRepositoryImpl.kt
@@ -4,18 +4,14 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import net.pantasystem.milktea.api.misskey.drive.DeleteFileDTO
import net.pantasystem.milktea.api.misskey.drive.ShowFile
-import net.pantasystem.milktea.api.misskey.drive.UpdateFileDTO
-import net.pantasystem.milktea.api.misskey.drive.from
+import net.pantasystem.milktea.api.misskey.drive.toJsonObject
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common.throwIfHasError
import net.pantasystem.milktea.common_android.hilt.IODispatcher
import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
import net.pantasystem.milktea.data.converters.FilePropertyDTOEntityConverter
import net.pantasystem.milktea.model.account.GetAccount
-import net.pantasystem.milktea.model.drive.DriveFileRepository
-import net.pantasystem.milktea.model.drive.FileProperty
-import net.pantasystem.milktea.model.drive.FilePropertyDataSource
-import net.pantasystem.milktea.model.drive.UpdateFileProperty
+import net.pantasystem.milktea.model.drive.*
import net.pantasystem.milktea.model.file.AppFile
import javax.inject.Inject
@@ -50,14 +46,10 @@ class DriveFileRepositoryImpl @Inject constructor(
val api = misskeyAPIProvider.get(account.normalizedInstanceUri)
val fileProperty = find(id)
val result = api.updateFile(
- UpdateFileDTO(
- account.token,
- fileId = id.fileId,
- isSensitive = !fileProperty.isSensitive,
- name = fileProperty.name,
- folderId = fileProperty.folderId,
- comment = fileProperty.comment
- )
+ UpdateFileProperty(
+ fileProperty.id,
+ isSensitive = ValueType.Some(!fileProperty.isSensitive)
+ ).toJsonObject(account.token)
).throwIfHasError()
driveFileDataSource.add(
@@ -100,9 +92,8 @@ class DriveFileRepositoryImpl @Inject constructor(
val res =
misskeyAPIProvider.get(getAccount.get(updateFileProperty.fileId.accountId))
.updateFile(
- UpdateFileDTO.from(
+ updateFileProperty.toJsonObject(
getAccount.get(updateFileProperty.fileId.accountId).token,
- updateFileProperty,
)
).throwIfHasError()
.body()!!
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/MediatorFilePropertyDataSource.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/MediatorFilePropertyDataSource.kt
index 6524af7d67..b811c5e65d 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/MediatorFilePropertyDataSource.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/MediatorFilePropertyDataSource.kt
@@ -1,7 +1,13 @@
package net.pantasystem.milktea.data.infrastructure.drive
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import net.pantasystem.milktea.common.Logger
import net.pantasystem.milktea.common.collection.LRUCache
@@ -144,6 +150,9 @@ class MediatorFilePropertyDataSource @Inject constructor(
}
override fun observeIn(ids: List): Flow> {
+ if (ids.isEmpty()) {
+ return flowOf(emptyList())
+ }
val accountIds = ids.map { it.accountId }.distinct()
val flows = accountIds.map { accountId ->
driveFileRecordDao.observeIn(
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/file_paginator.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/file_paginator.kt
index 5baba950c4..e7477d4747 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/file_paginator.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/file_paginator.kt
@@ -9,7 +9,12 @@ import net.pantasystem.milktea.api.misskey.drive.RequestFile
import net.pantasystem.milktea.app_store.drive.FilePropertyPagingStore
import net.pantasystem.milktea.common.PageableState
import net.pantasystem.milktea.common.StateContent
-import net.pantasystem.milktea.common.paginator.*
+import net.pantasystem.milktea.common.paginator.EntityConverter
+import net.pantasystem.milktea.common.paginator.IdGetter
+import net.pantasystem.milktea.common.paginator.PaginationState
+import net.pantasystem.milktea.common.paginator.PreviousLoader
+import net.pantasystem.milktea.common.paginator.PreviousPagingController
+import net.pantasystem.milktea.common.paginator.StateLocker
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common.throwIfHasError
import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
@@ -57,8 +62,8 @@ class FilePropertyPagingStoreImpl @Inject constructor(
override val isLoading: Boolean get() = this.filePropertyPagingImpl.mutex.isLocked
- override suspend fun loadPrevious() {
- previousPagingController.loadPrevious()
+ override suspend fun loadPrevious(): Result {
+ return previousPagingController.loadPrevious()
}
override suspend fun clear() {
@@ -69,7 +74,7 @@ class FilePropertyPagingStoreImpl @Inject constructor(
override suspend fun setCurrentDirectory(directory: Directory?) {
this.clear()
- this.currentDirectoryId = directory?.id
+ this.currentDirectoryId = directory?.id?.directoryId
}
override suspend fun setCurrentAccount(account: Account?) {
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/uploaders.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/uploaders.kt
index ec4e765162..af5a95f633 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/uploaders.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/drive/uploaders.kt
@@ -72,7 +72,7 @@ class OkHttpFileUploaderProvider(
instances[account.accountId]
?: throw IllegalStateException("生成したはずのインスタンスが消滅しました!!")
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
map[account.accountId] = MastodonOkHttpFileUploader(
context,
account,
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiApiAdapter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiApiAdapter.kt
index 6f1436b0f4..3036dc52a7 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiApiAdapter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiApiAdapter.kt
@@ -32,6 +32,14 @@ internal class CustomEmojiApiAdapterImpl @Inject constructor(
it.toEmoji()
}
}
+ is NodeInfo.SoftwareType.Pleroma -> {
+ val emojis = mastodonAPIProvider.get(nodeInfo.host).getCustomEmojis()
+ .throwIfHasError()
+ .body()
+ emojis?.map {
+ it.toEmoji()
+ }
+ }
is NodeInfo.SoftwareType.Misskey -> {
if (
nodeInfo.type.getVersion() >= Version("13")
@@ -42,6 +50,8 @@ internal class CustomEmojiApiAdapterImpl @Inject constructor(
.throwIfHasError()
.body()
emojis?.emojis?.map {
+ it.toModel()
+ }?.map {
it.copy(
url = if (it.url == null) V13EmojiUrlResolver.resolve(it, "https://${nodeInfo.host}") else it.url,
uri = if (it.uri == null) V13EmojiUrlResolver.resolve(it, "https://${nodeInfo.host}") else it.uri,
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiAspectRatioDataSourceImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiAspectRatioDataSourceImpl.kt
new file mode 100644
index 0000000000..e53cd3c1cf
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiAspectRatioDataSourceImpl.kt
@@ -0,0 +1,83 @@
+package net.pantasystem.milktea.data.infrastructure.emoji
+
+import io.objectbox.Box
+import io.objectbox.BoxStore
+import io.objectbox.kotlin.awaitCallInTx
+import io.objectbox.kotlin.boxFor
+import io.objectbox.kotlin.inValues
+import io.objectbox.query.QueryBuilder
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+import net.pantasystem.milktea.common.runCancellableCatching
+import net.pantasystem.milktea.common_android.hilt.IODispatcher
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatio
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
+import javax.inject.Inject
+
+class CustomEmojiAspectRatioDataSourceImpl @Inject constructor(
+ private val boxStore: BoxStore,
+ @IODispatcher val coroutineDispatcher: CoroutineDispatcher,
+) : CustomEmojiAspectRatioDataSource {
+ private val aspectBox: Box by lazy {
+ boxStore.boxFor()
+ }
+
+ override suspend fun findIn(uris: List): Result> =
+ runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ aspectBox.query().inValues(
+ CustomEmojiAspectRatioRecord_.uri,
+ uris.toTypedArray(),
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().find().map {
+ CustomEmojiAspectRatio(
+ uri = it.uri,
+ aspectRatio = it.aspectRatio
+ )
+ }
+ }
+ }
+
+ override suspend fun findOne(uri: String): Result = runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ aspectBox.query().equal(
+ CustomEmojiAspectRatioRecord_.uri,
+ uri,
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()?.let {
+ CustomEmojiAspectRatio(
+ uri = it.uri,
+ aspectRatio = it.aspectRatio
+ )
+ } ?: throw NoSuchElementException()
+ }
+ }
+
+ override suspend fun save(ratio: CustomEmojiAspectRatio): Result = runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ boxStore.awaitCallInTx {
+ val exists = aspectBox.query().equal(
+ CustomEmojiAspectRatioRecord_.uri,
+ ratio.uri,
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()
+ if (exists == null) {
+ aspectBox.put(CustomEmojiAspectRatioRecord.from(ratio))
+ } else {
+ aspectBox.put(exists.copy(aspectRatio = ratio.aspectRatio))
+ }
+ }
+ }
+ findOne(ratio.uri).getOrThrow()
+ }
+
+ override suspend fun delete(ratio: CustomEmojiAspectRatio): Result = runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ aspectBox.query().equal(
+ CustomEmojiAspectRatioRecord_.uri,
+ ratio.uri,
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().remove()
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiAspectRatioRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiAspectRatioRecord.kt
new file mode 100644
index 0000000000..870db85e60
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiAspectRatioRecord.kt
@@ -0,0 +1,24 @@
+package net.pantasystem.milktea.data.infrastructure.emoji
+
+import io.objectbox.annotation.Entity
+import io.objectbox.annotation.Id
+import io.objectbox.annotation.Unique
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatio
+
+@Entity
+data class CustomEmojiAspectRatioRecord (
+ @Id var id: Long = 0,
+ @Unique
+ var uri: String = "",
+ var aspectRatio: Float = 1f,
+) {
+
+ companion object {
+ fun from(model: CustomEmojiAspectRatio): CustomEmojiAspectRatioRecord {
+ return CustomEmojiAspectRatioRecord(
+ uri = model.uri,
+ aspectRatio = model.aspectRatio
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiRepositoryImpl.kt
index 3a143cd760..b21b3b6d9b 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/CustomEmojiRepositoryImpl.kt
@@ -3,24 +3,32 @@ package net.pantasystem.milktea.data.infrastructure.emoji
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
-import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.asFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common_android.hilt.IODispatcher
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiDAO
-import net.pantasystem.milktea.data.infrastructure.emoji.delegate.CustomEmojiUpInsertDelegate
+import net.pantasystem.milktea.data.infrastructure.emoji.objectbox.CustomEmojiRecord
+import net.pantasystem.milktea.data.infrastructure.emoji.objectbox.ObjectBoxCustomEmojiRecordDAO
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
import net.pantasystem.milktea.model.emoji.CustomEmojiRepository
import net.pantasystem.milktea.model.emoji.Emoji
+import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.nodeinfo.NodeInfo
import net.pantasystem.milktea.model.nodeinfo.NodeInfoRepository
import javax.inject.Inject
internal class CustomEmojiRepositoryImpl @Inject constructor(
private val nodeInfoRepository: NodeInfoRepository,
- private val customEmojiDAO: CustomEmojiDAO,
private val customEmojiApiAdapter: CustomEmojiApiAdapter,
private val customEmojiCache: CustomEmojiCache,
- private val upInsert: CustomEmojiUpInsertDelegate,
+ private val aspectRatioDataSource: CustomEmojiAspectRatioDataSource,
+ private val imageCacheRepository: ImageCacheRepository,
+ private val objectBoxCustomEmojiDao: ObjectBoxCustomEmojiRecordDAO,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : CustomEmojiRepository {
@@ -31,12 +39,33 @@ internal class CustomEmojiRepositoryImpl @Inject constructor(
return@withContext emojis
}
val nodeInfo = nodeInfoRepository.find(host).getOrThrow()
- emojis = customEmojiDAO.findBy(host).map {
+ emojis = objectBoxCustomEmojiDao.findBy(host).map {
it.toModel()
}
+
if (emojis.isEmpty()) {
emojis = fetch(nodeInfo).getOrThrow()
- upInsert(nodeInfo.host, emojis)
+
+ objectBoxCustomEmojiDao.replaceAll(host, emojis.map {
+ CustomEmojiRecord.from(it, nodeInfo.host)
+ })
+ }
+ val aspects = aspectRatioDataSource.findIn(emojis.mapNotNull {
+ it.url ?: it.uri
+ }).getOrElse { emptyList() }.associateBy {
+ it.uri
+ }
+ val fileCaches = imageCacheRepository.findBySourceUrls(emojis.mapNotNull {
+ it.url ?: it.uri
+ }).associateBy {
+ it.sourceUrl
+ }
+
+ emojis = emojis.map {
+ it.copy(
+ aspectRatio = aspects[it.url ?: it.uri]?.aspectRatio ?: it.aspectRatio,
+ cachePath = fileCaches[it.url ?: it.uri]?.cachePath,
+ )
}
customEmojiCache.put(host, emojis)
emojis
@@ -45,8 +74,25 @@ internal class CustomEmojiRepositoryImpl @Inject constructor(
override suspend fun findByName(host: String, name: String): Result> = runCancellableCatching {
withContext(ioDispatcher) {
- customEmojiDAO.findBy(host, name).map {
- it.toModel()
+ val dtoList = objectBoxCustomEmojiDao.findBy(host, name)
+ val aspects = aspectRatioDataSource.findIn(
+ dtoList.mapNotNull {
+ it.url ?: it.uri
+ }
+ ).getOrElse { emptyList() }.associateBy {
+ it.uri
+ }
+ val fileCaches = imageCacheRepository.findBySourceUrls(dtoList.mapNotNull {
+ it.url ?: it.uri
+ }).associateBy {
+ it.sourceUrl
+ }
+ dtoList.map {
+ it.toModel(
+ aspects[it.url ?: it.uri]?.aspectRatio,
+ fileCaches[it.url ?: it.uri]?.cachePath,
+ )
+
}
}
}
@@ -54,10 +100,28 @@ internal class CustomEmojiRepositoryImpl @Inject constructor(
override suspend fun sync(host: String): Result = runCancellableCatching {
withContext(ioDispatcher) {
val nodeInfo = nodeInfoRepository.find(host).getOrThrow()
- val emojis = fetch(nodeInfo).getOrThrow()
- customEmojiDAO.deleteByHost(nodeInfo.host)
+ var emojis = fetch(nodeInfo).getOrThrow()
+ val aspects = aspectRatioDataSource.findIn(emojis.mapNotNull {
+ it.url ?: it.uri
+ }).getOrElse { emptyList() }.associateBy {
+ it.uri
+ }
+ val fileCaches = imageCacheRepository.findBySourceUrls(emojis.mapNotNull {
+ it.url ?: it.uri
+ }).associateBy {
+ it.sourceUrl
+ }
+ emojis = emojis.map {
+ it.copy(
+ aspectRatio = aspects[it.url ?: it.uri]?.aspectRatio ?: it.aspectRatio,
+ cachePath = fileCaches[it.url ?: it.uri]?.cachePath,
+ )
+ }
+
customEmojiCache.put(host, emojis)
- upInsert(nodeInfo.host, emojis)
+ objectBoxCustomEmojiDao.replaceAll(host, emojis.map {
+ CustomEmojiRecord.from(it, nodeInfo.host)
+ })
}
}
@@ -67,9 +131,24 @@ internal class CustomEmojiRepositoryImpl @Inject constructor(
return suspend {
nodeInfoRepository.find(host).getOrThrow()
}.asFlow().flatMapLatest {
- customEmojiDAO.observeBy(host).map { list ->
+ objectBoxCustomEmojiDao.observeBy(host).map { list ->
+ val aspects = aspectRatioDataSource.findIn(
+ list.mapNotNull {
+ it.url ?: it.uri
+ }
+ ).getOrElse { emptyList() }.associateBy {
+ it.uri
+ }
+ val fileCaches = imageCacheRepository.findBySourceUrls(list.mapNotNull {
+ it.url ?: it.uri
+ }).associateBy {
+ it.sourceUrl
+ }
list.map {
- it.toModel()
+ it.toModel(
+ aspects[it.url ?: it.uri]?.aspectRatio,
+ fileCaches[it.url ?: it.uri]?.cachePath,
+ )
}
}
}.onEach {
@@ -87,7 +166,11 @@ internal class CustomEmojiRepositoryImpl @Inject constructor(
override suspend fun addEmojis(host: String, emojis: List): Result = runCancellableCatching {
withContext(ioDispatcher) {
- upInsert(host, emojis)
+ objectBoxCustomEmojiDao.appendEmojis(
+ emojis.map {
+ CustomEmojiRecord.from(it, host)
+ }
+ )
// NOTE: inMemキャッシュなどを更新したい
findBy(host).getOrThrow()
}
@@ -95,7 +178,7 @@ internal class CustomEmojiRepositoryImpl @Inject constructor(
override suspend fun deleteEmojis(host: String, emojis: List): Result = runCancellableCatching {
withContext(ioDispatcher) {
- customEmojiDAO.deleteByHostAndNames(host, emojis.map { it.name })
+ objectBoxCustomEmojiDao.deleteByHostAndNames(host, emojis.map { it.name })
// NOTE: inMemキャッシュなどを更新したい
findBy(host).getOrThrow()
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImpl.kt
index 65d464ae05..ff9410893c 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/Utf8EmojiRepositoryImpl.kt
@@ -1,95 +1,95 @@
package net.pantasystem.milktea.data.infrastructure.emoji
-
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
-import net.pantasystem.milktea.common.Logger
-import net.pantasystem.milktea.common.runCancellableCatching
-import net.pantasystem.milktea.model.emoji.Utf8Emoji
-import net.pantasystem.milktea.model.emoji.UtfEmojiRepository
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import javax.inject.Inject
-
-const val RAW_EMOJI_SOURCE_URL: String =
- "https://raw.githubusercontent.com/amio/emoji.json/master/emoji.json"
-
-class Utf8EmojiRepositoryImpl @Inject constructor(
- coroutineScope: CoroutineScope,
- private val loggerFactory: Logger.Factory?,
- private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
- private val utf8EmojisDAO: Utf8EmojisDAO,
-) : UtfEmojiRepository {
-
- private val logger by lazy {
- loggerFactory?.create("Utf8EmojiRepository")
- }
- private var isFetched = false
- private var emojis: List = emptyList()
-
-
- private val client by lazy {
- OkHttpClient.Builder()
- .build()
- }
-
- private val json = Json { ignoreUnknownKeys = true }
-
-
- init {
- coroutineScope.launch(dispatcher) {
- runCancellableCatching {
- findAll()
- }.onFailure {
- logger?.error("絵文字の取得に失敗しました", it)
- }
- }
- coroutineScope.launch(dispatcher) {
- utf8EmojisDAO.findAll().onEach { list ->
- emojis = list.map { it.toModel() }
- }.catch {
- logger?.error("絵文字の取得に失敗しました", it)
- }.launchIn(this)
- }
- }
-
- override suspend fun findAll(): List {
- if (!isFetched) {
- utf8EmojisDAO.clear()
- val fetchedEmojis = fetchEmojis()
- val list = fetchedEmojis.map { it.toDTO() }
- utf8EmojisDAO.insertAll(list)
- isFetched = true
- emojis = fetchedEmojis
- return fetchedEmojis
- }
- return emojis
-
- }
-
- override suspend fun exists(emoji: CharSequence): Boolean {
- logger?.debug { "call exists emoji:$emoji, ${emoji.javaClass.simpleName}" }
- return emojis.any {
- emoji.startsWith(it.char)
- }.also {
- logger?.debug { "call exists emoji:$emoji, ${emoji.javaClass.simpleName} return :$it" }
- logger?.debug { "target emojis:${emojis.filter { c ->emoji.startsWith(c.char) }}" }
- }
- }
-
-
- @Suppress("BlockingMethodInNonBlockingContext")
- private suspend fun fetchEmojis(): List {
- return withContext(dispatcher) {
- val res = client.newCall(Request.Builder().url(RAW_EMOJI_SOURCE_URL).build()).execute()
- if (!res.isSuccessful) {
- throw Exception("取得に失敗しました")
- }
- val body = res.body!!.string()
- json.decodeFromString(body)
- }
- }
-}
\ No newline at end of file
+//
+//import kotlinx.coroutines.*
+//import kotlinx.coroutines.flow.catch
+//import kotlinx.coroutines.flow.launchIn
+//import kotlinx.coroutines.flow.onEach
+//import kotlinx.serialization.decodeFromString
+//import kotlinx.serialization.json.Json
+//import net.pantasystem.milktea.common.Logger
+//import net.pantasystem.milktea.common.runCancellableCatching
+//import net.pantasystem.milktea.model.emoji.Utf8Emoji
+//import net.pantasystem.milktea.model.emoji.UtfEmojiRepository
+//import okhttp3.OkHttpClient
+//import okhttp3.Request
+//import javax.inject.Inject
+//
+//const val RAW_EMOJI_SOURCE_URL: String =
+// "https://raw.githubusercontent.com/amio/emoji.json/master/emoji.json"
+//
+//class Utf8EmojiRepositoryImpl @Inject constructor(
+// coroutineScope: CoroutineScope,
+// private val loggerFactory: Logger.Factory?,
+// private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
+// private val utf8EmojisDAO: Utf8EmojisDAO,
+//) : UtfEmojiRepository {
+//
+// private val logger by lazy {
+// loggerFactory?.create("Utf8EmojiRepository")
+// }
+// private var isFetched = false
+// private var emojis: List = emptyList()
+//
+//
+// private val client by lazy {
+// OkHttpClient.Builder()
+// .build()
+// }
+//
+// private val json = Json { ignoreUnknownKeys = true }
+//
+//
+// init {
+// coroutineScope.launch(dispatcher) {
+// runCancellableCatching {
+// findAll()
+// }.onFailure {
+// logger?.error("絵文字の取得に失敗しました", it)
+// }
+// }
+// coroutineScope.launch(dispatcher) {
+// utf8EmojisDAO.findAll().onEach { list ->
+// emojis = list.map { it.toModel() }
+// }.catch {
+// logger?.error("絵文字の取得に失敗しました", it)
+// }.launchIn(this)
+// }
+// }
+//
+// override suspend fun findAll(): List {
+// if (!isFetched) {
+// utf8EmojisDAO.clear()
+// val fetchedEmojis = fetchEmojis()
+// val list = fetchedEmojis.map { it.toDTO() }
+// utf8EmojisDAO.insertAll(list)
+// isFetched = true
+// emojis = fetchedEmojis
+// return fetchedEmojis
+// }
+// return emojis
+//
+// }
+//
+// override suspend fun exists(emoji: CharSequence): Boolean {
+// logger?.debug { "call exists emoji:$emoji, ${emoji.javaClass.simpleName}" }
+// return emojis.any {
+// emoji.startsWith(it.char)
+// }.also {
+// logger?.debug { "call exists emoji:$emoji, ${emoji.javaClass.simpleName} return :$it" }
+// logger?.debug { "target emojis:${emojis.filter { c ->emoji.startsWith(c.char) }}" }
+// }
+// }
+//
+//
+// @Suppress("BlockingMethodInNonBlockingContext")
+// private suspend fun fetchEmojis(): List {
+// return withContext(dispatcher) {
+// val res = client.newCall(Request.Builder().url(RAW_EMOJI_SOURCE_URL).build()).execute()
+// if (!res.isSuccessful) {
+// throw Exception("取得に失敗しました")
+// }
+// val body = res.body!!.string()
+// json.decodeFromString(body)
+// }
+// }
+//}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiDAO.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiDAO.kt
deleted file mode 100644
index 5d987fabe3..0000000000
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiDAO.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.pantasystem.milktea.data.infrastructure.emoji.db
-
-import androidx.room.*
-import kotlinx.coroutines.flow.Flow
-
-@Dao
-interface CustomEmojiDAO {
-
- @Transaction
- @Query("select * from custom_emojis where emojiHost = :host and name = :name")
- suspend fun findBy(host: String, name: String): List
-
-
- @Transaction
- @Query("select * from custom_emojis where emojiHost = :host")
- suspend fun findBy(host: String): List
-
- @Transaction
- @Query("select * from custom_emojis where emojiHost = :host")
- fun observeBy(host: String): Flow>
-
-
- @Insert(onConflict = OnConflictStrategy.IGNORE)
- suspend fun insert(customEmoji: CustomEmojiRecord): Long
-
- @Insert(onConflict = OnConflictStrategy.IGNORE)
- suspend fun insertAll(emojis: List): List
-
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun insertAliases(emojis: List)
-
- @Query("delete from custom_emoji_aliases where emojiId = :emojiId")
- suspend fun deleteAliasByEmojiId(emojiId: Long)
-
- @Query("delete from custom_emojis where emojiHost = :host")
- suspend fun deleteByHost(host: String)
-
- @Query("delete from custom_emojis where emojiHost = :host and name in (:names)")
- suspend fun deleteByHostAndNames(host: String, names: List)
-
- @Update
- suspend fun update(customEmoji: CustomEmojiRecord)
-}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiRecord.kt
index b1bfbb2909..aa64cb4891 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiRecord.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/db/CustomEmojiRecord.kt
@@ -1,7 +1,10 @@
package net.pantasystem.milktea.data.infrastructure.emoji.db
-import androidx.room.*
-import net.pantasystem.milktea.model.emoji.Emoji
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.ForeignKey
+import androidx.room.Index
+import androidx.room.PrimaryKey
@Entity(
tableName = "custom_emojis",
@@ -61,43 +64,3 @@ data class CustomEmojiAliasRecord(
@ColumnInfo(name = "value")
val value: String
)
-
-data class CustomEmojiRelated(
- @Embedded val emoji: CustomEmojiRecord,
-
- @Relation(
- parentColumn = "id",
- entityColumn = "emojiId"
- )
- val aliases: List
-) {
-
- @Ignore
- fun toModel(): Emoji {
- return Emoji(
- id = emoji.serverId,
- name = emoji.name,
- uri = emoji.uri,
- url = emoji.url,
- category = emoji.category,
- type = emoji.type,
- aliases = aliases.map {
- it.value
- },
-
- )
- }
-}
-
-fun Emoji.toRecord(host: String, dbId: Long = 0L): CustomEmojiRecord {
- return CustomEmojiRecord(
- serverId = id,
- name = name,
- uri = uri,
- url = url,
- id = dbId,
- type = type,
- category = category,
- emojiHost = host,
- )
-}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/delegate/CustomEmojiUpInsertDelegate.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/delegate/CustomEmojiUpInsertDelegate.kt
deleted file mode 100644
index 1285313c96..0000000000
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/delegate/CustomEmojiUpInsertDelegate.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package net.pantasystem.milktea.data.infrastructure.emoji.delegate
-
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiAliasRecord
-import net.pantasystem.milktea.data.infrastructure.emoji.db.CustomEmojiDAO
-import net.pantasystem.milktea.data.infrastructure.emoji.db.toRecord
-import net.pantasystem.milktea.model.emoji.Emoji
-import javax.inject.Inject
-
-internal class CustomEmojiUpInsertDelegate @Inject constructor(
- private val customEmojiDAO: CustomEmojiDAO,
-) {
- suspend operator fun invoke(host: String, emojis: List) {
- val record = emojis.map {
- it.toRecord(host)
- }
- val ids = customEmojiDAO.insertAll(record)
-
- ids.mapIndexed { index, id ->
- if (id == -1L) {
- customEmojiDAO.findBy(host, emojis[index].name).firstOrNull()?.let { record ->
- customEmojiDAO.update(emojis[index].toRecord(host, record.emoji.id))
- customEmojiDAO.deleteAliasByEmojiId(record.emoji.id)
- emojis[index].aliases?.map {
- CustomEmojiAliasRecord(
- emojiId = record.emoji.id,
- it
- )
- }?.let {
- customEmojiDAO.insertAliases(it)
- }
- record.emoji.id
- }
- } else {
- emojis[index].aliases?.filterNot {
- it.isBlank()
- }?.map {
- CustomEmojiAliasRecord(
- emojiId = id,
- it
- )
- }?.let {
- customEmojiDAO.insertAliases(it)
- }
- id
- }
- }
- }
-}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/objectbox/CustomEmojiRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/objectbox/CustomEmojiRecord.kt
new file mode 100644
index 0000000000..eb677f74e9
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/objectbox/CustomEmojiRecord.kt
@@ -0,0 +1,60 @@
+package net.pantasystem.milktea.data.infrastructure.emoji.objectbox
+
+import io.objectbox.annotation.Entity
+import io.objectbox.annotation.Id
+import io.objectbox.annotation.Index
+import net.pantasystem.milktea.model.emoji.Emoji
+
+@Entity
+data class CustomEmojiRecord(
+ @Id var id: Long = 0L,
+ var serverId: String? = null,
+
+ @Index var name: String = "",
+
+ @Index var emojiHost: String = "",
+
+ var url: String? = null,
+
+ var uri: String? = null,
+
+ var type: String? = null,
+
+ var category: String? = null,
+
+ var aliases: MutableList = mutableListOf()
+) {
+ companion object {
+ fun from(model: Emoji, host: String): CustomEmojiRecord {
+ val record = CustomEmojiRecord()
+ record.applyModel(model, host)
+ return record
+ }
+ }
+
+ fun applyModel(model: Emoji, host: String) {
+ serverId = model.id
+ name = model.name
+ emojiHost = host
+ url = model.url
+ uri = model.uri
+ type = model.type
+ category = model.category
+ aliases = model.aliases?.toMutableList() ?: mutableListOf()
+ }
+
+ fun toModel(aspectRatio: Float? = null, cachePath: String? = null): Emoji {
+ return Emoji(
+ id = serverId,
+ name = name,
+ host = emojiHost,
+ url = url,
+ uri = uri,
+ type = type,
+ category = category,
+ aliases = aliases,
+ aspectRatio = aspectRatio,
+ cachePath = cachePath,
+ )
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/objectbox/ObjectBoxCustomEmojiRecordDAO.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/objectbox/ObjectBoxCustomEmojiRecordDAO.kt
new file mode 100644
index 0000000000..fcb7a9b679
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/emoji/objectbox/ObjectBoxCustomEmojiRecordDAO.kt
@@ -0,0 +1,66 @@
+package net.pantasystem.milktea.data.infrastructure.emoji.objectbox
+
+import io.objectbox.Box
+import io.objectbox.BoxStore
+import io.objectbox.kotlin.awaitCallInTx
+import io.objectbox.kotlin.boxFor
+import io.objectbox.kotlin.inValues
+import io.objectbox.kotlin.toFlow
+import io.objectbox.query.QueryBuilder
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ObjectBoxCustomEmojiRecordDAO @Inject constructor(
+ val boxStore: BoxStore
+) {
+
+ private val customEmojiBoxStore: Box by lazy {
+ boxStore.boxFor()
+ }
+
+ fun findBy(host: String, name: String): List {
+ return customEmojiBoxStore.query()
+ .equal(CustomEmojiRecord_.emojiHost, host, QueryBuilder.StringOrder.CASE_INSENSITIVE)
+ .equal(CustomEmojiRecord_.name, name, QueryBuilder.StringOrder.CASE_INSENSITIVE)
+ .build()
+ .find()
+ }
+
+ fun findBy(host: String): List {
+ return customEmojiBoxStore.query()
+ .equal(CustomEmojiRecord_.emojiHost, host, QueryBuilder.StringOrder.CASE_INSENSITIVE)
+ .build()
+ .find()
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ fun observeBy(host: String): Flow> {
+ return customEmojiBoxStore.query()
+ .equal(CustomEmojiRecord_.emojiHost, host, QueryBuilder.StringOrder.CASE_INSENSITIVE)
+ .build()
+ .subscribe()
+ .toFlow()
+ }
+
+ suspend fun replaceAll(host: String, records: List) {
+ boxStore.awaitCallInTx {
+ customEmojiBoxStore.remove(findBy(host))
+ customEmojiBoxStore.put(records)
+ }
+ }
+
+ fun deleteByHostAndNames(host: String, names: List) {
+ customEmojiBoxStore.query()
+ .equal(CustomEmojiRecord_.emojiHost, host, QueryBuilder.StringOrder.CASE_INSENSITIVE)
+ .inValues(CustomEmojiRecord_.name, names.toTypedArray(), QueryBuilder.StringOrder.CASE_INSENSITIVE)
+ .build()
+ .remove()
+ }
+
+ fun appendEmojis(records: List) {
+ customEmojiBoxStore.put(records)
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/hashtag/HashtagRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/hashtag/HashtagRepositoryImpl.kt
index 211634c086..3e38a85fa5 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/hashtag/HashtagRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/hashtag/HashtagRepositoryImpl.kt
@@ -1,25 +1,85 @@
package net.pantasystem.milktea.data.infrastructure.hashtag
-import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
+import net.pantasystem.milktea.api.misskey.EmptyRequest
import net.pantasystem.milktea.api.misskey.hashtag.SearchHashtagRequest
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common.throwIfHasError
+import net.pantasystem.milktea.common_android.hilt.IODispatcher
+import net.pantasystem.milktea.data.api.mastodon.MastodonAPIProvider
import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
+import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.account.AccountRepository
+import net.pantasystem.milktea.model.hashtag.HashTag
import net.pantasystem.milktea.model.hashtag.HashtagRepository
import javax.inject.Inject
class HashtagRepositoryImpl @Inject constructor(
- val misskeyAPIProvider: MisskeyAPIProvider,
-): HashtagRepository {
- override suspend fun search(baseUrl: String, query: String, limit: Int, offset: Int): Result> = runCancellableCatching{
- withContext(Dispatchers.IO) {
+ private val accountRepository: AccountRepository,
+ private val misskeyAPIProvider: MisskeyAPIProvider,
+ private val mastodonAPIProvider: MastodonAPIProvider,
+ @IODispatcher private val ioDispatcher: CoroutineDispatcher,
+) : HashtagRepository {
+ override suspend fun search(
+ accountId: Long,
+ query: String,
+ limit: Int,
+ offset: Int,
+ ): Result> = runCancellableCatching {
+ withContext(ioDispatcher) {
+ val account = accountRepository.get(accountId).getOrThrow()
+ when (account.instanceType) {
+ Account.InstanceType.MISSKEY -> {
+ misskeyAPIProvider.get(account).searchHashtag(
+ SearchHashtagRequest(
+ query = query,
+ limit = limit,
+ offset = offset
+ )
+ ).throwIfHasError().body() ?: emptyList()
+ }
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
+ mastodonAPIProvider.get(account).search(
+ q = query,
+ limit = limit,
+ offset = offset,
+ type = "hashtags"
+ ).throwIfHasError().body()?.hashtags?.map {
+ it.name
+ } ?: emptyList()
+ }
+ }
- misskeyAPIProvider.get(baseUrl).searchHashtag(SearchHashtagRequest(
- query = query,
- limit = limit,
- offset = offset
- )).throwIfHasError().body() ?: emptyList()
}
}
+
+ override suspend fun trends(accountId: Long): Result> = runCancellableCatching {
+ withContext(ioDispatcher) {
+ val account = accountRepository.get(accountId).getOrThrow()
+ when(account.instanceType) {
+ Account.InstanceType.MISSKEY -> {
+ val body = requireNotNull(
+ misskeyAPIProvider.get(account).getTrendingHashtags(EmptyRequest)
+ .throwIfHasError()
+ .body()
+ )
+ body.map {
+ it.toModel()
+ }
+ }
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
+ val body = requireNotNull(
+ mastodonAPIProvider.get(account).getTagTrends()
+ .throwIfHasError()
+ .body()
+ )
+ body.map {
+ it.toModel()
+ }
+ }
+ }
+ }
+
+ }
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/image/ImageCacheRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/image/ImageCacheRecord.kt
new file mode 100644
index 0000000000..9877e8a0d4
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/image/ImageCacheRecord.kt
@@ -0,0 +1,38 @@
+package net.pantasystem.milktea.data.infrastructure.image
+
+import io.objectbox.annotation.Entity
+import io.objectbox.annotation.Id
+import io.objectbox.annotation.Unique
+import kotlinx.datetime.Instant
+import net.pantasystem.milktea.model.image.ImageCache
+
+@Entity
+data class ImageCacheRecord(
+ @Id var id: Long = 0L,
+ @Unique var sourceUrl: String = "",
+ var cachePath: String = "",
+ var cachedAt: Long = 0L,
+) {
+
+ companion object {
+ fun from(model: ImageCache): ImageCacheRecord {
+ return ImageCacheRecord().also {
+ it.applyModel(model)
+ }
+ }
+ }
+ fun applyModel(model: ImageCache) {
+ sourceUrl = model.sourceUrl
+ cachePath = model.cachePath
+ cachedAt = model.cachedAt.toEpochMilliseconds()
+ }
+
+ fun toModel(): ImageCache {
+ return ImageCache(
+ sourceUrl = sourceUrl,
+ cachePath = cachePath,
+ cachedAt = Instant.fromEpochMilliseconds(cachedAt)
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/image/ImageCacheRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/image/ImageCacheRepositoryImpl.kt
new file mode 100644
index 0000000000..6fdea93e75
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/image/ImageCacheRepositoryImpl.kt
@@ -0,0 +1,188 @@
+package net.pantasystem.milktea.data.infrastructure.image
+
+import android.content.Context
+import android.graphics.BitmapFactory
+import dagger.hilt.android.qualifiers.ApplicationContext
+import io.objectbox.BoxStore
+import io.objectbox.kotlin.awaitCallInTx
+import io.objectbox.kotlin.inValues
+import io.objectbox.query.QueryBuilder
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+import kotlinx.datetime.Clock
+import net.pantasystem.milktea.api.misskey.OkHttpClientProvider
+import net.pantasystem.milktea.common.Hash
+import net.pantasystem.milktea.common_android.hilt.IODispatcher
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatio
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
+import net.pantasystem.milktea.model.image.ImageCache
+import net.pantasystem.milktea.model.image.ImageCacheRepository
+import okhttp3.Request
+import java.io.File
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.days
+
+
+class ImageCacheRepositoryImpl @Inject constructor(
+ private val boxStore: BoxStore,
+ private val okHttpClientProvider: OkHttpClientProvider,
+ private val customEmojiAspectRatioDataSource: CustomEmojiAspectRatioDataSource,
+ @ApplicationContext val context: Context,
+ @IODispatcher val coroutineDispatcher: CoroutineDispatcher,
+) : ImageCacheRepository {
+
+ companion object {
+ const val cacheDir = "milktea_image_caches"
+ val cacheExpireDuration = 7.days
+ val cacheIgnoreUpdateDuration = 3.days
+ }
+
+ private val imageCacheStore by lazy {
+ boxStore.boxFor(ImageCacheRecord::class.java)
+ }
+
+ override suspend fun save(url: String): ImageCache {
+ when (val cache = findBySourceUrl(url)) {
+ null -> Unit
+ else -> if (cache.cachedAt + cacheIgnoreUpdateDuration > Clock.System.now()) {
+ if (File(cache.cachePath).exists()) {
+ return cache
+ }
+ }
+ }
+ return withContext(coroutineDispatcher) {
+ val fileName = Hash.sha256(url)
+ val file = File(context.filesDir, cacheDir).apply {
+ if (!exists()) {
+ mkdirs()
+ }
+ }.resolve(fileName)
+
+ downloadAndSaveFile(url, file)
+
+ val cache = ImageCache(
+ sourceUrl = url,
+ cachePath = File(context.filesDir, cacheDir).resolve(fileName).absolutePath,
+ cachedAt = Clock.System.now()
+ )
+ upInsert(cache)
+ return@withContext cache
+ }
+ }
+
+ override suspend fun findBySourceUrl(url: String): ImageCache? {
+ return withContext(coroutineDispatcher) {
+ val now = Clock.System.now()
+ val record = imageCacheStore.query().equal(
+ ImageCacheRecord_.sourceUrl,
+ url,
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()
+ val model = record?.toModel()
+ if (model != null && now - model.cachedAt > cacheExpireDuration) {
+ imageCacheStore.remove(record)
+ null
+ } else {
+ model
+ }
+ }
+ }
+
+ override suspend fun deleteExpiredCaches() {
+ withContext(coroutineDispatcher) {
+ val now = Clock.System.now()
+ imageCacheStore.query().lessOrEqual(
+ ImageCacheRecord_.cachedAt,
+ now.toEpochMilliseconds()
+ ).build().remove()
+ }
+ }
+
+ override suspend fun clear() {
+ withContext(coroutineDispatcher) {
+ imageCacheStore.removeAll()
+ File(context.cacheDir, cacheDir).deleteRecursively()
+ }
+ }
+
+ override suspend fun findBySourceUrls(urls: List): List {
+ return withContext(coroutineDispatcher) {
+ val now = Clock.System.now()
+ val records = imageCacheStore.query().inValues(
+ ImageCacheRecord_.sourceUrl,
+ urls.toTypedArray(),
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().find()
+ records.mapNotNull { record ->
+ val model = record.toModel()
+ if (now - model.cachedAt > cacheExpireDuration) {
+ null
+ } else {
+ model
+ }
+ }
+ }
+ }
+
+ private suspend fun upInsert(cache: ImageCache) {
+ val record = ImageCacheRecord.from(
+ cache
+ )
+ boxStore.awaitCallInTx {
+ val existsRecord = imageCacheStore.query().equal(
+ ImageCacheRecord_.sourceUrl,
+ cache.sourceUrl,
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()
+ if (existsRecord == null) {
+ imageCacheStore.put(record)
+ } else {
+ existsRecord.applyModel(record.toModel())
+ imageCacheStore.put(existsRecord)
+ }
+ }
+ }
+
+ private suspend fun downloadAndSaveFile(url: String, file: File) {
+ file.outputStream().use { out ->
+ val req = Request.Builder().url(url).build()
+ val response = okHttpClientProvider.get().newCall(req).execute()
+ val contentLength = response.header("Content-Length")?.toLongOrNull()
+ response.body?.byteStream()
+ ?.use { inStream ->
+ val bytesCopied = inStream.copyTo(out)
+ if (contentLength != null && bytesCopied != contentLength) {
+ throw Exception("Download failed: url=$url")
+ }
+ }
+ val options = BitmapFactory.Options()
+ options.inJustDecodeBounds = true
+ val bitmap = BitmapFactory.decodeFile(
+ file.absolutePath, options
+ )
+ if (bitmap != null) {
+ val aspectRatio = options.outWidth.toFloat() / options.outHeight.toFloat()
+ customEmojiAspectRatioDataSource.save(
+ CustomEmojiAspectRatio(
+ uri = url,
+ aspectRatio = aspectRatio,
+ )
+ )
+ }
+
+ }
+ }
+
+ override suspend fun findCachedFileCount(reality: Boolean): Long {
+ return if (reality) {
+ val dir = File(context.filesDir, cacheDir).apply {
+ if (!exists()) {
+ mkdirs()
+ }
+ }
+ dir.listFiles()?.size?.toLong() ?: 0L
+ } else {
+ imageCacheStore.count()
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/InstanceInfoRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/InstanceInfoRepositoryImpl.kt
index a7d65c08e4..143ce5ea85 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/InstanceInfoRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/InstanceInfoRepositoryImpl.kt
@@ -1,117 +1,117 @@
package net.pantasystem.milktea.data.infrastructure.instance
+//
+//import kotlinx.coroutines.CoroutineDispatcher
+//import kotlinx.coroutines.flow.Flow
+//import kotlinx.coroutines.flow.flowOn
+//import kotlinx.coroutines.flow.map
+//import kotlinx.coroutines.withContext
+//import net.pantasystem.milktea.api.milktea.CreateInstanceRequest
+//import net.pantasystem.milktea.api.milktea.InstanceInfoResponse
+//import net.pantasystem.milktea.api.milktea.MilkteaAPIServiceBuilder
+//import net.pantasystem.milktea.common.runCancellableCatching
+//import net.pantasystem.milktea.common.throwIfHasError
+//import net.pantasystem.milktea.common_android.hilt.IODispatcher
+//import net.pantasystem.milktea.data.infrastructure.instance.db.InstanceInfoDao
+//import net.pantasystem.milktea.data.infrastructure.instance.db.InstanceInfoRecord
+//import net.pantasystem.milktea.model.instance.InstanceInfo
+//import net.pantasystem.milktea.model.instance.InstanceInfoRepository
+//import javax.inject.Inject
+//
+//class InstanceInfoRepositoryImpl @Inject constructor(
+// private val instanceInfoDao: InstanceInfoDao,
+// private val milkteaAPIServiceBuilder: MilkteaAPIServiceBuilder,
+// @IODispatcher private val ioDispatcher: CoroutineDispatcher
+//): InstanceInfoRepository {
+// private val milkteaAPIService by lazy {
+// milkteaAPIServiceBuilder.build("https://milktea.pantasystem.net")
+// }
+// override suspend fun findAll(): Result> = runCancellableCatching {
+// withContext(ioDispatcher) {
+// instanceInfoDao.findAll().map {
+// it.toModel()
+// }
+// }
+// }
+//
+// override suspend fun sync(): Result = runCancellableCatching {
+// withContext(ioDispatcher) {
+// val instances = requireNotNull(milkteaAPIService.getInstances().throwIfHasError().body())
+// val models = instances.map {
+// it.toModel()
+// }
+// instanceInfoDao.clear()
+// instanceInfoDao.insertAll(models.map {
+// it.toRecord()
+// })
+// }
+// }
+//
+// override suspend fun findOne(id: String): Result = runCancellableCatching {
+// withContext(ioDispatcher) {
+// instanceInfoDao.findById(id)?.toModel()
+// ?: throw NoSuchElementException("指定されたId($id)のInstanceInfoは存在しません")
+// }
+// }
+//
+// override fun observeAll(): Flow> {
+// return instanceInfoDao.observeAll().map { list ->
+// list.map {
+// it.toModel()
+// }
+// }.flowOn(ioDispatcher)
+// }
+//
+// override suspend fun findByHost(host: String): Result = runCancellableCatching{
+// withContext(ioDispatcher) {
+// instanceInfoDao.findByHost(host)?.toModel() ?: throw NoSuchElementException()
+// }
+// }
+// override fun observeByHost(host: String): Flow {
+// return instanceInfoDao.observeByHost(host).map {
+// it?.toModel()
+// }
+// }
+//
+// override suspend fun postInstance(host: String): Result = runCancellableCatching {
+// withContext(ioDispatcher) {
+// milkteaAPIService.createInstance(CreateInstanceRequest(host = host)).throwIfHasError()
+// }
+// }
+//
+//}
+//
+//fun InstanceInfoRecord.toModel(): InstanceInfo {
+// return InstanceInfo(
+// id = id,
+// host = host,
+// name = name,
+// description = description,
+// clientMaxBodyByteSize = clientMaxBodyByteSize,
+// iconUrl = iconUrl,
+// themeColor = themeColor
+// )
+//}
+//
+//fun InstanceInfo.toRecord(): InstanceInfoRecord {
+// return InstanceInfoRecord(
+// id = id,
+// host = host,
+// name = name,
+// description = description,
+// clientMaxBodyByteSize = clientMaxBodyByteSize,
+// iconUrl = iconUrl,
+// themeColor = themeColor
+// )
+//}
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.withContext
-import net.pantasystem.milktea.api.milktea.CreateInstanceRequest
-import net.pantasystem.milktea.api.milktea.InstanceInfoResponse
-import net.pantasystem.milktea.api.milktea.MilkteaAPIServiceBuilder
-import net.pantasystem.milktea.common.runCancellableCatching
-import net.pantasystem.milktea.common.throwIfHasError
-import net.pantasystem.milktea.common_android.hilt.IODispatcher
-import net.pantasystem.milktea.data.infrastructure.instance.db.InstanceInfoDao
-import net.pantasystem.milktea.data.infrastructure.instance.db.InstanceInfoRecord
-import net.pantasystem.milktea.model.instance.InstanceInfo
-import net.pantasystem.milktea.model.instance.InstanceInfoRepository
-import javax.inject.Inject
-
-class InstanceInfoRepositoryImpl @Inject constructor(
- private val instanceInfoDao: InstanceInfoDao,
- private val milkteaAPIServiceBuilder: MilkteaAPIServiceBuilder,
- @IODispatcher private val ioDispatcher: CoroutineDispatcher
-): InstanceInfoRepository {
- private val milkteaAPIService by lazy {
- milkteaAPIServiceBuilder.build("https://milktea.pantasystem.net")
- }
- override suspend fun findAll(): Result> = runCancellableCatching {
- withContext(ioDispatcher) {
- instanceInfoDao.findAll().map {
- it.toModel()
- }
- }
- }
-
- override suspend fun sync(): Result = runCancellableCatching {
- withContext(ioDispatcher) {
- val instances = requireNotNull(milkteaAPIService.getInstances().throwIfHasError().body())
- val models = instances.map {
- it.toModel()
- }
- instanceInfoDao.clear()
- instanceInfoDao.insertAll(models.map {
- it.toRecord()
- })
- }
- }
-
- override suspend fun findOne(id: String): Result = runCancellableCatching {
- withContext(ioDispatcher) {
- instanceInfoDao.findById(id)?.toModel()
- ?: throw NoSuchElementException("指定されたId($id)のInstanceInfoは存在しません")
- }
- }
-
- override fun observeAll(): Flow> {
- return instanceInfoDao.observeAll().map { list ->
- list.map {
- it.toModel()
- }
- }.flowOn(ioDispatcher)
- }
-
- override suspend fun findByHost(host: String): Result = runCancellableCatching{
- withContext(ioDispatcher) {
- instanceInfoDao.findByHost(host)?.toModel() ?: throw NoSuchElementException()
- }
- }
- override fun observeByHost(host: String): Flow {
- return instanceInfoDao.observeByHost(host).map {
- it?.toModel()
- }
- }
-
- override suspend fun postInstance(host: String): Result = runCancellableCatching {
- withContext(ioDispatcher) {
- milkteaAPIService.createInstance(CreateInstanceRequest(host = host)).throwIfHasError()
- }
- }
-
-}
-
-fun InstanceInfoRecord.toModel(): InstanceInfo {
- return InstanceInfo(
- id = id,
- host = host,
- name = name,
- description = description,
- clientMaxBodyByteSize = clientMaxBodyByteSize,
- iconUrl = iconUrl,
- themeColor = themeColor
- )
-}
-
-fun InstanceInfo.toRecord(): InstanceInfoRecord {
- return InstanceInfoRecord(
- id = id,
- host = host,
- name = name,
- description = description,
- clientMaxBodyByteSize = clientMaxBodyByteSize,
- iconUrl = iconUrl,
- themeColor = themeColor
- )
-}
-
-fun InstanceInfoResponse.toModel(): InstanceInfo {
- return InstanceInfo(
- id = id,
- host = host,
- name = name,
- description = description,
- clientMaxBodyByteSize = clientMaxBodyByteSize,
- iconUrl = iconUrl,
- themeColor = themeColor
- )
-}
\ No newline at end of file
+//fun InstanceInfoResponse.toModel(): InstanceInfo {
+// return InstanceInfo(
+// id = id,
+// host = host,
+// name = name,
+// description = description,
+// clientMaxBodyByteSize = clientMaxBodyByteSize,
+// iconUrl = iconUrl,
+// themeColor = themeColor
+// )
+//}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MastodonInstanceInfoRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MastodonInstanceInfoRepositoryImpl.kt
index 2179cccf36..7ebf5c927c 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MastodonInstanceInfoRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MastodonInstanceInfoRepositoryImpl.kt
@@ -60,13 +60,8 @@ class MastodonInstanceInfoRepositoryImpl @Inject constructor(
override suspend fun sync(instanceDomain: String): Result = runCancellableCatching {
withContext(ioDispatcher) {
val model = mastodonAPIProvider.get(instanceDomain).getInstance().toModel()
- val exists = mastodonInstanceInfoDAO.findBy(URL(instanceDomain).host)
cache.put(instanceDomain, model)
- if (exists == null) {
- mastodonInstanceInfoDAO.insert(MastodonInstanceInfoRecord.from(model))
- } else {
- mastodonInstanceInfoDAO.update(MastodonInstanceInfoRecord.from(model))
- }
+ upInsert(model)
}
}
@@ -81,9 +76,20 @@ class MastodonInstanceInfoRepositoryImpl @Inject constructor(
}
)
}
+ instanceInfo.pleroma?.let { pleroma ->
+ mastodonInstanceInfoDAO.insertPleromaMetadataFeatures(
+ pleroma.metadata.features.map {
+ PleromaMetadataFeatures(
+ type = it,
+ uri = instanceInfo.uri,
+ )
+ }
+ )
+ }
} else {
mastodonInstanceInfoDAO.update(MastodonInstanceInfoRecord.from(instanceInfo))
mastodonInstanceInfoDAO.clearFedibirdCapabilities(instanceInfo.uri)
+ mastodonInstanceInfoDAO.clearPleromaMetadataFeatures(instanceInfo.uri)
instanceInfo.fedibirdCapabilities?.let { capabilities ->
mastodonInstanceInfoDAO.insertFedibirdCapabilities(
capabilities.map {
@@ -91,6 +97,16 @@ class MastodonInstanceInfoRepositoryImpl @Inject constructor(
}
)
}
+ instanceInfo.pleroma?.let { pleroma ->
+ mastodonInstanceInfoDAO.insertPleromaMetadataFeatures(
+ pleroma.metadata.features.map {
+ PleromaMetadataFeatures(
+ type = it,
+ uri = instanceInfo.uri,
+ )
+ }
+ )
+ }
}
}
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MetaRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MetaRepositoryImpl.kt
index 4c42cfc2a8..36458a07b6 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MetaRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/MetaRepositoryImpl.kt
@@ -88,6 +88,8 @@ class MetaRepositoryImpl @Inject constructor(
}
private suspend fun fetchEmojis(instanceDomain: String): List? {
- return misskeyAPIProvider.get(instanceDomain).getEmojis(EmptyRequest).throwIfHasError().body()?.emojis
+ return misskeyAPIProvider.get(instanceDomain).getEmojis(EmptyRequest).throwIfHasError().body()?.emojis?.map {
+ it.toModel()
+ }
}
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoDAO.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoDAO.kt
index aec1047fff..c4e7a75927 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoDAO.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoDAO.kt
@@ -35,4 +35,12 @@ abstract class MastodonInstanceInfoDAO {
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract fun insertFedibirdCapabilities(list: List): List
+ @Query("""
+ delete from pleroma_metadata_features where uri = :uri
+ """)
+ abstract fun clearPleromaMetadataFeatures(uri: String)
+
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ abstract fun insertPleromaMetadataFeatures(list: List): List
+
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoRecord.kt
index e4dae56ffa..8f98a914ea 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoRecord.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/db/MastodonInstanceInfoRecord.kt
@@ -90,6 +90,28 @@ data class FedibirdCapabilitiesRecord(
val uri: String
)
+@Entity(
+ tableName = "pleroma_metadata_features",
+ foreignKeys = [
+ ForeignKey(
+ parentColumns = ["uri"],
+ childColumns = ["uri"],
+ entity = MastodonInstanceInfoRecord::class,
+ onDelete = ForeignKey.CASCADE,
+ onUpdate = ForeignKey.CASCADE,
+ )
+ ],
+ indices = [Index("uri")],
+ primaryKeys = ["uri", "type"]
+)
+data class PleromaMetadataFeatures(
+ @ColumnInfo(name = "type")
+ val type: String,
+
+ @ColumnInfo(name = "uri")
+ val uri: String
+)
+
data class MastodonInstanceInfoRelated(
@Embedded val info: MastodonInstanceInfoRecord,
@Relation(
@@ -97,7 +119,14 @@ data class MastodonInstanceInfoRelated(
entityColumn = "uri",
entity = FedibirdCapabilitiesRecord::class
)
- val fedibirdCapabilities: List?
+ val fedibirdCapabilities: List?,
+
+ @Relation(
+ parentColumn = "uri",
+ entityColumn = "uri",
+ entity = PleromaMetadataFeatures::class
+ )
+ val pleromaMetadataFeatures: List?
)
fun MastodonInstanceInfoRecord.Companion.from(model: MastodonInstanceInfo): MastodonInstanceInfoRecord {
@@ -176,6 +205,15 @@ fun MastodonInstanceInfoRelated.toModel(): MastodonInstanceInfo {
}
)
},
- fedibirdCapabilities = fedibirdCapabilities?.map { it.type }
+ fedibirdCapabilities = fedibirdCapabilities?.map { it.type },
+ pleroma = pleromaMetadataFeatures?.let {
+ MastodonInstanceInfo.Pleroma(
+ metadata = MastodonInstanceInfo.Pleroma.Metadata(
+ features = it.map { feature ->
+ feature.type
+ }
+ )
+ )
+ }
)
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/online/user/count/OnlineUserCountRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/online/user/count/OnlineUserCountRepositoryImpl.kt
new file mode 100644
index 0000000000..0b81ad99c9
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/instance/online/user/count/OnlineUserCountRepositoryImpl.kt
@@ -0,0 +1,30 @@
+package net.pantasystem.milktea.data.infrastructure.instance.online.user.count
+
+import net.pantasystem.milktea.api.misskey.EmptyRequest
+import net.pantasystem.milktea.common.runCancellableCatching
+import net.pantasystem.milktea.common.throwIfHasError
+import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
+import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.account.AccountRepository
+import net.pantasystem.milktea.model.instance.online.user.count.OnlineUserCountRepository
+import net.pantasystem.milktea.model.instance.online.user.count.OnlineUserCountResult
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class OnlineUserCountRepositoryImpl @Inject constructor(
+ val accountRepository: AccountRepository,
+ val misskeyAPIProvider: MisskeyAPIProvider,
+): OnlineUserCountRepository {
+ override suspend fun find(accountId: Long): Result = runCancellableCatching {
+ val account = accountRepository.get(accountId).getOrThrow()
+ when(account.instanceType) {
+ Account.InstanceType.MISSKEY -> {
+ val res = misskeyAPIProvider.get(account).getOnlineUsersCount(EmptyRequest)
+ .throwIfHasError().body()
+ OnlineUserCountResult.Success(requireNotNull(res?.count))
+ }
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> OnlineUserCountResult.Unknown
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/list/UserListRepositoryWebAPIImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/list/UserListRepositoryWebAPIImpl.kt
index 779e8abbdd..66fcde4260 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/list/UserListRepositoryWebAPIImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/list/UserListRepositoryWebAPIImpl.kt
@@ -48,7 +48,7 @@ class UserListRepositoryWebAPIImpl @Inject constructor(
it.toEntity(account)
}
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).getMyLists()
.throwIfHasError()
.body()
@@ -142,7 +142,7 @@ class UserListRepositoryWebAPIImpl @Inject constructor(
.throwIfHasError()
res.body()!!.toEntity(account)
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val res = mastodonAPIProvider.get(account).getList(userListId.userListId)
.throwIfHasError()
requireNotNull(res.body()).toModel(account)
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/markers/MarkerRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/markers/MarkerRepositoryImpl.kt
index 673c1631eb..4d56df089a 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/markers/MarkerRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/markers/MarkerRepositoryImpl.kt
@@ -31,7 +31,7 @@ class MarkerRepositoryImpl @Inject constructor(
val account = accountRepository.get(accountId).getOrThrow()
when(account.instanceType) {
Account.InstanceType.MISSKEY -> throw IllegalArgumentException("Not support markers feature when use misskey.")
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).getMarkers(types.map {
it.name.lowercase()
}).throwIfHasError().body()
@@ -51,7 +51,7 @@ class MarkerRepositoryImpl @Inject constructor(
val account = accountRepository.get(accountId).getOrThrow()
when(account.instanceType) {
Account.InstanceType.MISSKEY -> throw IllegalArgumentException("Not support markers feature when use misskey.")
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).saveMarkers(
markers = SaveMarkersRequest(
home = params.home?.let {
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/FavoriteNoteTimelinePagingStoreImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/FavoriteNoteTimelinePagingStoreImpl.kt
index ad71e286e2..9c4d992707 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/FavoriteNoteTimelinePagingStoreImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/FavoriteNoteTimelinePagingStoreImpl.kt
@@ -94,7 +94,7 @@ internal class FavoriteNoteTimelinePagingStoreImpl(
FavoriteType.Misskey(it)
}
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
// NOTE: ページが末端であるかをチェックしている
if (getSinceId() == null && !isEmpty()) {
return@runCancellableCatching emptyList()
@@ -125,7 +125,7 @@ internal class FavoriteNoteTimelinePagingStoreImpl(
FavoriteType.Misskey(it)
}
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
// NOTE: ページが末端であるかをチェックしている
if (getUntilId() == null && !isEmpty()) {
return@runCancellableCatching emptyList()
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/MastodonTimelineStorePagingStoreImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/MastodonTimelineStorePagingStoreImpl.kt
index 9647239d0b..7e00396954 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/MastodonTimelineStorePagingStoreImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/MastodonTimelineStorePagingStoreImpl.kt
@@ -53,26 +53,26 @@ internal class MastodonTimelineStorePagingStoreImpl(
is Pageable.Mastodon.HashTagTimeline -> api.getHashtagTimeline(
pageableTimeline.hashtag,
minId = getSinceId(),
- )
+ ).getBodyOrFail()
Pageable.Mastodon.HomeTimeline -> api.getHomeTimeline(
minId = getSinceId(),
visibilities = getVisibilitiesParameter(getAccount()),
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.ListTimeline -> api.getListTimeline(
minId = getSinceId(),
listId = pageableTimeline.listId,
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.LocalTimeline -> api.getPublicTimeline(
local = true,
minId = getSinceId(),
visibilities = getVisibilitiesParameter(getAccount()),
onlyMedia = pageableTimeline.getOnlyMedia()
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.PublicTimeline -> api.getPublicTimeline(
minId = getSinceId(),
visibilities = getVisibilitiesParameter(getAccount()),
onlyMedia = pageableTimeline.getOnlyMedia()
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.UserTimeline -> {
api.getAccountTimeline(
accountId = pageableTimeline.userId,
@@ -82,16 +82,23 @@ internal class MastodonTimelineStorePagingStoreImpl(
minId = getSinceId()
).throwIfHasError().also {
updateMinIdFrom(it)
- }
+ }.getBodyOrFail()
}
Pageable.Mastodon.BookmarkTimeline -> {
api.getBookmarks(
minId = minId
).throwIfHasError().also {
updateMinIdFrom(it)
- }
+ }.getBodyOrFail()
}
- }.throwIfHasError().body()!!.let { list ->
+ is Pageable.Mastodon.SearchTimeline -> {
+ return@runCancellableCatching emptyList()
+ }
+ is Pageable.Mastodon.TrendTimeline -> {
+ return@runCancellableCatching emptyList()
+ }
+
+ }.let { list ->
if (isShouldUseLinkHeader()) {
filterNotExistsStatuses(list)
} else {
@@ -146,26 +153,26 @@ internal class MastodonTimelineStorePagingStoreImpl(
pageableTimeline.hashtag,
maxId = maxId,
onlyMedia = pageableTimeline.getOnlyMedia()
- )
+ ).getBodyOrFail()
Pageable.Mastodon.HomeTimeline -> api.getHomeTimeline(
maxId = maxId,
visibilities = getVisibilitiesParameter(getAccount())
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.ListTimeline -> api.getListTimeline(
maxId = maxId,
listId = pageableTimeline.listId,
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.LocalTimeline -> api.getPublicTimeline(
local = true,
maxId = maxId,
visibilities = getVisibilitiesParameter(getAccount()),
onlyMedia = pageableTimeline.getOnlyMedia()
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.PublicTimeline -> api.getPublicTimeline(
maxId = maxId,
visibilities = getVisibilitiesParameter(getAccount()),
onlyMedia = pageableTimeline.getOnlyMedia()
- )
+ ).getBodyOrFail()
is Pageable.Mastodon.UserTimeline -> {
api.getAccountTimeline(
accountId = pageableTimeline.userId,
@@ -175,16 +182,32 @@ internal class MastodonTimelineStorePagingStoreImpl(
maxId = maxId,
).throwIfHasError().also {
updateMaxIdFrom(it)
- }
+ }.body()
}
Pageable.Mastodon.BookmarkTimeline -> {
api.getBookmarks(
maxId = maxId,
).throwIfHasError().also {
updateMaxIdFrom(it)
- }
+ }.body()
+ }
+ is Pageable.Mastodon.SearchTimeline -> {
+ api.search(
+ q = pageableTimeline.query,
+ type = "statuses",
+ maxId = maxId,
+ offset = (getState().content as? StateContent.Exist)?.rawContent?.size ?: 0,
+ accountId = pageableTimeline.userId
+ ).throwIfHasError().also {
+ updateMaxIdFrom(it)
+ }.body()?.statuses
}
- }.throwIfHasError().body()!!.let { list ->
+ is Pageable.Mastodon.TrendTimeline -> {
+ api.getTrendStatuses(
+ offset = (getState().content as? StateContent.Exist)?.rawContent?.size ?: 0
+ ).getBodyOrFail()
+ }
+ }!!.let { list ->
if (isShouldUseLinkHeader()) {
filterNotExistsStatuses(list)
} else {
@@ -234,7 +257,7 @@ internal class MastodonTimelineStorePagingStoreImpl(
* responseのmaxIdがnullの場合は更新がキャンセルされる
* minIdがnullの場合はresponseのminIdが指定される
*/
- private fun updateMaxIdFrom(response: Response>) {
+ private fun updateMaxIdFrom(response: Response<*>) {
val decoder = MastodonLinkHeaderDecoder(response.headers()["link"])
// NOTE: 次のページネーションのIdが取得できない場合は次のIdが取得できるまで同じIdを使い回し続ける
@@ -254,7 +277,7 @@ internal class MastodonTimelineStorePagingStoreImpl(
* responseのminIdがnullの場合は更新がキャンセルされる
* maxIdがnullの場合はresponseのmaxIdが指定される
*/
- private fun updateMinIdFrom(response: Response>) {
+ private fun updateMinIdFrom(response: Response<*>) {
val decoder = MastodonLinkHeaderDecoder(response.headers()["link"])
// NOTE: 次のページネーションのIdが取得できない場合は次のIdが取得できるまで同じIdを使い回し続ける
@@ -268,4 +291,8 @@ internal class MastodonTimelineStorePagingStoreImpl(
maxId = decoder.getMaxId()
}
}
+
+ private fun Response>.getBodyOrFail(): List {
+ return requireNotNull(throwIfHasError().body())
+ }
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteCaptureAPIAdapterImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteCaptureAPIAdapterImpl.kt
index 7e46c7c2f1..40cdf76cf2 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteCaptureAPIAdapterImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteCaptureAPIAdapterImpl.kt
@@ -11,6 +11,8 @@ import net.pantasystem.milktea.common.mapCancellableCatching
import net.pantasystem.milktea.data.streaming.StreamingAPIProvider
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.account.AccountRepository
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatioDataSource
+import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.notes.Note
import net.pantasystem.milktea.model.notes.NoteCaptureAPIAdapter
import net.pantasystem.milktea.model.notes.NoteDataSource
@@ -26,6 +28,8 @@ class NoteCaptureAPIAdapterImpl(
private val noteCaptureAPIWithAccountProvider: NoteCaptureAPIWithAccountProvider,
private val streamingAPIProvider: StreamingAPIProvider,
private val noteDataSourceAdder: NoteDataSourceAdder,
+ private val customEmojiAspectRatioDataSource: CustomEmojiAspectRatioDataSource,
+ private val imageCacheRepository: ImageCacheRepository,
loggerFactory: Logger.Factory,
cs: CoroutineScope,
dispatcher: CoroutineDispatcher = Dispatchers.IO,
@@ -48,13 +52,19 @@ class NoteCaptureAPIAdapterImpl(
/**
* mastodonのStreaming APIから流れてきたEventがここに入る
*/
- private val streamingEventDispatcher = MutableSharedFlow>(extraBufferCapacity = 1000, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val streamingEventDispatcher = MutableSharedFlow>(
+ extraBufferCapacity = 1000,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
/**
* Noteのキャプチャーによって発生したイベントのQueue。
* ここから順番にイベントを取り出し、キャッシュに反映させるなどをしている。
*/
- private val noteUpdatedDispatcher = MutableSharedFlow>(extraBufferCapacity = 1000, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ private val noteUpdatedDispatcher = MutableSharedFlow>(
+ extraBufferCapacity = 1000,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
// /**
// * 使用されなくなったNoteのリソースが順番に入れられるQueue。
@@ -128,12 +138,13 @@ class NoteCaptureAPIAdapterImpl(
}.launchIn(coroutineScope)
noteIdWithJob[id] = job
}
- Account.InstanceType.MASTODON -> {
- val job = requireNotNull(streamingAPIProvider.get(account)).connectUser().catch { e ->
- logger.error("ノート更新イベント受信中にエラー発生", e = e)
- }.onEach {
- streamingEventDispatcher.tryEmit(account to it)
- }.launchIn(coroutineScope)
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
+ val job = requireNotNull(streamingAPIProvider.get(account)).connectUser()
+ .catch { e ->
+ logger.error("ノート更新イベント受信中にエラー発生", e = e)
+ }.onEach {
+ streamingEventDispatcher.tryEmit(account to it)
+ }.launchIn(coroutineScope)
noteIdWithJob[id] = job
}
}
@@ -170,7 +181,7 @@ class NoteCaptureAPIAdapterImpl(
*/
private fun addRepositoryEventListener(
noteId: Note.Id,
- listener: (NoteDataSource.Event) -> Unit
+ listener: (NoteDataSource.Event) -> Unit,
): Boolean {
synchronized(noteIdWithListeners) {
val listeners = noteIdWithListeners[noteId]
@@ -191,7 +202,7 @@ class NoteCaptureAPIAdapterImpl(
*/
private fun removeRepositoryEventListener(
noteId: Note.Id,
- listener: (NoteDataSource.Event) -> Unit
+ listener: (NoteDataSource.Event) -> Unit,
): Boolean {
synchronized(noteIdWithListeners) {
@@ -226,7 +237,22 @@ class NoteCaptureAPIAdapterImpl(
noteDataSource.delete(noteId)
}
is NoteUpdated.Body.Reacted -> {
- noteDataSource.add(note.onReacted(account, e))
+ noteDataSource.add(
+ note.onReacted(
+ account,
+ e,
+ aspectRatio = (e.body.emoji?.url ?: e.body.emoji?.url)?.let {
+ customEmojiAspectRatioDataSource.findOne(
+ it
+ ).getOrNull()
+ },
+ imageCache = (e.body.emoji?.url ?: e.body.emoji?.url)?.let {
+ imageCacheRepository.findBySourceUrl(
+ it
+ )
+ },
+ )
+ )
}
is NoteUpdated.Body.Unreacted -> {
noteDataSource.add(note.onUnReacted(account, e))
@@ -245,7 +271,7 @@ class NoteCaptureAPIAdapterImpl(
private suspend fun handleMastodonRemoteEvent(account: Account, e: Event) {
try {
- when(e) {
+ when (e) {
is Event.Delete -> {
noteDataSource.remove(Note.Id(account.accountId, e.id))
}
@@ -257,7 +283,14 @@ class NoteCaptureAPIAdapterImpl(
val noteId = Note.Id(account.accountId, e.reaction.statusId)
noteDataSource.get(noteId).mapCancellableCatching { note ->
- noteDataSource.add(note.onEmojiReacted(account, e.reaction))
+ noteDataSource.add(
+ note.onEmojiReacted(
+ account, e.reaction,
+ (e.reaction.url ?: e.reaction.staticUrl)?.let {
+ imageCacheRepository.findBySourceUrl(it)
+ }
+ ),
+ )
}.getOrThrow()
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteDataSourceAdder.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteDataSourceAdder.kt
index 2d62e1ccb0..826e346f2d 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteDataSourceAdder.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteDataSourceAdder.kt
@@ -165,7 +165,7 @@ suspend fun NoteDTO.toEntities(
files,
userDTOEntityConverter,
noteDTOEntityConverter,
- filePropertyDTOEntityConverter
+ filePropertyDTOEntityConverter,
)
return NoteRelationEntities(
note = note,
@@ -183,7 +183,7 @@ private suspend fun NoteDTO.pickEntities(
userDTOEntityConverter: UserDTOEntityConverter,
noteDTOEntityConverter: NoteDTOEntityConverter,
filePropertyDTOEntityConverter: FilePropertyDTOEntityConverter,
-) {
+ ) {
val (note, user) = this.toNoteAndUser(
account,
userDTOEntityConverter,
@@ -204,7 +204,7 @@ private suspend fun NoteDTO.pickEntities(
files,
userDTOEntityConverter,
noteDTOEntityConverter,
- filePropertyDTOEntityConverter
+ filePropertyDTOEntityConverter,
)
}
@@ -216,7 +216,7 @@ private suspend fun NoteDTO.pickEntities(
files,
userDTOEntityConverter,
noteDTOEntityConverter,
- filePropertyDTOEntityConverter
+ filePropertyDTOEntityConverter,
)
}
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteEventReducer.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteEventReducer.kt
index 15794130db..5060b09e10 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteEventReducer.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/NoteEventReducer.kt
@@ -3,6 +3,8 @@ package net.pantasystem.milktea.data.infrastructure.notes
import net.pantasystem.milktea.api_streaming.NoteUpdated
import net.pantasystem.milktea.api_streaming.mastodon.EmojiReaction
import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.emoji.CustomEmojiAspectRatio
+import net.pantasystem.milktea.model.image.ImageCache
import net.pantasystem.milktea.model.notes.Note
import net.pantasystem.milktea.model.notes.reaction.ReactionCount
@@ -27,7 +29,12 @@ fun Note.onUnReacted(account: Account, e: NoteUpdated.Body.Unreacted): Note {
)
}
-fun Note.onReacted(account: Account, e: NoteUpdated.Body.Reacted): Note {
+fun Note.onReacted(
+ account: Account,
+ e: NoteUpdated.Body.Reacted,
+ aspectRatio: CustomEmojiAspectRatio?,
+ imageCache: ImageCache?,
+): Note {
val hasItem = this.reactionCounts.any { count ->
count.reaction == e.body.reaction
}
@@ -43,7 +50,10 @@ fun Note.onReacted(account: Account, e: NoteUpdated.Body.Reacted): Note {
list = list + ReactionCount(reaction = e.body.reaction, count = 1, me = false)
}
- val emojis = when (val emoji = e.body.emoji) {
+ val emojis = when (val emoji = e.body.emoji?.copy(
+ aspectRatio = aspectRatio?.aspectRatio,
+ cachePath = imageCache?.cachePath
+ )) {
null -> this.emojis
else -> (this.emojis ?: emptyList()) + emoji
}
@@ -60,7 +70,7 @@ fun Note.onReacted(account: Account, e: NoteUpdated.Body.Reacted): Note {
)
}
-fun Note.onEmojiReacted(account: Account, e: EmojiReaction): Note {
+fun Note.onEmojiReacted(account: Account, e: EmojiReaction, imageCache: ImageCache?): Note {
val reactionCount = ReactionCount(e.reaction, e.count, me = false)
val hasItem = reactionCounts.any {
it.reaction == e.reaction
@@ -77,7 +87,7 @@ fun Note.onEmojiReacted(account: Account, e: EmojiReaction): Note {
list = list + reactionCount
}
- val emojis = when (val emoji = e.toEmoji()) {
+ val emojis = when (val emoji = e.toEmoji(imageCache?.cachePath)) {
null -> this.emojis
else -> (this.emojis ?: emptyList()) + emoji
}
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/PageParams.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/PageParams.kt
index a48b9aaf23..0511ac21b2 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/PageParams.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/PageParams.kt
@@ -24,5 +24,6 @@ fun PageParams.toNoteRequest(i: String?) : NoteRequest {
offset = offset,
markAsRead = markAsRead,
channelId = channelId,
+ userId = userId
)
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/ReplyStreamingImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/ReplyStreamingImpl.kt
new file mode 100644
index 0000000000..ef4225b4f4
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/ReplyStreamingImpl.kt
@@ -0,0 +1,47 @@
+package net.pantasystem.milktea.data.infrastructure.notes
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.*
+import net.pantasystem.milktea.api_streaming.ChannelBody
+import net.pantasystem.milktea.api_streaming.channel.ChannelAPI
+import net.pantasystem.milktea.api_streaming.mastodon.Event
+import net.pantasystem.milktea.data.streaming.ChannelAPIWithAccountProvider
+import net.pantasystem.milktea.data.streaming.StreamingAPIProvider
+import net.pantasystem.milktea.model.account.Account
+import net.pantasystem.milktea.model.notes.Note
+import net.pantasystem.milktea.model.notes.ReplyStreaming
+import javax.inject.Inject
+
+class ReplyStreamingImpl @Inject constructor(
+ private val channelAPIProvider: ChannelAPIWithAccountProvider,
+ private val noteDataSourceAdder: NoteDataSourceAdder,
+ private val streamingAPIProvider: StreamingAPIProvider,
+) : ReplyStreaming {
+ @OptIn(ExperimentalCoroutinesApi::class)
+ override fun connect(getAccount: suspend () -> Account): Flow {
+ return flow {
+ emit(getAccount())
+ }.flatMapLatest { ac ->
+ when(ac.instanceType) {
+ Account.InstanceType.MISSKEY -> {
+ requireNotNull(channelAPIProvider.get(ac)).connect(ChannelAPI.Type.Main).map {
+ it as ChannelBody.Main.Reply
+ }.map {
+ it.body
+ }.map {
+ noteDataSourceAdder.addNoteDtoToDataSource(ac, it)
+ }
+ }
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
+ requireNotNull(streamingAPIProvider.get(ac)).connectUser().mapNotNull {
+ (it as? Event.Update)?.status
+ }.filter {
+ it.inReplyToId != null
+ }.map {
+ noteDataSourceAdder.addTootStatusDtoIntoDataSource(ac, it)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelinePagingStoreImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelinePagingStoreImpl.kt
index f476bc22cb..b22184537e 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelinePagingStoreImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelinePagingStoreImpl.kt
@@ -21,6 +21,7 @@ import net.pantasystem.milktea.model.account.page.Pageable
import net.pantasystem.milktea.model.account.page.SincePaginate
import net.pantasystem.milktea.model.account.page.UntilPaginate
import net.pantasystem.milktea.model.instance.MetaRepository
+import net.pantasystem.milktea.model.instance.Version
import net.pantasystem.milktea.model.notes.Note
import retrofit2.Response
@@ -84,6 +85,17 @@ internal class TimelinePagingStoreImpl(
return@runCancellableCatching emptyList()
}
+ // NOTE: sinceIdが13.11.0で削除される破壊的変更が行われてしまったのでその判定を行なっている
+ // https://github.com/misskey-dev/misskey/commit/b53d6c7f8ca1a712eab44967e8d05a0cc7bcc034#diff-883a3f5d77794cf2344c96727836aabc74c19f57db5e2e0cd485fdb6d3af7efeL77
+ // sinceId削除の件は不具合で13.11.3で修正された
+ if (pageableTimeline is Pageable.Antenna) {
+ val account = getAccount()
+ val meta = metaRepository.find(account.normalizedInstanceUri).getOrThrow()
+ if (meta.getVersion() >= Version("13.11.0") && meta.getVersion() < Version("13.11.3")) {
+ return@runCancellableCatching emptyList()
+ }
+ }
+
val builder = NoteRequest.Builder(
i = getAccount.invoke().token,
pageable = pageableTimeline,
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelineScrollPositionRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelineScrollPositionRepositoryImpl.kt
new file mode 100644
index 0000000000..3a84df38b8
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/TimelineScrollPositionRepositoryImpl.kt
@@ -0,0 +1,35 @@
+package net.pantasystem.milktea.data.infrastructure.notes
+
+import android.content.SharedPreferences
+import net.pantasystem.milktea.model.notes.Note
+import net.pantasystem.milktea.model.notes.TimelineScrollPositionRepository
+
+class TimelineScrollPositionRepositoryImpl(
+ private val sharedPreferences: SharedPreferences
+) : TimelineScrollPositionRepository {
+ override suspend fun save(pageId: Long, noteId: Note.Id) {
+ sharedPreferences.edit()
+ .putString("timeline_scroll_position_note_id_$pageId", noteId.noteId)
+ .putLong("timeline_scroll_position_account_id_$pageId", noteId.accountId)
+ .apply()
+ }
+
+ override suspend fun get(pageId: Long): Note.Id? {
+ val noteId = sharedPreferences.getString("timeline_scroll_position_note_id_$pageId", null)
+ val accountId = sharedPreferences.getLong("timeline_scroll_position_account_id_$pageId", 0L).takeIf {
+ it > 0L
+ }
+ return if (noteId == null || accountId == null) {
+ null
+ } else {
+ Note.Id(accountId, noteId)
+ }
+ }
+
+ override suspend fun remove(pageId: Long) {
+ sharedPreferences.edit()
+ .remove("timeline_scroll_position_note_id_$pageId")
+ .remove("timeline_scroll_position_account_id_$pageId")
+ .apply()
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/bookmark/BookmarkRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/bookmark/BookmarkRepositoryImpl.kt
index 15dba76209..5b0adf3681 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/bookmark/BookmarkRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/bookmark/BookmarkRepositoryImpl.kt
@@ -29,7 +29,7 @@ class BookmarkRepositoryImpl @Inject constructor(
val account = accountRepository.get(noteId.accountId).getOrThrow()
when(account.instanceType) {
Account.InstanceType.MISSKEY -> favoriteRepository.create(noteId).getOrThrow()
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).bookmarkStatus(noteId.noteId)
.throwIfHasError()
.body()
@@ -44,7 +44,7 @@ class BookmarkRepositoryImpl @Inject constructor(
val account = accountRepository.get(noteId.accountId).getOrThrow()
when(account.instanceType) {
Account.InstanceType.MISSKEY -> favoriteRepository.delete(noteId).getOrThrow()
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).unbookmarkStatus(noteId.noteId)
.throwIfHasError()
.body()
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/favorite/FavoriteAPIAdapter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/favorite/FavoriteAPIAdapter.kt
index 18e149915b..bc2bd14f81 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/favorite/FavoriteAPIAdapter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/favorite/FavoriteAPIAdapter.kt
@@ -27,7 +27,7 @@ class FavoriteAPIAdapter @Inject constructor(
.throwIfHasError()
SuccessfulResponseData.Misskey
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val status = mastodonAPIProvider.get(account).favouriteStatus(noteId.noteId)
.throwIfHasError()
.body()
@@ -44,7 +44,7 @@ class FavoriteAPIAdapter @Inject constructor(
.throwIfHasError()
SuccessfulResponseData.Misskey
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val status = mastodonAPIProvider.get(account).unfavouriteStatus(noteId.noteId)
.throwIfHasError()
.body()
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/InMemoryNoteDataSource.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/InMemoryNoteDataSource.kt
index e0ee2f4724..3c7b82c773 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/InMemoryNoteDataSource.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/InMemoryNoteDataSource.kt
@@ -1,13 +1,24 @@
package net.pantasystem.milktea.data.infrastructure.notes.impl
-import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.data.infrastructure.MemoryCacheCleaner
import net.pantasystem.milktea.model.AddResult
-import net.pantasystem.milktea.model.notes.*
+import net.pantasystem.milktea.model.notes.Note
+import net.pantasystem.milktea.model.notes.NoteDataSource
+import net.pantasystem.milktea.model.notes.NoteDataSourceState
+import net.pantasystem.milktea.model.notes.NoteDeletedException
+import net.pantasystem.milktea.model.notes.NoteNotFoundException
+import net.pantasystem.milktea.model.notes.NoteRemovedException
+import net.pantasystem.milktea.model.notes.NoteThreadContext
import net.pantasystem.milktea.model.user.User
import javax.inject.Inject
@@ -142,11 +153,6 @@ class InMemoryNoteDataSource @Inject constructor(
}.distinctUntilChanged()
}
- override fun observeRecursiveReplies(noteId: Note.Id): Flow> {
- return _state.map {
- it.map.values.toList()
- }
- }
override suspend fun findByReplyId(id: Note.Id): Result> {
return Result.success(
@@ -188,6 +194,21 @@ class InMemoryNoteDataSource @Inject constructor(
}
}
+ override suspend fun addNoteThreadContext(
+ noteId: Note.Id,
+ context: NoteThreadContext
+ ): Result = Result.success(Unit)
+
+ override fun observeNoteThreadContext(noteId: Note.Id): Flow {
+ return emptyFlow()
+ }
+
+ override suspend fun findNoteThreadContext(noteId: Note.Id): Result = Result.success(
+ NoteThreadContext(emptyList(), emptyList())
+ )
+
+ override suspend fun clearNoteThreadContext(noteId: Note.Id): Result = Result.success(Unit)
+
private fun publish(ev: NoteDataSource.Event) = runBlocking {
listenersLock.withLock {
listeners.forEach {
@@ -196,4 +217,8 @@ class InMemoryNoteDataSource @Inject constructor(
}
}
+ override suspend fun findLocalCount(): Result {
+ return Result.success(notes.size.toLong())
+ }
+
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteApiAdapter.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteApiAdapter.kt
index 31a941fa0f..9140671491 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteApiAdapter.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteApiAdapter.kt
@@ -61,7 +61,7 @@ class NoteApiAdapter @Inject constructor(
val noteDTO = result.getOrThrow()
NoteResultType.Misskey(requireNotNull(noteDTO))
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val fileIds = coroutineScope {
createNote.files?.map { appFile ->
async {
@@ -94,6 +94,7 @@ class NoteApiAdapter @Inject constructor(
}?.toInt() ?: (5 * 60),
)
},
+ quoteId = createNote.renoteId?.noteId,
)
).throwIfHasError().body()
NoteResultType.Mastodon(requireNotNull(body))
@@ -113,7 +114,7 @@ class NoteApiAdapter @Inject constructor(
).throwIfHasError().body()
NoteResultType.Misskey(requireNotNull(body))
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account)
.getStatus(noteId.noteId)
.throwIfHasError().body()
@@ -134,7 +135,7 @@ class NoteApiAdapter @Inject constructor(
).throwIfHasError()
DeleteNoteResultType.Misskey
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).deleteStatus(noteId.noteId)
.throwIfHasError()
.body()
@@ -155,7 +156,7 @@ class NoteApiAdapter @Inject constructor(
).throwIfHasError()
ToggleThreadMuteResultType.Misskey
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account)
.muteConversation(noteId.noteId)
.throwIfHasError()
@@ -177,7 +178,7 @@ class NoteApiAdapter @Inject constructor(
).throwIfHasError()
ToggleThreadMuteResultType.Misskey
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val body = mastodonAPIProvider.get(account).unmuteConversation(noteId.noteId)
.throwIfHasError()
.body()
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteRepositoryImpl.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteRepositoryImpl.kt
index f0ccb53e42..25ef2a5a45 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteRepositoryImpl.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/NoteRepositoryImpl.kt
@@ -2,6 +2,9 @@ package net.pantasystem.milktea.data.infrastructure.notes.impl
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filterNotNull
+import net.pantasystem.milktea.api.misskey.notes.GetNoteChildrenRequest
+import net.pantasystem.milktea.api.misskey.notes.NoteDTO
import net.pantasystem.milktea.api.misskey.notes.NoteRequest
import net.pantasystem.milktea.common.*
import net.pantasystem.milktea.common_android.hilt.IODispatcher
@@ -28,7 +31,7 @@ class NoteRepositoryImpl @Inject constructor(
val noteDataSourceAdder: NoteDataSourceAdder,
val getAccount: GetAccount,
private val noteApiAdapter: NoteApiAdapter,
- @IODispatcher private val ioDispatcher: CoroutineDispatcher
+ @IODispatcher private val ioDispatcher: CoroutineDispatcher,
) : NoteRepository {
private val logger = loggerFactory.create("NoteRepositoryImpl")
@@ -40,23 +43,28 @@ class NoteRepositoryImpl @Inject constructor(
}
}
- override suspend fun renote(noteId: Note.Id): Result = runCancellableCatching{
+ override suspend fun renote(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
- when(account.instanceType) {
+ when (account.instanceType) {
Account.InstanceType.MISSKEY -> {
val n = find(noteId).getOrThrow()
- create(CreateNote(
- author = account, renoteId = noteId,
- text = null,
- visibility = n.visibility
- )).getOrThrow()
+ create(
+ CreateNote(
+ author = account, renoteId = noteId,
+ text = null,
+ visibility = n.visibility
+ )
+ ).getOrThrow()
}
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val toot = mastodonAPIProvider.get(account).reblog(noteId.noteId)
.throwIfHasError()
.body()
- noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, requireNotNull(toot))
+ noteDataSourceAdder.addTootStatusDtoIntoDataSource(
+ account,
+ requireNotNull(toot)
+ )
}
}
}
@@ -65,9 +73,9 @@ class NoteRepositoryImpl @Inject constructor(
override suspend fun unrenote(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
- when(account.instanceType) {
+ when (account.instanceType) {
Account.InstanceType.MISSKEY -> delete(noteId).getOrThrow()
- Account.InstanceType.MASTODON -> {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val res = mastodonAPIProvider.get(account).unreblog(noteId.noteId)
.throwIfHasError()
.body()
@@ -78,12 +86,15 @@ class NoteRepositoryImpl @Inject constructor(
}
}
- override suspend fun delete(noteId: Note.Id): Result = runCancellableCatching{
+ override suspend fun delete(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
val note = find(noteId).getOrThrow()
- when(val result = noteApiAdapter.delete(noteId)) {
- is DeleteNoteResultType.Mastodon -> noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, result.status)
+ when (val result = noteApiAdapter.delete(noteId)) {
+ is DeleteNoteResultType.Mastodon -> noteDataSourceAdder.addTootStatusDtoIntoDataSource(
+ account,
+ result.status
+ )
DeleteNoteResultType.Misskey -> note
}
}
@@ -144,32 +155,31 @@ class NoteRepositoryImpl @Inject constructor(
}
- override suspend fun vote(noteId: Note.Id, choice: Poll.Choice): Result = runCancellableCatching {
- withContext(ioDispatcher) {
- val account = getAccount.get(noteId.accountId)
- val note = find(noteId).getOrThrow()
- when(val type = note.type) {
- is Note.Type.Mastodon -> {
- mastodonAPIProvider.get(account).voteOnPoll(
- requireNotNull(type.pollId),
- choices = listOf(choice.index)
- )
- }
- is Note.Type.Misskey -> {
- misskeyAPIProvider.get(account).vote(
- Vote(
- i = getAccount.get(noteId.accountId).token,
- choice = choice.index,
- noteId = noteId.noteId
+ override suspend fun vote(noteId: Note.Id, choice: Poll.Choice): Result =
+ runCancellableCatching {
+ withContext(ioDispatcher) {
+ val account = getAccount.get(noteId.accountId)
+ val note = find(noteId).getOrThrow()
+ when (val type = note.type) {
+ is Note.Type.Mastodon -> {
+ mastodonAPIProvider.get(account).voteOnPoll(
+ requireNotNull(type.pollId),
+ choices = listOf(choice.index)
)
- ).throwIfHasError()
+ }
+ is Note.Type.Misskey -> {
+ misskeyAPIProvider.get(account).vote(
+ Vote(
+ i = getAccount.get(noteId.accountId).token,
+ choice = choice.index,
+ noteId = noteId.noteId
+ )
+ ).throwIfHasError()
+ }
}
- }
+ }
}
- }
-
-
private suspend fun fetchIn(noteIds: List) {
@@ -200,68 +210,55 @@ class NoteRepositoryImpl @Inject constructor(
}
}
- override suspend fun syncChildren(noteId: Note.Id): Result = runCancellableCatching {
+ override suspend fun syncThreadContext(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
- when(account.instanceType) {
+ when (account.instanceType) {
Account.InstanceType.MISSKEY -> {
- val dtoList = misskeyAPIProvider.get(account).children(
- NoteRequest(
- i = account.token,
- noteId = noteId.noteId,
- limit = 100,
- )
- ).throwIfHasError().body()!!
- dtoList.map {
+ val ancestors = requireNotNull(
+ misskeyAPIProvider.get(account).conversation(
+ NoteRequest(
+ i = account.token,
+ noteId = noteId.noteId,
+ )
+ ).throwIfHasError().body()
+ ).map {
noteDataSourceAdder.addNoteDtoToDataSource(account, it)
}
+ noteDataSource.clearNoteThreadContext(noteId)
+ noteDataSource.addNoteThreadContext(noteId, NoteThreadContext(
+ ancestors = ancestors,
+ descendants = emptyList()
+ ))
+ syncRecursiveThreadContext4Misskey(noteId, noteId)
}
- Account.InstanceType.MASTODON -> {
- val body = mastodonAPIProvider.get(account).getStatusesContext(noteId.noteId)
- .throwIfHasError()
- .body()
- requireNotNull(body).let {
- it.ancestors + it.descendants
- }.map {
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
+ val body = requireNotNull(
+ mastodonAPIProvider.get(account).getStatusesContext(noteId.noteId)
+ .throwIfHasError()
+ .body()
+ )
+ val ancestors = body.ancestors.map {
noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, it)
}
- }
- }
-
- }
- }
-
- override suspend fun syncConversation(noteId: Note.Id): Result = runCancellableCatching {
- withContext(ioDispatcher) {
- val account = getAccount.get(noteId.accountId)
- when(account.instanceType) {
- Account.InstanceType.MISSKEY -> {
- val dtoList = misskeyAPIProvider.get(account).conversation(
- NoteRequest(
- i = account.token,
- noteId = noteId.noteId,
- )
- ).throwIfHasError().body()!!
- dtoList.map {
- noteDataSourceAdder.addNoteDtoToDataSource(account, it)
- }
- }
- Account.InstanceType.MASTODON -> {
- val body = mastodonAPIProvider.get(account).getStatusesContext(noteId.noteId)
- .throwIfHasError()
- .body()
- requireNotNull(body).let {
- it.ancestors + it.descendants
- }.map {
+ val descendants = body.descendants.map {
noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, it)
}
+ noteDataSource.clearNoteThreadContext(noteId)
+ noteDataSource.addNoteThreadContext(noteId, NoteThreadContext(
+ ancestors = ancestors,
+ descendants = descendants
+ ))
}
}
-
}
}
+ override fun observeThreadContext(noteId: Note.Id): Flow {
+ return noteDataSource.observeNoteThreadContext(noteId).filterNotNull()
+ }
+
override suspend fun sync(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
@@ -272,7 +269,7 @@ class NoteRepositoryImpl @Inject constructor(
override suspend fun createThreadMute(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
- when(val result = noteApiAdapter.createThreadMute(noteId)) {
+ when (val result = noteApiAdapter.createThreadMute(noteId)) {
is ToggleThreadMuteResultType.Mastodon -> {
noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, result.status)
}
@@ -284,7 +281,7 @@ class NoteRepositoryImpl @Inject constructor(
override suspend fun deleteThreadMute(noteId: Note.Id): Result = runCancellableCatching {
withContext(ioDispatcher) {
val account = getAccount.get(noteId.accountId)
- when(val result = noteApiAdapter.deleteThreadMute(noteId)) {
+ when (val result = noteApiAdapter.deleteThreadMute(noteId)) {
is ToggleThreadMuteResultType.Mastodon -> {
noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, result.status)
}
@@ -293,40 +290,41 @@ class NoteRepositoryImpl @Inject constructor(
}
}
- override suspend fun findNoteState(noteId: Note.Id): Result = runCancellableCatching {
- withContext(ioDispatcher) {
- val account = getAccount.get(noteId.accountId)
- when(account.instanceType) {
- Account.InstanceType.MISSKEY -> {
- misskeyAPIProvider.get(account.normalizedInstanceUri).noteState(
- NoteRequest(
- i = account.token,
- noteId = noteId.noteId
- )
- ).throwIfHasError().body()!!.let {
- NoteState(
- isFavorited = it.isFavorited,
- isMutedThread = it.isMutedThread,
- isWatching = when(val watching = it.isWatching) {
- null -> NoteState.Watching.None
- else -> NoteState.Watching.Some(watching)
- }
- )
+ override suspend fun findNoteState(noteId: Note.Id): Result =
+ runCancellableCatching {
+ withContext(ioDispatcher) {
+ val account = getAccount.get(noteId.accountId)
+ when (account.instanceType) {
+ Account.InstanceType.MISSKEY -> {
+ misskeyAPIProvider.get(account.normalizedInstanceUri).noteState(
+ NoteRequest(
+ i = account.token,
+ noteId = noteId.noteId
+ )
+ ).throwIfHasError().body()!!.let {
+ NoteState(
+ isFavorited = it.isFavorited,
+ isMutedThread = it.isMutedThread,
+ isWatching = when (val watching = it.isWatching) {
+ null -> NoteState.Watching.None
+ else -> NoteState.Watching.Some(watching)
+ }
+ )
+ }
+ }
+ Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
+ find(noteId).mapCancellableCatching {
+ NoteState(
+ isFavorited = (it.type as Note.Type.Mastodon).favorited ?: false,
+ isMutedThread = (it.type as Note.Type.Mastodon).muted ?: false,
+ isWatching = NoteState.Watching.None,
+ )
+ }.getOrThrow()
}
}
- Account.InstanceType.MASTODON -> {
- find(noteId).mapCancellableCatching {
- NoteState(
- isFavorited = (it.type as Note.Type.Mastodon).favorited ?: false,
- isMutedThread = (it.type as Note.Type.Mastodon).muted ?: false,
- isWatching = NoteState.Watching.None,
- )
- }.getOrThrow()
- }
- }
+ }
}
- }
override fun observeIn(noteIds: List): Flow> {
return noteDataSource.observeIn(noteIds)
@@ -337,9 +335,53 @@ class NoteRepositoryImpl @Inject constructor(
}
private suspend fun convertAndAdd(account: Account, type: NoteResultType): Note {
- return when(type) {
- is NoteResultType.Mastodon -> noteDataSourceAdder.addTootStatusDtoIntoDataSource(account, type.status)
- is NoteResultType.Misskey -> noteDataSourceAdder.addNoteDtoToDataSource(account, type.note)
+ return when (type) {
+ is NoteResultType.Mastodon -> noteDataSourceAdder.addTootStatusDtoIntoDataSource(
+ account,
+ type.status
+ )
+ is NoteResultType.Misskey -> noteDataSourceAdder.addNoteDtoToDataSource(
+ account,
+ type.note
+ )
+ }
+ }
+
+ private suspend fun getMisskeyDescendants(targetNoteId: Note.Id): List {
+ val account = getAccount.get(targetNoteId.accountId)
+ return requireNotNull(
+ misskeyAPIProvider.get(account).children(
+ GetNoteChildrenRequest(
+ i = account.token,
+ noteId = targetNoteId.noteId,
+ limit = 30,
+ depth = 2,
+ )
+ ).throwIfHasError().body()
+ )
+ }
+
+ private suspend fun syncRecursiveThreadContext4Misskey(
+ targetNoteId: Note.Id,
+ appendTo: Note.Id,
+ ) {
+ val account = getAccount.get(appendTo.accountId)
+ val descendants = getMisskeyDescendants(targetNoteId).map {
+ noteDataSourceAdder.addNoteDtoToDataSource(account, it)
+ }
+ val tc = noteDataSource.findNoteThreadContext(targetNoteId).getOrThrow()
+ noteDataSource.addNoteThreadContext(
+ targetNoteId,
+ tc.copy(
+ descendants = tc.descendants + descendants
+ )
+ )
+ coroutineScope {
+ descendants.map { note ->
+ async {
+ syncRecursiveThreadContext4Misskey(note.id, appendTo)
+ }
+ }.awaitAll()
}
}
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/ObjectBoxNoteDataSource.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/ObjectBoxNoteDataSource.kt
index 7d23bc7525..a8f6053e58 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/ObjectBoxNoteDataSource.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/ObjectBoxNoteDataSource.kt
@@ -7,18 +7,16 @@ import io.objectbox.kotlin.boxFor
import io.objectbox.kotlin.inValues
import io.objectbox.kotlin.toFlow
import io.objectbox.query.QueryBuilder
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
-import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
-import kotlinx.coroutines.withContext
import net.pantasystem.milktea.common.Logger
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common_android.hilt.IODispatcher
import net.pantasystem.milktea.data.infrastructure.notes.impl.db.NoteRecord
import net.pantasystem.milktea.data.infrastructure.notes.impl.db.NoteRecord_
+import net.pantasystem.milktea.data.infrastructure.notes.impl.db.NoteThreadRecordDAO
import net.pantasystem.milktea.model.AddResult
import net.pantasystem.milktea.model.notes.*
import net.pantasystem.milktea.model.user.User
@@ -27,6 +25,7 @@ import javax.inject.Inject
class ObjectBoxNoteDataSource @Inject constructor(
private val boxStore: BoxStore,
+ private val noteThreadRecordDAO: NoteThreadRecordDAO,
@IODispatcher val coroutineDispatcher: CoroutineDispatcher,
loggerFactory: Logger.Factory
) : NoteDataSource {
@@ -106,12 +105,6 @@ class ObjectBoxNoteDataSource @Inject constructor(
}
}
- override fun observeRecursiveReplies(noteId: Note.Id): Flow> {
- return changedIdFlow.map {
- recursiveFindReplies(noteId).getOrThrow()
- }
- }
-
override suspend fun exists(noteId: Note.Id): Boolean {
return noteBox.query().equal(
NoteRecord_.accountIdAndNoteId,
@@ -214,7 +207,7 @@ class ObjectBoxNoteDataSource @Inject constructor(
override suspend fun clear(): Result = runCancellableCatching {
withContext(coroutineDispatcher) {
- boxStore.removeAllObjects()
+ noteBox.removeAll()
}
}
@@ -250,6 +243,65 @@ class ObjectBoxNoteDataSource @Inject constructor(
}
}
+ @OptIn(FlowPreview::class)
+ override fun observeNoteThreadContext(noteId: Note.Id): Flow {
+ return suspend {
+ noteThreadRecordDAO.appendBlank(noteId)
+ }.asFlow().map { record ->
+ NoteThreadContext(
+ descendants = record.descendants.map {
+ it.toModel()
+ },
+ ancestors = record.ancestors.map {
+ it.toModel()
+ }
+ )
+ }
+ }
+
+ override suspend fun addNoteThreadContext(
+ noteId: Note.Id,
+ context: NoteThreadContext
+ ): Result = runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ noteThreadRecordDAO.clearRelation(noteId)
+ val record = noteThreadRecordDAO.appendBlank(noteId)
+
+ record.ancestors.clear()
+ record.ancestors.addAll(findByNotes(context.ancestors.map { it.id }))
+ record.descendants.clear()
+ record.descendants.addAll(findByNotes(context.descendants.map { it.id }))
+ noteThreadRecordDAO.update(record)
+ }
+ }
+
+ override suspend fun clearNoteThreadContext(noteId: Note.Id): Result = runCancellableCatching{
+ withContext(coroutineDispatcher) {
+ noteThreadRecordDAO.clearRelation(noteId)
+ }
+ }
+
+ override suspend fun findNoteThreadContext(noteId: Note.Id): Result = runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ noteThreadRecordDAO.findBy(noteId)?.let { record ->
+ NoteThreadContext(
+ ancestors = record.ancestors.mapNotNull {
+ it?.toModel()
+ },
+ descendants = record.descendants.mapNotNull {
+ it?.toModel()
+ }
+ )
+ } ?: NoteThreadContext(emptyList(), emptyList())
+ }
+ }
+
+ override suspend fun findLocalCount(): Result = runCancellableCatching {
+ withContext(coroutineDispatcher) {
+ noteBox.count()
+ }
+ }
+
private fun publish(ev: NoteDataSource.Event) = runBlocking {
listenersLock.withLock {
listeners.forEach {
@@ -259,16 +311,19 @@ class ObjectBoxNoteDataSource @Inject constructor(
changedIdFlow.value = UUID.randomUUID().toString()
}
- private suspend fun recursiveFindReplies(noteId: Note.Id): Result> = runCancellableCatching {
- val children = findByReplyId(noteId).getOrThrow()
- children + children.map {
- recursiveFindReplies(it.id).getOrThrow()
- }.flatten()
- }
private suspend fun onAdded(note: Note) {
lock.withLock {
deleteNoteIds.remove(note.id)
}
}
+
+ private fun findByNotes(noteIds: List): List {
+ return noteBox.query().inValues(
+ NoteRecord_.accountIdAndNoteId, noteIds.map {
+ NoteRecord.generateAccountAndNoteId(it)
+ }.toTypedArray(),
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().find()
+ }
}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecord.kt
index 4dd3b19bc2..8fb634d0fc 100644
--- a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecord.kt
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteRecord.kt
@@ -86,10 +86,13 @@ data class NoteRecord(
var misskeyChannelId: String? = null,
var misskeyChannelName: String? = null,
var misskeyIsAcceptingOnlyLikeReaction: Boolean = false,
+ var misskeyIsNotAcceptingSensitiveReaction: Boolean = false,
var myReactions: MutableList? = null,
var maxReactionsPerAccount: Int = 0,
+ var customEmojiAspectRatioMap: MutableMap? = null,
+ var customEmojiUrlAndCachePathMap: MutableMap? = null,
) {
companion object {
@@ -168,8 +171,26 @@ data class NoteRecord(
misskeyChannelId = t.channel?.id?.channelId
misskeyChannelName = t.channel?.name
misskeyIsAcceptingOnlyLikeReaction = t.isAcceptingOnlyLikeReaction
+ misskeyIsNotAcceptingSensitiveReaction = t.isNotAcceptingSensitiveReaction
}
}
+ customEmojiAspectRatioMap = model.emojis?.mapNotNull { emoji ->
+ val aspectRatio = emoji.aspectRatio
+ val uri = emoji.url ?: emoji.uri
+ if (aspectRatio == null || uri == null) {
+ null
+ } else {
+ uri to aspectRatio.toString()
+ }
+ }?.toMap()?.toMutableMap()
+ customEmojiUrlAndCachePathMap = model.emojis?.mapNotNull { emoji ->
+ val url = (emoji.url ?: emoji.uri)
+ if (emoji.cachePath == null || url == null) {
+ null
+ } else {
+ url to emoji.cachePath
+ }
+ }?.toMap()?.toMutableMap()
}
fun toModel(): Note {
@@ -197,7 +218,12 @@ data class NoteRecord(
it == entry.key
} ?: false
) },
- emojis = emojis?.map { Emoji(name = it.key, url = it.value) },
+ emojis = emojis?.map { Emoji(
+ name = it.key,
+ url = it.value,
+ aspectRatio = customEmojiAspectRatioMap?.get(it.value)?.toFloatOrNull(),
+ cachePath = customEmojiUrlAndCachePathMap?.get(it.value)
+ ) },
repliesCount = repliesCount,
fileIds = fileIds?.map { FileProperty.Id(accountId, it) },
poll = getPoll(),
@@ -213,7 +239,8 @@ data class NoteRecord(
name = misskeyChannelName ?: ""
)
},
- isAcceptingOnlyLikeReaction = misskeyIsAcceptingOnlyLikeReaction
+ isAcceptingOnlyLikeReaction = misskeyIsAcceptingOnlyLikeReaction,
+ isNotAcceptingSensitiveReaction = misskeyIsNotAcceptingSensitiveReaction,
)
}
"mastodon" -> {
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteThreadRecordDAO.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteThreadRecordDAO.kt
new file mode 100644
index 0000000000..fdd462d456
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/NoteThreadRecordDAO.kt
@@ -0,0 +1,94 @@
+package net.pantasystem.milktea.data.infrastructure.notes.impl.db
+
+import io.objectbox.Box
+import io.objectbox.BoxStore
+import io.objectbox.kotlin.awaitCallInTx
+import io.objectbox.kotlin.boxFor
+import io.objectbox.kotlin.toFlow
+import io.objectbox.query.QueryBuilder
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import net.pantasystem.milktea.model.notes.Note
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+open class NoteThreadRecordDAO @Inject constructor(
+ private val boxStore: BoxStore,
+) {
+
+ private val noteThreadContextBox: Box by lazy {
+ boxStore.boxFor()
+ }
+
+ open suspend fun add(context: ThreadRecord) {
+ boxStore.awaitCallInTx {
+ val exists = noteThreadContextBox.query().equal(
+ ThreadRecord_.targetNoteIdAndAccountId,
+ context.targetNoteIdAndAccountId,
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()
+ when (exists) {
+ null -> noteThreadContextBox.put(context)
+ else -> noteThreadContextBox.put(context.copy(id = exists.id))
+ }
+ }
+
+ }
+
+ open suspend fun update(context: ThreadRecord) {
+ boxStore.awaitCallInTx {
+ noteThreadContextBox.put(context)
+ }
+ }
+
+ open suspend fun appendBlank(noteId: Note.Id): ThreadRecord {
+ return boxStore.awaitCallInTx {
+ val exists = noteThreadContextBox.query().equal(
+ ThreadRecord_.targetNoteIdAndAccountId,
+ NoteRecord.generateAccountAndNoteId(noteId),
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()
+ when (exists) {
+ null -> {
+ val new = ThreadRecord(
+ targetNoteId = noteId.noteId,
+ accountId = noteId.accountId,
+ targetNoteIdAndAccountId = NoteRecord.generateAccountAndNoteId(noteId)
+ )
+ noteThreadContextBox.put(new)
+ new
+ }
+ else -> exists
+ }
+ }!!
+ }
+
+
+ open suspend fun clearRelation(targetNote: Note.Id) {
+ boxStore.awaitCallInTx {
+ findBy(targetNote)?.also {
+ it.ancestors.clear()
+ it.descendants.clear()
+ noteThreadContextBox.put(it)
+ }
+ }
+ }
+
+ open fun findBy(noteId: Note.Id): ThreadRecord? {
+ return noteThreadContextBox.query().equal(
+ ThreadRecord_.targetNoteIdAndAccountId,
+ NoteRecord.generateAccountAndNoteId(noteId),
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().findFirst()
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ open fun observeBy(noteId: Note.Id): Flow> {
+ return noteThreadContextBox.query().equal(
+ ThreadRecord_.targetNoteIdAndAccountId,
+ NoteRecord.generateAccountAndNoteId(noteId),
+ QueryBuilder.StringOrder.CASE_SENSITIVE
+ ).build().subscribe().toFlow()
+ }
+}
\ No newline at end of file
diff --git a/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/ThreadRecord.kt b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/ThreadRecord.kt
new file mode 100644
index 0000000000..3fa057c21e
--- /dev/null
+++ b/modules/data/src/main/java/net/pantasystem/milktea/data/infrastructure/notes/impl/db/ThreadRecord.kt
@@ -0,0 +1,25 @@
+package net.pantasystem.milktea.data.infrastructure.notes.impl.db
+
+import io.objectbox.annotation.Entity
+import io.objectbox.annotation.Id
+import io.objectbox.annotation.Index
+import io.objectbox.annotation.Unique
+import io.objectbox.relation.ToMany
+
+@Entity
+data class ThreadRecord(
+ @Id
+ var id: Long = 0,
+
+
+ var targetNoteId: String = "",
+ var accountId: Long = 0L,
+
+ @Index
+ @Unique
+ var targetNoteIdAndAccountId: String = "",
+) {
+ lateinit var ancestors: ToMany