All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ducks.datasource.sagas.ts Maven / Gradle / Ivy

The newest version!
import {
    put,
    takeEvery,
    fork,
    cancel,
    delay,
} from 'redux-saga/effects'
import type { Task } from 'redux-saga'

import {
    clearModel,
    removeAllModel,
    removeModel,
    setModel,
    updateModel,
    appendFieldToArray,
    copyFieldArray,
    removeFieldFromArray,
} from '../models/store'
import { EffectWrapper } from '../api/utils/effectWrapper'
import { ModelPrefix } from '../../core/datasource/const'

import { dataRequest as query } from './sagas/query'
import { validate as validateSaga } from './sagas/validate'
import {
    changePage,
    changeSize,
    dataRequest,
    DATA_REQUEST,
    register,
    reset,
    remove,
    setSorting,
    startValidate,
    submit,
} from './store'
import { applyOnInitDependencies, watchDependencies } from './sagas/dependencies'
import type { ChangePageAction, DataRequestAction, RemoveAction } from './Actions'
import { submitSaga } from './sagas/submit'
import { clear } from './Providers/Storage'
import { ResetDatasourceAction } from './Actions'
import { autoSubmit } from './sagas/autoSubmit'

// Запуск запроса за данными при изменении мета-данных (фильтр, сортировка, страница)
export function* runDataRequest({ payload }: ChangePageAction) {
    const { id, page, options = {} } = payload

    // @ts-ignore поправить типы
    yield put(dataRequest(id, { ...options, page: page || 1 }))
}

/** Список активных задач dataRequest, которые надо отменить при дестрое */
const activeTasks: Record = {}

// Очистка данных и отмена активных задач при дестрое ds
export function* removeSaga({ payload }: RemoveAction) {
    const { id } = payload
    const tasks = activeTasks[id] || []

    for (const task of tasks) {
        yield cancel(task)
    }

    /**
     * При переходе со страницы, у которой есть несколько datsource, они удаляются поочерёдо
     * И, если делать удаление модели без задержки,
     * то может стригериться зависимость на удаляемую модуль у другого удаляемого в этот же момент datasource,
     * что в свою очередь может дёрнуть нежелаемый сабмит с пустой моделью
     * (из интерессного: упирается в именование датасурсов и какой id за каким следует в списке %) )
     *
     * Поэтому закидываем небольшую задержку, чтобы избежать этой гонки
     */
    yield delay(50)
    yield put(removeAllModel(id))
}

const queryWrapper = EffectWrapper((apiProvider: unknown, action: DataRequestAction) => query(action, apiProvider))

// Обёртка над dataRequestSaga для сохранения сылк на задачу, которую надо будет отменить в случае дестроя DS
export function* dataRequestWrapper(apiProvider: unknown, action: DataRequestAction) {
    const { id } = action.payload
    const task: Task = yield fork(queryWrapper, apiProvider, action)

    activeTasks[id] = activeTasks[id] || []
    activeTasks[id].push(task)
    // фильтр завершенных задач, чтобы память не текла
    yield task.toPromise().finally(() => {
        activeTasks[id] = activeTasks[id].filter(activeTask => activeTask !== task)
    })
}

export default (apiProvider: unknown) => [
    takeEvery([setSorting, changePage, changeSize], runDataRequest),
    // @ts-ignore FIXME: ругается на тип экшена, надо будет разобраться
    takeEvery(dataRequest, dataRequestWrapper, apiProvider),
    // @ts-ignore поправить типы
    takeEvery(DATA_REQUEST, function* remapRequest({ payload, meta }) {
        const { datasource, options } = payload

        // @ts-ignore поправить типы
        yield put(dataRequest(datasource, options, meta))
    }),
    takeEvery(startValidate, validateSaga),
    // @ts-ignore хер знает как затипизировать
    takeEvery(submit, EffectWrapper(submitSaga), apiProvider),
    takeEvery(remove, removeSaga),
    takeEvery([
        setModel,
        removeModel,
        removeAllModel,
        clearModel,
        updateModel,
        appendFieldToArray,
        removeFieldFromArray,
        copyFieldArray,
    ], watchDependencies),
    takeEvery(register, applyOnInitDependencies),
    // @ts-ignore FIXME: проставить тип action
    takeEvery(action => action.meta?.refresh?.datasources, function* refreshSaga({ meta }) {
        const { refresh } = meta
        const { datasources } = refresh

        for (const datasource of datasources) {
            yield put(dataRequest(datasource))
        }
    }),
    // @ts-ignore FIXME: проставить тип action
    takeEvery(action => action.meta?.clear, clear),
    takeEvery(reset, function* resetModels({ payload: { id } }: ResetDatasourceAction) {
        yield put(clearModel({ prefixes: Object.values(ModelPrefix), key: id }))
    }),
    ...autoSubmit,
]




© 2015 - 2024 Weber Informatics LLC | Privacy Policy