package joist.codegen.passes; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import joist.codegen.Codegen; import joist.codegen.dtos.Entity; import joist.jdbc.Jdbc; import joist.util.Interpolate; import joist.util.StringBuilderr; import joist.util.Wrap; public class GenerateFlushFunction implements Pass<Codegen> { private static final Logger log = LoggerFactory.getLogger(GenerateFlushFunction.class); private DataSource ds; public void pass(Codegen codegen) { log.info("Creating flush_test_database stored procedure"); this.ds = codegen.getConfig().dbAppSaSettings.getDataSource(); if (codegen.getConfig().db.isPg()) { this.generatePg(codegen); } else if (codegen.getConfig().db.isMySQL()) { this.generateMySQL(codegen); } else { throw new IllegalStateException("Unhandled db " + codegen.getConfig().db); } } private void generatePg(Codegen codegen) { StringBuilderr sql = new StringBuilderr(); sql.line("CREATE OR REPLACE FUNCTION flush_test_database() RETURNS integer AS"); sql.line("$BODY$"); sql.line("BEGIN"); sql.line("SET CONSTRAINTS ALL DEFERRED;"); for (Entity entity : codegen.getSchema().getEntities().values()) { if (entity.isRoot() && !entity.isStableTable()) { sql.line("ALTER SEQUENCE {} RESTART WITH 1 INCREMENT BY 1;", Wrap.quotes(entity.getTableName() + "_id_seq")); } } for (Entity entity : codegen.getSchema().getEntities().values()) { if (entity.isRoot() && !entity.isStableTable()) { sql.line("DELETE FROM {};", Wrap.quotes(entity.getTableName())); } } sql.line("RETURN 0;"); sql.line("END;"); sql.line("$BODY$"); sql.line(" LANGUAGE 'plpgsql' VOLATILE"); sql.line(" COST 100;"); sql.line("ALTER FUNCTION flush_test_database() SECURITY DEFINER;"); Jdbc.update(this.ds, sql.toString()); } private void generateMySQL(Codegen codegen) { StringBuilderr sql = new StringBuilderr(); sql.line("CREATE PROCEDURE flush_test_database()"); sql.line("BEGIN"); sql.line("SET FOREIGN_KEY_CHECKS=0;"); for (Entity entity : codegen.getSchema().getEntities().values()) { // mysql 5.6's TRUNCATE causes significant slow downs, so only conditionally // issue the truncate. This changed a single method in feature test from // take 3+ seconds to 0.1 seconds. See: https://bugs.mysql.com/bug.php?id=68184 if (!entity.isCodeEntity() && !entity.isStableTable() && entity.isRoot()) { sql.line( "SET @c = (SELECT `AUTO_INCREMENT` FROM information_schema.tables WHERE table_schema = '{}' AND table_name = '{}');", codegen.getConfig().dbAppUserSettings.schemaName, entity.getTableName()); sql.line("IF @c > 1 THEN "); for (Entity e : entity.getAllBaseAndSubEntities()) { sql.line("TRUNCATE TABLE {};", e.getTableName()); } sql.line("END IF;"); } } sql.line("SET FOREIGN_KEY_CHECKS=1;"); sql.line("SELECT 1;"); sql.line("END"); Jdbc.update(this.ds, "DROP PROCEDURE IF EXISTS flush_test_database;"); Jdbc.update(this.ds, sql.toString()); Jdbc.update(this.ds, Interpolate.string("GRANT ALL ON PROCEDURE flush_test_database TO {}@'%'", codegen.getConfig().dbAppUserSettings.user)); } }