简体   繁体   English

PostgreSQL 数据库播种器在第二次运行后抛出“触发“trigger_test_genid”关系“test”已经存在”

[英]PostgreSQL db seeder throws 'trigger “trigger_test_genid” for relation “test” already exists' after running second time

I'm trying to implement a database seeder which will run every time the server starts.我正在尝试实现一个每次服务器启动时都会运行的数据库播种器。 The seeder basically installs an extension and then makes a function to generate random short ids (got the function from a blog) for table data.播种机基本上安装了一个扩展,然后创建一个函数来为表数据生成随机短 id(从博客中获得该函数)。 And then it creates a table and inserts something.然后它创建一个表并插入一些东西。

So when the server starts for the first time, it will check if the extension is installed and the table exists or not.所以当服务器第一次启动时,它会检查是否安装了扩展以及表是否存在。 If it does then it will do nothing.如果它这样做,那么它什么都不做。 If it doesn't then it will install the extension, create a table and insert some initial data.如果没有,那么它将安装扩展,创建一个表并插入一些初始数据。

Right now when it starts the first time, it does what I want it to do.现在,当它第一次启动时,它会做我想要它做的事情。 But when it runs the second time then it throws this error trigger "trigger_test_genid" for relation "test" already exists .但是当它第二次运行时,它会trigger "trigger_test_genid" for relation "test" already exists抛出这个错误trigger "trigger_test_genid" for relation "test" already exists

I've tried putting IF NOT EXISTS in CREATE TRIGGER but apparently create trigger does not take in IF NOT EXISTS and throws a different error.我试过将IF NOT EXISTS放在CREATE TRIGGER但显然 create trigger 不接受IF NOT EXISTS并引发不同的错误。

I have also tried doing an if statement that when an extension with the name of pgcrypto exists then return and not run the rest of the code.我也试过做一个 if 语句,当一个名为pgcrypto的扩展存在时,然后返回而不运行其余的代码。 But that won't work cause the user might have pgcrypto installed in their database for other purposes.但这不起作用,因为用户可能出于其他目的在他们的数据库中安装了 pgcrypto。

Here's the full code:这是完整的代码:


const pool = require('./db');
const createExt = `
                CREATE EXTENSION IF NOT EXISTS "pgcrypto";
            `; 

const createExtFunc = `
                CREATE OR REPLACE FUNCTION unique_short_id()
                RETURNS TRIGGER AS $$
                DECLARE
                  key TEXT;
                  qry TEXT;
                  found TEXT;
                BEGIN
                    qry := 'SELECT id FROM ' || quote_ident(TG_TABLE_NAME) || ' WHERE id=';

                    LOOP

                        key := encode(gen_random_bytes(6), 'base64');
                        key := replace(key, '/', '_'); 
                        key := replace(key, '+', '-'); 

                        EXECUTE qry || quote_literal(key) INTO found;

                        IF found IS NULL THEN
                            EXIT;
                        END IF;

                    END LOOP;
                    NEW.id = key;
                    RETURN NEW;
                END;
                $$ language 'plpgsql';
            `;

const createDemoTable = `
                    CREATE TABLE IF NOT EXISTS test (id TEXT PRIMARY KEY, name TEXT);
                    CREATE TRIGGER trigger_test_genid BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE unique_short_id();
                `; 

const demoInsert = `
                    INSERT INTO test (name) VALUES ('cheese'), ('ham'), ('turkey'), ('chicken');
                    SELECT * FROM test;
                `;


const dbSeeder = async () => {
    try{
        await pool.query(createExt);
        await pool.query(createExtFunc);
        await pool.query(createDemoTable);
        await pool.query(demoInsert);

        const results = await pool.query('SELECT * FROM test');

        console.log('Data seeded successfully!', results.rows);
    }catch(e) {
        console.log(e);
    }
};


module.exports = dbSeeder;

So how can I run the seeder for the first time only and do nothing on the rest of the time?那么我怎样才能只在第一次运行播种机而在其余时间不做任何事情呢? And also put a log as well that says Data exists. No need to seed.并且还放了一个日志,说明Data exists. No need to seed. Data exists. No need to seed.

PS.附注。 I'm a noob in PGSQL.我是 PGSQL 的菜鸟。 This is my first learning project based on PEN Stack.这是我第一个基于 PEN Stack 的学习项目。 So please give me beginner friendly solutions.所以请给我初学者友好的解决方案。 Thanks谢谢

I'm trying to implement a database seeder which will run every time the server starts.我正在尝试实现一个每次服务器启动时都会运行的数据库播种器。 The seeder basically installs an extension and then makes a function to generate random short ids (got the function from a blog) for table data.播种机基本上安装了一个扩展,然后创建一个函数来为表数据生成随机短 id(从博客中获得该函数)。 And then it creates a table and inserts something.然后它创建一个表并插入一些东西。

So when the server starts for the first time, it will check if the extension is installed and the table exists or not.所以当服务器第一次启动时,它会检查是否安装了扩展以及表是否存在。 If it does then it will do nothing.如果它这样做,那么它什么都不做。 If it doesn't then it will install the extension, create a table and insert some initial data.如果没有,那么它将安装扩展,创建一个表并插入一些初始数据。

Right now when it starts the first time, it does what I want it to do.现在,当它第一次启动时,它会做我想要它做的事情。 But when it runs the second time then it throws this error trigger "trigger_test_genid" for relation "test" already exists .但是当它第二次运行时,它会trigger "trigger_test_genid" for relation "test" already exists抛出这个错误trigger "trigger_test_genid" for relation "test" already exists

I've tried putting IF NOT EXISTS in CREATE TRIGGER but apparently create trigger does not take in IF NOT EXISTS and throws a different error.我试过将IF NOT EXISTS放在CREATE TRIGGER但显然 create trigger 不接受IF NOT EXISTS并引发不同的错误。

I have also tried doing an if statement that when an extension with the name of pgcrypto exists then return and not run the rest of the code.我也试过做一个 if 语句,当一个名为pgcrypto的扩展存在时,然后返回而不运行其余的代码。 But that won't work cause the user might have pgcrypto installed in their database for other purposes.但这不起作用,因为用户可能出于其他目的在他们的数据库中安装了 pgcrypto。

Here's the full code:这是完整的代码:


const pool = require('./db');
const createExt = `
                CREATE EXTENSION IF NOT EXISTS "pgcrypto";
            `; 

const createExtFunc = `
                CREATE OR REPLACE FUNCTION unique_short_id()
                RETURNS TRIGGER AS $$
                DECLARE
                  key TEXT;
                  qry TEXT;
                  found TEXT;
                BEGIN
                    qry := 'SELECT id FROM ' || quote_ident(TG_TABLE_NAME) || ' WHERE id=';

                    LOOP

                        key := encode(gen_random_bytes(6), 'base64');
                        key := replace(key, '/', '_'); 
                        key := replace(key, '+', '-'); 

                        EXECUTE qry || quote_literal(key) INTO found;

                        IF found IS NULL THEN
                            EXIT;
                        END IF;

                    END LOOP;
                    NEW.id = key;
                    RETURN NEW;
                END;
                $$ language 'plpgsql';
            `;

const createDemoTable = `
                    CREATE TABLE IF NOT EXISTS test (id TEXT PRIMARY KEY, name TEXT);
                    CREATE TRIGGER trigger_test_genid BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE unique_short_id();
                `; 

const demoInsert = `
                    INSERT INTO test (name) VALUES ('cheese'), ('ham'), ('turkey'), ('chicken');
                    SELECT * FROM test;
                `;


const dbSeeder = async () => {
    try{
        await pool.query(createExt);
        await pool.query(createExtFunc);
        await pool.query(createDemoTable);
        await pool.query(demoInsert);

        const results = await pool.query('SELECT * FROM test');

        console.log('Data seeded successfully!', results.rows);
    }catch(e) {
        console.log(e);
    }
};


module.exports = dbSeeder;

So how can I run the seeder for the first time only and do nothing on the rest of the time?那么我怎样才能只在第一次运行播种机而在其余时间不做任何事情呢? And also put a log as well that says Data exists. No need to seed.并且还放了一个日志,说明Data exists. No need to seed. Data exists. No need to seed.

PS.附注。 I'm a noob in PGSQL.我是 PGSQL 的菜鸟。 This is my first learning project based on PEN Stack.这是我第一个基于 PEN Stack 的学习项目。 So please give me beginner friendly solutions.所以请给我初学者友好的解决方案。 Thanks谢谢

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM