Merge pull request #20 from flecomte/#4
#4
This commit was merged in pull request #20.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,5 @@
|
|||||||
/.idea
|
/.idea
|
||||||
/out
|
/out
|
||||||
/build
|
/build
|
||||||
*.iml
|
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
|
|||||||
11
.idea/dataSources.xml
generated
Normal file
11
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="dc-project@localhost" uuid="28368159-3c2d-4612-8719-e55ce11b962a">
|
||||||
|
<driver-ref>postgresql</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:postgresql://localhost:5432/dc-project</jdbc-url>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
|
|||||||
10
.idea/modules.xml
generated
Normal file
10
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/dcproject.iml" filepath="$PROJECT_DIR$/dcproject.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/dcproject.main.iml" filepath="$PROJECT_DIR$/.idea/modules/dcproject.main.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/dcproject.test.iml" filepath="$PROJECT_DIR$/.idea/modules/dcproject.test.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
111
.idea/modules/dcproject.main.iml
generated
Normal file
111
.idea/modules/dcproject.main.iml
generated
Normal file
File diff suppressed because one or more lines are too long
160
.idea/modules/dcproject.test.iml
generated
Normal file
160
.idea/modules/dcproject.test.iml
generated
Normal file
File diff suppressed because one or more lines are too long
31
.idea/runConfigurations/dcproject__run_.xml
generated
Normal file
31
.idea/runConfigurations/dcproject__run_.xml
generated
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="dcproject [run]" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="run" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" value="" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<extension name="net.ashald.envfile">
|
||||||
|
<option name="IS_ENABLED" value="false" />
|
||||||
|
<option name="IS_SUBST" value="false" />
|
||||||
|
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
|
||||||
|
<option name="IS_IGNORE_MISSING_FILES" value="false" />
|
||||||
|
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
|
||||||
|
<ENTRIES>
|
||||||
|
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
|
||||||
|
</ENTRIES>
|
||||||
|
</extension>
|
||||||
|
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
9
.idea/sqldialects.xml
generated
Normal file
9
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="PROJECT" dialect="PostgreSQL" />
|
||||||
|
</component>
|
||||||
|
<component name="SqlResolveMappings">
|
||||||
|
<file url="PROJECT" scope="{"node":{ "@negative":"1", "group":{ "@kind":"root", "node":{ "name":{ "@qname":"28368159-3c2d-4612-8719-e55ce11b962a" }, "group":{ "@kind":"database", "node":{ "name":{ "@qname":"dc-project" }, "group":{ "@kind":"schema", "node":{ "@negative":"1" } } } } } } }}" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
11
dcproject.iml
Normal file
11
dcproject.iml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.linked.project.id="dcproject" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="fr.dcproject" external.system.module.version="0.0.1" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
18
resources/functions/article/find_article_by_id.sql
Normal file
18
resources/functions/article/find_article_by_id.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
create or replace function find_article_by_id(in id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
select to_json(t)
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
a.*,
|
||||||
|
find_citizen_by_id(a.created_by_id) as created_by
|
||||||
|
into resource
|
||||||
|
from article as a
|
||||||
|
where a.id = _id
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_article_by_id(uuid, out json);
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
create or replace function find_last_article_by_version_id(in version_id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_version_id alias for version_id;
|
||||||
|
begin
|
||||||
|
select to_json(t)
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
a.*,
|
||||||
|
find_citizen_by_id(a.created_by_id) as created_by
|
||||||
|
into resource
|
||||||
|
from article as a
|
||||||
|
where a.version_id = _version_id
|
||||||
|
order by a.version_number desc
|
||||||
|
limit 1
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_last_article_by_version_id(uuid, inout json);
|
||||||
32
resources/functions/article/upsert_article.sql
Normal file
32
resources/functions/article/upsert_article.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
create or replace procedure upsert_article(inout resource json)
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
new_id uuid;
|
||||||
|
begin
|
||||||
|
insert into article (version_id, created_by_id, title, annonymous, content, description, tags)
|
||||||
|
select
|
||||||
|
version_id,
|
||||||
|
(resource#>>'{created_by, id}')::uuid,
|
||||||
|
title,
|
||||||
|
annonymous,
|
||||||
|
content,
|
||||||
|
description,
|
||||||
|
tags
|
||||||
|
from json_populate_record(null::article, resource)
|
||||||
|
returning id into new_id;
|
||||||
|
|
||||||
|
if resource->>'relations' is not null then
|
||||||
|
insert into article_relations (source_id, target_id, created_by_id)
|
||||||
|
select
|
||||||
|
(resource->>'id')::uuid,
|
||||||
|
id,
|
||||||
|
(resource#>>'{created_by, id}')::uuid
|
||||||
|
from json_populate_recordset(null::article, resource->>'relations');
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select find_article_by_id(new_id) into resource;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop procedure if exists upsert_article(inout json);
|
||||||
17
resources/functions/citizen/find_citizen_by_id.sql
Normal file
17
resources/functions/citizen/find_citizen_by_id.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
create or replace function find_citizen_by_id(in id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
select to_json(t) into resource
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
z.*,
|
||||||
|
find_user_by_id(z.user_id) as "user"
|
||||||
|
from citizen as z
|
||||||
|
where z.id = _id
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_citizen_by_id(uuid, inout json);
|
||||||
17
resources/functions/citizen/find_citizen_by_user_id.sql
Normal file
17
resources/functions/citizen/find_citizen_by_user_id.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
create or replace function find_citizen_by_user_id(in user_id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_user_id alias for user_id;
|
||||||
|
begin
|
||||||
|
select to_json(t) into resource
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
z.*,
|
||||||
|
find_user_by_id(z.user_id) as "user"
|
||||||
|
from citizen as z
|
||||||
|
where z.user_id = _user_id
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_citizen_by_user_id(uuid, inout json);
|
||||||
28
resources/functions/citizen/upsert_citizen.sql
Normal file
28
resources/functions/citizen/upsert_citizen.sql
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
create or replace procedure upsert_citizen(inout resource json)
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
new_id uuid;
|
||||||
|
begin
|
||||||
|
insert into citizen (id, name, birthday, user_id, vote_annonymous, follow_annonymous)
|
||||||
|
select
|
||||||
|
coalesce(id, uuid_generate_v4()),
|
||||||
|
name,
|
||||||
|
birthday,
|
||||||
|
(resource#>>'{user, id}')::uuid,
|
||||||
|
coalesce(vote_annonymous, true),
|
||||||
|
coalesce(follow_annonymous, true)
|
||||||
|
from json_populate_record(null::citizen, resource)
|
||||||
|
on conflict (id) do update set
|
||||||
|
name = excluded.name,
|
||||||
|
birthday = excluded.birthday,
|
||||||
|
user_id = excluded.user_id,
|
||||||
|
vote_annonymous = excluded.vote_annonymous,
|
||||||
|
follow_annonymous = excluded.follow_annonymous
|
||||||
|
returning id into new_id;
|
||||||
|
|
||||||
|
select find_citizen_by_id(new_id) into resource;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop procedure if exists insert_user(inout json);
|
||||||
25
resources/functions/comment/comment.sql
Normal file
25
resources/functions/comment/comment.sql
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
create or replace function comment(reference regclass, target_id uuid, citizen_id uuid, content text, parent_id uuid default null, out id uuid)
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_citizen_id alias for citizen_id;
|
||||||
|
_target_id alias for target_id;
|
||||||
|
_content alias for content;
|
||||||
|
_parent_id alias for parent_id;
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
if reference = 'article'::regclass then
|
||||||
|
insert into comment_on_article (citizen_id, target_id, content, parent_id)
|
||||||
|
values (_citizen_id, _target_id, _content, _parent_id)
|
||||||
|
returning comment_on_article.id into _id;
|
||||||
|
elseif reference = 'constitution'::regclass then
|
||||||
|
insert into comment_on_constitution (citizen_id, target_id, content, parent_id)
|
||||||
|
values (_citizen_id, _target_id, _content, _parent_id)
|
||||||
|
returning comment_on_constitution.id into _id;
|
||||||
|
else
|
||||||
|
raise exception '% no implemented', reference::text;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists comment(regclass, uuid, uuid, text, uuid);
|
||||||
20
resources/functions/comment/edit_comment.sql
Normal file
20
resources/functions/comment/edit_comment.sql
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
create or replace function edit_comment(reference regclass, id uuid, content text) returns void
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
_content alias for content;
|
||||||
|
begin
|
||||||
|
if reference = 'article'::regclass then
|
||||||
|
update comment_on_article c set
|
||||||
|
content = _content
|
||||||
|
where c.id = _id;
|
||||||
|
elseif reference = 'constitution'::regclass then
|
||||||
|
update comment_on_constitution c set
|
||||||
|
content = _content
|
||||||
|
where c.id = _id;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists edit_comment(regclass, uuid, uuid, text, uuid);
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
create or replace function create_title_in_constitution(title json, constitution_id uuid default null, out resource json)
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_title alias for title;
|
||||||
|
_constitution_id uuid = coalesce(constitution_id, (title#>>'{constitution_id}')::uuid);
|
||||||
|
_author_id uuid = (title#>>'{created_by, id}')::uuid;
|
||||||
|
new_id uuid;
|
||||||
|
begin
|
||||||
|
insert into title (created_by_id, name, rank, constitution_id)
|
||||||
|
select
|
||||||
|
_author_id,
|
||||||
|
ti.name,
|
||||||
|
row_number() OVER (),
|
||||||
|
_constitution_id
|
||||||
|
from json_populate_record(null::title, _title) ti
|
||||||
|
returning id into new_id;
|
||||||
|
|
||||||
|
if (_title->'articles' is not null) then
|
||||||
|
insert into article_in_title (created_by_id, rank, title_id, article_id, constitution_id)
|
||||||
|
select
|
||||||
|
_author_id,
|
||||||
|
row_number() over (),
|
||||||
|
new_id,
|
||||||
|
id,
|
||||||
|
coalesce ((_title->>'constitution_id')::uuid, _constitution_id)
|
||||||
|
from json_populate_recordset(null::article, _title->'articles') ;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
select find_constitution_title_by_id(new_id)
|
||||||
|
into resource;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists create_title_in_constitution(out json);
|
||||||
19
resources/functions/constitution/find_constitution_by_id.sql
Normal file
19
resources/functions/constitution/find_constitution_by_id.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
create or replace function find_constitution_by_id(in id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
select to_json(t)
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
c.*,
|
||||||
|
find_citizen_by_id(c.created_by_id) as created_by,
|
||||||
|
find_constitution_titles_by_id(c.id) as titles
|
||||||
|
into resource
|
||||||
|
from constitution as c
|
||||||
|
where c.id = _id
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_constitution_by_id(uuid, out json);
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
create or replace function find_constitution_title_by_id(in id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
select to_json(t)
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
ti.id,
|
||||||
|
ti.name,
|
||||||
|
ti.rank,
|
||||||
|
array_agg(a order by ait.rank) as articles
|
||||||
|
into resource
|
||||||
|
from title as ti
|
||||||
|
left join article_in_title ait on ti.id = ait.title_id
|
||||||
|
left join article a on ait.article_id = a.id
|
||||||
|
where ti.id = _id
|
||||||
|
group by ti.id
|
||||||
|
order by ti.rank
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_constitution_title_by_id(uuid, out json);
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
create or replace function find_constitution_titles_by_id(in constitution_id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_constitution_id alias for constitution_id;
|
||||||
|
begin
|
||||||
|
select json_agg(t)
|
||||||
|
from (
|
||||||
|
select
|
||||||
|
ti.id,
|
||||||
|
ti.name,
|
||||||
|
ti.rank
|
||||||
|
into resource
|
||||||
|
from title as ti
|
||||||
|
where ti.constitution_id = _constitution_id
|
||||||
|
order by ti.rank
|
||||||
|
) as t;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_constitution_titles_by_id(uuid, out json);
|
||||||
33
resources/functions/constitution/upsert_constitution.sql
Normal file
33
resources/functions/constitution/upsert_constitution.sql
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
create or replace procedure upsert_constitution(inout resource json)
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
titles json;
|
||||||
|
_title json;
|
||||||
|
_citizen_id uuid = (resource#>>'{created_by, id}')::uuid;
|
||||||
|
new_id uuid;
|
||||||
|
begin
|
||||||
|
insert into constitution (version_id, created_by_id, title, annonymous)
|
||||||
|
select
|
||||||
|
version_id,
|
||||||
|
_citizen_id,
|
||||||
|
title,
|
||||||
|
annonymous
|
||||||
|
from json_populate_record(null::constitution, resource)
|
||||||
|
returning id into new_id;
|
||||||
|
|
||||||
|
titles := (resource->>'titles');
|
||||||
|
|
||||||
|
for _title in select json_array_elements(titles) loop
|
||||||
|
if _title#>>'{created_by, id}' is null then
|
||||||
|
_title := jsonb_set(_title::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
perform create_title_in_constitution(_title, new_id);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
select find_constitution_by_id(new_id) into resource;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop procedure if exists upsert_constitution(inout json);
|
||||||
23
resources/functions/follow/follow.sql
Normal file
23
resources/functions/follow/follow.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
create or replace function follow(reference regclass, _target_id uuid, _citizen_id uuid) returns void
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
begin
|
||||||
|
if reference = 'article'::regclass then
|
||||||
|
insert into follow_article (citizen_id, target_id)
|
||||||
|
values (_citizen_id, _target_id)
|
||||||
|
on conflict (citizen_id, target_id) do nothing;
|
||||||
|
elseif reference = 'constitution'::regclass then
|
||||||
|
insert into follow_constitution (citizen_id, target_id)
|
||||||
|
values (_citizen_id, _target_id)
|
||||||
|
on conflict (citizen_id, target_id) do nothing;
|
||||||
|
elseif reference = 'citizen'::regclass then
|
||||||
|
insert into follow_citizen (citizen_id, target_id)
|
||||||
|
values (_citizen_id, _target_id)
|
||||||
|
on conflict (citizen_id, target_id) do nothing;
|
||||||
|
else
|
||||||
|
raise exception '% no implemented', reference::text;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists follow(regclass, uuid, uuid);
|
||||||
16
resources/functions/follow/unfollow.sql
Normal file
16
resources/functions/follow/unfollow.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
create or replace function unfollow(reference regclass, target_id uuid, citizen_id uuid) returns void
|
||||||
|
language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_citizen_id alias for citizen_id;
|
||||||
|
_target_id alias for target_id;
|
||||||
|
begin
|
||||||
|
delete
|
||||||
|
from follow f
|
||||||
|
where f.citizen_id = _citizen_id
|
||||||
|
and f.target_id = _target_id
|
||||||
|
and f.target_reference = reference;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists unfollow(regclass, uuid, uuid);
|
||||||
18
resources/functions/user/check_user.sql
Normal file
18
resources/functions/user/check_user.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
create or replace function check_user(in username text, in plain_password text, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_username alias for username;
|
||||||
|
begin
|
||||||
|
select
|
||||||
|
case when count(u) = 1
|
||||||
|
then to_jsonb(u) - 'password'
|
||||||
|
else null end
|
||||||
|
into resource
|
||||||
|
from "user" as u
|
||||||
|
where u.username = lower(_username)
|
||||||
|
and u.password = crypt(plain_password, u.password)
|
||||||
|
group by u;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists check_user(text, text, out json);
|
||||||
12
resources/functions/user/find_user_by_id.sql
Normal file
12
resources/functions/user/find_user_by_id.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
create or replace function find_user_by_id(in id uuid, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_id alias for id;
|
||||||
|
begin
|
||||||
|
select to_jsonb(u) - 'password' into resource
|
||||||
|
from "user" as u
|
||||||
|
where u.id = _id;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_user_by_id(uuid, out json);
|
||||||
12
resources/functions/user/find_user_by_username.sql
Normal file
12
resources/functions/user/find_user_by_username.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
create or replace function find_user_by_username(in username text, out resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
_username alias for username;
|
||||||
|
begin
|
||||||
|
select to_jsonb(u) - 'password' into resource
|
||||||
|
from "user" as u
|
||||||
|
where u.username = _username;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop function if exists find_user_by_username(text, out json);
|
||||||
18
resources/functions/user/insert_user.sql
Normal file
18
resources/functions/user/insert_user.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
create or replace procedure insert_user(inout resource json) language plpgsql as
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
new_id uuid;
|
||||||
|
begin
|
||||||
|
insert into "user" (username, password, blocked_at)
|
||||||
|
select
|
||||||
|
username,
|
||||||
|
crypt(resource->>'plain_password', gen_salt('bf', 8)),
|
||||||
|
case when blocked_at is not null then now() else null end
|
||||||
|
from json_populate_record(null::"user", resource)
|
||||||
|
returning id into new_id;
|
||||||
|
|
||||||
|
select find_user_by_id(new_id) into resource;
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- drop procedure if exists insert_user(inout json);
|
||||||
35
resources/functions/vote/vote.sql
Normal file
35
resources/functions/vote/vote.sql
Normal file
@@ -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);
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
-- Users
|
-- Users
|
||||||
create extension if not exists pgcrypto;
|
create extension if not exists pgcrypto;
|
||||||
-- select *
|
|
||||||
-- from "user"
|
|
||||||
-- where username = lower('nick@example.com')
|
|
||||||
-- and password = crypt('12346', password);
|
|
||||||
|
|
||||||
create table "user"
|
create table "user"
|
||||||
(
|
(
|
||||||
@@ -15,19 +11,13 @@ create table "user"
|
|||||||
password text not null check ( password != '' )
|
password text not null check ( password != '' )
|
||||||
);
|
);
|
||||||
|
|
||||||
create type "name" as (
|
|
||||||
first_name text,
|
|
||||||
last_name text,
|
|
||||||
civility text
|
|
||||||
);
|
|
||||||
|
|
||||||
create table citizen
|
create table citizen
|
||||||
(
|
(
|
||||||
id uuid default uuid_generate_v4() not null primary key,
|
id uuid default uuid_generate_v4() not null primary key,
|
||||||
created_at timestamptz default now() not null,
|
created_at timestamptz default now() not null,
|
||||||
name "name" not null check ( name != '' ),
|
name jsonb not null check ( name ? 'first_name' and name ? 'last_name' ),
|
||||||
birthday date not null,
|
birthday date not null,
|
||||||
user_id uuid not null references "user" (id),
|
user_id uuid not null references "user" (id) unique,
|
||||||
vote_annonymous boolean default true not null,
|
vote_annonymous boolean default true not null,
|
||||||
follow_annonymous boolean default true not null
|
follow_annonymous boolean default true not null
|
||||||
);
|
);
|
||||||
@@ -62,13 +52,35 @@ create table moderator
|
|||||||
user_id uuid not null references "user" (id)
|
user_id uuid not null references "user" (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Article & Contitution
|
-- Article & Constitution
|
||||||
|
|
||||||
create or replace function generate_version_number(tablename regclass, version_id uuid) returns int
|
create or replace function generate_version_number(tablename regclass, version_id uuid, out generated_number int)
|
||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
|
declare
|
||||||
|
_version_id alias for version_id;
|
||||||
begin
|
begin
|
||||||
return random(); -- TODO
|
if (tablename = 'article'::regclass) then
|
||||||
|
select version_number + 1
|
||||||
|
into generated_number
|
||||||
|
from article as t
|
||||||
|
where t.version_id = _version_id
|
||||||
|
order by version_number
|
||||||
|
limit 1;
|
||||||
|
elseif tablename = 'constitution'::regclass then
|
||||||
|
select version_number + 1
|
||||||
|
into generated_number
|
||||||
|
from constitution as t
|
||||||
|
where t.version_id = _version_id
|
||||||
|
order by version_number
|
||||||
|
limit 1;
|
||||||
|
else
|
||||||
|
raise exception '% is not implemented', tablename::text;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if not found then
|
||||||
|
generated_number := 1;
|
||||||
|
end if;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
@@ -77,6 +89,7 @@ create or replace function set_version_number() returns trigger
|
|||||||
$$
|
$$
|
||||||
begin
|
begin
|
||||||
new.version_number = generate_version_number(tg_table_name::regclass, new.version_id);
|
new.version_number = generate_version_number(tg_table_name::regclass, new.version_id);
|
||||||
|
return new;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
@@ -86,18 +99,20 @@ create table article
|
|||||||
created_at timestamptz default now() not null,
|
created_at timestamptz default now() not null,
|
||||||
created_by_id uuid not null references citizen (id),
|
created_by_id uuid not null references citizen (id),
|
||||||
version_id uuid default uuid_generate_v4() not null,
|
version_id uuid default uuid_generate_v4() not null,
|
||||||
version_number int not null unique,
|
version_number int not null,
|
||||||
title text not null,
|
title text not null,
|
||||||
annonymous boolean default false not null,
|
annonymous boolean default false not null,
|
||||||
content text not null check ( content != '' ),
|
content text not null check ( content != '' ),
|
||||||
description text,
|
description text,
|
||||||
tags varchar(32)[] default '{}' not null
|
tags varchar(32)[] default '{}' not null,
|
||||||
|
unique (version_id, version_number)
|
||||||
);
|
);
|
||||||
|
|
||||||
create trigger generate_version_number_trigger
|
create trigger generate_version_number_trigger
|
||||||
before insert
|
before insert
|
||||||
on article
|
on article
|
||||||
execute procedure set_version_number();
|
for each row
|
||||||
|
execute function set_version_number();
|
||||||
|
|
||||||
create table constitution
|
create table constitution
|
||||||
(
|
(
|
||||||
@@ -113,6 +128,7 @@ create table constitution
|
|||||||
create trigger generate_version_number_trigger
|
create trigger generate_version_number_trigger
|
||||||
before insert
|
before insert
|
||||||
on constitution
|
on constitution
|
||||||
|
for each row
|
||||||
execute procedure set_version_number();
|
execute procedure set_version_number();
|
||||||
|
|
||||||
create table title
|
create table title
|
||||||
@@ -145,6 +161,7 @@ begin
|
|||||||
from title as t
|
from title as t
|
||||||
where t.id = new.title_id
|
where t.id = new.title_id
|
||||||
);
|
);
|
||||||
|
return new;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
@@ -176,28 +193,35 @@ create table extra
|
|||||||
create table follow
|
create table follow
|
||||||
(
|
(
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (extra);
|
) inherits (extra);
|
||||||
|
|
||||||
create table follow_article
|
create table follow_article
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'article'::regclass not null,
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
foreign key (target_id) references article (id),
|
foreign key (target_id) references article (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (follow);
|
) inherits (follow);
|
||||||
|
|
||||||
create table follow_constitution
|
create table follow_constitution
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'constitution'::regclass not null,
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
foreign key (target_id) references constitution (id),
|
foreign key (target_id) references constitution (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (follow);
|
) inherits (follow);
|
||||||
|
|
||||||
create table follow_citizen
|
create table follow_citizen
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'citizen'::regclass not null,
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
foreign key (target_id) references citizen (id),
|
foreign key (target_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (follow);
|
) inherits (follow);
|
||||||
|
|
||||||
|
|
||||||
@@ -213,6 +237,7 @@ create table comment
|
|||||||
|
|
||||||
create table comment_on_article
|
create table comment_on_article
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'article'::regclass not null,
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
foreign key (target_id) references article (id),
|
foreign key (target_id) references article (id),
|
||||||
foreign key (parent_id) references comment_on_article (id),
|
foreign key (parent_id) references comment_on_article (id),
|
||||||
@@ -221,6 +246,7 @@ create table comment_on_article
|
|||||||
|
|
||||||
create table comment_on_constitution
|
create table comment_on_constitution
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'constitution'::regclass not null,
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
foreign key (target_id) references constitution (id),
|
foreign key (target_id) references constitution (id),
|
||||||
foreign key (parent_id) references comment_on_constitution (id),
|
foreign key (parent_id) references comment_on_constitution (id),
|
||||||
@@ -234,35 +260,44 @@ create table vote
|
|||||||
anonymous boolean default true not null,
|
anonymous boolean default true not null,
|
||||||
note int not null check ( note >= -1 and note <= 1 ),
|
note int not null check ( note >= -1 and note <= 1 ),
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (extra);
|
) inherits (extra);
|
||||||
|
|
||||||
create table vote_for_article
|
create table vote_for_article
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'article'::regclass not null,
|
||||||
foreign key (target_id) references article (id),
|
foreign key (target_id) references article (id),
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (vote);
|
) inherits (vote);
|
||||||
|
|
||||||
create table vote_for_constitution
|
create table vote_for_constitution
|
||||||
(
|
(
|
||||||
|
target_reference regclass default 'constitution'::regclass not null,
|
||||||
foreign key (target_id) references constitution (id),
|
foreign key (target_id) references constitution (id),
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (vote);
|
) inherits (vote);
|
||||||
|
|
||||||
create table vote_for_comment_on_article
|
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 (target_id) references comment_on_article (id),
|
||||||
foreign key (citizen_id) references citizen (id),
|
foreign key (citizen_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id),
|
||||||
|
unique (citizen_id, target_id)
|
||||||
) inherits (vote);
|
) inherits (vote);
|
||||||
|
|
||||||
create table vote_for_comment_on_constitution
|
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 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);
|
) inherits (vote);
|
||||||
|
|
||||||
-- Stats
|
-- Stats
|
||||||
|
|||||||
2
resources/sql/migrations/0000-init_view.down.sql
Normal file
2
resources/sql/migrations/0000-init_view.down.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- User
|
||||||
|
drop view if exists user_lite;
|
||||||
5
resources/sql/migrations/0000-init_view.up.sql
Normal file
5
resources/sql/migrations/0000-init_view.up.sql
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
-- User
|
||||||
|
create or replace view user_lite as
|
||||||
|
select u.id, u.created_at, u.blocked_at, u.username
|
||||||
|
from "user" u
|
||||||
|
where u.blocked_at is null;
|
||||||
53
resources/tests/article.sql
Normal file
53
resources/tests/article.sql
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
created_user json := '{"username": "george", "plain_password": "azerty"}';
|
||||||
|
_user_id uuid;
|
||||||
|
_citizen_id uuid;
|
||||||
|
created_citizen json := '{"name": {"first_name":"George", "last_name":"MICHEL"}, "birthday": "2001-01-01"}';
|
||||||
|
created_article json := '{"version_id":"933b6a1b-50c9-42b6-989f-c02a57814ef9", "title": "Love the world", "annonymous": false, "content": "bla bal bla", "tags": ["love", "test"]}';
|
||||||
|
selected_article json;
|
||||||
|
begin
|
||||||
|
-- insert user for context
|
||||||
|
call insert_user(created_user);
|
||||||
|
_user_id := created_user->>'id';
|
||||||
|
created_citizen := jsonb_set(created_citizen::jsonb, '{user}'::text[], jsonb_build_object('id', _user_id::text), true)::json;
|
||||||
|
assert created_citizen#>>'{user, id}' = _user_id::text, format('userId in citizen must be the same as user, %s = %s', created_citizen#>>'{user, id}', _user_id::text);
|
||||||
|
|
||||||
|
-- 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);
|
||||||
|
assert created_article->>'version_id' is not null, 'version_id should not be null';
|
||||||
|
assert (created_article->>'version_number')::int = 1, format('version_number must be equal to 1, %s instead', created_article->>'version_number');
|
||||||
|
-- try tu create new version
|
||||||
|
call upsert_article(created_article);
|
||||||
|
assert (created_article->>'version_number')::int = 2, format('version_number must be equal to 2, %s instead', created_article->>'version_number');
|
||||||
|
|
||||||
|
-- get article by id and check the title
|
||||||
|
select find_article_by_id((created_article->>'id')::uuid) into selected_article;
|
||||||
|
assert selected_article->>'title' = 'Love the world', format('title must be "Love the world", %s', selected_article->>'title');
|
||||||
|
|
||||||
|
-- get article by version_id and check the title
|
||||||
|
select find_last_article_by_version_id((created_article->>'version_id')::uuid) into selected_article;
|
||||||
|
assert selected_article->>'title' = 'Love the world', format('title must be "Love the world", %s', selected_article->>'title');
|
||||||
|
assert (selected_article->>'version_number')::int = 2, format('version_id must be 2, %s instead', selected_article->>'version_number');
|
||||||
|
-- check if user id is returned
|
||||||
|
assert (selected_article#>>'{created_by, user, id}')::uuid = _user_id, format('user_id must be %s instead of %s', _user_id, (selected_article#>>'{created_by, user, id}')::uuid);
|
||||||
|
|
||||||
|
-- delete article and context
|
||||||
|
delete from article;
|
||||||
|
delete from citizen;
|
||||||
|
delete from "user";
|
||||||
|
|
||||||
|
-- check if find by id return null if article not exist
|
||||||
|
select find_citizen_by_user_id((created_citizen->>'id')::uuid) into selected_article;
|
||||||
|
assert selected_article is null, format('article must be null if not exist, %s', selected_article);
|
||||||
|
|
||||||
|
raise notice 'article test pass';
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
46
resources/tests/citizen.sql
Normal file
46
resources/tests/citizen.sql
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
wrong_citizen json;
|
||||||
|
created_user json := '{"username": "george", "plain_password": "azerty"}';
|
||||||
|
_user_id uuid;
|
||||||
|
created_citizen json := '{"name": {"first_name":"George", "last_name":"MICHEL"}, "birthday": "2001-01-01"}';
|
||||||
|
selected_citizen json;
|
||||||
|
begin
|
||||||
|
-- insert user for context
|
||||||
|
call insert_user(created_user);
|
||||||
|
_user_id := created_user->>'id';
|
||||||
|
created_citizen := jsonb_set(created_citizen::jsonb, '{user}'::text[], jsonb_build_object('id', _user_id::text), true)::json;
|
||||||
|
assert created_citizen#>>'{user, id}' = _user_id::text, format('userId in citizen must be the same as user, %s = %s', created_citizen#>>'{user, id}', _user_id::text);
|
||||||
|
|
||||||
|
-- insert new citizen
|
||||||
|
call upsert_citizen(created_citizen);
|
||||||
|
assert created_citizen->>'birthday' = '2001-01-01'::text, format('birthday of inserted citizen must be the same of the original object, %s != %s', created_citizen->>'birthday', '2001-01-01'::text);
|
||||||
|
|
||||||
|
-- insert citizen without first name and test if throw exception
|
||||||
|
wrong_citizen := (created_citizen::jsonb - '{name, first_name}'::text[])::json;
|
||||||
|
begin
|
||||||
|
call upsert_citizen(wrong_citizen);
|
||||||
|
assert false, 'upsert_citizen must be throw exception if first_name not exist';
|
||||||
|
exception when not_null_violation then
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- get citizen by id and check the first name
|
||||||
|
select find_citizen_by_id((created_citizen->>'id')::uuid) into selected_citizen;
|
||||||
|
assert selected_citizen#>>'{name, first_name}' = 'George', format('first name must be George, %s', selected_citizen#>>'{name, first_name}');
|
||||||
|
|
||||||
|
-- get citizen by user id and check the first name
|
||||||
|
select find_citizen_by_user_id((created_citizen->>'user_id')::uuid) into selected_citizen;
|
||||||
|
assert selected_citizen#>>'{name, first_name}' = 'George', format('first name must be George, %s', selected_citizen#>>'{name, first_name}');
|
||||||
|
|
||||||
|
-- delete citizen
|
||||||
|
delete from citizen where user_id = _user_id;
|
||||||
|
delete from "user" where username = 'george';
|
||||||
|
|
||||||
|
-- check if fint by id return null if citizen not exist
|
||||||
|
select find_citizen_by_user_id((created_citizen->>'user_id')::uuid) into selected_citizen;
|
||||||
|
assert selected_citizen is null, format('citizen must be null if not exist, %s', selected_citizen);
|
||||||
|
|
||||||
|
raise notice 'citizen test pass';
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
71
resources/tests/comment.sql
Normal file
71
resources/tests/comment.sql
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
created_user json := '{"username": "george", "plain_password": "azerty"}';
|
||||||
|
created_user2 json := '{"username": "john", "plain_password": "qwerty"}';
|
||||||
|
_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$;
|
||||||
|
_comment_id uuid;
|
||||||
|
begin
|
||||||
|
-- insert user for context
|
||||||
|
call insert_user(created_user);
|
||||||
|
call insert_user(created_user2);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
select comment(
|
||||||
|
reference => 'article'::regclass,
|
||||||
|
target_id => (created_article->>'id')::uuid,
|
||||||
|
citizen_id => _citizen_id,
|
||||||
|
content => 'Ho my god !'::text
|
||||||
|
) into _comment_id;
|
||||||
|
assert (select count(*) = 1 from "comment"), 'comment must be inserted';
|
||||||
|
|
||||||
|
perform edit_comment(
|
||||||
|
reference => 'article'::regclass,
|
||||||
|
id => _comment_id,
|
||||||
|
content => 'edited'::text
|
||||||
|
);
|
||||||
|
assert (select count(*) = 1 from "comment"), 'edit comment must not insert new comment';
|
||||||
|
assert (select count(*) = 1 from "comment" where content = 'edited'), 'edit comment must not insert new comment';
|
||||||
|
|
||||||
|
-- delete comment and context
|
||||||
|
delete from "comment";
|
||||||
|
delete from article;
|
||||||
|
delete from citizen;
|
||||||
|
delete from "user";
|
||||||
|
|
||||||
|
raise notice 'comment test pass';
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
|
||||||
|
-- select uuid_generate_v4();
|
||||||
81
resources/tests/constitution.sql
Normal file
81
resources/tests/constitution.sql
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
created_user json := '{"username": "george", "plain_password": "azerty"}';
|
||||||
|
_user_id uuid;
|
||||||
|
_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$;
|
||||||
|
created_constitution json := $json$
|
||||||
|
{
|
||||||
|
"version_id": "18ff6dd6-3bc1-4c59-82f0-5e2a8d54ae3e",
|
||||||
|
"title": "Love the world",
|
||||||
|
"annonymous": false,
|
||||||
|
"titles": [
|
||||||
|
{
|
||||||
|
"name": "titleOne"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "titleTwo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
$json$;
|
||||||
|
begin
|
||||||
|
-- insert user for context
|
||||||
|
call insert_user(created_user);
|
||||||
|
_user_id := created_user->>'id';
|
||||||
|
created_citizen := jsonb_set(created_citizen::jsonb, '{user}'::text[], jsonb_build_object('id', _user_id::text), true)::json;
|
||||||
|
assert created_citizen#>>'{user, id}' = _user_id::text, format('userId in citizen must be the same as user, %s = %s', created_citizen#>>'{user, id}', _user_id::text);
|
||||||
|
|
||||||
|
-- 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 for context
|
||||||
|
call upsert_article(created_article);
|
||||||
|
assert created_article->>'version_id' is not null, 'version_id should not be null';
|
||||||
|
|
||||||
|
|
||||||
|
-- create new constitution
|
||||||
|
created_constitution := jsonb_set(created_constitution::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json;
|
||||||
|
created_constitution := jsonb_set(created_constitution::jsonb, '{titles, 0, articles}'::text[], jsonb_build_array(jsonb_build_object('id', created_article->>'id')), true)::json;
|
||||||
|
call upsert_constitution(created_constitution);
|
||||||
|
assert (created_constitution->>'version_number')::int = 1, format('version_number must be equal to 1, %s instead', created_constitution->>'version_number');
|
||||||
|
assert created_constitution#>>'{titles, 0, name}' = 'titleOne'::text, format('the name of the first title of contitution must be %s, not %s', 'titleOne', created_constitution#>>'{titles, 0, name}');
|
||||||
|
|
||||||
|
-- delete article and context
|
||||||
|
delete from article_in_title;
|
||||||
|
delete from title;
|
||||||
|
delete from constitution;
|
||||||
|
delete from article;
|
||||||
|
delete from citizen;
|
||||||
|
delete from "user";
|
||||||
|
|
||||||
|
raise notice 'constitution test pass';
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
|
||||||
|
-- select uuid_generate_v4();
|
||||||
59
resources/tests/follow.sql
Normal file
59
resources/tests/follow.sql
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
created_user json := '{"username": "george", "plain_password": "azerty"}';
|
||||||
|
created_user2 json := '{"username": "john", "plain_password": "qwerty"}';
|
||||||
|
_citizen_id uuid;
|
||||||
|
_citizen_id2 uuid;
|
||||||
|
created_citizen json := $json$
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"first_name": "George",
|
||||||
|
"last_name": "MICHEL"
|
||||||
|
},
|
||||||
|
"birthday": "2001-01-01"
|
||||||
|
}
|
||||||
|
$json$;
|
||||||
|
created_citizen2 json := $json$
|
||||||
|
{
|
||||||
|
"name": {
|
||||||
|
"first_name": "John",
|
||||||
|
"last_name": "Doe"
|
||||||
|
},
|
||||||
|
"birthday": "2002-01-01"
|
||||||
|
}
|
||||||
|
$json$;
|
||||||
|
begin
|
||||||
|
-- insert user for context
|
||||||
|
call insert_user(created_user);
|
||||||
|
call insert_user(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
|
||||||
|
call upsert_citizen(created_citizen);
|
||||||
|
_citizen_id := created_citizen->>'id';
|
||||||
|
-- insert new citizen for context
|
||||||
|
call upsert_citizen(created_citizen2);
|
||||||
|
_citizen_id2 := created_citizen2->>'id';
|
||||||
|
|
||||||
|
|
||||||
|
perform follow('citizen'::regclass, _citizen_id, _citizen_id2);
|
||||||
|
assert (select count(*) > 0 from follow), 'follow must be inserted';
|
||||||
|
|
||||||
|
perform follow('citizen'::regclass, _citizen_id, _citizen_id2);
|
||||||
|
assert (select count(*) > 0 from follow), 'follow must be inserted';
|
||||||
|
|
||||||
|
perform unfollow('citizen'::regclass, _citizen_id, _citizen_id2);
|
||||||
|
assert (select count(*) = 0 from follow), 'follow must be deleted after unfollow';
|
||||||
|
|
||||||
|
-- delete follow and context
|
||||||
|
delete from citizen;
|
||||||
|
delete from "user";
|
||||||
|
|
||||||
|
raise notice 'follow test pass';
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
|
||||||
|
-- select uuid_generate_v4();
|
||||||
35
resources/tests/user.sql
Normal file
35
resources/tests/user.sql
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
created_user json := '{"username": "george", "plain_password": "azerty"}';
|
||||||
|
selected_user json;
|
||||||
|
exist_user json;
|
||||||
|
begin
|
||||||
|
-- Insert user and check if username and password is correct
|
||||||
|
call insert_user(created_user);
|
||||||
|
assert created_user->>'username' = 'george', 'username must be george';
|
||||||
|
assert created_user->>'password' is null, 'password must not be returned';
|
||||||
|
|
||||||
|
-- get user by there id and check the username is correct
|
||||||
|
select find_user_by_id((created_user->>'id')::uuid) into selected_user;
|
||||||
|
assert selected_user->>'username' = 'george', format('username must be george, %s instead', selected_user);
|
||||||
|
|
||||||
|
-- get user by username and check the username is correct
|
||||||
|
select find_user_by_username(created_user->>'username') into selected_user;
|
||||||
|
assert selected_user->>'username' = 'george', 'username must be george';
|
||||||
|
|
||||||
|
-- check if user exist with username and password and verify the reterned user
|
||||||
|
select check_user('george', 'azerty') into exist_user;
|
||||||
|
assert exist_user is not null, format('the function check_user must be return user object if username and password is correct, %s is return', exist_user::text);
|
||||||
|
assert exist_user->>'username' = 'george', format('the function check_user must be return user object with username is "george", %s is return', exist_user::text);
|
||||||
|
assert exist_user->>'password' is null, format('the function check_user must not be return the password, %s is return', exist_user::text);
|
||||||
|
|
||||||
|
-- delete user and check if user is really not exists
|
||||||
|
delete from "user" where username = 'george';
|
||||||
|
select check_user('george', 'azerty') into exist_user;
|
||||||
|
assert exist_user is null, format('the function check_user must be return null if user not exist, %s is return', exist_user::text);
|
||||||
|
|
||||||
|
raise notice 'user test pass';
|
||||||
|
end;
|
||||||
|
$$;
|
||||||
|
|
||||||
82
resources/tests/vote.sql
Normal file
82
resources/tests/vote.sql
Normal file
@@ -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();
|
||||||
Reference in New Issue
Block a user