-
Notifications
You must be signed in to change notification settings - Fork 0
/
Migration.java
134 lines (117 loc) · 4.29 KB
/
Migration.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Actual migration script generator
* Requires the from/to models and the list of custom types
*/
class Migration {
List<Column> addedColumns = new ArrayList<>();
List<Column> removedColumns = new ArrayList<>();
Model model;
Map<String, String> types;
List<Column> commonFields = new ArrayList<>();
public Migration(Model from, Model to, Map<String, String> types) {
this.types = types;
model = to;
removedColumns.addAll(from.fields);
for (Column col : to.fields) {
Column oldCol = from.search(col);
if (oldCol == null) {
addedColumns.add(col);
} else if (oldCol.equals(col)) {
commonFields.add(col);
removedColumns.remove(oldCol);
} else {
throw new IllegalArgumentException("Changing a column type is not supported: " + col + " (was: " + oldCol + ")");
}
}
}
public void writeMigrationScript() throws IOException {
if (removedColumns.size() == 0 && addedColumns.size() == 0) {
System.out.println("No migration needed!");
return;
}
System.out.println("BEGIN TRANSACTION;");
System.out.println("");
if (removedColumns.size() > 0) {
System.out.println(computeCreateStatement(model, types)
.replaceAll(
"CREATE TABLE " + model.tableName,
"CREATE TABLE " + model.tableName + "_backup"
)
);
System.out.print("INSERT INTO " + model.tableName + "_backup (Id");
for (Column column : commonFields) {
System.out.print(", " + column.name);
}
System.out.print(") SELECT Id");
for (Column column : commonFields) {
System.out.print(", " + column.name);
}
System.out.println(" FROM " + model.tableName + ";");
System.out.println("DROP TABLE " + model.tableName + ";");
System.out.println("ALTER TABLE " + model.tableName + "_backup RENAME TO " + model.tableName + ";");
} else {
for (Column column : addedColumns) {
System.out.println(String.format("ALTER TABLE %s ADD COLUMN %s %s;",
model.tableName,
column.name,
getColumnType(column, types)
));
}
}
System.out.println("");
System.out.println("COMMIT;");
}
/**
* Convert a class information into an SQL statement
*/
private static String computeCreateStatement(Model model, Map<String, String> types) throws IOException {
String sql = "CREATE TABLE " + model.tableName + " (Id INTEGER PRIMARY KEY AUTOINCREMENT";
for (Column field : model.fields) {
sql += ", " + field.name + " " + getColumnType(field, types);
}
sql += ");";
return sql;
}
/**
* Convert native or custom type to SQLite type
*/
private static String getColumnType(Column field, Map<String, String> types) {
String type;
// Custom type? => get the DB type instead
if (types.containsKey(field.type)) {
type = types.get(field.type);
} else {
type = field.type;
}
// type is either a native type or a foreign key
switch (type) {
case "Double":
case "double":
case "Float":
case "float":
return "REAL";
case "Long":
case "long":
case "Integer":
case "int":
case "Boolean":
case "boolean":
case "Calendar":
return "INTEGER";
case "String":
return "TEXT";
default:
if (field.fk != null) {
return "INTEGER REFERENCES " + field.fk + "(Id) ON DELETE " + field.delete + " ON UPDATE " + field.update;
} else {
System.out.println("Unable to detect field type: " + field);
}
break;
}
return "";
}
}