Repository: solid/community-server
Pull request #393 (2020-12-04 14:35:09)

fix: Allow quad data for containers
This prevents the container data check from throwing an error when converting to quads if the incoming data already is quads.

Related to #384 but only solves part of it.


Patch:
diff --git a/src/storage/DataAccessorBasedStore.ts b/src/storage/DataAccessorBasedStore.ts
index f7514f70f..04a3a7382 100644
--- a/src/storage/DataAccessorBasedStore.ts
+++ b/src/storage/DataAccessorBasedStore.ts
@@ -1,3 +1,4 @@
+import arrayifyStream from 'arrayify-stream';
 import { DataFactory } from 'n3';
 import type { Quad } from 'rdf-js';
 import { v4 as uuid } from 'uuid';
@@ -240,7 +241,12 @@ export class DataAccessorBasedStore implements ResourceStore {
   protected async handleContainerData(representation: Representation): Promise<void> {
     let quads: Quad[];
     try {
-      quads = await parseQuads(representation.data);
+      // No need to parse the data if it already contains internal/quads
+      if (representation.metadata.contentType === INTERNAL_QUADS) {
+        quads = await arrayifyStream(representation.data);
+      } else {
+        quads = await parseQuads(representation.data);
+      }
     } catch (error: unknown) {
       if (error instanceof Error) {
         throw new BadRequestHttpError(`Can only create containers with RDF data. ${error.message}`);


Test patch:
diff --git a/test/unit/storage/DataAccessorBasedStore.test.ts b/test/unit/storage/DataAccessorBasedStore.test.ts
index 9d1721372..c24fc5060 100644
--- a/test/unit/storage/DataAccessorBasedStore.test.ts
+++ b/test/unit/storage/DataAccessorBasedStore.test.ts
@@ -17,6 +17,8 @@ import * as quadUtil from '../../../src/util/QuadUtil';
 import { guardedStreamFrom } from '../../../src/util/StreamUtil';
 import { CONTENT_TYPE, HTTP, LDP, RDF } from '../../../src/util/UriConstants';
 import { toNamedNode } from '../../../src/util/UriUtil';
+import quad = DataFactory.quad;
+import namedNode = DataFactory.namedNode;
 
 class SimpleDataAccessor implements DataAccessor {
   public readonly data: Record<string, Representation> = {};
@@ -295,6 +297,20 @@ describe('A DataAccessorBasedStore', (): void => {
       expect(accessor.data[resourceID.path].metadata.contentType).toBeUndefined();
     });
 
+    it('can write containers with quad data.', async(): Promise<void> => {
+      const resourceID = { path: `${root}container/` };
+
+      // Generate based on URI
+      representation.metadata.removeAll(RDF.type);
+      representation.metadata.contentType = 'internal/quads';
+      representation.data = guardedStreamFrom(
+        [ quad(namedNode(`${root}resource/`), namedNode('a'), namedNode('coolContainer')) ],
+      );
+      await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
+      expect(accessor.data[resourceID.path]).toBeTruthy();
+      expect(accessor.data[resourceID.path].metadata.contentType).toBeUndefined();
+    });
+
     it('errors when trying to create a container with containment triples.', async(): Promise<void> => {
       const resourceID = { path: `${root}container/` };
       representation.metadata.add(RDF.type, toNamedNode(LDP.Container));