diff --git a/resources/functions/vote/vote.sql b/resources/functions/vote/vote.sql new file mode 100644 index 0000000..3a11f9e --- /dev/null +++ b/resources/functions/vote/vote.sql @@ -0,0 +1,35 @@ +create or replace function vote(reference regclass, _target_id uuid, _citizen_id uuid, _note int, _anonymous bool default true) returns void + language plpgsql as +$$ +begin + if reference = 'article'::regclass then + insert into vote_for_article (citizen_id, target_id, note, anonymous) + values (_citizen_id, _target_id, _note, _anonymous) + on conflict (citizen_id, target_id) do update set + note = excluded.note, + anonymous = excluded.anonymous; + elseif reference = 'constitution'::regclass then + insert into vote_for_constitution (citizen_id, target_id, note, anonymous) + values (_citizen_id, _target_id, _note, _anonymous) + on conflict (citizen_id, target_id) do update set + note = excluded.note, + anonymous = excluded.anonymous; + elseif reference = 'comment_on_article'::regclass then + insert into vote_for_comment_on_article (citizen_id, target_id, note, anonymous) + values (_citizen_id, _target_id, _note, _anonymous) + on conflict (citizen_id, target_id) do update set + note = excluded.note, + anonymous = excluded.anonymous; + elseif reference = 'comment_on_constitution'::regclass then + insert into vote_for_comment_on_constitution (citizen_id, target_id, note, anonymous) + values (_citizen_id, _target_id, _note, _anonymous) + on conflict (citizen_id, target_id) do update set + note = excluded.note, + anonymous = excluded.anonymous; + else + raise exception '% no implemented', reference::text; + end if; +end; +$$; + +-- drop function if exists vote(regclass,uuid,uuid,integer,boolean); \ No newline at end of file diff --git a/resources/sql/migrations/0000-init_schema.up.sql b/resources/sql/migrations/0000-init_schema.up.sql index 1500e70..cee2c62 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -256,35 +256,44 @@ create table vote anonymous boolean default true not null, note int not null check ( note >= -1 and note <= 1 ), foreign key (citizen_id) references citizen (id), - primary key (id) + primary key (id), + unique (citizen_id, target_id) ) inherits (extra); create table vote_for_article ( + target_reference regclass default 'article'::regclass not null, foreign key (target_id) references article (id), foreign key (citizen_id) references citizen (id), - primary key (id) + primary key (id), + unique (citizen_id, target_id) ) inherits (vote); create table vote_for_constitution ( + target_reference regclass default 'constitution'::regclass not null, foreign key (target_id) references constitution (id), foreign key (citizen_id) references citizen (id), - primary key (id) + primary key (id), + unique (citizen_id, target_id) ) inherits (vote); create table vote_for_comment_on_article ( + target_reference regclass default 'comment_on_article'::regclass not null, foreign key (target_id) references comment_on_article (id), foreign key (citizen_id) references citizen (id), - primary key (id) + primary key (id), + unique (citizen_id, target_id) ) inherits (vote); create table vote_for_comment_on_constitution ( - primary key (id), + target_reference regclass default 'comment_on_constitution'::regclass not null, foreign key (target_id) references comment_on_constitution (id), - foreign key (target_id) references citizen (id) + foreign key (citizen_id) references citizen (id), + primary key (id), + unique (citizen_id, target_id) ) inherits (vote); -- Stats diff --git a/resources/tests/vote.sql b/resources/tests/vote.sql new file mode 100644 index 0000000..172c536 --- /dev/null +++ b/resources/tests/vote.sql @@ -0,0 +1,82 @@ +do +$$ +declare + created_user json := '{"username": "george", "plain_password": "azerty"}'; + _citizen_id uuid; + created_citizen json := $json$ + { + "name": { + "first_name": "George", + "last_name": "MICHEL" + }, + "birthday": "2001-01-01" + } + $json$; + created_article json := $json$ + { + "version_id": "933b6a1b-50c9-42b6-989f-c02a57814ef9", + "title": "Love the world", + "annonymous": false, + "content": "bla bal bla", + "tags": [ + "love", + "test" + ] + } + $json$; +begin + -- insert user for context + call insert_user(created_user); + created_citizen := jsonb_set(created_citizen::jsonb, '{user}'::text[], jsonb_build_object('id', created_user->>'id'), true)::json; + + -- insert new citizen for context + call upsert_citizen(created_citizen); + _citizen_id := created_citizen->>'id'; + created_article := jsonb_set(created_article::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + assert created_article#>>'{created_by, id}' = _citizen_id::text, format('citizenId in article must be the same as citizen, %s != %s', created_article#>>'{created_by, id}', _citizen_id::text); + -- upsert article + call upsert_article(created_article); + + + perform vote( + reference => 'article'::regclass, + _target_id => (created_article->>'id')::uuid, + _citizen_id => _citizen_id, + _note => 1 + ); + assert (select count(*) = 1 from vote_for_article), 'vote must be inserted'; + assert (select note = 1 from vote_for_article limit 1), 'vote must be equal to 1'; + + perform vote( + reference => 'article'::regclass, + _target_id => (created_article->>'id')::uuid, + _citizen_id => _citizen_id, + _note => -1 + ); + assert (select count(*) = 1 from vote_for_article), 'vote must be inserted'; + assert (select note = -1 from vote_for_article limit 1), 'vote must be equal to -1'; + + begin + perform vote( + reference => 'article'::regclass, + _target_id => (created_article->>'id')::uuid, + _citizen_id => _citizen_id, + _note => -10 + ); + assert false, 'vote must be throw exception if note is not -1, 0 or 1'; + exception when check_violation then + end; + + + -- delete vote and context + delete from vote; + delete from article; + delete from citizen; + delete from "user"; + + raise notice 'vote test pass'; +end; +$$; + + +-- select uuid_generate_v4(); \ No newline at end of file