import { Ref, toRaw } from 'vue' import { deepIsRevise } from './diff' export const storeSecurityPush = (items: T[], pushItem: T) => { const index = items.indexOf(pushItem) if (!~index) { items.push(pushItem) return true } else { return false } } export const storeSecurityDelete = (items: T[], pushItem: T) => { const index = items.indexOf(pushItem) if (~index) { items.splice(index, 1) return true } else { return false } } export function addStoreItem ( items: Ref, addAction: (item: T) => Promise, ): (item: T) => Promise export function addStoreItem ( items: Ref, addAction: (item: K) => Promise, transform: (item: T) => Promise | K ): (item: T) => Promise export function addStoreItem ( items: Ref, addAction: (item: K) => Promise, transform?: (item: T) => Promise | K ) { return async (item: T) => { let actionData: K if (transform) { actionData = await transform(item) } else { actionData = item as unknown as K } const newItem = await addAction(actionData) const self = items.value.find(findItem => findItem.id === item.id) if (self) { Object.assign(self, newItem) } else { storeSecurityPush(items.value, item) } return newItem } } export function updateStoreItem ( items: Ref, updateAction: (item: T, oldItem: T) => Promise, ): (item: T, oldItem: T) => Promise export function updateStoreItem ( items: Ref, updateAction: (item: K, oldItem: T) => Promise, transform: (item: T) => Promise | K ): (item: T, oldItem: T) => Promise export function updateStoreItem ( items: Ref, updateAction: (item: K, oldItem: T) => Promise, transform?: (item: T) => Promise | K ) { return async (item: T, oldItem: T) => { let actionData: K if (transform) { actionData = await transform(item) } else { actionData = item as unknown as K } await updateAction(actionData, oldItem) const storeItem = items.value.find(atom => atom.id === item.id) if (storeItem) { Object.assign(storeItem, item) } } } export function deleteStoreItem ( items: Ref, deleteAction: (item: T) => Promise, ): (item: T) => Promise export function deleteStoreItem ( items: Ref, deleteAction: (item: K) => Promise, transform: (item: T) => Promise | K ): (item: T) => Promise export function deleteStoreItem ( items: Ref, deleteAction: (item: K) => Promise, transform?: (item: T) => Promise | K ) { return async (item: T) => { let actionData: K if (transform) { actionData = await transform(item) } else { actionData = item as unknown as K } await deleteAction(actionData) storeSecurityDelete(items.value, item) } } export function fetchStoreItems ( items: Ref, fetchAction: () => Promise, callback: (() => void) | null, ): () => Promise export function fetchStoreItems ( items: Ref, fetchAction: () => Promise, callback: (() => void) | null, transform: (items: K[]) => Promise | T[], ): () => Promise export function fetchStoreItems ( items: Ref, fetchAction: () => Promise, callback: (() => void) | null, transform?: (items: K[]) => Promise | T[], ) { return async () => { const fetchItems = await fetchAction() let actionData: T[] if (transform) { actionData = await transform(fetchItems) } else { actionData = fetchItems as unknown as T[] } items.value = actionData callback && callback() } } export const saveStoreItems = ( newItems: Ref, getOldItem: () => T[], actions: { add?: ReturnType>, update?: ReturnType>, delete?: ReturnType>, } ) => () => { const oldItems = getOldItem() const { deleted, updated, added } = diffStoreItemsChange(newItems.value, oldItems) const promiseAll: Promise[] = [] if (actions.delete) { for (const delItem of deleted) { promiseAll.push(actions.delete(delItem)) } } if (actions.update) { for (const [newItem, oldItem] of updated) { promiseAll.push(actions.update(newItem, oldItem)) } } if (actions.add) { for (const addItem of added) { promiseAll.push(actions.add(addItem)) } } return Promise.all(promiseAll) } export const diffStoreItemsChange = >(newItems: T, oldItems: T) => { const addedItems = [] as unknown as T const deletedItems = [] as unknown as T const updateItems = [] as unknown as [T[number], T[number]][] newItems = toRaw(newItems) for (const newItem of newItems) { const oldItem = oldItems.find(oldItem => newItem.id === oldItem.id) if (!oldItem) { storeSecurityPush(addedItems, newItem) } else if (deepIsRevise(oldItem, newItem)) { storeSecurityPush(updateItems, [newItem, oldItem] as any) } } for (const oldItem of oldItems) { const newItem = newItems.find(newItem => newItem.id === oldItem.id) if (!newItem) { storeSecurityPush(deletedItems, oldItem) } } return { added: addedItems, deleted: deletedItems, updated: updateItems } } export const recoverStoreItems = >(items: Ref, getBackupItems: () => T) => () => { const backupItems = getBackupItems() items.value = backupItems.map(oldItem => { const model = items.value.find(item => item.id === oldItem.id) console.log("===>", model, oldItem) return model ? Object.assign(model, oldItem) : oldItem }) as T }