001/*-
002 * #%L
003 * HAPI FHIR Server - SQL Migration
004 * %%
005 * Copyright (C) 2014 - 2023 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.BinaryCondition;
027import com.healthmarketscience.sqlbuilder.CreateIndexQuery;
028import com.healthmarketscience.sqlbuilder.CreateTableQuery;
029import com.healthmarketscience.sqlbuilder.DeleteQuery;
030import com.healthmarketscience.sqlbuilder.FunctionCall;
031import com.healthmarketscience.sqlbuilder.InsertQuery;
032import com.healthmarketscience.sqlbuilder.SelectQuery;
033import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
034import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema;
035import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec;
036import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040import java.sql.Types;
041
042public class MigrationQueryBuilder {
043        private static final Logger ourLog = LoggerFactory.getLogger(MigrationQueryBuilder.class);
044
045        private final DbSpec mySpec;
046        private final DbSchema mySchema;
047        private final DbTable myTable;
048        private final DbColumn myVersionCol;
049        private final DbColumn myInstalledRankCol;
050        private final DbColumn myDescriptionCol;
051        private final DbColumn myTypeCol;
052        private final DbColumn myScriptCol;
053        private final DbColumn myChecksumCol;
054        private final DbColumn myInstalledByCol;
055        private final DbColumn myInstalledOnCol;
056        private final DbColumn myExecutionTimeCol;
057        private final DbColumn mySuccessCol;
058        private final String myDeleteAll;
059        private final String myHighestKeyQuery;
060        private final DriverTypeEnum myDriverType;
061        private final String myMigrationTablename;
062        private final String myBooleanType;
063
064        public MigrationQueryBuilder(DriverTypeEnum theDriverType, String theMigrationTablename) {
065                myDriverType = theDriverType;
066                myMigrationTablename = theMigrationTablename;
067
068                mySpec = new DbSpec();
069                mySchema = mySpec.addDefaultSchema();
070                myTable = mySchema.addTable("\"" + theMigrationTablename + "\"");
071
072                myInstalledRankCol = myTable.addColumn("\"installed_rank\"", Types.INTEGER, null);
073                myInstalledRankCol.notNull();
074
075                myVersionCol = myTable.addColumn("\"version\"", Types.VARCHAR, HapiMigrationEntity.VERSION_MAX_SIZE);
076
077                myDescriptionCol =
078                                myTable.addColumn("\"description\"", Types.VARCHAR, HapiMigrationEntity.DESCRIPTION_MAX_SIZE);
079                myDescriptionCol.notNull();
080
081                myTypeCol = myTable.addColumn("\"type\"", Types.VARCHAR, HapiMigrationEntity.TYPE_MAX_SIZE);
082                myTypeCol.notNull();
083
084                myScriptCol = myTable.addColumn("\"script\"", Types.VARCHAR, HapiMigrationEntity.SCRIPT_MAX_SIZE);
085                myScriptCol.notNull();
086
087                myChecksumCol = myTable.addColumn("\"checksum\"", Types.INTEGER, null);
088
089                myInstalledByCol =
090                                myTable.addColumn("\"installed_by\"", Types.VARCHAR, HapiMigrationEntity.INSTALLED_BY_MAX_SIZE);
091                myInstalledByCol.notNull();
092
093                myInstalledOnCol = myTable.addColumn("\"installed_on\"", Types.DATE, null);
094                myInstalledOnCol.notNull();
095
096                myExecutionTimeCol = myTable.addColumn("\"execution_time\"", Types.INTEGER, null);
097                myExecutionTimeCol.notNull();
098
099                myBooleanType = ColumnTypeToDriverTypeToSqlType.getColumnTypeToDriverTypeToSqlType()
100                                .get(ColumnTypeEnum.BOOLEAN)
101                                .get(theDriverType);
102                mySuccessCol = myTable.addColumn("\"success\"", myBooleanType, null);
103                mySuccessCol.notNull();
104
105                myDeleteAll = new DeleteQuery(myTable).toString();
106                myHighestKeyQuery = buildHighestKeyQuery();
107        }
108
109        public String deleteAll() {
110                return myDeleteAll;
111        }
112
113        public String getHighestKeyQuery() {
114                return myHighestKeyQuery;
115        }
116
117        private String buildHighestKeyQuery() {
118                return new SelectQuery()
119                                .addCustomColumns(FunctionCall.max().addColumnParams(myInstalledRankCol))
120                                .validate()
121                                .toString();
122        }
123
124        public String insertPreparedStatement() {
125                return new InsertQuery(myTable)
126                                .addPreparedColumns(
127                                                myInstalledRankCol,
128                                                myVersionCol,
129                                                myDescriptionCol,
130                                                myTypeCol,
131                                                myScriptCol,
132                                                myChecksumCol,
133                                                myInstalledByCol,
134                                                myInstalledOnCol,
135                                                myExecutionTimeCol,
136                                                mySuccessCol)
137                                .validate()
138                                .toString();
139        }
140
141        public String createTableStatement() {
142                return new CreateTableQuery(myTable, true).validate().toString();
143        }
144
145        public String createIndexStatement() {
146                return new CreateIndexQuery(myTable, myMigrationTablename.toUpperCase() + "_PK_INDEX")
147                                .setIndexType(CreateIndexQuery.IndexType.UNIQUE)
148                                .addColumns(myInstalledRankCol)
149                                .validate()
150                                .toString();
151        }
152
153        public String findAllQuery() {
154                return new SelectQuery()
155                                .addFromTable(myTable)
156                                .addCondition(BinaryCondition.notEqualTo(myInstalledRankCol, HapiMigrationEntity.CREATE_TABLE_PID))
157                                .addAllColumns()
158                                .validate()
159                                .toString();
160        }
161
162        public String deleteLockRecordStatement(Integer theLockPid, String theLockDescription) {
163                return new DeleteQuery(myTable)
164                                .addCondition(BinaryCondition.equalTo(myInstalledRankCol, theLockPid))
165                                .addCondition(BinaryCondition.equalTo(myDescriptionCol, theLockDescription))
166                                .validate()
167                                .toString();
168        }
169
170        public String findByPidAndNotDescriptionQuery(Integer theLockPid, String theLockDescription) {
171                return new SelectQuery()
172                                .addFromTable(myTable)
173                                .addCondition(BinaryCondition.equalTo(myInstalledRankCol, theLockPid))
174                                .addCondition(BinaryCondition.notEqualTo(myDescriptionCol, theLockDescription))
175                                .addAllColumns()
176                                .validate()
177                                .toString();
178        }
179}