Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I populate Liquibase parameter values from an external properties file?

Is there any way that I can populate parameters in a Liquibase changelog file based on the contents of an external property file?

As in, I would like to be able to say:

<createTable tableName="${table.name}">
     <column name="id" type="int"/>
     <column name="${column1.name}" type="varchar(${column1.length})"/>
     <column name="${column2.name}" type="int"/>
</createTable>

And keep the value of table.name and the other parameters in an external file db.properties, and reference this file either from within the changelog, or from the Liquibase command line, or as an option of the Maven plugin that runs liquibase.

I can't seem to find any way to do this, is it possible?

like image 206
amoe Avatar asked Mar 22 '23 07:03

amoe


1 Answers

Do that at compile time: sounds like job for maven filters and/or profiles

NOTE: be carefull with liquibase and any "marker" replacements... liquibase stores CRC of applied changessets

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>test</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <build>
        <filters>
            <filter>src/main/filters/liquibase.properties</filter>
        </filters>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>liquibase.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

/src/main/filters/liquibase.properties

table.name=TABLE_NAME
column1.name=COLUMN1_NAME
column1.length=10
column2.name=COLUMN2_NAME

/src/main/resources/liquibase.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog logicalFilePath="liquibase.xml" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

    <changeSet author="me" id="changeSetId1">
        <comment>Test</comment>

        <createTable tableName="${table.name}">
            <column name="id" type="int" />
            <column name="${column1.name}" type="varchar(${column1.length})" />
            <column name="${column2.name}" type="int" />
        </createTable>
    </changeSet>

</databaseChangeLog>

EDIT: A typical invocation (using filtered resources) would look like this: mvn resources:resources liquibase:update or more preferably use profiles... mvn resources:resources liquibase:update -P<profile_name>

EDIT2: There is one big advantage of this way of defining columns. You could use this property's (e.g.: column1.length) value (e.g.: 10) for validation of every layer: Hibernate, DAO, WEB, faces, JavaScript. Just use this property at each place where you need to validate against it. Even in i18n/messages.properties if needed (e.g.: input1.validation=No more than ${column1.length} letters.).

The only complication is that if you need to change this value you need to provide proper liquibase update/rollback script. Sometimes it is possible to change value and set new liquibase checksum (safe operation like increase varchar length), but other times you need to create a safe update changescript using new property/value.

like image 100
Wooff Avatar answered Apr 24 '23 23:04

Wooff