@@ -16,34 +16,72 @@ export const statisticsRouter = {
1616 async ( { input } ) => {
1717 const { dateFrom, dateTo } = input || { } ;
1818
19- const partyFilter = Prisma . sql `
20- p1.datum_inactief IS NULL
21- AND p2.datum_inactief IS NULL
22- ` ;
23-
2419 const dateFilter =
2520 dateFrom && dateTo
26- ? Prisma . sql `AND pl .gestart_op BETWEEN ${ dateFrom } AND ${ dateTo } `
21+ ? Prisma . sql `AND z .gestart_op BETWEEN ${ dateFrom } AND ${ dateTo } `
2722 : Prisma . empty ;
2823
24+ // Simplified approach: directly compare votes between parties
25+ // Based on the PHP implementation which looks at all stemmingen
2926 const results : PartyLikeness [ ] = await db . $queryRaw `
30- SELECT
31- p1.id AS "party1Id",
32- p1.afkorting AS "party1Name",
33- p2.id AS "party2Id",
34- p2.afkorting AS "party2Name",
35- COUNT(*) AS "commonMotions",
36- SUM(CASE WHEN pl.same_vote THEN 1 ELSE 0 END) AS "sameVotes",
37- (SUM(CASE WHEN pl.same_vote THEN 1 ELSE 0 END)::float / NULLIF(COUNT(*), 0)::float) * 100 AS "likenessPercentage"
38- FROM party_likeness_per_motion pl
39- JOIN fracties p1 ON pl.fractie1_id = p1.id
40- JOIN fracties p2 ON pl.fractie2_id = p2.id
41- WHERE ${ partyFilter } ${ dateFilter }
42- GROUP BY p1.id, p1.afkorting, p2.id, p2.afkorting
43- ORDER BY p1.afkorting, "likenessPercentage" DESC;
44- ` ;
27+ WITH PartyVotes AS (
28+ SELECT DISTINCT
29+ b.zaak_id,
30+ f.id as fractie_id,
31+ f.afkorting as fractie_name,
32+ s.soort as vote_type
33+ FROM stemmingen s
34+ JOIN besluiten b ON s.besluit_id = b.id
35+ JOIN zaken z ON b.zaak_id = z.id
36+ JOIN fracties f ON (s.actor_fractie = f.naam_nl OR s.actor_fractie = f.afkorting)
37+ WHERE s.actor_fractie IS NOT NULL
38+ AND s.soort IN ('Voor', 'Tegen')
39+ AND z.soort = 'Motie'
40+ AND f.datum_inactief IS NULL
41+ ${ dateFilter }
42+ ),
43+ PartyComparisons AS (
44+ SELECT
45+ p1.fractie_id as party1_id,
46+ p1.fractie_name as party1_name,
47+ p2.fractie_id as party2_id,
48+ p2.fractie_name as party2_name,
49+ COUNT(*) as common_motions,
50+ SUM(CASE WHEN p1.vote_type = p2.vote_type THEN 1 ELSE 0 END) as same_votes
51+ FROM PartyVotes p1
52+ JOIN PartyVotes p2 ON p1.zaak_id = p2.zaak_id AND p1.fractie_id < p2.fractie_id
53+ GROUP BY p1.fractie_id, p1.fractie_name, p2.fractie_id, p2.fractie_name
54+ )
55+ SELECT
56+ party1_id AS "party1Id",
57+ party1_name AS "party1Name",
58+ party2_id AS "party2Id",
59+ party2_name AS "party2Name",
60+ common_motions AS "commonMotions",
61+ same_votes AS "sameVotes",
62+ CASE
63+ WHEN common_motions > 0
64+ THEN (same_votes::float / common_motions::float) * 100
65+ ELSE 0
66+ END AS "likenessPercentage"
67+ FROM PartyComparisons
68+ ORDER BY party1_name, "likenessPercentage" DESC;
69+ ` ;
4570
46- return results . map ( ( r ) => ( {
71+ // Also get the reverse relationships (party2 to party1)
72+ const reverseResults : PartyLikeness [ ] = results . map ( ( r ) => ( {
73+ party1Id : r . party2Id ,
74+ party1Name : r . party2Name ,
75+ party2Id : r . party1Id ,
76+ party2Name : r . party1Name ,
77+ commonMotions : r . commonMotions ,
78+ sameVotes : r . sameVotes ,
79+ likenessPercentage : r . likenessPercentage ,
80+ } ) ) ;
81+
82+ const allResults = [ ...results , ...reverseResults ] ;
83+
84+ return allResults . map ( ( r ) => ( {
4785 ...r ,
4886 commonMotions : Number ( r . commonMotions ) ,
4987 sameVotes : Number ( r . sameVotes ) ,
@@ -71,31 +109,31 @@ export const statisticsRouter = {
71109 : Prisma . empty ;
72110
73111 const results : PartyFocusCategory [ ] = await db . $queryRaw `
74- SELECT
75- mc.id AS "categoryId",
76- mc.name AS "categoryName",
77- mc.type AS "categoryType",
78- COUNT(z.id) AS "motionCount"
79- FROM
80- zaak_actors za
81- JOIN
82- zaken z ON za.zaak_id = z.id
83- JOIN
84- fracties f ON za.actor_fractie = f.naam_nl OR za.actor_fractie = f.afkorting
85- JOIN
86- zaak_categories zc ON z.id = zc.zaak_id
87- JOIN
88- motion_categories mc ON zc.category_id = mc.id
89- WHERE
90- f.id = ${ partyId }
91- AND za.relatie = 'Indiener'
92- AND z.soort = 'Motie'
93- ${ dateFilter }
94- GROUP BY
95- mc.id, mc.name, mc.type
96- ORDER BY
97- "motionCount" DESC;
98- `;
112+ SELECT
113+ mc.id AS "categoryId",
114+ mc.name AS "categoryName",
115+ mc.type AS "categoryType",
116+ COUNT(z.id) AS "motionCount"
117+ FROM
118+ zaak_actors za
119+ JOIN
120+ zaken z ON za.zaak_id = z.id
121+ JOIN
122+ fracties f ON za.actor_fractie = f.naam_nl OR za.actor_fractie = f.afkorting
123+ JOIN
124+ zaak_categories zc ON z.id = zc.zaak_id
125+ JOIN
126+ motion_categories mc ON zc.category_id = mc.id
127+ WHERE
128+ f.id = ${ partyId }
129+ AND za.relatie = 'Indiener'
130+ AND z.soort = 'Motie'
131+ ${ dateFilter }
132+ GROUP BY
133+ mc.id, mc.name, mc.type
134+ ORDER BY
135+ "motionCount" DESC;
136+ `;
99137
100138 return {
101139 party : mapPartyToContract ( party ) ,
@@ -112,45 +150,57 @@ export const statisticsRouter = {
112150
113151 const dateFilter =
114152 dateFrom && dateTo
115- ? Prisma . sql `WHERE gestart_op BETWEEN ${ dateFrom } AND ${ dateTo } `
153+ ? Prisma . sql `AND z. gestart_op BETWEEN ${ dateFrom } AND ${ dateTo } `
116154 : Prisma . empty ;
117155
156+ // Simplified approach: directly analyze votes by category
118157 const results : PartyCategoryLikeness [ ] = await db . $queryRaw `
119- WITH MotionMajorityVotes AS (
120- SELECT * FROM majority_party_votes ${ dateFilter }
121- ),
122- MotionCategoryVotes AS (
123- SELECT
124- mmv.zaak_id,
125- mmv.fractie_id,
126- mmv.vote_type,
127- zc.category_id
128- FROM MotionMajorityVotes mmv
129- JOIN zaak_categories zc ON mmv.zaak_id = zc.zaak_id
130- )
131- SELECT
132- mc.id AS "categoryId",
133- mc.name AS "categoryName",
134- p2.id AS "party2Id",
135- p2.afkorting AS "party2Name",
136- (SUM(CASE WHEN mcv1.vote_type = mcv2.vote_type THEN 1 ELSE 0 END)::float / NULLIF(COUNT(mcv2.zaak_id), 0)::float) * 100 AS "likenessPercentage"
137- FROM
138- (SELECT * FROM MotionCategoryVotes WHERE fractie_id = ${ partyId } ) mcv1
139- JOIN
140- MotionCategoryVotes mcv2 ON mcv1.zaak_id = mcv2.zaak_id AND mcv1.category_id = mcv2.category_id
141- JOIN
142- fracties p2 ON mcv2.fractie_id = p2.id
143- JOIN
144- motion_categories mc ON mcv1.category_id = mc.id
145- WHERE
146- mcv1.fractie_id != mcv2.fractie_id
147- AND p2.datum_inactief IS NULL
148- AND p2.naam_nl NOT IN ('Groep Van Haga', 'Fractie Den Haan', 'Lid Omtzigt', 'Lid Gündoğan')
149- GROUP BY
150- mc.id, mc.name, p2.id, p2.afkorting
151- ORDER BY
152- mc.name, p2.afkorting;
153- ` ;
158+ WITH PartyVotesByCategory AS (
159+ SELECT DISTINCT
160+ b.zaak_id,
161+ f.id as fractie_id,
162+ s.soort as vote_type,
163+ zc.category_id
164+ FROM stemmingen s
165+ JOIN besluiten b ON s.besluit_id = b.id
166+ JOIN zaken z ON b.zaak_id = z.id
167+ JOIN fracties f ON (s.actor_fractie = f.naam_nl OR s.actor_fractie = f.afkorting)
168+ JOIN zaak_categories zc ON z.id = zc.zaak_id
169+ WHERE s.actor_fractie IS NOT NULL
170+ AND s.soort IN ('Voor', 'Tegen')
171+ AND z.soort = 'Motie'
172+ AND f.datum_inactief IS NULL
173+ ${ dateFilter }
174+ ),
175+ CategoryComparisons AS (
176+ SELECT
177+ pv1.category_id,
178+ pv2.fractie_id as other_party_id,
179+ COUNT(*) as total_votes,
180+ SUM(CASE WHEN pv1.vote_type = pv2.vote_type THEN 1 ELSE 0 END) as same_votes
181+ FROM PartyVotesByCategory pv1
182+ JOIN PartyVotesByCategory pv2 ON pv1.zaak_id = pv2.zaak_id
183+ AND pv1.category_id = pv2.category_id
184+ AND pv1.fractie_id != pv2.fractie_id
185+ WHERE pv1.fractie_id = ${ partyId }
186+ GROUP BY pv1.category_id, pv2.fractie_id
187+ )
188+ SELECT
189+ mc.id AS "categoryId",
190+ mc.name AS "categoryName",
191+ f.id AS "party2Id",
192+ f.afkorting AS "party2Name",
193+ CASE
194+ WHEN cc.total_votes > 0
195+ THEN (cc.same_votes::float / cc.total_votes::float) * 100
196+ ELSE 0
197+ END AS "likenessPercentage"
198+ FROM CategoryComparisons cc
199+ JOIN motion_categories mc ON cc.category_id = mc.id
200+ JOIN fracties f ON cc.other_party_id = f.id
201+ WHERE f.datum_inactief IS NULL
202+ ORDER BY mc.name, f.afkorting;
203+ ` ;
154204
155205 return results . map ( ( r ) => ( {
156206 ...r ,
0 commit comments