Skip to content

Commit

Permalink
Fix deleting literals with different formats
Browse files Browse the repository at this point in the history
  • Loading branch information
NoelDeMartin committed Feb 17, 2025
1 parent 57ff3d0 commit 21f96a5
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 8 deletions.
8 changes: 5 additions & 3 deletions src/engines/SolidEngine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ describe('SolidEngine', () => {

expect(properties).toHaveLength(3);
expect(properties).toContainEqual(RDFResourceProperty.type(personUrl, IRI('foaf:Person')));
expect(properties).toContainEqual(RDFResourceProperty.literal(personUrl, IRI('foaf:name'), name));
expect(properties).toContainEqual(RDFResourceProperty.literal(personUrl, IRI('foaf:birthdate'), date));
expect(properties).toContainEqual(RDFResourceProperty.literal(personUrl, IRI('foaf:name'), name, name));
expect(properties).toContainEqual(
RDFResourceProperty.literal(personUrl, IRI('foaf:birthdate'), date, '1997-07-21T23:42:00.000Z'),
);
});

it('creates one container', async () => {
Expand Down Expand Up @@ -95,7 +97,7 @@ describe('SolidEngine', () => {

expect(properties).toHaveLength(2);
expect(properties).toContainEqual(RDFResourceProperty.type(documentUrl, LDP_CONTAINER));
expect(properties).toContainEqual(RDFResourceProperty.literal(documentUrl, IRI('rdfs:label'), name));
expect(properties).toContainEqual(RDFResourceProperty.literal(documentUrl, IRI('rdfs:label'), name, name));
});

it('fails creating documents if the provided url is already in use', async () => {
Expand Down
24 changes: 19 additions & 5 deletions src/solid/RDFResourceProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,23 @@ abstract class RDFResourceProperty {
);
}

const object = statement.object as Literal;

return this.literal(
resourceUrl,
statement.predicate.value,
this.castLiteralValue(statement.object.value, (statement.object as Literal).datatype.value),
this.castLiteralValue(statement.object.value, object.datatype.value),
object.value,
);
}

public static literal(
resourceUrl: string | null,
name: string,
value: LiteralValue,
originalValue?: unknown,
): RDFResourceProperty {
return new RDFResourceLiteralProperty(resourceUrl, name, value);
return new RDFResourceLiteralProperty(resourceUrl, name, value, originalValue);
}

public static reference(
Expand Down Expand Up @@ -133,8 +137,11 @@ abstract class RDFResourceProperty {
resourceUrl = resourceUrl ?? this.resourceUrl;

switch (this.type) {
case RDFResourcePropertyType.Literal:
return RDFResourceProperty.literal(resourceUrl, this.name, this.value as LiteralValue);
case RDFResourcePropertyType.Literal: {
const property = this as unknown as RDFResourceLiteralProperty;

return RDFResourceProperty.literal(resourceUrl, property.name, property.value, property.originalValue);
}
case RDFResourcePropertyType.Type:
return RDFResourceProperty.type(resourceUrl, this.value as string);
case RDFResourcePropertyType.Reference:
Expand Down Expand Up @@ -181,13 +188,20 @@ abstract class RDFResourceProperty {
class RDFResourceLiteralProperty extends RDFResourceProperty {

declare public readonly value: LiteralValue;
declare public readonly originalValue?: unknown;
public readonly type = RDFResourcePropertyType.Literal;

constructor(resourceUrl: string | null, name: string, value: LiteralValue) {
constructor(resourceUrl: string | null, name: string, value: LiteralValue, originalValue?: unknown) {
super(resourceUrl, name, value);

this.originalValue = originalValue;
}

protected getTurtleObject(): string {
if (this.originalValue && this.value instanceof Date) {
return `"${this.originalValue}"^^<${IRI('xsd:dateTime')}>`;
}

if (this.value instanceof Date) {
const digits = (...numbers: number[]) => numbers.map(number => number.toString().padStart(2, '0'));
const date = digits(
Expand Down
41 changes: 41 additions & 0 deletions src/solid/SolidClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,47 @@ describe('SolidClient', () => {
`);
});

it('updates documents using the same notation for deleted triples', async () => {
// Arrange
const documentUrl = faker.internet.url();
const url = `${documentUrl}#it`;
const data = `
@prefix purl: <http://purl.org/dc/terms/> .
@prefix xml: <http://www.w3.org/2001/XMLSchema#> .
<#it>
purl:created "2018-11-14T00:00:00Z"^^xml:dateTime ;
purl:modified "2018-11-14T00:00:00.000Z"^^xml:dateTime .
`;
const operations = [
new RemovePropertyOperation(url, 'http://purl.org/dc/terms/created'),
new RemovePropertyOperation(url, 'http://purl.org/dc/terms/modified'),
];

StubFetcher.addFetchResponse(data);
StubFetcher.addFetchResponse();

// Act
await client.updateDocument(documentUrl, operations);

// Assert
expect(StubFetcher.fetch).toHaveBeenCalledWith(
documentUrl,
{
method: 'PATCH',
headers: { 'Content-Type': 'application/sparql-update' },
body: expect.anything(),
},
);

expect(StubFetcher.fetchSpy.mock.calls[1]?.[1]?.body).toContain(
'"2018-11-14T00:00:00.000Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .',
);
expect(StubFetcher.fetchSpy.mock.calls[1]?.[1]?.body).toContain(
'"2018-11-14T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .',
);
});

it('updates container documents', async () => {
// Arrange
const containerUrl = urlResolveDirectory(faker.internet.url(), stringToSlug(faker.random.word()));
Expand Down

0 comments on commit 21f96a5

Please sign in to comment.