diff --git a/src/main/resources/sql/functions/opinion/count_opinion.sql b/src/main/resources/sql/functions/opinion/count_opinion.sql new file mode 100644 index 0000000..dccfb4a --- /dev/null +++ b/src/main/resources/sql/functions/opinion/count_opinion.sql @@ -0,0 +1,27 @@ +create or replace function count_opinion(_target_id uuid, out resource json) + language plpgsql as +$$ +declare + agg jsonb; + empty jsonb = '[]'::jsonb; +begin + select jsonb_object_agg(t.label, t.total) + into agg + from ( + select + count(o.opinion) as total, + ol.name as label + from opinion o + join opinion_list ol on o.opinion = ol.id + where o.target_id = _target_id + group by ol.name + order by ol.name + ) t; + + resource = empty || coalesce(agg, empty); +end; +$$; + +-- drop function if exists count_opinion(uuid); + +-- select * from count_opinion('ced1563f-ecf5-4f11-8518-8aeceff3c13a'); \ No newline at end of file diff --git a/src/main/resources/sql/functions/opinion/opinion.sql b/src/main/resources/sql/functions/opinion/opinion.sql new file mode 100644 index 0000000..a983eaa --- /dev/null +++ b/src/main/resources/sql/functions/opinion/opinion.sql @@ -0,0 +1,17 @@ +create or replace function opinion(reference regclass, _target_id uuid, _created_by_id uuid, _opinion uuid, out resource json) + language plpgsql as +$$ +begin + if reference = 'article'::regclass then + insert into opinion_on_article (created_by_id, target_id, opinion) + values (_created_by_id, _target_id, _opinion) + on conflict (created_by_id, target_id, opinion) do nothing; + else + raise exception '% no implemented for opinion', reference::text; + end if; + + select count_opinion(_target_id) into resource; +end; +$$; + +-- drop function if exists vote(regclass,uuid,uuid,integer,boolean); \ No newline at end of file diff --git a/src/main/resources/sql/migrations/0000-init_schema.down.sql b/src/main/resources/sql/migrations/0000-init_schema.down.sql index f2885a1..43c7b38 100644 --- a/src/main/resources/sql/migrations/0000-init_schema.down.sql +++ b/src/main/resources/sql/migrations/0000-init_schema.down.sql @@ -2,6 +2,10 @@ drop table if exists resource_view; -- Extra resources +drop table if exists opinion_on_article; +drop table if exists opinion; +drop table if exists opinion_list; + drop table if exists follow_article; drop table if exists follow_constitution; drop table if exists follow_citizen; diff --git a/src/main/resources/sql/migrations/0000-init_schema.up.sql b/src/main/resources/sql/migrations/0000-init_schema.up.sql index 8aead58..6020c8e 100644 --- a/src/main/resources/sql/migrations/0000-init_schema.up.sql +++ b/src/main/resources/sql/migrations/0000-init_schema.up.sql @@ -503,6 +503,32 @@ create table resource_view ip cidr null ); +create table opinion_list +( + id uuid default uuid_generate_v4() not null primary key, + name text not null, + target text null, + created_at timestamptz default now() not null, + deleted_at timestamptz null +); + +create table opinion +( + opinion uuid not null references opinion_list (id), + foreign key (created_by_id) references citizen (id), + primary key (id), + unique (created_by_id, target_id, opinion) +) inherits (extra); + +create table opinion_on_article +( + target_reference regclass default 'article'::regclass not null, + foreign key (opinion) references opinion_list (id), + foreign key (target_id) references article (id), + foreign key (created_by_id) references citizen (id), + primary key (id), + unique (created_by_id, target_id, opinion) +) inherits (opinion); -------------- diff --git a/src/test/sql/opinion.sql b/src/test/sql/opinion.sql new file mode 100644 index 0000000..f8d2abe --- /dev/null +++ b/src/test/sql/opinion.sql @@ -0,0 +1,89 @@ +do +$$ +declare + created_user json := '{"username": "george", "plain_password": "azerty", "roles": ["ROLE_USER"]}'; + created_user2 json := '{"username": "george2", "plain_password": "azerty", "roles": ["ROLE_USER"]}'; + _citizen_id uuid; + _citizen_id2 uuid; + created_citizen json := $json$ + { + "name": { + "first_name": "George", + "last_name": "MICHEL" + }, + "birthday": "2001-01-01", + "email":"george.michel@gmail.com" + } + $json$; + created_citizen2 json := $json$ + { + "name": { + "first_name": "George2", + "last_name": "MICHEL2" + }, + "birthday": "2001-01-02", + "email":"george.michel2@gmail.com" + } + $json$; + created_article json := $json$ + { + "version_id": "933b6a1b-50c9-42b6-989f-c02a57814ef9", + "title": "Love the world", + "anonymous": false, + "content": "bla bal bla", + "tags": [ + "love", + "test" + ], + "draft":false + } + $json$; + opinion1 uuid = uuid_generate_v4(); + opinion2 uuid = uuid_generate_v4(); +begin + -- insert user for context + select insert_user(created_user) into created_user; + select insert_user(created_user2) into created_user2; + created_citizen := jsonb_set(created_citizen::jsonb, '{user}'::text[], jsonb_build_object('id', created_user->>'id'), true)::json; + created_citizen2 := jsonb_set(created_citizen2::jsonb, '{user}'::text[], jsonb_build_object('id', created_user2->>'id'), true)::json; + + -- insert new citizen for context + select upsert_citizen(created_citizen) into created_citizen; + select upsert_citizen(created_citizen2) into created_citizen2; + _citizen_id := created_citizen->>'id'; + _citizen_id2 := created_citizen2->>'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 + select upsert_article(created_article) into created_article; + + + insert into opinion_list(id, name, target) + values (opinion1, 'Opinion1', (created_article->>'id')::uuid); + + insert into opinion_list(id, name, target) + values (opinion2, 'Opinion2', (created_article->>'id')::uuid); + + insert into opinion_list(name, target) + values ('Opinion3', (created_article->>'id')::uuid); + + perform opinion( + reference => 'article'::regclass, + _target_id => (created_article->>'id')::uuid, + _created_by_id => _citizen_id, + _opinion => opinion1 + ); + assert (select count(*) = 1 from opinion_on_article), 'opinion must be inserted'; + assert (select opinion = opinion1 from opinion_on_article limit 1), 'opinion must be inserted'; + + + -- delete vote and context + delete from opinion; + delete from opinion_list; + delete from article; + delete from citizen; + delete from "user"; + + raise notice 'opinion test pass'; +end; +$$;