Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
var BaseCollection = require('./data-observatory-base-collection');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
// Interpolation boundary tag filters geometries to only show full coverage geometries
var FILTER_CLIPPED_GEOMS_IF_EXISTS = 'WHERE CASE WHEN EXISTS(SELECT 1 as cond FROM _data WHERE geom_tags ?\'boundary_type/tags.interpolation_boundary\' group by cond) THEN geom_tags ? \'boundary_type/tags.interpolation_boundary\' ELSE true END';
var ORDER_CLAUSE_GEOMS = 'ORDER BY geom_weight::numeric DESC;';
var COMMON_DATA_QUERY = 'bounds => (SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), numer_id => {{{ measurement }}}, number_geometries => (SELECT CDB_EstimateRowCount(\'{{{ query }}}\')::INTEGER)';
var BOUNDARIES_QUERY_PLAIN = 'WITH _data as (SELECT * FROM OBS_GetAvailableGeometries( ' + COMMON_DATA_QUERY + ' ) denoms WHERE valid_numer IS TRUE) SELECT *, rank() OVER (ORDER BY score DESC) FROM _data ' + FILTER_CLIPPED_GEOMS_IF_EXISTS + ' ' + ORDER_CLAUSE_GEOMS;
var BOUNDARIES_QUERY_NORMALIZE = 'WITH _data as (SELECT * FROM OBS_GetAvailableGeometries(' + COMMON_DATA_QUERY + ', denom_id => {{{ denom_id }}}) denoms WHERE valid_numer IS TRUE AND valid_denom IS TRUE) SELECT *, rank() OVER (ORDER BY score DESC) FROM _data ' + FILTER_CLIPPED_GEOMS_IF_EXISTS + ' ' + ORDER_CLAUSE_GEOMS;
var BOUNDARIES_QUERY_TIMESPAN = 'WITH _data as (SELECT * FROM OBS_GetAvailableGeometries(' + COMMON_DATA_QUERY + ', timespan => {{{ timespan }}}) denoms WHERE valid_numer IS TRUE AND valid_timespan = TRUE) SELECT *, rank() OVER (ORDER BY score DESC) FROM _data ' + FILTER_CLIPPED_GEOMS_IF_EXISTS + ' ' + ORDER_CLAUSE_GEOMS;
var BOUNDARIES_QUERY_NORMALIZE_TIMESPAN = 'WITH _data as (SELECT * FROM OBS_GetAvailableGeometries(' + COMMON_DATA_QUERY + ', denom_id => {{{ denom_id }}}, timespan => {{{ timespan }}}) denoms WHERE valid_numer IS TRUE AND valid_denom IS TRUE AND valid_timespan is TRUE) SELECT *, rank() OVER (ORDER BY score DESC) FROM _data ' + FILTER_CLIPPED_GEOMS_IF_EXISTS + ' ' + ORDER_CLAUSE_GEOMS;
module.exports = BaseCollection.extend({
model: function (attrs, opts) {
// label and val to custom list compatibility
var o = {};
o.val = attrs.geom_id;
o.label = attrs.geom_name;
o.rank = attrs.rank;
return new BaseModel(o);
},
getLabels: function () {
return this.pluck('label');
},
getValues: function () {
return this.pluck('val');
},
getPreSelectedBoundaryValue: function () {
var boundary = this.models.filter(
function (boundary) { return boundary.attributes.rank === 1; }
).shift();
return boundary && boundary.attributes && boundary.attributes.val;
},
buildQuery: function (options) {
if (options.denom_id != null && options.timespan != null) {
return BOUNDARIES_QUERY_NORMALIZE_TIMESPAN;
} else {
if (options.denom_id != null) {
return BOUNDARIES_QUERY_NORMALIZE;
} else if (options.timespan != null) {
return BOUNDARIES_QUERY_TIMESPAN;
} else {
return BOUNDARIES_QUERY_PLAIN;
}
}
}
});

View File

@@ -0,0 +1,74 @@
var _ = require('underscore');
var $ = require('jquery');
var cdb = require('internal-carto.js');
var errorParse = require('builder/helpers/error-parser');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'configModel',
'nodeDefModel'
];
var OBS_META_QUERY = 'SELECT OBS_GetMeta((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), {{{ metadata }}})';
var ColumnName = function (options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
this._querySchemaModel = this._nodeDefModel.querySchemaModel;
this.isFetching = false;
var configModel = options.configModel;
this.SQL = new cdb.SQL({
user: configModel.get('user_name'),
sql_api_template: configModel.get('sql_api_template'),
api_key: configModel.get('api_key')
});
};
ColumnName.prototype = {
buildQuery: function () {
return OBS_META_QUERY;
},
buildQueryOptions: function (options) {
return {
metadata: "'[" + JSON.stringify(options) + "]'",
query: this._querySchemaModel.get('query')
};
},
fetch: function (options) {
if (!options.numer_id) {
return;
}
this._success = options && options.success;
this._error = options && options.error;
var deferred = $.Deferred();
var queryOptions = this.buildQueryOptions(_.omit(options, 'sucess', 'error'));
var sqlQuery = this.buildQuery();
if (!this.isFetching) {
this.isFetching = true;
this.SQL.execute(sqlQuery, queryOptions, {
success: function (data) {
this.isFetching = false;
this._success && this._success(data);
deferred.resolve();
}.bind(this),
error: function (err) {
this.isFetching = false;
this._error && this._error(errorParse(err));
deferred.reject();
}.bind(this)
});
} else {
deferred.reject();
}
return deferred.promise();
}
};
module.exports = ColumnName;

View File

@@ -0,0 +1,105 @@
var Backbone = require('backbone');
var _ = require('underscore');
var $ = require('jquery');
var cdb = require('internal-carto.js');
var errorParse = require('builder/helpers/error-parser');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var CustomListCollection = require('builder/components/custom-list/custom-list-collection');
var REQUIRED_OPTS = [
'configModel',
'nodeDefModel'
];
module.exports = CustomListCollection.extend({
initialize: function (models, options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
this._querySchemaModel = this._nodeDefModel.querySchemaModel;
var configModel = options.configModel;
this.SQL = new cdb.SQL({
user: configModel.get('user_name'),
sql_api_template: configModel.get('sql_api_template'),
api_key: configModel.get('api_key')
});
this.stateModel = new Backbone.Model({
state: 'unfetched'
});
CustomListCollection.prototype.initialize.call(this, models, options);
},
_onSelectedChange: function (changedModel, isSelected) {
if (this.type === 'multiple') {
return;
}
if (isSelected) {
this.each(function (m) {
if (m.cid !== changedModel.cid) {
m.set({ selected: false }, { silent: true });
}
}, this);
}
},
buildQuery: function () {
throw new Error('subclasses of DataObservatoryBaseCollection must implement buildQuery');
},
fetch: function (options) {
this._success = options && options.success;
this._error = options && options.error;
var defaults = {
filters: null,
measurement: null,
normalize: null,
timespan: null,
query: this._querySchemaModel.get('query')
};
this.deferred = $.Deferred();
var queryOptions = _.defaults(options, defaults);
var sqlQuery = this.buildQuery(queryOptions);
this.stateModel.set('state', 'fetching');
this.SQL.execute(sqlQuery, queryOptions, {
success: function (data) {
this._onFetchSuccess(data);
this.stateModel.set('state', 'fetched');
this.deferred.resolve();
this._success && this._success();
}.bind(this),
error: function (err) {
this.stateModel.set('state', 'error');
this.deferred.reject();
this._error && this._error(errorParse(err));
}.bind(this)
});
return this.deferred.promise();
},
_onFetchSuccess: function (data) {
var models = data.rows;
this.reset(models);
},
isFetching: function () {
return this.getState() === 'fetching';
},
getState: function () {
return this.stateModel.get('state');
},
getItem: function (value) {
return this.findWhere({ val: value });
},
isAsync: function () {
return true;
}
});

View File

@@ -0,0 +1,63 @@
var _ = require('underscore');
var BaseCollection = require('./data-observatory-base-collection');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
var FILTERS_QUERY_WITH_REGION = "SELECT count(*) num_measurements, tag.key subsection_id, tag.value subsection_name FROM OBS_GetAvailableNumerators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), {{{ region }}}) numers, Jsonb_Each(numers.numer_tags) tag WHERE tag.key like 'subsection%' GROUP BY tag.key, tag.value";
module.exports = BaseCollection.extend({
initialize: function (models, options) {
this.type = 'multiple';
BaseCollection.prototype.initialize.call(this, models, options);
},
model: function (attrs, opts) {
// label and val to custom list compatibility
var o = {};
o.val = attrs.subsection_id;
o.label = attrs.subsection_name;
o.items = attrs.num_measurements;
return new BaseModel(o);
},
setSelected: function (value) {
var silentTrue = { silent: true };
if (_.isArray(value)) {
this.each(function (mdl) {
if (_.contains(value, mdl.getValue())) {
mdl.set({
selected: true
}, silentTrue);
} else {
mdl.set({
selected: false
}, silentTrue);
}
});
} else {
this.each(function (mdl) {
if (mdl.getValue() === value) {
mdl.set({
selected: true
}, silentTrue);
} else {
mdl.set({
selected: false
}, silentTrue);
}
});
}
},
getSelected: function () {
return this.filter(function (mdl) {
return mdl.get('selected') === true;
});
},
buildQuery: function (options) {
return FILTERS_QUERY_WITH_REGION;
}
});

View File

@@ -0,0 +1,111 @@
var _ = require('underscore');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
var $ = require('jquery');
var cdb = require('internal-carto.js');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'configModel',
'nodeDefModel'
];
var MEASUREMENT_ATTRIBUTES = ['aggregate', 'type', 'label', 'val', 'description', 'filter', 'license'];
var MEASUREMENT_BY_ID = 'SELECT numer_id, numer_name, numer_description, numer_type, numer_aggregate, numer_tags FROM _OBS_GetNumerators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), section_tags => {{{ area }}}, ids => {{{ measurement }}})';
module.exports = BaseModel.extend({
initialize: function (attrs, options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
this._querySchemaModel = this._nodeDefModel.querySchemaModel;
var configModel = options.configModel;
this.SQL = new cdb.SQL({
user: configModel.get('user_name'),
sql_api_template: configModel.get('sql_api_template'),
api_key: configModel.get('api_key')
});
BaseModel.prototype.initialize.call(this, attrs, options);
},
fetch: function (options) {
var defaults = {
area: null,
measurement: null,
query: this._querySchemaModel.get('query')
};
this.deferred = $.Deferred();
var queryOptions = _.defaults(options, defaults);
this.set('state', 'fetching');
this.SQL.execute(MEASUREMENT_BY_ID, queryOptions, {
success: function (data) {
this._onFetchSuccess(data);
this.set('state', 'fetched');
this.deferred.resolve();
}.bind(this),
error: function () {
this.set('state', 'error');
this.deferred.reject();
}.bind(this)
});
return this.deferred.promise();
},
isFetching: function () {
return this.getState() === 'fetching';
},
getState: function () {
return this.get('state');
},
_onFetchSuccess: function (data) {
var model = _.first(data.rows);
if (!model) {
this._clear();
return;
}
var o = {};
// label and val to custom list compatibility
o.val = model.numer_id;
o.label = model.numer_name;
o.description = model.numer_description;
o.type = model.numer_type;
o.aggregate = model.numer_aggregate;
// a measurement can belong to more than one category (filter)
o.filter = [];
var tags = model.numer_tags;
if (!_.isObject(tags)) {
tags = JSON.parse(tags);
}
for (var key in tags) {
if (/^subsection/.test(key)) {
o.filter.push({
id: key,
name: tags[key]
});
}
if (/^license/.test(key)) {
o.license = tags[key];
}
}
this.set(o);
},
_clear: function (options) {
var attrs = MEASUREMENT_ATTRIBUTES.reduce(function (memo, attr) {
memo[attr] = null;
return memo;
}, {});
this.set(attrs, {silent: true});
}
});

View File

@@ -0,0 +1,72 @@
var _ = require('underscore');
var BaseCollection = require('./data-observatory-base-collection');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
var MEASUREMENTS_QUERY_WITH_REGION = 'SELECT numer_id, numer_name, numer_description, numer_type, numer_aggregate, numer_tags FROM _OBS_GetNumerators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), section_tags => {{{ region }}}) ORDER BY numer_name ASC';
var MEASUREMENTS_QUERY_WITH_FILTERS = 'SELECT numer_id, numer_name, numer_description, numer_type, numer_aggregate, numer_tags FROM _OBS_GetNumerators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), section_tags => {{{ region }}}, subsection_tags => {{{ filters }}})';
var MEASUREMENTS_QUERY_SEARCH = "SELECT numer_id, numer_name, numer_description, numer_type, numer_aggregate, numer_tags FROM _OBS_GetNumerators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), section_tags => {{{ region }}}, name => '{{{ search }}}')";
var MEASUREMENTS_QUERY_SEARCH_AND_FILTERS = "SELECT numer_id, numer_name, numer_description, numer_type, numer_aggregate, numer_tags FROM _OBS_GetNumerators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), section_tags => {{{ region }}} , name => '{{{ search }}}', subsection_tags => {{{ filters }}})";
module.exports = BaseCollection.extend({
model: function (attrs, opts) {
return new BaseModel(attrs, opts);
},
_onFetchSuccess: function (data) {
var models = data.rows;
models = _.map(models, function (model) {
var o = {};
// label and val to custom list compatibility
o.val = model.numer_id;
o.label = model.numer_name;
o.description = model.numer_description;
o.type = model.numer_type;
o.aggregate = model.numer_aggregate;
// a measurement can belong to more than one category (filter)
o.filter = [];
var tags = model.numer_tags;
if (!_.isObject(tags)) {
tags = JSON.parse(tags);
}
for (var key in tags) {
if (/^subsection/.test(key)) {
o.filter.push({
id: key,
name: tags[key]
});
}
if (/^license/.test(key)) {
o.license = tags[key];
}
}
return o;
}).filter(function (model) {
return model.filter.length > 0;
});
this.reset(models);
},
buildQuery: function (options) {
if (options && options.search && options.filters) {
return MEASUREMENTS_QUERY_SEARCH_AND_FILTERS;
} else if (options && options.filters) {
return MEASUREMENTS_QUERY_WITH_FILTERS;
} else if (options && options.search) {
return MEASUREMENTS_QUERY_SEARCH;
} else {
return MEASUREMENTS_QUERY_WITH_REGION;
}
},
search: function () {
return this;
}
});

View File

@@ -0,0 +1,19 @@
var BaseCollection = require('./data-observatory-base-collection');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
var NORMALIZE_QUERY_WITH_MEASUREMENT = 'SELECT * FROM OBS_GetAvailableDenominators((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), NULL, {{{ measurement }}}) denoms WHERE valid_numer IS TRUE';
module.exports = BaseCollection.extend({
model: function (attrs, opts) {
// label and val to custom list compatibility
var o = {};
o.val = attrs.denom_id;
o.label = attrs.denom_name;
return new BaseModel(o);
},
buildQuery: function (options) {
return NORMALIZE_QUERY_WITH_MEASUREMENT;
}
});

View File

@@ -0,0 +1,35 @@
var BaseCollection = require('./data-observatory-base-collection');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
var REGIONS_QUERY = "SELECT count(*) num_measurements, tag.key region_id, tag.value region_name FROM (SELECT * FROM OBS_GetAvailableNumerators() WHERE jsonb_pretty(numer_tags) LIKE '%subsection/%') numers, Jsonb_Each(numers.numer_tags) tag WHERE tag.key like 'section%' GROUP BY tag.key, tag.value ORDER BY region_name";
module.exports = BaseCollection.extend({
buildQuery: function () {
return REGIONS_QUERY;
},
model: function (attrs, opts) {
// label and val to custom list compatibility
var o = {};
o.val = attrs.region_id;
o.label = attrs.region_name.replace(/["]+/g, '');
o.renderOptions = {
measurements: attrs.num_measurements
};
return new BaseModel(o);
},
fetch: function (options) {
this.stateModel.set('state', 'fetching');
// check if the geometry type is available, if not wait until it's finished
if (this._nodeDefModel.queryGeometryModel.isFetched()) {
BaseCollection.prototype.fetch.call(this, options);
} else {
this._nodeDefModel.queryGeometryModel.once('change:status', function () {
BaseCollection.prototype.fetch.call(this, options);
}, this);
}
}
});

View File

@@ -0,0 +1,32 @@
var BaseCollection = require('./data-observatory-base-collection');
var BaseModel = require('builder/components/custom-list/custom-list-item-model');
var TIMESPAN_QUERY_WITH_NORMALIZE = 'SELECT * FROM OBS_GetAvailableTimespans((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), NULL, {{{ measurement }}}, {{{ denom_id }}}) denoms WHERE valid_numer IS TRUE AND (valid_denom IS TRUE OR {{{ denom_id }}} IS NULL) ORDER BY timespan_name DESC';
var TIMESPAN_QUERY_WITHOUT_NORMALIZE = 'SELECT * FROM OBS_GetAvailableTimespans((SELECT ST_SetSRID(ST_Extent(the_geom), 4326) FROM ({{{ query }}}) q), NULL, {{{ measurement }}}, NULL) denoms WHERE valid_numer IS TRUE ORDER BY timespan_name DESC';
module.exports = BaseCollection.extend({
model: function (attrs, opts) {
// label and val to custom list compatibility
var o = {};
o.val = attrs.timespan_id;
o.label = attrs.timespan_name;
return new BaseModel(o);
},
buildQuery: function (options) {
if (options.denom_id != null) {
return TIMESPAN_QUERY_WITH_NORMALIZE;
} else {
return TIMESPAN_QUERY_WITHOUT_NORMALIZE;
}
},
selectFirstAsDefault: function () {
var first = this.first();
if (first) {
this.setSelected(first.getValue());
}
}
});