Recursive PostgreSQL Query for Updating Column

Hello I'm trying to update database column recursively with SQL query.

I have 2 tables module and module_dependency.

First table module has columns (with example data):

id, name, state,
1, "website", "installed"
2, "purchase", "installed"
3, "crm", "installed"
4, "sale", "uninstalled"
5, "account", "installed"
6, "website_sale", "installed"
7, "purchase_bonus", "installed"
8, "website_blog", "installed"
9, "sale_discount", "installed"
10, "website_online", "installed"

Second table module_dependency has columns (with example data):

 id | dependency_name | module_id 
----+-----------------+-----------
  1 | website_sale    |         1
  2 | sale_bonus      |         4
  3 | website_blog    |         1
  4 | sale_discount   |         4
  5 | website_online  |         1
  6 | crm             |         10
  7 | account         |         3

I need to change state of website module to "to upgrade" with all of it's depended modules.

I can check current module's state:

SELECT * FROM module WHERE name = 'website' AND state = 'installed';

 id |  name   |   state   
----+---------+-----------
  1 | website | installed

To get all dependencies of website module I use query:

SELECT m.name, md.dependency_name , md.module_id
FROM module m JOIN module_dependency md ON (m.id = md.module_id)
WHERE m.name = 'website' AND m.state = 'installed';

  name   | dependency_name | module_id 
---------+-----------------+-----------
 website | website_sale    |         1
 website | website_blog    |         1
 website | website_online  |         1

That means website_sale, website_blog, and website_online is depended on module_id 1 which is website.

The main problem is that website_online is depended on crm and crm on account module.

SELECT m.name, md.dependency_name , md.module_id
FROM module m JOIN module_dependency md ON (m.id = md.module_id)
WHERE m.name = 'website_online' AND m.state = 'installed';

      name      | dependency_name | module_id 
----------------+-----------------+-----------
 website_online | crm             |        10

SELECT m.name, md.dependency_name , md.module_id
FROM module m JOIN module_dependency md ON (m.id = md.module_id)
WHERE m.name = 'crm' AND m.state = 'installed';

 name | dependency_name | module_id 
------+-----------------+-----------
 crm  | account         |         3

I need recursively change state of all website dependencies to "to upgrade". Updated rows should look like this:

id, name, state,
1, "website", "to upgrade"
3, "crm", "to upgrade"
5, "account", "to upgrade"
6, "website_sale", "to upgrade"
8, "website_blog", "to upgrade"
10, "website_online", "to upgrade"

You can create tables with test data:

CREATE TABLE module(id integer, name text, state text);
INSERT INTO module VALUES
(1, 'website', 'installed'),
(2, 'purchase', 'installed'),
(3, 'crm', 'installed'),
(4, 'sale', 'uninstalled'),
(5, 'account', 'installed'),
(6, 'website_sale', 'installed'),
(7, 'purchase_bonus', 'installed'),
(8, 'website_blog', 'installed'),
(9, 'sale_discount', 'installed'),
(10, 'website_online', 'installed');


CREATE TABLE module_dependency(id integer, dependency_name text, module_id integer);
INSERT INTO module_dependency VALUES
(1, 'website_sale', 1),
(2, 'sale_bonus', 4),
(3, 'website_blog', 1),
(4, 'sale_discount', 4),
(5, 'website_online', 1),
(6, 'crm', 10),
(7, 'account', 3);

I have tried to write recursive query, but unsuccessfully. Looks like infinite loop. If I could get all module ids of module table, I could simply update selected entries.

WITH RECURSIVE modules_to_upgrade AS
(
    SELECT id
    FROM module
    WHERE name = 'website'

        UNION ALL

    SELECT md.module_id
    FROM module_dependency md JOIN modules_to_upgrade mtu on mtu.id = md.module_id
)
select * from modules_to_upgrade;

To link the recursive part back to modules it seems you can't use the dependency id.

So it has to be on the names.

WITH RECURSIVE rcte_modules_to_upgrade AS
(
    SELECT 
      m.id as module_id
    , m.name as module_name
    , md.id as dependency_id
    , md.dependency_name
    , m.id as base_module_id
    , 1 as depth
    FROM module m
    JOIN module_dependency md 
      ON md.module_id = m.id
    WHERE m.name = 'website'

    UNION ALL

    SELECT 
      m.id
    , m.name
    , md.id
    , md.dependency_name
    , rcte.base_module_id
    , rcte.depth + 1
    FROM rcte_modules_to_upgrade rcte
    JOIN module m
      ON m.name = rcte.dependency_name
    LEFT JOIN module_dependency md 
      ON md.module_id = m.id
)
select * 
from rcte_modules_to_upgrade;
module_id | module_name    | dependency_id | dependency_name | base_module_id | depth
--------: | :------------- | ------------: | :-------------- | -------------: | ----:
        1 | website        |             1 | website_sale    |              1 |     1
        1 | website        |             3 | website_blog    |              1 |     1
        1 | website        |             5 | website_online  |              1 |     1
        6 | website_sale   |          null | null            |              1 |     2
        8 | website_blog   |          null | null            |              1 |     2
       10 | website_online |             6 | crm             |              1 |     2
        3 | crm            |             7 | account         |              1 |     3
        5 | account        |          null | null            |              1 |     4
WITH RECURSIVE rcte_modules_to_upgrade AS
(
    SELECT 
      m.id as module_id
    , md.dependency_name
    FROM module m
    JOIN module_dependency md 
      ON md.module_id = m.id
    WHERE m.name = 'website'

    UNION ALL

    SELECT 
      m.id
    , md.dependency_name
    FROM rcte_modules_to_upgrade rcte
    JOIN module m
      ON m.name = rcte.dependency_name
    LEFT JOIN module_dependency md 
      ON md.module_id = m.id
)
update module
set state = 'to upgrade'
where id in (select distinct module_id 
             from rcte_modules_to_upgrade);
6 rows affected
select * from module order by id;
id | name           | state      
-: | :------------- | :----------
 1 | website        | to upgrade 
 2 | purchase       | installed  
 3 | crm            | to upgrade 
 4 | sale           | uninstalled
 5 | account        | to upgrade 
 6 | website_sale   | to upgrade 
 7 | purchase_bonus | installed  
 8 | website_blog   | to upgrade 
 9 | sale_discount  | installed  
10 | website_online | to upgrade 

db<>fiddle here