|
@@ -79,6 +79,11 @@ export type QueryFieldValue =
|
|
|
kind: 'field';
|
|
|
alias?: string;
|
|
|
}
|
|
|
+ | {
|
|
|
+ field: string;
|
|
|
+ kind: 'calculatedField';
|
|
|
+ alias?: string;
|
|
|
+ }
|
|
|
| {
|
|
|
field: string;
|
|
|
kind: 'equation';
|
|
@@ -857,6 +862,7 @@ export function parseArguments(functionText: string, columnText: string): string
|
|
|
// `|` is an invalid field character, so it is used to determine whether a field is an equation or not
|
|
|
const EQUATION_PREFIX = 'equation|';
|
|
|
const EQUATION_ALIAS_PATTERN = /^equation\[(\d+)\]$/;
|
|
|
+export const CALCULATED_FIELD_PREFIX = 'calculated|';
|
|
|
|
|
|
export function isEquation(field: string): boolean {
|
|
|
return field.startsWith(EQUATION_PREFIX);
|
|
@@ -933,11 +939,23 @@ export function generateAggregateFields(
|
|
|
return fields.map(field => ({field})) as Field[];
|
|
|
}
|
|
|
|
|
|
+export function isDerivedMetric(field: string): boolean {
|
|
|
+ return field.startsWith(CALCULATED_FIELD_PREFIX);
|
|
|
+}
|
|
|
+
|
|
|
+export function stripDerivedMetricsPrefix(field: string): string {
|
|
|
+ return field.replace(CALCULATED_FIELD_PREFIX, '');
|
|
|
+}
|
|
|
+
|
|
|
export function explodeFieldString(field: string, alias?: string): Column {
|
|
|
if (isEquation(field)) {
|
|
|
return {kind: 'equation', field: getEquation(field), alias};
|
|
|
}
|
|
|
|
|
|
+ if (isDerivedMetric(field)) {
|
|
|
+ return {kind: 'calculatedField', field: stripDerivedMetricsPrefix(field)};
|
|
|
+ }
|
|
|
+
|
|
|
const results = parseFunction(field);
|
|
|
|
|
|
if (results) {
|
|
@@ -961,6 +979,10 @@ export function generateFieldAsString(value: QueryFieldValue): string {
|
|
|
return value.field;
|
|
|
}
|
|
|
|
|
|
+ if (value.kind === 'calculatedField') {
|
|
|
+ return `${CALCULATED_FIELD_PREFIX}${value.field}`;
|
|
|
+ }
|
|
|
+
|
|
|
if (value.kind === 'equation') {
|
|
|
return `${EQUATION_PREFIX}${value.field}`;
|
|
|
}
|
|
@@ -1001,11 +1023,28 @@ export function isAggregateField(field: string): boolean {
|
|
|
}
|
|
|
|
|
|
export function isAggregateFieldOrEquation(field: string): boolean {
|
|
|
- return isAggregateField(field) || isAggregateEquation(field);
|
|
|
+ return isAggregateField(field) || isAggregateEquation(field) || isNumericMetrics(field);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Temporary hardcoded hack to enable testing derived metrics.
|
|
|
+ * Can be removed after we get rid of getAggregateFields
|
|
|
+ */
|
|
|
+export function isNumericMetrics(field: string): boolean {
|
|
|
+ return [
|
|
|
+ 'session.crash_free_rate',
|
|
|
+ 'session.crashed',
|
|
|
+ 'session.errored_preaggregated',
|
|
|
+ 'session.errored_set',
|
|
|
+ 'session.init',
|
|
|
+ ].includes(field);
|
|
|
}
|
|
|
|
|
|
export function getAggregateFields(fields: string[]): string[] {
|
|
|
- return fields.filter(field => isAggregateField(field) || isAggregateEquation(field));
|
|
|
+ return fields.filter(
|
|
|
+ field =>
|
|
|
+ isAggregateField(field) || isAggregateEquation(field) || isNumericMetrics(field)
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
export function getColumnsAndAggregates(fields: string[]): {
|
|
@@ -1022,13 +1061,14 @@ export function getColumnsAndAggregatesAsStrings(fields: QueryFieldValue[]): {
|
|
|
columns: string[];
|
|
|
fieldAliases: string[];
|
|
|
} {
|
|
|
+ // TODO(dam): distinguish between metrics, derived metrics and tags
|
|
|
const aggregateFields: string[] = [];
|
|
|
const nonAggregateFields: string[] = [];
|
|
|
const fieldAliases: string[] = [];
|
|
|
|
|
|
for (const field of fields) {
|
|
|
const fieldString = generateFieldAsString(field);
|
|
|
- if (field.kind === 'function') {
|
|
|
+ if (field.kind === 'function' || field.kind === 'calculatedField') {
|
|
|
aggregateFields.push(fieldString);
|
|
|
} else if (field.kind === 'equation') {
|
|
|
if (isAggregateEquation(fieldString)) {
|
|
@@ -1190,7 +1230,7 @@ export function fieldAlignment(
|
|
|
/**
|
|
|
* Match on types that are legal to show on a timeseries chart.
|
|
|
*/
|
|
|
-export function isLegalYAxisType(match: ColumnType) {
|
|
|
+export function isLegalYAxisType(match: ColumnType | MetricsType) {
|
|
|
return ['number', 'integer', 'duration', 'percentage'].includes(match);
|
|
|
}
|
|
|
|