F7: Deduplicate the four CRUD composables
useExercises/useCombos/useSessions/useCollections were the same 54 lines with a different repository (~160 duplicated lines). They are now one-liners over a createCrudComposable(repository, itemsKey) factory; the returned API is identical so no call site changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a6b4723ac6
commit
e3847edae1
71
src/composables/createCrudComposable.js
Normal file
71
src/composables/createCrudComposable.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import { ref } from 'vue'
|
||||
|
||||
/**
|
||||
* Factory for the four identical CRUD composables (exercises, combos,
|
||||
* sessions, collections). Returns a composable exposing the reactive item
|
||||
* list under `itemsKey` plus the shared loading/error/CRUD API, so
|
||||
* useExercises & co. stay one-liners with unchanged call sites.
|
||||
*/
|
||||
export function createCrudComposable(repository, itemsKey) {
|
||||
return function useCrud() {
|
||||
const items = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
items.value = await repository.getAll()
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function create(data) {
|
||||
const id = await repository.create(data)
|
||||
await fetchAll()
|
||||
return id
|
||||
}
|
||||
|
||||
async function update(id, data) {
|
||||
await repository.update(id, data)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await repository.delete(id)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function search(query) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
items.value = await repository.search(query)
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getById(id) {
|
||||
return repository.getById(id)
|
||||
}
|
||||
|
||||
return {
|
||||
[itemsKey]: items,
|
||||
loading,
|
||||
error,
|
||||
fetchAll,
|
||||
create,
|
||||
update,
|
||||
remove,
|
||||
search,
|
||||
getById,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +1,4 @@
|
|||
import { ref } from 'vue'
|
||||
import { collectionRepository } from '../db/repositories/collectionRepository.js'
|
||||
import { createCrudComposable } from './createCrudComposable.js'
|
||||
|
||||
export function useCollections() {
|
||||
const collections = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
collections.value = await collectionRepository.getAll()
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function create(data) {
|
||||
const id = await collectionRepository.create(data)
|
||||
await fetchAll()
|
||||
return id
|
||||
}
|
||||
|
||||
async function update(id, data) {
|
||||
await collectionRepository.update(id, data)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await collectionRepository.delete(id)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function search(query) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
collections.value = await collectionRepository.search(query)
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getById(id) {
|
||||
return collectionRepository.getById(id)
|
||||
}
|
||||
|
||||
return { collections, loading, error, fetchAll, create, update, remove, search, getById }
|
||||
}
|
||||
export const useCollections = createCrudComposable(collectionRepository, 'collections')
|
||||
|
|
|
|||
|
|
@ -1,54 +1,4 @@
|
|||
import { ref } from 'vue'
|
||||
import { comboRepository } from '../db/repositories/comboRepository.js'
|
||||
import { createCrudComposable } from './createCrudComposable.js'
|
||||
|
||||
export function useCombos() {
|
||||
const combos = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
combos.value = await comboRepository.getAll()
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function create(data) {
|
||||
const id = await comboRepository.create(data)
|
||||
await fetchAll()
|
||||
return id
|
||||
}
|
||||
|
||||
async function update(id, data) {
|
||||
await comboRepository.update(id, data)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await comboRepository.delete(id)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function search(query) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
combos.value = await comboRepository.search(query)
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getById(id) {
|
||||
return comboRepository.getById(id)
|
||||
}
|
||||
|
||||
return { combos, loading, error, fetchAll, create, update, remove, search, getById }
|
||||
}
|
||||
export const useCombos = createCrudComposable(comboRepository, 'combos')
|
||||
|
|
|
|||
|
|
@ -1,54 +1,4 @@
|
|||
import { ref } from 'vue'
|
||||
import { exerciseRepository } from '../db/repositories/exerciseRepository.js'
|
||||
import { createCrudComposable } from './createCrudComposable.js'
|
||||
|
||||
export function useExercises() {
|
||||
const exercises = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
exercises.value = await exerciseRepository.getAll()
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function create(data) {
|
||||
const id = await exerciseRepository.create(data)
|
||||
await fetchAll()
|
||||
return id
|
||||
}
|
||||
|
||||
async function update(id, data) {
|
||||
await exerciseRepository.update(id, data)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await exerciseRepository.delete(id)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function search(query) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
exercises.value = await exerciseRepository.search(query)
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getById(id) {
|
||||
return exerciseRepository.getById(id)
|
||||
}
|
||||
|
||||
return { exercises, loading, error, fetchAll, create, update, remove, search, getById }
|
||||
}
|
||||
export const useExercises = createCrudComposable(exerciseRepository, 'exercises')
|
||||
|
|
|
|||
|
|
@ -1,54 +1,4 @@
|
|||
import { ref } from 'vue'
|
||||
import { sessionRepository } from '../db/repositories/sessionRepository.js'
|
||||
import { createCrudComposable } from './createCrudComposable.js'
|
||||
|
||||
export function useSessions() {
|
||||
const sessions = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
sessions.value = await sessionRepository.getAll()
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function create(data) {
|
||||
const id = await sessionRepository.create(data)
|
||||
await fetchAll()
|
||||
return id
|
||||
}
|
||||
|
||||
async function update(id, data) {
|
||||
await sessionRepository.update(id, data)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function remove(id) {
|
||||
await sessionRepository.delete(id)
|
||||
await fetchAll()
|
||||
}
|
||||
|
||||
async function search(query) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
sessions.value = await sessionRepository.search(query)
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function getById(id) {
|
||||
return sessionRepository.getById(id)
|
||||
}
|
||||
|
||||
return { sessions, loading, error, fetchAll, create, update, remove, search, getById }
|
||||
}
|
||||
export const useSessions = createCrudComposable(sessionRepository, 'sessions')
|
||||
|
|
|
|||
Loading…
Reference in a new issue