Skip to content
File

Blob: src/worker/objects/common/collection-describe.ts

typescript60 lines
1import type {
2 CollectionDomainError,
3 DomainCollection,
4 DomainDescribeInput,
5 DomainObjectResources,
6} from "@/worker/objects/common/collection-types";
7 
8export interface CollectionDescribeSpec<
9 TDb,
10 TCollection extends DomainCollection,
11 TObject,
12 TResource extends { href: string; syncToken?: string },
13 TError extends CollectionDomainError,
14> {
15 collectionKind: string;
16 ensureCollection(db: TDb, subjectId: string, nowMs: number, collectionName: string): TCollection | null;
17 homeResource(db: TDb): TResource;
18 listCollections(db: TDb, subjectId: string, nowMs: number): TCollection[];
19 collectionResource(db: TDb, collection: TCollection): TResource;
20 objectByName(db: TDb, collectionId: string, objectName: string): TObject | undefined;
21 objectResource(db: TDb, collection: TCollection, object: TObject): TResource;
22 objectResources(db: TDb, collection: TCollection, maxResults: number): DomainObjectResources<TResource>;
23 syncToken(seq: number): string;
24 collectionNotFound(): TError;
25 objectNotFound(): TError;
26}
27 
28export function describeCollectionDomain<
29 TDb,
30 TCollection extends DomainCollection,
31 TObject,
32 TResource extends { href: string; syncToken?: string },
33 TError extends CollectionDomainError,
34>(
35 db: TDb,
36 input: DomainDescribeInput,
37 spec: CollectionDescribeSpec<TDb, TCollection, TObject, TResource, TError>,
38): { ok: true; resources: TResource[]; syncToken: string } | TError {
39 if (input.kind === "home") {
40 const collections = spec.listCollections(db, input.subjectId, input.nowMs);
41 return {
42 ok: true,
43 resources: [spec.homeResource(db), ...collections.map((collection) => spec.collectionResource(db, collection))],
44 syncToken: spec.syncToken(0),
45 };
46 }
47 
48 const collection = spec.ensureCollection(db, input.subjectId, input.nowMs, input.collectionName ?? "");
49 if (!collection) return spec.collectionNotFound();
50 if (input.kind === spec.collectionKind) {
51 const resources = [spec.collectionResource(db, collection)];
52 if (input.depth === "1") resources.push(...spec.objectResources(db, collection, input.maxResults).resources);
53 return { ok: true, resources, syncToken: resources[0]!.syncToken ?? spec.syncToken(0) };
54 }
55 
56 const object = spec.objectByName(db, collection.id, input.objectName ?? "");
57 if (!object) return spec.objectNotFound();
58 return { ok: true, resources: [spec.objectResource(db, collection, object)], syncToken: spec.syncToken(0) };
59}