Skip to content

Commit

Permalink
fix(db): remove remaining data if unfollow feed
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Aug 15, 2024
1 parent 687e039 commit 1edf560
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 9 deletions.
10 changes: 10 additions & 0 deletions setup-file.ts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
// @ts-nocheck
import "fake-indexeddb/auto"

import { enableMapSet } from "immer"

globalThis.window = {
location: new URL("https://example.com"),
__dbIsReady: true,

}
enableMapSet()
234 changes: 234 additions & 0 deletions src/renderer/src/services/__mock__data__/entries.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
[
{
"read": true,
"view": 0,
"entries": {
"id": "46877798792098816",
"title": "DWMBlurGlass – 为 Windows 10/11 启用窗口透明/玻璃/模糊效果",
"url": "https://www.appinn.com/dwmblurglass/",
"description": "DWMBlurGlass 是一款为 Win10、Win11 全局系统标题栏添加自定义效果的开源工具,主要有模糊、混合颜色、文本颜色、Aero 效果等。@Appinn 来自发现频道,@suntrise 同学的推荐:https://meta.appinn.net/t/topic/59864\n\nDWMBlurGlass:为 Windows 10/11 启用窗口透明/玻璃/模糊效果\n\n今年,又有一款能让窗口标题栏拥有透明效果的应用 DWMBlurGlass 出现,不仅支持 Win10 2004+ 和 Win11,而且还是免费开源的。…",
"guid": "https://www.appinn.com/?p=48489",
"author": "青小蛙",
"authorUrl": null,
"authorAvatar": null,
"insertedAt": "2024-08-15T11:59:12.267Z",
"publishedAt": "2024-08-15T11:34:12.839Z",
"media": [
{
"url": "https://www.appinn.com/wp-content/uploads/2024/08/Appinn-feature-images-2024-08-15T185350.869.jpg",
"type": "photo",
"width": 1608,
"height": 700
},
{
"url": "https://www.appinn.com/wp-content/uploads/2024/08/001701-1.avif",
"type": "photo"
},
{
"url": "https://www.appinn.com/wp-content/uploads/2024/08/013521.avif",
"type": "photo"
},
{
"url": "https://www.appinn.com/wp-content/uploads/2024/08/e3c13f90a0c5d7ca478d7.avif",
"type": "photo"
}
],
"categories": [
"Windows",
"美化主题",
"模糊",
"玻璃",
"透明"
],
"attachments": null
},
"feeds": {
"id": "41370691926515712",
"url": "https://www.appinn.com/feed/",
"title": "小众软件",
"description": "分享免费、小巧、实用、有趣、绿色的软件",
"siteUrl": "https://www.appinn.com/",
"image": null,
"checkedAt": "2024-08-15T11:59:12.267Z",
"lastModifiedHeader": "Thu, 15 Aug 2024 11:34:18 GMT",
"etagHeader": "W/\"74dc42ccaecdc9834948c29b13261d87\"",
"ttl": 30,
"errorMessage": null,
"errorAt": null,
"ownerUserId": null
},
"collections": null,
"settings": {}
},
{
"read": true,
"view": 0,
"entries": {
"id": "46871301655897088",
"title": "开放麒麟 openKylin 新增 LTS 长期支持版,采用“创新版本 + LTS 版本”双轨并行策略",
"url": "https://www.ithome.com/0/788/779.htm",
"description": "IT 之家 8 月 15 日消息,开放原子开源基金会上周刚刚发布了最新的 openKylin 2.0 版本!该版本汇聚了超过 6500 + 开发者的智慧与汗水,并得到了 110+ SIG 和 520 + 企业的鼎力支持。经过社区投票决议,openKylin 今天宣布将推出长期支持版本(LTS),未来,社区将采用“创新版本 + LTS 版本”双轨并行策略:\n\n创新版本:每年发布 1 个版本,提供 1 年被动更新支持\n\nLTS 版本:每 3 年发布 1 个版本,提供 1 年主动更新支持 + 1 年被动更新支持\n\nopenKylin 介绍称,LTS…",
"guid": "https://www.ithome.com/0/788/779.htm",
"author": null,
"authorUrl": null,
"authorAvatar": null,
"insertedAt": "2024-08-15T11:33:04.823Z",
"publishedAt": "2024-08-15T11:11:47.914Z",
"media": [
{
"url": "https://img.ithome.com/newsuploadfiles/2024/8/1145ab09-45b1-4af4-a6e4-7bbec2548cfe.png?x-bce-process=image/format,f_auto",
"type": "photo",
"width": 1080,
"height": 448
}
],
"categories": null,
"attachments": null
},
"feeds": {
"id": "41397633064960000",
"url": "https://www.ithome.com/rss/",
"title": "IT 之家",
"description": "IT 之家 - 软媒旗下网站",
"siteUrl": "https://www.ithome.com/",
"image": null,
"checkedAt": "2024-08-15T11:33:04.823Z",
"lastModifiedHeader": null,
"etagHeader": null,
"ttl": 30,
"errorMessage": null,
"errorAt": null,
"ownerUserId": null
},
"collections": null,
"settings": {}
},
{
"read": true,
"view": 0,
"entries": {
"id": "46871301655897089",
"title": "微星海外推出 2024 款 Pro DP21 系列迷你主机:升级 14 代酷睿处理器、自带“古老”COM 串口",
"url": "https://www.ithome.com/0/788/778.htm",
"description": "IT 之家 8 月 15 日消息,据微星官网,微星今天在海外推出 2024 款 Pro DP21 系列迷你主机,该迷你主机主要升级 14 代酷睿处理器,适用于商务应用场景,截至 IT 之家发稿,官网还未显示具体售价信息。外观方面,这款迷你主机尺寸为 204 x 208 x 54.8mm,重 1.52 千克,整体有点类似 CD 光驱,正面采用格栅式设计,侧面和顶部配备进气孔,支持通过 VESA 支架壁挂。\n\n规格方面,该机基于英特尔 Q670 主板,可选 20 核心 28 线程酷睿 i7-14700 或 14 核心 20 线程酷睿 i5-14500 处理器,至高可选…",
"guid": "https://www.ithome.com/0/788/778.htm",
"author": null,
"authorUrl": null,
"authorAvatar": null,
"insertedAt": "2024-08-15T11:33:04.823Z",
"publishedAt": "2024-08-15T11:06:25.894Z",
"media": [
{
"url": "https://img.ithome.com/newsuploadfiles/2024/8/dc1110c9-483a-4b6d-84cc-b229ec92a7b4.png",
"type": "photo",
"width": 1440,
"height": 668
},
{
"url": "https://img.ithome.com/newsuploadfiles/2024/8/df476b81-144a-4fbd-b0bb-6d81c9734b76.png",
"type": "photo",
"width": 1210,
"height": 862
},
{
"url": "https://img.ithome.com/newsuploadfiles/2024/8/568aaf73-5501-4562-9f11-ab77d654c733.png",
"type": "photo",
"width": 1440,
"height": 611
},
{
"url": "https://img.ithome.com/newsuploadfiles/2024/8/6120d871-2337-42d3-acb9-f8694362f63a.png",
"type": "photo",
"width": 1440,
"height": 575
},
{
"url": "https://img.ithome.com/newsuploadfiles/2024/8/e0dffc94-9746-4fc8-bbde-175a13af4115.png",
"type": "photo",
"width": 1440,
"height": 866
}
],
"categories": null,
"attachments": null
},
"feeds": {
"id": "41397633064960000",
"url": "https://www.ithome.com/rss/",
"title": "IT 之家",
"description": "IT 之家 - 软媒旗下网站",
"siteUrl": "https://www.ithome.com/",
"image": null,
"checkedAt": "2024-08-15T11:33:04.823Z",
"lastModifiedHeader": null,
"etagHeader": null,
"ttl": 30,
"errorMessage": null,
"errorAt": null,
"ownerUserId": null
},
"collections": null,
"settings": {}
},
{
"read": true,
"view": 0,
"entries": {
"id": "46871301655897090",
"title": "半年低至 88 元:百度网盘 SVIP 官方预售 0 点开始",
"url": "https://www.ithome.com/0/788/777.htm",
"description": "百度网盘超级会员年卡官方售价 298 元,今日半年卡预告将在 8 月 16 日 0 点开启 88 元预售狂促。约合 14.66 元 / 月、176 元 / 年好价:\n\n天猫百度网盘 超级会员 半年卡填登录手机号 16 日 0 点 88 元直达链接\n\n注:现购买权益时长 + 已有权益时长,不能超过 5 年,否则会充值失败。\n\n百度网盘 SVIP 特权:\n\n天猫百度网盘 超级会员 半年卡填登录手机号 16 日 0 点 88 元直达链接",
"guid": "https://www.ithome.com/0/788/777.htm",
"author": null,
"authorUrl": null,
"authorAvatar": null,
"insertedAt": "2024-08-15T11:33:04.823Z",
"publishedAt": "2024-08-15T11:04:27.697Z",
"media": [
{
"url": "https://img.alicdn.com/bao/uploaded/i4/2201501708471/O1CN01JbgDBP2CRm3TqFHQs_!!0-item_pic.jpg",
"type": "photo",
"width": 800,
"height": 800
},
{
"url": "https://img.alicdn.com/imgextra/i4/2201501708471/O1CN01rpvXMz2CRltEbTc4P_!!2201501708471.jpg",
"type": "photo",
"width": 1500,
"height": 2322
},
{
"url": "https://img.alicdn.com/imgextra/i4/2201501708471/O1CN01W0kow62CRlt2y0KYf_!!2201501708471.jpg",
"type": "photo",
"width": 1500,
"height": 762
},
{
"url": "https://img.alicdn.com/bao/uploaded/i4/2201501708471/O1CN01JbgDBP2CRm3TqFHQs_!!0-item_pic.jpg",
"type": "photo",
"width": 800,
"height": 800
}
],
"categories": null,
"attachments": null
},
"feeds": {
"id": "41397633064960000",
"url": "https://www.ithome.com/rss/",
"title": "IT 之家",
"description": "IT 之家 - 软媒旗下网站",
"siteUrl": "https://www.ithome.com/",
"image": null,
"checkedAt": "2024-08-15T11:33:04.823Z",
"lastModifiedHeader": null,
"etagHeader": null,
"ttl": 30,
"errorMessage": null,
"errorAt": null,
"ownerUserId": null
},
"collections": null,
"settings": {}
}
]
6 changes: 4 additions & 2 deletions src/renderer/src/services/entry-related.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ class ServiceStatic {
return task
}

async deleteItem(type: EntryRelatedKey, key: string) {
async deleteItems(type: EntryRelatedKey, keys: string[]) {
const oldData = await this.findAll(type as any)
delete oldData[key]
keys.forEach((key) => {
delete oldData[key]
})

return entryRelatedModel.put({
data: oldData,
Expand Down
71 changes: 71 additions & 0 deletions src/renderer/src/services/entry.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { browserDB } from "@renderer/database"
import { sleep } from "@renderer/lib/utils"
import { entryActions } from "@renderer/store/entry"
import { beforeAll, beforeEach, describe, expect, test } from "vitest"

import mockEntiresData from "./__mock__data__/entries.json"
import { EntryService } from "./entry"
import { EntryRelatedKey, EntryRelatedService } from "./entry-related"

const deleteIds = ["46871301655897088", "46871301655897090"]

describe.concurrent("Entry Service", () => {
beforeAll(async () => {
await browserDB.delete()
})
beforeEach(async () => {
await browserDB.open()
entryActions.upsertMany(mockEntiresData as any[])
await sleep(1)
})

test.sequential("assert data is ready", async () => {
const data = await EntryService.findAll()
const ids = data.map((d) => d.id)
expect(ids).toMatchInlineSnapshot(`
[
"46871301655897088",
"46871301655897089",
"46871301655897090",
"46877798792098816",
]
`)
const readMap = await EntryRelatedService.findAll(EntryRelatedKey.READ)
expect(readMap).toMatchInlineSnapshot(`
{
"46871301655897088": true,
"46871301655897089": true,
"46871301655897090": true,
"46877798792098816": true,
}
`)
})
test.sequential("delete entry", async () => {
await EntryService.deleteEntries(deleteIds)
const readMap = await EntryRelatedService.findAll(EntryRelatedKey.READ)
expect(readMap).toMatchInlineSnapshot(`
{
"46871301655897089": true,
"46877798792098816": true,
}
`)
const ret = await EntryService.findAll()
expect(ret.map((d) => d.id)).not.toContain(deleteIds)
})

test.sequential("delete by feed id ", async () => {
await EntryService.deleteEntriesByFeedIds(["41397633064960000"])
const ret = await EntryService.findAll()
expect(ret.map((d) => d.id)).toMatchInlineSnapshot(`
[
"46877798792098816",
]
`)
const readMap = await EntryRelatedService.findAll(EntryRelatedKey.READ)
expect(readMap).toMatchInlineSnapshot(`
{
"46877798792098816": true,
}
`)
})
})
23 changes: 20 additions & 3 deletions src/renderer/src/services/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,32 @@ class EntryServiceStatic extends BaseService<EntryModel> {
}

async deleteCollection(entryId: string) {
return EntryRelatedService.deleteItem(EntryRelatedKey.COLLECTION, entryId)
return EntryRelatedService.deleteItems(EntryRelatedKey.COLLECTION, [
entryId,
])
}

async deleteEntries(entryIds: string[]) {
await this.table.bulkDelete(entryIds)
await Promise.all([
this.table.bulkDelete(entryIds),
EntryRelatedService.deleteItems(EntryRelatedKey.READ, entryIds),
EntryRelatedService.deleteItems(EntryRelatedKey.COLLECTION, entryIds),
])
}

async deleteEntriesByFeedIds(feedIds: string[]) {
await this.table.where("feedId").anyOf(feedIds).delete()
const deleteEntryIds = await this.table
.where("feedId")
.anyOf(feedIds)
.primaryKeys()
await Promise.all([
this.table.where("feedId").anyOf(feedIds).delete(),
EntryRelatedService.deleteItems(EntryRelatedKey.READ, deleteEntryIds),
EntryRelatedService.deleteItems(
EntryRelatedKey.COLLECTION,
deleteEntryIds,
),
])
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/renderer/src/store/entry/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import type {
FeedModel,
UserModel,
} from "@renderer/models"
import {
EntryService,
} from "@renderer/services"
import { EntryService } from "@renderer/services"
import { produce } from "immer"
import { isNil, merge, omit } from "lodash-es"
import type { EntryReadHistoriesModel } from "src/hono"
Expand Down Expand Up @@ -144,6 +142,8 @@ class EntryActions {

const changedReadStatusMap = {} as Record<string, boolean>

// TODO collection patch in db

set((state) =>
produce(state, (draft) => {
const ids = draft.entries[feedId]
Expand Down Expand Up @@ -235,7 +235,9 @@ class EntryActions {
// Push entry
entries.push(mergedEntry)
// Push entry2Read
entry2Read[item.entries.id] = item.read || false
if (!isNil(item.read)) {
entry2Read[item.entries.id] = item.read
}
// Push entryFeedMap
entryFeedMap[item.entries.id] = item.feeds.id
// Push entryCollection
Expand Down
Loading

0 comments on commit 1edf560

Please sign in to comment.