|
| 1 | +import { partition } from "lodash/fp"; |
| 2 | +import type { Vault } from "obsidian"; |
1 | 3 | import { STask, type DataviewApi } from "obsidian-dataview"; |
2 | 4 |
|
3 | 5 | import { |
4 | 6 | type Scheduler, |
5 | 7 | createBackgroundBatchScheduler, |
6 | 8 | } from "../util/scheduler"; |
| 9 | +import { isNotVoid } from "typed-assert"; |
| 10 | + |
| 11 | +interface STaskCacheEntry { |
| 12 | + mtime: number; |
| 13 | + tasks: STask[]; |
| 14 | +} |
7 | 15 |
|
8 | 16 | export class DataviewFacade { |
9 | 17 | private readonly scheduler: Scheduler<STask[]> = |
10 | 18 | createBackgroundBatchScheduler({ |
11 | 19 | timeRemainingLowerLimit: 5, |
12 | 20 | }); |
| 21 | + private readonly taskCache = new Map<string, STaskCacheEntry>(); |
| 22 | + |
| 23 | + constructor( |
| 24 | + private readonly getDataview: () => DataviewApi | undefined, |
| 25 | + private readonly vault: Vault, |
| 26 | + ) {} |
| 27 | + |
| 28 | + private isCached = (path: string) => { |
| 29 | + const cacheForPath = this.taskCache.get(path); |
| 30 | + |
| 31 | + if (!cacheForPath) { |
| 32 | + return false; |
| 33 | + } |
13 | 34 |
|
14 | | - constructor(private readonly getDataview: () => DataviewApi | undefined) {} |
| 35 | + const fileInVault = this.vault.getFileByPath(path); |
| 36 | + |
| 37 | + isNotVoid(fileInVault); |
| 38 | + |
| 39 | + return cacheForPath.mtime === fileInVault.stat.mtime; |
| 40 | + }; |
15 | 41 |
|
16 | 42 | getAllTasksFrom = async (source: string) => { |
17 | | - return new Promise<STask[]>((resolve) => { |
18 | | - const paths: string[] = this.getDataview()?.pagePaths(source).array(); |
| 43 | + const pathsForSource: string[] = this.getDataview() |
| 44 | + ?.pagePaths(source) |
| 45 | + .array(); |
19 | 46 |
|
20 | | - const pageQueries: Array<() => STask[]> = paths.map( |
21 | | - (path) => () => |
22 | | - this.getDataview()?.page(path)?.file.tasks.array() || [], |
23 | | - ); |
| 47 | + const [pathsWithValidCache, pathsToBeQueried] = partition( |
| 48 | + this.isCached, |
| 49 | + pathsForSource, |
| 50 | + ); |
24 | 51 |
|
| 52 | + const cachedTasks = pathsWithValidCache.map( |
| 53 | + (it) => this.taskCache.get(it)?.tasks || [], |
| 54 | + ); |
| 55 | + |
| 56 | + const pageQueries: Array<() => STask[]> = pathsToBeQueried.map( |
| 57 | + (path) => () => { |
| 58 | + const tasks = this.getDataview()?.page(path)?.file.tasks.array() || []; |
| 59 | + const mtime = this.vault.getFileByPath(path)?.stat.mtime; |
| 60 | + |
| 61 | + if (mtime && tasks.length > 0) { |
| 62 | + this.taskCache.set(path, { mtime, tasks }); |
| 63 | + } |
| 64 | + |
| 65 | + return tasks; |
| 66 | + }, |
| 67 | + ); |
| 68 | + |
| 69 | + return new Promise<STask[]>((resolve) => { |
25 | 70 | this.scheduler.enqueueTasks(pageQueries, (results) => { |
26 | | - resolve(results.flat()); |
| 71 | + resolve(results.concat(cachedTasks).flat()); |
27 | 72 | }); |
28 | 73 | }); |
29 | 74 | }; |
30 | 75 |
|
31 | | - getPathsFrom = (source: string) => { |
32 | | - return this.getDataview()?.pages(source).file.path.array() || []; |
33 | | - }; |
34 | | - |
35 | 76 | getAllListsFrom = (source: string) => { |
36 | 77 | return this.getDataview()?.pages(source).file.lists.array() || []; |
37 | 78 | }; |
|
0 commit comments