This commit is contained in:
Carl-Gerhard Lindesvärd
2025-11-20 13:56:58 +01:00
parent 00e25ed4b8
commit dd71fd4e11
15 changed files with 1357 additions and 190 deletions

View File

@@ -175,8 +175,8 @@ export function getChartSql({
if (event.segment === 'property_sum' && event.property) {
if (event.property === 'revenue') {
sb.select.count = `sum(revenue) as count`;
sb.where.property = `revenue > 0`;
sb.select.count = 'sum(revenue) as count';
sb.where.property = 'revenue > 0';
} else {
sb.select.count = `sum(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
@@ -185,8 +185,8 @@ export function getChartSql({
if (event.segment === 'property_average' && event.property) {
if (event.property === 'revenue') {
sb.select.count = `avg(revenue) as count`;
sb.where.property = `revenue > 0`;
sb.select.count = 'avg(revenue) as count';
sb.where.property = 'revenue > 0';
} else {
sb.select.count = `avg(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
@@ -195,8 +195,8 @@ export function getChartSql({
if (event.segment === 'property_max' && event.property) {
if (event.property === 'revenue') {
sb.select.count = `max(revenue) as count`;
sb.where.property = `revenue > 0`;
sb.select.count = 'max(revenue) as count';
sb.where.property = 'revenue > 0';
} else {
sb.select.count = `max(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
@@ -205,8 +205,8 @@ export function getChartSql({
if (event.segment === 'property_min' && event.property) {
if (event.property === 'revenue') {
sb.select.count = `min(revenue) as count`;
sb.where.property = `revenue > 0`;
sb.select.count = 'min(revenue) as count';
sb.where.property = 'revenue > 0';
} else {
sb.select.count = `min(toFloat64(${getSelectPropertyKey(event.property)})) as count`;
sb.where.property = `${getSelectPropertyKey(event.property)} IS NOT NULL AND notEmpty(${getSelectPropertyKey(event.property)})`;
@@ -230,16 +230,13 @@ export function getChartSql({
return sql;
}
// Add total unique count for user segment using a scalar subquery
if (event.segment === 'user') {
const totalUniqueSubquery = `(
const totalUniqueSubquery = `(
SELECT ${sb.select.count}
FROM ${sb.from}
${getJoins()}
${getWhere()}
)`;
sb.select.total_unique_count = `${totalUniqueSubquery} as total_count`;
}
sb.select.total_unique_count = `${totalUniqueSubquery} as total_count`;
const sql = `${getSelect()} ${getFrom()} ${getJoins()} ${getWhere()} ${getGroupBy()} ${getOrderBy()} ${getFill()}`;
console.log('-- Report --');

View File

@@ -7,6 +7,8 @@ import type {
IChartBreakdown,
IChartEvent,
IChartEventFilter,
IChartEventItem,
IChartFormula,
IChartLineType,
IChartProps,
IChartRange,
@@ -31,11 +33,39 @@ export function transformFilter(
};
}
export function transformReportEvent(
event: Partial<IChartEvent>,
export function transformReportEventItem(
item: Partial<IChartEventItem> | Partial<IChartEvent>,
index: number,
): IChartEvent {
): IChartEventItem {
// If item already has type field, it's the new format
if (item && typeof item === 'object' && 'type' in item) {
if (item.type === 'formula') {
// Transform formula
const formula = item as Partial<IChartFormula>;
return {
type: 'formula',
id: formula.id ?? alphabetIds[index]!,
formula: formula.formula || '',
displayName: formula.displayName,
};
}
// Transform event with type field
const event = item as Partial<IChartEvent>;
return {
type: 'event',
segment: event.segment ?? 'event',
filters: (event.filters ?? []).map(transformFilter),
id: event.id ?? alphabetIds[index]!,
name: event.name || 'unknown_event',
displayName: event.displayName,
property: event.property,
};
}
// Old format without type field - assume it's an event
const event = item as Partial<IChartEvent>;
return {
type: 'event',
segment: event.segment ?? 'event',
filters: (event.filters ?? []).map(transformFilter),
id: event.id ?? alphabetIds[index]!,
@@ -45,13 +75,31 @@ export function transformReportEvent(
};
}
// Keep the old function for backward compatibility, but it now uses the new transformer
export function transformReportEvent(
event: Partial<IChartEvent>,
index: number,
): IChartEvent {
const transformed = transformReportEventItem(event, index);
if (transformed.type === 'event') {
return transformed;
}
// This shouldn't happen for old code, but handle it gracefully
throw new Error('transformReportEvent called on a formula');
}
export function transformReport(
report: DbReport & { layout?: ReportLayout | null },
): IChartProps & { id: string; layout?: ReportLayout | null } {
// Events can be either old format (IChartEvent[]) or new format (IChartEventItem[])
const eventsData = report.events as unknown as Array<
Partial<IChartEventItem> | Partial<IChartEvent>
>;
return {
id: report.id,
projectId: report.projectId,
events: (report.events as IChartEvent[]).map(transformReportEvent),
events: eventsData.map(transformReportEventItem),
breakdowns: report.breakdowns as IChartBreakdown[],
chartType: report.chartType,
lineType: (report.lineType as IChartLineType) ?? lineTypes.monotone,