260 lines
7.9 KiB
TypeScript
260 lines
7.9 KiB
TypeScript
/**
|
|
* Services Store
|
|
*/
|
|
|
|
import { ref, computed, readonly } from 'vue'
|
|
import { defineStore } from 'pinia'
|
|
import { serviceService } from '../services'
|
|
import { ServiceObject } from '../models/service'
|
|
import type {
|
|
SourceSelector,
|
|
ServiceInterface,
|
|
} from '../types'
|
|
|
|
export const useServicesStore = defineStore('documentsServicesStore', () => {
|
|
// State
|
|
const _services = ref<Record<string, ServiceObject>>({})
|
|
const transceiving = ref(false)
|
|
|
|
/**
|
|
* Get count of services in store
|
|
*/
|
|
const count = computed(() => Object.keys(_services.value).length)
|
|
|
|
/**
|
|
* Check if any services are present in store
|
|
*/
|
|
const has = computed(() => count.value > 0)
|
|
|
|
/**
|
|
* Get all services present in store
|
|
*/
|
|
const services = computed(() => Object.values(_services.value))
|
|
|
|
/**
|
|
* Get all services present in store grouped by provider
|
|
*/
|
|
const servicesByProvider = computed(() => {
|
|
const groups: Record<string, ServiceObject[]> = {}
|
|
|
|
Object.values(_services.value).forEach((service) => {
|
|
const providerServices = (groups[service.provider] ??= [])
|
|
providerServices.push(service)
|
|
})
|
|
|
|
return groups
|
|
})
|
|
|
|
/**
|
|
* Get a specific service from store, with optional retrieval
|
|
*
|
|
* @param provider - provider identifier
|
|
* @param identifier - service identifier
|
|
* @param retrieve - Retrieve behavior: true = fetch if missing or refresh, false = cache only
|
|
*
|
|
* @returns Service object or null
|
|
*/
|
|
function service(provider: string, identifier: string | number, retrieve: boolean = false): ServiceObject | null {
|
|
const key = identifierKey(provider, identifier)
|
|
if (retrieve === true && !_services.value[key]) {
|
|
console.debug(`[Documents Manager][Store] - Force fetching service "${key}"`)
|
|
fetch(provider, identifier)
|
|
}
|
|
|
|
return _services.value[key] || null
|
|
}
|
|
|
|
/**
|
|
* Unique key for a service
|
|
*/
|
|
function identifierKey(provider: string, identifier: string | number | null): string {
|
|
return `${provider}:${identifier ?? ''}`
|
|
}
|
|
|
|
// Actions
|
|
|
|
/**
|
|
* Retrieve all or specific services, optionally filtered by source selector
|
|
*
|
|
* @param sources - optional source selector
|
|
*
|
|
* @returns Promise with service object list keyed by provider and service identifier
|
|
*/
|
|
async function list(sources?: SourceSelector): Promise<Record<string, ServiceObject>> {
|
|
transceiving.value = true
|
|
try {
|
|
const response = await serviceService.list({ sources })
|
|
|
|
// Flatten nested structure: provider-id: { service-id: object } -> "provider-id:service-id": object
|
|
const services: Record<string, ServiceObject> = {}
|
|
Object.entries(response).forEach(([_providerId, providerServices]) => {
|
|
Object.entries(providerServices).forEach(([_serviceId, serviceObj]) => {
|
|
const key = identifierKey(serviceObj.provider, serviceObj.identifier)
|
|
services[key] = serviceObj
|
|
})
|
|
})
|
|
|
|
// Merge retrieved services into state
|
|
_services.value = { ..._services.value, ...services }
|
|
|
|
console.debug('[Documents Manager][Store] - Successfully retrieved', Object.keys(services).length, 'services')
|
|
return services
|
|
} catch (error: any) {
|
|
console.error('[Documents Manager][Store] - Failed to retrieve services:', error)
|
|
throw error
|
|
} finally {
|
|
transceiving.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve a specific service by provider and identifier
|
|
*
|
|
* @param provider - provider identifier
|
|
* @param identifier - service identifier
|
|
*
|
|
* @returns Promise with service object
|
|
*/
|
|
async function fetch(provider: string, identifier: string | number): Promise<ServiceObject> {
|
|
transceiving.value = true
|
|
try {
|
|
const service = await serviceService.fetch({ provider, identifier })
|
|
|
|
// Merge fetched service into state
|
|
const key = identifierKey(service.provider, service.identifier)
|
|
_services.value[key] = service
|
|
|
|
console.debug('[Documents Manager][Store] - Successfully fetched service:', key)
|
|
return service
|
|
} catch (error: any) {
|
|
console.error('[Documents Manager][Store] - Failed to fetch service:', error)
|
|
throw error
|
|
} finally {
|
|
transceiving.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve service availability status for a given source selector
|
|
*
|
|
* @param sources - source selector to check availability for
|
|
*
|
|
* @returns Promise with service availability status
|
|
*/
|
|
async function extant(sources: SourceSelector) {
|
|
transceiving.value = true
|
|
try {
|
|
const response = await serviceService.extant({ sources })
|
|
|
|
console.debug('[Documents Manager][Store] - Successfully checked', sources ? Object.keys(sources).length : 0, 'services')
|
|
return response
|
|
} catch (error: any) {
|
|
console.error('[Documents Manager][Store] - Failed to check services:', error)
|
|
throw error
|
|
} finally {
|
|
transceiving.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new service with given provider and data
|
|
*
|
|
* @param provider - provider identifier for the new service
|
|
* @param data - partial service data for creation
|
|
*
|
|
* @returns Promise with created service object
|
|
*/
|
|
async function create(provider: string, data: Partial<ServiceInterface>): Promise<ServiceObject> {
|
|
transceiving.value = true
|
|
try {
|
|
const service = await serviceService.create({ provider, data })
|
|
|
|
// Merge created service into state
|
|
const key = identifierKey(service.provider, service.identifier)
|
|
_services.value[key] = service
|
|
|
|
console.debug('[Documents Manager][Store] - Successfully created service:', key)
|
|
return service
|
|
} catch (error: any) {
|
|
console.error('[Documents Manager][Store] - Failed to create service:', error)
|
|
throw error
|
|
} finally {
|
|
transceiving.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update an existing service with given provider, identifier, and data
|
|
*
|
|
* @param provider - provider identifier for the service to update
|
|
* @param identifier - service identifier for the service to update
|
|
* @param data - partial service data for update
|
|
*
|
|
* @returns Promise with updated service object
|
|
*/
|
|
async function update(provider: string, identifier: string | number, data: Partial<ServiceInterface>): Promise<ServiceObject> {
|
|
transceiving.value = true
|
|
try {
|
|
const service = await serviceService.update({ provider, identifier, data })
|
|
|
|
// Merge updated service into state
|
|
const key = identifierKey(service.provider, service.identifier)
|
|
_services.value[key] = service
|
|
|
|
console.debug('[Documents Manager][Store] - Successfully updated service:', key)
|
|
return service
|
|
} catch (error: any) {
|
|
console.error('[Documents Manager][Store] - Failed to update service:', error)
|
|
throw error
|
|
} finally {
|
|
transceiving.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete a service by provider and identifier
|
|
*
|
|
* @param provider - provider identifier for the service to delete
|
|
* @param identifier - service identifier for the service to delete
|
|
*
|
|
* @returns Promise with deletion result
|
|
*/
|
|
async function remove(provider: string, identifier: string | number): Promise<any> {
|
|
transceiving.value = true
|
|
try {
|
|
await serviceService.delete({ provider, identifier })
|
|
|
|
// Remove deleted service from state
|
|
const key = identifierKey(provider, identifier)
|
|
delete _services.value[key]
|
|
|
|
console.debug('[Documents Manager][Store] - Successfully deleted service:', key)
|
|
} catch (error: any) {
|
|
console.error('[Documents Manager][Store] - Failed to delete service:', error)
|
|
throw error
|
|
} finally {
|
|
transceiving.value = false
|
|
}
|
|
}
|
|
|
|
// Return public API
|
|
return {
|
|
// State (readonly)
|
|
transceiving: readonly(transceiving),
|
|
// Getters
|
|
count,
|
|
has,
|
|
services,
|
|
servicesByProvider,
|
|
|
|
// Actions
|
|
service,
|
|
list,
|
|
fetch,
|
|
extant,
|
|
create,
|
|
update,
|
|
delete: remove,
|
|
}
|
|
})
|