forked from sheepzh/time-tracker-4-browser
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathperiod-database.ts
More file actions
110 lines (95 loc) · 3.46 KB
/
period-database.ts
File metadata and controls
110 lines (95 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
* Copyright (c) 2021 Hengyang Zhang
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
import { getDateString, keyOf } from "@util/period"
import BaseDatabase from "./common/base-database"
import { REMAIN_WORD_PREFIX } from "./common/constant"
/**
* order => milliseconds of focus
*/
type DailyResult = Record<string, number>
const KEY_PREFIX = REMAIN_WORD_PREFIX + 'PERIOD'
const KEY_PREFIX_LENGTH = KEY_PREFIX.length
const generateKey = (date: string) => KEY_PREFIX + date
function merge(exists: { [dateKey: string]: DailyResult }, toMerge: timer.period.Result[]) {
toMerge.forEach(period => {
const { order, milliseconds } = period
const key = generateKey(getDateString(period))
const exist = exists[key] || {}
const previous = exist[order] || 0
exist[order] = previous + milliseconds
exists[key] = exist
})
}
function db2PeriodInfos(data: { [dateKey: string]: DailyResult }): timer.period.Result[] {
const result: timer.period.Result[] = []
Object.entries(data).forEach((([dateKey, val]) => {
const dateStr = dateKey.substring(KEY_PREFIX_LENGTH)
const date = new Date(
Number.parseInt(dateStr.substring(0, 4)),
Number.parseInt(dateStr.substring(4, 6)) - 1,
Number.parseInt(dateStr.substring(6, 8))
)
Object
.entries(val)
.forEach(([order, milliseconds]) => result.push({
...keyOf(date, Number.parseInt(order)),
milliseconds
}))
}))
return result
}
/**
* @since v0.2.1
* @deprecated
* Starting with v4, all timeline data will be stored in IndexedDB, and periodic results will be queried using the timeline database.
* Therefore, this will be removed one year after the release of version 4 (around 2027-04-01)
*/
class PeriodDatabase extends BaseDatabase {
async get(date: string): Promise<DailyResult> {
const key = generateKey(date)
const result = await this.storage.getOne<DailyResult>(key)
return result || {}
}
async accumulate(items: timer.period.Result[]): Promise<void> {
const dates = Array.from(new Set(items.map(getDateString)))
const exists = await this.getBatch0(dates)
merge(exists, items)
await this.updateBatch(exists)
}
private updateBatch(data: { [dateKey: string]: DailyResult }): Promise<void> {
return this.storage.set(data)
}
/**
* Used by self
*/
private getBatch0(dates: string[]): Promise<{ [dateKey: string]: DailyResult }> {
const keys = dates.map(generateKey)
return this.storage.get(keys)
}
async getBatch(dates: string[]): Promise<timer.period.Result[]> {
const data = await this.getBatch0(dates)
return db2PeriodInfos(data)
}
/**
* @since 1.0.0
* @returns all period items
*/
async getAll(): Promise<timer.period.Result[]> {
const allItems = await this.storage.get()
const periodItems: { [dateKey: string]: DailyResult } = {}
Object.entries(allItems)
.filter(([key]) => key.startsWith(KEY_PREFIX))
.forEach(([key, val]) => periodItems[key] = val)
return db2PeriodInfos(periodItems)
}
async batchDelete(dates: string[]) {
const keys = dates.map(generateKey)
await this.storage.remove(keys)
}
}
const periodDatabase = new PeriodDatabase()
export default periodDatabase