diff --git a/backend/.sqlfluff b/backend/.sqlfluff index 6aa7b483c..b7fdc696a 100644 --- a/backend/.sqlfluff +++ b/backend/.sqlfluff @@ -1,8 +1,9 @@ # https://docs.sqlfluff.com/en/stable/configuration.html [sqlfluff] dialect = postgres +max_line_length = 120 -#enforce upper and lowercase +# Capitalization Rules [sqlfluff:rules:capitalisation.keywords] capitalisation_policy = upper [sqlfluff:rules:capitalisation.identifiers] @@ -12,4 +13,4 @@ extended_capitalisation_policy = lower [sqlfluff:rules:capitalisation.literals] capitalisation_policy = lower [sqlfluff:rules:capitalisation.types] -extended_capitalisation_policy = upper +extended_capitalisation_policy = lower diff --git a/backend/migrations/2023-07-04-190000_base_layer/up.sql b/backend/migrations/2023-07-04-190000_base_layer/up.sql index c3db15b86..b64e17ae6 100644 --- a/backend/migrations/2023-07-04-190000_base_layer/up.sql +++ b/backend/migrations/2023-07-04-190000_base_layer/up.sql @@ -3,10 +3,10 @@ -- Please create a new migration instead. CREATE TABLE base_layer_images ( - id UUID PRIMARY KEY, - layer_id INTEGER NOT NULL, - path TEXT NOT NULL, - rotation REAL NOT NULL, - scale REAL NOT NULL, + id uuid PRIMARY KEY, + layer_id integer NOT NULL, + path text NOT NULL, + rotation real NOT NULL, + scale real NOT NULL, FOREIGN KEY (layer_id) REFERENCES layers (id) ON DELETE CASCADE ); diff --git a/backend/migrations/2023-07-12-143111_user_data/up.sql b/backend/migrations/2023-07-12-143111_user_data/up.sql index d07d2e6d2..9cf490b86 100644 --- a/backend/migrations/2023-07-12-143111_user_data/up.sql +++ b/backend/migrations/2023-07-12-143111_user_data/up.sql @@ -22,16 +22,16 @@ CREATE TYPE membership AS ENUM ( ); CREATE TABLE users ( - id UUID PRIMARY KEY, - salutation SALUTATION NOT NULL, - title TEXT, - country TEXT NOT NULL, - phone TEXT, - website TEXT, - organization TEXT, - experience EXPERIENCE, - membership MEMBERSHIP, - member_years INTEGER ARRAY, - member_since DATE, - permacoins INTEGER ARRAY + id uuid PRIMARY KEY, + salutation salutation NOT NULL, + title text, + country text NOT NULL, + phone text, + website text, + organization text, + experience experience, + membership membership, + member_years integer ARRAY, + member_since date, + permacoins integer ARRAY ); diff --git a/backend/migrations/2023-07-21-085933_gain_blossoms/up.sql b/backend/migrations/2023-07-21-085933_gain_blossoms/up.sql index b622d9f90..2feb514df 100644 --- a/backend/migrations/2023-07-21-085933_gain_blossoms/up.sql +++ b/backend/migrations/2023-07-21-085933_gain_blossoms/up.sql @@ -10,22 +10,22 @@ CREATE TYPE track AS ENUM ( ); CREATE TABLE guided_tours ( - user_id UUID PRIMARY KEY, - editor_tour_completed BOOLEAN NOT NULL DEFAULT false + user_id uuid PRIMARY KEY, + editor_tour_completed boolean NOT NULL DEFAULT false ); CREATE TABLE blossoms ( - title TEXT PRIMARY KEY, - description TEXT, - track TRACK, - icon TEXT, - is_seasonal BOOLEAN NOT NULL + title text PRIMARY KEY, + description text, + track track, + icon text, + is_seasonal boolean NOT NULL ); CREATE TABLE gained_blossoms ( - user_id UUID NOT NULL, - blossom TEXT NOT NULL, - times_gained INTEGER NOT NULL, - gained_date DATE NOT NULL, + user_id uuid NOT NULL, + blossom text NOT NULL, + times_gained integer NOT NULL, + gained_date date NOT NULL, PRIMARY KEY (user_id, blossom) ); diff --git a/doc/changelog.md b/doc/changelog.md index b300be5de..8e788bbbc 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -45,7 +45,7 @@ Syntax: `- short text describing the change _(Your Name)_` - _()_ - _()_ - update `doc/database/hierarchy.md` to clarify how we render plant names _(temmey)_ -- _()_ +- updated sqlfluff config, remove unused .sql files _(temmey)_ - _()_ - _()_ - _()_ diff --git a/doc/decisions/database_plant_hierarchy.md b/doc/decisions/database_plant_hierarchy.md index 8d0653cdb..cdb46ebff 100644 --- a/doc/decisions/database_plant_hierarchy.md +++ b/doc/decisions/database_plant_hierarchy.md @@ -92,8 +92,8 @@ Cons: - We add "cultivar" as lowest rank. - We remove the rank "subfamily". -For details on the schema see this [example SQL](example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql) -Here are some [example queries](example_migrations/normalized-plants-and-ranks/example_queries.sql) +For details on the schema see this [example SQL](example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql.md) +Here are some [example queries](example_migrations/normalized-plants-and-ranks/example_queries.sql.md) ## Rationale diff --git a/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/down.sql b/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/down.sql deleted file mode 100644 index f37139ed5..000000000 --- a/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/down.sql +++ /dev/null @@ -1,8 +0,0 @@ -DROP TABLE plant_relationships; -DROP TYPE relationship_kind; -ALTER TABLE plants - DROP COLUMN family_id, - DROP COLUMN subfamily_id, - DROP COLUMN genus_id, - DROP COLUMN species_id; -DROP TYPE taxonomic_rank; diff --git a/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/down.sql.md b/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/down.sql.md new file mode 100644 index 000000000..4c7975035 --- /dev/null +++ b/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/down.sql.md @@ -0,0 +1,8 @@ +DROP TABLE plant_relationships; +DROP TYPE relationship_kind; +ALTER TABLE plants +DROP COLUMN family_id, +DROP COLUMN subfamily_id, +DROP COLUMN genus_id, +DROP COLUMN species_id; +DROP TYPE taxonomic_rank; diff --git a/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql b/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql deleted file mode 100644 index 2f9ea577a..000000000 --- a/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TYPE taxonomic_rank AS ENUM ('family', 'subfamily', 'genus', 'species', 'variety'); -ALTER TABLE plants - ADD COLUMN rank TAXONOMIC_RANK NOT NULL, - ADD COLUMN family_id INTEGER REFERENCES plants (id) NULL, - ADD COLUMN subfamily_id INTEGER REFERENCES plants (id) NULL, - ADD COLUMN genus_id INTEGER REFERENCES plants (id) NULL, - ADD COLUMN species_id INTEGER REFERENCES plants (id) NULL; - - -CREATE TYPE relationship_kind AS ENUM ('companion', 'antagonist', 'neutral'); -CREATE TABLE plant_relationships ( - id SERIAL PRIMARY KEY NOT NULL, - confidence INTEGER CHECK (confidence >= 0) NOT NULL, - kind relationship_kind NOT NULL, - left_plant_id INTEGER REFERENCES plants (id) NOT NULL, - right_plant_id INTEGER REFERENCES plants (id) NOT NULL -); diff --git a/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql.md b/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql.md new file mode 100644 index 000000000..cef2990dd --- /dev/null +++ b/doc/decisions/example_migrations/normalized-plants-and-ranks/2023-04-07-130215_plant_relationships/up.sql.md @@ -0,0 +1,16 @@ +CREATE TYPE taxonomic_rank AS ENUM ('family', 'subfamily', 'genus', 'species', 'variety'); +ALTER TABLE plants +ADD COLUMN rank TAXONOMIC_RANK NOT NULL, +ADD COLUMN family_id INTEGER REFERENCES plants (id) NULL, +ADD COLUMN subfamily_id INTEGER REFERENCES plants (id) NULL, +ADD COLUMN genus_id INTEGER REFERENCES plants (id) NULL, +ADD COLUMN species_id INTEGER REFERENCES plants (id) NULL; + +CREATE TYPE relationship_kind AS ENUM ('companion', 'antagonist', 'neutral'); +CREATE TABLE plant_relationships ( +id SERIAL PRIMARY KEY NOT NULL, +confidence INTEGER CHECK (confidence >= 0) NOT NULL, +kind relationship_kind NOT NULL, +left_plant_id INTEGER REFERENCES plants (id) NOT NULL, +right_plant_id INTEGER REFERENCES plants (id) NOT NULL +); diff --git a/doc/decisions/example_migrations/normalized-plants-and-ranks/example_queries.sql b/doc/decisions/example_migrations/normalized-plants-and-ranks/example_queries.sql deleted file mode 100644 index 033985a14..000000000 --- a/doc/decisions/example_migrations/normalized-plants-and-ranks/example_queries.sql +++ /dev/null @@ -1,254 +0,0 @@ --- --- Example: Relationships --- --- For this example we use the following notation --- companion "<->" --- antagonist ">-<" --- Consider the following relationships between plants: --- Radish <-> carrot --- Radish <-> potato --- Carrot >-< potato --- Marigold <-> carrot --- Marigold <-> radish --- --- We want to plant carrots and radish and get suggestions for it. --- When looking for companions we would expect the result just to be marigold. --- Potato wouldn't be in the result since it's an antagonist to carrot. --- --- Let's insert the plants. --- insert carrot -WITH carrot_family AS ( - INSERT INTO plants (rank, binomial_name) - VALUES ('family', 'Apiaceae') RETURNING id -), - - carrot_subfamily AS ( - INSERT INTO plants (rank, binomial_name, family_id) - VALUES ('subfamily', 'Apioideae', (SELECT id FROM carrot_family)) - RETURNING id - ), - - carrot_genus AS ( - INSERT INTO plants (rank, binomial_name, family_id, subfamily_id) - VALUES ( - 'genus', - -- TODO: rename to latin_name - 'Daucus', - (SELECT id from carrot_family), - (SELECT id from carrot_subfamily) - ) - RETURNING id - ), - - carrot_species AS ( - INSERT INTO plants (rank, binomial_name, common_name, family_id, subfamily_id, genus_id) - VALUES ( - 'species', - 'Daucus carota', - '{"Carrot"}', - (SELECT id from carrot_family), - (SELECT id from carrot_subfamily), - (SELECT id from carrot_genus) - ) - RETURNING id - ), - --- insert radish - radish_family AS ( - INSERT INTO plants (rank, binomial_name) - VALUES ('family', 'Brassicaceae') RETURNING id - ), - - radish_genus AS ( - INSERT INTO plants (rank, binomial_name, family_id) - VALUES ('genus', 'Raphanus', (SELECT id FROM radish_family)) - RETURNING id - ), - - radish_species AS ( - INSERT INTO plants (rank, binomial_name, common_name, family_id, genus_id) - VALUES ( - 'species', - 'Raphanus raphanistrum', - '{"Radish"}', - (SELECT id from radish_family), - (SELECT id from radish_genus) - ) - RETURNING id - ), - --- insert marigold - marigold_family AS ( - INSERT INTO plants (rank, binomial_name) - VALUES ('family', 'Asteraceae') RETURNING id - ), - - marigold_subfamily AS ( - INSERT INTO plants (rank, binomial_name, family_id) - VALUES ('subfamily', 'Asteroideae', (SELECT id FROM marigold_family)) - RETURNING id - ), - - marigold_genus AS ( - INSERT INTO plants (rank, binomial_name, family_id, subfamily_id) - VALUES ( - 'genus', - 'Calendula', - (SELECT id from marigold_family), - (SELECT id from marigold_subfamily) - ) - RETURNING id - ), - - marigold_species AS ( - INSERT INTO plants (rank, binomial_name, common_name, family_id, subfamily_id, genus_id) - VALUES ( - 'species', - 'Calendula officinalis', - '{"Marigold"}', - (SELECT id from marigold_family), - (SELECT id from marigold_subfamily), - (SELECT id from marigold_genus) - ) - RETURNING id - ), - --- insert potato - potato_family AS ( - INSERT INTO plants (rank, binomial_name) - VALUES ('family', 'Solanaceae') RETURNING id - ), - - potato_subfamily AS ( - INSERT INTO plants (rank, binomial_name, family_id) - VALUES ('subfamily', 'Solanoideae', (SELECT id FROM potato_family)) - RETURNING id - ), - - potato_genus AS ( - INSERT INTO plants (rank, binomial_name, family_id, subfamily_id) - VALUES ( - 'genus', - 'Solanum', - (SELECT id from potato_family), - (SELECT id from potato_subfamily) - ) - RETURNING id - ), - - potato_species AS ( - INSERT INTO plants (rank, binomial_name, common_name, family_id, subfamily_id, genus_id) - VALUES ( - 'species', - 'Solanum tuberosum', - '{"Potato"}', - (SELECT id from potato_family), - (SELECT id from potato_subfamily), - (SELECT id from potato_genus) - ) - RETURNING id - ) - -INSERT INTO plant_relationships (kind, confidence, left_plant_id, right_plant_id) --- Radish <-> carrot -VALUES - ('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM carrot_species)), --- Radish <-> potato - ('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM potato_species)), --- Carrot >-< potato - ('antagonist', 1, (SELECT id FROM carrot_species), (SELECT id FROM potato_species)), --- Marigold <-> carrot - ('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM carrot_species)), --- Marigold <-> radish - ('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM radish_species)); - --- Let's look for companions that go well with carrot and radish --- --- First we get related plants which are not in the set we already have -WITH potential_companions AS ( - SELECT - r1.left_plant_id AS plant_id, - r1.kind - FROM plant_relationships AS r1 - WHERE r1.right_plant_id IN (4, 1) - AND r1.left_plant_id NOT IN (4, 1) - UNION - SELECT - r2.right_plant_id AS plant_id, - r2.kind - FROM plant_relationships AS r2 - WHERE r2.left_plant_id IN (4, 1) - AND r2.right_plant_id NOT IN (4, 1) -) - -SELECT * -FROM plants AS p - RIGHT JOIN potential_companions AS companions ON companions.plant_id IN (p.id, p.family_id, p.subfamily_id, p.genus_id, p.species_id) --- Then we need to remove companions are antagonists as well -WHERE kind = 'companion' - AND NOT EXISTS ( - SELECT 1 - FROM potential_companions AS antagonists - WHERE kind = 'antagonist' - AND companions.plant_id = antagonists.plant_id -); - --- --- Example: Hierarchical Information (Varieties) --- --- Let's say carrots have a height of 0.3m and a white flower colour. -UPDATE plants -SET - mature_size_height = '0.3', - flower_colour = 'white' -WHERE binomial_name = 'Daucus carota'; - --- Let's insert some varieteis. -WITH carrot_species AS ( - SELECT * FROM plants WHERE binomial_name = 'Daucus carota' -) -INSERT INTO plants ( - binomial_name, - rank, - family_id, - subfamily_id, - genus_id, - species_id, - mature_size_height, - flower_colour -) --- There is a variety of it which grows higher but has the same flower_colour. -VALUES ( - 'Daucus carota var. magna', - 'variety', - (SELECT family_id FROM carrot_species), - (SELECT subfamily_id FROM carrot_species), - (SELECT genus_id FROM carrot_species), - (SELECT id FROM carrot_species), - '0.5', - NULL -), --- And another variety which has the same height but yellow flowers. -( - 'Daucus carota var. solis', - 'variety', - (SELECT family_id FROM carrot_species), - (SELECT subfamily_id FROM carrot_species), - (SELECT genus_id FROM carrot_species), - (SELECT id FROM carrot_species), - NULL, - 'yellow' -); - --- Get all plants and varieties while inheriting information for higher levels. -SELECT - p.id, - p.binomial_name, - COALESCE(p.mature_size_height, s.mature_size_height, g.mature_size_height, sf.mature_size_height, f.mature_size_height), - COALESCE(p.flower_colour, s.flower_colour, g.flower_colour, sf.flower_colour, f.flower_colour) -FROM plants AS p - LEFT JOIN plants AS s ON p.species_id = s.id - LEFT JOIN plants AS g ON p.genus_id = s.id - LEFT JOIN plants AS sf ON p.subfamily_id = s.id - LEFT JOIN plants AS f ON p.family_id = s.id -WHERE p.rank IN ('species', 'variety'); diff --git a/doc/decisions/example_migrations/normalized-plants-and-ranks/example_queries.sql.md b/doc/decisions/example_migrations/normalized-plants-and-ranks/example_queries.sql.md new file mode 100644 index 000000000..cad454fdd --- /dev/null +++ b/doc/decisions/example_migrations/normalized-plants-and-ranks/example_queries.sql.md @@ -0,0 +1,254 @@ +-- +-- Example: Relationships +-- +-- For this example we use the following notation +-- companion "<->" +-- antagonist ">-<" +-- Consider the following relationships between plants: +-- Radish <-> carrot +-- Radish <-> potato +-- Carrot >-< potato +-- Marigold <-> carrot +-- Marigold <-> radish +-- +-- We want to plant carrots and radish and get suggestions for it. +-- When looking for companions we would expect the result just to be marigold. +-- Potato wouldn't be in the result since it's an antagonist to carrot. +-- +-- Let's insert the plants. +-- insert carrot +WITH carrot_family AS ( +INSERT INTO plants (rank, binomial_name) +VALUES ('family', 'Apiaceae') RETURNING id +), + +carrot_subfamily AS ( +INSERT INTO plants (rank, binomial_name, family_id) +VALUES ('subfamily', 'Apioideae', (SELECT id FROM carrot_family)) +RETURNING id +), + +carrot_genus AS ( +INSERT INTO plants (rank, binomial_name, family_id, subfamily_id) +VALUES ( +'genus', +-- TODO: rename to latin_name +'Daucus', +(SELECT id from carrot_family), +(SELECT id from carrot_subfamily) +) +RETURNING id +), + +carrot_species AS ( +INSERT INTO plants (rank, binomial_name, common_name, family_id, subfamily_id, genus_id) +VALUES ( +'species', +'Daucus carota', +'{"Carrot"}', +(SELECT id from carrot_family), +(SELECT id from carrot_subfamily), +(SELECT id from carrot_genus) +) +RETURNING id +), + +-- insert radish +radish_family AS ( +INSERT INTO plants (rank, binomial_name) +VALUES ('family', 'Brassicaceae') RETURNING id +), + +radish_genus AS ( +INSERT INTO plants (rank, binomial_name, family_id) +VALUES ('genus', 'Raphanus', (SELECT id FROM radish_family)) +RETURNING id +), + +radish_species AS ( +INSERT INTO plants (rank, binomial_name, common_name, family_id, genus_id) +VALUES ( +'species', +'Raphanus raphanistrum', +'{"Radish"}', +(SELECT id from radish_family), +(SELECT id from radish_genus) +) +RETURNING id +), + +-- insert marigold +marigold_family AS ( +INSERT INTO plants (rank, binomial_name) +VALUES ('family', 'Asteraceae') RETURNING id +), + +marigold_subfamily AS ( +INSERT INTO plants (rank, binomial_name, family_id) +VALUES ('subfamily', 'Asteroideae', (SELECT id FROM marigold_family)) +RETURNING id +), + +marigold_genus AS ( +INSERT INTO plants (rank, binomial_name, family_id, subfamily_id) +VALUES ( +'genus', +'Calendula', +(SELECT id from marigold_family), +(SELECT id from marigold_subfamily) +) +RETURNING id +), + +marigold_species AS ( +INSERT INTO plants (rank, binomial_name, common_name, family_id, subfamily_id, genus_id) +VALUES ( +'species', +'Calendula officinalis', +'{"Marigold"}', +(SELECT id from marigold_family), +(SELECT id from marigold_subfamily), +(SELECT id from marigold_genus) +) +RETURNING id +), + +-- insert potato +potato_family AS ( +INSERT INTO plants (rank, binomial_name) +VALUES ('family', 'Solanaceae') RETURNING id +), + +potato_subfamily AS ( +INSERT INTO plants (rank, binomial_name, family_id) +VALUES ('subfamily', 'Solanoideae', (SELECT id FROM potato_family)) +RETURNING id +), + +potato_genus AS ( +INSERT INTO plants (rank, binomial_name, family_id, subfamily_id) +VALUES ( +'genus', +'Solanum', +(SELECT id from potato_family), +(SELECT id from potato_subfamily) +) +RETURNING id +), + +potato_species AS ( +INSERT INTO plants (rank, binomial_name, common_name, family_id, subfamily_id, genus_id) +VALUES ( +'species', +'Solanum tuberosum', +'{"Potato"}', +(SELECT id from potato_family), +(SELECT id from potato_subfamily), +(SELECT id from potato_genus) +) +RETURNING id +) + +INSERT INTO plant_relationships (kind, confidence, left_plant_id, right_plant_id) +-- Radish <-> carrot +VALUES +('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM carrot_species)), +-- Radish <-> potato +('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM potato_species)), +-- Carrot >-< potato +('antagonist', 1, (SELECT id FROM carrot_species), (SELECT id FROM potato_species)), +-- Marigold <-> carrot +('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM carrot_species)), +-- Marigold <-> radish +('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM radish_species)); + +## -- Let's look for companions that go well with carrot and radish + +-- First we get related plants which are not in the set we already have +WITH potential_companions AS ( +SELECT +r1.left_plant_id AS plant_id, +r1.kind +FROM plant_relationships AS r1 +WHERE r1.right_plant_id IN (4, 1) +AND r1.left_plant_id NOT IN (4, 1) +UNION +SELECT +r2.right_plant_id AS plant_id, +r2.kind +FROM plant_relationships AS r2 +WHERE r2.left_plant_id IN (4, 1) +AND r2.right_plant_id NOT IN (4, 1) +) + +SELECT \* +FROM plants AS p +RIGHT JOIN potential_companions AS companions ON companions.plant_id IN (p.id, p.family_id, p.subfamily_id, p.genus_id, p.species_id) +-- Then we need to remove companions are antagonists as well +WHERE kind = 'companion' +AND NOT EXISTS ( +SELECT 1 +FROM potential_companions AS antagonists +WHERE kind = 'antagonist' +AND companions.plant_id = antagonists.plant_id +); + +-- +-- Example: Hierarchical Information (Varieties) +-- +-- Let's say carrots have a height of 0.3m and a white flower colour. +UPDATE plants +SET +mature_size_height = '0.3', +flower_colour = 'white' +WHERE binomial_name = 'Daucus carota'; + +-- Let's insert some varieteis. +WITH carrot_species AS ( +SELECT \* FROM plants WHERE binomial_name = 'Daucus carota' +) +INSERT INTO plants ( +binomial_name, +rank, +family_id, +subfamily_id, +genus_id, +species_id, +mature_size_height, +flower_colour +) +-- There is a variety of it which grows higher but has the same flower_colour. +VALUES ( +'Daucus carota var. magna', +'variety', +(SELECT family_id FROM carrot_species), +(SELECT subfamily_id FROM carrot_species), +(SELECT genus_id FROM carrot_species), +(SELECT id FROM carrot_species), +'0.5', +NULL +), +-- And another variety which has the same height but yellow flowers. +( +'Daucus carota var. solis', +'variety', +(SELECT family_id FROM carrot_species), +(SELECT subfamily_id FROM carrot_species), +(SELECT genus_id FROM carrot_species), +(SELECT id FROM carrot_species), +NULL, +'yellow' +); + +-- Get all plants and varieties while inheriting information for higher levels. +SELECT +p.id, +p.binomial_name, +COALESCE(p.mature_size_height, s.mature_size_height, g.mature_size_height, sf.mature_size_height, f.mature_size_height), +COALESCE(p.flower_colour, s.flower_colour, g.flower_colour, sf.flower_colour, f.flower_colour) +FROM plants AS p +LEFT JOIN plants AS s ON p.species_id = s.id +LEFT JOIN plants AS g ON p.genus_id = s.id +LEFT JOIN plants AS sf ON p.subfamily_id = s.id +LEFT JOIN plants AS f ON p.family_id = s.id +WHERE p.rank IN ('species', 'variety'); diff --git a/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/down.sql b/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/down.sql.md similarity index 100% rename from doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/down.sql rename to doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/down.sql.md diff --git a/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/up.sql b/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/up.sql deleted file mode 100644 index a74d9168b..000000000 --- a/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/up.sql +++ /dev/null @@ -1,52 +0,0 @@ --- Your SQL goes here -CREATE TABLE genus ( - id SERIAL PRIMARY KEY, - name VARCHAR NOT NULL, - created_at TIMESTAMP DEFAULT now() NOT NULL, - updated_at TIMESTAMP DEFAULT now() NOT NULL, - CONSTRAINT genus_name_key UNIQUE (name) -); -CREATE TABLE subfamily ( - id SERIAL PRIMARY KEY, - name VARCHAR NOT NULL, - created_at TIMESTAMP DEFAULT now() NOT NULL, - updated_at TIMESTAMP DEFAULT now() NOT NULL, - CONSTRAINT subfamily_name_key UNIQUE (name) -); -CREATE TABLE family ( - id SERIAL PRIMARY KEY, - name VARCHAR NOT NULL, - created_at TIMESTAMP DEFAULT now() NOT NULL, - updated_at TIMESTAMP DEFAULT now() NOT NULL, - CONSTRAINT family_name_key UNIQUE (name) -); -ALTER TABLE plants -ADD CONSTRAINT plants_genus_fkey FOREIGN KEY (genus) REFERENCES genus (name); -ALTER TABLE plants -ADD CONSTRAINT plants_subfamily_fkey FOREIGN KEY ( - subfamily -) REFERENCES subfamily (name); -ALTER TABLE plants -ADD CONSTRAINT plants_family_fkey FOREIGN KEY (family) REFERENCES family (name); -CREATE TYPE relation_type AS ENUM ('companion', 'antagonist', 'neutral'); -CREATE TYPE hierarchy_level_type AS ENUM ( - 'plant', 'genus', 'subfamily', 'family' -); -CREATE TABLE relations ( - id SERIAL PRIMARY KEY, - from_id INTEGER NOT NULL, - from_type HIERARCHY_LEVEL_TYPE NOT NULL, - to_id INTEGER NOT NULL, - to_type HIERARCHY_LEVEL_TYPE NOT NULL, - relation_type RELATION_TYPE NOT NULL, - relation_strength INTEGER NOT NULL, - created_at TIMESTAMP DEFAULT now() NOT NULL, - updated_at TIMESTAMP DEFAULT now() NOT NULL, - CHECK ( - relation_strength >= 0 - AND relation_strength <= 3 - ), - CONSTRAINT relations_from_id_from_type_to_id_to_type_key UNIQUE ( - from_id, from_type, to_id, to_type - ) -); diff --git a/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/up.sql.md b/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/up.sql.md new file mode 100644 index 000000000..4fccb6531 --- /dev/null +++ b/doc/decisions/example_migrations/one-table-per-taxonomy/2023-03-09-194135_plant_relations/up.sql.md @@ -0,0 +1,52 @@ +-- Your SQL goes here +CREATE TABLE genus ( +id SERIAL PRIMARY KEY, +name VARCHAR NOT NULL, +created_at TIMESTAMP DEFAULT now() NOT NULL, +updated_at TIMESTAMP DEFAULT now() NOT NULL, +CONSTRAINT genus_name_key UNIQUE (name) +); +CREATE TABLE subfamily ( +id SERIAL PRIMARY KEY, +name VARCHAR NOT NULL, +created_at TIMESTAMP DEFAULT now() NOT NULL, +updated_at TIMESTAMP DEFAULT now() NOT NULL, +CONSTRAINT subfamily_name_key UNIQUE (name) +); +CREATE TABLE family ( +id SERIAL PRIMARY KEY, +name VARCHAR NOT NULL, +created_at TIMESTAMP DEFAULT now() NOT NULL, +updated_at TIMESTAMP DEFAULT now() NOT NULL, +CONSTRAINT family_name_key UNIQUE (name) +); +ALTER TABLE plants +ADD CONSTRAINT plants_genus_fkey FOREIGN KEY (genus) REFERENCES genus (name); +ALTER TABLE plants +ADD CONSTRAINT plants_subfamily_fkey FOREIGN KEY ( +subfamily +) REFERENCES subfamily (name); +ALTER TABLE plants +ADD CONSTRAINT plants_family_fkey FOREIGN KEY (family) REFERENCES family (name); +CREATE TYPE relation_type AS ENUM ('companion', 'antagonist', 'neutral'); +CREATE TYPE hierarchy_level_type AS ENUM ( +'plant', 'genus', 'subfamily', 'family' +); +CREATE TABLE relations ( +id SERIAL PRIMARY KEY, +from_id INTEGER NOT NULL, +from_type HIERARCHY_LEVEL_TYPE NOT NULL, +to_id INTEGER NOT NULL, +to_type HIERARCHY_LEVEL_TYPE NOT NULL, +relation_type RELATION_TYPE NOT NULL, +relation_strength INTEGER NOT NULL, +created_at TIMESTAMP DEFAULT now() NOT NULL, +updated_at TIMESTAMP DEFAULT now() NOT NULL, +CHECK ( +relation_strength >= 0 +AND relation_strength <= 3 +), +CONSTRAINT relations_from_id_from_type_to_id_to_type_key UNIQUE ( +from_id, from_type, to_id, to_type +) +); diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/down.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/down.sql deleted file mode 100644 index 4ff01182c..000000000 --- a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/down.sql +++ /dev/null @@ -1,7 +0,0 @@ -ALTER TABLE plants - DROP COLUMN family_id, - DROP COLUMN subfamily_id, - DROP COLUMN genus_id, - DROP COLUMN species_id; -DROP TABLE taxons; -DROP TYPE taxonomic_rank; diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/down.sql.md b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/down.sql.md new file mode 100644 index 000000000..e92699936 --- /dev/null +++ b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/down.sql.md @@ -0,0 +1,7 @@ +ALTER TABLE plants +DROP COLUMN family_id, +DROP COLUMN subfamily_id, +DROP COLUMN genus_id, +DROP COLUMN species_id; +DROP TABLE taxons; +DROP TYPE taxonomic_rank; diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/up.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/up.sql deleted file mode 100644 index 0bb04497a..000000000 --- a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/up.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TYPE taxonomic_rank AS ENUM ('family', 'subfamily', 'genus', 'species'); -CREATE TABLE taxons ( - id SERIAL PRIMARY KEY NOT NULL, - rank TAXONOMIC_RANK NOT NULL, - name VARCHAR NOT NULL, - icon_url VARCHAR NULL, - parent_id INTEGER REFERENCES taxons (id) NULL -); - --- TODO: drop taxonomic names in plants (family, subfamily, genus, species) -ALTER TABLE plants - ADD COLUMN family_id INTEGER REFERENCES taxons (id) NOT NULL, - ADD COLUMN subfamily_id INTEGER REFERENCES taxons (id) NULL, - ADD COLUMN genus_id INTEGER REFERENCES taxons (id) NOT NULL, - ADD COLUMN species_id INTEGER REFERENCES taxons (id) NOT NULL; diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/up.sql.md b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/up.sql.md new file mode 100644 index 000000000..f371e383b --- /dev/null +++ b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220813_taxons/up.sql.md @@ -0,0 +1,15 @@ +CREATE TYPE taxonomic_rank AS ENUM ('family', 'subfamily', 'genus', 'species'); +CREATE TABLE taxons ( +id SERIAL PRIMARY KEY NOT NULL, +rank TAXONOMIC_RANK NOT NULL, +name VARCHAR NOT NULL, +icon_url VARCHAR NULL, +parent_id INTEGER REFERENCES taxons (id) NULL +); + +-- TODO: drop taxonomic names in plants (family, subfamily, genus, species) +ALTER TABLE plants +ADD COLUMN family_id INTEGER REFERENCES taxons (id) NOT NULL, +ADD COLUMN subfamily_id INTEGER REFERENCES taxons (id) NULL, +ADD COLUMN genus_id INTEGER REFERENCES taxons (id) NOT NULL, +ADD COLUMN species_id INTEGER REFERENCES taxons (id) NOT NULL; diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/down.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/down.sql.md similarity index 100% rename from doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/down.sql rename to doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/down.sql.md diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/up.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/up.sql deleted file mode 100644 index 9b0e6bdeb..000000000 --- a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/up.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TYPE relationship_kind AS ENUM ('companion', 'antagonist'); -CREATE TABLE taxon_relationships ( - id SERIAL PRIMARY KEY NOT NULL, - strength INTEGER CHECK (strength >= 0) NOT NULL, - kind relationship_kind NOT NULL, - left_taxon_id INTEGER REFERENCES taxons (id) NOT NULL, - right_taxon_id INTEGER REFERENCES taxons (id) NOT NULL -); diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/up.sql.md b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/up.sql.md new file mode 100644 index 000000000..330ffdc52 --- /dev/null +++ b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-04-220921_plant_relationships/up.sql.md @@ -0,0 +1,8 @@ +CREATE TYPE relationship_kind AS ENUM ('companion', 'antagonist'); +CREATE TABLE taxon_relationships ( +id SERIAL PRIMARY KEY NOT NULL, +strength INTEGER CHECK (strength >= 0) NOT NULL, +kind relationship_kind NOT NULL, +left_taxon_id INTEGER REFERENCES taxons (id) NOT NULL, +right_taxon_id INTEGER REFERENCES taxons (id) NOT NULL +); diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/down.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/down.sql.md similarity index 100% rename from doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/down.sql rename to doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/down.sql.md diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/up.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/up.sql.md similarity index 61% rename from doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/up.sql rename to doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/up.sql.md index bb48296e6..293fedcc3 100644 --- a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/up.sql +++ b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/2023-04-07-112305_varieties/up.sql.md @@ -4,8 +4,8 @@ -- It could easily be extended to other columns. -- CREATE TABLE varieties ( - id SERIAL PRIMARY KEY NOT NULL, - plant_id INTEGER REFERENCES plants (id), - mature_size_height VARCHAR, - flower_colour VARCHAR +id SERIAL PRIMARY KEY NOT NULL, +plant_id INTEGER REFERENCES plants (id), +mature_size_height VARCHAR, +flower_colour VARCHAR ); diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/example_queries.sql b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/example_queries.sql deleted file mode 100644 index 06d71e1a1..000000000 --- a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/example_queries.sql +++ /dev/null @@ -1,280 +0,0 @@ --- --- Example: Relationships --- --- For this example we use the following notation --- companion "<->" --- antagonist ">-<" --- Consider the following relationships between plants: --- Radish <-> carrot --- Radish <-> potato --- Carrot >-< potato --- Marigold <-> carrot --- Marigold <-> radish --- --- We want to plant carrots and radish and get suggestions for it. --- When looking for companions we would expect the result just to be marigold. --- Potato wouldn't be in the result since it's an antagonist to carrot. --- --- Let's insert the plants. --- insert carrot -WITH carrot_family AS ( - INSERT INTO taxons (rank, name, parent_id) - VALUES ('family', 'Apiaceae', NULL) RETURNING id -), - - carrot_subfamily AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'subfamily', 'Apioideae', carrot_family.id - FROM carrot_family RETURNING id - ), - - carrot_genus AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'genus', 'Daucus', carrot_subfamily.id - FROM carrot_subfamily RETURNING id - ), - - carrot_species AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'species', 'Daucus carota', carrot_genus.id - FROM carrot_genus RETURNING id - ), - - carrot AS ( - INSERT INTO plants (binomial_name, common_name, family_id, subfamily_id, genus_id, species_id) - SELECT - 'Daucus carota', - '{"Carrot"}', - (Select id from carrot_family), - (SELECT id FROM carrot_subfamily), - (SELECT id from carrot_genus), - (SELECT id from carrot_species) - RETURNING id - ), - --- insert radish - radish_family AS ( - INSERT INTO taxons (rank, name, parent_id) - VALUES ('family', 'Brassicaceae', NULL) RETURNING id - ), - - radish_genus AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'genus', 'Raphanus', radish_family.id - FROM radish_family RETURNING id - ), - - radish_species AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'species', 'Raphanus raphanistrum', radish_genus.id - FROM radish_genus RETURNING id - ), - - radish AS ( - INSERT INTO plants (binomial_name, common_name, family_id, genus_id, species_id) - SELECT - 'Raphanus raphanistrum', - '{"Radish"}', - (Select id from radish_family), - (SELECT id from radish_genus), - (SELECT id from radish_species) - RETURNING id - ), - --- insert marigold - marigold_family AS ( - INSERT INTO taxons (rank, name, parent_id) - VALUES ('family', 'Asteraceae', NULL) RETURNING id - ), - - marigold_subfamily AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'subfamily', 'Asteroideae', marigold_family.id - FROM marigold_family RETURNING id - ), - - marigold_genus AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'genus', 'Calendula', marigold_subfamily.id - FROM marigold_subfamily RETURNING id - ), - - marigold_species AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'species', 'Calendula officinalis', marigold_genus.id - FROM marigold_genus RETURNING id - ), - - marigold AS ( - INSERT INTO plants (binomial_name, common_name, family_id, subfamily_id, genus_id, species_id) - SELECT - 'Calendula officinalis', - '{"Marigold"}', - (Select id from marigold_family), - (SELECT id FROM marigold_subfamily), - (SELECT id from marigold_genus), - (SELECT id from marigold_species) - RETURNING id - ), - --- insert potato - potato_family AS ( - INSERT INTO taxons (rank, name, parent_id) - VALUES ('family', 'Solanaceae', NULL) RETURNING id - ), - - potato_subfamily AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'subfamily', 'Solanoideae', potato_family.id - FROM potato_family RETURNING id - ), - - potato_genus AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'genus', 'Solanum', potato_subfamily.id - FROM potato_subfamily RETURNING id - ), - - potato_species AS ( - INSERT INTO taxons (rank, name, parent_id) - SELECT 'species', 'Solanum tuberosum', potato_genus.id - FROM potato_genus RETURNING id - ), - - potato AS ( - INSERT INTO plants (binomial_name, common_name, family_id, subfamily_id, genus_id, species_id) - SELECT - 'Solanum tuberosum', - '{"Potato"}', - (Select id from potato_family), - (SELECT id FROM potato_subfamily), - (SELECT id from potato_genus), - (SELECT id from potato_species) - FROM potato_species RETURNING id - ) - -INSERT INTO taxon_relationships (kind, strength, left_taxon_id, right_taxon_id) --- Radish <-> carrot -VALUES - ('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM carrot_species)), --- Radish <-> potato - ('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM potato_species)), --- Carrot >-< potato - ('antagonist', 1, (SELECT id FROM carrot_species), (SELECT id FROM potato_species)), --- Marigold <-> carrot - ('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM carrot_species)), --- Marigold <-> radish - ('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM radish_species)); - --- Let's look for companions that go well with carrot and radish --- --- First we get related plants which are not in the set we already have -WITH potential_companions AS ( - SELECT - r1.left_taxon_id AS taxon_id, - r1.kind - FROM taxon_relationships AS r1 - WHERE r1.right_taxon_id IN (3, 7) - AND r1.left_taxon_id NOT IN (3, 7) - UNION - SELECT - r2.right_taxon_id AS taxon_id, - r2.kind - FROM taxon_relationships AS r2 - WHERE r2.left_taxon_id IN (3, 7) - AND r2.right_taxon_id NOT IN (5, 7) -) - -SELECT * -FROM potential_companions companions - LEFT JOIN taxons AS t ON companions.taxon_id = t.id - LEFT JOIN plants AS p ON t.id IN (p.family_id, p.subfamily_id, p.genus_id, p.species_id) --- Then we need to remove companions are antagonists as well -WHERE kind = 'companion' - AND NOT EXISTS ( - SELECT 1 - FROM potential_companions antagonists - WHERE kind = 'antagonist' - AND companions.taxon_id = antagonists.taxon_id - ); - --- --- Example: Hierarchical information --- --- Let's set an for the family of potato and one for the carrot species. -UPDATE taxons -SET icon_url = '/assets/img/solanaceae.png' -WHERE name = 'Solanaceae'; -UPDATE taxons -SET icon_url = '/assets/img/daucus_carota.png' -WHERE name = 'Daucus carota'; --- Get all plants with their hierarchy information -SELECT - plants.common_name, - species.name, - genus.name, - subfamily.name, - family.name, - COALESCE(species.icon_url, genus.icon_url, subfamily.icon_url, family.icon_url) AS icon_url -FROM plants - LEFT JOIN taxons AS species - ON (species.rank = 'species' AND species.id = plants.species_id) - LEFT JOIN taxons AS genus - ON (genus.rank = 'genus' AND genus.id = plants.genus_id) - LEFT JOIN taxons AS subfamily - ON (subfamily.rank = 'subfamily' AND subfamily.id = plants.subfamily_id) - LEFT JOIN taxons AS family - ON (family.rank = 'family' AND family.id = plants.family_id); - --- --- Example: Varieties --- --- Let's say carrots have a height of 0.3m and a white flower colour. -UPDATE plants -SET - mature_size_height = '0.3', - flower_colour = 'white' -WHERE binomial_name = 'Daucus carota'; - --- There is a variety of it which grows higher but has the same flower_colour. -INSERT INTO varieties (plant_id, mature_size_height) -VALUES ((SELECT id FROM plants WHERE binomial_name = 'Daucus carota'), '0.5'); - --- And another variety which has the same height but yellow flowers. -INSERT INTO varieties (plant_id, flower_colour) -VALUES ((SELECT id FROM plants WHERE binomial_name = 'Daucus carota'), 'yellow'); - --- Get all plants without varieties. -SELECT - id, - binomial_name, - mature_size_height, - flower_colour -FROM plants; - --- Get all varieties. -SELECT - v.id, - p.binomial_name, - COALESCE(v.mature_size_height, p.mature_size_height), - COALESCE(v.flower_colour, p.flower_colour) -FROM varieties AS v - LEFT JOIN plants p - ON v.plant_id = p.id; - --- Get all plants and varieties. -SELECT - p.id, - p.binomial_name, - p.mature_size_height, - p.flower_colour -FROM plants AS p -UNION -SELECT - v.id, - p.binomial_name, - COALESCE(v.mature_size_height, p.mature_size_height), - COALESCE(v.flower_colour, p.flower_colour) -FROM varieties AS v - LEFT JOIN plants p - ON v.plant_id = p.id; diff --git a/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/example_queries.sql.md b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/example_queries.sql.md new file mode 100644 index 000000000..c97ae95e1 --- /dev/null +++ b/doc/decisions/example_migrations/taxonomy-ranks-and-concrete-plants/example_queries.sql.md @@ -0,0 +1,280 @@ +-- +-- Example: Relationships +-- +-- For this example we use the following notation +-- companion "<->" +-- antagonist ">-<" +-- Consider the following relationships between plants: +-- Radish <-> carrot +-- Radish <-> potato +-- Carrot >-< potato +-- Marigold <-> carrot +-- Marigold <-> radish +-- +-- We want to plant carrots and radish and get suggestions for it. +-- When looking for companions we would expect the result just to be marigold. +-- Potato wouldn't be in the result since it's an antagonist to carrot. +-- +-- Let's insert the plants. +-- insert carrot +WITH carrot_family AS ( +INSERT INTO taxons (rank, name, parent_id) +VALUES ('family', 'Apiaceae', NULL) RETURNING id +), + +carrot_subfamily AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'subfamily', 'Apioideae', carrot_family.id +FROM carrot_family RETURNING id +), + +carrot_genus AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'genus', 'Daucus', carrot_subfamily.id +FROM carrot_subfamily RETURNING id +), + +carrot_species AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'species', 'Daucus carota', carrot_genus.id +FROM carrot_genus RETURNING id +), + +carrot AS ( +INSERT INTO plants (binomial_name, common_name, family_id, subfamily_id, genus_id, species_id) +SELECT +'Daucus carota', +'{"Carrot"}', +(Select id from carrot_family), +(SELECT id FROM carrot_subfamily), +(SELECT id from carrot_genus), +(SELECT id from carrot_species) +RETURNING id +), + +-- insert radish +radish_family AS ( +INSERT INTO taxons (rank, name, parent_id) +VALUES ('family', 'Brassicaceae', NULL) RETURNING id +), + +radish_genus AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'genus', 'Raphanus', radish_family.id +FROM radish_family RETURNING id +), + +radish_species AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'species', 'Raphanus raphanistrum', radish_genus.id +FROM radish_genus RETURNING id +), + +radish AS ( +INSERT INTO plants (binomial_name, common_name, family_id, genus_id, species_id) +SELECT +'Raphanus raphanistrum', +'{"Radish"}', +(Select id from radish_family), +(SELECT id from radish_genus), +(SELECT id from radish_species) +RETURNING id +), + +-- insert marigold +marigold_family AS ( +INSERT INTO taxons (rank, name, parent_id) +VALUES ('family', 'Asteraceae', NULL) RETURNING id +), + +marigold_subfamily AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'subfamily', 'Asteroideae', marigold_family.id +FROM marigold_family RETURNING id +), + +marigold_genus AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'genus', 'Calendula', marigold_subfamily.id +FROM marigold_subfamily RETURNING id +), + +marigold_species AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'species', 'Calendula officinalis', marigold_genus.id +FROM marigold_genus RETURNING id +), + +marigold AS ( +INSERT INTO plants (binomial_name, common_name, family_id, subfamily_id, genus_id, species_id) +SELECT +'Calendula officinalis', +'{"Marigold"}', +(Select id from marigold_family), +(SELECT id FROM marigold_subfamily), +(SELECT id from marigold_genus), +(SELECT id from marigold_species) +RETURNING id +), + +-- insert potato +potato_family AS ( +INSERT INTO taxons (rank, name, parent_id) +VALUES ('family', 'Solanaceae', NULL) RETURNING id +), + +potato_subfamily AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'subfamily', 'Solanoideae', potato_family.id +FROM potato_family RETURNING id +), + +potato_genus AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'genus', 'Solanum', potato_subfamily.id +FROM potato_subfamily RETURNING id +), + +potato_species AS ( +INSERT INTO taxons (rank, name, parent_id) +SELECT 'species', 'Solanum tuberosum', potato_genus.id +FROM potato_genus RETURNING id +), + +potato AS ( +INSERT INTO plants (binomial_name, common_name, family_id, subfamily_id, genus_id, species_id) +SELECT +'Solanum tuberosum', +'{"Potato"}', +(Select id from potato_family), +(SELECT id FROM potato_subfamily), +(SELECT id from potato_genus), +(SELECT id from potato_species) +FROM potato_species RETURNING id +) + +INSERT INTO taxon_relationships (kind, strength, left_taxon_id, right_taxon_id) +-- Radish <-> carrot +VALUES +('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM carrot_species)), +-- Radish <-> potato +('companion', 1, (SELECT id FROM radish_species), (SELECT id FROM potato_species)), +-- Carrot >-< potato +('antagonist', 1, (SELECT id FROM carrot_species), (SELECT id FROM potato_species)), +-- Marigold <-> carrot +('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM carrot_species)), +-- Marigold <-> radish +('companion', 1, (SELECT id FROM marigold_species), (SELECT id FROM radish_species)); + +## -- Let's look for companions that go well with carrot and radish + +-- First we get related plants which are not in the set we already have +WITH potential_companions AS ( +SELECT +r1.left_taxon_id AS taxon_id, +r1.kind +FROM taxon_relationships AS r1 +WHERE r1.right_taxon_id IN (3, 7) +AND r1.left_taxon_id NOT IN (3, 7) +UNION +SELECT +r2.right_taxon_id AS taxon_id, +r2.kind +FROM taxon_relationships AS r2 +WHERE r2.left_taxon_id IN (3, 7) +AND r2.right_taxon_id NOT IN (5, 7) +) + +SELECT \* +FROM potential_companions companions +LEFT JOIN taxons AS t ON companions.taxon_id = t.id +LEFT JOIN plants AS p ON t.id IN (p.family_id, p.subfamily_id, p.genus_id, p.species_id) +-- Then we need to remove companions are antagonists as well +WHERE kind = 'companion' +AND NOT EXISTS ( +SELECT 1 +FROM potential_companions antagonists +WHERE kind = 'antagonist' +AND companions.taxon_id = antagonists.taxon_id +); + +-- +-- Example: Hierarchical information +-- +-- Let's set an for the family of potato and one for the carrot species. +UPDATE taxons +SET icon_url = '/assets/img/solanaceae.png' +WHERE name = 'Solanaceae'; +UPDATE taxons +SET icon_url = '/assets/img/daucus_carota.png' +WHERE name = 'Daucus carota'; +-- Get all plants with their hierarchy information +SELECT +plants.common_name, +species.name, +genus.name, +subfamily.name, +family.name, +COALESCE(species.icon_url, genus.icon_url, subfamily.icon_url, family.icon_url) AS icon_url +FROM plants +LEFT JOIN taxons AS species +ON (species.rank = 'species' AND species.id = plants.species_id) +LEFT JOIN taxons AS genus +ON (genus.rank = 'genus' AND genus.id = plants.genus_id) +LEFT JOIN taxons AS subfamily +ON (subfamily.rank = 'subfamily' AND subfamily.id = plants.subfamily_id) +LEFT JOIN taxons AS family +ON (family.rank = 'family' AND family.id = plants.family_id); + +-- +-- Example: Varieties +-- +-- Let's say carrots have a height of 0.3m and a white flower colour. +UPDATE plants +SET +mature_size_height = '0.3', +flower_colour = 'white' +WHERE binomial_name = 'Daucus carota'; + +-- There is a variety of it which grows higher but has the same flower_colour. +INSERT INTO varieties (plant_id, mature_size_height) +VALUES ((SELECT id FROM plants WHERE binomial_name = 'Daucus carota'), '0.5'); + +-- And another variety which has the same height but yellow flowers. +INSERT INTO varieties (plant_id, flower_colour) +VALUES ((SELECT id FROM plants WHERE binomial_name = 'Daucus carota'), 'yellow'); + +-- Get all plants without varieties. +SELECT +id, +binomial_name, +mature_size_height, +flower_colour +FROM plants; + +-- Get all varieties. +SELECT +v.id, +p.binomial_name, +COALESCE(v.mature_size_height, p.mature_size_height), +COALESCE(v.flower_colour, p.flower_colour) +FROM varieties AS v +LEFT JOIN plants p +ON v.plant_id = p.id; + +-- Get all plants and varieties. +SELECT +p.id, +p.binomial_name, +p.mature_size_height, +p.flower_colour +FROM plants AS p +UNION +SELECT +v.id, +p.binomial_name, +COALESCE(v.mature_size_height, p.mature_size_height), +COALESCE(v.flower_colour, p.flower_colour) +FROM varieties AS v +LEFT JOIN plants p +ON v.plant_id = p.id; diff --git a/scraper/migrate_plant_detail_to_plant.sql b/scraper/migrate_plant_detail_to_plant.sql.md similarity index 66% rename from scraper/migrate_plant_detail_to_plant.sql rename to scraper/migrate_plant_detail_to_plant.sql.md index 75103aad2..15c573a4b 100644 --- a/scraper/migrate_plant_detail_to_plant.sql +++ b/scraper/migrate_plant_detail_to_plant.sql.md @@ -2,7 +2,11 @@ -- TODO: automatically perform these actions after the data is put plant detail. BEGIN TRANSACTION; ALTER TABLE plants ALTER COLUMN tags DROP NOT NULL; -INSERT INTO plants (species, plant, plant_type) SELECT binomial_name, common_name[1], id FROM plant_detail; -UPDATE plants SET tags=ARRAY[]::text[]; +INSERT INTO plants (species, plant, plant_type) SELECT +binomial_name, +common_name[1], +id +FROM plant_detail; +UPDATE plants SET tags = ARRAY[]::TEXT []; ALTER TABLE plants ALTER COLUMN tags SET NOT NULL; COMMIT;