dataset.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /**
  2. * Backbone model denoting the remote Fuseki server.
  3. */
  4. define(
  5. function( require ) {
  6. "use strict";
  7. var Marionette = require( "marionette" ),
  8. Backbone = require( "backbone" ),
  9. _ = require( "underscore" ),
  10. fui = require( "app/fui" ),
  11. sprintf = require( "sprintf" ),
  12. Task = require( "app/models/task" );
  13. /**
  14. * This model represents the core representation of the remote Fuseki
  15. * server. Individual datasets have their own model.
  16. */
  17. var Dataset = Backbone.Model.extend( {
  18. initialize: function( datasetDescription, baseURL, mgmtURL ) {
  19. this.set( datasetDescription );
  20. this.set( {
  21. baseURL: baseURL,
  22. mgmtURL: mgmtURL,
  23. counts: {},
  24. countPerformed: false,
  25. counting: false,
  26. statistics: false
  27. } );
  28. },
  29. /* x is the empty object if baseURL is ""
  30. * Ensure it is always a string.
  31. */
  32. getStr: function(key) {
  33. var x = this.get( key );
  34. return jQuery.isEmptyObject(x) ? "" : x ;
  35. },
  36. baseURL: function() {
  37. return this.getStr( "baseURL" );
  38. },
  39. mgmtURL: function() {
  40. return this.getStr( "mgmtURL" );
  41. },
  42. mgmtActionURL: function() {
  43. return this.get( "mgmtURL" ) + this.name();
  44. },
  45. statisticsURL: function() {
  46. return sprintf( "%s/$/stats%s", this.baseURL(), this.name() );
  47. },
  48. name: function() {
  49. return this.get( "ds.name" );
  50. },
  51. services: function() {
  52. return this.get( "ds.services" );
  53. },
  54. countPerformed: function() {
  55. return this.get( "countPerformed" );
  56. },
  57. counts: function() {
  58. return this.get( "counts" );
  59. },
  60. serviceTypes: function() {
  61. return _.map( this.services(), function( s ) {return s["srv.type"];} );
  62. },
  63. /** Return a descriptive data-structure listing all this datasets services */
  64. servicesDescription: function() {
  65. var description = [];
  66. var self = this;
  67. _.each( this.services(), function( s ) {
  68. _.each( s["srv.endpoints"], function( e ) {
  69. description.push( {label: s["srv.description"],
  70. url: self.datasetEndpointURL( e )
  71. } );
  72. } );
  73. } );
  74. description.sort( function( d0, d1 ) {
  75. return (d0.label < d1.label) ? -1 : (d0.label > d1.label ? 1 : 0);
  76. } );
  77. return description;
  78. },
  79. /** Return the first service that has the given type */
  80. serviceOfType: function( serviceType ) {
  81. return _.find( this.services(), function( s ) {
  82. return s["srv.type"] === serviceType;
  83. } );
  84. },
  85. /** Return the first endpoint of the first service that has the given type */
  86. endpointOfType: function( serviceType ) {
  87. var service = this.serviceOfType( serviceType );
  88. return service && _.first( service["srv.endpoints"] );
  89. },
  90. /* Return URL for a service of a given type or null, if no such service */
  91. endpointURL: function( serviceType ) {
  92. var endpoint = this.endpointOfType( serviceType );
  93. return endpoint ? this.datasetEndpointURL( endpoint ) : null;
  94. },
  95. /** Return the URL for the given endpoint */
  96. datasetEndpointURL: function( endpoint ) {
  97. return sprintf( "%s%s/%s", this.baseURL(), this.name(), endpoint );
  98. },
  99. /** Return the sparql query URL for this dataset, if it has one, or null */
  100. queryURL: function() {
  101. return this.endpointURL( "Query" ) ;
  102. },
  103. /** Return the sparql query URL for this dataset, if it has one, or null */
  104. quadsURL: function() {
  105. return this.endpointURL( "Quads" ) ;
  106. },
  107. /** Return the sparql update URL for this dataset, if it has one, or null */
  108. updateURL: function() {
  109. return this.endpointURL( "Update" ) ;
  110. },
  111. /** Return the GSP write URL for this dataset, if it has one, or null */
  112. graphStoreProtocolURL: function() {
  113. if ( this.endpointURL( "GSP" ) )
  114. // Old name
  115. return this.endpointURL( "GSP" ) ;
  116. return this.endpointURL( "GSP_RW" ) ;
  117. },
  118. /** Return the GSP read URL for this dataset, if it has one, or null */
  119. graphStoreProtocolReadURL: function() {
  120. return this.endpointURL( "GSP_R" ) ;
  121. },
  122. /** Return the upload URL for this dataset, if it has one, or null */
  123. uploadURL: function( graphName ) {
  124. if (this.graphStoreProtocolURL() !== null) {
  125. return sprintf( "%s%s", this.graphStoreProtocolURL(), (graphName === "default" ? "" : ("?graph=" + graphName) ));
  126. }
  127. else {
  128. return null;
  129. }
  130. },
  131. /** Perform the action to delete the dataset. Returns the Ajax deferred object */
  132. deleteDataset: function() {
  133. return $.ajax( {
  134. url: this.mgmtActionURL(),
  135. type: 'DELETE'
  136. } );
  137. },
  138. /** Perform the action of taking a backup of this dataset */
  139. backupDataset: function() {
  140. var backupURL = sprintf( "%s/$/backup%s", this.baseURL(), this.name() );
  141. var ds = this;
  142. return $.ajax( {
  143. url: backupURL,
  144. type: 'POST'
  145. } )
  146. .done( function( taskDescription ) {
  147. new Task( ds, "backup", taskDescription );
  148. } );
  149. },
  150. /**
  151. * Request the statistics for this dataset, and return the promise object for the callback.
  152. * @param keep If truthy, and we have existing statistics, re-use the existing stats
  153. * */
  154. statistics: function( keep ) {
  155. var self = this;
  156. var currentStats = this.get( "statistics" );
  157. if (currentStats && keep) {
  158. return $.Deferred().resolveWith( null, currentStats );
  159. }
  160. else {
  161. return $.getJSON( this.statisticsURL() )
  162. .then( function( data ) {
  163. self.set( "statistics", data );
  164. return data;
  165. } );
  166. }
  167. },
  168. /** Perform a count query to determine the size of the dataset. Changes the size property when done,
  169. * but also returns the JQuery promise object used to monitor the query response */
  170. count: function() {
  171. var self = this;
  172. var query1 = sprintf( "select (count(*) as ?count) {?s ?p ?o}" );
  173. var query2 = sprintf( "select ?g (count(*) as ?count) {graph ?g {?s ?p ?o}} group by ?g" );
  174. self.set( "counting", true );
  175. var updateCount = function( model, result, graph ) {
  176. var n = parseInt( result.count.value );
  177. var counts = _.extend( {}, model.get( "counts" ) );
  178. counts[graph] = n;
  179. model.set( "counts", counts );
  180. };
  181. $.getJSON( self.queryURL(), { query: query1 } )
  182. .done( function( data ) {
  183. updateCount( self, data.results.bindings[0], "default graph" );
  184. $.getJSON( self.queryURL(), { query: query2 } )
  185. .done( function( data ) {
  186. _.each( data.results.bindings, function( binding ) {
  187. if (binding.g) {
  188. updateCount( self, binding, binding.g.value );
  189. }
  190. } );
  191. } );
  192. self.set( {countPerformed: true, counting: false} );
  193. } );
  194. },
  195. /**
  196. * Fetch the content of the given graph as Turtle. Return the jQuery promise
  197. * object for the Ajax call.
  198. */
  199. fetchGraph: function( graphName ) {
  200. return $.ajax( this.graphStoreProtocolReadURL(),
  201. {method: "get",
  202. headers: {Accept : "text/turtle; charset=utf-8"},
  203. dataType: "html",
  204. data: {graph: graphName}
  205. } );
  206. },
  207. /**
  208. * Put the given Turtle content back to the server using the given graph name
  209. */
  210. putGraph: function( turtle, graphName ) {
  211. return $.ajax( sprintf( "%s?graph=%s", this.graphStoreProtocolURL(), graphName ),
  212. {method: "put",
  213. dataType: "json",
  214. data: turtle,
  215. contentType: "text/turtle; charset=uft-8"
  216. } );
  217. }
  218. } );
  219. return Dataset;
  220. }
  221. );