diff --git a/app/schemas/one.mixin.android.db.MixinDatabase/64.json b/app/schemas/one.mixin.android.db.MixinDatabase/64.json new file mode 100644 index 0000000000..26e226a9fa --- /dev/null +++ b/app/schemas/one.mixin.android.db.MixinDatabase/64.json @@ -0,0 +1,3486 @@ +{ + "formatVersion": 1, + "database": { + "version": 64, + "identityHash": "edabaab5427aedb6b77a897e670dfd06", + "entities": [ + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `identity_number` TEXT NOT NULL, `relationship` TEXT NOT NULL, `biography` TEXT NOT NULL, `full_name` TEXT, `avatar_url` TEXT, `phone` TEXT, `is_verified` INTEGER, `created_at` TEXT, `mute_until` TEXT, `has_pin` INTEGER, `app_id` TEXT, `is_scam` INTEGER, `is_deactivated` INTEGER, `membership` TEXT, PRIMARY KEY(`user_id`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identityNumber", + "columnName": "identity_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "relationship", + "columnName": "relationship", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "biography", + "columnName": "biography", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "full_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatar_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "phone", + "columnName": "phone", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isVerified", + "columnName": "is_verified", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "muteUntil", + "columnName": "mute_until", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "hasPin", + "columnName": "has_pin", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isScam", + "columnName": "is_scam", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isDeactivated", + "columnName": "is_deactivated", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "membership", + "columnName": "membership", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "user_id" + ] + }, + "indices": [ + { + "name": "index_users_relationship_full_name", + "unique": false, + "columnNames": [ + "relationship", + "full_name" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_users_relationship_full_name` ON `${TABLE_NAME}` (`relationship`, `full_name`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "conversations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`conversation_id` TEXT NOT NULL, `owner_id` TEXT, `category` TEXT, `name` TEXT, `icon_url` TEXT, `announcement` TEXT, `code_url` TEXT, `pay_type` TEXT, `created_at` TEXT NOT NULL, `pin_time` TEXT, `last_message_id` TEXT, `last_read_message_id` TEXT, `unseen_message_count` INTEGER, `status` INTEGER NOT NULL, `draft` TEXT, `mute_until` TEXT, `last_message_created_at` TEXT, `expire_in` INTEGER, PRIMARY KEY(`conversation_id`))", + "fields": [ + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ownerId", + "columnName": "owner_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "announcement", + "columnName": "announcement", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "codeUrl", + "columnName": "code_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "payType", + "columnName": "pay_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pinTime", + "columnName": "pin_time", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastMessageId", + "columnName": "last_message_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastReadMessageId", + "columnName": "last_read_message_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "unseenMessageCount", + "columnName": "unseen_message_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "draft", + "columnName": "draft", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "muteUntil", + "columnName": "mute_until", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastMessageCreatedAt", + "columnName": "last_message_created_at", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "expireIn", + "columnName": "expire_in", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "conversation_id" + ] + }, + "indices": [ + { + "name": "index_conversations_pin_time_last_message_created_at", + "unique": false, + "columnNames": [ + "pin_time", + "last_message_created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_conversations_pin_time_last_message_created_at` ON `${TABLE_NAME}` (`pin_time`, `last_message_created_at`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `conversation_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `category` TEXT NOT NULL, `content` TEXT, `media_url` TEXT, `media_mime_type` TEXT, `media_size` INTEGER, `media_duration` TEXT, `media_width` INTEGER, `media_height` INTEGER, `media_hash` TEXT, `thumb_image` TEXT, `thumb_url` TEXT, `media_key` BLOB, `media_digest` BLOB, `media_status` TEXT, `status` TEXT NOT NULL, `created_at` TEXT NOT NULL, `action` TEXT, `participant_id` TEXT, `snapshot_id` TEXT, `hyperlink` TEXT, `name` TEXT, `album_id` TEXT, `sticker_id` TEXT, `shared_user_id` TEXT, `media_waveform` BLOB, `media_mine_type` TEXT, `quote_message_id` TEXT, `quote_content` TEXT, `caption` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`conversation_id`) REFERENCES `conversations`(`conversation_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaUrl", + "columnName": "media_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaMimeType", + "columnName": "media_mime_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaSize", + "columnName": "media_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaDuration", + "columnName": "media_duration", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaWidth", + "columnName": "media_width", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaHeight", + "columnName": "media_height", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaHash", + "columnName": "media_hash", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbImage", + "columnName": "thumb_image", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbUrl", + "columnName": "thumb_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaKey", + "columnName": "media_key", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "mediaDigest", + "columnName": "media_digest", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "mediaStatus", + "columnName": "media_status", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "participantId", + "columnName": "participant_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "snapshotId", + "columnName": "snapshot_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "hyperlink", + "columnName": "hyperlink", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "stickerId", + "columnName": "sticker_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedUserId", + "columnName": "shared_user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaWaveform", + "columnName": "media_waveform", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "mediaMineType", + "columnName": "media_mine_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "quoteMessageId", + "columnName": "quote_message_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "quoteContent", + "columnName": "quote_content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "caption", + "columnName": "caption", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_messages_conversation_id_created_at", + "unique": false, + "columnNames": [ + "conversation_id", + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_conversation_id_created_at` ON `${TABLE_NAME}` (`conversation_id`, `created_at`)" + }, + { + "name": "index_messages_conversation_id_category", + "unique": false, + "columnNames": [ + "conversation_id", + "category" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_conversation_id_category` ON `${TABLE_NAME}` (`conversation_id`, `category`)" + }, + { + "name": "index_messages_conversation_id_quote_message_id", + "unique": false, + "columnNames": [ + "conversation_id", + "quote_message_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_conversation_id_quote_message_id` ON `${TABLE_NAME}` (`conversation_id`, `quote_message_id`)" + }, + { + "name": "index_messages_conversation_id_status_user_id_created_at", + "unique": false, + "columnNames": [ + "conversation_id", + "status", + "user_id", + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_conversation_id_status_user_id_created_at` ON `${TABLE_NAME}` (`conversation_id`, `status`, `user_id`, `created_at`)" + } + ], + "foreignKeys": [ + { + "table": "conversations", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "conversation_id" + ], + "referencedColumns": [ + "conversation_id" + ] + } + ] + }, + { + "tableName": "participants", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`conversation_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `role` TEXT NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`conversation_id`, `user_id`), FOREIGN KEY(`conversation_id`) REFERENCES `conversations`(`conversation_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "conversation_id", + "user_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "conversations", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "conversation_id" + ], + "referencedColumns": [ + "conversation_id" + ] + } + ] + }, + { + "tableName": "participant_session", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`conversation_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `session_id` TEXT NOT NULL, `sent_to_server` INTEGER, `created_at` TEXT, `public_key` TEXT, PRIMARY KEY(`conversation_id`, `user_id`, `session_id`))", + "fields": [ + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sentToServer", + "columnName": "sent_to_server", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "publicKey", + "columnName": "public_key", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "conversation_id", + "user_id", + "session_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "offsets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `timestamp` TEXT NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "key" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "assets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `symbol` TEXT NOT NULL, `name` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `balance` TEXT NOT NULL, `destination` TEXT NOT NULL, `tag` TEXT, `price_btc` TEXT NOT NULL, `price_usd` TEXT NOT NULL, `chain_id` TEXT NOT NULL, `change_usd` TEXT NOT NULL, `change_btc` TEXT NOT NULL, `confirmations` INTEGER NOT NULL, `asset_key` TEXT, `reserve` TEXT, `deposit_entries` TEXT, `withdrawal_memo_possibility` TEXT, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "balance", + "columnName": "balance", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "destination", + "columnName": "destination", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "priceBtc", + "columnName": "price_btc", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceUsd", + "columnName": "price_usd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainId", + "columnName": "chain_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changeUsd", + "columnName": "change_usd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changeBtc", + "columnName": "change_btc", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "confirmations", + "columnName": "confirmations", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "assetKey", + "columnName": "asset_key", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "reserve", + "columnName": "reserve", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "depositEntries", + "columnName": "deposit_entries", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "withdrawalMemoPossibility", + "columnName": "withdrawal_memo_possibility", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "assets_extra", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `hidden` INTEGER, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tokens_extra", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `kernel_asset_id` TEXT NOT NULL, `hidden` INTEGER, `balance` TEXT, `updated_at` TEXT NOT NULL, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "asset", + "columnName": "kernel_asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "balance", + "columnName": "balance", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "indices": [ + { + "name": "index_tokens_extra_kernel_asset_id", + "unique": false, + "columnNames": [ + "kernel_asset_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tokens_extra_kernel_asset_id` ON `${TABLE_NAME}` (`kernel_asset_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "snapshots", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`snapshot_id` TEXT NOT NULL, `type` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `amount` TEXT NOT NULL, `created_at` TEXT NOT NULL, `opponent_id` TEXT, `trace_id` TEXT, `transaction_hash` TEXT, `sender` TEXT, `receiver` TEXT, `memo` TEXT, `confirmations` INTEGER, `snapshot_hash` TEXT, `opening_balance` TEXT, `closing_balance` TEXT, PRIMARY KEY(`snapshot_id`))", + "fields": [ + { + "fieldPath": "snapshotId", + "columnName": "snapshot_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "opponentId", + "columnName": "opponent_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "traceId", + "columnName": "trace_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transactionHash", + "columnName": "transaction_hash", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sender", + "columnName": "sender", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "receiver", + "columnName": "receiver", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "confirmations", + "columnName": "confirmations", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "snapshotHash", + "columnName": "snapshot_hash", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "openingBalance", + "columnName": "opening_balance", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "closingBalance", + "columnName": "closing_balance", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "snapshot_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "messages_history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, PRIMARY KEY(`message_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sent_sender_keys", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`conversation_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `sent_to_server` INTEGER NOT NULL, `sender_key_id` INTEGER, `created_at` TEXT, PRIMARY KEY(`conversation_id`, `user_id`))", + "fields": [ + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sentToServer", + "columnName": "sent_to_server", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderKeyId", + "columnName": "sender_key_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "conversation_id", + "user_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "stickers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sticker_id` TEXT NOT NULL, `album_id` TEXT, `name` TEXT NOT NULL, `asset_url` TEXT NOT NULL, `asset_type` TEXT NOT NULL, `asset_width` INTEGER NOT NULL, `asset_height` INTEGER NOT NULL, `created_at` TEXT NOT NULL, `last_use_at` TEXT, PRIMARY KEY(`sticker_id`))", + "fields": [ + { + "fieldPath": "stickerId", + "columnName": "sticker_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetUrl", + "columnName": "asset_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetType", + "columnName": "asset_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetWidth", + "columnName": "asset_width", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "assetHeight", + "columnName": "asset_height", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUseAt", + "columnName": "last_use_at", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "sticker_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sticker_albums", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`album_id` TEXT NOT NULL, `name` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `created_at` TEXT NOT NULL, `update_at` TEXT NOT NULL, `user_id` TEXT NOT NULL, `category` TEXT NOT NULL, `description` TEXT NOT NULL, `banner` TEXT, `is_verified` INTEGER NOT NULL, `ordered_at` INTEGER NOT NULL DEFAULT 0, `added` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`album_id`))", + "fields": [ + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updateAt", + "columnName": "update_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "banner", + "columnName": "banner", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isVerified", + "columnName": "is_verified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderedAt", + "columnName": "ordered_at", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "added", + "columnName": "added", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "album_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "apps", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`app_id` TEXT NOT NULL, `app_number` TEXT NOT NULL, `home_uri` TEXT NOT NULL, `redirect_uri` TEXT NOT NULL, `name` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `category` TEXT, `description` TEXT NOT NULL, `app_secret` TEXT NOT NULL, `capabilities` TEXT, `creator_id` TEXT NOT NULL, `resource_patterns` TEXT, `updated_at` TEXT, PRIMARY KEY(`app_id`))", + "fields": [ + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appNumber", + "columnName": "app_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "homeUri", + "columnName": "home_uri", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "redirectUri", + "columnName": "redirect_uri", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appSecret", + "columnName": "app_secret", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "capabilities", + "columnName": "capabilities", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "creatorId", + "columnName": "creator_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resourcePatterns", + "columnName": "resource_patterns", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "app_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "hyperlinks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`hyperlink` TEXT NOT NULL, `site_name` TEXT NOT NULL, `site_title` TEXT NOT NULL, `site_description` TEXT, `site_image` TEXT, PRIMARY KEY(`hyperlink`))", + "fields": [ + { + "fieldPath": "hyperlink", + "columnName": "hyperlink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "siteName", + "columnName": "site_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "siteTitle", + "columnName": "site_title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "siteDescription", + "columnName": "site_description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "siteImage", + "columnName": "site_image", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "hyperlink" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "flood_messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `data` TEXT NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`message_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "addresses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address_id` TEXT NOT NULL, `type` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `destination` TEXT NOT NULL, `label` TEXT NOT NULL, `updated_at` TEXT NOT NULL, `tag` TEXT, `dust` TEXT, PRIMARY KEY(`address_id`))", + "fields": [ + { + "fieldPath": "addressId", + "columnName": "address_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "destination", + "columnName": "destination", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dust", + "columnName": "dust", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "address_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "resend_messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `status` INTEGER NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`message_id`, `user_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id", + "user_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "resend_session_messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `session_id` TEXT NOT NULL, `status` INTEGER NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`message_id`, `user_id`, `session_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id", + "user_id", + "session_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sticker_relationships", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`album_id` TEXT NOT NULL, `sticker_id` TEXT NOT NULL, PRIMARY KEY(`album_id`, `sticker_id`))", + "fields": [ + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stickerId", + "columnName": "sticker_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "album_id", + "sticker_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "top_assets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `symbol` TEXT NOT NULL, `name` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `balance` TEXT NOT NULL, `destination` TEXT NOT NULL, `tag` TEXT, `price_btc` TEXT NOT NULL, `price_usd` TEXT NOT NULL, `chain_id` TEXT NOT NULL, `change_usd` TEXT NOT NULL, `change_btc` TEXT NOT NULL, `confirmations` INTEGER NOT NULL, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "balance", + "columnName": "balance", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "destination", + "columnName": "destination", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "priceBtc", + "columnName": "price_btc", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceUsd", + "columnName": "price_usd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainId", + "columnName": "chain_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changeUsd", + "columnName": "change_usd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changeBtc", + "columnName": "change_btc", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "confirmations", + "columnName": "confirmations", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "favorite_apps", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`app_id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`app_id`, `user_id`))", + "fields": [ + { + "fieldPath": "appId", + "columnName": "app_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "app_id", + "user_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "jobs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`job_id` TEXT NOT NULL, `action` TEXT NOT NULL, `created_at` TEXT NOT NULL, `order_id` INTEGER, `priority` INTEGER NOT NULL, `user_id` TEXT, `blaze_message` TEXT, `conversation_id` TEXT, `resend_message_id` TEXT, `run_count` INTEGER NOT NULL, PRIMARY KEY(`job_id`))", + "fields": [ + { + "fieldPath": "jobId", + "columnName": "job_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "order_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "priority", + "columnName": "priority", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "blazeMessage", + "columnName": "blaze_message", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "resendMessageId", + "columnName": "resend_message_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "runCount", + "columnName": "run_count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "job_id" + ] + }, + "indices": [ + { + "name": "index_jobs_action", + "unique": false, + "columnNames": [ + "action" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_jobs_action` ON `${TABLE_NAME}` (`action`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "message_mentions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `conversation_id` TEXT NOT NULL, `mentions` TEXT NOT NULL, `has_read` INTEGER NOT NULL, PRIMARY KEY(`message_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mentions", + "columnName": "mentions", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasRead", + "columnName": "has_read", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id" + ] + }, + "indices": [ + { + "name": "index_message_mentions_conversation_id", + "unique": false, + "columnNames": [ + "conversation_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_message_mentions_conversation_id` ON `${TABLE_NAME}` (`conversation_id`)" + } + ], + "foreignKeys": [] + }, + { + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "unicode61", + "tokenizerArgs": [], + "contentTable": "", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [ + "message_id" + ], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [], + "tableName": "messages_fts4", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`message_id` TEXT NOT NULL, `content` TEXT, tokenize=unicode61, notindexed=`message_id`)", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "circles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`circle_id` TEXT NOT NULL, `name` TEXT NOT NULL, `created_at` TEXT NOT NULL, `ordered_at` TEXT, PRIMARY KEY(`circle_id`))", + "fields": [ + { + "fieldPath": "circleId", + "columnName": "circle_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderedAt", + "columnName": "ordered_at", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "circle_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "circle_conversations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`conversation_id` TEXT NOT NULL, `circle_id` TEXT NOT NULL, `user_id` TEXT, `created_at` TEXT NOT NULL, `pin_time` TEXT, PRIMARY KEY(`conversation_id`, `circle_id`))", + "fields": [ + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "circleId", + "columnName": "circle_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pinTime", + "columnName": "pin_time", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "conversation_id", + "circle_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "traces", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`trace_id` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `amount` TEXT NOT NULL, `opponent_id` TEXT, `destination` TEXT, `tag` TEXT, `snapshot_id` TEXT, `created_at` TEXT NOT NULL, PRIMARY KEY(`trace_id`))", + "fields": [ + { + "fieldPath": "traceId", + "columnName": "trace_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "opponentId", + "columnName": "opponent_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "destination", + "columnName": "destination", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "snapshotId", + "columnName": "snapshot_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "trace_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transcript_messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`transcript_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `user_id` TEXT, `user_full_name` TEXT, `category` TEXT NOT NULL, `created_at` TEXT NOT NULL, `content` TEXT, `media_url` TEXT, `media_name` TEXT, `media_size` INTEGER, `media_width` INTEGER, `media_height` INTEGER, `media_mime_type` TEXT, `media_duration` INTEGER, `media_status` TEXT, `media_waveform` BLOB, `thumb_image` TEXT, `thumb_url` TEXT, `media_key` BLOB, `media_digest` BLOB, `media_created_at` TEXT, `sticker_id` TEXT, `shared_user_id` TEXT, `mentions` TEXT, `quote_id` TEXT, `quote_content` TEXT, `caption` TEXT, PRIMARY KEY(`transcript_id`, `message_id`))", + "fields": [ + { + "fieldPath": "transcriptId", + "columnName": "transcript_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "userFullName", + "columnName": "user_full_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaUrl", + "columnName": "media_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaName", + "columnName": "media_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaSize", + "columnName": "media_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaWidth", + "columnName": "media_width", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaHeight", + "columnName": "media_height", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaMimeType", + "columnName": "media_mime_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaDuration", + "columnName": "media_duration", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mediaStatus", + "columnName": "media_status", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaWaveform", + "columnName": "media_waveform", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "thumbImage", + "columnName": "thumb_image", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thumbUrl", + "columnName": "thumb_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mediaKey", + "columnName": "media_key", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "mediaDigest", + "columnName": "media_digest", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "mediaCreatedAt", + "columnName": "media_created_at", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "stickerId", + "columnName": "sticker_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedUserId", + "columnName": "shared_user_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mentions", + "columnName": "mentions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "quoteId", + "columnName": "quote_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "quoteContent", + "columnName": "quote_content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "caption", + "columnName": "caption", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "transcript_id", + "message_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "pin_messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `conversation_id` TEXT NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`message_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id" + ] + }, + "indices": [ + { + "name": "index_pin_messages_conversation_id_created_at", + "unique": false, + "columnNames": [ + "conversation_id", + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_pin_messages_conversation_id_created_at` ON `${TABLE_NAME}` (`conversation_id`, `created_at`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "properties", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `value` TEXT NOT NULL, `updated_at` TEXT NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "key" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "remote_messages_status", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `conversation_id` TEXT NOT NULL, `status` TEXT NOT NULL, PRIMARY KEY(`message_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id" + ] + }, + "indices": [ + { + "name": "index_remote_messages_status_conversation_id_status", + "unique": false, + "columnNames": [ + "conversation_id", + "status" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_remote_messages_status_conversation_id_status` ON `${TABLE_NAME}` (`conversation_id`, `status`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "expired_messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`message_id` TEXT NOT NULL, `expire_in` INTEGER NOT NULL, `expire_at` INTEGER, PRIMARY KEY(`message_id`))", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "expireIn", + "columnName": "expire_in", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expireAt", + "columnName": "expire_at", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "message_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "conversation_ext", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`conversation_id` TEXT NOT NULL, `count` INTEGER NOT NULL DEFAULT 0, `created_at` TEXT NOT NULL, PRIMARY KEY(`conversation_id`))", + "fields": [ + { + "fieldPath": "conversationId", + "columnName": "conversation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "conversation_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "chains", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`chain_id` TEXT NOT NULL, `name` TEXT NOT NULL, `symbol` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `threshold` INTEGER NOT NULL, `withdrawal_memo_possibility` TEXT NOT NULL, PRIMARY KEY(`chain_id`))", + "fields": [ + { + "fieldPath": "chainId", + "columnName": "chain_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "threshold", + "columnName": "threshold", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "withdrawalMemoPossibility", + "columnName": "withdrawal_memo_possibility", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "chain_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "outputs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`output_id` TEXT NOT NULL, `transaction_hash` TEXT NOT NULL, `output_index` INTEGER NOT NULL, `asset` TEXT NOT NULL, `sequence` INTEGER NOT NULL, `amount` TEXT NOT NULL, `mask` TEXT NOT NULL, `keys` TEXT NOT NULL, `receivers` TEXT NOT NULL, `receivers_hash` TEXT NOT NULL, `receivers_threshold` INTEGER NOT NULL, `extra` TEXT NOT NULL, `state` TEXT NOT NULL, `created_at` TEXT NOT NULL, `updated_at` TEXT NOT NULL, `signed_by` TEXT NOT NULL, `signed_at` TEXT NOT NULL, `spent_at` TEXT NOT NULL, `inscription_hash` TEXT, PRIMARY KEY(`output_id`))", + "fields": [ + { + "fieldPath": "outputId", + "columnName": "output_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transactionHash", + "columnName": "transaction_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "outputIndex", + "columnName": "output_index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "asset", + "columnName": "asset", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sequence", + "columnName": "sequence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mask", + "columnName": "mask", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "keys", + "columnName": "keys", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "receivers", + "columnName": "receivers", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "receiversHash", + "columnName": "receivers_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "receiversThreshold", + "columnName": "receivers_threshold", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "extra", + "columnName": "extra", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "signedBy", + "columnName": "signed_by", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "signedAt", + "columnName": "signed_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "spentAt", + "columnName": "spent_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "inscriptionHash", + "columnName": "inscription_hash", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "output_id" + ] + }, + "indices": [ + { + "name": "index_outputs_asset_state_sequence", + "unique": false, + "columnNames": [ + "asset", + "state", + "sequence" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_outputs_asset_state_sequence` ON `${TABLE_NAME}` (`asset`, `state`, `sequence`)" + }, + { + "name": "index_outputs_transaction_hash_output_index", + "unique": true, + "columnNames": [ + "transaction_hash", + "output_index" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_outputs_transaction_hash_output_index` ON `${TABLE_NAME}` (`transaction_hash`, `output_index`)" + }, + { + "name": "index_outputs_inscription_hash", + "unique": false, + "columnNames": [ + "inscription_hash" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_outputs_inscription_hash` ON `${TABLE_NAME}` (`inscription_hash`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tokens", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `kernel_asset_id` TEXT NOT NULL, `symbol` TEXT NOT NULL, `name` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `price_btc` TEXT NOT NULL, `price_usd` TEXT NOT NULL, `chain_id` TEXT NOT NULL, `change_usd` TEXT NOT NULL, `change_btc` TEXT NOT NULL, `confirmations` INTEGER NOT NULL, `asset_key` TEXT NOT NULL, `dust` TEXT NOT NULL, `collection_hash` TEXT, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "asset", + "columnName": "kernel_asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceBtc", + "columnName": "price_btc", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceUsd", + "columnName": "price_usd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainId", + "columnName": "chain_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changeUsd", + "columnName": "change_usd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "changeBtc", + "columnName": "change_btc", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "confirmations", + "columnName": "confirmations", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "assetKey", + "columnName": "asset_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dust", + "columnName": "dust", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "collectionHash", + "columnName": "collection_hash", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "indices": [ + { + "name": "index_tokens_kernel_asset_id", + "unique": false, + "columnNames": [ + "kernel_asset_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tokens_kernel_asset_id` ON `${TABLE_NAME}` (`kernel_asset_id`)" + }, + { + "name": "index_tokens_collection_hash", + "unique": false, + "columnNames": [ + "collection_hash" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tokens_collection_hash` ON `${TABLE_NAME}` (`collection_hash`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "deposit_entries", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`entry_id` TEXT NOT NULL, `chain_id` TEXT NOT NULL, `destination` TEXT NOT NULL, `members` TEXT NOT NULL, `tag` TEXT, `signature` TEXT NOT NULL, `threshold` INTEGER NOT NULL, `is_primary` INTEGER NOT NULL, PRIMARY KEY(`entry_id`))", + "fields": [ + { + "fieldPath": "entryId", + "columnName": "entry_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainId", + "columnName": "chain_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "destination", + "columnName": "destination", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "members", + "columnName": "members", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "signature", + "columnName": "signature", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "threshold", + "columnName": "threshold", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPrimary", + "columnName": "is_primary", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "entry_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "safe_snapshots", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`snapshot_id` TEXT NOT NULL, `type` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `amount` TEXT NOT NULL, `user_id` TEXT NOT NULL, `opponent_id` TEXT NOT NULL, `memo` TEXT NOT NULL, `transaction_hash` TEXT NOT NULL, `created_at` TEXT NOT NULL, `trace_id` TEXT, `confirmations` INTEGER, `opening_balance` TEXT, `closing_balance` TEXT, `deposit` TEXT, `withdrawal` TEXT, `inscription_hash` TEXT, PRIMARY KEY(`snapshot_id`))", + "fields": [ + { + "fieldPath": "snapshotId", + "columnName": "snapshot_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "opponentId", + "columnName": "opponent_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transactionHash", + "columnName": "transaction_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "traceId", + "columnName": "trace_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "confirmations", + "columnName": "confirmations", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "openingBalance", + "columnName": "opening_balance", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "closingBalance", + "columnName": "closing_balance", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deposit", + "columnName": "deposit", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "withdrawal", + "columnName": "withdrawal", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "inscriptionHash", + "columnName": "inscription_hash", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "snapshot_id" + ] + }, + "indices": [ + { + "name": "index_safe_snapshots_created_at", + "unique": false, + "columnNames": [ + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_safe_snapshots_created_at` ON `${TABLE_NAME}` (`created_at`)" + }, + { + "name": "index_safe_snapshots_type_asset_id", + "unique": false, + "columnNames": [ + "type", + "asset_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_safe_snapshots_type_asset_id` ON `${TABLE_NAME}` (`type`, `asset_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "raw_transactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`request_id` TEXT NOT NULL, `raw_transaction` TEXT NOT NULL, `receiver_id` TEXT NOT NULL, `type` INTEGER NOT NULL, `state` TEXT NOT NULL, `created_at` TEXT NOT NULL, `inscription_hash` TEXT, `transaction_hash` TEXT, PRIMARY KEY(`request_id`))", + "fields": [ + { + "fieldPath": "requestId", + "columnName": "request_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rawTransaction", + "columnName": "raw_transaction", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "receiverId", + "columnName": "receiver_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "inscriptionHash", + "columnName": "inscription_hash", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transactionHash", + "columnName": "transaction_hash", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "request_id" + ] + }, + "indices": [ + { + "name": "index_raw_transactions_state_type", + "unique": false, + "columnNames": [ + "state", + "type" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_raw_transactions_state_type` ON `${TABLE_NAME}` (`state`, `type`)" + }, + { + "name": "index_raw_transactions_transaction_hash", + "unique": false, + "columnNames": [ + "transaction_hash" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_raw_transactions_transaction_hash` ON `${TABLE_NAME}` (`transaction_hash`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "inscription_collections", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`collection_hash` TEXT NOT NULL, `supply` TEXT NOT NULL, `unit` TEXT NOT NULL, `symbol` TEXT NOT NULL, `name` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `created_at` TEXT NOT NULL, `updated_at` TEXT NOT NULL, `description` TEXT, `kernel_asset_id` TEXT, `treasury` TEXT, PRIMARY KEY(`collection_hash`))", + "fields": [ + { + "fieldPath": "collectionHash", + "columnName": "collection_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "supply", + "columnName": "supply", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "unit", + "columnName": "unit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconURL", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "kernelAssetId", + "columnName": "kernel_asset_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "treasury", + "columnName": "treasury", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "collection_hash" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "inscription_items", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`inscription_hash` TEXT NOT NULL, `collection_hash` TEXT NOT NULL, `sequence` INTEGER NOT NULL, `content_type` TEXT NOT NULL, `content_url` TEXT NOT NULL, `occupied_by` TEXT, `occupied_at` TEXT, `created_at` TEXT NOT NULL, `updated_at` TEXT NOT NULL, `owner` TEXT, `traits` TEXT, PRIMARY KEY(`inscription_hash`))", + "fields": [ + { + "fieldPath": "inscriptionHash", + "columnName": "inscription_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "collectionHash", + "columnName": "collection_hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sequence", + "columnName": "sequence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contentURL", + "columnName": "content_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "occupiedBy", + "columnName": "occupied_by", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "occupiedAt", + "columnName": "occupied_at", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "owner", + "columnName": "owner", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "traits", + "columnName": "traits", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "inscription_hash" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "markets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`coin_id` TEXT NOT NULL, `name` TEXT NOT NULL, `symbol` TEXT NOT NULL, `icon_url` TEXT NOT NULL, `current_price` TEXT NOT NULL, `market_cap` TEXT NOT NULL, `market_cap_rank` TEXT NOT NULL, `total_volume` TEXT NOT NULL, `high_24h` TEXT NOT NULL, `low_24h` TEXT NOT NULL, `price_change_24h` TEXT NOT NULL, `price_change_percentage_1h` TEXT NOT NULL, `price_change_percentage_24h` TEXT NOT NULL, `price_change_percentage_7d` TEXT NOT NULL, `price_change_percentage_30d` TEXT NOT NULL, `market_cap_change_24h` TEXT NOT NULL, `market_cap_change_percentage_24h` TEXT NOT NULL, `circulating_supply` TEXT NOT NULL, `total_supply` TEXT NOT NULL, `max_supply` TEXT NOT NULL, `ath` TEXT NOT NULL, `ath_change_percentage` TEXT NOT NULL, `ath_date` TEXT NOT NULL, `atl` TEXT NOT NULL, `atl_change_percentage` TEXT NOT NULL, `atl_date` TEXT NOT NULL, `asset_ids` TEXT, `sparkline_in_7d` TEXT NOT NULL, `sparkline_in_24h` TEXT NOT NULL, `updated_at` TEXT NOT NULL, PRIMARY KEY(`coin_id`))", + "fields": [ + { + "fieldPath": "coinId", + "columnName": "coin_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currentPrice", + "columnName": "current_price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marketCap", + "columnName": "market_cap", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marketCapRank", + "columnName": "market_cap_rank", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalVolume", + "columnName": "total_volume", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "high24h", + "columnName": "high_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "low24h", + "columnName": "low_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceChange24h", + "columnName": "price_change_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceChangePercentage1H", + "columnName": "price_change_percentage_1h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceChangePercentage24H", + "columnName": "price_change_percentage_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceChangePercentage7D", + "columnName": "price_change_percentage_7d", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priceChangePercentage30D", + "columnName": "price_change_percentage_30d", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marketCapChange24h", + "columnName": "market_cap_change_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marketCapChangePercentage24h", + "columnName": "market_cap_change_percentage_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "circulatingSupply", + "columnName": "circulating_supply", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalSupply", + "columnName": "total_supply", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "maxSupply", + "columnName": "max_supply", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ath", + "columnName": "ath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "athChangePercentage", + "columnName": "ath_change_percentage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "athDate", + "columnName": "ath_date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "atl", + "columnName": "atl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "atlChangePercentage", + "columnName": "atl_change_percentage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "atlDate", + "columnName": "atl_date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetIds", + "columnName": "asset_ids", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sparklineIn7d", + "columnName": "sparkline_in_7d", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sparklineIn24h", + "columnName": "sparkline_in_24h", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "coin_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "history_prices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`coin_id` TEXT NOT NULL, `type` TEXT NOT NULL, `data` TEXT NOT NULL, `updated_at` TEXT NOT NULL, PRIMARY KEY(`coin_id`, `type`))", + "fields": [ + { + "fieldPath": "coinId", + "columnName": "coin_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "coin_id", + "type" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "market_coins", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `coin_id` TEXT NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "coinId", + "columnName": "coin_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "market_favored", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`coin_id` TEXT NOT NULL, `is_favored` INTEGER NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`coin_id`))", + "fields": [ + { + "fieldPath": "coinId", + "columnName": "coin_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isFavored", + "columnName": "is_favored", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "coin_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "market_alerts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alert_id` TEXT NOT NULL, `coin_id` TEXT NOT NULL, `type` TEXT NOT NULL, `frequency` TEXT NOT NULL, `status` TEXT NOT NULL, `value` TEXT NOT NULL, `created_at` TEXT NOT NULL, PRIMARY KEY(`alert_id`))", + "fields": [ + { + "fieldPath": "alertId", + "columnName": "alert_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "coinId", + "columnName": "coin_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "frequency", + "columnName": "frequency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "alert_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "market_cap_ranks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`coin_id` TEXT NOT NULL, `market_cap_rank` TEXT NOT NULL, `updated_at` TEXT NOT NULL, PRIMARY KEY(`coin_id`))", + "fields": [ + { + "fieldPath": "coinId", + "columnName": "coin_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marketCapRank", + "columnName": "market_cap_rank", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "coin_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "user_fetch_times", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `last_fetch_at` INTEGER NOT NULL, PRIMARY KEY(`user_id`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastFetchAt", + "columnName": "last_fetch_at", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "user_id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "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, 'edabaab5427aedb6b77a897e670dfd06')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/one/mixin/android/Constants.kt b/app/src/main/java/one/mixin/android/Constants.kt index 0612bd9a8e..4f9bf6b404 100644 --- a/app/src/main/java/one/mixin/android/Constants.kt +++ b/app/src/main/java/one/mixin/android/Constants.kt @@ -165,7 +165,7 @@ object Constants { object DataBase { const val DB_NAME = "mixin.db" const val MINI_VERSION = 15 - const val CURRENT_VERSION = 63 + const val CURRENT_VERSION = 64 const val FTS_DB_NAME = "fts.db" const val PENDING_DB_NAME = "pending.db" diff --git a/app/src/main/java/one/mixin/android/MixinApplication.kt b/app/src/main/java/one/mixin/android/MixinApplication.kt index e02c6cec79..c527d5d3db 100644 --- a/app/src/main/java/one/mixin/android/MixinApplication.kt +++ b/app/src/main/java/one/mixin/android/MixinApplication.kt @@ -80,6 +80,7 @@ import one.mixin.android.ui.web.refresh import one.mixin.android.ui.web.releaseAll import one.mixin.android.util.CursorWindowFixer import one.mixin.android.util.MemoryCallback +import one.mixin.android.util.UserBatchProcessor import one.mixin.android.util.debug.FileLogTree import one.mixin.android.util.initNativeLibs import one.mixin.android.util.mlkit.entityInitialize @@ -296,7 +297,7 @@ open class MixinApplication : activity.shouldLogout = true return } - + UserBatchProcessor.getInstance().shutdown() if (force || isOnline.compareAndSet(true, false)) { val sessionId = Session.getSessionId() BlazeMessageService.stopService(this) diff --git a/app/src/main/java/one/mixin/android/db/MixinDatabase.kt b/app/src/main/java/one/mixin/android/db/MixinDatabase.kt index 754fa6ca27..60ea979cf4 100644 --- a/app/src/main/java/one/mixin/android/db/MixinDatabase.kt +++ b/app/src/main/java/one/mixin/android/db/MixinDatabase.kt @@ -64,6 +64,7 @@ import one.mixin.android.db.MixinDatabaseMigrations.Companion.MIGRATION_59_60 import one.mixin.android.db.MixinDatabaseMigrations.Companion.MIGRATION_60_61 import one.mixin.android.db.MixinDatabaseMigrations.Companion.MIGRATION_61_62 import one.mixin.android.db.MixinDatabaseMigrations.Companion.MIGRATION_62_63 +import one.mixin.android.db.MixinDatabaseMigrations.Companion.MIGRATION_63_64 import one.mixin.android.db.converter.DepositEntryListConverter import one.mixin.android.db.converter.MembershipConverter import one.mixin.android.db.converter.MessageStatusConverter @@ -116,6 +117,7 @@ import one.mixin.android.vo.TopAsset import one.mixin.android.vo.Trace import one.mixin.android.vo.TranscriptMessage import one.mixin.android.vo.User +import one.mixin.android.vo.UserFetchTime import one.mixin.android.vo.market.HistoryPrice import one.mixin.android.vo.market.Market import one.mixin.android.vo.market.MarketCapRank @@ -181,7 +183,8 @@ import kotlin.math.min (MarketCoin::class), (MarketFavored::class), (Alert::class), - (MarketCapRank::class) + (MarketCapRank::class), + (UserFetchTime::class), ], version = CURRENT_VERSION, ) @@ -356,6 +359,7 @@ abstract class MixinDatabase : RoomDatabase() { MIGRATION_60_61, MIGRATION_61_62, MIGRATION_62_63, + MIGRATION_63_64, ) .enableMultiInstanceInvalidation() .setQueryExecutor( diff --git a/app/src/main/java/one/mixin/android/db/MixinDatabaseMigrations.kt b/app/src/main/java/one/mixin/android/db/MixinDatabaseMigrations.kt index d95e89d13e..f9b579855c 100644 --- a/app/src/main/java/one/mixin/android/db/MixinDatabaseMigrations.kt +++ b/app/src/main/java/one/mixin/android/db/MixinDatabaseMigrations.kt @@ -544,6 +544,15 @@ class MixinDatabaseMigrations private constructor() { db.execSQL("CREATE INDEX IF NOT EXISTS `index_pin_messages_conversation_id_created_at` ON `pin_messages` (`conversation_id`, `created_at`)") } } + + val MIGRATION_63_64: Migration = + object : Migration(63, 64) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("CREATE TABLE IF NOT EXISTS `user_fetch_times` (`user_id` TEXT NOT NULL, `last_fetch_at` INTEGER NOT NULL, PRIMARY KEY(`user_id`))") + db.execSQL("ALTER TABLE `raw_transactions` ADD COLUMN `transaction_hash` TEXT") + db.execSQL("CREATE INDEX IF NOT EXISTS `index_raw_transactions_transaction_hash` ON `raw_transactions` (`transaction_hash`)") + } + } // If you add a new table, be sure to add a clear method to the DatabaseUtil } } diff --git a/app/src/main/java/one/mixin/android/db/UserDao.kt b/app/src/main/java/one/mixin/android/db/UserDao.kt index cfd6186aeb..e249643194 100644 --- a/app/src/main/java/one/mixin/android/db/UserDao.kt +++ b/app/src/main/java/one/mixin/android/db/UserDao.kt @@ -2,6 +2,8 @@ package one.mixin.android.db import androidx.lifecycle.LiveData import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.RoomWarnings import androidx.room.Transaction @@ -12,6 +14,7 @@ import one.mixin.android.vo.CallUser import one.mixin.android.vo.ForwardUser import one.mixin.android.vo.MentionUser import one.mixin.android.vo.User +import one.mixin.android.vo.UserFetchTime import one.mixin.android.vo.UserItem @Dao @@ -29,6 +32,7 @@ interface UserDao : BaseDao { user.relationship = relationship update(user) } + insertFetch(UserFetchTime(user.userId, System.currentTimeMillis())) } @Transaction @@ -45,6 +49,10 @@ interface UserDao : BaseDao { } appDao.insertList(apps) insertList(users) + val currentTime = System.currentTimeMillis() + insertAllFetch(users.map { user -> + UserFetchTime(user.userId, currentTime) + }) } @Transaction @@ -62,8 +70,22 @@ interface UserDao : BaseDao { } else { update(user) } + insertFetch(UserFetchTime(user.userId, System.currentTimeMillis())) } + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertFetch(userFetchTime: UserFetchTime) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAllFetch(userFetchTimes: List) + + @Query(""" + SELECT user_id FROM user_fetch_times + WHERE user_id IN (:userIds) + AND (strftime('%s','now') - last_fetch_at) < 24 * 60 * 60 * 1000 + """) + suspend fun filterUserIdsNotFetchedIn24Hours(userIds: List): List + @Query("SELECT * FROM users WHERE relationship = 'FRIEND' ORDER BY full_name, identity_number ASC") fun findFriends(): LiveData> diff --git a/app/src/main/java/one/mixin/android/job/RestoreTransactionJob.kt b/app/src/main/java/one/mixin/android/job/RestoreTransactionJob.kt index bbfe64785d..7423830f04 100644 --- a/app/src/main/java/one/mixin/android/job/RestoreTransactionJob.kt +++ b/app/src/main/java/one/mixin/android/job/RestoreTransactionJob.kt @@ -56,9 +56,9 @@ class RestoreTransactionJob : BaseJob( Timber.e("Restore Transaction(${transaction.requestId}): db begin") runInTransaction { Timber.e("Restore Transaction(${transaction.requestId}): update raw transaction ${transaction.requestId}") - rawTransactionDao.updateRawTransaction(transaction.requestId, OutputState.signed.name) + rawTransactionDao.updateRawTransaction(transaction.requestId, OutputState.spent.name) Timber.e("Restore Transaction(${transaction.requestId}): update raw transaction $feeTraceId") - rawTransactionDao.updateRawTransaction(feeTraceId, OutputState.signed.name) + rawTransactionDao.updateRawTransaction(feeTraceId, OutputState.spent.name) } Timber.e("Restore Transaction(${transaction.requestId}): db end") if (feeTransaction == null) { @@ -83,9 +83,9 @@ class RestoreTransactionJob : BaseJob( Timber.e("Restore Transaction(${transaction.requestId}): db begin") runInTransaction { Timber.e("Restore Transaction(${transaction.requestId}): update raw transaction ${transaction.requestId}") - rawTransactionDao.updateRawTransaction(transaction.requestId, OutputState.signed.name) + rawTransactionDao.updateRawTransaction(transaction.requestId, OutputState.spent.name) Timber.e("Restore Transaction(${transaction.requestId}): update raw transaction $feeTraceId") - rawTransactionDao.updateRawTransaction(feeTraceId, OutputState.signed.name) + rawTransactionDao.updateRawTransaction(feeTraceId, OutputState.spent.name) } Timber.e("Restore Transaction(${transaction.requestId}): db end") if (feeTransaction == null && transaction.receiverId.isNotBlank()) { @@ -94,8 +94,8 @@ class RestoreTransactionJob : BaseJob( } else { Timber.e("Restore Transaction(${transaction.requestId}): Post Transaction Error ${transactionRsp.errorDescription}") reportException(e = Throwable("Transaction Error ${transactionRsp.errorDescription}")) - rawTransactionDao.updateRawTransaction(transaction.requestId, OutputState.signed.name) - rawTransactionDao.updateRawTransaction(feeTraceId, OutputState.signed.name) + rawTransactionDao.updateRawTransaction(transaction.requestId, OutputState.spent.name) + rawTransactionDao.updateRawTransaction(feeTraceId, OutputState.spent.name) } jobManager.addJobInBackground(SyncOutputJob()) } else if (response.errorCode >= 500) { diff --git a/app/src/main/java/one/mixin/android/job/UserBatchProcessorJob.kt b/app/src/main/java/one/mixin/android/job/UserBatchProcessorJob.kt new file mode 100644 index 0000000000..f66ac4099f --- /dev/null +++ b/app/src/main/java/one/mixin/android/job/UserBatchProcessorJob.kt @@ -0,0 +1,26 @@ +package one.mixin.android.job + +import com.birbit.android.jobqueue.Params +import kotlinx.coroutines.runBlocking +import timber.log.Timber +import java.util.concurrent.TimeUnit + +class UserBatchProcessorJob( + private val userIds: List +) : BaseJob(Params(PRIORITY_UI_HIGH).addTags(GROUP).requireNetwork().persist()) { + + companion object { + private const val serialVersionUID = 1L + private const val GROUP = "UserBatchProcessorJob" + private const val FETCH_INTERVAL_HOURS = 24L + } + + override fun onRun() = runBlocking { + val filterId = userDao.filterUserIdsNotFetchedIn24Hours(userIds) + (userIds - filterId).let { ids -> + if (ids.isNotEmpty()) { + jobManager.addJobInBackground(RefreshUserJob(ids, forceRefresh = true)) + } + } + } +} diff --git a/app/src/main/java/one/mixin/android/ui/common/BottomSheetViewModel.kt b/app/src/main/java/one/mixin/android/ui/common/BottomSheetViewModel.kt index ac7a065caa..7e96317cd8 100644 --- a/app/src/main/java/one/mixin/android/ui/common/BottomSheetViewModel.kt +++ b/app/src/main/java/one/mixin/android/ui/common/BottomSheetViewModel.kt @@ -3,7 +3,6 @@ package one.mixin.android.ui.common import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.google.protobuf.Mixin import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers @@ -74,7 +73,6 @@ import one.mixin.android.util.uniqueObjectId import one.mixin.android.vo.Account import one.mixin.android.vo.Address import one.mixin.android.vo.AddressItem -import one.mixin.android.vo.App import one.mixin.android.vo.AssetPrecision import one.mixin.android.vo.Circle import one.mixin.android.vo.CircleConversation @@ -306,9 +304,9 @@ class BottomSheetViewModel Timber.e("Kernel Withdrawal($traceId): db insert fee snapshot") tokenRepository.insertSafeSnapshot(UUID.nameUUIDFromBytes("$senderId:$feeTransactionHash".toByteArray()).toString(), senderId, receiverId, feeTransactionHash, feeTraceId, feeAssetId, feeAmount, "", SafeSnapshotType.snapshot) Timber.e("Kernel Withdrawal($traceId): db raw transaction") - tokenRepository.insetRawTransaction(RawTransaction(withdrawalData.requestId, signWithdrawalResult.raw, formatDestination(destination, tag), RawTransactionType.WITHDRAWAL, OutputState.unspent, nowInUtc(), withdrawalUtxos.inscriptionHash)) + tokenRepository.insetRawTransaction(RawTransaction(withdrawalData.requestId, signWithdrawalResult.raw, formatDestination(destination, tag), RawTransactionType.WITHDRAWAL, OutputState.unspent, nowInUtc(), withdrawalUtxos.inscriptionHash, transactionHash)) Timber.e("Kernel Withdrawal($traceId): db insert fee raw transaction") - tokenRepository.insetRawTransaction(RawTransaction(feeData.requestId, signFeeResult.raw, receiverId, RawTransactionType.FEE, OutputState.unspent, nowInUtc(), null)) + tokenRepository.insetRawTransaction(RawTransaction(feeData.requestId, signFeeResult.raw, receiverId, RawTransactionType.FEE, OutputState.unspent, nowInUtc(), null, transactionHash)) } Timber.e("Kernel Withdrawal($traceId): db end") jobManager.addJobInBackground(CheckBalanceJob(arrayListOf(assetIdToAsset(assetId), assetIdToAsset(feeAssetId)))) @@ -341,7 +339,7 @@ class BottomSheetViewModel ), ) Timber.e("Kernel Withdrawal($traceId): db update raw transaction") - tokenRepository.insetRawTransaction(RawTransaction(withdrawalData.requestId, signWithdrawalResult.raw, formatDestination(destination, tag), RawTransactionType.WITHDRAWAL, OutputState.unspent, nowInUtc(), withdrawalUtxos.inscriptionHash)) + tokenRepository.insetRawTransaction(RawTransaction(withdrawalData.requestId, signWithdrawalResult.raw, formatDestination(destination, tag), RawTransactionType.WITHDRAWAL, OutputState.unspent, nowInUtc(), withdrawalUtxos.inscriptionHash, transactionHash)) } Timber.e("Kernel Withdrawal($traceId): db end") jobManager.addJobInBackground(CheckBalanceJob(arrayListOf(assetIdToAsset(assetId)))) @@ -357,12 +355,12 @@ class BottomSheetViewModel if (transactionRsp.error != null) { Timber.e("Kernel Withdrawal($traceId): withdrawal error ${transactionRsp.errorDescription}") reportException(Throwable("Transaction Error ${transactionRsp.errorDescription}")) - tokenRepository.updateRawTransaction(traceId, OutputState.signed.name) - tokenRepository.updateRawTransaction(feeTraceId, OutputState.signed.name) + tokenRepository.updateRawTransaction(traceId, OutputState.spent.name) + tokenRepository.updateRawTransaction(feeTraceId, OutputState.spent.name) return transactionRsp } else { - tokenRepository.updateRawTransaction(traceId, OutputState.signed.name) - tokenRepository.updateRawTransaction(feeTraceId, OutputState.signed.name) + tokenRepository.updateRawTransaction(traceId, OutputState.spent.name) + tokenRepository.updateRawTransaction(feeTraceId, OutputState.spent.name) } jobManager.addJobInBackground(SyncOutputJob()) Timber.e("Kernel Withdrawal($traceId): withdrawal end") @@ -435,7 +433,7 @@ class BottomSheetViewModel Timber.e("Kernel Address Transaction($trace): sign db insert snapshot") tokenRepository.insertSafeSnapshot(UUID.nameUUIDFromBytes("$senderId:$transactionHash".toByteArray()).toString(), senderId, kernelAddress, transactionHash, trace, assetId, amount, memo, SafeSnapshotType.snapshot, reference = reference) Timber.e("Kernel Address Transaction($trace): sign db insert raw transaction") - tokenRepository.insetRawTransaction(RawTransaction(transactionResponse.data!!.first().requestId, signResult.raw, "", RawTransactionType.TRANSFER, OutputState.unspent, nowInUtc(), utxoWrapper.inscriptionHash)) + tokenRepository.insetRawTransaction(RawTransaction(transactionResponse.data!!.first().requestId, signResult.raw, "", RawTransactionType.TRANSFER, OutputState.unspent, nowInUtc(), utxoWrapper.inscriptionHash, transactionHash)) Timber.e("Kernel Address Transaction($trace): sign db mark utxo ${utxoWrapper.ids.joinToString(", ")}") tokenRepository.updateUtxoToSigned(utxoWrapper.ids) Timber.e("Kernel Address Transaction: sign end") @@ -530,8 +528,13 @@ class BottomSheetViewModel Timber.e("Kernel Transaction($trace): sign db insert snapshot") tokenRepository.insertSafeSnapshot(UUID.nameUUIDFromBytes("${senderIds.first()}:$transactionHash".toByteArray()).toString(), senderIds.first(), opponentId, transactionHash, trace, assetId, amount, memo, SafeSnapshotType.snapshot, reference = reference ?: (if (release == true) null else inscriptionHash)) } + val transactionHash = if (!isConsolidation) { + sign.hash + } else { + null + } Timber.e("Kernel Transaction($trace): sign db insert raw transaction") - tokenRepository.insetRawTransaction(RawTransaction(transactionResponse.data!!.first().requestId, signResult.raw, receiverIds.joinToString(","), RawTransactionType.TRANSFER, OutputState.unspent, nowInUtc(), if (release == true) null else utxoWrapper.inscriptionHash)) + tokenRepository.insetRawTransaction(RawTransaction(transactionResponse.data!!.first().requestId, signResult.raw, receiverIds.joinToString(","), RawTransactionType.TRANSFER, OutputState.unspent, nowInUtc(), if (release == true) null else utxoWrapper.inscriptionHash, transactionHash)) Timber.e("Kernel Transaction($trace): sign db mark utxo ${utxoWrapper.ids.joinToString(", ")}") tokenRepository.updateUtxoToSigned(utxoWrapper.ids) Timber.e("Kernel Transaction: sign end") @@ -561,11 +564,11 @@ class BottomSheetViewModel if (transactionRsp.error != null) { Timber.e("Kernel Transaction($traceId): innerTransaction error ${transactionRsp.errorDescription}") reportException(Throwable("Transaction Error ${transactionRsp.errorDescription}")) - tokenRepository.updateRawTransaction(transactionRsp.data!!.first().requestId, OutputState.signed.name) + tokenRepository.updateRawTransaction(transactionRsp.data!!.first().requestId, OutputState.spent.name) return transactionRsp } else { Timber.e("Kernel Transaction($traceId): innerTransaction update raw transaction") - tokenRepository.updateRawTransaction(transactionRsp.data!!.first().requestId, OutputState.signed.name) + tokenRepository.updateRawTransaction(transactionRsp.data!!.first().requestId, OutputState.spent.name) } if (receiverIds.size == 1 && !isConsolidation) { // Workaround with only the case of a single transfer diff --git a/app/src/main/java/one/mixin/android/ui/conversation/ConversationActivity.kt b/app/src/main/java/one/mixin/android/ui/conversation/ConversationActivity.kt index 04f707f240..5a4bc65d48 100644 --- a/app/src/main/java/one/mixin/android/ui/conversation/ConversationActivity.kt +++ b/app/src/main/java/one/mixin/android/ui/conversation/ConversationActivity.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.launch import one.mixin.android.R import one.mixin.android.extension.replaceFragment +import one.mixin.android.job.MixinJobManager import one.mixin.android.repository.ConversationRepository import one.mixin.android.repository.UserRepository import one.mixin.android.session.Session @@ -20,6 +21,7 @@ import one.mixin.android.ui.conversation.ConversationFragment.Companion.CONVERSA import one.mixin.android.ui.conversation.ConversationFragment.Companion.RECIPIENT import one.mixin.android.ui.conversation.ConversationFragment.Companion.RECIPIENT_ID import one.mixin.android.ui.home.MainActivity +import one.mixin.android.util.UserBatchProcessor import one.mixin.android.vo.TranscriptData import one.mixin.android.vo.User import javax.inject.Inject @@ -30,6 +32,7 @@ class ConversationActivity : BlazeBaseActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_chat) WindowCompat.setDecorFitsSystemWindows(window, false) + UserBatchProcessor.getInstance().init(jobManager) if (savedInstanceState == null) { if (intent.getBooleanExtra(ARGS_FAST_SHOW, false)) { replaceFragment( @@ -62,6 +65,9 @@ class ConversationActivity : BlazeBaseActivity() { @Inject lateinit var userRepository: UserRepository + @Inject + lateinit var jobManager: MixinJobManager + private fun showConversation(intent: Intent) { val bundle = intent.extras ?: return lifecycleScope.launch( diff --git a/app/src/main/java/one/mixin/android/util/UserBatchProcessor.kt b/app/src/main/java/one/mixin/android/util/UserBatchProcessor.kt new file mode 100644 index 0000000000..13b382b7f6 --- /dev/null +++ b/app/src/main/java/one/mixin/android/util/UserBatchProcessor.kt @@ -0,0 +1,89 @@ +package one.mixin.android.util + +import one.mixin.android.job.MixinJobManager +import one.mixin.android.job.UserBatchProcessorJob +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.TimeUnit + +class UserBatchProcessor private constructor() { + private val userSet = ConcurrentHashMap.newKeySet() + private lateinit var scheduler: ScheduledExecutorService + private var lastProcessTime = System.currentTimeMillis() + private lateinit var jobManager: MixinJobManager + + companion object { + private const val MAX_SIZE = 100 + private const val MAX_INTERVAL_MINUTES = 10L + + @Volatile + private var instance: UserBatchProcessor? = null + + fun getInstance(): UserBatchProcessor { + return instance ?: synchronized(this) { + instance ?: UserBatchProcessor().also { instance = it } + } + } + } + + @Volatile + private var isInitialized = false + + fun init(jobManager: MixinJobManager) { + if (!isInitialized) { + synchronized(this) { + if (!isInitialized) { + this.jobManager = jobManager + + if (!::scheduler.isInitialized) { + scheduler = Executors.newSingleThreadScheduledExecutor() + } + + scheduler.scheduleAtFixedRate({ + checkAndProcess() + }, 1, 10, TimeUnit.MINUTES) + + isInitialized = true + } + } + } + } + fun addUser(userId: String) { + userSet.add(userId) + if (userSet.size >= MAX_SIZE) { + processUsers() + } + } + + private fun checkAndProcess() { + val currentTime = System.currentTimeMillis() + if (currentTime - lastProcessTime >= TimeUnit.MINUTES.toMillis(MAX_INTERVAL_MINUTES)) { + processUsers() + } + } + + private fun processUsers() { + if (userSet.isEmpty) return + + synchronized(userSet) { + try { + jobManager.addJobInBackground(UserBatchProcessorJob(userSet.toList())) + userSet.clear() + lastProcessTime = System.currentTimeMillis() + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + + fun isInitialized(): Boolean = isInitialized + + fun shutdown() { + scheduler.shutdown() + userSet.clear() + instance = null + isInitialized = false + } +} \ No newline at end of file diff --git a/app/src/main/java/one/mixin/android/vo/UserFetchTime.kt b/app/src/main/java/one/mixin/android/vo/UserFetchTime.kt new file mode 100644 index 0000000000..023dcab770 --- /dev/null +++ b/app/src/main/java/one/mixin/android/vo/UserFetchTime.kt @@ -0,0 +1,16 @@ +package one.mixin.android.vo + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity( + tableName = "user_fetch_times", +) +class UserFetchTime( + @PrimaryKey + @ColumnInfo("user_id") + val userId: String, + @ColumnInfo("last_fetch_at") + val lastFetchAt: Long, +) \ No newline at end of file diff --git a/app/src/main/java/one/mixin/android/vo/safe/Output.kt b/app/src/main/java/one/mixin/android/vo/safe/Output.kt index a6e58e56f2..09fb943b96 100644 --- a/app/src/main/java/one/mixin/android/vo/safe/Output.kt +++ b/app/src/main/java/one/mixin/android/vo/safe/Output.kt @@ -78,5 +78,7 @@ data class Output( enum class OutputState { unspent, + spent, + @Deprecated("use spent") signed, } diff --git a/app/src/main/java/one/mixin/android/vo/safe/RawTransaction.kt b/app/src/main/java/one/mixin/android/vo/safe/RawTransaction.kt index 8410c2d80e..e6efb3551e 100644 --- a/app/src/main/java/one/mixin/android/vo/safe/RawTransaction.kt +++ b/app/src/main/java/one/mixin/android/vo/safe/RawTransaction.kt @@ -9,6 +9,7 @@ import androidx.room.PrimaryKey tableName = "raw_transactions", indices = [ Index(value = arrayOf("state", "type")), + Index(value = arrayOf("transaction_hash")), ], ) data class RawTransaction( @@ -27,6 +28,8 @@ data class RawTransaction( val createdAt: String, @ColumnInfo(name = "inscription_hash") val inscriptionHash: String?, + @ColumnInfo(name = "transaction_hash") + val transactionHash: String? ) fun formatDestination( diff --git a/app/src/main/java/one/mixin/android/widget/NameTextView.kt b/app/src/main/java/one/mixin/android/widget/NameTextView.kt index c5fe2caea3..5bbb7146b1 100644 --- a/app/src/main/java/one/mixin/android/widget/NameTextView.kt +++ b/app/src/main/java/one/mixin/android/widget/NameTextView.kt @@ -22,6 +22,7 @@ import one.mixin.android.extension.equalsIgnoreCase import one.mixin.android.extension.highLight import one.mixin.android.extension.highLightMao import one.mixin.android.extension.spToPx +import one.mixin.android.util.UserBatchProcessor import one.mixin.android.vo.Account import one.mixin.android.vo.CallUser import one.mixin.android.vo.ChatHistoryMessageItem @@ -387,6 +388,7 @@ class NameTextView : LinearLayoutCompat { fun setMessageName(message: MessageItem) { this.textView.text = message.userFullName + UserBatchProcessor.getInstance().addUser(message.userId) if (message.isProsperity()) { iconView.isVisible = true iconView.setImageDrawable( @@ -555,6 +557,9 @@ class NameTextView : LinearLayoutCompat { fun setName(conversationItem: ConversationItem) { this.textView.text = conversationItem.getConversationName() + if (!conversationItem.isGroupConversation()) { + UserBatchProcessor.getInstance().addUser(conversationItem.ownerId) + } if (conversationItem.isProsperity()) { iconView.isVisible = true iconView.setImageDrawable(