@cbm-common/data-access
v0.0.7
Published
Esta librería proporciona clases reutilizables para manejar operaciones de listado y paginación en forma reactiva: `ListService` y `PaginatedListService`.
Downloads
766
Readme
data-access — Biblioteca de acceso a datos (List y PaginatedList)
Esta librería proporciona clases reutilizables para manejar operaciones de listado y paginación en forma reactiva: ListService y PaginatedListService.
Resumen de artefactos
ListService<T, R>: clase base que realiza la llamada al repositorio, transforma la respuesta (mapFn) y expone señales (data,loading) y helpers (list(),getParams(),setParams(),updateParams()).PaginatedListService<T, R>: extiendeListServiceañadiendo soporte de paginación (señalpagination, métodosnextPage, getters/setters de paginado ylist(resetPg?: boolean)).- Modelos expuestos:
ListModel.Repository<T>: contrato que debe exponerdestroyRefylist$(función que devuelve Observable).ListModel.Config<T,R>: opciones:mapFn,notificationService,typeahead.PaginatedListModel.Paginated: forma{ page, size, pages, records }y valor inicialinitPaginated.
Concepto y comportamiento
- Ambas clases no son Angular services (no llevan
@Injectable) sino helpers/clases que se instancian desde otros servicios o componentes con una dependenciarepository(implementación concreta que exponelist$ydestroyRef). ListServicemaneja:data(señal con el resultado transformado pormapFn).loading(señal booleana durante la petición).typeahead(siconfig.typeaheadestá definido,typeahead$se escucha y actualiza params tras debounce).notificationService(si se pasa en config, se usa para mostrar errores).
PaginatedListServiceagrega paginación y funciones para avanzar páginas, preservar parámetros y mapear la respuesta con acceso a la señal de paginado.
Tipos clave (resumen)
ListModel.Repository:
- destroyRef:
DestroyRef(para takeUntilDestroyed) - list$: (...args: any[]) => Observable
- destroyRef:
ListModel.Config<T,R>:
- mapFn?: (res: T, pg?: WritableSignal<PaginatedListModel.Paginated>) => R
- notificationService?: servicio con método
sendAlert(opcional) - typeahead?: string — nombre del parámetro que se usará para búsquedas tipo typeahead
Ejemplo básico de uso
Supongamos que tienes un repositorio con la forma esperada:
// repo.mock.ts (ejemplo)
const repo = {
destroyRef: someDestroyRef,
list$: (params: any) => httpClient.get('/api/items', { params })
};
// crear servicio de lista
const listService = new ListService(repo, {
mapFn: (res) => res.items, // transformar respuesta
notificationService: notificationServiceInstance,
typeahead: 'q'
});
// usar
await listService.list();
console.log(listService.data());Ejemplo con paginación:
const paginated = new PaginatedListService(repo, { mapFn: (res, pg) => res.items });
await paginated.list();
paginated.nextPage(searchTerm);Notas de implementación
ListServiceusatakeUntilDestroyed(this._destroyRef)para cancelar observables cuando el consumer se destruye; por ellorepository.destroyRefdebe estar presente.mapFnpermite adaptar la respuesta del backend al tipo consumido por la UI. Si no se provee, se usadefaultMapFnque hace un cast simple.
Errores comunes y sugerencias
"La propiedad se usa antes de su inicialización" (TypeScript/ESNext class fields):
- Si ves un error tipo
La propiedad "_config" se usa antes de su inicializaciónes probable que la configuración del compilador (useDefineForClassFields) o la forma en que se declaran propiedades haga que las inicializaciones de campos que dependen de parámetros del constructor intenten evaluarse antes del constructor. - Solución práctica: mover cualquier inicialización que use
this._configothis._repositorya dentro del constructor o definir las propiedades sin inicializar y asignarlas en el constructor. De esta forma se evita acceder a campos antes de tiempo.
- Si ves un error tipo
Ejemplo de corrección (esquema):
// incorrecto (campo inicializado con referencia a parámetro del constructor)
protected readonly notificationService = this._config.notificationService; // puede fallar
// correcto (asignar en constructor)
protected readonly notificationService: any;
constructor(repo, config) {
this.notificationService = config.notificationService;
}Pruebas y validación
- Para probar las clases crea mocks del
repositoryque exponganlist$(por ejemploof(mockResponse)) y undestroyRefapropiado. Testealist(), comportamiento deloading, y quemapFntransforma el resultado.
Contribuciones y extensión
- Puedes extender
ListServicepara soportar caching, cancelación explícita de peticiones o estrategia de reintento.
Si quieres, implemento:
- ejemplos de tests unitarios (Jest/Karma) para
ListServiceyPaginatedListService; - o aplico la corrección automática para evitar el problema de inicialización de propiedades (mover inicializaciones al constructor). Indica cuál prefieres.
