From 02b2d90f2a9f1b881f38001de337f4ab3ec643ad Mon Sep 17 00:00:00 2001 From: Jackson Morgan Date: Tue, 14 Jan 2025 18:30:42 -0500 Subject: [PATCH] Complete type-index --- package-lock.json | 8 ++ packages/ldo/src/index.ts | 1 + packages/solid-type-index/package.json | 1 + packages/solid-type-index/src/constants.ts | 5 +- packages/solid-type-index/src/setTypeIndex.ts | 61 ++++++------ packages/solid-type-index/src/util/Options.ts | 5 +- .../solid-type-index/test/General.test.tsx | 95 +++++++++++++++++-- packages/solid/src/SolidLdoDataset.ts | 3 +- .../solid/src/SolidLdoTransactionDataset.ts | 14 ++- packages/solid/src/index.ts | 2 + packages/solid/src/types.ts | 6 +- 11 files changed, 155 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index 22f44a0..173d83b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29746,12 +29746,20 @@ "@rdfjs/types": "^1.0.1", "@testing-library/react": "^14.1.2", "@types/jest": "^27.0.3", + "@types/uuid": "^10.0.0", "jest-environment-jsdom": "^27.0.0", "start-server-and-test": "^2.0.3", "ts-jest": "^27.1.2", "ts-node": "^10.9.2" } }, + "packages/solid-type-index/node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, "packages/solid-type-index/node_modules/ts-jest": { "version": "27.1.5", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", diff --git a/packages/ldo/src/index.ts b/packages/ldo/src/index.ts index 77f5250..a951c44 100644 --- a/packages/ldo/src/index.ts +++ b/packages/ldo/src/index.ts @@ -7,3 +7,4 @@ export * from "./LdoBuilder"; export * from "./createLdoDataset"; import type { LdoBase as LdoBaseImport } from "./util"; export type LdoBase = LdoBaseImport; +export * from "./types"; diff --git a/packages/solid-type-index/package.json b/packages/solid-type-index/package.json index b53a786..e6a7c93 100644 --- a/packages/solid-type-index/package.json +++ b/packages/solid-type-index/package.json @@ -30,6 +30,7 @@ "@rdfjs/types": "^1.0.1", "@testing-library/react": "^14.1.2", "@types/jest": "^27.0.3", + "@types/uuid": "^10.0.0", "jest-environment-jsdom": "^27.0.0", "start-server-and-test": "^2.0.3", "ts-jest": "^27.1.2", diff --git a/packages/solid-type-index/src/constants.ts b/packages/solid-type-index/src/constants.ts index 4fc412b..830a590 100644 --- a/packages/solid-type-index/src/constants.ts +++ b/packages/solid-type-index/src/constants.ts @@ -1,4 +1,7 @@ export const RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"; export const TYPE_REGISTRATION = "http://www.w3.org/ns/solid/terms#TypeRegistration"; -export const FOR_CLASS = "http://www.w3.org/2006/vcard/ns#forClass"; +export const FOR_CLASS = "http://www.w3.org/ns/solid/terms#forClass"; +export const INSTANCE = "http://www.w3.org/ns/solid/terms#instance"; +export const INSTANCE_CONTAINER = + "http://www.w3.org/ns/solid/terms#instanceContainer"; diff --git a/packages/solid-type-index/src/setTypeIndex.ts b/packages/solid-type-index/src/setTypeIndex.ts index 747ac68..1c784dc 100644 --- a/packages/solid-type-index/src/setTypeIndex.ts +++ b/packages/solid-type-index/src/setTypeIndex.ts @@ -5,12 +5,13 @@ import { } from "./.ldo/typeIndex.shapeTypes"; import { FOR_CLASS, RDF_TYPE, TYPE_REGISTRATION } from "./constants"; import { guaranteeOptions, type Options } from "./util/Options"; -import { namedNode } from "@rdfjs/data-model"; +import { namedNode, quad } from "@rdfjs/data-model"; import type { TypeRegistration } from "./.ldo/typeIndex.typings"; import { getProfile } from "./getTypeIndex"; import { TypeIndexProfileShapeType } from "./.ldo/profile.shapeTypes"; -import type { SolidLdoDataset } from "@ldo/solid"; import type { Container } from "@ldo/solid"; +import type { ISolidLdoDataset } from "@ldo/solid"; +import type { NamedNode } from "@rdfjs/types"; /** * ============================================================================= @@ -32,7 +33,7 @@ export async function initTypeIndex( await createIndex(webId, profileFolder, dataset, true); } if (!profile.publicTypeIndex?.length) { - await createIndex(webId, profileFolder, dataset, true); + await createIndex(webId, profileFolder, dataset, false); } } } @@ -46,7 +47,7 @@ export async function initTypeIndex( export async function createIndex( webId, profileFolder: Container, - dataset: SolidLdoDataset, + dataset: ISolidLdoDataset, isPrivate: boolean, ) { // Create a private type index @@ -88,19 +89,9 @@ export async function createIndex( .write(indexResource.uri) .fromSubject(indexResource.uri); - console.log(indexResource.uri, webId); cTypeIndex.type = [{ "@id": "ListedDocument" }, { "@id": "TypeIndex" }]; - console.log("added", transaction.getChanges().added?.toString()); - console.log("removed", transaction.getChanges().added?.toString()); const commitResult = await transaction.commitToPod(); - if (commitResult.isError) { - commitResult.errors.forEach((err) => { - if (err.type === "invalidUriError") { - console.log(err.uri); - } - }); - throw commitResult; - } + if (commitResult.isError) throw commitResult; } /** @@ -148,6 +139,8 @@ export async function removeRegistration( options, ); + console.log(typeRegistration["@id"]); + // Add instances to type registration instances.instance?.forEach((instance) => { typeRegistration.instance?.splice( @@ -156,8 +149,9 @@ export async function removeRegistration( ); }); instances.instanceContainer?.forEach((instanceContainer) => { - typeRegistration.instance?.splice( - typeRegistration.instance.findIndex( + console.log("Splicing instanceContainers", instanceContainer); + typeRegistration.instanceContainer?.splice( + typeRegistration.instanceContainer.findIndex( (val) => val["@id"] === instanceContainer, ), 1, @@ -172,27 +166,40 @@ export function findAppropriateTypeRegistration( ) { const { dataset } = guaranteeOptions(options); // Check to see if its already in the index - const existingRegistrationUri: string | undefined = dataset + const existingRegistrationsUris: NamedNode[] = dataset .match( null, namedNode(RDF_TYPE), namedNode(TYPE_REGISTRATION), namedNode(indexUri), ) - .match(null, namedNode(FOR_CLASS), namedNode(classUri)) - .toArray()[0]?.subject.value; + .toArray() + .map((quad) => quad.subject) as NamedNode[]; + + const existingRegistrationForClassUri = existingRegistrationsUris.find( + (registrationUri) => { + return dataset.has( + quad( + registrationUri, + namedNode(FOR_CLASS), + namedNode(classUri), + namedNode(indexUri), + ), + ); + }, + )?.value; + let typeRegistration: TypeRegistration; - if (existingRegistrationUri) { + if (existingRegistrationForClassUri) { typeRegistration = dataset .usingType(TypeRegistrationShapeType) .write(indexUri) - .fromSubject(existingRegistrationUri); + .fromSubject(existingRegistrationForClassUri); } else { - typeRegistration = dataset.createData( - TypeRegistrationShapeType, - `${indexUri}#${v4()}`, - dataset.getResource(indexUri), - ); + typeRegistration = dataset + .usingType(TypeRegistrationShapeType) + .write(indexUri) + .fromSubject(`${indexUri}#${v4()}`); typeRegistration.type = { "@id": "TypeRegistration" }; typeRegistration.forClass = { "@id": classUri }; } diff --git a/packages/solid-type-index/src/util/Options.ts b/packages/solid-type-index/src/util/Options.ts index bc85a52..d551bf3 100644 --- a/packages/solid-type-index/src/util/Options.ts +++ b/packages/solid-type-index/src/util/Options.ts @@ -1,8 +1,9 @@ -import { createSolidLdoDataset, type SolidLdoDataset } from "@ldo/solid"; +import { createSolidLdoDataset } from "@ldo/solid"; +import type { ISolidLdoDataset } from "@ldo/solid"; import { guaranteeFetch } from "@ldo/solid/dist/util/guaranteeFetch"; export interface Options { - solidLdoDataset?: SolidLdoDataset; + solidLdoDataset?: ISolidLdoDataset; fetch?: typeof fetch; } diff --git a/packages/solid-type-index/test/General.test.tsx b/packages/solid-type-index/test/General.test.tsx index 346292d..7cf8380 100644 --- a/packages/solid-type-index/test/General.test.tsx +++ b/packages/solid-type-index/test/General.test.tsx @@ -2,18 +2,31 @@ import { createSolidLdoDataset } from "@ldo/solid"; import { MY_BOOKMARKS_1_URI, MY_BOOKMARKS_2_URI, + PRIVATE_TYPE_INDEX_URI, + PUBLIC_TYPE_INDEX_URI, + ROOT_CONTAINER, setupEmptyTypeIndex, setupFullTypeIndex, setUpServer, WEB_ID, } from "./setUpServer"; import { getInstanceUris, getTypeRegistrations } from "../src/getTypeIndex"; -import { initTypeIndex } from "../src/setTypeIndex"; +import { + addRegistration, + initTypeIndex, + removeRegistration, +} from "../src/setTypeIndex"; import { TypeIndexProfileShapeType } from "../src/.ldo/profile.shapeTypes"; +import { namedNode } from "@rdfjs/dataset"; +import { INSTANCE } from "../src/constants"; // Use an increased timeout, since the CSS server takes too much setup time. jest.setTimeout(40_000); +const ADDRESS_BOOK = "http://www.w3.org/2006/vcard/ns#AddressBook"; +const BOOKMARK = "http://www.w3.org/2002/01/bookmark#Bookmark"; +const EXAMPLE_THING = "https://example.com/ExampleThing"; + describe("General Tests", () => { const s = setUpServer(); @@ -25,7 +38,7 @@ describe("General Tests", () => { solidLdoDataset, }); const addressBookUris = await getInstanceUris( - "http://www.w3.org/2006/vcard/ns#AddressBook", + ADDRESS_BOOK, typeRegistrations, { solidLdoDataset }, ); @@ -35,11 +48,9 @@ describe("General Tests", () => { "https://example.com/myPublicAddressBook.ttl", ]), ); - const bookmarkUris = await getInstanceUris( - "http://www.w3.org/2002/01/bookmark#Bookmark", - typeRegistrations, - { solidLdoDataset }, - ); + const bookmarkUris = await getInstanceUris(BOOKMARK, typeRegistrations, { + solidLdoDataset, + }); expect(bookmarkUris).toEqual( expect.arrayContaining([MY_BOOKMARKS_1_URI, MY_BOOKMARKS_2_URI]), ); @@ -55,9 +66,73 @@ describe("General Tests", () => { const profile = solidLdoDataset .usingType(TypeIndexProfileShapeType) .fromSubject(WEB_ID); - console.log(solidLdoDataset.toString()); - expect(profile.privateTypeIndex?.["@id"]).toBeDefined(); - expect(profile.publicTypeIndex?.["@id"]).toBeDefined(); + expect(profile.privateTypeIndex?.[0]?.["@id"]).toBeDefined(); + expect(profile.publicTypeIndex?.[0]?.["@id"]).toBeDefined(); + }); + + it("Adds to the typeIndex", async () => { + await setupFullTypeIndex(s); + + const solidLdoDataset = createSolidLdoDataset(); + + await getTypeRegistrations(WEB_ID, { solidLdoDataset }); + + const transaction = solidLdoDataset.startTransaction(); + addRegistration( + PUBLIC_TYPE_INDEX_URI, + ADDRESS_BOOK, + { instance: ["https://example.com/AdressBook3"] }, + { solidLdoDataset: transaction }, + ); + addRegistration( + PRIVATE_TYPE_INDEX_URI, + EXAMPLE_THING, + { instanceContainer: ["https://example.com/ExampleInstance"] }, + { solidLdoDataset: transaction }, + ); + const { added, removed } = transaction.getChanges(); + + const existingRegistration = namedNode( + "http://localhost:3003/example/profile/publicTypeIndex.ttl#ab09fd", + ); + + expect(removed).not.toBeDefined(); + expect(added?.size).toBe(4); + expect(added?.match(existingRegistration).size).toBe(1); + expect( + added?.match( + existingRegistration, + namedNode(INSTANCE), + namedNode("https://example.com/AdressBook3"), + namedNode("http://localhost:3003/example/profile/publicTypeIndex.ttl"), + ).size, + ).toBe(1); + }); + + it("Removes from the typeIndex", async () => { + await setupFullTypeIndex(s); + + const solidLdoDataset = createSolidLdoDataset(); + + await getTypeRegistrations(WEB_ID, { solidLdoDataset }); + + const transaction = solidLdoDataset.startTransaction(); + removeRegistration( + PUBLIC_TYPE_INDEX_URI, + ADDRESS_BOOK, + { instance: ["https://example.com/myPublicAddressBook.ttl"] }, + { solidLdoDataset: transaction }, + ); + removeRegistration( + PRIVATE_TYPE_INDEX_URI, + BOOKMARK, + { instanceContainer: [`${ROOT_CONTAINER}myBookmarks/`] }, + { solidLdoDataset: transaction }, + ); + const { added, removed } = transaction.getChanges(); + + expect(added).not.toBeDefined(); + expect(removed?.size).toBe(2); }); }); diff --git a/packages/solid/src/SolidLdoDataset.ts b/packages/solid/src/SolidLdoDataset.ts index 034235d..d95bf44 100644 --- a/packages/solid/src/SolidLdoDataset.ts +++ b/packages/solid/src/SolidLdoDataset.ts @@ -15,6 +15,7 @@ import type { NoRootContainerError } from "./requester/results/error/NoRootConta import type { ReadResultError } from "./requester/requests/readResource"; import { ProfileWithStorageShapeType } from "./.ldo/solid.shapeTypes"; import type { GetStorageContainerFromWebIdSuccess } from "./requester/results/success/CheckRootContainerSuccess"; +import type { ISolidLdoDataset } from "./types"; /** * A SolidLdoDataset has all the functionality of an LdoDataset with the added @@ -41,7 +42,7 @@ import type { GetStorageContainerFromWebIdSuccess } from "./requester/results/su * .fromSubject("https://example.com/profile#me"); * ``` */ -export class SolidLdoDataset extends LdoDataset { +export class SolidLdoDataset extends LdoDataset implements ISolidLdoDataset { /** * @internal */ diff --git a/packages/solid/src/SolidLdoTransactionDataset.ts b/packages/solid/src/SolidLdoTransactionDataset.ts index f66265f..4a2306e 100644 --- a/packages/solid/src/SolidLdoTransactionDataset.ts +++ b/packages/solid/src/SolidLdoTransactionDataset.ts @@ -14,7 +14,6 @@ import { updateDatasetInBulk, type ITransactionDatasetFactory, } from "@ldo/subscribable-dataset"; -import type { SolidLdoDataset } from "./SolidLdoDataset"; import type { AggregateSuccess } from "./requester/results/success/SuccessResult"; import type { ResourceResult } from "./resource/resourceResult/ResourceResult"; import type { @@ -75,7 +74,7 @@ export class SolidLdoTransactionDataset * @param initialDataset - A set of triples to initialize this dataset */ constructor( - parentDataset: SolidLdoDataset, + parentDataset: ISolidLdoDataset, context: SolidLdoDatasetContext, datasetFactory: DatasetFactory, transactionDatasetFactory: ITransactionDatasetFactory, @@ -108,6 +107,15 @@ export class SolidLdoTransactionDataset return this.context.resourceStore.get(uri, options); } + public startTransaction(): SolidLdoTransactionDataset { + return new SolidLdoTransactionDataset( + this, + this.context, + this.datasetFactory, + this.transactionDatasetFactory, + ); + } + async commitToPod(): Promise< | AggregateSuccess< ResourceResult @@ -117,8 +125,6 @@ export class SolidLdoTransactionDataset const changes = this.getChanges(); const changesByGraph = splitChangesByGraph(changes); - console.log(changesByGraph); - // Iterate through all changes by graph in const results: [ GraphNode, diff --git a/packages/solid/src/index.ts b/packages/solid/src/index.ts index bb84a05..7692142 100644 --- a/packages/solid/src/index.ts +++ b/packages/solid/src/index.ts @@ -27,3 +27,5 @@ export * from "./resource/wac/results/GetWacRuleSuccess"; export * from "./resource/wac/results/GetWacUriSuccess"; export * from "./resource/wac/results/SetWacRuleSuccess"; export * from "./resource/wac/results/WacRuleAbsent"; + +export * from "./types"; \ No newline at end of file diff --git a/packages/solid/src/types.ts b/packages/solid/src/types.ts index e87f63c..91141ea 100644 --- a/packages/solid/src/types.ts +++ b/packages/solid/src/types.ts @@ -1,12 +1,16 @@ +import type { ILdoDataset } from "@ldo/ldo"; import type { ResourceGetterOptions } from "./ResourceStore"; import type { Container } from "./resource/Container"; import type { Leaf } from "./resource/Leaf"; import type { ContainerUri, LeafUri } from "./util/uriTypes"; +import type { SolidLdoTransactionDataset } from "./SolidLdoTransactionDataset"; /** * A SolidLdoDataset provides methods for getting Solid resources. */ -export interface ISolidLdoDataset { +export interface ISolidLdoDataset extends ILdoDataset { + startTransaction(): SolidLdoTransactionDataset; + getResource(uri: ContainerUri, options?: ResourceGetterOptions): Container; getResource(uri: LeafUri, options?: ResourceGetterOptions): Leaf; getResource(uri: string, options?: ResourceGetterOptions): Leaf | Container;