@raclettejs/core 0.1.36 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +32 -7
  2. package/dist/cli.js +1 -1
  3. package/dist/cli.js.map +2 -2
  4. package/package.json +2 -2
  5. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.schema.ts +10 -4
  6. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/interactionLink.schema.ts +4 -1
  7. package/services/backend/src/shared/schemas/core/CompositionCreate.schema.ts +4 -0
  8. package/services/backend/src/shared/schemas/core/InteractionLinkCreate.schema.ts +4 -0
  9. package/services/backend/src/shared/types/core/CompositionCreate.types.ts +1 -0
  10. package/services/backend/src/shared/types/core/InteractionLinkCreate.types.ts +1 -0
  11. package/services/frontend/src/core/lib/scheduleTask.ts +35 -0
  12. package/services/frontend/src/core/store/index.ts +5 -1
  13. package/services/frontend/src/core/store/reducers/compositionSlots/reducers.ts +1 -5
  14. package/services/frontend/src/core/store/reducers/data/reducers.ts +101 -65
  15. package/services/frontend/src/core/store/reducers/metaReducer.ts +23 -0
  16. package/services/frontend/src/core/store/reducers/notifications/reducers.ts +39 -47
  17. package/services/frontend/src/core/store/reducers/queries/effects.ts +55 -2
  18. package/services/frontend/src/core/store/reducers/queries/reducers.ts +60 -62
  19. package/services/frontend/src/core/store/reducers/queriesCache/effects.ts +105 -0
  20. package/services/frontend/src/core/store/reducers/queriesCache/index.ts +2 -1
  21. package/services/frontend/src/core/store/reducers/queriesCache/queryCacheHelper.ts +79 -9
  22. package/services/frontend/src/core/store/reducers/queriesCache/reducers.ts +95 -100
  23. package/services/frontend/src/orchestrator/components/CompositionLoadingState.vue +28 -0
  24. package/services/frontend/src/orchestrator/components/composition/CompositionOverlay.vue +5 -7
  25. package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +171 -39
  26. package/services/frontend/src/orchestrator/components/dataTable/BaseDataTable.vue +336 -56
  27. package/services/frontend/src/orchestrator/components/dataTable/BaseDataTableConfirmDeleteBtn.vue +27 -0
  28. package/services/frontend/src/orchestrator/components/dataTable/BaseDataTableFilterDrawerShell.vue +72 -0
  29. package/services/frontend/src/orchestrator/components/index.ts +4 -0
  30. package/services/frontend/src/orchestrator/composables/index.ts +1 -0
  31. package/services/frontend/src/orchestrator/composables/useBaseDataTableDeleteConfirm.ts +23 -0
  32. package/services/frontend/src/orchestrator/composables/useVueWriteOperationHelper.ts +16 -4
  33. package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +53 -23
  34. package/services/frontend/src/orchestrator/constants/widgetSlotType.ts +4 -0
  35. package/services/frontend/src/orchestrator/i18n/de-DE.json +7 -1
  36. package/services/frontend/src/orchestrator/i18n/en-EU.json +7 -1
  37. package/services/frontend/src/orchestrator/i18n/sk.json +7 -1
  38. package/services/frontend/src/orchestrator/router/routerHooks/afterEach.ts +15 -9
  39. package/services/frontend/src/orchestrator/types/DataApi.ts +2 -1
@@ -3,9 +3,9 @@
3
3
  */
4
4
 
5
5
  import { fixQueryParamTypes } from "@racletteCore/lib/dataHelper"
6
- import { difference, mergeDeepRight, filter } from "ramda"
6
+ import { difference, mergeDeepRight } from "ramda"
7
7
  import type { CustomStoreActionParams } from "@racletteCore/types"
8
- import { $eventbus, $store } from "@racletteCore/main"
8
+
9
9
  export type Query = {
10
10
  target: string
11
11
  actionId: string
@@ -22,8 +22,7 @@ const updateQueryItems = (state, action) => {
22
22
  if (!actionId || !state[actionId]) {
23
23
  return state
24
24
  }
25
- const queries = structuredClone(state)
26
- const query = queries[actionId]
25
+ const query = { ...state[actionId] }
27
26
  if (items) {
28
27
  const uuids = Object.values(items).map((item) => item._id)
29
28
  let dataItemsToRemove = []
@@ -35,15 +34,14 @@ const updateQueryItems = (state, action) => {
35
34
  query.loading = false
36
35
  query.uuids = uuids
37
36
  if (dataItemsToRemove.length > 0) {
38
- $store.dispatch({
39
- type: "data/deleteFromCache",
40
- payload: { uuids: dataItemsToRemove },
41
- actionId: actionId,
42
- })
37
+ action.actionResult.dataCacheCleanup = {
38
+ actionId,
39
+ uuids: dataItemsToRemove,
40
+ }
43
41
  }
44
42
  }
45
43
 
46
- return queries
44
+ return { ...state, [actionId]: query }
47
45
  }
48
46
 
49
47
  const updateQuery = (state, action) => {
@@ -53,8 +51,7 @@ const updateQuery = (state, action) => {
53
51
  return state
54
52
  }
55
53
 
56
- let queries = structuredClone(state)
57
- const query = queries[actionId]
54
+ const query = { ...state[actionId] }
58
55
  if (payload.target) {
59
56
  query.target = payload.target
60
57
  }
@@ -106,20 +103,19 @@ const updateQuery = (state, action) => {
106
103
  query.backend = fixQueryParamTypes(query.backend)
107
104
  }
108
105
 
109
- return queries
106
+ return { ...state, [actionId]: query }
110
107
  }
111
108
  const queryiesSetCacheKey = (state, action) => {
112
- let queries = structuredClone(state)
113
109
  const payload = action.payload
114
110
  const { actionId, cacheKey } = payload
115
111
  if (!actionId || !state[actionId]) {
116
112
  return state
117
113
  }
118
114
 
119
- queries[actionId] = { ...queries[actionId], cacheKey }
115
+ const updatedQuery = { ...state[actionId], cacheKey }
120
116
  action.actionResult.updated.itemBefore = state[actionId]
121
- action.actionResult.updated.item = queries[actionId]
122
- return queries
117
+ action.actionResult.updated.item = updatedQuery
118
+ return { ...state, [actionId]: updatedQuery }
123
119
  }
124
120
  const queriesUpdateLoading = (state, action) => {
125
121
  const payload = action.payload
@@ -127,12 +123,13 @@ const queriesUpdateLoading = (state, action) => {
127
123
  if (!actionId || !state[actionId]) {
128
124
  return state
129
125
  }
130
- const queries = structuredClone(state)
131
- const query = queries[actionId]
132
- if (payload.hasOwnProperty("loading")) {
133
- query.loading = payload.loading
126
+ if (!payload.hasOwnProperty("loading")) {
127
+ return state
128
+ }
129
+ return {
130
+ ...state,
131
+ [actionId]: { ...state[actionId], loading: payload.loading },
134
132
  }
135
- return queries
136
133
  }
137
134
  /**
138
135
  * execute queries
@@ -141,14 +138,11 @@ const queriesExecute = (state, action) => {
141
138
  if (Object.keys(state).length === 0) {
142
139
  return state
143
140
  }
144
- const { target, params, actionId, reset, type } = structuredClone(
145
- action.payload,
146
- )
141
+ const { target, params, actionId, reset, type } = action.payload
147
142
  const isResetQuery = reset || params?.reset
148
- const queries = structuredClone(state)
149
143
 
150
- if (actionId && queries[actionId]) {
151
- const query = queries[actionId]
144
+ if (actionId && state[actionId]) {
145
+ const query = { ...state[actionId] }
152
146
 
153
147
  query.loading = true
154
148
  action.actionResult.updated.itemsBefore[actionId] = state[actionId]
@@ -166,24 +160,27 @@ const queriesExecute = (state, action) => {
166
160
  }
167
161
  query.params = fixQueryParamTypes(query.params)
168
162
  action.actionResult.updated.items[actionId] = query
169
- queries[actionId] = query
170
- } else {
171
- Object.keys(queries).forEach((actionId) => {
172
- const query = queries[actionId]
173
- action.actionResult.updated.itemsBefore[actionId] = state[actionId]
174
- if (
175
- !type ||
176
- (type === "find" && query.params.find) ||
177
- (type === "search" && query.params.search)
178
- ) {
179
- query.loading = true
180
- query.params = fixQueryParamTypes(query.params)
181
- action.actionResult.updated.itemsBefore[actionId] = state[actionId]
182
- action.actionResult.updated.items[actionId] = query
183
- }
184
- })
163
+
164
+ return { ...state, [actionId]: query }
185
165
  }
186
166
 
167
+ const queries = structuredClone(state)
168
+
169
+ Object.keys(queries).forEach((queryActionId) => {
170
+ const query = queries[queryActionId]
171
+ action.actionResult.updated.itemsBefore[queryActionId] = state[queryActionId]
172
+ if (
173
+ !type ||
174
+ (type === "find" && query.params.find) ||
175
+ (type === "search" && query.params.search)
176
+ ) {
177
+ query.loading = true
178
+ query.params = fixQueryParamTypes(query.params)
179
+ action.actionResult.updated.itemsBefore[queryActionId] = state[queryActionId]
180
+ action.actionResult.updated.items[queryActionId] = query
181
+ }
182
+ })
183
+
187
184
  return queries
188
185
  }
189
186
  /**
@@ -209,36 +206,37 @@ const queriesAdd = (state, action) => {
209
206
  }
210
207
 
211
208
  action.actionResult.added.push(query)
212
- const queries = structuredClone(state)
213
- queries[actionId] = query
214
209
 
215
- return queries
210
+ return { ...state, [actionId]: query }
216
211
  }
217
212
 
218
213
  /**
219
214
  * remove queries
220
215
  */
221
216
  const queriesRemove = (state, action) => {
222
- let queries = structuredClone(state)
223
217
  const { actionId } = action.payload
224
- if (actionId && queries[actionId]) {
225
- const query = queries[actionId] || {}
226
- action.actionResult.deleted.hard[actionId] = query
227
- if (query?.uuids?.length) {
228
- // when we delete a query we will now have to remove all data Items which have been retrieven ONLY for this query. This will be determined in dataDelete reducer
229
- $store.dispatch({
230
- type: "data/deleteFromCache",
231
- payload: { uuids: query.uuids },
232
- actionId: actionId,
233
- })
218
+ if (!actionId || !state[actionId]) {
219
+ return state
220
+ }
221
+
222
+ const query = state[actionId]
223
+ action.actionResult.deleted.hard[actionId] = query
224
+ if (query?.uuids?.length) {
225
+ action.actionResult.dataCacheCleanup = {
226
+ actionId,
227
+ uuids: query.uuids,
234
228
  }
229
+ }
235
230
 
236
- $eventbus.emit("query_deleted_" + actionId, structuredClone(query))
237
- // check for parent query and if there are more than this actionId childs of it
238
- delete queries[actionId]
231
+ action.actionResult.queryDeleted = {
232
+ actionId,
233
+ query: structuredClone(query),
239
234
  }
240
235
 
241
- return queries || {}
236
+ const queries = { ...state }
237
+ delete queries[actionId]
238
+
239
+ return queries
242
240
  }
243
241
 
244
242
  export {
@@ -0,0 +1,105 @@
1
+ import { tap, distinctUntilChanged, ignoreElements } from "rxjs/operators"
2
+ import { actions$, ofType } from "mini-rx-store"
3
+ import log from "@racletteCore/lib/logger"
4
+ import {
5
+ scheduleAfterPaint,
6
+ scheduleIdleWork,
7
+ } from "@racletteCore/lib/scheduleTask"
8
+
9
+ const GRACE_PERIOD_MS = 500
10
+ const deleteTimeouts: Record<string, ReturnType<typeof setTimeout>> = {}
11
+
12
+ const clearGraceTimeout = (cacheKey: string) => {
13
+ if (deleteTimeouts[cacheKey]) {
14
+ clearTimeout(deleteTimeouts[cacheKey])
15
+ delete deleteTimeouts[cacheKey]
16
+ }
17
+ }
18
+
19
+ const queriesCacheEffects = (store) => {
20
+ const queriesCacheScheduleGraceEviction = actions$.pipe(
21
+ ofType("queries/remove"),
22
+ distinctUntilChanged((prev, curr) => !store.hasChanges(prev, curr)),
23
+
24
+ tap((action) => {
25
+ const grace = action.actionResult?.cacheGraceEviction as
26
+ | { cacheKey: string; actionId: string }
27
+ | undefined
28
+
29
+ if (!grace?.cacheKey) {
30
+ return
31
+ }
32
+
33
+ clearGraceTimeout(grace.cacheKey)
34
+ deleteTimeouts[grace.cacheKey] = setTimeout(() => {
35
+ delete deleteTimeouts[grace.cacheKey]
36
+ scheduleAfterPaint(() => {
37
+ store.dispatch({
38
+ type: "queriesCache/remove",
39
+ payload: { cacheKey: grace.cacheKey, actionId: grace.actionId },
40
+ })
41
+ })
42
+ }, GRACE_PERIOD_MS)
43
+ }),
44
+ ignoreElements(),
45
+ )
46
+
47
+ const queriesCacheCancelGraceEviction = actions$.pipe(
48
+ ofType("queriesCache/add"),
49
+ distinctUntilChanged((prev, curr) => !store.hasChanges(prev, curr)),
50
+
51
+ tap((action) => {
52
+ const cancel = action.actionResult?.cacheGraceCancel as
53
+ | { cacheKey: string }
54
+ | undefined
55
+
56
+ if (cancel?.cacheKey) {
57
+ clearGraceTimeout(cancel.cacheKey)
58
+ }
59
+ }),
60
+ ignoreElements(),
61
+ )
62
+
63
+ const queriesCacheEvictData = actions$.pipe(
64
+ ofType("queriesCache/remove"),
65
+ distinctUntilChanged((prev, curr) => !store.hasChanges(prev, curr)),
66
+
67
+ tap((action) => {
68
+ const cancelled = action.actionResult?.cacheRemoveCancelled as
69
+ | { cacheKey: string; childCount: number }
70
+ | undefined
71
+
72
+ if (cancelled) {
73
+ log.store(
74
+ "cacheRemove",
75
+ `the cache with hash ${cancelled.cacheKey} is still/again in use by ${cancelled.childCount} queries`,
76
+ )
77
+ }
78
+
79
+ const eviction = action.actionResult?.cacheEviction as
80
+ | { cacheKey: string; uuids: string[] }
81
+ | undefined
82
+
83
+ if (!eviction?.uuids?.length) {
84
+ return
85
+ }
86
+
87
+ scheduleIdleWork(() => {
88
+ store.dispatch({
89
+ type: "data/deleteFromCache",
90
+ actionId: eviction.cacheKey,
91
+ payload: { uuids: eviction.uuids },
92
+ })
93
+ })
94
+ }),
95
+ ignoreElements(),
96
+ )
97
+
98
+ return [
99
+ queriesCacheScheduleGraceEviction,
100
+ queriesCacheCancelGraceEviction,
101
+ queriesCacheEvictData,
102
+ ]
103
+ }
104
+
105
+ export default queriesCacheEffects
@@ -1,6 +1,7 @@
1
1
  import reducerFromMap from "@racletteCore/lib/reducerFromMap"
2
2
  import { applicationState } from "@racletteCore/store/state"
3
3
  import * as reducers from "./reducers"
4
+ import queriesCacheEffects from "./effects"
4
5
 
5
6
  const reducerMap = {
6
7
  init: () => applicationState.queriesCache || {},
@@ -12,4 +13,4 @@ const reducerMap = {
12
13
 
13
14
  const queriesCacheReducers = reducerFromMap(reducerMap)
14
15
 
15
- export { queriesCacheReducers }
16
+ export { queriesCacheEffects, queriesCacheReducers }
@@ -2,15 +2,82 @@ import createStableHash from "@racletteCore/lib/createStableHash"
2
2
  import { $store } from "@racletteCore"
3
3
  import log from "@racletteCore/lib/logger"
4
4
 
5
- const isParentResultFresh = (cacheKey: string, ttl: number = 1000): boolean => {
6
- const queriesState = $store.getState("queriesCache")
7
- const currentTimeStamp = new Date().getTime()
5
+ export type ParentQuery = {
6
+ cacheKey: string
7
+ loading?: boolean
8
+ uuids?: Array<string>
9
+ lastFetched?: number
10
+ deleted?: boolean
11
+ }
12
+
13
+ type QueryRef = {
14
+ target: string
15
+ params: Record<string, unknown>
16
+ }
17
+
18
+ const DEFAULT_TTL_MS = 1000
19
+
20
+ const countChildQueriesForCacheKey = (
21
+ queries: Record<string, QueryRef>,
22
+ cacheKey: string,
23
+ ): number => {
24
+ let count = 0
25
+ Object.values(queries).forEach((query) => {
26
+ const queryCacheKey = createStableHash({
27
+ target: query.target,
28
+ params: query.params,
29
+ })
30
+ if (cacheKey === queryCacheKey) {
31
+ count++
32
+ }
33
+ })
34
+ return count
35
+ }
36
+
37
+ const getCacheEntryForRemovedQuery = (
38
+ queriesCache: Record<string, ParentQuery>,
39
+ removedQuery: QueryRef | null | undefined,
40
+ ): { cacheKey: string; entry: ParentQuery } | null => {
41
+ if (!removedQuery) {
42
+ return null
43
+ }
44
+
45
+ const cacheKey = createStableHash({
46
+ target: removedQuery.target,
47
+ params: removedQuery.params,
48
+ })
49
+ const entry = queriesCache[cacheKey]
50
+
51
+ if (!entry) {
52
+ return null
53
+ }
54
+
55
+ return { cacheKey, entry }
56
+ }
57
+
58
+ const isCacheEntryFresh = (
59
+ entry: ParentQuery | undefined,
60
+ ttl: number = DEFAULT_TTL_MS,
61
+ now: number = Date.now(),
62
+ ): boolean => {
63
+ if (
64
+ !entry?.lastFetched ||
65
+ !entry?.uuids ||
66
+ entry.loading === true
67
+ ) {
68
+ return false
69
+ }
70
+
71
+ return entry.lastFetched + ttl >= now
72
+ }
73
+
74
+ const isParentResultFresh = (cacheKey: string, ttl: number = DEFAULT_TTL_MS): boolean => {
75
+ const queriesState = $store.getState("queriesCache") as Record<string, ParentQuery>
8
76
  const parentQuery = queriesState[cacheKey]
9
77
 
10
78
  if (
11
- !parentQuery.lastFetched ||
12
- !parentQuery.uuids ||
13
- parentQuery.hasOwnProperty("loading") === false ||
79
+ !parentQuery?.lastFetched ||
80
+ !parentQuery?.uuids ||
14
81
  parentQuery.loading === true
15
82
  ) {
16
83
  log.store(
@@ -21,14 +88,14 @@ const isParentResultFresh = (cacheKey: string, ttl: number = 1000): boolean => {
21
88
  return false
22
89
  }
23
90
 
24
- const isParentResultFresh = parentQuery.lastFetched + ttl >= currentTimeStamp
91
+ const fresh = isCacheEntryFresh(parentQuery, ttl)
25
92
 
26
93
  log.store(
27
94
  "queryCacheHelper",
28
- `cache #${cacheKey} is ${isParentResultFresh ? "fresh" : "stale"} for ttl of ${ttl}ms`,
95
+ `cache #${cacheKey} is ${fresh ? "fresh" : "stale"} for ttl of ${ttl}ms`,
29
96
  )
30
97
 
31
- return isParentResultFresh
98
+ return fresh
32
99
  }
33
100
 
34
101
  const getParentActionIdHash = (
@@ -62,6 +129,9 @@ const hasCacheQuery = (
62
129
  }
63
130
 
64
131
  export {
132
+ countChildQueriesForCacheKey,
133
+ getCacheEntryForRemovedQuery,
134
+ isCacheEntryFresh,
65
135
  getCacheQueryAndHash,
66
136
  hasCacheQuery,
67
137
  getParentActionIdHash,
@@ -1,135 +1,130 @@
1
1
  import createStableHash from "@racletteCore/lib/createStableHash"
2
- import log from "@racletteCore/lib/logger"
3
- import { $store } from "@racletteCore"
4
- import { isParentResultFresh } from "./queryCacheHelper"
5
- const deleteTimeouts = {}
6
- export type ParentQuery = {
7
- cacheKey: string
8
- loading?: boolean
9
- uuids?: Array<string>
10
- lastFetched?: number
11
- deleted?: boolean
12
- }
13
- const cacheMap = {}
14
- const getAffectedCacheQuery = (state, actionId) => {
15
- const removedQuery = $store.getState(["queries", actionId])
16
- if (!removedQuery) {
17
- return null
18
- }
19
- const removedQueryCacheKey = createStableHash({
20
- target: removedQuery.target,
21
- params: removedQuery.params,
22
- })
23
- return state[removedQueryCacheKey]
24
- }
25
- const getChildQueries = (cacheKey: string): Array<Record<string, object>> => {
26
- const queries = $store.getState("queries")
27
- const childQueries = []
28
- Object.values(queries).forEach((query) => {
29
- const queryCacheKey = createStableHash({
30
- target: query.target,
31
- params: query.params,
32
- })
33
- if (cacheKey === queryCacheKey) {
34
- childQueries.push(query)
35
- }
36
- })
37
- return childQueries
38
- }
2
+ import {
3
+ countChildQueriesForCacheKey,
4
+ getCacheEntryForRemovedQuery,
5
+ isCacheEntryFresh,
6
+ type ParentQuery,
7
+ } from "./queryCacheHelper"
8
+
9
+ export type { ParentQuery }
10
+
39
11
  const cacheAdd = (state, action) => {
40
- const newState = structuredClone(state)
41
12
  const { payload } = action
42
13
  const { target, params, cacheKey } = payload
43
- const parentQueryContent = {
44
- cacheKey,
45
- loading: true,
46
- }
47
14
  const hash =
48
15
  cacheKey ||
49
16
  createStableHash({
50
17
  target,
51
18
  params,
52
19
  })
53
- if (!newState[hash]) {
54
- newState[hash] = parentQueryContent
55
- } else {
56
- if (newState[hash].deleted) {
57
- if (!isParentResultFresh(hash)) {
58
- // it seems that this chache got requested again during it's grace delte time period. So Let's just set our loading state to true and delete the delete flag
59
- newState[hash].loading = true
60
- }
61
-
62
- delete newState[hash].deleted
20
+ const existing = state[hash]
21
+
22
+ if (!existing) {
23
+ return {
24
+ ...state,
25
+ [hash]: {
26
+ cacheKey,
27
+ loading: true,
28
+ },
63
29
  }
64
30
  }
65
31
 
66
- return newState
32
+ if (!existing.deleted) {
33
+ return state
34
+ }
35
+
36
+ action.actionResult.cacheGraceCancel = { cacheKey: hash }
37
+
38
+ const updated = { ...existing }
39
+ if (!isCacheEntryFresh(existing)) {
40
+ // it seems that this chache got requested again during it's grace delte time period. So Let's just set our loading state to true and delete the delete flag
41
+ updated.loading = true
42
+ }
43
+ delete updated.deleted
44
+
45
+ return { ...state, [hash]: updated }
67
46
  }
47
+
68
48
  const cacheCheck = (state: Record<string, ParentQuery>, action) => {
69
- const newState = structuredClone(state)
70
-
71
- const { items, cacheKey, actionId } = action.payload
72
- cacheMap[actionId] = cacheKey
73
- const affectedCacheQuery = newState[cacheKey]
74
- if (affectedCacheQuery) {
75
- affectedCacheQuery.loading = false
76
- affectedCacheQuery.lastFetched = new Date().getTime()
77
- action.actionResult.relationships.resolved.push(`cacheQuery_${cacheKey}`)
78
- if (items) {
79
- affectedCacheQuery.uuids = Object.values(items).map((item) => item._id)
80
- }
49
+ const { items, cacheKey } = action.payload
50
+ const affectedCacheQuery = state[cacheKey]
51
+ if (!affectedCacheQuery) {
52
+ return state
81
53
  }
82
54
 
83
- return newState
55
+ const updated: ParentQuery = {
56
+ ...affectedCacheQuery,
57
+ loading: false,
58
+ lastFetched: new Date().getTime(),
59
+ }
60
+ action.actionResult.relationships.resolved.push(`cacheQuery_${cacheKey}`)
61
+ if (items) {
62
+ updated.uuids = (Object.values(items) as Array<{ _id: string }>).map(
63
+ (item) => item._id,
64
+ )
65
+ }
66
+
67
+ return { ...state, [cacheKey]: updated }
84
68
  }
69
+
85
70
  const cacheRemove = (state, action) => {
86
- const newState = structuredClone(state)
87
71
  const { cacheKey } = action.payload
88
- const childQueries = getChildQueries(cacheKey)
89
- if (childQueries.length === 0) {
90
- // We have no further childs for this cache, so we will delete it and it's items
91
- $store.dispatch({
92
- type: "data/deleteFromCache",
93
- actionId: cacheKey,
94
- })
95
- delete newState[cacheKey]
96
- } else {
97
- // We still have child items so we will just delete the deleted flag in case we were called during grace deletion period
98
- log.store(
99
- "cacheRemove",
100
- `the cache with hash ${cacheKey} is still/again in use by ${childQueries.length} queries`,
101
- )
102
- delete newState[cacheKey].deleted
72
+ const cacheEntry = state[cacheKey]
73
+ const queries = action.storeLookup?.queries ?? {}
74
+
75
+ if (!cacheEntry) {
76
+ return state
77
+ }
78
+
79
+ // Grace-period timeout: cacheAdd clears `deleted` when the same parent is requested again.
80
+ const isGraceEviction = cacheEntry.deleted === true
81
+
82
+ if (!isGraceEviction) {
83
+ const childCount = countChildQueriesForCacheKey(queries, cacheKey)
84
+ if (childCount > 0) {
85
+ const updated = { ...state[cacheKey] }
86
+ delete updated.deleted
87
+ action.actionResult.cacheRemoveCancelled = { cacheKey, childCount }
88
+
89
+ return { ...state, [cacheKey]: updated }
90
+ }
91
+ }
92
+
93
+ const uuids = cacheEntry.uuids ?? []
94
+ if (uuids.length > 0) {
95
+ action.actionResult.cacheEviction = { cacheKey, uuids }
103
96
  }
104
97
 
98
+ const newState = { ...state }
99
+ delete newState[cacheKey]
105
100
  return newState
106
101
  }
107
102
 
108
103
  const cacheChildRemove = (state, action) => {
109
- const newState = structuredClone(state)
110
104
  const { actionId } = action.payload
111
105
  if (!actionId) return state
112
106
 
113
- const affectedCacheQuery = getAffectedCacheQuery(state, actionId)
114
- if (!affectedCacheQuery) {
107
+ const removedQuery = action.storeLookup?.queries?.[actionId]
108
+ const cacheRef = getCacheEntryForRemovedQuery(state, removedQuery)
109
+ if (!cacheRef) {
115
110
  return state
116
111
  }
117
- const childQueries = getChildQueries(affectedCacheQuery.cacheKey)
118
- if (childQueries.length === 1) {
119
- // if the action which is currently deleted is the last one needing this cache, we will give it a 2sek grace period before we remove the cache
120
- newState[affectedCacheQuery.cacheKey].deleted = true
121
- if (deleteTimeouts[affectedCacheQuery.cacheKey]) {
122
- clearTimeout(deleteTimeouts[affectedCacheQuery.cacheKey])
123
- delete deleteTimeouts[affectedCacheQuery.cacheKey]
112
+
113
+ const { cacheKey } = cacheRef
114
+ const queries = action.storeLookup?.queries ?? {}
115
+ const childCount = countChildQueriesForCacheKey(queries, cacheKey)
116
+
117
+ if (childCount === 1) {
118
+ // if the action which is currently deleted is the last one needing this cache, we will give it a grace period before we remove the cache
119
+ action.actionResult.cacheGraceEviction = { cacheKey, actionId }
120
+
121
+ return {
122
+ ...state,
123
+ [cacheKey]: { ...state[cacheKey], deleted: true },
124
124
  }
125
- deleteTimeouts[affectedCacheQuery.cacheKey] = setTimeout(() => {
126
- $store.dispatch({
127
- type: "queriesCache/remove",
128
- payload: { cacheKey: affectedCacheQuery.cacheKey, actionId },
129
- })
130
- }, 500)
131
125
  }
132
- delete cacheMap[actionId]
133
- return newState
126
+
127
+ return state
134
128
  }
129
+
135
130
  export { cacheAdd, cacheCheck, cacheChildRemove, cacheRemove }