replace Article entity by Article request for the HTTP request

Add draft
This commit is contained in:
2019-09-16 22:47:37 +02:00
parent 05c28a2f62
commit c2beed416e
13 changed files with 157 additions and 73 deletions

View File

@@ -10,6 +10,8 @@ class Article(
var content: String?, var content: String?,
var description: String?, var description: String?,
var tags: List<String> = emptyList(), var tags: List<String> = emptyList(),
var draft: Boolean = false,
var lastVersion: Boolean = false,
createdBy: Citizen? createdBy: Citizen?
): ):
UuidEntity(id), UuidEntity(id),

View File

@@ -8,6 +8,8 @@ class Constitution(
var title: String?, var title: String?,
var anonymous: Boolean? = true, var anonymous: Boolean? = true,
var titles: List<Title> = listOf(), var titles: List<Title> = listOf(),
var draft: Boolean = false,
var lastVersion: Boolean = false,
createdBy: Citizen? createdBy: Citizen?
): UuidEntity(id), ): UuidEntity(id),
EntityVersioning<UUID, Int> by UuidEntityVersioning(), EntityVersioning<UUID, Int> by UuidEntityVersioning(),

View File

@@ -0,0 +1,41 @@
package fr.dcproject.entity.request
import fr.dcproject.entity.Citizen
import java.util.*
import fr.dcproject.entity.Article as ArticleEntity
class Article(
val id: UUID?,
val title: String,
val anonymous: Boolean? = true,
val content: String,
val description: String,
val tags: List<String> = emptyList(),
val draft: Boolean = false,
val versionId: UUID?
):
Request {
fun merge(article: ArticleEntity) {
article.title = this.title
article.content = this.content
article.description = this.description
article.tags = this.tags.distinct()
article.anonymous = this.anonymous
article.draft = this.draft
article.versionId = this.versionId ?: UUID.randomUUID()
}
fun create(createdBy: Citizen): ArticleEntity {
return ArticleEntity(
id ?: UUID.randomUUID(),
title,
anonymous,
content,
description,
tags,
draft,
createdBy = createdBy
).apply { this.versionId = this@Article.versionId ?: UUID.randomUUID() }
}
}

View File

@@ -0,0 +1,3 @@
package fr.dcproject.entity.request
interface Request

View File

@@ -14,6 +14,7 @@ import io.ktor.request.receive
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import fr.dcproject.entity.Article as ArticleEntity import fr.dcproject.entity.Article as ArticleEntity
import fr.dcproject.entity.request.Article as ArticleEntityRequest
import fr.dcproject.repository.Article as ArticleRepository import fr.dcproject.repository.Article as ArticleRepository
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
@@ -53,8 +54,8 @@ fun Route.article(repo: ArticleRepository) {
} }
post<ArticlesPaths.PostArticleRequest> { post<ArticlesPaths.PostArticleRequest> {
val article = call.receive<ArticleEntity>() val request = call.receive<ArticleEntityRequest>()
article.createdBy = citizen val article = request.create(citizen)
assertCan(CREATE, article) assertCan(CREATE, article)

View File

@@ -560,6 +560,13 @@ components:
version_id: version_id:
$ref: '#/components/schemas/UUID' $ref: '#/components/schemas/UUID'
lastVersion:
properties:
last_version:
type: boolean
required: false
default: false
Paginated: Paginated:
properties: properties:
result: result:
@@ -696,6 +703,10 @@ components:
type: boolean type: boolean
required: false required: false
default: true default: true
draft:
type: boolean
required: false
default: false
- $ref: '#/components/schemas/versionId' - $ref: '#/components/schemas/versionId'
ArticleResponse: ArticleResponse:
type: object type: object
@@ -704,6 +715,7 @@ components:
- $ref: '#/components/schemas/UuidEntity' - $ref: '#/components/schemas/UuidEntity'
- $ref: '#/components/schemas/CreatedBy' - $ref: '#/components/schemas/CreatedBy'
- $ref: '#/components/schemas/CreatedAt' - $ref: '#/components/schemas/CreatedAt'
- $ref: '#/components/schemas/lastVersion'
ArticleRequest: ArticleRequest:
$ref: '#/components/schemas/ArticleBase' $ref: '#/components/schemas/ArticleBase'
@@ -727,6 +739,10 @@ components:
type: boolean type: boolean
required: false required: false
default: true default: true
draft:
type: boolean
required: false
default: false
- $ref: '#/components/schemas/versionId' - $ref: '#/components/schemas/versionId'
ConstitutionResponse: ConstitutionResponse:
type: object type: object

View File

@@ -13,7 +13,7 @@ begin
delete from article_relations; delete from article_relations;
delete from article; delete from article;
insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags, created_at, is_draft) insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags, created_at, draft)
select select
uuid_in(md5('article'||row_number() over ())::cstring), uuid_in(md5('article'||row_number() over ())::cstring),
uuid_in(md5('article_v'||row_number() over () % (_citizen_count / 2))::cstring), uuid_in(md5('article_v'||row_number() over () % (_citizen_count / 2))::cstring),

View File

@@ -9,7 +9,7 @@ create or replace function find_articles(
) language plpgsql as ) language plpgsql as
$$ $$
begin begin
select json_agg(t), (select count(id) from article a where (_search is null or _search = '' or a ==> dsl.multi_match('{title^3, content, description}', _search)) and a.is_last_version = true) select json_agg(t), (select count(id) from article a where (_search is null or _search = '' or a ==> dsl.multi_match('{title^3, content, description}', _search)) and a.last_version = true)
into resource, total into resource, total
from ( from (
select select
@@ -21,7 +21,7 @@ begin
_search is null _search is null
or _search = '' or _search = ''
or a ==> dsl.multi_match('{title^3, content, description}', _search) or a ==> dsl.multi_match('{title^3, content, description}', _search)
) and a.is_last_version = true ) and a.last_version = true
order by order by
_score desc, _score desc,
case direction when 'asc' then case direction when 'asc' then

View File

@@ -11,7 +11,7 @@ begin
into resource into resource
from article as a from article as a
where a.version_id = _version_id where a.version_id = _version_id
and a.is_draft = false and a.draft = false
and a.deleted_at is null and a.deleted_at is null
order by a.version_number desc order by a.version_number desc
limit 1 limit 1

View File

@@ -4,29 +4,46 @@ $$
declare declare
new_id uuid; new_id uuid;
_id_exist boolean; _id_exist boolean;
_existing_draft article = (
select a from article a
where a.version_id = (resource->>'version_id')::uuid
and a.draft = true
);
begin begin
-- check if version id already exist -- check if version id already exist
select count(*) >= 1 select count(*) >= 1
into _id_exist into _id_exist
from article from article
where (resource->>'id')::uuid is not null where (resource->>'id')::uuid is not null
and id = (resource->>'id')::uuid and id = (resource->>'id')::uuid;
-- and draft = false
;
insert into article (id, version_id, created_by_id, title, anonymous, content, description, tags) if (_existing_draft.id is not null) then
select update article a2 set
case when _id_exist then uuid_generate_v4() title = a.title,
else coalesce(id, uuid_generate_v4()) end, anonymous = a.anonymous,
coalesce(version_id, uuid_generate_v4()), content = a.content,
(resource#>>'{created_by, id}')::uuid, description = a.description,
title, tags = a.tags,
anonymous, draft = a.draft
content, from json_populate_record(null::article, resource) a
description, where a2.id = (_existing_draft.id)::uuid
tags returning a2.id into new_id;
from json_populate_record(null::article, resource) else
returning id into new_id; insert into article (id, version_id, created_by_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,
title,
anonymous,
content,
description,
tags,
draft
from json_populate_record(null::article, resource)
returning id into new_id;
end if;
if resource->>'relations' is not null then if resource->>'relations' is not null then
delete from article_relations delete from article_relations

View File

@@ -13,11 +13,7 @@ begin
into _id_exist into _id_exist
from constitution from constitution
where (resource->>'id')::uuid is not null where (resource->>'id')::uuid is not null
and id = (resource->>'id')::uuid and id = (resource->>'id')::uuid;
-- and draft = false
;
raise notice '%', _id_exist;
insert into constitution (id, version_id, created_by_id, title, anonymous) insert into constitution (id, version_id, created_by_id, title, anonymous)
select select

View File

@@ -94,12 +94,14 @@ declare
begin begin
if (tablename = 'article'::regclass) then if (tablename = 'article'::regclass) then
update article a update article a
set is_last_version = false set last_version = false
where a.version_id = _version_id and a.is_last_version = true; where a.version_id = _version_id
and a.last_version = true;
elseif (tablename = 'constitution'::regclass) then elseif (tablename = 'constitution'::regclass) then
update constitution c update constitution c
set is_last_version = false set last_version = false
where c.version_id = _version_id and c.is_last_version = true; where c.version_id = _version_id
and c.last_version = true;
else else
raise exception '% is not implemented', tablename::text; raise exception '% is not implemented', tablename::text;
end if; end if;
@@ -116,28 +118,32 @@ begin
if (tablename = 'article'::regclass) then if (tablename = 'article'::regclass) then
update article a1 update article a1
set is_last_version = true set last_version = true
from ( from (
select id from article a2 select id
from article a2
where a2.version_id = _version_id where a2.version_id = _version_id
and a2.is_draft = false and a2.draft = false
and a2.deleted_at is null and a2.deleted_at is null
order by version_number desc order by version_number desc
limit 1 limit 1
) as a3 ) as a3
where a1.version_id = _version_id and a1.id = a3.id; where a1.version_id = _version_id
and a1.id = a3.id;
elseif (tablename = 'constitution'::regclass) then elseif (tablename = 'constitution'::regclass) then
update constitution c1 update constitution c1
set is_last_version = true set last_version = true
from ( from (
select id from constitution c2 select id
from constitution c2
where c2.version_id = _version_id where c2.version_id = _version_id
and c2.is_draft = false and c2.draft = false
and c2.deleted_at is null and c2.deleted_at is null
order by version_number desc order by version_number desc
limit 1 limit 1
) as c3 ) as c3
where c1.version_id = _version_id and c1.id = c3.id; where c1.version_id = _version_id
and c1.id = c3.id;
else else
raise exception '% is not implemented', tablename::text; raise exception '% is not implemented', tablename::text;
end if; end if;
@@ -158,11 +164,11 @@ create or replace function set_to_last_version() returns trigger
language plpgsql as language plpgsql as
$$ $$
begin begin
if (new.is_draft = false and new.deleted_at is null) then if (new.draft = false and new.deleted_at is null) then
perform set_all_version_to_old(tg_table_name::regclass, new.version_id); perform set_all_version_to_old(tg_table_name::regclass, new.version_id);
new.is_last_version = true; new.last_version = true;
else else
new.is_last_version = false; new.last_version = false;
end if; end if;
return new; return new;
end; end;
@@ -172,7 +178,7 @@ create or replace function set_last_version() returns trigger
language plpgsql as language plpgsql as
$$ $$
begin begin
if (new.is_draft != old.is_draft or new.deleted_at != old.deleted_at) then if (new.draft != old.draft or new.deleted_at != old.deleted_at) then
perform set_correct_last_version(tg_table_name::regclass, new.version_id); perform set_correct_last_version(tg_table_name::regclass, new.version_id);
end if; end if;
return new; return new;
@@ -184,23 +190,23 @@ $$;
------------- -------------
create table article create table article
( (
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,
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, version_number int not null,
title text not null check ( length(title) < 128 ), title text not null check ( length(title) < 128 ),
anonymous boolean default false not null, anonymous boolean default false not null,
content text not null check ( content != '' and length(content) < 4096 ), content text not null check ( content != '' and length(content) < 4096 ),
description text null check ( description != '' and length(description) < 4096 ), description text null check ( description != '' and length(description) < 4096 ),
tags varchar(32)[] default '{}' not null, tags varchar(32)[] default '{}' not null,
deleted_at timestamptz default null null, deleted_at timestamptz default null null,
is_draft boolean default false not null, draft boolean default false not null,
is_last_version boolean default false not null, last_version boolean default false not null,
unique (version_id, version_number) unique (version_id, version_number)
); );
create unique index last_version_article_idx on article (is_last_version, version_id) where is_last_version = true; create unique index last_version_article_idx on article (last_version, version_id) where last_version = true;
create trigger generate_version_number_trigger create trigger generate_version_number_trigger
before insert before insert
@@ -226,21 +232,21 @@ execute function set_last_version();
create table constitution create table constitution
( (
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,
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, version_number int not null,
title text not null check ( length(title) < 128 ), title text not null check ( length(title) < 128 ),
intro text null check ( length(intro) < 4096 ), intro text null check ( length(intro) < 4096 ),
anonymous boolean default false not null, anonymous boolean default false not null,
deleted_at timestamptz default null null, deleted_at timestamptz default null null,
is_draft boolean default false not null, draft boolean default false not null,
is_last_version boolean default false not null, last_version boolean default false not null,
unique (version_id, version_number) unique (version_id, version_number)
); );
create unique index last_version_constitution_idx on constitution (is_last_version, version_id) where is_last_version = true; create unique index last_version_constitution_idx on constitution (last_version, version_id) where last_version = true;
create trigger generate_version_number_trigger create trigger generate_version_number_trigger
before insert before insert

View File

@@ -28,13 +28,13 @@ begin
select upsert_article(created_article) into created_article; select upsert_article(created_article) into created_article;
assert created_article->>'version_id' is not null, 'version_id should not be null'; 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'); assert (created_article->>'version_number')::int = 1, format('version_number must be equal to 1, %s instead', created_article->>'version_number');
assert (created_article->>'is_last_version')::bool = true, 'The first insert must be set to the last version'; assert (created_article->>'last_version')::bool = true, 'The first insert must be set to the last version';
first_article_id = (created_article->>'id')::uuid; first_article_id = (created_article->>'id')::uuid;
-- try to create new version -- try to create new version
select upsert_article(created_article) into created_article_v2; select upsert_article(created_article) into created_article_v2;
assert (created_article_v2->>'version_number')::int = 2, format('version_number must be equal to 2, %s instead', created_article_v2->>'version_number'); assert (created_article_v2->>'version_number')::int = 2, format('version_number must be equal to 2, %s instead', created_article_v2->>'version_number');
assert (created_article_v2->>'is_last_version')::bool = true, 'The second insert must be set to the last version'; assert (created_article_v2->>'last_version')::bool = true, 'The second insert must be set to the last version';
second_article_id = (created_article_v2->>'id')::uuid; second_article_id = (created_article_v2->>'id')::uuid;
-- get articles versions by version_id -- get articles versions by version_id
@@ -60,14 +60,14 @@ begin
-- update to draft, then the last_version column must be change -- update to draft, then the last_version column must be change
update article update article
set is_draft = true set draft = true
where id = second_article_id; where id = second_article_id;
select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article; select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article;
assert (selected_article->>'version_number')::int = 1, format('version_id must be 1, %s instead', selected_article->>'version_number'); assert (selected_article->>'version_number')::int = 1, format('version_id must be 1, %s instead', selected_article->>'version_number');
update article update article
set is_draft = false set draft = false
where id = second_article_id; where id = second_article_id;
select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article; select find_last_article_by_version_id((created_article_v2->>'version_id')::uuid) into selected_article;