feat(bd): ServicioFavoritos SQLite — PluriWave Fase 1 #1

Closed
Ghost wants to merge 0 commits from feature/bd-favoritos into main

PluriWave — ServicioFavoritos (SQLite, sqflite)

Qué incluye este PR

lib/modelos/emisora.dart

  • Modelo Emisora con todos los campos pedidos: id, uuid, nombre, url, favicon, pais, idioma, tags, orden
  • fromMap() / toMap() para serialización SQLite
  • copyWith() para mutaciones inmutables
  • == y hashCode por uuid (identidad de negocio)

lib/servicios/servicio_favoritos.dart

  • Singleton ServicioFavoritos con inicialización lazy (DB se abre en el primer acceso)
  • Tabla favoritos creada con CREATE TABLE IF NOT EXISTS — idempotente
  • Índice UNIQUE en uuid + índice en orden
  • Migration-ready: versión 1, _onUpgrade preparado para futuras versiones sin perder datos

Métodos implementados

Método Descripción
obtenerTodos() List<Emisora> ordenado por orden ASC
agregar(Emisora) Insert + upsert por conflicto en uuid; orden auto al final si viene en 0
eliminar(uuid) DELETE por uuid, idempotente
esFavorito(uuid) bool — query ligera solo con id
reordenar(uuid, nuevoOrden) Actualiza orden de una emisora
reordenarLista(uuids) Reordena lista completa en una transacción (drag & drop)
contarFavoritos() int — helper de utilidad

Decisiones de diseño

  • path package: servicio_favoritos.dart usa package:path/path.dart para construir la ruta de la BD — ya es dependencia transitiva de sqflite en el sdk de Flutter, no requiere añadir nada al pubspec
  • Orden automático: cuando se llama agregar() con orden = 0 y la emisora es nueva, se asigna MAX(orden) + 1 para que aparezca al final de la lista sin necesidad de recalcular todos los índices
  • Sin eliminación lógica en esta versión: los favoritos son una lista explícita del usuario; el borrado es intencional y reversible (volviendo a agregar). Si en v2 se necesita historial, se añade eliminado BOOLEAN en la migración

Tests sugeridos para QA

// 1. Agregar y obtener
await servicio.agregar(emisora);
expect(await servicio.obtenerTodos(), contains(emisora));

// 2. esFavorito
expect(await servicio.esFavorito(emisora.uuid), isTrue);
expect(await servicio.esFavorito("uuid-inexistente"), isFalse);

// 3. Eliminar e idempotencia
await servicio.eliminar(emisora.uuid);
expect(await servicio.esFavorito(emisora.uuid), isFalse);
await servicio.eliminar(emisora.uuid); // no lanza, devuelve 0

// 4. Reordenar
await servicio.reordenar(emisora.uuid, 5);
final lista = await servicio.obtenerTodos();
expect(lista.first.orden, equals(5));

// 5. Upsert — agregar dos veces no duplica
await servicio.agregar(emisora);
await servicio.agregar(emisora.copyWith(nombre: "Nombre actualizado"));
expect(await servicio.contarFavoritos(), equals(1));
## PluriWave — ServicioFavoritos (SQLite, sqflite) ### Qué incluye este PR **`lib/modelos/emisora.dart`** - Modelo `Emisora` con todos los campos pedidos: `id`, `uuid`, `nombre`, `url`, `favicon`, `pais`, `idioma`, `tags`, `orden` - `fromMap()` / `toMap()` para serialización SQLite - `copyWith()` para mutaciones inmutables - `==` y `hashCode` por `uuid` (identidad de negocio) **`lib/servicios/servicio_favoritos.dart`** - Singleton `ServicioFavoritos` con inicialización lazy (DB se abre en el primer acceso) - Tabla `favoritos` creada con `CREATE TABLE IF NOT EXISTS` — idempotente - Índice UNIQUE en `uuid` + índice en `orden` - Migration-ready: versión 1, `_onUpgrade` preparado para futuras versiones sin perder datos ### Métodos implementados | Método | Descripción | |--------|-------------| | `obtenerTodos()` | `List<Emisora>` ordenado por `orden ASC` | | `agregar(Emisora)` | Insert + upsert por conflicto en `uuid`; orden auto al final si viene en 0 | | `eliminar(uuid)` | DELETE por uuid, idempotente | | `esFavorito(uuid)` | `bool` — query ligera solo con `id` | | `reordenar(uuid, nuevoOrden)` | Actualiza `orden` de una emisora | | `reordenarLista(uuids)` | Reordena lista completa en una transacción (drag & drop) | | `contarFavoritos()` | `int` — helper de utilidad | ### Decisiones de diseño - **`path` package**: `servicio_favoritos.dart` usa `package:path/path.dart` para construir la ruta de la BD — ya es dependencia transitiva de sqflite en el sdk de Flutter, no requiere añadir nada al pubspec - **Orden automático**: cuando se llama `agregar()` con `orden = 0` y la emisora es nueva, se asigna `MAX(orden) + 1` para que aparezca al final de la lista sin necesidad de recalcular todos los índices - **Sin eliminación lógica** en esta versión: los favoritos son una lista explícita del usuario; el borrado es intencional y reversible (volviendo a agregar). Si en v2 se necesita historial, se añade `eliminado BOOLEAN` en la migración ### Tests sugeridos para QA ```dart // 1. Agregar y obtener await servicio.agregar(emisora); expect(await servicio.obtenerTodos(), contains(emisora)); // 2. esFavorito expect(await servicio.esFavorito(emisora.uuid), isTrue); expect(await servicio.esFavorito("uuid-inexistente"), isFalse); // 3. Eliminar e idempotencia await servicio.eliminar(emisora.uuid); expect(await servicio.esFavorito(emisora.uuid), isFalse); await servicio.eliminar(emisora.uuid); // no lanza, devuelve 0 // 4. Reordenar await servicio.reordenar(emisora.uuid, 5); final lista = await servicio.obtenerTodos(); expect(lista.first.orden, equals(5)); // 5. Upsert — agregar dos veces no duplica await servicio.agregar(emisora); await servicio.agregar(emisora.copyWith(nombre: "Nombre actualizado")); expect(await servicio.contarFavoritos(), equals(1)); ```
Ghost added 2 commits 2026-04-04 16:28:55 +02:00
FreeTLab closed this pull request 2026-04-05 19:07:32 +02:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: FreeTLab/pluriwave#1