pboyd04/CSDLParser

View on GitHub
lib/Metadata.js

Summary

Maintainability
A
0 mins
Test Coverage
const xmldoc = require('xmldoc');
const fs = require('fs');
const request = require('request');

const Reference = require('./Reference');
const Schema = require('./Schema');
const CSDLCache = require('./cache/csdlCache');

class Metadata {
  constructor(options) {
    this._options = {useLocal: null, useNetwork: true};
    this.References = [];
    this.setOptions(options);
  }

  setOptions(options) {
    if(options) {
      this._options = Object.assign(this._options, options);
    }
    if(this._options.cache === undefined) {
      this._options.cache = new CSDLCache(this._options.useLocal, this._options.useNetwork);
    }
    else {
      this._options.cache.useLocal = this._options.useLocal;
      this._options.cache.useNetwork = this._options.useNetwork;
    }
  }

  parse(string, callback) {
    let doc;
    try {
      doc = new xmldoc.XmlDocument(string);
    }
    catch(e) {
      callback(e, null);
      return;
    }
    let me = this;
    let arr = this.getChildElementPromises(doc);
    Promise.all(arr).then(() => {
      me._options.cache.addMetadata(me);
      callback(null, me);
    }).catch((e) => {
      callback(e, null);
    });
  }

  getChildElementPromises(doc) {
    let arr = [];
    let me = this;
    doc.eachChild(function(child) {
      let elemName = child.name;
      switch(elemName) {
        case 'Reference':
        case 'edmx:Reference':
          arr.push(me.getReferencePromise(child));
          break;
        case 'DataServices':
        case 'edmx:DataServices':
          arr.push(me.parseDataServices(child));
          break;
        default:
          arr.push(Promise.reject(new Error('Unknown element name '+elemName)));
          break;
      }
    });
    return arr;
  }

  getReferencePromise(child) {
    let ref = new Reference();
    ref.init(child);
    this.References.push(ref);
    return ref.bind(this._options.cache);
  }

  parseDataServices(element) {
    let me = this;
    let ret = Promise.resolve(null);
    element.eachChild(function(child) {
      let elemName = child.name;
      let namespace;
      switch(elemName) {
        case 'Schema':
          namespace = child.attr['Namespace'];
          me[namespace] = new Schema();
          me[namespace].init(child);
          break;
        default:
          ret = Promise.reject(new Error('Unknown element name '+elemName));
      }
    });
    return ret;
  }

  resolve() {
    if(this.References === undefined || this.References.length === 0) {
      return Promise.resolve(null);
    }
    return this._options.cache.waitForCoherent();
  }
}

module.exports.construct = Metadata;

module.exports.parseMetadata = function(string, options, callback) {
  var meta = new Metadata(options);
  meta.parse(string, (err, data) => {
    if(err) {
      callback(err, data);
      return;
    }
    let promise = data.resolve();
    promise.then(() => {
      callback(null, data);
    }).catch((e) => {
      callback(e, data);
    });
  }); 
}

module.exports.parseMetadataFile = function(filename, options, callback) {
  fs.readFile(filename, 'utf8', function(err, data) {
    if(err) {
      callback(err, null);
      return;
    }
    module.exports.parseMetadata(data, options, callback);
  });
}

module.exports.parseMetadataUri = function(uri, options, callback) {
  request.get(uri, function(error, request, body) {
    if(error) {
      callback(error, null);
      return;
    }
    module.exports.parseMetadata(body, options, callback);
  });
}
/* vim: set tabstop=2 shiftwidth=2 expandtab: */