cartodb/lib/assets/javascripts/builder/editor/widgets/time-series-query-model.js
2020-06-15 10:58:47 +08:00

165 lines
4.1 KiB
JavaScript

var Backbone = require('backbone');
var cdb = require('internal-carto.js');
var _ = require('underscore');
var moment = require('moment');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var QUERY_TEMPLATE = _.template('SELECT MAX(<%= column %>), MIN(<%= column %>) FROM (<%= table %>) __wrapped');
var STATUS = {
unavailable: 'unavailable',
unfetched: 'unfetched',
fetching: 'fetching',
fetched: 'fetched'
};
var DEFAULT_MAX_BUCKETS = 367;
var REQUIRED_OPTS = [
'configModel',
'querySchemaModel'
];
module.exports = Backbone.Model.extend({
defaults: {
status: STATUS.unfetched,
buckets: []
},
initialize: function (attrs, opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
if (!_.has(attrs, 'column')) {
throw new Error('Column is required');
}
this._SQL = new cdb.SQL({
user: this._configModel.get('user_name'),
sql_api_template: this._configModel.get('sql_api_template'),
api_key: this._configModel.get('api_key')
});
this._initBinds();
if (this._querySchemaModel.get('status') === STATUS.fetched) {
this._queryData();
}
},
_initBinds: function () {
this.on('change:column', this._queryData, this);
this.listenTo(this._querySchemaModel, 'change:status', this._onQuerySchemaStatusChanged);
},
_onQuerySchemaStatusChanged: function () {
if (this._querySchemaModel.get('status') === STATUS.fetched) {
this._queryData();
}
},
_queryData: function () {
if (this._querySchemaModel.getColumnType(this.get('column')) !== 'date') {
return;
}
var query = QUERY_TEMPLATE({
column: this.get('column'),
table: this._querySchemaModel.get('query')
});
var callback = {
success: this._onQuerySuccess.bind(this),
error: this._onQueryError.bind(this)
};
this.set('status', STATUS.fetching);
this._SQL.execute(query, null, callback);
},
_onQuerySuccess: function (data) {
this.set('status', STATUS.fetched);
var row = data.rows && data.rows[0];
var max = row && row.max ? row.max : 0;
var min = row && row.min ? row.min : 0;
this._calculateBuckets(max, min);
},
_onQueryError: function () {
this.set('status', STATUS.unavailable);
},
_calculateDecadesDiff: function (start, end) {
var startYear = start.year();
var endYear = end.year();
var startDecade = Math.floor(startYear / 10);
var endDecade = Math.floor((endYear + 10) / 10);
return endDecade - startDecade;
},
_calculateBuckets: function (max, min) {
var end = moment(max).utc();
var start = moment(min).utc();
var BUCKET_INCREMENT = 1;
var buckets = [{
bins: end.diff(start, 'minutes', true),
val: 'minute',
label: 'Minutes'
}, {
bins: end.diff(start, 'hours', true),
val: 'hour',
label: 'Hours'
}, {
bins: end.diff(start, 'days', true),
val: 'day',
label: 'Days'
}, {
bins: end.diff(start, 'weeks', true),
val: 'week',
label: 'Weeks'
}, {
bins: end.diff(start, 'months', true),
val: 'month',
label: 'Months'
}, {
bins: end.diff(start, 'quarters', true),
val: 'quarter',
label: 'Quarters'
}, {
bins: end.diff(start, 'years', true),
val: 'year',
label: 'Years'
}, {
bins: this._calculateDecadesDiff(start, end),
val: 'decade',
label: 'Decades'
}];
var incrementedBuckets = _.map(buckets, function (bucket) {
var increment = bucket.val === 'decade'
? 0
: BUCKET_INCREMENT;
return _.extend(_.clone(bucket), {
bins: Math.ceil(bucket.bins) + increment
});
});
this.set('buckets', incrementedBuckets);
},
getFilteredBuckets: function (max) {
var limit = max || DEFAULT_MAX_BUCKETS;
var buckets = _.filter(this.get('buckets'), function (bucket) {
return bucket.bins <= limit;
});
return buckets;
},
getPreferredBucket: function (max) {
var sortedBuckets = _.sortBy(this.getFilteredBuckets(max), 'bins');
return sortedBuckets.length > 0 ? sortedBuckets[sortedBuckets.length - 1] : {};
}
});