Monday, May 21, 2018

Conditional Scala Play Evolutions

Leave a Comment

I would like to implement an evolution that applies only if a condition is met on a Scala Play framework application. The condition is that the application should be in a certain environment.

I have this evolution right now:

# payments SCHEMA  # --- !Ups  INSERT INTO table1 (id, provider_name, provider_country, provider_code, status, flag) VALUES (10, 'XXXXX', 'XX', 'XXXXX', '1', '0');  # --- !Downs DELETE FROM table2 WHERE id = 10; 

I want the evolution to run if this condition is met

if(config.env == 'dev'){    //execute evolution } 

How do I achieve this? Is this a function of the evolution or the application logic?

3 Answers

Answers 1

Ideally production code should not be polluted with DEV artefacts, so I believe this is a function of evolutions.

Say we have production evolutions under

conf/evolutions/default 

We could create corresponding DEV evolutions under

conf/evolutions/dev 

Then we could load the appropriate DB on the basis of an env flag:

class SomeRepository @Inject()(dbapi: DBApi, config: Configuration)(implicit ec: DatabaseExecutionContext) {    private val db =     if(config.env == "dev"){       dbapi.database("dev")     } else {       dbapi.database("default")     }    def findById(id: Long): Future[Option[SomeModel]] = Future {     db.withConnection { implicit connection =>       SQL"select * from ...     }   }(ec) ... } 

Answers 2

One approach might be to use a stored procedure in conjunction with a db-based app 'setting'. Assume your app had an appSetting table for storing app settings.

create table appSetting (   name varchar(63) not null primary key,    value varchar(255) ) ; -- insert into appSetting values ('environment','dev'); 

Then, something along the following lines would create a tmpLog table (or insert a value into table1) only if appSetting has a value of 'dev' for setting 'environment' at the time of running the evolution:

# --- !Ups create procedure doEvolution31()   begin     declare environment varchar(31);;     select value       into environment       from appSetting     where name='environment'     ;;     if (environment='dev') then       create table tmpLog (id int not null primary key, text varchar(255));;       -- or INSERT INTO table1 (id, provider_name, provider_country, provider_code, status, flag) VALUES (10, 'XXXXX', 'XX', 'XXXXX', '1', '0');     end if;;   end ; call doEvolution31();  # --- !Downs drop procedure doEvolution31; drop table if exists tmpLog; -- or delete from table2 where id=10; 

You don't mention which db you are using. The above is MYSQL syntax. There might be a way to get a config value into the stored proc, perhaps via some sbt magic, but I think we would use the above if we had such a requirement. (BTW The double semicolons are for escaping out a single semicolon so that individual statements of the procedures are not executed when the procedure is being created.)

Answers 3

Why do you need it at all? Don't you use separate db for different environments as it's being told at documentation? If you do - then you probably have different db configurations, probably at different files. That, probably, looks something like that:

# application.conf db.default {     driver=com.mysql.jdbc.Driver     url="jdbc:mysql://localhost/playdb"     username=playdbuser     password="a strong password" } # dev.conf db.dev {     driver=com.mysql.jdbc.Driver     url="jdbc:mysql://localhost/playdb"     username=playdbuser     password="a strong password" } # staging.conf db.staging {     driver=com.mysql.jdbc.Driver     url="jdbc:mysql://localhost/playdb"     username=playdbuser     password="a strong password" } # prod.conf db.prod {     driver=com.mysql.jdbc.Driver     url="jdbc:mysql://localhost/playdb"     username=playdbuser     password="a strong password" } 

Actually nothing stops you to make it the same db but don't - just use proper db per environment. Assuming you are using jdbc connector and PlayEvolutions plugin - just put your evolution to right directory and you'll achieve what you want. The other question is actually: "How to use proper db per environment?" And the answer is strongly depend on your choice of DI.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment