store-help.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import { Ref, toRaw } from 'vue'
  2. import { deepIsRevise } from './diff'
  3. export const storeSecurityPush = <T extends any>(items: T[], pushItem: T) => {
  4. const index = items.indexOf(pushItem)
  5. if (!~index) {
  6. items.push(pushItem)
  7. return true
  8. } else {
  9. return false
  10. }
  11. }
  12. export const storeSecurityDelete = <T extends any>(items: T[], pushItem: T) => {
  13. const index = items.indexOf(pushItem)
  14. if (~index) {
  15. items.splice(index, 1)
  16. return true
  17. } else {
  18. return false
  19. }
  20. }
  21. export function addStoreItem <T extends {id: any}>(
  22. items: Ref<T[]>,
  23. addAction: (item: T) => Promise<T>,
  24. ): (item: T) => Promise<T>
  25. export function addStoreItem <T extends {id: any}, K extends {id: any} = T>(
  26. items: Ref<T[]>,
  27. addAction: (item: K) => Promise<K>,
  28. transform: (item: T) => Promise<K> | K
  29. ): (item: T) => Promise<K>
  30. export function addStoreItem <T extends {id: any}, K extends {id: any} = T>(
  31. items: Ref<T[]>,
  32. addAction: (item: K) => Promise<K>,
  33. transform?: (item: T) => Promise<K> | K
  34. ) {
  35. return async (item: T) => {
  36. let actionData: K
  37. if (transform) {
  38. actionData = await transform(item)
  39. } else {
  40. actionData = item as unknown as K
  41. }
  42. const newItem = await addAction(actionData)
  43. const self = items.value.find(findItem => findItem.id === item.id)
  44. if (self) {
  45. Object.assign(self, newItem)
  46. } else {
  47. storeSecurityPush(items.value, item)
  48. }
  49. return newItem
  50. }
  51. }
  52. export function updateStoreItem <T extends {id: any}>(
  53. items: Ref<T[]>,
  54. updateAction: (item: T, oldItem: T) => Promise<any>,
  55. ): (item: T, oldItem: T) => Promise<void>
  56. export function updateStoreItem <T extends {id: any}, K extends {id: any} = T>(
  57. items: Ref<T[]>,
  58. updateAction: (item: K, oldItem: T) => Promise<any>,
  59. transform: (item: T) => Promise<K> | K
  60. ): (item: T, oldItem: T) => Promise<void>
  61. export function updateStoreItem <T extends {id: any}, K extends {id: any} = T>(
  62. items: Ref<T[]>,
  63. updateAction: (item: K, oldItem: T) => Promise<any>,
  64. transform?: (item: T) => Promise<K> | K
  65. ) {
  66. return async (item: T, oldItem: T) => {
  67. let actionData: K
  68. if (transform) {
  69. actionData = await transform(item)
  70. } else {
  71. actionData = item as unknown as K
  72. }
  73. await updateAction(actionData, oldItem)
  74. const storeItem = items.value.find(atom => atom.id === item.id)
  75. if (storeItem) {
  76. Object.assign(storeItem, item)
  77. }
  78. }
  79. }
  80. export function deleteStoreItem <T extends {id: any}>(
  81. items: Ref<T[]>,
  82. deleteAction: (item: T) => Promise<any>,
  83. ): (item: T) => Promise<void>
  84. export function deleteStoreItem <T extends {id: any}, K extends {id: any} = T>(
  85. items: Ref<T[]>,
  86. deleteAction: (item: K) => Promise<any>,
  87. transform: (item: T) => Promise<K> | K
  88. ): (item: T) => Promise<void>
  89. export function deleteStoreItem <T extends {id: any}, K extends {id: any} = T>(
  90. items: Ref<T[]>,
  91. deleteAction: (item: K) => Promise<any>,
  92. transform?: (item: T) => Promise<K> | K
  93. ) {
  94. return async (item: T) => {
  95. let actionData: K
  96. if (transform) {
  97. actionData = await transform(item)
  98. } else {
  99. actionData = item as unknown as K
  100. }
  101. await deleteAction(actionData)
  102. storeSecurityDelete(items.value, item)
  103. }
  104. }
  105. export function fetchStoreItems <T extends {id: any}, K extends {id: any} = T>(
  106. items: Ref<T[]>,
  107. fetchAction: () => Promise<T[]>,
  108. ): () => Promise<void>
  109. export function fetchStoreItems <T extends {id: any}, K extends {id: any} = T>(
  110. items: Ref<T[]>,
  111. fetchAction: () => Promise<T[]>,
  112. callback: (() => void) | null,
  113. ): () => Promise<void>
  114. export function fetchStoreItems <T extends {id: any}, K extends {id: any} = T>(
  115. items: Ref<T[]>,
  116. fetchAction: () => Promise<K[]>,
  117. callback: (() => void) | null,
  118. transform: (items: K[]) => Promise<T[]> | T[],
  119. ): () => Promise<void>
  120. export function fetchStoreItems <T extends {id: any}, K extends {id: any} = T>(
  121. items: Ref<T[]>,
  122. fetchAction: () => Promise<K[]>,
  123. callback?: (() => void) | null,
  124. transform?: (items: K[]) => Promise<T[]> | T[],
  125. ) {
  126. return async () => {
  127. const fetchItems = await fetchAction()
  128. let actionData: T[]
  129. if (transform) {
  130. actionData = await transform(fetchItems)
  131. } else {
  132. actionData = fetchItems as unknown as T[]
  133. }
  134. items.value = actionData
  135. callback && callback()
  136. }
  137. }
  138. export const saveStoreItems = <T extends {id: any}>(
  139. newItems: Ref<T[]>,
  140. getOldItem: () => T[],
  141. actions: {
  142. add?: ReturnType<typeof addStoreItem<T>>,
  143. update?: ReturnType<typeof updateStoreItem<T>>,
  144. delete?: ReturnType<typeof deleteStoreItem<T>>,
  145. }
  146. ) => () => {
  147. const oldItems = getOldItem()
  148. const {
  149. deleted,
  150. updated,
  151. added
  152. } = diffStoreItemsChange(newItems.value, oldItems)
  153. const promiseAll: Promise<any>[] = []
  154. if (actions.delete) {
  155. for (const delItem of deleted) {
  156. promiseAll.push(actions.delete(delItem))
  157. }
  158. }
  159. if (actions.update) {
  160. for (const [newItem, oldItem] of updated) {
  161. promiseAll.push(actions.update(newItem, oldItem))
  162. }
  163. }
  164. if (actions.add) {
  165. for (const addItem of added) {
  166. promiseAll.push(actions.add(addItem))
  167. }
  168. }
  169. return Promise.all(promiseAll)
  170. }
  171. export const diffStoreItemsChange = <T extends Array<{ id: any }>>(newItems: T, oldItems: T) => {
  172. const addedItems = [] as unknown as T
  173. const deletedItems = [] as unknown as T
  174. const updateItems = [] as unknown as [T[number], T[number]][]
  175. newItems = toRaw(newItems)
  176. for (const newItem of newItems) {
  177. const oldItem = oldItems.find(oldItem => newItem.id === oldItem.id)
  178. if (!oldItem) {
  179. storeSecurityPush(addedItems, newItem)
  180. } else if (deepIsRevise(oldItem, newItem)) {
  181. storeSecurityPush(updateItems, [newItem, oldItem] as any)
  182. }
  183. }
  184. for (const oldItem of oldItems) {
  185. const newItem = newItems.find(newItem => newItem.id === oldItem.id)
  186. if (!newItem) {
  187. storeSecurityPush(deletedItems, oldItem)
  188. }
  189. }
  190. return {
  191. added: addedItems,
  192. deleted: deletedItems,
  193. updated: updateItems
  194. }
  195. }
  196. export const recoverStoreItems = <T extends Array<{ id: any }>>(items: Ref<T>, getBackupItems: () => T) => () => {
  197. const backupItems = getBackupItems()
  198. items.value = backupItems.map(oldItem => {
  199. const model = items.value.find(item => item.id === oldItem.id)
  200. return model ? Object.assign(model, oldItem) : oldItem
  201. }) as T
  202. }