datahub/dist/recline.dataset.min.js
2015-03-06 15:32:03 -03:00

1 line
14 KiB
JavaScript

this.recline=this.recline||{};this.recline.Model=this.recline.Model||{};(function(my){"use strict";var Deferred=typeof jQuery!=="undefined"&&jQuery.Deferred||_.Deferred;my.Dataset=Backbone.Model.extend({constructor:function Dataset(){Backbone.Model.prototype.constructor.apply(this,arguments)},initialize:function(){var self=this;_.bindAll(this,"query");this.backend=null;if(this.get("backend")){this.backend=this._backendFromString(this.get("backend"))}else{if(this.get("records")){this.backend=recline.Backend.Memory}}this.fields=new my.FieldList;this.records=new my.RecordList;this._changes={deletes:[],updates:[],creates:[]};this.facets=new my.FacetList;this.recordCount=null;this.queryState=new my.Query;this.queryState.bind("change facet:add",function(){self.query()});this._store=this.backend;this._handleResult=this.backend!=null&&_.has(this.backend,"handleQueryResult")?this.backend.handleQueryResult:this._handleQueryResult;if(this.backend==recline.Backend.Memory){this.fetch()}},sync:function(method,model,options){return this.backend.sync(method,model,options)},fetch:function(){var self=this;var dfd=new Deferred;if(this.backend!==recline.Backend.Memory){this.backend.fetch(this.toJSON()).done(handleResults).fail(function(args){dfd.reject(args)})}else{handleResults({records:this.get("records"),fields:this.get("fields"),useMemoryStore:true})}function handleResults(results){var fields=self.get("fields")||results.fields;var out=self._normalizeRecordsAndFields(results.records,fields);if(results.useMemoryStore){self._store=new recline.Backend.Memory.Store(out.records,out.fields)}self.set(results.metadata);self.fields.reset(out.fields);self.query().done(function(){dfd.resolve(self)}).fail(function(args){dfd.reject(args)})}return dfd.promise()},_normalizeRecordsAndFields:function(records,fields){if(!fields&&records&&records.length>0){if(records[0]instanceof Array){fields=records[0];records=records.slice(1)}else{fields=_.map(_.keys(records[0]),function(key){return{id:key}})}}if(fields&&fields.length>0&&(fields[0]===null||typeof fields[0]!="object")){var seen={};fields=_.map(fields,function(field,index){if(field===null){field=""}else{field=field.toString()}var fieldId=field.replace(/^\s+|\s+$/g,"");if(fieldId===""){fieldId="_noname_";field=fieldId}while(fieldId in seen){seen[field]+=1;fieldId=field+seen[field]}if(!(field in seen)){seen[field]=0}return{id:fieldId}})}if(records&&records.length>0&&records[0]instanceof Array){records=_.map(records,function(doc){var tmp={};_.each(fields,function(field,idx){tmp[field.id]=doc[idx]});return tmp})}return{fields:fields,records:records}},save:function(){var self=this;return this._store.save(this._changes,this.toJSON())},query:function(queryObj){var self=this;var dfd=new Deferred;this.trigger("query:start");if(queryObj){var attributes=queryObj;if(queryObj instanceof my.Query){attributes=queryObj.toJSON()}this.queryState.set(attributes,{silent:true})}var actualQuery=this.queryState.toJSON();this._store.query(actualQuery,this.toJSON()).done(function(queryResult){self._handleResult(queryResult);self.trigger("query:done");dfd.resolve(self.records)}).fail(function(args){self.trigger("query:fail",args);dfd.reject(args)});return dfd.promise()},_handleQueryResult:function(queryResult){var self=this;self.recordCount=queryResult.total;var docs=_.map(queryResult.hits,function(hit){var _doc=new my.Record(hit);_doc.fields=self.fields;_doc.bind("change",function(doc){self._changes.updates.push(doc.toJSON())});_doc.bind("destroy",function(doc){self._changes.deletes.push(doc.toJSON())});return _doc});self.records.reset(docs);if(queryResult.facets){var facets=_.map(queryResult.facets,function(facetResult,facetId){facetResult.id=facetId;return new my.Facet(facetResult)});self.facets.reset(facets)}},toTemplateJSON:function(){var data=this.toJSON();data.recordCount=this.recordCount;data.fields=this.fields.toJSON();return data},getFieldsSummary:function(){var self=this;var query=new my.Query;query.set({size:0});this.fields.each(function(field){query.addFacet(field.id)});var dfd=new Deferred;this._store.query(query.toJSON(),this.toJSON()).done(function(queryResult){if(queryResult.facets){_.each(queryResult.facets,function(facetResult,facetId){facetResult.id=facetId;var facet=new my.Facet(facetResult);self.fields.get(facetId).facets.reset(facet)})}dfd.resolve(queryResult)});return dfd.promise()},recordSummary:function(record){return record.summary()},_backendFromString:function(backendString){var backend=null;if(recline&&recline.Backend){_.each(_.keys(recline.Backend),function(name){if(name.toLowerCase()===backendString.toLowerCase()){backend=recline.Backend[name]}})}return backend}});my.Record=Backbone.Model.extend({constructor:function Record(){Backbone.Model.prototype.constructor.apply(this,arguments)},initialize:function(){_.bindAll(this,"getFieldValue")},getFieldValue:function(field){var val=this.getFieldValueUnrendered(field);if(field&&!_.isUndefined(field.renderer)){val=field.renderer(val,field,this.toJSON())}return val},getFieldValueUnrendered:function(field){if(!field){return""}var val=this.get(field.id);if(field.deriver){val=field.deriver(val,field,this)}return val},summary:function(record){var self=this;var html='<div class="recline-record-summary">';this.fields.each(function(field){if(field.id!="id"){html+='<div class="'+field.id+'"><strong>'+field.get("label")+"</strong>: "+self.getFieldValue(field)+"</div>"}});html+="</div>";return html},fetch:function(){},save:function(){},destroy:function(){this.trigger("destroy",this)}});my.RecordList=Backbone.Collection.extend({constructor:function RecordList(){Backbone.Collection.prototype.constructor.apply(this,arguments)},model:my.Record});my.Field=Backbone.Model.extend({constructor:function Field(){Backbone.Model.prototype.constructor.apply(this,arguments)},defaults:{label:null,type:"string",format:null,is_derived:false},initialize:function(data,options){if("0"in data){throw new Error("Looks like you did not pass a proper hash with id to Field constructor")}if(this.attributes.label===null){this.set({label:this.id})}if(this.attributes.type.toLowerCase()in this._typeMap){this.attributes.type=this._typeMap[this.attributes.type.toLowerCase()]}if(options){this.renderer=options.renderer;this.deriver=options.deriver}if(!this.renderer){this.renderer=this.defaultRenderers[this.get("type")]}this.facets=new my.FacetList},_typeMap:{text:"string","double":"number","float":"number",numeric:"number","int":"integer",datetime:"date-time",bool:"boolean",timestamp:"date-time",json:"object"},defaultRenderers:{object:function(val,field,doc){return JSON.stringify(val)},geo_point:function(val,field,doc){return JSON.stringify(val)},number:function(val,field,doc){var format=field.get("format");if(format==="percentage"){return val+"%"}return val},string:function(val,field,doc){var format=field.get("format");if(format==="markdown"){if(typeof Showdown!=="undefined"){var showdown=new Showdown.converter;out=showdown.makeHtml(val);return out}else{return val}}else if(format=="plain"){return val}else{if(val&&typeof val==="string"){val=val.replace(/(https?:\/\/[^ ]+)/g,'<a href="$1">$1</a>')}return val}}}});my.FieldList=Backbone.Collection.extend({constructor:function FieldList(){Backbone.Collection.prototype.constructor.apply(this,arguments)},model:my.Field});my.Query=Backbone.Model.extend({constructor:function Query(){Backbone.Model.prototype.constructor.apply(this,arguments)},defaults:function(){return{size:100,from:0,q:"",facets:{},filters:[]}},_filterTemplates:{term:{type:"term",field:"",term:""},range:{type:"range",from:"",to:""},geo_distance:{type:"geo_distance",distance:10,unit:"km",point:{lon:0,lat:0}}},addFilter:function(filter){var ourfilter=JSON.parse(JSON.stringify(filter));if(_.keys(filter).length<=3){ourfilter=_.defaults(ourfilter,this._filterTemplates[filter.type])}var filters=this.get("filters");filters.push(ourfilter);this.trigger("change:filters:new-blank")},replaceFilter:function(filter){var filters=this.get("filters");var idx=-1;_.each(this.get("filters"),function(f,key,list){if(filter.field==f.field){idx=key}});if(idx>=0){filters.splice(idx,1);this.set({filters:filters})}this.addFilter(filter)},updateFilter:function(index,value){},removeFilter:function(filterIndex){var filters=this.get("filters");filters.splice(filterIndex,1);this.set({filters:filters});this.trigger("change")},addFacet:function(fieldId,size,silent){var facets=this.get("facets");if(_.contains(_.keys(facets),fieldId)){return}facets[fieldId]={terms:{field:fieldId}};if(!_.isUndefined(size)){facets[fieldId].terms.size=size}this.set({facets:facets},{silent:true});if(!silent){this.trigger("facet:add",this)}},addHistogramFacet:function(fieldId){var facets=this.get("facets");facets[fieldId]={date_histogram:{field:fieldId,interval:"day"}};this.set({facets:facets},{silent:true});this.trigger("facet:add",this)},removeFacet:function(fieldId){var facets=this.get("facets");if(!_.contains(_.keys(facets),fieldId)){return}delete facets[fieldId];this.set({facets:facets},{silent:true});this.trigger("facet:remove",this)},clearFacets:function(){var facets=this.get("facets");_.each(_.keys(facets),function(fieldId){delete facets[fieldId]});this.trigger("facet:remove",this)},refreshFacets:function(){this.trigger("facet:add",this)}});my.Facet=Backbone.Model.extend({constructor:function Facet(){Backbone.Model.prototype.constructor.apply(this,arguments)},defaults:function(){return{_type:"terms",total:0,other:0,missing:0,terms:[]}}});my.FacetList=Backbone.Collection.extend({constructor:function FacetList(){Backbone.Collection.prototype.constructor.apply(this,arguments)},model:my.Facet});my.ObjectState=Backbone.Model.extend({})})(this.recline.Model);this.recline=this.recline||{};this.recline.Backend=this.recline.Backend||{};this.recline.Backend.Memory=this.recline.Backend.Memory||{};(function(my){"use strict";my.__type__="memory";var Deferred=typeof jQuery!=="undefined"&&jQuery.Deferred||_.Deferred;my.Store=function(records,fields){var self=this;this.records=records;this.data=this.records;if(fields){this.fields=fields}else{if(records){this.fields=_.map(records[0],function(value,key){return{id:key,type:"string"}})}}this.update=function(doc){_.each(self.records,function(internalDoc,idx){if(doc.id===internalDoc.id){self.records[idx]=doc}})};this.remove=function(doc){var newdocs=_.reject(self.records,function(internalDoc){return doc.id===internalDoc.id});this.records=newdocs};this.save=function(changes,dataset){var self=this;var dfd=new Deferred;_.each(changes.updates,function(record){self.update(record)});_.each(changes.deletes,function(record){self.remove(record)});dfd.resolve();return dfd.promise()},this.query=function(queryObj){var dfd=new Deferred;var numRows=queryObj.size||this.records.length;var start=queryObj.from||0;var results=this.records;results=this._applyFilters(results,queryObj);results=this._applyFreeTextQuery(results,queryObj);_.each(queryObj.sort,function(sortObj){var fieldName=sortObj.field;results=_.sortBy(results,function(doc){var _out=doc[fieldName];return _out});if(sortObj.order=="desc"){results.reverse()}});var facets=this.computeFacets(results,queryObj);var out={total:results.length,hits:results.slice(start,start+numRows),facets:facets};dfd.resolve(out);return dfd.promise()};this._applyFilters=function(results,queryObj){var filters=queryObj.filters;var filterFunctions={term:term,terms:terms,range:range,geo_distance:geo_distance};var dataParsers={integer:function(e){return parseFloat(e,10)},"float":function(e){return parseFloat(e,10)},number:function(e){return parseFloat(e,10)},string:function(e){return e.toString()},date:function(e){return moment(e).valueOf()},datetime:function(e){return new Date(e).valueOf()}};var keyedFields={};_.each(self.fields,function(field){keyedFields[field.id]=field});function getDataParser(filter){var fieldType=keyedFields[filter.field].type||"string";return dataParsers[fieldType]}return _.filter(results,function(record){var passes=_.map(filters,function(filter){return filterFunctions[filter.type](record,filter)});return _.all(passes,_.identity)});function term(record,filter){var parse=getDataParser(filter);var value=parse(record[filter.field]);var term=parse(filter.term);return value===term}function terms(record,filter){var parse=getDataParser(filter);var value=parse(record[filter.field]);var terms=parse(filter.terms).split(",");return _.indexOf(terms,value)>=0}function range(record,filter){var fromnull=_.isUndefined(filter.from)||filter.from===null||filter.from==="";var tonull=_.isUndefined(filter.to)||filter.to===null||filter.to==="";var parse=getDataParser(filter);var value=parse(record[filter.field]);var from=parse(fromnull?"":filter.from);var to=parse(tonull?"":filter.to);if((!fromnull||!tonull)&&value===""){return false}return(fromnull||value>=from)&&(tonull||value<=to)}function geo_distance(){}};this._applyFreeTextQuery=function(results,queryObj){if(queryObj.q){var terms=queryObj.q.split(" ");var patterns=_.map(terms,function(term){return new RegExp(term.toLowerCase())});results=_.filter(results,function(rawdoc){var matches=true;_.each(patterns,function(pattern){var foundmatch=false;_.each(self.fields,function(field){var value=rawdoc[field.id];if(value!==null&&value!==undefined){value=value.toString()}else{value=""}foundmatch=foundmatch||pattern.test(value.toLowerCase())});matches=matches&&foundmatch});return matches})}return results};this.computeFacets=function(records,queryObj){var facetResults={};if(!queryObj.facets){return facetResults}_.each(queryObj.facets,function(query,facetId){facetResults[facetId]=new recline.Model.Facet({id:facetId}).toJSON();facetResults[facetId].termsall={}});_.each(records,function(doc){_.each(queryObj.facets,function(query,facetId){var fieldId=query.terms.field;var val=doc[fieldId];var tmp=facetResults[facetId];if(val){tmp.termsall[val]=tmp.termsall[val]?tmp.termsall[val]+1:1}else{tmp.missing=tmp.missing+1}})});_.each(queryObj.facets,function(query,facetId){var tmp=facetResults[facetId];var terms=_.map(tmp.termsall,function(count,term){return{term:term,count:count}});tmp.terms=_.sortBy(terms,function(item){return-item.count});tmp.terms=tmp.terms.slice(0,10)});return facetResults}}})(this.recline.Backend.Memory);