Skip to content

Commit

Permalink
refactor: Add isContainerPath function
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimvh committed Nov 18, 2020
1 parent 1073c2f commit 75e4f73
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 15 deletions.
18 changes: 12 additions & 6 deletions src/storage/DataAccessorBasedStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ import { MethodNotAllowedHttpError } from '../util/errors/MethodNotAllowedHttpEr
import { NotFoundHttpError } from '../util/errors/NotFoundHttpError';
import { NotImplementedError } from '../util/errors/NotImplementedError';
import { UnsupportedHttpError } from '../util/errors/UnsupportedHttpError';
import { ensureTrailingSlash, getParentContainer, trimTrailingSlashes } from '../util/PathUtil';
import {
ensureTrailingSlash,
getParentContainer,
isContainerIdentifier,
isContainerPath,
trimTrailingSlashes,
} from '../util/PathUtil';
import { parseQuads } from '../util/QuadUtil';
import { generateResourceQuads } from '../util/ResourceUtil';
import { CONTENT_TYPE, HTTP, LDP, RDF } from '../util/UriConstants';
Expand Down Expand Up @@ -93,7 +99,7 @@ export class DataAccessorBasedStore implements ResourceStore {

// When a POST method request targets a non-container resource without an existing representation,
// the server MUST respond with the 404 status code.
if (!parentMetadata && !container.path.endsWith('/')) {
if (!parentMetadata && !isContainerIdentifier(container)) {
throw new NotFoundHttpError();
}

Expand All @@ -104,7 +110,7 @@ export class DataAccessorBasedStore implements ResourceStore {
const newID = this.createSafeUri(container, representation.metadata, parentMetadata);

// Write the data. New containers will need to be created if there is no parent.
await this.writeData(newID, representation, newID.path.endsWith('/'), !parentMetadata);
await this.writeData(newID, representation, isContainerIdentifier(newID), !parentMetadata);

return newID;
}
Expand All @@ -128,7 +134,7 @@ export class DataAccessorBasedStore implements ResourceStore {
if (oldMetadata && isContainer !== this.isExistingContainer(oldMetadata)) {
throw new ConflictHttpError('Input resource type does not match existing resource type.');
}
if (isContainer !== identifier.path.endsWith('/')) {
if (isContainer !== isContainerIdentifier(identifier)) {
throw new UnsupportedHttpError('Containers should have a `/` at the end of their path, resources should not.');
}

Expand Down Expand Up @@ -172,7 +178,7 @@ export class DataAccessorBasedStore implements ResourceStore {
* @param identifier - Identifier that needs to be checked.
*/
protected async getNormalizedMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
const hasSlash = identifier.path.endsWith('/');
const hasSlash = isContainerIdentifier(identifier);
try {
return await this.accessor.getMetadata(identifier);
} catch (error: unknown) {
Expand Down Expand Up @@ -312,7 +318,7 @@ export class DataAccessorBasedStore implements ResourceStore {
isContainer = this.isExistingContainer(metadata);
} catch {
const slug = suffix ?? metadata.get(HTTP.slug)?.value;
isContainer = Boolean(slug?.endsWith('/'));
isContainer = Boolean(slug && isContainerPath(slug));
}
return isContainer;
}
Expand Down
3 changes: 2 additions & 1 deletion src/storage/ExtensionBasedMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
decodeUriPathComponents,
encodeUriPathComponents,
ensureTrailingSlash,
isContainerIdentifier,
trimTrailingSlashes,
} from '../util/PathUtil';
import type { FileIdentifierMapper, ResourceLink } from './FileIdentifierMapper';
Expand Down Expand Up @@ -74,7 +75,7 @@ export class ExtensionBasedMapper implements FileIdentifierMapper {
let filePath = this.getAbsolutePath(path);

// Container
if (identifier.path.endsWith('/')) {
if (isContainerIdentifier(identifier)) {
this.logger.debug(`URL ${identifier.path} points to the container ${filePath}`);
return {
identifier,
Expand Down
9 changes: 5 additions & 4 deletions src/storage/accessors/FileDataAccessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ConflictHttpError } from '../../util/errors/ConflictHttpError';
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
import { isSystemError } from '../../util/errors/SystemError';
import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMediaTypeHttpError';
import { isContainerIdentifier } from '../../util/PathUtil';
import { parseQuads, pushQuad, serializeQuads } from '../../util/QuadUtil';
import { generateContainmentQuads, generateResourceQuads } from '../../util/ResourceUtil';
import { CONTENT_TYPE, DCTERMS, POSIX, RDF, XSD } from '../../util/UriConstants';
Expand Down Expand Up @@ -62,10 +63,10 @@ export class FileDataAccessor implements DataAccessor {
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
const link = await this.resourceMapper.mapUrlToFilePath(identifier);
const stats = await this.getStats(link.filePath);
if (!identifier.path.endsWith('/') && stats.isFile()) {
if (!isContainerIdentifier(identifier) && stats.isFile()) {
return this.getFileMetadata(link, stats);
}
if (identifier.path.endsWith('/') && stats.isDirectory()) {
if (isContainerIdentifier(identifier) && stats.isDirectory()) {
return this.getDirectoryMetadata(link, stats);
}
throw new NotFoundHttpError();
Expand Down Expand Up @@ -131,9 +132,9 @@ export class FileDataAccessor implements DataAccessor {
}
}

if (!identifier.path.endsWith('/') && stats.isFile()) {
if (!isContainerIdentifier(identifier) && stats.isFile()) {
await fsPromises.unlink(link.filePath);
} else if (identifier.path.endsWith('/') && stats.isDirectory()) {
} else if (isContainerIdentifier(identifier) && stats.isDirectory()) {
await fsPromises.rmdir(link.filePath);
} else {
throw new NotFoundHttpError();
Expand Down
4 changes: 2 additions & 2 deletions src/storage/accessors/InMemoryDataAccessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { NamedNode } from 'rdf-js';
import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata';
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
import { ensureTrailingSlash } from '../../util/PathUtil';
import { ensureTrailingSlash, isContainerIdentifier } from '../../util/PathUtil';
import { generateContainmentQuads, generateResourceQuads } from '../../util/ResourceUtil';
import type { DataAccessor } from './DataAccessor';

Expand Down Expand Up @@ -66,7 +66,7 @@ export class InMemoryDataAccessor implements DataAccessor {

public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
const entry = this.getEntry(identifier);
if (this.isDataEntry(entry) === identifier.path.endsWith('/')) {
if (this.isDataEntry(entry) === isContainerIdentifier(identifier)) {
throw new NotFoundHttpError();
}
return this.generateMetadata(identifier, entry);
Expand Down
4 changes: 2 additions & 2 deletions src/storage/accessors/SparqlDataAccessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { ConflictHttpError } from '../../util/errors/ConflictHttpError';
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
import { UnsupportedMediaTypeHttpError } from '../../util/errors/UnsupportedMediaTypeHttpError';
import { ensureTrailingSlash, getParentContainer } from '../../util/PathUtil';
import { ensureTrailingSlash, getParentContainer, isContainerIdentifier } from '../../util/PathUtil';
import { generateResourceQuads } from '../../util/ResourceUtil';
import { CONTENT_TYPE, LDP } from '../../util/UriConstants';
import { toNamedNode } from '../../util/UriUtil';
Expand Down Expand Up @@ -81,7 +81,7 @@ export class SparqlDataAccessor implements DataAccessor {
*/
public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {
const name = namedNode(identifier.path);
const query = identifier.path.endsWith('/') ?
const query = isContainerIdentifier(identifier) ?
this.sparqlConstructContainer(name) :
this.sparqlConstruct(this.getMetadataNode(name));
const stream = await this.sendSparqlConstruct(query);
Expand Down
12 changes: 12 additions & 0 deletions src/util/PathUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,15 @@ export const getParentContainer = (id: ResourceIdentifier): ResourceIdentifier =

return { path: parentPath };
};

/**
* Checks if the path corresponds to a container path (ending in a /).
* @param path - Path to check.
*/
export const isContainerPath = (path: string): boolean => path.endsWith('/');

/**
* Checks if the identifier corresponds to a container identifier.
* @param identifier - Identifier to check.
*/
export const isContainerIdentifier = (identifier: ResourceIdentifier): boolean => isContainerPath(identifier.path);

0 comments on commit 75e4f73

Please sign in to comment.