liquid_feedback_core

view update/core-update.v4.2.0-v4.2.1.sql @ 615:5ae68278492f

Added update script core-update.v4.2.0-v4.2.1.sql
author jbe
date Sun May 17 13:56:43 2020 +0200 (2020-05-17)
parents
children ae53fc96c953
line source
1 CREATE OR REPLACE VIEW "liquid_feedback_version" AS
2 SELECT * FROM (VALUES ('4.2.1-incomplete-update', 4, 2, -1))
3 AS "subquery"("string", "major", "minor", "revision");
5 BEGIN;
7 ALTER TABLE "unit" ADD COLUMN "member_weight" INT4;
8 COMMENT ON COLUMN "unit"."member_weight" IS 'Sum of active members'' voting weight';
10 ALTER TABLE "snapshot_population" ADD COLUMN "weight" INT4 NOT NULL DEFAULT 1;
11 ALTER TABLE "snapshot_population" ALTER COLUMN "weight" DROP DEFAULT;
13 ALTER TABLE "privilege" ADD COLUMN "weight" INT4 NOT NULL DEFAULT 1 CHECK ("weight" >= 0);
14 COMMENT ON COLUMN "privilege"."weight" IS 'Voting weight of member in unit';
16 CREATE TABLE "issue_privilege" (
17 PRIMARY KEY ("issue_id", "member_id"),
18 "issue_id" INT4 REFERENCES "issue" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
19 "member_id" INT4 REFERENCES "member" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
20 "initiative_right" BOOLEAN,
21 "voting_right" BOOLEAN,
22 "polling_right" BOOLEAN,
23 "weight" INT4 CHECK ("weight" >= 0) );
24 CREATE INDEX "issue_privilege_idx" ON "issue_privilege" ("member_id");
25 COMMENT ON TABLE "issue_privilege" IS 'Override of "privilege" table for rights of members in certain issues';
27 ALTER TABLE "direct_interest_snapshot" ADD COLUMN "ownweight" INT4 NOT NULL DEFAULT 1;
28 ALTER TABLE "direct_interest_snapshot" ALTER COLUMN "ownweight" DROP DEFAULT;
29 COMMENT ON COLUMN "direct_interest_snapshot"."ownweight" IS 'Own voting weight of member, disregading delegations';
30 COMMENT ON COLUMN "direct_interest_snapshot"."weight" IS 'Voting weight of member according to own weight and "delegating_interest_snapshot"';
32 ALTER TABLE "delegating_interest_snapshot" ADD COLUMN "ownweight" INT4 NOT NULL DEFAULT 1;
33 ALTER TABLE "delegating_interest_snapshot" ALTER COLUMN "ownweight" DROP DEFAULT;
34 COMMENT ON COLUMN "delegating_interest_snapshot"."ownweight" IS 'Own voting weight of member, disregading delegations';
35 COMMENT ON COLUMN "delegating_interest_snapshot"."weight" IS 'Intermediate voting weight considering incoming delegations';
37 ALTER TABLE "direct_voter" ADD COLUMN "ownweight" INT4 DEFAULT 1;
38 ALTER TABLE "direct_voter" ALTER COLUMN "ownweight" DROP DEFAULT;
39 COMMENT ON COLUMN "direct_voter"."ownweight" IS 'Own voting weight of member, disregarding delegations';
40 COMMENT ON COLUMN "direct_voter"."weight" IS 'Voting weight of member according to own weight and "delegating_interest_snapshot"';
42 ALTER TABLE "delegating_voter" ADD COLUMN "ownweight" INT4 NOT NULL DEFAULT 1;
43 ALTER TABLE "delegating_voter" ALTER COLUMN "ownweight" DROP DEFAULT;
44 COMMENT ON COLUMN "delegating_voter"."ownweight" IS 'Own voting weight of member, disregarding delegations';
45 COMMENT ON COLUMN "delegating_voter"."weight" IS 'Intermediate voting weight considering incoming delegations';
47 DROP VIEW "issue_delegation";
48 CREATE VIEW "issue_delegation" AS
49 SELECT DISTINCT ON ("issue"."id", "delegation"."truster_id")
50 "issue"."id" AS "issue_id",
51 "delegation"."id",
52 "delegation"."truster_id",
53 "delegation"."trustee_id",
54 COALESCE("issue_privilege"."weight", "privilege"."weight") AS "weight",
55 "delegation"."scope"
56 FROM "issue"
57 JOIN "area"
58 ON "area"."id" = "issue"."area_id"
59 JOIN "delegation"
60 ON "delegation"."unit_id" = "area"."unit_id"
61 OR "delegation"."area_id" = "area"."id"
62 OR "delegation"."issue_id" = "issue"."id"
63 JOIN "member"
64 ON "delegation"."truster_id" = "member"."id"
65 LEFT JOIN "privilege"
66 ON "area"."unit_id" = "privilege"."unit_id"
67 AND "delegation"."truster_id" = "privilege"."member_id"
68 LEFT JOIN "issue_privilege"
69 ON "issue"."id" = "issue_privilege"."issue_id"
70 AND "delegation"."truster_id" = "issue_privilege"."member_id"
71 WHERE "member"."active"
72 AND COALESCE("issue_privilege"."voting_right", "privilege"."voting_right")
73 ORDER BY
74 "issue"."id",
75 "delegation"."truster_id",
76 "delegation"."scope" DESC;
77 COMMENT ON VIEW "issue_delegation" IS 'Issue delegations where trusters are active and have voting right';
79 CREATE OR REPLACE VIEW "unit_member" AS
80 SELECT
81 "privilege"."unit_id" AS "unit_id",
82 "member"."id" AS "member_id",
83 "privilege"."weight"
84 FROM "privilege" JOIN "member" ON "member"."id" = "privilege"."member_id"
85 WHERE "privilege"."voting_right" AND "member"."active";
87 CREATE OR REPLACE VIEW "unit_member_count" AS
88 SELECT
89 "unit"."id" AS "unit_id",
90 count("unit_member"."member_id") AS "member_count",
91 sum("unit_member"."weight") AS "member_weight"
92 FROM "unit" LEFT JOIN "unit_member"
93 ON "unit"."id" = "unit_member"."unit_id"
94 GROUP BY "unit"."id";
96 CREATE OR REPLACE VIEW "event_for_notification" AS
97 SELECT
98 "member"."id" AS "recipient_id",
99 "event".*
100 FROM "member" CROSS JOIN "event"
101 JOIN "issue" ON "issue"."id" = "event"."issue_id"
102 JOIN "area" ON "area"."id" = "issue"."area_id"
103 LEFT JOIN "privilege" ON
104 "privilege"."member_id" = "member"."id" AND
105 "privilege"."unit_id" = "area"."unit_id"
106 LEFT JOIN "issue_privilege" ON
107 "issue_privilege"."member_id" = "member"."id" AND
108 "issue_privilege"."issue_id" = "event"."issue_id"
109 LEFT JOIN "subscription" ON
110 "subscription"."member_id" = "member"."id" AND
111 "subscription"."unit_id" = "area"."unit_id"
112 LEFT JOIN "ignored_area" ON
113 "ignored_area"."member_id" = "member"."id" AND
114 "ignored_area"."area_id" = "issue"."area_id"
115 LEFT JOIN "interest" ON
116 "interest"."member_id" = "member"."id" AND
117 "interest"."issue_id" = "event"."issue_id"
118 LEFT JOIN "supporter" ON
119 "supporter"."member_id" = "member"."id" AND
120 "supporter"."initiative_id" = "event"."initiative_id"
121 WHERE (
122 COALESCE("issue_privilege"."voting_right", "privilege"."voting_right") OR
123 "subscription"."member_id" NOTNULL
124 ) AND ("ignored_area"."member_id" ISNULL OR "interest"."member_id" NOTNULL)
125 AND (
126 "event"."event" = 'issue_state_changed'::"event_type" OR
127 ( "event"."event" = 'initiative_revoked'::"event_type" AND
128 "supporter"."member_id" NOTNULL ) );
130 CREATE OR REPLACE FUNCTION "featured_initiative"
131 ( "recipient_id_p" "member"."id"%TYPE,
132 "area_id_p" "area"."id"%TYPE )
133 RETURNS SETOF "initiative"."id"%TYPE
134 LANGUAGE 'plpgsql' STABLE AS $$
135 DECLARE
136 "counter_v" "member"."notification_counter"%TYPE;
137 "sample_size_v" "member"."notification_sample_size"%TYPE;
138 "initiative_id_ary" INT4[]; --"initiative"."id"%TYPE[]
139 "match_v" BOOLEAN;
140 "member_id_v" "member"."id"%TYPE;
141 "seed_v" TEXT;
142 "initiative_id_v" "initiative"."id"%TYPE;
143 BEGIN
144 SELECT "notification_counter", "notification_sample_size"
145 INTO "counter_v", "sample_size_v"
146 FROM "member" WHERE "id" = "recipient_id_p";
147 IF COALESCE("sample_size_v" <= 0, TRUE) THEN
148 RETURN;
149 END IF;
150 "initiative_id_ary" := '{}';
151 LOOP
152 "match_v" := FALSE;
153 FOR "member_id_v", "seed_v" IN
154 SELECT * FROM (
155 SELECT DISTINCT
156 "supporter"."member_id",
157 md5(
158 "recipient_id_p" || '-' ||
159 "counter_v" || '-' ||
160 "area_id_p" || '-' ||
161 "supporter"."member_id"
162 ) AS "seed"
163 FROM "supporter"
164 JOIN "initiative" ON "initiative"."id" = "supporter"."initiative_id"
165 JOIN "issue" ON "issue"."id" = "initiative"."issue_id"
166 WHERE "supporter"."member_id" != "recipient_id_p"
167 AND "issue"."area_id" = "area_id_p"
168 AND "issue"."state" IN ('admission', 'discussion', 'verification')
169 ) AS "subquery"
170 ORDER BY "seed"
171 LOOP
172 SELECT "initiative"."id" INTO "initiative_id_v"
173 FROM "initiative"
174 JOIN "issue" ON "issue"."id" = "initiative"."issue_id"
175 JOIN "area" ON "area"."id" = "issue"."area_id"
176 JOIN "supporter" ON "supporter"."initiative_id" = "initiative"."id"
177 LEFT JOIN "supporter" AS "self_support" ON
178 "self_support"."initiative_id" = "initiative"."id" AND
179 "self_support"."member_id" = "recipient_id_p"
180 LEFT JOIN "privilege" ON
181 "privilege"."member_id" = "recipient_id_p" AND
182 "privilege"."unit_id" = "area"."unit_id"
183 LEFT JOIN "issue_privilege" ON
184 "privilege"."member_id" = "recipient_id_p" AND
185 "privilege"."issue_id" = "initiative"."issue_id"
186 LEFT JOIN "subscription" ON
187 "subscription"."member_id" = "recipient_id_p" AND
188 "subscription"."unit_id" = "area"."unit_id"
189 LEFT JOIN "ignored_initiative" ON
190 "ignored_initiative"."member_id" = "recipient_id_p" AND
191 "ignored_initiative"."initiative_id" = "initiative"."id"
192 WHERE "supporter"."member_id" = "member_id_v"
193 AND "issue"."area_id" = "area_id_p"
194 AND "issue"."state" IN ('admission', 'discussion', 'verification')
195 AND "initiative"."revoked" ISNULL
196 AND "self_support"."member_id" ISNULL
197 AND NOT "initiative_id_ary" @> ARRAY["initiative"."id"]
198 AND (
199 COALESCE(
200 "issue_privilege"."voting_right", "privilege"."voting_right"
201 ) OR "subscription"."member_id" NOTNULL )
202 AND "ignored_initiative"."member_id" ISNULL
203 AND NOT EXISTS (
204 SELECT NULL FROM "draft"
205 JOIN "ignored_member" ON
206 "ignored_member"."member_id" = "recipient_id_p" AND
207 "ignored_member"."other_member_id" = "draft"."author_id"
208 WHERE "draft"."initiative_id" = "initiative"."id"
209 )
210 ORDER BY md5("seed_v" || '-' || "initiative"."id")
211 LIMIT 1;
212 IF FOUND THEN
213 "match_v" := TRUE;
214 RETURN NEXT "initiative_id_v";
215 IF array_length("initiative_id_ary", 1) + 1 >= "sample_size_v" THEN
216 RETURN;
217 END IF;
218 "initiative_id_ary" := "initiative_id_ary" || "initiative_id_v";
219 END IF;
220 END LOOP;
221 EXIT WHEN NOT "match_v";
222 END LOOP;
223 RETURN;
224 END;
225 $$;
227 CREATE OR REPLACE FUNCTION "delegation_chain"
228 ( "member_id_p" "member"."id"%TYPE,
229 "unit_id_p" "unit"."id"%TYPE,
230 "area_id_p" "area"."id"%TYPE,
231 "issue_id_p" "issue"."id"%TYPE,
232 "simulate_trustee_id_p" "member"."id"%TYPE DEFAULT NULL,
233 "simulate_default_p" BOOLEAN DEFAULT FALSE )
234 RETURNS SETOF "delegation_chain_row"
235 LANGUAGE 'plpgsql' STABLE AS $$
236 DECLARE
237 "scope_v" "delegation_scope";
238 "unit_id_v" "unit"."id"%TYPE;
239 "area_id_v" "area"."id"%TYPE;
240 "issue_row" "issue"%ROWTYPE;
241 "visited_member_ids" INT4[]; -- "member"."id"%TYPE[]
242 "loop_member_id_v" "member"."id"%TYPE;
243 "output_row" "delegation_chain_row";
244 "output_rows" "delegation_chain_row"[];
245 "simulate_v" BOOLEAN;
246 "simulate_here_v" BOOLEAN;
247 "delegation_row" "delegation"%ROWTYPE;
248 "row_count" INT4;
249 "i" INT4;
250 "loop_v" BOOLEAN;
251 BEGIN
252 IF "simulate_trustee_id_p" NOTNULL AND "simulate_default_p" THEN
253 RAISE EXCEPTION 'Both "simulate_trustee_id_p" is set, and "simulate_default_p" is true';
254 END IF;
255 IF "simulate_trustee_id_p" NOTNULL OR "simulate_default_p" THEN
256 "simulate_v" := TRUE;
257 ELSE
258 "simulate_v" := FALSE;
259 END IF;
260 IF
261 "unit_id_p" NOTNULL AND
262 "area_id_p" ISNULL AND
263 "issue_id_p" ISNULL
264 THEN
265 "scope_v" := 'unit';
266 "unit_id_v" := "unit_id_p";
267 ELSIF
268 "unit_id_p" ISNULL AND
269 "area_id_p" NOTNULL AND
270 "issue_id_p" ISNULL
271 THEN
272 "scope_v" := 'area';
273 "area_id_v" := "area_id_p";
274 SELECT "unit_id" INTO "unit_id_v"
275 FROM "area" WHERE "id" = "area_id_v";
276 ELSIF
277 "unit_id_p" ISNULL AND
278 "area_id_p" ISNULL AND
279 "issue_id_p" NOTNULL
280 THEN
281 SELECT INTO "issue_row" * FROM "issue" WHERE "id" = "issue_id_p";
282 IF "issue_row"."id" ISNULL THEN
283 RETURN;
284 END IF;
285 IF "issue_row"."closed" NOTNULL THEN
286 IF "simulate_v" THEN
287 RAISE EXCEPTION 'Tried to simulate delegation chain for closed issue.';
288 END IF;
289 FOR "output_row" IN
290 SELECT * FROM
291 "delegation_chain_for_closed_issue"("member_id_p", "issue_id_p")
292 LOOP
293 RETURN NEXT "output_row";
294 END LOOP;
295 RETURN;
296 END IF;
297 "scope_v" := 'issue';
298 SELECT "area_id" INTO "area_id_v"
299 FROM "issue" WHERE "id" = "issue_id_p";
300 SELECT "unit_id" INTO "unit_id_v"
301 FROM "area" WHERE "id" = "area_id_v";
302 ELSE
303 RAISE EXCEPTION 'Exactly one of unit_id_p, area_id_p, or issue_id_p must be NOTNULL.';
304 END IF;
305 "visited_member_ids" := '{}';
306 "loop_member_id_v" := NULL;
307 "output_rows" := '{}';
308 "output_row"."index" := 0;
309 "output_row"."member_id" := "member_id_p";
310 "output_row"."member_valid" := TRUE;
311 "output_row"."participation" := FALSE;
312 "output_row"."overridden" := FALSE;
313 "output_row"."disabled_out" := FALSE;
314 "output_row"."scope_out" := NULL;
315 LOOP
316 IF "visited_member_ids" @> ARRAY["output_row"."member_id"] THEN
317 "loop_member_id_v" := "output_row"."member_id";
318 ELSE
319 "visited_member_ids" :=
320 "visited_member_ids" || "output_row"."member_id";
321 END IF;
322 IF "output_row"."participation" ISNULL THEN
323 "output_row"."overridden" := NULL;
324 ELSIF "output_row"."participation" THEN
325 "output_row"."overridden" := TRUE;
326 END IF;
327 "output_row"."scope_in" := "output_row"."scope_out";
328 "output_row"."member_valid" := EXISTS (
329 SELECT NULL FROM "member"
330 LEFT JOIN "privilege"
331 ON "privilege"."member_id" = "member"."id"
332 AND "privilege"."unit_id" = "unit_id_v"
333 LEFT JOIN "issue_privilege"
334 ON "issue_privilege"."member_id" = "member"."id"
335 AND "issue_privilege"."issue_id" = "issue_id_p"
336 WHERE "id" = "output_row"."member_id"
337 AND "member"."active"
338 AND COALESCE(
339 "issue_privilege"."voting_right", "privilege"."voting_right")
340 );
341 "simulate_here_v" := (
342 "simulate_v" AND
343 "output_row"."member_id" = "member_id_p"
344 );
345 "delegation_row" := ROW(NULL);
346 IF "output_row"."member_valid" OR "simulate_here_v" THEN
347 IF "scope_v" = 'unit' THEN
348 IF NOT "simulate_here_v" THEN
349 SELECT * INTO "delegation_row" FROM "delegation"
350 WHERE "truster_id" = "output_row"."member_id"
351 AND "unit_id" = "unit_id_v";
352 END IF;
353 ELSIF "scope_v" = 'area' THEN
354 IF "simulate_here_v" THEN
355 IF "simulate_trustee_id_p" ISNULL THEN
356 SELECT * INTO "delegation_row" FROM "delegation"
357 WHERE "truster_id" = "output_row"."member_id"
358 AND "unit_id" = "unit_id_v";
359 END IF;
360 ELSE
361 SELECT * INTO "delegation_row" FROM "delegation"
362 WHERE "truster_id" = "output_row"."member_id"
363 AND (
364 "unit_id" = "unit_id_v" OR
365 "area_id" = "area_id_v"
366 )
367 ORDER BY "scope" DESC;
368 END IF;
369 ELSIF "scope_v" = 'issue' THEN
370 IF "issue_row"."fully_frozen" ISNULL THEN
371 "output_row"."participation" := EXISTS (
372 SELECT NULL FROM "interest"
373 WHERE "issue_id" = "issue_id_p"
374 AND "member_id" = "output_row"."member_id"
375 );
376 ELSE
377 IF "output_row"."member_id" = "member_id_p" THEN
378 "output_row"."participation" := EXISTS (
379 SELECT NULL FROM "direct_voter"
380 WHERE "issue_id" = "issue_id_p"
381 AND "member_id" = "output_row"."member_id"
382 );
383 ELSE
384 "output_row"."participation" := NULL;
385 END IF;
386 END IF;
387 IF "simulate_here_v" THEN
388 IF "simulate_trustee_id_p" ISNULL THEN
389 SELECT * INTO "delegation_row" FROM "delegation"
390 WHERE "truster_id" = "output_row"."member_id"
391 AND (
392 "unit_id" = "unit_id_v" OR
393 "area_id" = "area_id_v"
394 )
395 ORDER BY "scope" DESC;
396 END IF;
397 ELSE
398 SELECT * INTO "delegation_row" FROM "delegation"
399 WHERE "truster_id" = "output_row"."member_id"
400 AND (
401 "unit_id" = "unit_id_v" OR
402 "area_id" = "area_id_v" OR
403 "issue_id" = "issue_id_p"
404 )
405 ORDER BY "scope" DESC;
406 END IF;
407 END IF;
408 ELSE
409 "output_row"."participation" := FALSE;
410 END IF;
411 IF "simulate_here_v" AND "simulate_trustee_id_p" NOTNULL THEN
412 "output_row"."scope_out" := "scope_v";
413 "output_rows" := "output_rows" || "output_row";
414 "output_row"."member_id" := "simulate_trustee_id_p";
415 ELSIF "delegation_row"."trustee_id" NOTNULL THEN
416 "output_row"."scope_out" := "delegation_row"."scope";
417 "output_rows" := "output_rows" || "output_row";
418 "output_row"."member_id" := "delegation_row"."trustee_id";
419 ELSIF "delegation_row"."scope" NOTNULL THEN
420 "output_row"."scope_out" := "delegation_row"."scope";
421 "output_row"."disabled_out" := TRUE;
422 "output_rows" := "output_rows" || "output_row";
423 EXIT;
424 ELSE
425 "output_row"."scope_out" := NULL;
426 "output_rows" := "output_rows" || "output_row";
427 EXIT;
428 END IF;
429 EXIT WHEN "loop_member_id_v" NOTNULL;
430 "output_row"."index" := "output_row"."index" + 1;
431 END LOOP;
432 "row_count" := array_upper("output_rows", 1);
433 "i" := 1;
434 "loop_v" := FALSE;
435 LOOP
436 "output_row" := "output_rows"["i"];
437 EXIT WHEN "output_row" ISNULL; -- NOTE: ISNULL and NOT ... NOTNULL produce different results!
438 IF "loop_v" THEN
439 IF "i" + 1 = "row_count" THEN
440 "output_row"."loop" := 'last';
441 ELSIF "i" = "row_count" THEN
442 "output_row"."loop" := 'repetition';
443 ELSE
444 "output_row"."loop" := 'intermediate';
445 END IF;
446 ELSIF "output_row"."member_id" = "loop_member_id_v" THEN
447 "output_row"."loop" := 'first';
448 "loop_v" := TRUE;
449 END IF;
450 IF "scope_v" = 'unit' THEN
451 "output_row"."participation" := NULL;
452 END IF;
453 RETURN NEXT "output_row";
454 "i" := "i" + 1;
455 END LOOP;
456 RETURN;
457 END;
458 $$;
460 CREATE OR REPLACE FUNCTION "calculate_member_counts"()
461 RETURNS VOID
462 LANGUAGE 'plpgsql' VOLATILE AS $$
463 BEGIN
464 PERFORM "require_transaction_isolation"();
465 DELETE FROM "member_count";
466 INSERT INTO "member_count" ("total_count")
467 SELECT "total_count" FROM "member_count_view";
468 UPDATE "unit" SET
469 "member_count" = "view"."member_count",
470 "member_weight" = "view"."member_weight"
471 FROM "unit_member_count" AS "view"
472 WHERE "view"."unit_id" = "unit"."id";
473 RETURN;
474 END;
475 $$;
476 COMMENT ON FUNCTION "calculate_member_counts"() IS 'Updates "member_count" table and "member_count" and "member_weight" columns of table "area" by materializing data from views "member_count_view" and "unit_member_count"';
478 CREATE OR REPLACE FUNCTION "weight_of_added_delegations_for_snapshot"
479 ( "snapshot_id_p" "snapshot"."id"%TYPE,
480 "issue_id_p" "issue"."id"%TYPE,
481 "member_id_p" "member"."id"%TYPE,
482 "delegate_member_ids_p" "delegating_interest_snapshot"."delegate_member_ids"%TYPE )
483 RETURNS "direct_interest_snapshot"."weight"%TYPE
484 LANGUAGE 'plpgsql' VOLATILE AS $$
485 DECLARE
486 "issue_delegation_row" "issue_delegation"%ROWTYPE;
487 "delegate_member_ids_v" "delegating_interest_snapshot"."delegate_member_ids"%TYPE;
488 "weight_v" INT4;
489 "sub_weight_v" INT4;
490 BEGIN
491 PERFORM "require_transaction_isolation"();
492 "weight_v" := 0;
493 FOR "issue_delegation_row" IN
494 SELECT * FROM "issue_delegation"
495 WHERE "trustee_id" = "member_id_p"
496 AND "issue_id" = "issue_id_p"
497 LOOP
498 IF NOT EXISTS (
499 SELECT NULL FROM "direct_interest_snapshot"
500 WHERE "snapshot_id" = "snapshot_id_p"
501 AND "issue_id" = "issue_id_p"
502 AND "member_id" = "issue_delegation_row"."truster_id"
503 ) AND NOT EXISTS (
504 SELECT NULL FROM "delegating_interest_snapshot"
505 WHERE "snapshot_id" = "snapshot_id_p"
506 AND "issue_id" = "issue_id_p"
507 AND "member_id" = "issue_delegation_row"."truster_id"
508 ) THEN
509 "delegate_member_ids_v" :=
510 "member_id_p" || "delegate_member_ids_p";
511 INSERT INTO "delegating_interest_snapshot" (
512 "snapshot_id",
513 "issue_id",
514 "member_id",
515 "ownweight",
516 "scope",
517 "delegate_member_ids"
518 ) VALUES (
519 "snapshot_id_p",
520 "issue_id_p",
521 "issue_delegation_row"."truster_id",
522 "issue_delegation_row"."weight",
523 "issue_delegation_row"."scope",
524 "delegate_member_ids_v"
525 );
526 "sub_weight_v" := "issue_delegation_row"."weight" +
527 "weight_of_added_delegations_for_snapshot"(
528 "snapshot_id_p",
529 "issue_id_p",
530 "issue_delegation_row"."truster_id",
531 "delegate_member_ids_v"
532 );
533 UPDATE "delegating_interest_snapshot"
534 SET "weight" = "sub_weight_v"
535 WHERE "snapshot_id" = "snapshot_id_p"
536 AND "issue_id" = "issue_id_p"
537 AND "member_id" = "issue_delegation_row"."truster_id";
538 "weight_v" := "weight_v" + "sub_weight_v";
539 END IF;
540 END LOOP;
541 RETURN "weight_v";
542 END;
543 $$;
545 CREATE OR REPLACE FUNCTION "take_snapshot"
546 ( "issue_id_p" "issue"."id"%TYPE,
547 "area_id_p" "area"."id"%TYPE = NULL )
548 RETURNS "snapshot"."id"%TYPE
549 LANGUAGE 'plpgsql' VOLATILE AS $$
550 DECLARE
551 "area_id_v" "area"."id"%TYPE;
552 "unit_id_v" "unit"."id"%TYPE;
553 "snapshot_id_v" "snapshot"."id"%TYPE;
554 "issue_id_v" "issue"."id"%TYPE;
555 "member_id_v" "member"."id"%TYPE;
556 BEGIN
557 IF "issue_id_p" NOTNULL AND "area_id_p" NOTNULL THEN
558 RAISE EXCEPTION 'One of "issue_id_p" and "area_id_p" must be NULL';
559 END IF;
560 PERFORM "require_transaction_isolation"();
561 IF "issue_id_p" ISNULL THEN
562 "area_id_v" := "area_id_p";
563 ELSE
564 SELECT "area_id" INTO "area_id_v"
565 FROM "issue" WHERE "id" = "issue_id_p";
566 END IF;
567 SELECT "unit_id" INTO "unit_id_v" FROM "area" WHERE "id" = "area_id_v";
568 INSERT INTO "snapshot" ("area_id", "issue_id")
569 VALUES ("area_id_v", "issue_id_p")
570 RETURNING "id" INTO "snapshot_id_v";
571 INSERT INTO "snapshot_population" ("snapshot_id", "member_id", "weight")
572 SELECT
573 "snapshot_id_v",
574 "member"."id",
575 COALESCE("issue_privilege"."weight", "privilege"."weight")
576 FROM "member"
577 LEFT JOIN "privilege"
578 ON "privilege"."unit_id" = "unit_id_v"
579 AND "privilege"."member_id" = "member"."id"
580 LEFT JOIN "issue_privilege"
581 ON "issue_privilege"."issue_id" = "issue_id_p"
582 AND "issue_privilege"."member_id" = "member"."id"
583 WHERE "member"."active" AND COALESCE(
584 "issue_privilege"."voting_right", "privilege"."voting_right");
585 UPDATE "snapshot" SET
586 "population" = (
587 SELECT sum("weight") FROM "snapshot_population"
588 WHERE "snapshot_id" = "snapshot_id_v"
589 ) WHERE "id" = "snapshot_id_v";
590 FOR "issue_id_v" IN
591 SELECT "id" FROM "issue"
592 WHERE CASE WHEN "issue_id_p" ISNULL THEN
593 "area_id" = "area_id_p" AND
594 "state" = 'admission'
595 ELSE
596 "id" = "issue_id_p"
597 END
598 LOOP
599 INSERT INTO "snapshot_issue" ("snapshot_id", "issue_id")
600 VALUES ("snapshot_id_v", "issue_id_v");
601 INSERT INTO "direct_interest_snapshot"
602 ("snapshot_id", "issue_id", "member_id", "ownweight")
603 SELECT
604 "snapshot_id_v" AS "snapshot_id",
605 "issue_id_v" AS "issue_id",
606 "member"."id" AS "member_id",
607 COALESCE(
608 "issue_privilege"."weight", "privilege"."weight"
609 ) AS "ownweight"
610 FROM "issue"
611 JOIN "area" ON "issue"."area_id" = "area"."id"
612 JOIN "interest" ON "issue"."id" = "interest"."issue_id"
613 JOIN "member" ON "interest"."member_id" = "member"."id"
614 LEFT JOIN "privilege"
615 ON "privilege"."unit_id" = "area"."unit_id"
616 AND "privilege"."member_id" = "member"."id"
617 LEFT JOIN "issue_privilege"
618 ON "issue_privilege"."issue_id" = "issue_id_v"
619 AND "issue_privilege"."member_id" = "member"."id"
620 WHERE "issue"."id" = "issue_id_v"
621 AND "member"."active" AND COALESCE(
622 "issue_privilege"."voting_right", "privilege"."voting_right");
623 FOR "member_id_v" IN
624 SELECT "member_id" FROM "direct_interest_snapshot"
625 WHERE "snapshot_id" = "snapshot_id_v"
626 AND "issue_id" = "issue_id_v"
627 LOOP
628 UPDATE "direct_interest_snapshot" SET
629 "weight" = "ownweight" +
630 "weight_of_added_delegations_for_snapshot"(
631 "snapshot_id_v",
632 "issue_id_v",
633 "member_id_v",
634 '{}'
635 )
636 WHERE "snapshot_id" = "snapshot_id_v"
637 AND "issue_id" = "issue_id_v"
638 AND "member_id" = "member_id_v";
639 END LOOP;
640 INSERT INTO "direct_supporter_snapshot"
641 ( "snapshot_id", "issue_id", "initiative_id", "member_id",
642 "draft_id", "informed", "satisfied" )
643 SELECT
644 "snapshot_id_v" AS "snapshot_id",
645 "issue_id_v" AS "issue_id",
646 "initiative"."id" AS "initiative_id",
647 "supporter"."member_id" AS "member_id",
648 "supporter"."draft_id" AS "draft_id",
649 "supporter"."draft_id" = "current_draft"."id" AS "informed",
650 NOT EXISTS (
651 SELECT NULL FROM "critical_opinion"
652 WHERE "initiative_id" = "initiative"."id"
653 AND "member_id" = "supporter"."member_id"
654 ) AS "satisfied"
655 FROM "initiative"
656 JOIN "supporter"
657 ON "supporter"."initiative_id" = "initiative"."id"
658 JOIN "current_draft"
659 ON "initiative"."id" = "current_draft"."initiative_id"
660 JOIN "direct_interest_snapshot"
661 ON "snapshot_id_v" = "direct_interest_snapshot"."snapshot_id"
662 AND "supporter"."member_id" = "direct_interest_snapshot"."member_id"
663 AND "initiative"."issue_id" = "direct_interest_snapshot"."issue_id"
664 WHERE "initiative"."issue_id" = "issue_id_v";
665 DELETE FROM "temporary_suggestion_counts";
666 INSERT INTO "temporary_suggestion_counts"
667 ( "id",
668 "minus2_unfulfilled_count", "minus2_fulfilled_count",
669 "minus1_unfulfilled_count", "minus1_fulfilled_count",
670 "plus1_unfulfilled_count", "plus1_fulfilled_count",
671 "plus2_unfulfilled_count", "plus2_fulfilled_count" )
672 SELECT
673 "suggestion"."id",
674 ( SELECT coalesce(sum("di"."weight"), 0)
675 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
676 ON "di"."snapshot_id" = "snapshot_id_v"
677 AND "di"."issue_id" = "issue_id_v"
678 AND "di"."member_id" = "opinion"."member_id"
679 WHERE "opinion"."suggestion_id" = "suggestion"."id"
680 AND "opinion"."degree" = -2
681 AND "opinion"."fulfilled" = FALSE
682 ) AS "minus2_unfulfilled_count",
683 ( SELECT coalesce(sum("di"."weight"), 0)
684 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
685 ON "di"."snapshot_id" = "snapshot_id_v"
686 AND "di"."issue_id" = "issue_id_v"
687 AND "di"."member_id" = "opinion"."member_id"
688 WHERE "opinion"."suggestion_id" = "suggestion"."id"
689 AND "opinion"."degree" = -2
690 AND "opinion"."fulfilled" = TRUE
691 ) AS "minus2_fulfilled_count",
692 ( SELECT coalesce(sum("di"."weight"), 0)
693 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
694 ON "di"."snapshot_id" = "snapshot_id_v"
695 AND "di"."issue_id" = "issue_id_v"
696 AND "di"."member_id" = "opinion"."member_id"
697 WHERE "opinion"."suggestion_id" = "suggestion"."id"
698 AND "opinion"."degree" = -1
699 AND "opinion"."fulfilled" = FALSE
700 ) AS "minus1_unfulfilled_count",
701 ( SELECT coalesce(sum("di"."weight"), 0)
702 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
703 ON "di"."snapshot_id" = "snapshot_id_v"
704 AND "di"."issue_id" = "issue_id_v"
705 AND "di"."member_id" = "opinion"."member_id"
706 WHERE "opinion"."suggestion_id" = "suggestion"."id"
707 AND "opinion"."degree" = -1
708 AND "opinion"."fulfilled" = TRUE
709 ) AS "minus1_fulfilled_count",
710 ( SELECT coalesce(sum("di"."weight"), 0)
711 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
712 ON "di"."snapshot_id" = "snapshot_id_v"
713 AND "di"."issue_id" = "issue_id_v"
714 AND "di"."member_id" = "opinion"."member_id"
715 WHERE "opinion"."suggestion_id" = "suggestion"."id"
716 AND "opinion"."degree" = 1
717 AND "opinion"."fulfilled" = FALSE
718 ) AS "plus1_unfulfilled_count",
719 ( SELECT coalesce(sum("di"."weight"), 0)
720 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
721 ON "di"."snapshot_id" = "snapshot_id_v"
722 AND "di"."issue_id" = "issue_id_v"
723 AND "di"."member_id" = "opinion"."member_id"
724 WHERE "opinion"."suggestion_id" = "suggestion"."id"
725 AND "opinion"."degree" = 1
726 AND "opinion"."fulfilled" = TRUE
727 ) AS "plus1_fulfilled_count",
728 ( SELECT coalesce(sum("di"."weight"), 0)
729 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
730 ON "di"."snapshot_id" = "snapshot_id_v"
731 AND "di"."issue_id" = "issue_id_v"
732 AND "di"."member_id" = "opinion"."member_id"
733 WHERE "opinion"."suggestion_id" = "suggestion"."id"
734 AND "opinion"."degree" = 2
735 AND "opinion"."fulfilled" = FALSE
736 ) AS "plus2_unfulfilled_count",
737 ( SELECT coalesce(sum("di"."weight"), 0)
738 FROM "opinion" JOIN "direct_interest_snapshot" AS "di"
739 ON "di"."snapshot_id" = "snapshot_id_v"
740 AND "di"."issue_id" = "issue_id_v"
741 AND "di"."member_id" = "opinion"."member_id"
742 WHERE "opinion"."suggestion_id" = "suggestion"."id"
743 AND "opinion"."degree" = 2
744 AND "opinion"."fulfilled" = TRUE
745 ) AS "plus2_fulfilled_count"
746 FROM "suggestion" JOIN "initiative"
747 ON "suggestion"."initiative_id" = "initiative"."id"
748 WHERE "initiative"."issue_id" = "issue_id_v";
749 END LOOP;
750 RETURN "snapshot_id_v";
751 END;
752 $$;
754 CREATE OR REPLACE FUNCTION "weight_of_added_vote_delegations"
755 ( "issue_id_p" "issue"."id"%TYPE,
756 "member_id_p" "member"."id"%TYPE,
757 "delegate_member_ids_p" "delegating_voter"."delegate_member_ids"%TYPE )
758 RETURNS "direct_voter"."weight"%TYPE
759 LANGUAGE 'plpgsql' VOLATILE AS $$
760 DECLARE
761 "issue_delegation_row" "issue_delegation"%ROWTYPE;
762 "delegate_member_ids_v" "delegating_voter"."delegate_member_ids"%TYPE;
763 "weight_v" INT4;
764 "sub_weight_v" INT4;
765 BEGIN
766 PERFORM "require_transaction_isolation"();
767 "weight_v" := 0;
768 FOR "issue_delegation_row" IN
769 SELECT * FROM "issue_delegation"
770 WHERE "trustee_id" = "member_id_p"
771 AND "issue_id" = "issue_id_p"
772 LOOP
773 IF NOT EXISTS (
774 SELECT NULL FROM "direct_voter"
775 WHERE "member_id" = "issue_delegation_row"."truster_id"
776 AND "issue_id" = "issue_id_p"
777 ) AND NOT EXISTS (
778 SELECT NULL FROM "delegating_voter"
779 WHERE "member_id" = "issue_delegation_row"."truster_id"
780 AND "issue_id" = "issue_id_p"
781 ) THEN
782 "delegate_member_ids_v" :=
783 "member_id_p" || "delegate_member_ids_p";
784 INSERT INTO "delegating_voter" (
785 "issue_id",
786 "member_id",
787 "ownweight",
788 "scope",
789 "delegate_member_ids"
790 ) VALUES (
791 "issue_id_p",
792 "issue_delegation_row"."truster_id",
793 "issue_delegation_row"."weight",
794 "issue_delegation_row"."scope",
795 "delegate_member_ids_v"
796 );
797 "sub_weight_v" := "issue_delegation_row"."weight" +
798 "weight_of_added_vote_delegations"(
799 "issue_id_p",
800 "issue_delegation_row"."truster_id",
801 "delegate_member_ids_v"
802 );
803 UPDATE "delegating_voter"
804 SET "weight" = "sub_weight_v"
805 WHERE "issue_id" = "issue_id_p"
806 AND "member_id" = "issue_delegation_row"."truster_id";
807 "weight_v" := "weight_v" + "sub_weight_v";
808 END IF;
809 END LOOP;
810 RETURN "weight_v";
811 END;
812 $$;
814 CREATE OR REPLACE FUNCTION "add_vote_delegations"
815 ( "issue_id_p" "issue"."id"%TYPE )
816 RETURNS VOID
817 LANGUAGE 'plpgsql' VOLATILE AS $$
818 DECLARE
819 "member_id_v" "member"."id"%TYPE;
820 BEGIN
821 PERFORM "require_transaction_isolation"();
822 FOR "member_id_v" IN
823 SELECT "member_id" FROM "direct_voter"
824 WHERE "issue_id" = "issue_id_p"
825 LOOP
826 UPDATE "direct_voter" SET
827 "weight" = "ownweight" + "weight_of_added_vote_delegations"(
828 "issue_id_p",
829 "member_id_v",
830 '{}'
831 )
832 WHERE "member_id" = "member_id_v"
833 AND "issue_id" = "issue_id_p";
834 END LOOP;
835 RETURN;
836 END;
837 $$;
839 CREATE OR REPLACE FUNCTION "close_voting"("issue_id_p" "issue"."id"%TYPE)
840 RETURNS VOID
841 LANGUAGE 'plpgsql' VOLATILE AS $$
842 DECLARE
843 "area_id_v" "area"."id"%TYPE;
844 "unit_id_v" "unit"."id"%TYPE;
845 "member_id_v" "member"."id"%TYPE;
846 BEGIN
847 PERFORM "require_transaction_isolation"();
848 SELECT "area_id" INTO "area_id_v" FROM "issue" WHERE "id" = "issue_id_p";
849 SELECT "unit_id" INTO "unit_id_v" FROM "area" WHERE "id" = "area_id_v";
850 -- override protection triggers:
851 INSERT INTO "temporary_transaction_data" ("key", "value")
852 VALUES ('override_protection_triggers', TRUE::TEXT);
853 -- delete timestamp of voting comment:
854 UPDATE "direct_voter" SET "comment_changed" = NULL
855 WHERE "issue_id" = "issue_id_p";
856 -- delete delegating votes (in cases of manual reset of issue state):
857 DELETE FROM "delegating_voter"
858 WHERE "issue_id" = "issue_id_p";
859 -- delete votes from non-privileged voters:
860 DELETE FROM "direct_voter"
861 USING (
862 SELECT "direct_voter"."member_id"
863 FROM "direct_voter"
864 JOIN "member" ON "direct_voter"."member_id" = "member"."id"
865 LEFT JOIN "privilege"
866 ON "privilege"."unit_id" = "unit_id_v"
867 AND "privilege"."member_id" = "direct_voter"."member_id"
868 LEFT JOIN "issue_privilege"
869 ON "issue_privilege"."issue_id" = "issue_id_p"
870 AND "issue_privilege"."member_id" = "direct_voter"."member_id"
871 WHERE "direct_voter"."issue_id" = "issue_id_p" AND (
872 "member"."active" = FALSE OR
873 COALESCE(
874 "issue_privilege"."voting_right",
875 "privilege"."voting_right",
876 FALSE
877 ) = FALSE
878 )
879 ) AS "subquery"
880 WHERE "direct_voter"."issue_id" = "issue_id_p"
881 AND "direct_voter"."member_id" = "subquery"."member_id";
882 -- consider voting weight and delegations:
883 UPDATE "direct_voter" SET "ownweight" = "privilege"."weight"
884 FROM "privilege"
885 WHERE "issue_id" = "issue_id_p"
886 AND "privilege"."unit_id" = "unit_id_v"
887 AND "privilege"."member_id" = "direct_voter"."member_id";
888 UPDATE "direct_voter" SET "ownweight" = "issue_privilege"."weight"
889 FROM "issue_privilege"
890 WHERE "direct_voter"."issue_id" = "issue_id_p"
891 AND "issue_privilege"."issue_id" = "issue_id_p"
892 AND "issue_privilege"."member_id" = "direct_voter"."member_id";
893 PERFORM "add_vote_delegations"("issue_id_p");
894 -- mark first preferences:
895 UPDATE "vote" SET "first_preference" = "subquery"."first_preference"
896 FROM (
897 SELECT
898 "vote"."initiative_id",
899 "vote"."member_id",
900 CASE WHEN "vote"."grade" > 0 THEN
901 CASE WHEN "vote"."grade" = max("agg"."grade") THEN TRUE ELSE FALSE END
902 ELSE NULL
903 END AS "first_preference"
904 FROM "vote"
905 JOIN "initiative" -- NOTE: due to missing index on issue_id
906 ON "vote"."issue_id" = "initiative"."issue_id"
907 JOIN "vote" AS "agg"
908 ON "initiative"."id" = "agg"."initiative_id"
909 AND "vote"."member_id" = "agg"."member_id"
910 GROUP BY "vote"."initiative_id", "vote"."member_id", "vote"."grade"
911 ) AS "subquery"
912 WHERE "vote"."issue_id" = "issue_id_p"
913 AND "vote"."initiative_id" = "subquery"."initiative_id"
914 AND "vote"."member_id" = "subquery"."member_id";
915 -- finish overriding protection triggers (avoids garbage):
916 DELETE FROM "temporary_transaction_data"
917 WHERE "key" = 'override_protection_triggers';
918 -- materialize battle_view:
919 -- NOTE: "closed" column of issue must be set at this point
920 DELETE FROM "battle" WHERE "issue_id" = "issue_id_p";
921 INSERT INTO "battle" (
922 "issue_id",
923 "winning_initiative_id", "losing_initiative_id",
924 "count"
925 ) SELECT
926 "issue_id",
927 "winning_initiative_id", "losing_initiative_id",
928 "count"
929 FROM "battle_view" WHERE "issue_id" = "issue_id_p";
930 -- set voter count:
931 UPDATE "issue" SET
932 "voter_count" = (
933 SELECT coalesce(sum("weight"), 0)
934 FROM "direct_voter" WHERE "issue_id" = "issue_id_p"
935 )
936 WHERE "id" = "issue_id_p";
937 -- copy "positive_votes" and "negative_votes" from "battle" table:
938 -- NOTE: "first_preference_votes" is set to a default of 0 at this step
939 UPDATE "initiative" SET
940 "first_preference_votes" = 0,
941 "positive_votes" = "battle_win"."count",
942 "negative_votes" = "battle_lose"."count"
943 FROM "battle" AS "battle_win", "battle" AS "battle_lose"
944 WHERE
945 "battle_win"."issue_id" = "issue_id_p" AND
946 "battle_win"."winning_initiative_id" = "initiative"."id" AND
947 "battle_win"."losing_initiative_id" ISNULL AND
948 "battle_lose"."issue_id" = "issue_id_p" AND
949 "battle_lose"."losing_initiative_id" = "initiative"."id" AND
950 "battle_lose"."winning_initiative_id" ISNULL;
951 -- calculate "first_preference_votes":
952 -- NOTE: will only set values not equal to zero
953 UPDATE "initiative" SET "first_preference_votes" = "subquery"."sum"
954 FROM (
955 SELECT "vote"."initiative_id", sum("direct_voter"."weight")
956 FROM "vote" JOIN "direct_voter"
957 ON "vote"."issue_id" = "direct_voter"."issue_id"
958 AND "vote"."member_id" = "direct_voter"."member_id"
959 WHERE "vote"."first_preference"
960 GROUP BY "vote"."initiative_id"
961 ) AS "subquery"
962 WHERE "initiative"."issue_id" = "issue_id_p"
963 AND "initiative"."admitted"
964 AND "initiative"."id" = "subquery"."initiative_id";
965 END;
966 $$;
968 COMMIT;

Impressum / About Us