-
Notifications
You must be signed in to change notification settings - Fork 13
Hierarchy Implementation Proposal #793
base: master
Are you sure you want to change the base?
Changes from 1 commit
7fbab8b
93c660a
7532f7d
d28a3e0
f61fd59
f64f7ad
991a00f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,8 @@ See the [PSQL documentation](https://www.postgresql.org/docs/current/ddl-inherit | |
|
||
> Table inheritance is typically established when the child table is created, using the INHERITS clause of the CREATE TABLE statement. | ||
|
||
> Rust Diesel isn't intended for that. To only select data from a specific table, and not include all child tables, we would need to use the `FROM ONLY` keyword, which is not implemented in Rust Diesel. | ||
|
||
So the inheritance is useful to deal with complex DDL structure on the startup, but will not help us to avoid bulk operations e.g. updating a column for every `variety` in the entire `genus` | ||
|
||
### One table per taxonomy rank and one for concrete plants. | ||
|
@@ -85,6 +87,28 @@ Cons: | |
- Almost everything in the plants table needs to be nullable. | ||
- More complex insert and update logic. | ||
|
||
### One table per taxonomy rank and one for concrete plants. + View and custom insert/update/delete functionality | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This title is a bit confusing in my opinion. |
||
|
||
[Example](example_migrations/one-table-per-taxonomy-view-functions) | ||
|
||
It's similar to `One table for taxonomy ranks and one for concrete plants` We are extending it with a view and custom functions to reduce insert and update complexity in the backend. | ||
|
||
Pros: | ||
|
||
- Inserting new plants is easy. We only need to implement minor backend changes. | ||
|
||
Cons: | ||
|
||
- Attribute overrides can only be done on the variety or cultivar level. | ||
temmey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- More complex insert and update logic. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But it would be hidden behind triggers? In general this sounds like a good idea, as we then don't need to keep Rust, maybe Python (E2E) and JavaScript code (scraper) in sync. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, and the view would act just like our plant table right now, we only extend it with some more properties. |
||
When a species/variety is added or updated, the columns can't just be set. | ||
First, we need to make sure all higher levels are in the table. | ||
Then we need to check for each column value if there is a higher rank that already defines the same value. | ||
Only if we can't find a match, the value should be written. | ||
- We can offset this issue by implementing insert/update functions. | ||
Since they are going to be complicated, long-term maintainability may be an issue. | ||
- Almost everything in the plants and parent tables needs to be nullable. (Is this a downside?) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I think so. If everything is nullable (even if this goes against our data model) we need to perform more manual integrity checks. |
||
|
||
## Decision | ||
|
||
- We go with the last option "All ranks in one table" as described [in our documentation](../database/hierarchy.md). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# example |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- This file should undo anything in `up.sql` | ||
-- since this is WIP, i will keep this empty for now. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
-- Create the "family" table | ||
CREATE TABLE family ( | ||
id SERIAL PRIMARY KEY, | ||
name VARCHAR NOT NULL, | ||
property1 TEXT, | ||
CONSTRAINT family_name_key UNIQUE (name) | ||
); | ||
|
||
-- Create the "genus" table | ||
CREATE TABLE genus ( | ||
id SERIAL PRIMARY KEY, | ||
name VARCHAR NOT NULL, | ||
property1 TEXT, | ||
family_id INTEGER NOT NULL REFERENCES family (id), | ||
CONSTRAINT genus_name_key UNIQUE (name) | ||
); | ||
|
||
-- Create the "species" table | ||
CREATE TABLE species ( | ||
id SERIAL PRIMARY KEY, | ||
name VARCHAR NOT NULL, | ||
property1 TEXT, | ||
genus_id INTEGER NOT NULL REFERENCES genus (id), | ||
CONSTRAINT species_name_key UNIQUE (name) | ||
); | ||
|
||
-- Create the "variety" table | ||
CREATE TABLE variety ( | ||
id SERIAL PRIMARY KEY, | ||
name VARCHAR NOT NULL, | ||
property1 TEXT, | ||
species_id INTEGER NOT NULL REFERENCES species (id), | ||
CONSTRAINT variety_name_key UNIQUE (name) | ||
); | ||
|
||
-- Create the "cultivar" table | ||
CREATE TABLE cultivar ( | ||
id SERIAL PRIMARY KEY, | ||
name VARCHAR NOT NULL, | ||
property1 TEXT, | ||
species_id INTEGER NOT NULL REFERENCES species (id), | ||
variety_id INTEGER NOT NULL REFERENCES variety (id), | ||
CONSTRAINT cultivar_name_key UNIQUE (name) | ||
); | ||
|
||
-- Create the "plantsDetails" table | ||
CREATE TABLE plantsdetails ( | ||
id INTEGER NOT NULL, | ||
unique_name TEXT NOT NULL, | ||
common_name_en TEXT [], | ||
common_name_de TEXT [], | ||
property1 TEXT, | ||
family_id INTEGER NOT NULL REFERENCES family (id), | ||
genus_id INTEGER NOT NULL REFERENCES genus (id), | ||
species_id INTEGER NOT NULL, | ||
variety_id INTEGER, | ||
cultivar_id INTEGER, | ||
CONSTRAINT unique_name_key UNIQUE (unique_name), | ||
CONSTRAINT check_variety_or_cultivar CHECK ( | ||
variety_id IS NULL OR cultivar_id IS NULL | ||
) | ||
); | ||
|
||
-- Create a view joining the tables together | ||
-- COALESCE function accepts an unlimited number of arguments. | ||
-- It returns the first argument that is not null. | ||
CREATE OR REPLACE VIEW plants AS | ||
SELECT | ||
p.id AS plant_id, | ||
p.unique_name, | ||
p.common_name_en, | ||
p.common_name_de, | ||
f.name AS family_name, | ||
g.name AS genus_name, | ||
s.name AS species_name, | ||
v.name AS variety_name, | ||
c.name AS cultivar_name, | ||
coalesce( | ||
p.property1, | ||
c.property1, | ||
v.property1, | ||
s.property1, | ||
g.property1, | ||
f.property1 | ||
) AS property1 | ||
FROM plants AS p | ||
INNER JOIN family AS f ON p.family_id = f.id | ||
INNER JOIN genus AS g ON p.genus_id = g.id | ||
INNER JOIN species AS s ON p.species_id = s.id | ||
LEFT JOIN variety AS v ON p.variety_id = v.id | ||
LEFT JOIN cultivar AS c ON p.cultivar_id = c.id; | ||
|
||
|
||
CREATE OR REPLACE FUNCTION insert_plant_view_placeholder() | ||
RETURNS TRIGGER AS $$ | ||
BEGIN | ||
-- Placeholder function, no implementation provided. | ||
-- will insert a new item and only fill columns, if they differ from parent tables. | ||
RETURN NEW; | ||
END; | ||
$$ | ||
LANGUAGE plpgsql; | ||
|
||
CREATE TRIGGER insert_plant_view_trigger | ||
INSTEAD OF INSERT ON plants_view | ||
FOR EACH ROW | ||
EXECUTE FUNCTION insert_plant_view_placeholder(); | ||
|
||
|
||
|
||
CREATE OR REPLACE FUNCTION update_plant_view_placeholder() | ||
RETURNS TRIGGER AS $$ | ||
BEGIN | ||
-- Placeholder function, no implementation provided. | ||
-- will only update values in plantDetails if they differ from a parent table. | ||
RETURN NEW; | ||
END; | ||
$$ | ||
LANGUAGE plpgsql; | ||
|
||
CREATE TRIGGER update_plant_view_trigger | ||
INSTEAD OF UPDATE ON plants_view | ||
FOR EACH ROW | ||
EXECUTE FUNCTION update_plant_view_placeholder(); | ||
|
||
|
||
CREATE OR REPLACE FUNCTION delete_plant_view_placeholder() | ||
RETURNS TRIGGER AS $$ | ||
BEGIN | ||
-- Placeholder function, no implementation provided. | ||
-- Will simply delete from the plantsDetails table | ||
RETURN OLD; | ||
END; | ||
$$ | ||
LANGUAGE plpgsql; | ||
|
||
CREATE TRIGGER delete_plant_view_trigger | ||
INSTEAD OF DELETE ON plants_view | ||
FOR EACH ROW | ||
EXECUTE FUNCTION delete_plant_view_placeholder(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# One Table Per Taxonomy + View + Custom Insert, Update, Delete functions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sentences need to be written on separate lines according to our documentation guidelines.