feat: use resource identifiers
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
+76
-68
@@ -6,6 +6,7 @@ import { computed, ref, readonly } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import type {
|
||||
CollectionIdentifier,
|
||||
EntityIdentifier,
|
||||
ServiceIdentifier,
|
||||
ListFilter,
|
||||
ListSort,
|
||||
@@ -16,6 +17,7 @@ import type {
|
||||
import { CollectionObject, EntityObject } from '../models'
|
||||
import { useCollectionsStore } from './collectionsStore'
|
||||
import { useEntitiesStore } from './entitiesStore'
|
||||
import { nodeService } from '../services/nodeService'
|
||||
|
||||
export const ROOT_ID = '00000000-0000-0000-0000-000000000000'
|
||||
|
||||
@@ -46,8 +48,8 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
|
||||
function getServiceNodes(providerId: string, serviceId: string | number): NodeRecord[] {
|
||||
return [
|
||||
...collectionsStore.collectionsForService(providerId, serviceId),
|
||||
...entitiesStore.entitiesForService(providerId, serviceId),
|
||||
...collectionsStore.collectionsForService(`${providerId}:${serviceId}`),
|
||||
...entitiesStore.entitiesForService(`${providerId}:${serviceId}`),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -105,20 +107,13 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function fetchCollections(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number | null,
|
||||
sources?: (ServiceIdentifier | CollectionIdentifier)[],
|
||||
filter?: ListFilter,
|
||||
sort?: ListSort,
|
||||
): Promise<CollectionObject[]> {
|
||||
error.value = null
|
||||
try {
|
||||
const sources: (ServiceIdentifier | CollectionIdentifier)[] = collectionId === null
|
||||
? [`${providerId}:${serviceId}`]
|
||||
: [`${providerId}:${serviceId}:${collectionId}`]
|
||||
|
||||
await collectionsStore.list(sources, filter, sort)
|
||||
return collectionsStore.collectionsForService(providerId, serviceId)
|
||||
return Object.values(await collectionsStore.list(sources, filter, sort))
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to fetch collections'
|
||||
throw e
|
||||
@@ -126,43 +121,76 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function fetchEntities(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number | null,
|
||||
sources?: (ServiceIdentifier | CollectionIdentifier)[],
|
||||
filter?: ListFilter,
|
||||
sort?: ListSort,
|
||||
range?: ListRange,
|
||||
): Promise<EntityObject[]> {
|
||||
error.value = null
|
||||
try {
|
||||
const sources: (ServiceIdentifier | CollectionIdentifier)[] = collectionId === null
|
||||
? [`${providerId}:${serviceId}`]
|
||||
: [`${providerId}:${serviceId}:${collectionId}`]
|
||||
|
||||
await entitiesStore.list(sources, filter, sort, range)
|
||||
return entitiesStore.entitiesForCollection(providerId, serviceId, collectionId)
|
||||
return Object.values(await entitiesStore.list(sources, filter, sort, range))
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to fetch entities'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a unified node listing, optionally limited to a page by range.
|
||||
*/
|
||||
async function fetchNodes(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
parentId: string | number | null = ROOT_ID,
|
||||
sources?: (ServiceIdentifier | CollectionIdentifier)[],
|
||||
filter?: ListFilter,
|
||||
sort?: ListSort,
|
||||
range?: ListRange,
|
||||
): Promise<NodeRecord[]> {
|
||||
mode: 'reset' | 'append' = 'reset',
|
||||
): Promise<{ collections: CollectionObject[]; entities: EntityObject[]; isLastPage: boolean }> {
|
||||
error.value = null
|
||||
try {
|
||||
await Promise.all([
|
||||
fetchCollections(providerId, serviceId, parentId, filter, sort),
|
||||
fetchEntities(providerId, serviceId, parentId, filter, sort, range),
|
||||
])
|
||||
const result = await nodeService.list({ sources, filter, sort, range })
|
||||
|
||||
return getChildren(providerId, serviceId, parentId)
|
||||
// Service selectors list the root; collection selectors list that folder.
|
||||
// Omitted sources list roots across services, not every cached descendant.
|
||||
const locations = new Map<string, { provider: string; service: string; parent: string }>()
|
||||
if (sources?.length) {
|
||||
for (const source of sources) {
|
||||
const [provider, service, parent] = source.split(':')
|
||||
const location = { provider: provider!, service: service!, parent: isRoot(parent) ? ROOT_ID : parent! }
|
||||
locations.set(`${location.provider}:${location.service}:${location.parent}`, location)
|
||||
}
|
||||
} else {
|
||||
for (const node of [...nodeList.value, ...result]) {
|
||||
const location = { provider: node.provider, service: String(node.service), parent: ROOT_ID }
|
||||
locations.set(`${location.provider}:${location.service}:${ROOT_ID}`, location)
|
||||
}
|
||||
}
|
||||
|
||||
// Replace only the selected locations, and only after the stream succeeds.
|
||||
if (mode === 'reset') {
|
||||
for (const { provider, service, parent } of locations.values()) {
|
||||
const staleIds = getChildCollections(provider, service, parent)
|
||||
.map((node): CollectionIdentifier => `${node.provider}:${node.service}:${node.identifier}`)
|
||||
collectionsStore.removeMany(staleIds)
|
||||
entitiesStore.clearCollection(`${provider}:${service}:${parent}`)
|
||||
}
|
||||
}
|
||||
|
||||
const pageCollections = result.filter((node): node is CollectionObject => node instanceof CollectionObject)
|
||||
const pageEntities = result.filter((node): node is EntityObject => node instanceof EntityObject)
|
||||
|
||||
collectionsStore.mergeMany(pageCollections)
|
||||
entitiesStore.mergeMany(pageEntities)
|
||||
|
||||
// The backend applies the range independently to each selected location.
|
||||
const counts = new Map<string, number>()
|
||||
for (const node of result) {
|
||||
const parent = isRoot(node.collection) ? ROOT_ID : String(node.collection)
|
||||
const key = `${node.provider}:${node.service}:${parent}`
|
||||
counts.set(key, (counts.get(key) ?? 0) + 1)
|
||||
}
|
||||
const isLastPage = range === undefined || [...counts.values()].every(count => count < range.tally)
|
||||
|
||||
return { collections: pageCollections, entities: pageEntities, isLastPage }
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to fetch nodes'
|
||||
throw e
|
||||
@@ -170,14 +198,12 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function createCollection(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
parentCollectionId: string | number | null,
|
||||
target: ServiceIdentifier | CollectionIdentifier,
|
||||
properties: CollectionMutableProperties,
|
||||
): Promise<CollectionObject> {
|
||||
error.value = null
|
||||
try {
|
||||
return await collectionsStore.create(providerId, serviceId, parentCollectionId, properties)
|
||||
return await collectionsStore.create(target, properties)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to create collection'
|
||||
throw e
|
||||
@@ -185,14 +211,12 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function updateCollection(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
identifier: string | number,
|
||||
target: CollectionIdentifier,
|
||||
properties: CollectionMutableProperties,
|
||||
): Promise<CollectionObject> {
|
||||
error.value = null
|
||||
try {
|
||||
return await collectionsStore.update(providerId, serviceId, identifier, properties)
|
||||
return await collectionsStore.update(target, properties)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to update collection'
|
||||
throw e
|
||||
@@ -200,13 +224,11 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function deleteCollection(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
identifier: string | number,
|
||||
target: CollectionIdentifier,
|
||||
): Promise<boolean> {
|
||||
error.value = null
|
||||
try {
|
||||
const response = await collectionsStore.delete(providerId, serviceId, identifier)
|
||||
const response = await collectionsStore.delete(target)
|
||||
return response.success
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to delete collection'
|
||||
@@ -215,15 +237,13 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function createEntity(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number,
|
||||
target: CollectionIdentifier,
|
||||
properties: DocumentInterface,
|
||||
options?: Record<string, unknown>,
|
||||
): Promise<EntityObject> {
|
||||
error.value = null
|
||||
try {
|
||||
return await entitiesStore.create(providerId, serviceId, collectionId, properties, options)
|
||||
return await entitiesStore.create(target, properties, options)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to create entity'
|
||||
throw e
|
||||
@@ -231,15 +251,12 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function updateEntity(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number,
|
||||
identifier: string | number,
|
||||
target: EntityIdentifier,
|
||||
properties: DocumentInterface,
|
||||
): Promise<EntityObject> {
|
||||
error.value = null
|
||||
try {
|
||||
return await entitiesStore.update(providerId, serviceId, collectionId, identifier, properties)
|
||||
return await entitiesStore.update(target, properties)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to update entity'
|
||||
throw e
|
||||
@@ -247,15 +264,12 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function deleteEntity(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number,
|
||||
identifier: string | number,
|
||||
target: EntityIdentifier,
|
||||
): Promise<boolean> {
|
||||
error.value = null
|
||||
try {
|
||||
const response = await entitiesStore.delete(providerId, serviceId, collectionId, identifier)
|
||||
return response.success
|
||||
const response = await entitiesStore.delete([target])
|
||||
return response.successes.includes(target)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to delete entity'
|
||||
throw e
|
||||
@@ -263,14 +277,11 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function readEntity(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number,
|
||||
identifier: string | number,
|
||||
target: EntityIdentifier,
|
||||
): Promise<string | null> {
|
||||
error.value = null
|
||||
try {
|
||||
return await entitiesStore.read(providerId, serviceId, collectionId, identifier)
|
||||
return await entitiesStore.read(target)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to read entity'
|
||||
throw e
|
||||
@@ -278,15 +289,12 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
async function writeEntity(
|
||||
providerId: string,
|
||||
serviceId: string | number,
|
||||
collectionId: string | number,
|
||||
identifier: string | number,
|
||||
target: EntityIdentifier,
|
||||
content: string,
|
||||
): Promise<number> {
|
||||
error.value = null
|
||||
try {
|
||||
return await entitiesStore.write(providerId, serviceId, collectionId, identifier, content)
|
||||
return await entitiesStore.write(target, content)
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to write entity'
|
||||
throw e
|
||||
@@ -294,8 +302,8 @@ export const useNodesStore = defineStore('documentsNodesStore', () => {
|
||||
}
|
||||
|
||||
function clearServiceNodes(providerId: string, serviceId: string | number): void {
|
||||
collectionsStore.clearService(providerId, serviceId)
|
||||
entitiesStore.clearService(providerId, serviceId)
|
||||
collectionsStore.clearService(`${providerId}:${serviceId}`)
|
||||
entitiesStore.clearService(`${providerId}:${serviceId}`)
|
||||
}
|
||||
|
||||
function clearNodes(): void {
|
||||
|
||||
Reference in New Issue
Block a user