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 = myTable.addColumn("\"description\"", Types.VARCHAR, HapiMigrationEntity.DESCRIPTION_MAX_SIZE);
078                myDescriptionCol.notNull();
079
080                myTypeCol = myTable.addColumn("\"type\"", Types.VARCHAR, HapiMigrationEntity.TYPE_MAX_SIZE);
081                myTypeCol.notNull();
082
083                myScriptCol = myTable.addColumn("\"script\"", Types.VARCHAR, HapiMigrationEntity.SCRIPT_MAX_SIZE);
084                myScriptCol.notNull();
085
086                myChecksumCol = myTable.addColumn("\"checksum\"", Types.INTEGER, null);
087
088                myInstalledByCol = myTable.addColumn("\"installed_by\"", Types.VARCHAR, HapiMigrationEntity.INSTALLED_BY_MAX_SIZE);
089                myInstalledByCol.notNull();
090
091                myInstalledOnCol = myTable.addColumn("\"installed_on\"", Types.DATE, null);
092                myInstalledOnCol.notNull();
093
094                myExecutionTimeCol = myTable.addColumn("\"execution_time\"", Types.INTEGER, null);
095                myExecutionTimeCol.notNull();
096
097                myBooleanType = ColumnTypeToDriverTypeToSqlType.getColumnTypeToDriverTypeToSqlType().get(ColumnTypeEnum.BOOLEAN).get(theDriverType);
098                mySuccessCol = myTable.addColumn("\"success\"", myBooleanType, null);
099                mySuccessCol.notNull();
100
101                myDeleteAll = new DeleteQuery(myTable).toString();
102                myHighestKeyQuery = buildHighestKeyQuery();
103        }
104
105        public String deleteAll() {
106                return myDeleteAll;
107        }
108
109        public String getHighestKeyQuery() {
110                return myHighestKeyQuery;
111        }
112
113        private String buildHighestKeyQuery() {
114                return new SelectQuery()
115                        .addCustomColumns(FunctionCall.max().addColumnParams(myInstalledRankCol))
116                        .validate()
117                        .toString();
118        }
119
120        public String insertPreparedStatement() {
121                return new InsertQuery(myTable)
122                        .addPreparedColumns(myInstalledRankCol,
123                                myVersionCol,
124                                myDescriptionCol,
125                                myTypeCol,
126                                myScriptCol,
127                                myChecksumCol,
128                                myInstalledByCol,
129                                myInstalledOnCol,
130                                myExecutionTimeCol,
131                                mySuccessCol)
132                        .validate()
133                        .toString();
134        }
135
136        public String createTableStatement() {
137                return new CreateTableQuery(myTable, true)
138                        .validate()
139                        .toString();
140        }
141
142        public String createIndexStatement() {
143                return new CreateIndexQuery(myTable, myMigrationTablename.toUpperCase() + "_PK_INDEX")
144                        .setIndexType(CreateIndexQuery.IndexType.UNIQUE)
145                        .addColumns(myInstalledRankCol)
146                        .validate()
147                        .toString();
148        }
149
150        public String findAllQuery() {
151                return new SelectQuery()
152                        .addFromTable(myTable)
153                        .addCondition(BinaryCondition.notEqualTo(myInstalledRankCol, HapiMigrationEntity.CREATE_TABLE_PID))
154                        .addAllColumns()
155                        .validate()
156                        .toString();
157        }
158
159    public String deleteLockRecordStatement(Integer theLockPid, String theLockDescription) {
160                 return new DeleteQuery(myTable)
161                        .addCondition(BinaryCondition.equalTo(myInstalledRankCol, theLockPid))
162                                .addCondition(BinaryCondition.equalTo(myDescriptionCol, theLockDescription))
163                                .validate()
164                                .toString();
165    }
166
167        public String findByPidAndNotDescriptionQuery(Integer theLockPid, String theLockDescription) {
168                return new SelectQuery()
169                        .addFromTable(myTable)
170                        .addCondition(BinaryCondition.equalTo(myInstalledRankCol, theLockPid))
171                        .addCondition(BinaryCondition.notEqualTo(myDescriptionCol, theLockDescription))
172                        .addAllColumns()
173                        .validate()
174                        .toString();
175        }
176}