Validate hierarchies
This commit is contained in:
parent
277fad827d
commit
d4540f8498
13 changed files with 611 additions and 33 deletions
|
@ -9,15 +9,15 @@ class OrgUnit < ApplicationRecord
|
|||
class_name: 'OrgUnitKind',
|
||||
inverse_of: :instances
|
||||
|
||||
belongs_to :parent,
|
||||
belongs_to :parent_unit,
|
||||
class_name: 'OrgUnit',
|
||||
inverse_of: :children,
|
||||
inverse_of: :children_units,
|
||||
optional: true
|
||||
|
||||
has_many :children,
|
||||
has_many :children_units,
|
||||
class_name: 'OrgUnit',
|
||||
inverse_of: :parent,
|
||||
foreign_key: :parent_id
|
||||
inverse_of: :parent_unit,
|
||||
foreign_key: :parent_unit_id
|
||||
|
||||
has_many :all_relationships,
|
||||
class_name: 'Relationship',
|
||||
|
@ -31,7 +31,7 @@ class OrgUnit < ApplicationRecord
|
|||
|
||||
validates :name, good_small_text: true, uniqueness: true
|
||||
|
||||
validates :parent,
|
||||
validates :parent_unit,
|
||||
presence: {
|
||||
if: ->(record) { record.kind&.parent_kind },
|
||||
message: :required,
|
||||
|
@ -39,9 +39,19 @@ class OrgUnit < ApplicationRecord
|
|||
|
||||
validate :parent_matches_kind
|
||||
|
||||
#############
|
||||
# Callbacks #
|
||||
#############
|
||||
|
||||
before_validation :set_level
|
||||
|
||||
private
|
||||
|
||||
def parent_matches_kind
|
||||
errors.add :parent unless parent&.kind == kind&.parent_kind
|
||||
errors.add :parent_unit unless parent_unit&.kind == kind&.parent_kind
|
||||
end
|
||||
|
||||
def set_level
|
||||
self.level = parent_unit.nil? ? 0 : parent_unit.level + 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,6 +30,12 @@ class OrgUnitKind < ApplicationRecord
|
|||
|
||||
validates :name, good_small_text: true, uniqueness: true
|
||||
|
||||
#############
|
||||
# Callbacks #
|
||||
#############
|
||||
|
||||
before_validation :set_level
|
||||
|
||||
###########
|
||||
# Methods #
|
||||
###########
|
||||
|
@ -37,4 +43,10 @@ class OrgUnitKind < ApplicationRecord
|
|||
def to_param
|
||||
codename
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_level
|
||||
self.level = parent_kind.nil? ? 0 : parent_kind.level + 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,13 +7,35 @@ class Relationship < ApplicationRecord
|
|||
|
||||
belongs_to :org_unit, inverse_of: :all_relationships
|
||||
|
||||
belongs_to :parent_rel,
|
||||
class_name: 'Relationship',
|
||||
inverse_of: :children_rels,
|
||||
optional: true
|
||||
|
||||
belongs_to :status, class_name: 'RelationStatus'
|
||||
|
||||
belongs_to :person, inverse_of: :all_relationships
|
||||
|
||||
has_many :children_rels,
|
||||
class_name: 'Relationship',
|
||||
inverse_of: :parent_rel,
|
||||
foreign_key: :parent_rel_id
|
||||
|
||||
###############
|
||||
# Validations #
|
||||
###############
|
||||
|
||||
validates :from_date, presence: true, uniqueness: { scope: :person_id }
|
||||
|
||||
#############
|
||||
# Callbacks #
|
||||
#############
|
||||
|
||||
before_validation :set_level
|
||||
|
||||
private
|
||||
|
||||
def set_level
|
||||
self.level = parent_rel.nil? ? 0 : parent_rel.level + 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,15 +24,15 @@
|
|||
<dt><%= OrgUnit.human_attribute_name :name %></dt>
|
||||
<dd><%= @org_unit.name %></dd>
|
||||
|
||||
<dt><%= OrgUnit.human_attribute_name :parent %></dt>
|
||||
<dt><%= OrgUnit.human_attribute_name :parent_unit %></dt>
|
||||
<dd>
|
||||
<% if @org_unit.parent.nil? %>
|
||||
<% if @org_unit.parent_unit.nil? %>
|
||||
<%= none %>
|
||||
<% elsif policy([:staff, @org_unit.parent]).show? %>
|
||||
<%= link_to @org_unit.parent.name,
|
||||
[:staff, @org_unit.parent] %>
|
||||
<% elsif policy([:staff, @org_unit.parent_unit]).show? %>
|
||||
<%= link_to @org_unit.parent_unit.name,
|
||||
[:staff, @org_unit.parent_unit] %>
|
||||
<% else %>
|
||||
<%= @org_unit.parent.name %>
|
||||
<%= @org_unit.parent_unit.name %>
|
||||
<% end %>
|
||||
</dd>
|
||||
</dl>
|
||||
|
|
|
@ -77,7 +77,7 @@ en:
|
|||
kind: Type
|
||||
short_name: Short name
|
||||
name: Name
|
||||
parent: Parent
|
||||
parent_unit: Parent
|
||||
org_unit_kind:
|
||||
id: ID
|
||||
codename: Codename
|
||||
|
|
|
@ -77,7 +77,7 @@ ru:
|
|||
kind: Тип
|
||||
short_name: Короткое развание
|
||||
name: Название
|
||||
parent: Родитель
|
||||
parent_unit: Родитель
|
||||
org_unit_kind:
|
||||
id: ID
|
||||
codename: Кодовое имя
|
||||
|
|
229
db/migrate/20191002002101_add_level_to_tables.rb
Normal file
229
db/migrate/20191002002101_add_level_to_tables.rb
Normal file
|
@ -0,0 +1,229 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddLevelToTables < ActiveRecord::Migration[6.0]
|
||||
include Partynest::Migration
|
||||
|
||||
def change
|
||||
rename_column :org_units, :parent_id, :parent_unit_id
|
||||
|
||||
add_reference :relationships,
|
||||
:parent_rel,
|
||||
null: true,
|
||||
index: true,
|
||||
foreign_key: { to_table: :relationships }
|
||||
|
||||
# rubocop:disable Rails/NotNullColumn
|
||||
add_column :org_unit_kinds, :level, :integer, null: false
|
||||
add_column :org_units, :level, :integer, null: false
|
||||
add_column :relationships, :level, :integer, null: false
|
||||
# rubocop:enable Rails/NotNullColumn
|
||||
|
||||
add_constraint :org_unit_kinds, :level, 'level >= 0'
|
||||
add_constraint :org_units, :level, 'level >= 0'
|
||||
add_constraint :relationships, :level, 'level >= 0'
|
||||
|
||||
add_constraint :org_unit_kinds, :parent_kind, 'parent_kind_id != id'
|
||||
add_constraint :org_units, :parent_unit, 'parent_unit_id != id'
|
||||
add_constraint :relationships, :parent_rel, 'parent_rel_id != id'
|
||||
|
||||
add_func_validate_org_unit_kind_hierarchy
|
||||
add_func_validate_org_unit_hierarchy
|
||||
add_func_validate_relationship_hierarchy
|
||||
|
||||
add_trigger :org_unit_kinds,
|
||||
:validate_hierarchy,
|
||||
'BEFORE INSERT OR UPDATE',
|
||||
'validate_org_unit_kind_hierarchy()'
|
||||
|
||||
add_trigger :org_units,
|
||||
:validate_hierarchy,
|
||||
'BEFORE INSERT OR UPDATE',
|
||||
'validate_org_unit_hierarchy()'
|
||||
|
||||
add_trigger :relationships,
|
||||
:validate_hierarchy,
|
||||
'BEFORE INSERT OR UPDATE',
|
||||
'validate_relationship_hierarchy()'
|
||||
end
|
||||
|
||||
def add_func_validate_org_unit_kind_hierarchy
|
||||
add_func :validate_org_unit_kind_hierarchy, <<~SQL
|
||||
() RETURNS trigger LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
parent_kind record;
|
||||
BEGIN
|
||||
IF NEW.parent_kind_id IS NULL THEN
|
||||
IF NEW.level != 0 THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_unit_kinds
|
||||
INTO parent_kind
|
||||
WHERE id = NEW.parent_kind_id;
|
||||
|
||||
IF parent_kind IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find parent';
|
||||
END IF;
|
||||
|
||||
IF NEW.level != parent_kind.level + 1 THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
SQL
|
||||
end
|
||||
|
||||
def add_func_validate_org_unit_hierarchy
|
||||
add_func :validate_org_unit_hierarchy, <<~SQL
|
||||
() RETURNS trigger LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
kind record;
|
||||
parent_kind record;
|
||||
parent_unit record;
|
||||
BEGIN
|
||||
IF NEW.kind_id IS NULL THEN
|
||||
RAISE EXCEPTION 'does not have type';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_unit_kinds
|
||||
INTO kind
|
||||
WHERE id = NEW.kind_id;
|
||||
|
||||
IF kind IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find type';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_unit_kinds
|
||||
INTO parent_kind
|
||||
WHERE id = kind.parent_kind_id;
|
||||
|
||||
IF (kind.parent_kind_id IS NULL) != (parent_kind IS NULL) THEN
|
||||
RAISE EXCEPTION 'can not find parent type';
|
||||
END IF;
|
||||
|
||||
IF parent_kind IS NULL THEN
|
||||
IF NEW.parent_unit_id IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'parent is invalid (expected NULL)';
|
||||
END IF;
|
||||
|
||||
IF NEW.level != 0 THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF NEW.parent_unit_id IS NULL THEN
|
||||
RAISE EXCEPTION 'parent is invalid (expected NOT NULL)';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_units
|
||||
INTO parent_unit
|
||||
WHERE id = NEW.parent_unit_id;
|
||||
|
||||
IF parent_unit IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find parent';
|
||||
END IF;
|
||||
|
||||
IF parent_unit.kind_id != parent_kind.id THEN
|
||||
RAISE EXCEPTION 'parent is invalid';
|
||||
END IF;
|
||||
|
||||
IF (
|
||||
NEW.level != kind.level OR
|
||||
NEW.level != parent_kind.level + 1 OR
|
||||
NEW.level != parent_unit.level + 1
|
||||
) THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
SQL
|
||||
end
|
||||
|
||||
def add_func_validate_relationship_hierarchy
|
||||
add_func :validate_relationship_hierarchy, <<~SQL
|
||||
() RETURNS trigger LANGUAGE plpgsql AS
|
||||
$$
|
||||
DECLARE
|
||||
org_unit record;
|
||||
parent_unit record;
|
||||
parent_rel record;
|
||||
BEGIN
|
||||
IF NEW.org_unit_id IS NULL THEN
|
||||
RAISE EXCEPTION 'does not have org unit';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_units
|
||||
INTO org_unit
|
||||
WHERE id = NEW.org_unit_id;
|
||||
|
||||
IF org_unit IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find org unit';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_units
|
||||
INTO parent_unit
|
||||
WHERE id = org_unit.parent_unit_id;
|
||||
|
||||
IF (org_unit.parent_unit_id IS NULL) != (parent_unit IS NULL) THEN
|
||||
RAISE EXCEPTION 'can not find parent org unit';
|
||||
END IF;
|
||||
|
||||
IF parent_unit IS NULL THEN
|
||||
IF NEW.parent_rel_id IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'parent rel is invalid (expected NULL)';
|
||||
END IF;
|
||||
|
||||
IF NEW.level != 0 THEN
|
||||
RAISE EXCEPTION 'level is invalid (expected 0)';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF NEW.parent_rel_id IS NULL THEN
|
||||
RAISE EXCEPTION 'parent rel is invalid (expected NOT NULL)';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM relationships
|
||||
INTO parent_rel
|
||||
WHERE id = NEW.parent_rel_id;
|
||||
|
||||
IF parent_rel IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find parent rel';
|
||||
END IF;
|
||||
|
||||
IF parent_rel.org_unit_id != parent_unit.id THEN
|
||||
RAISE EXCEPTION 'parent rel is invalid';
|
||||
END IF;
|
||||
|
||||
IF (
|
||||
NEW.level != org_unit.level OR
|
||||
NEW.level != parent_unit.level + 1 OR
|
||||
NEW.level != parent_rel.level + 1
|
||||
) THEN
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
SQL
|
||||
end
|
||||
end
|
246
db/structure.sql
246
db/structure.sql
|
@ -199,6 +199,193 @@ END;
|
|||
$_$;
|
||||
|
||||
|
||||
--
|
||||
-- Name: validate_org_unit_hierarchy(); Type: FUNCTION; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE FUNCTION public.validate_org_unit_hierarchy() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
kind record;
|
||||
parent_kind record;
|
||||
parent_unit record;
|
||||
BEGIN
|
||||
IF NEW.kind_id IS NULL THEN
|
||||
RAISE EXCEPTION 'does not have type';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_unit_kinds
|
||||
INTO kind
|
||||
WHERE id = NEW.kind_id;
|
||||
|
||||
IF kind IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find type';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_unit_kinds
|
||||
INTO parent_kind
|
||||
WHERE id = kind.parent_kind_id;
|
||||
|
||||
IF (kind.parent_kind_id IS NULL) != (parent_kind IS NULL) THEN
|
||||
RAISE EXCEPTION 'can not find parent type';
|
||||
END IF;
|
||||
|
||||
IF parent_kind IS NULL THEN
|
||||
IF NEW.parent_unit_id IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'parent is invalid (expected NULL)';
|
||||
END IF;
|
||||
|
||||
IF NEW.level != 0 THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF NEW.parent_unit_id IS NULL THEN
|
||||
RAISE EXCEPTION 'parent is invalid (expected NOT NULL)';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_units
|
||||
INTO parent_unit
|
||||
WHERE id = NEW.parent_unit_id;
|
||||
|
||||
IF parent_unit IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find parent';
|
||||
END IF;
|
||||
|
||||
IF parent_unit.kind_id != parent_kind.id THEN
|
||||
RAISE EXCEPTION 'parent is invalid';
|
||||
END IF;
|
||||
|
||||
IF (
|
||||
NEW.level != kind.level OR
|
||||
NEW.level != parent_kind.level + 1 OR
|
||||
NEW.level != parent_unit.level + 1
|
||||
) THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
--
|
||||
-- Name: validate_org_unit_kind_hierarchy(); Type: FUNCTION; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE FUNCTION public.validate_org_unit_kind_hierarchy() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
parent_kind record;
|
||||
BEGIN
|
||||
IF NEW.parent_kind_id IS NULL THEN
|
||||
IF NEW.level != 0 THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_unit_kinds
|
||||
INTO parent_kind
|
||||
WHERE id = NEW.parent_kind_id;
|
||||
|
||||
IF parent_kind IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find parent';
|
||||
END IF;
|
||||
|
||||
IF NEW.level != parent_kind.level + 1 THEN
|
||||
RAISE EXCEPTION 'level is invalid';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
--
|
||||
-- Name: validate_relationship_hierarchy(); Type: FUNCTION; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE FUNCTION public.validate_relationship_hierarchy() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
org_unit record;
|
||||
parent_unit record;
|
||||
parent_rel record;
|
||||
BEGIN
|
||||
IF NEW.org_unit_id IS NULL THEN
|
||||
RAISE EXCEPTION 'does not have org unit';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_units
|
||||
INTO org_unit
|
||||
WHERE id = NEW.org_unit_id;
|
||||
|
||||
IF org_unit IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find org unit';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM org_units
|
||||
INTO parent_unit
|
||||
WHERE id = org_unit.parent_unit_id;
|
||||
|
||||
IF (org_unit.parent_unit_id IS NULL) != (parent_unit IS NULL) THEN
|
||||
RAISE EXCEPTION 'can not find parent org unit';
|
||||
END IF;
|
||||
|
||||
IF parent_unit IS NULL THEN
|
||||
IF NEW.parent_rel_id IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'parent rel is invalid (expected NULL)';
|
||||
END IF;
|
||||
|
||||
IF NEW.level != 0 THEN
|
||||
RAISE EXCEPTION 'level is invalid (expected 0)';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF NEW.parent_rel_id IS NULL THEN
|
||||
RAISE EXCEPTION 'parent rel is invalid (expected NOT NULL)';
|
||||
END IF;
|
||||
|
||||
SELECT *
|
||||
FROM relationships
|
||||
INTO parent_rel
|
||||
WHERE id = NEW.parent_rel_id;
|
||||
|
||||
IF parent_rel IS NULL THEN
|
||||
RAISE EXCEPTION 'can not find parent rel';
|
||||
END IF;
|
||||
|
||||
IF parent_rel.org_unit_id != parent_unit.id THEN
|
||||
RAISE EXCEPTION 'parent rel is invalid';
|
||||
END IF;
|
||||
|
||||
IF (
|
||||
NEW.level != org_unit.level OR
|
||||
NEW.level != parent_unit.level + 1 OR
|
||||
NEW.level != parent_rel.level + 1
|
||||
) THEN
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_with_oids = false;
|
||||
|
@ -473,8 +660,11 @@ CREATE TABLE public.org_unit_kinds (
|
|||
short_name character varying NOT NULL,
|
||||
name character varying NOT NULL,
|
||||
parent_kind_id bigint,
|
||||
level integer NOT NULL,
|
||||
CONSTRAINT codename CHECK (public.is_codename((codename)::text)),
|
||||
CONSTRAINT level CHECK ((level >= 0)),
|
||||
CONSTRAINT name CHECK (public.is_good_small_text((name)::text)),
|
||||
CONSTRAINT parent_kind CHECK ((parent_kind_id <> id)),
|
||||
CONSTRAINT short_name CHECK (public.is_good_small_text((short_name)::text))
|
||||
);
|
||||
|
||||
|
@ -509,8 +699,11 @@ CREATE TABLE public.org_units (
|
|||
short_name character varying NOT NULL,
|
||||
name character varying NOT NULL,
|
||||
kind_id bigint NOT NULL,
|
||||
parent_id bigint,
|
||||
parent_unit_id bigint,
|
||||
level integer NOT NULL,
|
||||
CONSTRAINT level CHECK ((level >= 0)),
|
||||
CONSTRAINT name CHECK (public.is_good_small_text((name)::text)),
|
||||
CONSTRAINT parent_unit CHECK ((parent_unit_id <> id)),
|
||||
CONSTRAINT short_name CHECK (public.is_good_small_text((short_name)::text))
|
||||
);
|
||||
|
||||
|
@ -759,7 +952,11 @@ CREATE TABLE public.relationships (
|
|||
person_id bigint NOT NULL,
|
||||
from_date date NOT NULL,
|
||||
status_id bigint NOT NULL,
|
||||
org_unit_id bigint NOT NULL
|
||||
org_unit_id bigint NOT NULL,
|
||||
parent_rel_id bigint,
|
||||
level integer NOT NULL,
|
||||
CONSTRAINT level CHECK ((level >= 0)),
|
||||
CONSTRAINT parent_rel CHECK ((parent_rel_id <> id))
|
||||
);
|
||||
|
||||
|
||||
|
@ -1343,10 +1540,10 @@ CREATE UNIQUE INDEX index_org_units_on_name ON public.org_units USING btree (nam
|
|||
|
||||
|
||||
--
|
||||
-- Name: index_org_units_on_parent_id; Type: INDEX; Schema: public; Owner: -
|
||||
-- Name: index_org_units_on_parent_unit_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_org_units_on_parent_id ON public.org_units USING btree (parent_id);
|
||||
CREATE INDEX index_org_units_on_parent_unit_id ON public.org_units USING btree (parent_unit_id);
|
||||
|
||||
|
||||
--
|
||||
|
@ -1454,6 +1651,13 @@ CREATE INDEX index_relationships_on_from_date ON public.relationships USING btre
|
|||
CREATE INDEX index_relationships_on_org_unit_id ON public.relationships USING btree (org_unit_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_relationships_on_parent_rel_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_relationships_on_parent_rel_id ON public.relationships USING btree (parent_rel_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_relationships_on_person_id_and_from_date; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1545,6 +1749,27 @@ CREATE TRIGGER ensure_contact_list_id_remains_unchanged BEFORE UPDATE OF contact
|
|||
CREATE TRIGGER ensure_superuser_has_related_user BEFORE INSERT OR UPDATE ON public.accounts FOR EACH ROW EXECUTE PROCEDURE public.ensure_superuser_has_related_user();
|
||||
|
||||
|
||||
--
|
||||
-- Name: org_unit_kinds validate_hierarchy; Type: TRIGGER; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TRIGGER validate_hierarchy BEFORE INSERT OR UPDATE ON public.org_unit_kinds FOR EACH ROW EXECUTE PROCEDURE public.validate_org_unit_kind_hierarchy();
|
||||
|
||||
|
||||
--
|
||||
-- Name: org_units validate_hierarchy; Type: TRIGGER; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TRIGGER validate_hierarchy BEFORE INSERT OR UPDATE ON public.org_units FOR EACH ROW EXECUTE PROCEDURE public.validate_org_unit_hierarchy();
|
||||
|
||||
|
||||
--
|
||||
-- Name: relationships validate_hierarchy; Type: TRIGGER; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TRIGGER validate_hierarchy BEFORE INSERT OR UPDATE ON public.relationships FOR EACH ROW EXECUTE PROCEDURE public.validate_relationship_hierarchy();
|
||||
|
||||
|
||||
--
|
||||
-- Name: relationships fk_rails_0ea63a126c; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1566,7 +1791,7 @@ ALTER TABLE ONLY public.people
|
|||
--
|
||||
|
||||
ALTER TABLE ONLY public.org_units
|
||||
ADD CONSTRAINT fk_rails_54c0512b74 FOREIGN KEY (parent_id) REFERENCES public.org_units(id);
|
||||
ADD CONSTRAINT fk_rails_54c0512b74 FOREIGN KEY (parent_unit_id) REFERENCES public.org_units(id);
|
||||
|
||||
|
||||
--
|
||||
|
@ -1657,6 +1882,14 @@ ALTER TABLE ONLY public.relation_transitions
|
|||
ADD CONSTRAINT fk_rails_b61956945e FOREIGN KEY (from_status_id) REFERENCES public.relation_statuses(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: relationships fk_rails_b943fd3c34; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.relationships
|
||||
ADD CONSTRAINT fk_rails_b943fd3c34 FOREIGN KEY (parent_rel_id) REFERENCES public.relationships(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: org_units fk_rails_ccc56f184e; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1725,6 +1958,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20190930210852'),
|
||||
('20190930215223'),
|
||||
('20191001022049'),
|
||||
('20191001211809');
|
||||
('20191001211809'),
|
||||
('20191002002101');
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ FactoryBot.define do
|
|||
trait :with_parent do
|
||||
association :kind, factory: :some_children_org_unit_kind
|
||||
|
||||
parent { create :some_root_org_unit, kind: kind.parent_kind }
|
||||
parent_unit { create :some_root_org_unit, kind: kind.parent_kind }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :supporter_relationship, class: Relationship do
|
||||
association :org_unit, factory: :some_children_org_unit
|
||||
factory :some_root_relationship, class: Relationship do
|
||||
association :org_unit, factory: :some_root_org_unit
|
||||
association :status, factory: :some_relation_status
|
||||
association :person, factory: :initial_person
|
||||
|
||||
sequence :from_date do |n|
|
||||
Date.new rand((10 * n)...(11 * n)), rand(1..12), rand(1..28)
|
||||
end
|
||||
|
||||
trait :with_parent do
|
||||
association :org_unit, factory: :some_children_org_unit
|
||||
|
||||
parent_rel do
|
||||
create :some_root_relationship, org_unit: org_unit&.parent_unit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :some_children_relationship,
|
||||
parent: :some_root_relationship,
|
||||
traits: %i[with_parent]
|
||||
|
||||
factory :supporter_relationship, parent: :some_children_relationship
|
||||
|
||||
factory :excluded_relationship, parent: :supporter_relationship
|
||||
|
||||
factory :member_relationship, parent: :supporter_relationship
|
||||
|
|
|
@ -44,6 +44,20 @@ module Partynest
|
|||
end
|
||||
end
|
||||
|
||||
def add_trigger(table, name, events, call)
|
||||
reversible do |dir|
|
||||
dir.up { trigger_creation(table, name, events, call).call }
|
||||
dir.down { trigger_deletion(table, name).call }
|
||||
end
|
||||
end
|
||||
|
||||
def remove_trigger(table, name, events, call)
|
||||
reversible do |dir|
|
||||
dir.up { trigger_deletion(table, name).call }
|
||||
dir.down { trigger_creation(table, name, events, call).call }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def func_creation(name, sql)
|
||||
|
@ -69,6 +83,18 @@ module Partynest
|
|||
end
|
||||
end
|
||||
|
||||
def trigger_creation(table, name, events, call)
|
||||
lambda do
|
||||
execute <<~SQL
|
||||
CREATE TRIGGER #{name}
|
||||
#{events}
|
||||
ON #{table}
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE #{call};
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
||||
def func_deletion(name)
|
||||
lambda do
|
||||
execute "DROP FUNCTION #{name}"
|
||||
|
@ -86,5 +112,11 @@ module Partynest
|
|||
execute "ALTER TABLE #{table} DROP CONSTRAINT #{name}"
|
||||
end
|
||||
end
|
||||
|
||||
def trigger_deletion(table, name)
|
||||
lambda do
|
||||
execute "DROP TRIGGER #{name} ON #{table}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,19 +17,21 @@ RSpec.describe OrgUnit do
|
|||
it { is_expected.to validate_presence_of(:kind).with_message(:required) }
|
||||
end
|
||||
|
||||
describe '#parent' do
|
||||
describe '#parent_unit' do
|
||||
it do
|
||||
is_expected.to \
|
||||
belong_to(:parent)
|
||||
belong_to(:parent_unit)
|
||||
.class_name('OrgUnit')
|
||||
.inverse_of(:children)
|
||||
.inverse_of(:children_units)
|
||||
end
|
||||
|
||||
context 'when organizational unit type does not require parent' do
|
||||
subject { create :some_root_org_unit }
|
||||
|
||||
it do
|
||||
is_expected.not_to validate_presence_of(:parent).with_message(:required)
|
||||
is_expected.not_to \
|
||||
validate_presence_of(:parent_unit)
|
||||
.with_message(:required)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,18 +39,20 @@ RSpec.describe OrgUnit do
|
|||
subject { create :some_children_org_unit }
|
||||
|
||||
it do
|
||||
is_expected.to validate_presence_of(:parent).with_message(:required)
|
||||
is_expected.to \
|
||||
validate_presence_of(:parent_unit)
|
||||
.with_message(:required)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#children' do
|
||||
describe '#children_units' do
|
||||
it do
|
||||
is_expected.to \
|
||||
have_many(:children)
|
||||
have_many(:children_units)
|
||||
.class_name('OrgUnit')
|
||||
.inverse_of(:parent)
|
||||
.with_foreign_key(:parent_id)
|
||||
.inverse_of(:parent_unit)
|
||||
.with_foreign_key(:parent_unit_id)
|
||||
.dependent(:restrict_with_exception)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,27 @@ RSpec.describe Relationship do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#parent_rel' do
|
||||
it do
|
||||
is_expected.to \
|
||||
belong_to(:parent_rel)
|
||||
.class_name('Relationship')
|
||||
.inverse_of(:children_rels)
|
||||
.optional
|
||||
end
|
||||
end
|
||||
|
||||
describe '#children_rels' do
|
||||
it do
|
||||
is_expected.to \
|
||||
have_many(:children_rels)
|
||||
.class_name('Relationship')
|
||||
.inverse_of(:parent_rel)
|
||||
.with_foreign_key(:parent_rel_id)
|
||||
.dependent(:restrict_with_exception)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#status' do
|
||||
it do
|
||||
is_expected.to belong_to(:status).class_name('RelationStatus').required
|
||||
|
|
Reference in a new issue