From 491ca1328408f734ee5296b9017734ce98b7d8da Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 12 Mar 2020 12:38:32 +0100 Subject: [PATCH] #29 Implement Workgroup (create query) Create SQL query to get/set workgroup Add workgroup to article query --- .idea/runConfigurations/Fixtures_on_Test.xml | 6 +- .idea/runConfigurations/Test_All_SQL.xml | 11 +++- .idea/runConfigurations/Test_Follow.xml | 2 +- .idea/runConfigurations/Test_Opinions.xml | 2 +- .idea/runConfigurations/Workgroup_test.xml | 31 ++++++++++ .../resources/sql/fixtures/04-article.sql | 7 ++- .../functions/article/find_article_by_id.sql | 1 + .../sql/functions/article/find_articles.sql | 1 + .../find_articles_versions_by_version_id.sql | 1 + .../find_last_article_by_version_id.sql | 1 + .../sql/functions/article/upsert_article.sql | 5 +- .../workgroup/find_workgroup_by_id.sql | 22 +++++++ .../functions/workgroup/find_workgroups.sql | 59 +++++++++++++++++++ .../functions/workgroup/upsert_workgroup.sql | 29 +++++++++ .../sql/migrations/0000-init_schema.up.sql | 25 +++++++- src/test/sql/fixtures/fixture_workgroup.sql | 29 +++++++++ src/test/sql/workgroup.sql | 44 ++++++++++++++ 17 files changed, 264 insertions(+), 12 deletions(-) create mode 100644 .idea/runConfigurations/Workgroup_test.xml create mode 100644 src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql create mode 100644 src/main/resources/sql/functions/workgroup/find_workgroups.sql create mode 100644 src/main/resources/sql/functions/workgroup/upsert_workgroup.sql create mode 100644 src/test/sql/fixtures/fixture_workgroup.sql create mode 100644 src/test/sql/workgroup.sql diff --git a/.idea/runConfigurations/Fixtures_on_Test.xml b/.idea/runConfigurations/Fixtures_on_Test.xml index 1edd808..c835ed6 100644 --- a/.idea/runConfigurations/Fixtures_on_Test.xml +++ b/.idea/runConfigurations/Fixtures_on_Test.xml @@ -1,7 +1,5 @@ - - @@ -13,6 +11,8 @@ FILE - + + \ No newline at end of file diff --git a/.idea/runConfigurations/Test_All_SQL.xml b/.idea/runConfigurations/Test_All_SQL.xml index 91b3691..0c1b39f 100644 --- a/.idea/runConfigurations/Test_All_SQL.xml +++ b/.idea/runConfigurations/Test_All_SQL.xml @@ -1,7 +1,5 @@ - - @@ -55,6 +53,10 @@ + + + + @@ -63,8 +65,11 @@ + FILE - + + \ No newline at end of file diff --git a/.idea/runConfigurations/Test_Follow.xml b/.idea/runConfigurations/Test_Follow.xml index 5b88876..fe3e336 100644 --- a/.idea/runConfigurations/Test_Follow.xml +++ b/.idea/runConfigurations/Test_Follow.xml @@ -11,7 +11,7 @@ FILE - \ No newline at end of file diff --git a/.idea/runConfigurations/Test_Opinions.xml b/.idea/runConfigurations/Test_Opinions.xml index 2c59f4e..735f7a7 100644 --- a/.idea/runConfigurations/Test_Opinions.xml +++ b/.idea/runConfigurations/Test_Opinions.xml @@ -13,7 +13,7 @@ FILE - \ No newline at end of file diff --git a/.idea/runConfigurations/Workgroup_test.xml b/.idea/runConfigurations/Workgroup_test.xml new file mode 100644 index 0000000..dff779a --- /dev/null +++ b/.idea/runConfigurations/Workgroup_test.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/sql/fixtures/04-article.sql b/src/main/resources/sql/fixtures/04-article.sql index 719c03e..fe2bfdc 100644 --- a/src/main/resources/sql/fixtures/04-article.sql +++ b/src/main/resources/sql/fixtures/04-article.sql @@ -9,15 +9,17 @@ declare } $tags$; _citizen_count int = (select count(z) from citizen z); + _workgroup_count int = (select count(w) from workgroup w); begin delete from article_relations; delete from article; - insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags, created_at, draft) + insert into article (id, version_id, created_by_id, workgroup_id, title, anonymous, content, description, tags, created_at, draft) select uuid_in(md5('article'||row_number() over ())::cstring), uuid_in(md5('article_v'||row_number() over () % (_citizen_count / 2))::cstring), z.id, + case when row_number() over () % 2 = 0 then w.id end, 'title' || row_number() over (), row_number() over () % 3 = 0, 'content' || row_number() over (), @@ -25,7 +27,8 @@ begin _tags[(row_number() over () % 5):(row_number() over () % 9)], now() + (row_number() over () * interval '7 minute 3 second'), (row_number() over () % 7) = 0 - from citizen z; + from (select *, row_number() over () rn from citizen z) z + join (select *, row_number() over () % _workgroup_count rn from workgroup) w using (rn); insert into article_relations (source_id, target_id, created_by_id, comment) select diff --git a/src/main/resources/sql/functions/article/find_article_by_id.sql b/src/main/resources/sql/functions/article/find_article_by_id.sql index f2e714d..0707434 100644 --- a/src/main/resources/sql/functions/article/find_article_by_id.sql +++ b/src/main/resources/sql/functions/article/find_article_by_id.sql @@ -8,6 +8,7 @@ begin select a.*, find_citizen_by_id(a.created_by_id) as created_by, + find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes, count_opinion(a.id) as opinions into resource diff --git a/src/main/resources/sql/functions/article/find_articles.sql b/src/main/resources/sql/functions/article/find_articles.sql index cd9e5e0..8c6f032 100644 --- a/src/main/resources/sql/functions/article/find_articles.sql +++ b/src/main/resources/sql/functions/article/find_articles.sql @@ -22,6 +22,7 @@ begin select a.*, find_citizen_by_id(a.created_by_id) as created_by, + find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes, count_opinion(a.id) as opinions, zdb.score(a.ctid) _score diff --git a/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql b/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql index 3c16167..31ffdce 100644 --- a/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql +++ b/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql @@ -15,6 +15,7 @@ begin select a.*, find_citizen_by_id(a.created_by_id) as created_by, + find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes from article as a where a.version_id = _version_id diff --git a/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql b/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql index c88ec2f..d0c8d31 100644 --- a/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql +++ b/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql @@ -8,6 +8,7 @@ begin select a.*, find_citizen_by_id(a.created_by_id) as created_by, + find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes into resource from article as a diff --git a/src/main/resources/sql/functions/article/upsert_article.sql b/src/main/resources/sql/functions/article/upsert_article.sql index 42e38f9..fd925ba 100644 --- a/src/main/resources/sql/functions/article/upsert_article.sql +++ b/src/main/resources/sql/functions/article/upsert_article.sql @@ -19,6 +19,8 @@ begin if (_existing_draft_id is not null) then update article a2 set + created_by_id = (resource#>>'{created_by, id}')::uuid, + workgroup_id = (resource#>>'{workgroup, id}')::uuid, title = a.title, anonymous = a.anonymous, content = a.content, @@ -29,12 +31,13 @@ begin where a2.id = (_existing_draft_id)::uuid returning a2.id into new_id; else - insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags, draft) + insert into article (id, version_id, created_by_id, workgroup_id, title, anonymous, content, description, tags, draft) select case when _id_exist then uuid_generate_v4() else coalesce(id, uuid_generate_v4()) end, coalesce(version_id, uuid_generate_v4()), (resource#>>'{created_by, id}')::uuid, + (resource#>>'{workgroup, id}')::uuid, title, anonymous, content, diff --git a/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql b/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql new file mode 100644 index 0000000..7b8173d --- /dev/null +++ b/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql @@ -0,0 +1,22 @@ +create or replace function find_workgroup_by_id(in id uuid, out resource json) language plpgsql as +$$ +declare + _id alias for id; +begin + select to_json(t) + from ( + select + w.*, + find_citizen_by_id(w.created_by_id) as created_by, + find_citizen_by_id(w.owner_id) as owner + into resource + from workgroup as w + left join citizen_in_workgroup ciw on w.id = ciw.workgroup_id + where w.id = _id + and deleted_at is null + ) as t; +end; +$$; + +-- drop function if exists find_workgroup_by_id(uuid, out json); +-- select * from find_workgroup_by_id('d011ad4c-fa1b-40a3-593b-7816479ff33b') diff --git a/src/main/resources/sql/functions/workgroup/find_workgroups.sql b/src/main/resources/sql/functions/workgroup/find_workgroups.sql new file mode 100644 index 0000000..6a5c6c1 --- /dev/null +++ b/src/main/resources/sql/functions/workgroup/find_workgroups.sql @@ -0,0 +1,59 @@ +create or replace function find_workgroups( + _search text default null, + _filter json default '{}', + direction text default 'desc', + sort text default 'created_at', + "limit" int default 50, + "offset" int default 0, + out resource json, + out total int +) language plpgsql as +$$ +begin + select json_agg(t), ( + select count(id) + from workgroup w + where deleted_at is null + and (_search is null or _search = '' or w ==> dsl.multi_match('{name^3, description}', _search)) + and (_filter->>'created_by_id' is null or w.created_by_id = (_filter->>'created_by_id')::uuid) + ) + into resource, total + from ( + select + w.*, + find_citizen_by_id(w.created_by_id) as created_by, + find_citizen_by_id(w.owner_id) as owner, + zdb.score(w.ctid) _score + from workgroup as w + where deleted_at is null + and ( + _search is null + or _search = '' + or w ==> dsl.multi_match('{name^3, description}', _search) + ) + and (_filter->>'created_by_id' is null or w.created_by_id = (_filter->>'created_by_id')::uuid) + + order by + _score desc, + case direction when 'asc' then + case sort + when 'name' then w.name + when 'created_at' then w.created_at::text + else null + end + end, + case direction when 'desc' then + case sort + when 'title' then w.name + when 'created_at' then w.created_at::text + end + end + desc, + w.created_at desc + limit "limit" offset "offset" + ) as t; +end; +$$; + +-- drop function if exists find_workgroups(text, json, text, text, int, int); +-- select * from find_workgroups('49', "limit" := 2) \ No newline at end of file diff --git a/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql b/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql new file mode 100644 index 0000000..c2d825f --- /dev/null +++ b/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql @@ -0,0 +1,29 @@ +create or replace function upsert_workgroup(inout resource json) + language plpgsql as +$$ +declare + new_id uuid = coalesce((resource->>'id')::uuid, uuid_generate_v4()); +begin + insert into workgroup (id, created_by_id, name, description, anonymous, logo, owner_id) + select + new_id, + (resource#>>'{created_by, id}')::uuid, + name, + description, + anonymous, + logo, + (resource#>>'{owner, id}')::uuid + from json_populate_record(null::workgroup, resource) + on conflict (id) do update set + name = excluded.name, + description = excluded.description, + anonymous = excluded.anonymous, + logo = excluded.logo, + owner_id = excluded.owner_id; + + + select find_workgroup_by_id(new_id) into resource; +end; +$$; + +-- drop procedure if exists upsert_workgroup(inout json); \ No newline at end of file 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 d635838..1e87249 100644 --- a/src/main/resources/sql/migrations/0000-init_schema.up.sql +++ b/src/main/resources/sql/migrations/0000-init_schema.up.sql @@ -27,6 +27,7 @@ create table workgroup id uuid default uuid_generate_v4() not null primary key, created_at timestamptz default now() not null, updated_at timestamptz default now() not null check ( updated_at >= created_at ), + deleted_at timestamptz null check ( deleted_at is null or deleted_at >= updated_at ), created_by_id uuid not null references citizen (id), name varchar(128) not null, description text null, @@ -194,6 +195,7 @@ create table article id uuid default uuid_generate_v4() not null primary key, created_at timestamptz default now() not null, created_by_id uuid not null references citizen (id), + workgroup_id uuid null references workgroup (id), version_id uuid default uuid_generate_v4() not null, version_number int not null, title text not null check ( length(title) < 128 ), @@ -740,4 +742,25 @@ create index citizen_idx using zombodb ((citizen.*)) with (alias ='citizen_idx'); -reindex index citizen_idx; \ No newline at end of file +reindex index citizen_idx; + + +-- INDEX workgroup table +select zdb.define_field_mapping('workgroup', 'name', '{ + "type": "text", + "analyzer": "name_analyzer", + "search_analyzer": "name_analyzer" +}'); + +select zdb.define_field_mapping('workgroup', 'description', '{ + "type": "text", + "analyzer": "fr_analyzer", + "search_analyzer": "fr_analyzer" +}'); + +create index workgroup_idx + on workgroup + using zombodb ((workgroup.*)) + with (alias ='workgroup_idx'); + +reindex index workgroup_idx; \ No newline at end of file diff --git a/src/test/sql/fixtures/fixture_workgroup.sql b/src/test/sql/fixtures/fixture_workgroup.sql new file mode 100644 index 0000000..cdf029c --- /dev/null +++ b/src/test/sql/fixtures/fixture_workgroup.sql @@ -0,0 +1,29 @@ +create or replace function fixture_workgroup(in name text default 'vert', _citizen_id uuid default fixture_citizen(), out _article_id uuid) + language plpgsql as +$$ +declare + created_workgroup json; +begin + if (name = 'vert') then + created_workgroup = '{ + "name": "Le groupe des vert", + "description": "test", + "anonymous": false + }'; + elseif (name = 'rouge') then + created_workgroup = '{ + "name": "Le groupe des rouge", + "description": "test", + "anonymous": false + }'; + end if; + + created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + created_workgroup := jsonb_set(created_workgroup::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text); + + -- upsert workgroup + select upsert_workgroup(created_workgroup) into created_workgroup; + assert created_workgroup->>'description' is not null, 'description should not be null'; +end; +$$ \ No newline at end of file diff --git a/src/test/sql/workgroup.sql b/src/test/sql/workgroup.sql new file mode 100644 index 0000000..4afe90d --- /dev/null +++ b/src/test/sql/workgroup.sql @@ -0,0 +1,44 @@ +do +$$ +declare + _citizen_id uuid := fixture_citizen(); + created_workgroup json := '{ + "name": "Le groupe des vert", + "description": "test", + "anonymous": false + }'; + created_workgroup_2 json := '{ + "name": "hello", + "description": "super", + "anonymous": false + }'; + selected_workgroup json; + selected_workgroup_2 json; +begin + created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + created_workgroup := jsonb_set(created_workgroup::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text); + + -- upsert workgroup + select upsert_workgroup(created_workgroup) into created_workgroup; + assert created_workgroup->>'description' is not null, 'description should not be null'; + assert (created_workgroup->>'name') = 'Le groupe des vert', format('name must be equal to "Le groupe des vert", %s instead', created_workgroup->>'name'); + + -- insert another workgroup + created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; + assert created_workgroup_2#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup_2#>>'{created_by, id}', _citizen_id::text); + select upsert_workgroup(created_workgroup_2) into created_workgroup_2; + + -- get workgroup by id and check the name + select find_workgroup_by_id((created_workgroup->>'id')::uuid) into selected_workgroup; + assert selected_workgroup->>'name' = 'Le groupe des vert', format('name must be "Le groupe des vert", %s', selected_workgroup->>'name'); + + -- search workgroups and check the name + select (w.resource->0) into selected_workgroup from find_workgroups('Le groupe des vert', "limit" := 1) w; + assert (selected_workgroup->>'name') = 'Le groupe des vert', format('name must be "Le groupe des vert" instead of : %s', (selected_workgroup->>'name')); + + rollback; + raise notice 'workgroup test pass'; +end +$$;