UNPKG

@gmod/jbrowse

Version:

JBrowse - client-side genome browser

168 lines (149 loc) 5.54 kB
define([ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/request/xhr', 'JBrowse/Store/SeqFeature', 'JBrowse/Store/DeferredStatsMixin', 'JBrowse/Store/SeqFeature/GlobalStatsEstimationMixin', 'JBrowse/Util', 'JBrowse/Model/SimpleFeature', 'dojo/io-query' ], function( declare, lang, array, xhr, SeqFeatureStore, DeferredStatsMixin, GlobalStatsEstimationMixin, Util, SimpleFeature, ioQuery ) { return declare( [ SeqFeatureStore, DeferredStatsMixin, GlobalStatsEstimationMixin ], /** * @lends JBrowse.Store.SeqFeature.SPARQL */ { /** * JBrowse feature backend to retrieve features from a SPARQL endpoint. * @constructs */ constructor: function(args) { this.url = this.urlTemplate; this.refSeq = args.refSeq; this.baseUrl = args.baseUrl; this.density = 0; this.url = Util.resolveUrl( this.baseUrl, Util.fillTemplate( args.urlTemplate, { 'refseq': this.refSeq.name } ) ); this.queryTemplate = args.queryTemplate; if( ! this.queryTemplate ) { console.error("No queryTemplate set for SPARQL backend, no data will be displayed"); } var thisB = this; this._estimateGlobalStats() .then( function( stats ) { thisB.globalStats = stats; thisB._deferred.stats.resolve( stats ); }, lang.hitch( this, '_failAllDeferred' ) ); }, // load: function() { // // ping the endpoint to see if it's there // dojo.xhrGet({ url: this.url+'?'+ioQuery.objectToQuery({ query: 'SELECT ?s WHERE { ?s ?p ?o } LIMIT 1' }), // handleAs: "text", // failOk: false, // load: Util.debugHandler( this, function(o) { this.loadSuccess(o); }), // error: dojo.hitch( this, function(error) { this.loadFail(error, this.url); } ) // }); // }, _makeQuery: function( query ) { if( this.config.variables ) query = dojo.mixin( dojo.mixin( {}, this.config.variables ), query ); return Util.fillTemplate( this.queryTemplate, query ); }, _getFeatures: function() { this.getFeatures.apply( this, arguments ); }, getFeatures: function( query, featCallback, finishCallback, errorCallback ) { if( this.queryTemplate ) { var thisB = this; var headers = { "Accept": "application/json" }; if(this.config.disablePreflight) { // https://www.sitepen.com/blog/2014/01/15/faq-cors-with-dojo/ headers["X-Requested-With"] = null; } xhr.get( this.url+'?'+ioQuery.objectToQuery({ query: this._makeQuery( query ) }), { headers: headers, handleAs: "json", failOk: true }) .then( function(o) { thisB._resultsToFeatures( o, featCallback ); finishCallback(); }, lang.hitch( this, '_failAllDeferred' ) ); } else { finishCallback(); } }, _resultsToFeatures: function( results, featCallback ) { var rows = ((results||{}).results||{}).bindings || []; if( ! rows.length ) return; var fields = results.head.vars; var requiredFields = ['start','end','strand','uniqueID']; for( var i = 0; i<requiredFields.length; i++ ) { if( fields.indexOf( requiredFields[i] ) == -1 ) { console.error("Required field "+requiredFields[i]+" missing from feature data"); return; } }; var seenFeatures = {}; array.forEach( rows, function( row ) { var f = { data: { subfeatures: [] } }; var data = f.data; array.forEach( fields, function(field) { if( field in row ) data[field] = row[field].value; }); data.start = parseInt( data.start ); data.end = parseInt( data.end ); data.strand = parseInt( data.strand ); var id = data.uniqueID; delete data.uniqueID; f.id = id; seenFeatures[ id ] = f; },this); // resolve subfeatures, keeping only top-level features in seenFeatures for( var id in seenFeatures ) { var f = seenFeatures[id]; var pid = f.data.parentUniqueID; delete f.data.parentUniqueID; if( pid ) { var p = seenFeatures[ pid ]; if( p ) { p.data.subfeatures.push( f.data ); delete seenFeatures[id]; } } } for( var id in seenFeatures ) { featCallback( new SimpleFeature( seenFeatures[id] ) ); } } }); });