Skip to content

Commit 973872f

Browse files
committed
Merge branch 'integrate-jsonb-stats-extension'
2 parents bbd3307 + 55cb22f commit 973872f

File tree

51 files changed

+11438
-4690
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+11438
-4690
lines changed

app/src/app/enterprises/[id]/statistical-variables/statistical-variables-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export default function StatisticalVariablesForm({
2727
return (
2828
<form className="space-y-4">
2929
{statDefinitions.map((statDefinition) => {
30-
const value = data?.stats_summary?.[statDefinition.code]?.sum;
30+
const metric = data?.stats_summary?.[statDefinition.code];
31+
const value = metric && "sum" in metric ? metric.sum : undefined;
3132
return (
3233
<DisplayFormField
3334
key={statDefinition.code}

app/src/app/reports/ReportsPageClient.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,15 @@ export default function ReportsPageClient({
6565
...(drillDown.available.region?.map((point) =>
6666
value === "count"
6767
? point.count
68-
: ((point.stats_summary?.[value]?.sum as number) ?? 0)
68+
: (() => { const m = point.stats_summary?.[value]; return m && "sum" in m ? (m.sum as number) : 0; })()
6969
) || [])
7070
);
7171
const categoryMax = Math.max(
7272
0,
7373
...(drillDown.available.activity_category?.map((point) =>
7474
value === "count"
7575
? point.count
76-
: ((point.stats_summary?.[value]?.sum as number) ?? 0)
76+
: (() => { const m = point.stats_summary?.[value]; return m && "sum" in m ? (m.sum as number) : 0; })()
7777
) || [])
7878
);
7979

app/src/app/reports/drill-down-chart.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ export const DrillDownChart = ({
131131
return <div ref={chartContainerRef} />;
132132
};
133133

134-
const getStatValue = (point: DrillDownPoint, variable: string): number =>
135-
variable === "count"
136-
? point.count
137-
: ((point.stats_summary?.[variable]?.sum as number) ?? 0);
134+
const getStatValue = (point: DrillDownPoint, variable: string): number => {
135+
if (variable === "count") return point.count;
136+
const metric = point.stats_summary?.[variable];
137+
return metric && "sum" in metric ? (metric.sum as number) : 0;
138+
};
138139

139140
const toPointOptionObject = (point: DrillDownPoint, variable: string) => ({
140141
name: `${point.path} - ${point.name}`,

app/src/app/search/components/statistical-unit-table-row.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,10 @@ export const StatisticalUnitTableRow = ({
379379
const metric = unit.stats_summary[column.stat_code];
380380
let valueToDisplay: number | string | null = null;
381381

382-
if (metric && metric.type === "number") {
383-
// metric is NumberStatMetric, sum is number | undefined
382+
if (metric && ("sum" in metric)) {
384383
valueToDisplay = metric.sum !== undefined ? metric.sum : null;
385384
} else {
386-
// For other types or if metric is undefined, display a placeholder
387-
// as we are only asked to display 'sum' from 'number' type metrics.
388-
valueToDisplay = "-"; // Or null for an empty cell
385+
valueToDisplay = "-";
389386
}
390387
return thousandSeparator(valueToDisplay);
391388
})()}

app/src/app/types.d.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,48 @@ interface ExternalIdents {
1212
[key: string]: number | string;
1313
}
1414

15+
// jsonb_stats aggregate types — see jsonb_stats README.md "Structures in Detail"
16+
17+
/** Numeric aggregate (int_agg, float_agg, dec2_agg, nat_agg) */
18+
interface NumericStatAgg {
19+
type: "int_agg" | "float_agg" | "dec2_agg" | "nat_agg";
20+
count: number;
21+
sum: number;
22+
min: number;
23+
max: number;
24+
mean: number;
25+
sum_sq_diff: number;
26+
variance: number | null;
27+
stddev: number | null;
28+
coefficient_of_variation_pct: number | null;
29+
}
30+
31+
/** Categorical aggregate (str_agg, bool_agg) */
32+
interface CategoricalStatAgg {
33+
type: "str_agg" | "bool_agg";
34+
counts: { [value: string]: number };
35+
}
36+
37+
/** Array aggregate */
38+
interface ArrayStatAgg {
39+
type: "arr_agg";
40+
count: number;
41+
counts: { [element: string]: number };
42+
}
43+
44+
/** Date aggregate */
45+
interface DateStatAgg {
46+
type: "date_agg";
47+
counts: { [isoDate: string]: number };
48+
min: string;
49+
max: string;
50+
}
51+
52+
type StatAgg = NumericStatAgg | CategoricalStatAgg | ArrayStatAgg | DateStatAgg;
53+
54+
/** stats_agg object: { type: "stats_agg", [statCode]: StatAgg } */
1555
interface StatsSummary {
16-
[key: string]: {
17-
[key: string]: number | string;
18-
};
56+
[statCode: string]: StatAgg;
1957
}
2058

2159
interface StatisticalUnit extends Tables<"statistical_unit"> {

app/src/atoms/search.ts

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -233,39 +233,9 @@ export const resetSearchInitializationAtom = atom(
233233
// SELECTION ATOMS - Replace SelectionContext
234234
// ============================================================================
235235

236-
interface ExternalIdents {
237-
[key: string]: string;
238-
}
239-
240-
// Define the structure for metrics within stats_summary
241-
interface BaseStatMetric {
242-
type: "array" | "number" | "string" | "boolean";
243-
}
244-
245-
export interface NumberStatMetric extends BaseStatMetric {
246-
type: "number";
247-
max?: number;
248-
min?: number;
249-
sum?: number; // If present, this is always a number
250-
mean?: number;
251-
count?: number;
252-
stddev?: number;
253-
variance?: number;
254-
sum_sq_diff?: number;
255-
coefficient_of_variation_pct?: number;
256-
}
257-
258-
export interface CountsStatMetric extends BaseStatMetric {
259-
type: "array" | "string" | "boolean";
260-
counts: { [key: string]: number };
261-
}
262-
263-
export type StatMetric = NumberStatMetric | CountsStatMetric;
264-
265-
// Refined StatsSummary: Each key is a stat_code, value is its metric object or undefined
266-
interface StatsSummary {
267-
[statCode: string]: StatMetric | undefined;
268-
}
236+
// Re-export discriminated union types from app/types.d.ts for use in search components
237+
export type { NumericStatAgg, CategoricalStatAgg, ArrayStatAgg, DateStatAgg, StatAgg } from '@/app/types';
238+
import type { StatsSummary, ExternalIdents } from '@/app/types';
269239

270240
export type StatisticalUnit = Omit<Tables<"statistical_unit">, 'external_idents' | 'stats_summary'> & {
271241
external_idents: ExternalIdents;

app/src/components/statistical-unit-hierarchy/topology-item.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ export function TopologyItem({
110110
/>
111111
{statDefinitions.map(
112112
(statDefinition: Tables<"stat_definition_active">) => {
113-
const statsSum =
114-
stats?.stats_summary?.[statDefinition.code]?.sum;
113+
const metric = stats?.stats_summary?.[statDefinition.code];
114+
const statsSum = metric && "sum" in metric ? metric.sum : undefined;
115115
const stat = unit.stat_for_unit?.find(
116116
(s) => s.stat_definition_id === statDefinition.id
117117
);

app/src/components/statistical-unit-hierarchy/types.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ declare interface StatisticalUnitStats {
266266
unit_id: number;
267267
valid_from: string;
268268
valid_to: string;
269-
stats: { [key: string]: number | string };
269+
stats: { type: "stats"; [statCode: string]: { type: string; value: number | string | boolean } | string };
270270
stats_summary: StatsSummary;
271271
};
272272

app/src/lib/database.types.ts

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2929,6 +2929,7 @@ export type Database = {
29292929
establishment_id: number | null
29302930
id: number
29312931
legal_unit_id: number | null
2932+
stat: Json | null
29322933
stat_definition_id: number
29332934
valid_from: string
29342935
valid_range: string
@@ -2947,6 +2948,7 @@ export type Database = {
29472948
establishment_id?: number | null
29482949
id?: number
29492950
legal_unit_id?: number | null
2951+
stat?: Json | null
29502952
stat_definition_id: number
29512953
valid_from: string
29522954
valid_range: string
@@ -2965,6 +2967,7 @@ export type Database = {
29652967
establishment_id?: number | null
29662968
id?: number
29672969
legal_unit_id?: number | null
2970+
stat?: Json | null
29682971
stat_definition_id?: number
29692972
valid_from?: string
29702973
valid_range?: string
@@ -12040,23 +12043,77 @@ export type Database = {
1204012043
Args: never
1204112044
Returns: boolean
1204212045
},
12043-
jsonb_stats_summary_merge: {
12046+
jsonb_stats_accum: {
12047+
Args: {
12048+
state?: Json
12049+
stats?: Json
12050+
}
12051+
Returns: Json
12052+
},
12053+
jsonb_stats_accum_sfunc: {
12054+
Args: {
12055+
internal?: unknown
12056+
stats?: Json
12057+
}
12058+
Returns: unknown
12059+
},
12060+
jsonb_stats_combine: {
12061+
Args: {
12062+
state1?: unknown
12063+
state2?: unknown
12064+
}
12065+
Returns: unknown
12066+
},
12067+
jsonb_stats_deserial: {
12068+
Args: {
12069+
bytes?: string
12070+
_internal?: unknown
12071+
}
12072+
Returns: unknown
12073+
},
12074+
jsonb_stats_final: {
12075+
Args: {
12076+
state?: Json
12077+
}
12078+
Returns: Json
12079+
},
12080+
jsonb_stats_final_internal: {
12081+
Args: {
12082+
internal?: unknown
12083+
}
12084+
Returns: Json
12085+
},
12086+
jsonb_stats_merge: {
1204412087
Args: {
1204512088
a?: Json
1204612089
b?: Json
1204712090
}
1204812091
Returns: Json
1204912092
},
12050-
jsonb_stats_to_summary: {
12093+
jsonb_stats_merge_sfunc: {
12094+
Args: {
12095+
internal?: unknown
12096+
agg?: Json
12097+
}
12098+
Returns: unknown
12099+
},
12100+
jsonb_stats_serial: {
12101+
Args: {
12102+
internal?: unknown
12103+
}
12104+
Returns: string
12105+
},
12106+
jsonb_stats_sfunc: {
1205112107
Args: {
1205212108
state?: Json
12053-
stats?: Json
12109+
code?: string
12110+
stat_val?: Json
1205412111
}
1205512112
Returns: Json
1205612113
},
12057-
jsonb_stats_to_summary_round: {
12114+
jsonb_stats_to_agg: {
1205812115
Args: {
12059-
state?: Json
12116+
stats?: Json
1206012117
}
1206112118
Returns: Json
1206212119
},
@@ -12810,6 +12867,12 @@ export type Database = {
1281012867
}
1281112868
Returns: string
1281212869
},
12870+
stat: {
12871+
Args: {
12872+
value?: unknown
12873+
}
12874+
Returns: Json
12875+
},
1281312876
stat_for_unit_hierarchy: {
1281412877
Args: {
1281512878
parent_establishment_id?: number
@@ -12944,6 +13007,19 @@ export type Database = {
1294413007
}
1294513008
Returns: Json
1294613009
},
13010+
stats: {
13011+
Args: {
13012+
input?: Json
13013+
}
13014+
Returns: Json
13015+
}
13016+
| {
13017+
Args: {
13018+
code?: string
13019+
val?: unknown
13020+
}
13021+
Returns: Json
13022+
},
1294713023
status: {
1294813024
Args: {
1294913025
statistical_unit?: Database["public"]["Tables"]["statistical_unit"]["Row"]

doc/data-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ These tables link to any of the four core statistical units:
7070

7171
### Statistics
7272

73-
- `stat_for_unit(id, value_int, value_float, value_string, value_bool, stat_definition_id, data_source_id, establishment_id, legal_unit_id, edit_by_user_id, valid_range, valid_from, valid_to, valid_until, edit_at, edit_comment)` (temporal)
73+
- `stat_for_unit(id, value_int, value_float, value_string, value_bool, stat_definition_id, data_source_id, establishment_id, legal_unit_id, edit_by_user_id, valid_range, valid_from, valid_to, valid_until, edit_at, edit_comment, stat)` (temporal)
7474
- Key FKs: data_source_id, edit_by_user_id, establishment_id, legal_unit_id, stat_definition_id, valid_range, valid_range.
7575
- `stat_definition(id, code, type, name, enabled, frequency, description, priority)`
7676
- Enums: `frequency` (`public.stat_frequency`), `type` (`public.stat_type`).

0 commit comments

Comments
 (0)