001/*- 002 * #%L 003 * HAPI FHIR Server - SQL Migration 004 * %% 005 * Copyright (C) 2014 - 2025 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.migrate.dao; 021 022import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; 023import ca.uhn.fhir.jpa.migrate.entity.HapiMigrationEntity; 024import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeEnum; 025import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeToDriverTypeToSqlType; 026import com.healthmarketscience.sqlbuilder.AlterTableQuery; 027import com.healthmarketscience.sqlbuilder.BinaryCondition; 028import com.healthmarketscience.sqlbuilder.CreateIndexQuery; 029import com.healthmarketscience.sqlbuilder.CreateTableQuery; 030import com.healthmarketscience.sqlbuilder.DeleteQuery; 031import com.healthmarketscience.sqlbuilder.FunctionCall; 032import com.healthmarketscience.sqlbuilder.InsertQuery; 033import com.healthmarketscience.sqlbuilder.SelectQuery; 034import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn; 035import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema; 036import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec; 037import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041import java.sql.Types; 042 043public class MigrationQueryBuilder { 044 private static final Logger ourLog = LoggerFactory.getLogger(MigrationQueryBuilder.class); 045 046 private final DbSpec mySpec; 047 private final DbSchema mySchema; 048 private final DbTable myTable; 049 private final DbColumn myVersionCol; 050 private final DbColumn myInstalledRankCol; 051 private final DbColumn myDescriptionCol; 052 private final DbColumn myTypeCol; 053 private final DbColumn myScriptCol; 054 private final DbColumn myChecksumCol; 055 private final DbColumn myInstalledByCol; 056 private final DbColumn myInstalledOnCol; 057 private final DbColumn myExecutionTimeCol; 058 private final DbColumn mySuccessCol; 059 private final DbColumn myResultCol; 060 private final String myDeleteAll; 061 private final String myHighestKeyQuery; 062 private final DriverTypeEnum myDriverType; 063 private final String myMigrationTablename; 064 private final String myBooleanType; 065 066 public MigrationQueryBuilder(DriverTypeEnum theDriverType, String theMigrationTablename) { 067 myDriverType = theDriverType; 068 myMigrationTablename = theMigrationTablename; 069 070 mySpec = new DbSpec(); 071 mySchema = mySpec.addDefaultSchema(); 072 myTable = mySchema.addTable("\"" + theMigrationTablename + "\""); 073 074 myInstalledRankCol = myTable.addColumn("\"installed_rank\"", Types.INTEGER, null); 075 myInstalledRankCol.notNull(); 076 077 myVersionCol = myTable.addColumn("\"version\"", Types.VARCHAR, HapiMigrationEntity.VERSION_MAX_SIZE); 078 079 myDescriptionCol = 080 myTable.addColumn("\"description\"", Types.VARCHAR, HapiMigrationEntity.DESCRIPTION_MAX_SIZE); 081 myDescriptionCol.notNull(); 082 083 myTypeCol = myTable.addColumn("\"type\"", Types.VARCHAR, HapiMigrationEntity.TYPE_MAX_SIZE); 084 myTypeCol.notNull(); 085 086 myScriptCol = myTable.addColumn("\"script\"", Types.VARCHAR, HapiMigrationEntity.SCRIPT_MAX_SIZE); 087 myScriptCol.notNull(); 088 089 myChecksumCol = myTable.addColumn("\"checksum\"", Types.INTEGER, null); 090 091 myInstalledByCol = 092 myTable.addColumn("\"installed_by\"", Types.VARCHAR, HapiMigrationEntity.INSTALLED_BY_MAX_SIZE); 093 myInstalledByCol.notNull(); 094 095 myInstalledOnCol = myTable.addColumn("\"installed_on\"", Types.DATE, null); 096 myInstalledOnCol.notNull(); 097 098 myExecutionTimeCol = myTable.addColumn("\"execution_time\"", Types.INTEGER, null); 099 myExecutionTimeCol.notNull(); 100 101 myBooleanType = ColumnTypeToDriverTypeToSqlType.getColumnTypeToDriverTypeToSqlType() 102 .get(ColumnTypeEnum.BOOLEAN) 103 .get(theDriverType); 104 mySuccessCol = myTable.addColumn("\"success\"", myBooleanType, null); 105 mySuccessCol.notNull(); 106 107 myResultCol = myTable.addColumn("\"result\"", Types.VARCHAR, HapiMigrationEntity.RESULT_MAX_SIZE); 108 109 myDeleteAll = new DeleteQuery(myTable).toString(); 110 myHighestKeyQuery = buildHighestKeyQuery(); 111 } 112 113 public String deleteAll() { 114 return myDeleteAll; 115 } 116 117 public String getHighestKeyQuery() { 118 return myHighestKeyQuery; 119 } 120 121 private String buildHighestKeyQuery() { 122 return new SelectQuery() 123 .addCustomColumns(FunctionCall.max().addColumnParams(myInstalledRankCol)) 124 .validate() 125 .toString(); 126 } 127 128 public String insertPreparedStatement() { 129 return new InsertQuery(myTable) 130 .addPreparedColumns( 131 myInstalledRankCol, 132 myVersionCol, 133 myDescriptionCol, 134 myTypeCol, 135 myScriptCol, 136 myChecksumCol, 137 myInstalledByCol, 138 myInstalledOnCol, 139 myExecutionTimeCol, 140 mySuccessCol, 141 myResultCol) 142 .validate() 143 .toString(); 144 } 145 146 public String createTableStatement() { 147 return new CreateTableQuery(myTable, true).validate().toString(); 148 } 149 150 public String addResultColumnStatement() { 151 return new AlterTableQuery(myTable).setAddColumn(myResultCol).validate().toString(); 152 } 153 154 public String createIndexStatement() { 155 return new CreateIndexQuery(myTable, myMigrationTablename.toUpperCase() + "_PK_INDEX") 156 .setIndexType(CreateIndexQuery.IndexType.UNIQUE) 157 .addColumns(myInstalledRankCol) 158 .validate() 159 .toString(); 160 } 161 162 public String findAllQuery() { 163 return new SelectQuery() 164 .addFromTable(myTable) 165 .addCondition(BinaryCondition.notEqualTo(myInstalledRankCol, HapiMigrationEntity.CREATE_TABLE_PID)) 166 .addAllColumns() 167 .validate() 168 .toString(); 169 } 170 171 public String deleteLockRecordStatement(Integer theLockPid, String theLockDescription) { 172 return new DeleteQuery(myTable) 173 .addCondition(BinaryCondition.equalTo(myInstalledRankCol, theLockPid)) 174 .addCondition(BinaryCondition.equalTo(myDescriptionCol, theLockDescription)) 175 .validate() 176 .toString(); 177 } 178 179 public String findByPidAndNotDescriptionQuery(Integer theLockPid, String theLockDescription) { 180 return new SelectQuery() 181 .addFromTable(myTable) 182 .addCondition(BinaryCondition.equalTo(myInstalledRankCol, theLockPid)) 183 .addCondition(BinaryCondition.notEqualTo(myDescriptionCol, theLockDescription)) 184 .addAllColumns() 185 .validate() 186 .toString(); 187 } 188}