• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alovajs / alova / #210

08 Oct 2024 07:26AM CUT coverage: 93.734% (-0.09%) from 93.826%
#210

push

github

web-flow
Merge pull request #554 from alovajs/changeset-release/main

ci: release

1608 of 1761 branches covered (91.31%)

Branch coverage included in aggregate %.

9537 of 10129 relevant lines covered (94.16%)

60.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.36
/packages/alova/src/functions/manipulateCache.ts
1
import { usingL1CacheAdapters, usingL2CacheAdapters } from '@/alova';
1✔
2
import { globalConfigMap } from '@/globalConfig';
1✔
3
import {
1✔
4
  clearWithCacheAdapter,
1✔
5
  getWithCacheAdapter,
1✔
6
  hitTargetCacheWithCacheAdapter,
1✔
7
  removeWithCacheAdapter,
1✔
8
  setWithCacheAdapter
1✔
9
} from '@/storage/cacheWrapper';
1✔
10
import {
1✔
11
  getConfig,
1✔
12
  getContext,
1✔
13
  getLocalCacheConfigParam,
1✔
14
  getMethodInternalKey,
1✔
15
  getTime,
1✔
16
  isFn
1✔
17
} from '@alova/shared/function';
1✔
18
import { MEMORY, PromiseCls, STORAGE_RESTORE, isArray, len, mapItem, undefinedValue } from '@alova/shared/vars';
1✔
19
import { AlovaGenerics, CacheController, CacheQueryOptions, CacheSetOptions, Method } from '~/typings';
1✔
20

1✔
21
/*
1✔
22
 * 以下三个函数中的matcher为Method实例匹配器,它分为3种情况:
1✔
23
 * 1. 如果matcher为Method实例,则清空该Method实例缓存
1✔
24
 * 2. 如果matcher为字符串或正则,则清空所有符合条件的Method实例缓存
1✔
25
 * 3. 如果未传入matcher,则会清空所有缓存
1✔
26
 */
1✔
27

1✔
28
/**
1✔
29
 * 查询缓存
1✔
30
 * @param matcher Method实例匹配器
1✔
31
 * @returns 缓存数据,未查到时返回undefined
1✔
32
 */
1✔
33
export const queryCache = async <Responded>(
1✔
34
  matcher: Method<AlovaGenerics<Responded>>,
48✔
35
  { policy = 'all' }: CacheQueryOptions = {}
48✔
36
) => {
48✔
37
  // if key exists, that means it's a method instance.
48✔
38
  if (matcher && matcher.key) {
48✔
39
    const { id, l1Cache, l2Cache } = getContext(matcher);
48✔
40
    const methodKey = getMethodInternalKey(matcher);
48✔
41
    const { f: cacheFor, c: controlled, s: store, e: expireMilliseconds, t: tag } = getLocalCacheConfigParam(matcher);
48✔
42
    // if it's controlled cache, it will return the result of cacheFor function.
48✔
43
    if (controlled) {
48✔
44
      return (cacheFor as CacheController<Responded>)();
1✔
45
    }
1✔
46

47✔
47
    let cachedData: Responded | undefined =
47✔
48
      policy !== 'l2' ? await getWithCacheAdapter(id, methodKey, l1Cache) : undefinedValue;
48✔
49
    if (policy === 'l2') {
48✔
50
      cachedData = await getWithCacheAdapter(id, methodKey, l2Cache, tag);
6✔
51
    } else if (policy === 'all' && !cachedData) {
48✔
52
      if (store && expireMilliseconds(STORAGE_RESTORE) > getTime()) {
10!
53
        cachedData = await getWithCacheAdapter(id, methodKey, l2Cache, tag);
×
54
      }
×
55
    }
10✔
56
    return cachedData;
47✔
57
  }
47✔
58
};
48✔
59

1✔
60
/**
1✔
61
 * 手动设置缓存响应数据,如果对应的methodInstance设置了持久化存储,则还会去检出持久化存储中的缓存
1✔
62
 * @param matcher Method实例匹配器
1✔
63
 * @param data 缓存数据
1✔
64
 */
1✔
65
export const setCache = async <Responded>(
1✔
66
  matcher: Method<AlovaGenerics<Responded>> | Method<AlovaGenerics<Responded>>[],
8✔
67
  dataOrUpdater: Responded | ((oldCache?: Responded) => Responded | undefined | void),
8✔
68
  { policy = 'all' }: CacheSetOptions = {}
8✔
69
) => {
8✔
70
  const methodInstances = isArray(matcher) ? matcher : [matcher];
8✔
71
  const batchPromises = methodInstances.map(async methodInstance => {
8✔
72
    const { hitSource } = methodInstance;
10✔
73
    const { id, l1Cache, l2Cache } = getContext(methodInstance);
10✔
74
    const methodKey = getMethodInternalKey(methodInstance);
10✔
75
    const { e: expireMilliseconds, s: toStore, t: tag, c: controlled } = getLocalCacheConfigParam(methodInstance);
10✔
76
    // don't set cache when it's controlled cache.
10✔
77
    if (controlled) {
10✔
78
      return;
1✔
79
    }
1✔
80
    let data: any = dataOrUpdater;
9✔
81
    if (isFn(dataOrUpdater)) {
10✔
82
      let cachedData = policy !== 'l2' ? await getWithCacheAdapter(id, methodKey, l1Cache) : undefinedValue;
5!
83
      if (
5✔
84
        policy === 'l2' ||
5✔
85
        (policy === 'all' && !cachedData && toStore && expireMilliseconds(STORAGE_RESTORE) > getTime())
5!
86
      ) {
5!
87
        cachedData = await getWithCacheAdapter(id, methodKey, l2Cache, tag);
×
88
      }
×
89
      data = dataOrUpdater(cachedData);
5✔
90
      if (data === undefinedValue) {
5✔
91
        return;
2✔
92
      }
2✔
93
    }
5✔
94
    return PromiseCls.all([
7✔
95
      policy !== 'l2' && setWithCacheAdapter(id, methodKey, data, expireMilliseconds(MEMORY), l1Cache, hitSource),
10✔
96
      policy === 'l2' || (policy === 'all' && toStore)
10✔
97
        ? setWithCacheAdapter(id, methodKey, data, expireMilliseconds(STORAGE_RESTORE), l2Cache, hitSource, tag)
10✔
98
        : undefinedValue
10✔
99
    ]);
10✔
100
  });
8✔
101
  return PromiseCls.all(batchPromises);
8✔
102
};
8✔
103

1✔
104
/**
1✔
105
 * 失效缓存
1✔
106
 * @param matcher Method实例匹配器
1✔
107
 */
1✔
108
export const invalidateCache = async (matcher?: Method | Method[]) => {
1✔
109
  if (!matcher) {
7✔
110
    await PromiseCls.all([clearWithCacheAdapter(usingL1CacheAdapters), clearWithCacheAdapter(usingL2CacheAdapters)]);
3✔
111
    return;
3✔
112
  }
3✔
113
  const methodInstances = isArray(matcher) ? matcher : [matcher];
7✔
114
  const batchPromises = methodInstances.map(methodInstance => {
7✔
115
    const { id, l1Cache, l2Cache } = getContext(methodInstance);
7✔
116
    const { c: controlled } = getLocalCacheConfigParam(methodInstance);
7✔
117
    // don't invalidate cache when it's controlled cache.
7✔
118
    if (controlled) {
7✔
119
      return;
1✔
120
    }
1✔
121
    const methodKey = getMethodInternalKey(methodInstance);
6✔
122
    return PromiseCls.all([
6✔
123
      removeWithCacheAdapter(id, methodKey, l1Cache),
6✔
124
      removeWithCacheAdapter(id, methodKey, l2Cache)
6✔
125
    ]);
6✔
126
  });
7✔
127
  await PromiseCls.all(batchPromises);
7✔
128
};
4✔
129

1✔
130
/**
1✔
131
 * hit(invalidate) target caches by source method
1✔
132
 * this is the implementation of auto invalidate cache
1✔
133
 * @param sourceMethod source method instance
1✔
134
 */
1✔
135
export const hitCacheBySource = async <AG extends AlovaGenerics>(sourceMethod: Method<AG>) => {
1✔
136
  // 查找hit target cache,让它的缓存失效
42✔
137
  // 通过全局配置`autoHitCache`来控制自动缓存失效范围
42✔
138
  const { autoHitCache } = globalConfigMap;
42✔
139
  const { l1Cache, l2Cache } = getContext(sourceMethod);
42✔
140
  const sourceKey = getMethodInternalKey(sourceMethod);
42✔
141
  const { name: sourceName } = getConfig(sourceMethod);
42✔
142
  const cacheAdaptersInvolved = {
42✔
143
    global: [...usingL1CacheAdapters, ...usingL2CacheAdapters],
42✔
144
    self: [l1Cache, l2Cache],
42✔
145
    close: []
42✔
146
  }[autoHitCache];
42✔
147
  if (cacheAdaptersInvolved && len(cacheAdaptersInvolved)) {
42✔
148
    await PromiseCls.all(
42✔
149
      mapItem(cacheAdaptersInvolved, involvedCacheAdapter =>
42✔
150
        hitTargetCacheWithCacheAdapter(sourceKey, sourceName, involvedCacheAdapter)
744✔
151
      )
42✔
152
    );
42✔
153
  }
42✔
154
};
42✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc