From 0a923161288a67820ed07b2d8bbe32b3d0e10518 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 26 Jul 2019 02:47:43 +0200 Subject: [PATCH 01/14] feature #4: create procedure for user --- resources/functions/user/check_user.sql | 18 +++++++++++ resources/functions/user/find_user_by_id.sql | 12 +++++++ .../functions/user/find_user_by_username.sql | 12 +++++++ resources/functions/user/insert_user.sql | 20 ++++++++++++ .../sql/migrations/0000-init_schema.up.sql | 4 --- .../sql/migrations/0000-init_view.down.sql | 2 ++ .../sql/migrations/0000-init_view.up.sql | 5 +++ resources/tests/user.sql | 31 +++++++++++++++++++ 8 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 resources/functions/user/check_user.sql create mode 100644 resources/functions/user/find_user_by_id.sql create mode 100644 resources/functions/user/find_user_by_username.sql create mode 100644 resources/functions/user/insert_user.sql create mode 100644 resources/sql/migrations/0000-init_view.down.sql create mode 100644 resources/sql/migrations/0000-init_view.up.sql create mode 100644 resources/tests/user.sql diff --git a/resources/functions/user/check_user.sql b/resources/functions/user/check_user.sql new file mode 100644 index 0000000..4142278 --- /dev/null +++ b/resources/functions/user/check_user.sql @@ -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_json(json_populate_record(null::user_lite, to_json(u))) -- TODO refactor this ! + 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); \ No newline at end of file diff --git a/resources/functions/user/find_user_by_id.sql b/resources/functions/user/find_user_by_id.sql new file mode 100644 index 0000000..7f2e1ca --- /dev/null +++ b/resources/functions/user/find_user_by_id.sql @@ -0,0 +1,12 @@ +create or replace procedure find_user_by_id(in id uuid, inout resource json) language plpgsql as +$$ +declare + _id alias for id; +begin + select to_json(u) into resource + from "user" as u + where u.id = _id; +end; +$$; + +-- drop procedure if exists find_user_by_id(inout json); \ No newline at end of file diff --git a/resources/functions/user/find_user_by_username.sql b/resources/functions/user/find_user_by_username.sql new file mode 100644 index 0000000..c8c6e4b --- /dev/null +++ b/resources/functions/user/find_user_by_username.sql @@ -0,0 +1,12 @@ +create or replace procedure find_user_by_username(in username text, inout resource json) language plpgsql as +$$ +declare + _username alias for username; +begin + select to_json(u) into resource + from "user" as u + where u.username = _username; +end; +$$; + +-- drop procedure if exists find_user_by_username(text, inout json); \ No newline at end of file diff --git a/resources/functions/user/insert_user.sql b/resources/functions/user/insert_user.sql new file mode 100644 index 0000000..803b268 --- /dev/null +++ b/resources/functions/user/insert_user.sql @@ -0,0 +1,20 @@ +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 to_json(u) into resource + from "user" as u + where u.id = new_id; +end; +$$; + +-- drop procedure if exists insert_user(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 8ec5264..4f6577b 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -1,9 +1,5 @@ -- Users create extension if not exists pgcrypto; --- select * --- from "user" --- where username = lower('nick@example.com') --- and password = crypt('12346', password); create table "user" ( diff --git a/resources/sql/migrations/0000-init_view.down.sql b/resources/sql/migrations/0000-init_view.down.sql new file mode 100644 index 0000000..3a46f2f --- /dev/null +++ b/resources/sql/migrations/0000-init_view.down.sql @@ -0,0 +1,2 @@ +-- User +drop view if exists user_lite; \ No newline at end of file diff --git a/resources/sql/migrations/0000-init_view.up.sql b/resources/sql/migrations/0000-init_view.up.sql new file mode 100644 index 0000000..354be37 --- /dev/null +++ b/resources/sql/migrations/0000-init_view.up.sql @@ -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; \ No newline at end of file diff --git a/resources/tests/user.sql b/resources/tests/user.sql new file mode 100644 index 0000000..6db54af --- /dev/null +++ b/resources/tests/user.sql @@ -0,0 +1,31 @@ +do +$$ +declare + created_user json := '{"username": "george", "plain_password": "azerty"}'; + selected_user json; + exist_user json; +begin + 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'; + + call find_user_by_id((created_user->>'id')::uuid, selected_user); + assert selected_user->>'username' = 'george', 'username must be george'; + + call find_user_by_username(created_user->>'username', selected_user); + assert selected_user->>'username' = 'george', 'username must be george'; + + 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 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; +$$; + From fc06965cda04757e95a9188f0fac9888adbf395a Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 26 Jul 2019 14:29:48 +0200 Subject: [PATCH 02/14] feature #4: create procedure for citizen --- .../functions/citizen/find_citizen_by_id.sql | 12 +++++ .../citizen/find_citizen_by_user_id.sql | 12 +++++ .../functions/citizen/upsert_citizen.sql | 31 +++++++++++++ resources/functions/user/check_user.sql | 2 +- resources/functions/user/find_user_by_id.sql | 2 +- .../sql/migrations/0000-init_schema.up.sql | 10 +--- resources/tests/citizen.sql | 46 +++++++++++++++++++ resources/tests/user.sql | 6 ++- 8 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 resources/functions/citizen/find_citizen_by_id.sql create mode 100644 resources/functions/citizen/find_citizen_by_user_id.sql create mode 100644 resources/functions/citizen/upsert_citizen.sql create mode 100644 resources/tests/citizen.sql 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); From 4ce81c6210be77da1801515c2a15e3dfc4f60bbc Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 26 Jul 2019 16:18:31 +0200 Subject: [PATCH 03/14] refactoring: replace procedure find_user_by_* to function --- resources/functions/user/find_user_by_id.sql | 4 ++-- resources/functions/user/find_user_by_username.sql | 4 ++-- resources/tests/user.sql | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/functions/user/find_user_by_id.sql b/resources/functions/user/find_user_by_id.sql index d5f8ffa..9833093 100644 --- a/resources/functions/user/find_user_by_id.sql +++ b/resources/functions/user/find_user_by_id.sql @@ -1,4 +1,4 @@ -create or replace procedure find_user_by_id(in id uuid, inout resource json) language plpgsql as +create or replace function find_user_by_id(in id uuid, out resource json) language plpgsql as $$ declare _id alias for id; @@ -9,4 +9,4 @@ begin end; $$; --- drop procedure if exists find_user_by_id(uuid, inout json); \ No newline at end of file +-- drop function if exists find_user_by_id(uuid, inout json); \ No newline at end of file diff --git a/resources/functions/user/find_user_by_username.sql b/resources/functions/user/find_user_by_username.sql index c8c6e4b..717a643 100644 --- a/resources/functions/user/find_user_by_username.sql +++ b/resources/functions/user/find_user_by_username.sql @@ -1,4 +1,4 @@ -create or replace procedure find_user_by_username(in username text, inout resource json) language plpgsql as +create or replace function find_user_by_username(in username text, out resource json) language plpgsql as $$ declare _username alias for username; @@ -9,4 +9,4 @@ begin end; $$; --- drop procedure if exists find_user_by_username(text, inout json); \ No newline at end of file +-- drop function if exists find_user_by_username(text, out json); \ No newline at end of file diff --git a/resources/tests/user.sql b/resources/tests/user.sql index cff7005..ec89e82 100644 --- a/resources/tests/user.sql +++ b/resources/tests/user.sql @@ -11,11 +11,11 @@ begin 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'; + 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 - call find_user_by_username(created_user->>'username', selected_user); + 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 From 8581ebb5582fdcb93b3e73a366c1e30e64b05ecd Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 26 Jul 2019 16:27:46 +0200 Subject: [PATCH 04/14] refactoring: securize find_user_by_* --- resources/functions/user/find_user_by_id.sql | 2 +- resources/functions/user/find_user_by_username.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/functions/user/find_user_by_id.sql b/resources/functions/user/find_user_by_id.sql index 9833093..0e2a5d1 100644 --- a/resources/functions/user/find_user_by_id.sql +++ b/resources/functions/user/find_user_by_id.sql @@ -3,7 +3,7 @@ $$ declare _id alias for id; begin - select to_json(u) into resource + select to_jsonb(u) - 'password' into resource from "user" as u where u.id = _id; end; diff --git a/resources/functions/user/find_user_by_username.sql b/resources/functions/user/find_user_by_username.sql index 717a643..60ab0d8 100644 --- a/resources/functions/user/find_user_by_username.sql +++ b/resources/functions/user/find_user_by_username.sql @@ -3,7 +3,7 @@ $$ declare _username alias for username; begin - select to_json(u) into resource + select to_jsonb(u) - 'password' into resource from "user" as u where u.username = _username; end; From 2286568ae923d8ba63ac4c0dc88e0cbd4b73207d Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 26 Jul 2019 16:29:11 +0200 Subject: [PATCH 05/14] refactoring: replace procedure find_citizen_by_* to function and include user into citizen object --- .../functions/citizen/find_citizen_by_id.sql | 15 ++++++++++----- .../citizen/find_citizen_by_user_id.sql | 17 +++++++++++------ resources/tests/citizen.sql | 6 +++--- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/resources/functions/citizen/find_citizen_by_id.sql b/resources/functions/citizen/find_citizen_by_id.sql index 9ca616e..3b8e675 100644 --- a/resources/functions/citizen/find_citizen_by_id.sql +++ b/resources/functions/citizen/find_citizen_by_id.sql @@ -1,12 +1,17 @@ -create or replace procedure find_citizen_by_id(in id uuid, inout resource json) language plpgsql as +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(z) into resource - from citizen as z - where z.id = _id; + select to_json(t) into resource + from ( + select + z.*, + find_user_by_id(z.user_id) + from citizen as z + where z.id = _id + ) as t; end; $$; --- drop procedure if exists find_citizen_by_id(uuid, inout json); \ No newline at end of file +-- drop function 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 index 0f9ffe3..3d62d1c 100644 --- a/resources/functions/citizen/find_citizen_by_user_id.sql +++ b/resources/functions/citizen/find_citizen_by_user_id.sql @@ -1,12 +1,17 @@ -create or replace procedure find_citizen_by_user_id(in id uuid, inout resource json) language plpgsql as +create or replace function find_citizen_by_user_id(in user_id uuid, out resource json) language plpgsql as $$ declare - _id alias for id; + _user_id alias for user_id; begin - select to_json(z) into resource - from citizen as z - where z.user_id = _id; + select to_json(t) into resource + from ( + select + z.*, + find_user_by_id(z.user_id) + from citizen as z + where z.user_id = _user_id + ) as t; end; $$; --- drop procedure if exists find_citizen_by_user_id(uuid, inout json); \ No newline at end of file +-- drop function if exists find_citizen_by_user_id(uuid, inout json); \ No newline at end of file diff --git a/resources/tests/citizen.sql b/resources/tests/citizen.sql index 230ae6d..a7be3f4 100644 --- a/resources/tests/citizen.sql +++ b/resources/tests/citizen.sql @@ -26,11 +26,11 @@ begin end; -- get citizen by id and check the first name - call find_citizen_by_id((created_citizen->>'id')::uuid, selected_citizen); + 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 - call find_citizen_by_user_id((created_citizen->>'user_id')::uuid, selected_citizen); + 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 @@ -38,7 +38,7 @@ begin 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); + 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'; From ce2f2b4f2abcee27f29a8c5afaf37dcec7d91467 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sat, 27 Jul 2019 01:19:25 +0200 Subject: [PATCH 06/14] feature #4: create function for article implement generate_version_number() --- .../functions/article/find_article_by_id.sql | 18 +++++++ .../find_last_article_by_version_id.sql | 20 +++++++ .../functions/article/upsert_article.sql | 23 ++++++++ .../functions/citizen/find_citizen_by_id.sql | 2 +- .../citizen/find_citizen_by_user_id.sql | 2 +- .../functions/citizen/upsert_citizen.sql | 5 +- resources/functions/user/find_user_by_id.sql | 2 +- resources/functions/user/insert_user.sql | 4 +- .../sql/migrations/0000-init_schema.up.sql | 30 ++++++++--- resources/tests/article.sql | 53 +++++++++++++++++++ resources/tests/user.sql | 2 +- 11 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 resources/functions/article/find_article_by_id.sql create mode 100644 resources/functions/article/find_last_article_by_version_id.sql create mode 100644 resources/functions/article/upsert_article.sql create mode 100644 resources/tests/article.sql diff --git a/resources/functions/article/find_article_by_id.sql b/resources/functions/article/find_article_by_id.sql new file mode 100644 index 0000000..ebe2c50 --- /dev/null +++ b/resources/functions/article/find_article_by_id.sql @@ -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); \ No newline at end of file diff --git a/resources/functions/article/find_last_article_by_version_id.sql b/resources/functions/article/find_last_article_by_version_id.sql new file mode 100644 index 0000000..795b5aa --- /dev/null +++ b/resources/functions/article/find_last_article_by_version_id.sql @@ -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); \ No newline at end of file diff --git a/resources/functions/article/upsert_article.sql b/resources/functions/article/upsert_article.sql new file mode 100644 index 0000000..4c3090c --- /dev/null +++ b/resources/functions/article/upsert_article.sql @@ -0,0 +1,23 @@ +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; + + select find_article_by_id(new_id) into resource; +end; +$$; + +-- drop procedure if exists upsert_article(inout json); \ No newline at end of file diff --git a/resources/functions/citizen/find_citizen_by_id.sql b/resources/functions/citizen/find_citizen_by_id.sql index 3b8e675..c2f5b57 100644 --- a/resources/functions/citizen/find_citizen_by_id.sql +++ b/resources/functions/citizen/find_citizen_by_id.sql @@ -7,7 +7,7 @@ begin from ( select z.*, - find_user_by_id(z.user_id) + find_user_by_id(z.user_id) as "user" from citizen as z where z.id = _id ) as t; diff --git a/resources/functions/citizen/find_citizen_by_user_id.sql b/resources/functions/citizen/find_citizen_by_user_id.sql index 3d62d1c..001a5ee 100644 --- a/resources/functions/citizen/find_citizen_by_user_id.sql +++ b/resources/functions/citizen/find_citizen_by_user_id.sql @@ -7,7 +7,7 @@ begin from ( select z.*, - find_user_by_id(z.user_id) + find_user_by_id(z.user_id) as "user" from citizen as z where z.user_id = _user_id ) as t; diff --git a/resources/functions/citizen/upsert_citizen.sql b/resources/functions/citizen/upsert_citizen.sql index 0889531..c9fd132 100644 --- a/resources/functions/citizen/upsert_citizen.sql +++ b/resources/functions/citizen/upsert_citizen.sql @@ -21,10 +21,7 @@ begin 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; + select find_citizen_by_id(new_id) into resource; end; $$; diff --git a/resources/functions/user/find_user_by_id.sql b/resources/functions/user/find_user_by_id.sql index 0e2a5d1..99fdaa1 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 function if exists find_user_by_id(uuid, inout json); \ No newline at end of file +-- drop function if exists find_user_by_id(uuid, out json); \ No newline at end of file diff --git a/resources/functions/user/insert_user.sql b/resources/functions/user/insert_user.sql index 803b268..b629b37 100644 --- a/resources/functions/user/insert_user.sql +++ b/resources/functions/user/insert_user.sql @@ -11,9 +11,7 @@ begin from json_populate_record(null::"user", resource) returning id into new_id; - select to_json(u) into resource - from "user" as u - where u.id = new_id; + select find_user_by_id(new_id) into resource; end; $$; diff --git a/resources/sql/migrations/0000-init_schema.up.sql b/resources/sql/migrations/0000-init_schema.up.sql index 960c2e9..0fadcbe 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -52,13 +52,28 @@ create table moderator 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 $$ +declare + _version_id alias for version_id; 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; + else + raise exception '% is not implemented', tablename::text; + end if; + + if not found then + generated_number := 1; + end if; end; $$; @@ -67,6 +82,7 @@ create or replace function set_version_number() returns trigger $$ begin new.version_number = generate_version_number(tg_table_name::regclass, new.version_id); + return new; end; $$; @@ -76,18 +92,20 @@ create table article created_at timestamptz default now() not null, created_by_id uuid not null references citizen (id), version_id uuid default uuid_generate_v4() not null, - version_number int not null unique, + version_number int not null, title text not null, annonymous boolean default false not null, content text not null check ( content != '' ), 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 before insert on article -execute procedure set_version_number(); + for each row +execute function set_version_number(); create table constitution ( diff --git a/resources/tests/article.sql b/resources/tests/article.sql new file mode 100644 index 0000000..93dd712 --- /dev/null +++ b/resources/tests/article.sql @@ -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; +$$; diff --git a/resources/tests/user.sql b/resources/tests/user.sql index ec89e82..8e5a5ea 100644 --- a/resources/tests/user.sql +++ b/resources/tests/user.sql @@ -8,7 +8,7 @@ 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'; + 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; From a15847ab9e30746cc3d95537db5ee10e9832548d Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sat, 27 Jul 2019 02:45:51 +0200 Subject: [PATCH 07/14] feature #4: create function for constitution and title (not article in title) --- .../constitution/find_constitution_by_id.sql | 19 ++++++++ .../find_constitution_titles_by_id.sql | 20 ++++++++ .../constitution/upsert_constitution.sql | 32 +++++++++++++ .../sql/migrations/0000-init_schema.up.sql | 8 ++++ resources/tests/constitution.sql | 46 +++++++++++++++++++ 5 files changed, 125 insertions(+) create mode 100644 resources/functions/constitution/find_constitution_by_id.sql create mode 100644 resources/functions/constitution/find_constitution_titles_by_id.sql create mode 100644 resources/functions/constitution/upsert_constitution.sql create mode 100644 resources/tests/constitution.sql diff --git a/resources/functions/constitution/find_constitution_by_id.sql b/resources/functions/constitution/find_constitution_by_id.sql new file mode 100644 index 0000000..e830051 --- /dev/null +++ b/resources/functions/constitution/find_constitution_by_id.sql @@ -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); \ No newline at end of file diff --git a/resources/functions/constitution/find_constitution_titles_by_id.sql b/resources/functions/constitution/find_constitution_titles_by_id.sql new file mode 100644 index 0000000..8f1e695 --- /dev/null +++ b/resources/functions/constitution/find_constitution_titles_by_id.sql @@ -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); \ No newline at end of file diff --git a/resources/functions/constitution/upsert_constitution.sql b/resources/functions/constitution/upsert_constitution.sql new file mode 100644 index 0000000..0b09868 --- /dev/null +++ b/resources/functions/constitution/upsert_constitution.sql @@ -0,0 +1,32 @@ +create or replace procedure upsert_constitution(inout resource json) + language plpgsql as +$$ +declare + titles json; + new_id uuid; +begin + insert into constitution (version_id, created_by_id, title, annonymous) + select + version_id, + (resource#>>'{created_by, id}')::uuid, + title, + annonymous + from json_populate_record(null::constitution, resource) + returning id into new_id; + + titles := (resource->>'titles'); + + insert into title (created_by_id, name, rank, constitution_id) + select + coalesce((ti#>>'{created_by, id}')::uuid, (resource#>>'{created_by, id}')::uuid), + ti->>'name', + row_number() OVER (), + new_id + from json_array_elements(titles) ti, + lateral json_populate_record(null::title, ti); + + select find_constitution_by_id(new_id) into resource; +end; +$$; + +-- drop procedure if exists upsert_constitution(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 0fadcbe..1046234 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -67,6 +67,13 @@ begin 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; @@ -121,6 +128,7 @@ create table constitution create trigger generate_version_number_trigger before insert on constitution + for each row execute procedure set_version_number(); create table title diff --git a/resources/tests/constitution.sql b/resources/tests/constitution.sql new file mode 100644 index 0000000..2a95203 --- /dev/null +++ b/resources/tests/constitution.sql @@ -0,0 +1,46 @@ +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"]}'; + created_constitution json := '{"version_id":"18ff6dd6-3bc1-4c59-82f0-5e2a8d54ae3e", "title": "Love the world", "annonymous": false, "titles": [{"name":"titleOne"},{"name":"titleTwo"}]}'; +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; + 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 title; + delete from constitution; + delete from article; + delete from citizen; + delete from "user"; + + raise notice 'constitution test pass'; +end; +$$; + + +-- select uuid_generate_v4(); \ No newline at end of file From ef740734b2f55ccb0c8a963a3e34352d9bfb5866 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sun, 28 Jul 2019 22:42:49 +0200 Subject: [PATCH 08/14] feature #4: add "article in title" on contitution creation --- .../create_title_in_constitution.sql | 35 ++++++++++++++++ .../find_constitution_title_by_id.sql | 24 +++++++++++ .../constitution/upsert_constitution.sql | 19 +++++---- .../sql/migrations/0000-init_schema.up.sql | 1 + resources/tests/constitution.sql | 41 +++++++++++++++++-- 5 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 resources/functions/constitution/create_title_in_constitution.sql create mode 100644 resources/functions/constitution/find_constitution_title_by_id.sql diff --git a/resources/functions/constitution/create_title_in_constitution.sql b/resources/functions/constitution/create_title_in_constitution.sql new file mode 100644 index 0000000..dad5dd5 --- /dev/null +++ b/resources/functions/constitution/create_title_in_constitution.sql @@ -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); \ No newline at end of file diff --git a/resources/functions/constitution/find_constitution_title_by_id.sql b/resources/functions/constitution/find_constitution_title_by_id.sql new file mode 100644 index 0000000..d4296b9 --- /dev/null +++ b/resources/functions/constitution/find_constitution_title_by_id.sql @@ -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); \ No newline at end of file diff --git a/resources/functions/constitution/upsert_constitution.sql b/resources/functions/constitution/upsert_constitution.sql index 0b09868..42fe892 100644 --- a/resources/functions/constitution/upsert_constitution.sql +++ b/resources/functions/constitution/upsert_constitution.sql @@ -3,12 +3,14 @@ create or replace procedure upsert_constitution(inout resource json) $$ 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, - (resource#>>'{created_by, id}')::uuid, + _citizen_id, title, annonymous from json_populate_record(null::constitution, resource) @@ -16,14 +18,13 @@ begin titles := (resource->>'titles'); - insert into title (created_by_id, name, rank, constitution_id) - select - coalesce((ti#>>'{created_by, id}')::uuid, (resource#>>'{created_by, id}')::uuid), - ti->>'name', - row_number() OVER (), - new_id - from json_array_elements(titles) ti, - lateral json_populate_record(null::title, ti); + 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; diff --git a/resources/sql/migrations/0000-init_schema.up.sql b/resources/sql/migrations/0000-init_schema.up.sql index 1046234..7a6ed8d 100644 --- a/resources/sql/migrations/0000-init_schema.up.sql +++ b/resources/sql/migrations/0000-init_schema.up.sql @@ -161,6 +161,7 @@ begin from title as t where t.id = new.title_id ); + return new; end; $$; diff --git a/resources/tests/constitution.sql b/resources/tests/constitution.sql index 2a95203..8f73638 100644 --- a/resources/tests/constitution.sql +++ b/resources/tests/constitution.sql @@ -4,9 +4,42 @@ 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"]}'; - created_constitution json := '{"version_id":"18ff6dd6-3bc1-4c59-82f0-5e2a8d54ae3e", "title": "Love the world", "annonymous": false, "titles": [{"name":"titleOne"},{"name":"titleTwo"}]}'; + 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); @@ -27,11 +60,13 @@ begin -- 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; From 4407a39482e51029d19948aff972ad9693779ac8 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sun, 28 Jul 2019 22:45:15 +0200 Subject: [PATCH 09/14] add ide files --- .gitignore | 1 - .idea/dataSources.xml | 11 ++ .idea/gradle.xml | 1 + .idea/modules.xml | 10 ++ .idea/modules/dcproject.main.iml | 111 ++++++++++++++ .idea/modules/dcproject.test.iml | 160 ++++++++++++++++++++ .idea/runConfigurations/dcproject__run_.xml | 31 ++++ .idea/sqldialects.xml | 9 ++ dcproject.iml | 11 ++ 9 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/modules/dcproject.main.iml create mode 100644 .idea/modules/dcproject.test.iml create mode 100644 .idea/runConfigurations/dcproject__run_.xml create mode 100644 .idea/sqldialects.xml create mode 100644 dcproject.iml diff --git a/.gitignore b/.gitignore index fae6b74..baeba60 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ /.idea /out /build -*.iml *.ipr *.iws diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..582056a --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,11 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/dc-project + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 3a36432..cae81d0 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,5 +1,6 @@ +