View Javadoc
1   /*
2    *    Copyright 2010-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.migration.operations;
17  
18  import java.io.PrintStream;
19  import java.sql.Connection;
20  import java.sql.SQLException;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Set;
26  
27  import org.apache.ibatis.migration.Change;
28  import org.apache.ibatis.migration.ConnectionProvider;
29  import org.apache.ibatis.migration.MigrationException;
30  import org.apache.ibatis.migration.MigrationLoader;
31  import org.apache.ibatis.migration.options.DatabaseOperationOption;
32  import org.apache.ibatis.migration.utils.Util;
33  
34  public final class StatusOperation extends DatabaseOperation {
35  
36    private int applied;
37    private int pending;
38    private int missing;
39  
40    private List<Change> changes;
41  
42    public StatusOperation operate(ConnectionProvider connectionProvider, MigrationLoader migrationsLoader,
43        DatabaseOperationOption option, PrintStream printStream) {
44      if (option == null) {
45        option = new DatabaseOperationOption();
46      }
47      println(printStream, "ID             Applied At          Description");
48      println(printStream, Util.horizontalLine("", 80));
49      changes = new ArrayList<>();
50      List<Change> migrations = migrationsLoader.getMigrations();
51      String skippedOrMissing = null;
52      try (Connection con = connectionProvider.getConnection()) {
53        if (changelogExists(con, option)) {
54          List<Change> changelog = getChangelog(con, option);
55          skippedOrMissing = checkSkippedOrMissing(changelog, migrations);
56  
57          Set<Change> changelogAndMigrations = new HashSet<>(changelog);
58          changelogAndMigrations.addAll(migrations);
59  
60          for (Change change : changelogAndMigrations) {
61            if (!migrations.contains(change)) {
62              change = new MissingScript(change);
63              missing++;
64            } else if (change.getAppliedTimestamp() != null) {
65              applied++;
66            } else {
67              pending++;
68            }
69            changes.add(change);
70          }
71        } else {
72          changes.addAll(migrations);
73          pending = migrations.size();
74        }
75      } catch (SQLException e) {
76        throw new MigrationException("Error getting connection. Cause: " + e, e);
77      }
78  
79      Collections.sort(changes);
80      for (Change change : changes) {
81        println(printStream, change.toString());
82      }
83      println(printStream);
84  
85      if (skippedOrMissing != null && !skippedOrMissing.isEmpty()) {
86        println(printStream, skippedOrMissing);
87      }
88  
89      return this;
90    }
91  
92    public int getAppliedCount() {
93      return applied;
94    }
95  
96    public int getPendingCount() {
97      return pending;
98    }
99  
100   public int getMissingCount() {
101     return missing;
102   }
103 
104   public List<Change> getCurrentStatus() {
105     return changes;
106   }
107 
108   class MissingScript extends Change {
109     public MissingScript(Change change) {
110       super(change);
111     }
112 
113     @Override
114     public String toString() {
115       return super.toString() + " <=== MISSING!";
116     }
117   }
118 }