Розробка конструктора звітів
Конструктор звітів—це UI, який дозволяє користувачам самостійно формувати запит до даних: вибирати поля, фільтри, групування, тип візуалізації—та зберігати як назване звіти. На відміну від Pivot Table, він працює на вищому рівні абстракції: користувачі оперують бізнес-поняттями (замовлення, клієнти, регіони), а не сирими полями таблиці.
Архітектура
Конструктор звітів складається з чотирьох шарів:
Metadata Layer—каталог доступних сутностей та полів із людиночитаємими назвами, типами, дозволеними агрегаціями. Серверна сторона, завантажується при ініціалізації.
Query Builder—UI для складання запиту. Клієнт збирає конфіг запиту.
Query Engine—сервер перетворює конфіг у SQL (або запит OLAP) та повертає дані.
Renderer—клієнт рендерить таблицю або графік.
Структура метаданих
interface FieldMeta {
id: string;
label: string;
type: 'string' | 'number' | 'date' | 'boolean';
entity: string;
aggregatable: boolean;
filterable: boolean;
// Дозволені агрегації для числових полів
aggregations?: ('sum' | 'avg' | 'count' | 'min' | 'max' | 'count_distinct')[];
}
interface EntityMeta {
id: string;
label: string;
fields: FieldMeta[];
// Доступні шляхи об'єднання
relations?: { entity: string; via: string; label: string }[];
}
// Приклад метаданих для e-commerce
const metadata: EntityMeta[] = [
{
id: 'orders',
label: 'Замовлення',
fields: [
{ id: 'orders.created_at', label: 'Дата замовлення', type: 'date', entity: 'orders', aggregatable: false, filterable: true },
{ id: 'orders.total', label: 'Сума замовлення', type: 'number', entity: 'orders', aggregatable: true, filterable: true, aggregations: ['sum', 'avg', 'min', 'max'] },
{ id: 'orders.status', label: 'Статус', type: 'string', entity: 'orders', aggregatable: false, filterable: true },
{ id: 'orders.count', label: 'Кількість замовлень', type: 'number', entity: 'orders', aggregatable: true, filterable: false, aggregations: ['count'] },
],
relations: [
{ entity: 'customers', via: 'customer_id', label: 'Клієнт' },
],
},
];
Конфіг запиту
interface ReportQuery {
entity: string;
dimensions: string[]; // поля групування
measures: { field: string; agg: string }[];
filters: { field: string; operator: string; value: any }[];
orderBy?: { field: string; desc: boolean }[];
limit?: number;
}
Запит до SQL
function queryToSQL(query: ReportQuery, meta: EntityMeta[]): string {
const entity = meta.find(e => e.id === query.entity)!;
const cols = [...query.dimensions, ...query.measures.map(m => `${m.agg}(${m.field})`)];
let sql = `SELECT ${cols.join(', ')} FROM ${query.entity}`;
if (query.filters.length) {
const where = query.filters.map(f => `${f.field} ${f.operator} '${f.value}'`).join(' AND ');
sql += ` WHERE ${where}`;
}
if (query.dimensions.length) {
sql += ` GROUP BY ${query.dimensions.join(', ')}`;
}
if (query.orderBy?.length) {
const order = query.orderBy.map(o => `${o.field} ${o.desc ? 'DESC' : 'ASC'}`).join(', ');
sql += ` ORDER BY ${order}`;
}
if (query.limit) sql += ` LIMIT ${query.limit}`;
return sql;
}
Часова шкала
Базовий конструктор запитів з рендеруванням таблиці—5–7 днів. З збереженими звітами, плануванням та кількома типами графіків—10–14 днів.







