yahoo-swiv
Version:
A web-based exploratory visualization UI for Druid.io
287 lines (286 loc) • 13.9 kB
JavaScript
;
var yaml = require('js-yaml');
var index_1 = require('../../../common/models/index');
var labels_1 = require('../../../common/models/labels');
function spaces(n) {
return (new Array(n + 1)).join(' ');
}
function extend(a, b) {
for (var key in a) {
b[key] = a[key];
}
return b;
}
function yamlObject(lines, indent) {
if (indent === void 0) { indent = 2; }
var pad = spaces(indent);
return lines.map(function (line, i) {
if (line === '')
return '';
return pad + (i ? ' ' : '- ') + line;
});
}
function yamlPropAdder(lines, withComments, options) {
var object = options.object, propName = options.propName, defaultValue = options.defaultValue, comment = options.comment;
var value = object[propName];
if (value == null) {
if (withComments && typeof defaultValue !== "undefined") {
lines.push('', "# " + comment, "#" + propName + ": " + defaultValue + " # <- default");
}
}
else {
if (withComments)
lines.push('', "# " + comment);
lines.push(propName + ": " + value);
}
}
function getYamlPropAdder(object, labels, lines, withComments) {
if (withComments === void 0) { withComments = false; }
var adder = function (propName, additionalOptions) {
var propVerbiage = labels[propName];
var comment;
if (!propVerbiage) {
console.warn("No labels for " + propName + ", please fix this in 'common/models/labels.ts'");
comment = '';
}
else {
comment = propVerbiage.description;
}
var options = { object: object, propName: propName, comment: comment };
if (additionalOptions)
options = extend(additionalOptions, options);
yamlPropAdder(lines, withComments, options);
return { add: adder };
};
return { add: adder };
}
function clusterToYAML(cluster, withComments) {
var lines = [
("name: " + cluster.name)
];
var props = getYamlPropAdder(cluster, labels_1.CLUSTER, lines, withComments);
props
.add('type')
.add('host')
.add('version')
.add('timeout', { defaultValue: index_1.Cluster.DEFAULT_TIMEOUT })
.add('sourceListScan', { defaultValue: index_1.Cluster.DEFAULT_SOURCE_LIST_SCAN })
.add('sourceListRefreshOnLoad', { defaultValue: false })
.add('sourceListRefreshInterval', { defaultValue: index_1.Cluster.DEFAULT_SOURCE_LIST_REFRESH_INTERVAL })
.add('sourceReintrospectOnLoad', { defaultValue: false })
.add('sourceReintrospectInterval', { defaultValue: index_1.Cluster.DEFAULT_SOURCE_REINTROSPECT_INTERVAL });
if (withComments) {
lines.push('', "# Database specific (" + cluster.type + ") ===============");
}
switch (cluster.type) {
case 'druid':
props
.add('introspectionStrategy', { defaultValue: index_1.Cluster.DEFAULT_INTROSPECTION_STRATEGY })
.add('requestDecorator');
break;
case 'postgres':
case 'mysql':
props
.add('database')
.add('user')
.add('password');
break;
}
lines.push('');
return yamlObject(lines);
}
exports.clusterToYAML = clusterToYAML;
function collectionToYAML(collection, withComments) {
var lines = [
("name: " + collection.name)
];
var addProps = getYamlPropAdder(collection, labels_1.COLLECTION, lines, withComments);
addProps
.add('title')
.add('description');
lines.push('tiles:');
lines = lines.concat.apply(lines, collection.tiles.map(CollectionTileToYAML));
lines.push('');
return yamlObject(lines);
}
exports.collectionToYAML = collectionToYAML;
function CollectionTileToYAML(item) {
var lines = [
("name: " + item.name)
];
var addProps = getYamlPropAdder(item, labels_1.COLLECTION_ITEM, lines);
addProps
.add('title')
.add('description')
.add('group')
.add('dataCube');
lines.push("essence:");
lines.push(yaml.safeDump(item.essence.toJSON()));
lines.push('');
return yamlObject(lines);
}
exports.CollectionTileToYAML = CollectionTileToYAML;
function attributeToYAML(attribute) {
var lines = [
("name: " + attribute.name),
("type: " + attribute.type)
];
if (attribute.special) {
lines.push("special: " + attribute.special);
}
lines.push('');
return yamlObject(lines);
}
exports.attributeToYAML = attributeToYAML;
function dimensionToYAML(dimension) {
var lines = [
("name: " + dimension.name),
("title: " + dimension.title)
];
if (dimension.kind !== 'string') {
lines.push("kind: " + dimension.kind);
}
lines.push("formula: " + dimension.formula);
lines.push('');
return yamlObject(lines);
}
exports.dimensionToYAML = dimensionToYAML;
function measureToYAML(measure) {
var lines = [
("name: " + measure.name),
("title: " + measure.title)
];
if (measure.units) {
lines.push("units: " + measure.units);
}
lines.push("formula: " + measure.formula);
var format = measure.format;
if (!!format) {
lines.push("format: " + format);
}
lines.push('');
return yamlObject(lines);
}
exports.measureToYAML = measureToYAML;
function dataCubeToYAML(dataCube, withComments) {
var lines = [
("name: " + dataCube.name),
("title: " + dataCube.title),
("clusterName: " + dataCube.clusterName),
("source: " + dataCube.source)
];
var timeAttribute = dataCube.timeAttribute;
if (timeAttribute && !(dataCube.clusterName === 'druid' && timeAttribute.name === '__time')) {
if (withComments) {
lines.push("# The primary time attribute of the data refers to the attribute that must always be filtered on");
lines.push("# This is particularly useful for Druid data cubes as they must always have a time filter.");
}
lines.push("timeAttribute: " + timeAttribute.name, '');
}
var refreshRule = dataCube.refreshRule;
if (withComments) {
lines.push("# The refresh rule describes how often the data cube looks for new data. Default: 'query'/PT1M (every minute)");
}
lines.push("refreshRule:");
lines.push(" rule: " + refreshRule.rule);
if (refreshRule.time) {
lines.push(" time: " + refreshRule.time.toISOString());
}
lines.push('');
var addProps = getYamlPropAdder(dataCube, labels_1.DATA_CUBE, lines, withComments);
addProps
.add('defaultTimezone', { defaultValue: index_1.DataCube.DEFAULT_DEFAULT_TIMEZONE })
.add('defaultDuration', { defaultValue: index_1.DataCube.DEFAULT_DEFAULT_DURATION })
.add('defaultSortMeasure', { defaultValue: dataCube.getDefaultSortMeasure() });
var defaultSelectedMeasures = dataCube.defaultSelectedMeasures ? dataCube.defaultSelectedMeasures.toArray() : null;
if (withComments) {
lines.push('', "# The names of measures that are selected by default");
}
if (defaultSelectedMeasures) {
lines.push("defaultSelectedMeasures: " + JSON.stringify(defaultSelectedMeasures));
}
else if (withComments) {
lines.push("#defaultSelectedMeasures: []");
}
var defaultPinnedDimensions = dataCube.defaultPinnedDimensions ? dataCube.defaultPinnedDimensions.toArray() : null;
if (withComments) {
lines.push('', "# The names of dimensions that are pinned by default (in order that they will appear in the pin bar)");
}
if (defaultPinnedDimensions) {
lines.push('', "defaultPinnedDimensions: " + JSON.stringify(defaultPinnedDimensions));
}
else if (withComments) {
lines.push('', "#defaultPinnedDimensions: []");
}
var introspection = dataCube.getIntrospection();
if (withComments) {
lines.push("", "# How the dataset should be introspected", "# possible options are:", "# * none - Do not do any introspection, take what is written in the config as the rule of law.", "# * no-autofill - Introspect the datasource but do not automatically generate dimensions or measures", "# * autofill-dimensions-only - Introspect the datasource, automatically generate dimensions only", "# * autofill-measures-only - Introspect the datasource, automatically generate measures only", "# * autofill-all - (default) Introspect the datasource, automatically generate dimensions and measures");
}
lines.push("introspection: " + introspection);
var attributeOverrides = dataCube.attributeOverrides;
if (withComments) {
lines.push('', "# The list of attribute overrides in case introspection get something wrong");
}
lines.push('attributeOverrides:');
if (withComments) {
lines.push(" # A general attribute override looks like so:", " #", " # name: user_unique", " # ^ the name of the attribute (the column in the database)", " #", " # type: STRING", " # ^ (optional) plywood type of the attribute", " #", " # special: unique", " # ^ (optional) any kind of special significance associated with this attribute", "");
}
lines = lines.concat.apply(lines, attributeOverrides.map(attributeToYAML));
var dimensions = dataCube.dimensions.toArray();
if (withComments) {
lines.push('', "# The list of dimensions defined in the UI. The order here will be reflected in the UI");
}
lines.push('dimensions:');
if (withComments) {
lines.push(" # A general dimension looks like so:", " #", " # name: channel", " # ^ the name of the dimension as used in the URL (you should try not to change these)", " #", " # title: The Channel", " # ^ (optional) the human readable title. If not set a title is generated from the 'name'", " #", " # kind: string", " # ^ (optional) the kind of the dimension. Can be 'string', 'time', 'number', or 'boolean'. Defaults to 'string'", " #", " # formula: $channel", " # ^ (optional) the Plywood bucketing expression for this dimension. Defaults to '$name'", " # if, say, channel was called 'cnl' in the data you would put '$cnl' here", " # See also the expressions API reference: https://plywood.imply.io/expressions", " #", " # url: string", " # ^ (optional) a url (including protocol) associated with the dimension, with optional token '%s'", " # that is replaced by the dimension value to generate links specific to each value.", "");
}
lines = lines.concat.apply(lines, dimensions.map(dimensionToYAML));
if (withComments) {
lines.push(" # This is the place where you might want to add derived dimensions.", " #", " # Here are some examples of possible derived dimensions:", " #", " # - name: is_usa", " # title: Is USA?", " # formula: $country == 'United States'", " #", " # - name: file_version", " # formula: $filename.extract('(\\d+\\.\\d+\\.\\d+)')", "");
}
var measures = dataCube.measures.toArray();
if (withComments) {
lines.push('', "# The list of measures defined in the UI. The order here will be reflected in the UI");
}
lines.push("measures:");
if (withComments) {
lines.push(" # A general measure looks like so:", " #", " # name: avg_revenue", " # ^ the name of the dimension as used in the URL (you should try not to change these)", " #", " # title: Average Revenue", " # ^ (optional) the human readable title. If not set a title is generated from the 'name'", " #", " # formula: $main.sum($revenue) / $main.sum($volume) * 10", " # ^ (optional) the Plywood bucketing expression for this dimension.", " # Usually defaults to '$main.sum($name)' but if the name contains 'min' or 'max' will use that as the aggregate instead of sum.", " # this is the place to define your fancy formulas", "");
}
lines = lines.concat.apply(lines, measures.map(measureToYAML));
if (withComments) {
lines.push(" # This is the place where you might want to add derived measures (a.k.a Post Aggregators).", " #", " # Here are some examples of possible derived measures:", " #", " # - name: ecpm", " # title: eCPM", " # formula: $main.sum($revenue) / $main.sum($impressions) * 1000", " #", " # - name: usa_revenue", " # title: USA Revenue", " # formula: $main.filter($country == 'United States').sum($revenue)", "");
}
lines.push('');
return yamlObject(lines);
}
exports.dataCubeToYAML = dataCubeToYAML;
function appSettingsToYAML(appSettings, withComments, extra) {
if (extra === void 0) { extra = {}; }
var dataCubes = appSettings.dataCubes, clusters = appSettings.clusters, collections = appSettings.collections;
if (!dataCubes.length)
throw new Error('Could not find any data cubes, please verify network connectivity');
var lines = [];
if (extra.header && extra.version) {
lines.push("# generated by Swiv version " + extra.version, "# for a more detailed walk-through go to: https://github.com/yahoo/swiv/blob/v" + extra.version + "/docs/configuration.md", '');
}
if (extra.verbose) {
if (withComments) {
lines.push("# Run Swiv in verbose mode so it prints out the queries that it issues");
}
lines.push("verbose: true", '');
}
if (extra.port) {
if (withComments) {
lines.push("# The port on which the Swiv server will listen on");
}
lines.push("port: " + extra.port, '');
}
if (clusters.length) {
lines.push('clusters:');
lines = lines.concat.apply(lines, clusters.map(function (c) { return clusterToYAML(c, withComments); }));
}
lines.push('dataCubes:');
lines = lines.concat.apply(lines, dataCubes.map(function (d) { return dataCubeToYAML(d, withComments); }));
return lines.join('\n');
}
exports.appSettingsToYAML = appSettingsToYAML;