Source: service/namespace-service.js

const Service = require('./service');
const HttpRequestBuilder = require('../http/http-request-builder');
const ServiceRequest = require('./service-request');
const PATH_NAMESPACES = require('./service-paths').PATH_NAMESPACES;

const RDFMimeType = require('../http/rdf-mime-type');
const Namespace = require('../model/namespace');

const LoggingUtils = require('../logging/logging-utils');
const StringUtils = require('../util/string-utils');

const DataFactory = require('n3').DataFactory;

/**
 * Service for namespace management.
 *
 * @author Mihail Radkov
 * @author Svilen Velikov
 */
class NamespaceService extends Service {
  /**
   * Retrieves all present namespaces as a collection of {@link Namespace}.
   *
   * @return {ServiceRequest} a service request resolving to a collection of
   * {@link Namespace}
   */
  getNamespaces() {
    const requestBuilder = HttpRequestBuilder.httpGet(PATH_NAMESPACES)
      .addAcceptHeader(RDFMimeType.SPARQL_RESULTS_JSON);

    return new ServiceRequest(requestBuilder, () => {
      return this.httpRequestExecutor(requestBuilder).then((response) => {
        this.logger.debug(LoggingUtils.getLogPayload(response),
          'Fetched namespaces');
        return this.mapNamespaceResponse(response.getData());
      });
    });
  }

  /**
   * Maps the response data from the namespaces request into {@link Namespace}.
   *
   * @private
   *
   * @param {object} responseData the data to map
   *
   * @return {Namespace[]} the mapped namespaces
   */
  mapNamespaceResponse(responseData) {
    return responseData.results.bindings.map((binding) => {
      const prefix = binding.prefix.value;
      const namespace = DataFactory.namedNode(binding.namespace.value);
      return new Namespace(prefix, namespace);
    });
  }

  /**
   * Retrieves the namespace for the given prefix as {@link NamedNode}.
   *
   * For example if <code>rdfs</code> is provided as prefix that would result in
   * a {@link NamedNode} corresponding to following namespace:
   * <code>http://www.w3.org/2000/01/rdf-schema#</code>
   *
   * Note: This method should be invoked only with prefixes. Anything else would
   * result in an error from the server.
   *
   * @param {string} prefix prefix of the namespace to be retrieved
   *
   * @return {ServiceRequest} service request resolving to {@link NamedNode}
   *
   * @throws {Error} if the prefix parameter is not supplied
   */
  getNamespace(prefix) {
    if (StringUtils.isBlank(prefix)) {
      throw new Error('Parameter prefix is required!');
    }

    const namespaceUrl = `${PATH_NAMESPACES}/${prefix}`;
    const requestBuilder = HttpRequestBuilder.httpGet(namespaceUrl);

    return new ServiceRequest(requestBuilder, () => {
      return this.httpRequestExecutor(requestBuilder).then((response) => {
        this.logger.debug(LoggingUtils.getLogPayload(response, {prefix}),
          'Fetched namespace');

        return DataFactory.namedNode(response.getData());
      });
    });
  }

  /**
   * Creates or updates the namespace for the given prefix.
   *
   * If the provided prefix or namespace parameter is not a string or
   * {@link NamedNode} then the method will throw an error.
   *
   * @param {string} prefix prefix of the namespace to be created/updated
   * @param {string|NamedNode} namespace the namespace to be created/updated
   *
   * @return {ServiceRequest} service request that will be resolved if the
   * create/update request is successful
   *
   * @throws {Error} if the prefix or namespace parameter are not provided
   */
  saveNamespace(prefix, namespace) {
    if (StringUtils.isBlank(prefix)) {
      throw new Error('Parameter prefix is required!');
    }

    let payload = namespace;
    if (namespace.termType && namespace.termType === 'NamedNode') {
      payload = namespace.value;
    } else if (StringUtils.isBlank(namespace)) {
      throw new Error('Parameter namespace is required!');
    }

    const requestBuilder = HttpRequestBuilder
      .httpPut(`${PATH_NAMESPACES}/${prefix}`)
      .setData(payload);

    return new ServiceRequest(requestBuilder, () => {
      return this.httpRequestExecutor(requestBuilder).then((response) => {
        this.logger.debug(LoggingUtils.getLogPayload(response,
          {prefix, namespace}), 'Saved namespace');
      });
    });
  }

  /**
   * Deletes a namespace that corresponds to the given prefix.
   *
   * For example if <code>rdfs</code> is provided as prefix that would delete
   * the following namespace: <code>http://www.w3.org/2000/01/rdf-schema#</code>
   *
   * Note: This method should be invoked only with prefixes. Anything else would
   * result in an error from the server.
   *
   * @param {string} prefix prefix of the namespace to be deleted
   *
   * @return {Promise<void>} promise that will be resolved if the deletion is
   * successful
   *
   * @throws {Error} if the prefix parameter is not provided
   */
  deleteNamespace(prefix) {
    if (StringUtils.isBlank(prefix)) {
      throw new Error('Parameter prefix is required!');
    }

    const requestBuilder = HttpRequestBuilder
      .httpDelete(`${PATH_NAMESPACES}/${prefix}`);

    return new ServiceRequest(requestBuilder, () => {
      return this.httpRequestExecutor(requestBuilder).then((response) => {
        this.logger.debug(LoggingUtils.getLogPayload(response, {prefix}),
          'Deleted namespace');
      });
    });
  }

  /**
   * Deletes all namespace declarations in the repository.
   *
   * @return {Promise<void>} promise that will be resolved after
   * successful deletion
   */
  deleteNamespaces() {
    const requestBuilder = HttpRequestBuilder.httpDelete(PATH_NAMESPACES);

    return new ServiceRequest(requestBuilder, () => {
      return this.httpRequestExecutor(requestBuilder).then((response) => {
        this.logger.debug(LoggingUtils.getLogPayload(response),
          'Deleted all namespaces');
      });
    });
  }

  /**
   * @inheritDoc
   */
  getServiceName() {
    return 'NamespaceService';
  }
}

module.exports = NamespaceService;