diff --git a/resources/functions/citizen/find_citizen_by_id.sql b/resources/functions/citizen/find_citizen_by_id.sql new file mode 100644 index 0000000..9ca616e --- /dev/null +++ b/resources/functions/citizen/find_citizen_by_id.sql @@ -0,0 +1,12 @@ +create or replace procedure find_citizen_by_id(in id uuid, inout resource json) language plpgsql as +$$ +declare + _id alias for id; +begin + select to_json(z) into resource + from citizen as z + where z.id = _id; +end; +$$; + +-- drop procedure if exists find_citizen_by_id(uuid, inout json); \ No newline at end of file diff --git a/resources/functions/citizen/find_citizen_by_user_id.sql b/resources/functions/citizen/find_citizen_by_user_id.sql new file mode 100644 index 0000000..0f9ffe3 --- /dev/null +++ b/resources/functions/citizen/find_citizen_by_user_id.sql @@ -0,0 +1,12 @@ +create or replace procedure find_citizen_by_user_id(in id uuid, inout resource json) language plpgsql as +$$ +declare + _id alias for id; +begin + select to_json(z) into resource + from citizen as z + where z.user_id = _id; +end; +$$; + +-- drop procedure if exists find_citizen_by_user_id(uuid, inout json); \ No newline at end of file diff --git a/resources/functions/citizen/upsert_citizen.sql b/resources/functions/citizen/upsert_citizen.sql new file mode 100644 index 0000000..0889531 --- /dev/null +++ b/resources/functions/citizen/upsert_citizen.sql @@ -0,0 +1,31 @@ +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 to_json(z) + into resource + from citizen as z + where z.id = new_id; +end; +$$; + +-- drop procedure if exists insert_user(inout json); \ No newline at end of file diff --git a/resources/functions/user/check_user.sql b/resources/functions/user/check_user.sql index 4142278..2297b31 100644 --- a/resources/functions/user/check_user.sql +++ b/resources/functions/user/check_user.sql @@ -5,7 +5,7 @@ declare begin select case when count(u) = 1 - then to_json(json_populate_record(null::user_lite, to_json(u))) -- TODO refactor this ! + then to_jsonb(u) - 'password' else null end into resource from "user" as u diff --git a/resources/functions/user/find_user_by_id.sql b/resources/functions/user/find_user_by_id.sql index 7f2e1ca..d5f8ffa 100644 --- a/resources/functions/user/find_user_by_id.sql +++ b/resources/functions/user/find_user_by_id.sql @@ -9,4 +9,4 @@ begin end; $$; --- drop procedure if exists find_user_by_id(inout json); \ No newline at end of file +-- drop procedure if exists find_user_by_id(uuid, inout json); \ No newline at end of file diff --git a/resources/sql/migrations/0000-init_schema.up.sql b/resources/sql/migrations/0000-init_schema.up.sql index 4f6577b..960c2e9 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -11,19 +11,13 @@ create table "user" password text not null check ( password != '' ) ); -create type "name" as ( - first_name text, - last_name text, - civility text - ); - create table citizen ( id uuid default uuid_generate_v4() not null primary key, 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, - user_id uuid not null references "user" (id), + user_id uuid not null references "user" (id) unique, vote_annonymous boolean default true not null, follow_annonymous boolean default true not null ); diff --git a/resources/tests/citizen.sql b/resources/tests/citizen.sql new file mode 100644 index 0000000..230ae6d --- /dev/null +++ b/resources/tests/citizen.sql @@ -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 + call find_citizen_by_id((created_citizen->>'id')::uuid, 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 + call find_citizen_by_user_id((created_citizen->>'user_id')::uuid, 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 + call find_citizen_by_user_id((created_citizen->>'user_id')::uuid, selected_citizen); + assert selected_citizen is null, format('citizen must be null if not exist, %s', selected_citizen); + + raise notice 'citizen test pass'; +end; +$$; diff --git a/resources/tests/user.sql b/resources/tests/user.sql index 6db54af..cff7005 100644 --- a/resources/tests/user.sql +++ b/resources/tests/user.sql @@ -5,23 +5,27 @@ declare 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 not null, 'password must be generated'; + -- get user by there id and check the username is correct call find_user_by_id((created_user->>'id')::uuid, selected_user); assert selected_user->>'username' = 'george', 'username must be george'; + -- get user by username and check the username is correct call find_user_by_username(created_user->>'username', 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);