]> gitweb.ps.run Git - l21s-case-study/blob - src/DbMigration.java
update
[l21s-case-study] / src / DbMigration.java
1 import java.io.*;
2 import java.nio.file.*;
3 import java.sql.*;
4 import java.util.*;
5
6 class DbMigration {
7     // constants {{{
8     static final boolean CONFIG_PRINT_DB = true;
9     static final String CSV_SEPARATOR = ",";
10     static final String DB_URL = "jdbc:postgresql:migration";
11     static final int    DB_BATCH_SIZE = 10;
12     static final String SQL_GET_USERS = "SELECT * FROM users;";
13     static final String SQL_UPSERT_USER =
14             """
15             INSERT INTO users VALUES (?, ?, ?, ?, ?)
16             ON CONFLICT (USER_ID)
17             DO UPDATE SET
18                 MAIL = EXCLUDED.MAIL,
19                 CAN_READ = EXCLUDED.CAN_READ,
20                 CAN_WRITE = EXCLUDED.CAN_WRITE,
21                 CAN_DELETE = EXCLUDED.CAN_DELETE
22             ;
23             """;
24
25     // }}}
26
27     // user {{{
28     public record Role(boolean read, boolean write, boolean delete) {
29         static final Role Default = new Role(false, false, false);
30     }
31
32     public record User(int id, String mail, Role role) {
33         public String toString() {
34             return this.id + " " + this.mail + " " + this.role;
35         }
36     }
37
38     // }}}
39
40     // csv {{{
41     public static ArrayList<String[]> LoadCSV(String filename) throws IOException {
42         var path = Paths.get(filename);
43         var list = Files.lines(path)
44                 .skip(1)
45                 .map(line -> line.split(CSV_SEPARATOR))
46                 .toList();
47         return new ArrayList<String[]>(list);
48     }
49
50     // }}}
51
52     // db {{{
53     public static void insertUser(PreparedStatement stmt, User user) throws SQLException {
54         stmt.setInt(1, user.id);
55         stmt.setString(2, user.mail);
56         stmt.setBoolean(3, user.role.read);
57         stmt.setBoolean(4, user.role.write);
58         stmt.setBoolean(5, user.role.delete);
59
60         // batching
61         stmt.addBatch();
62     }
63
64     static User[] getUsers(Connection conn) throws SQLException {
65         var users = new ArrayList<User>();
66
67         try (var st = conn.createStatement();
68              var rs = st.executeQuery(SQL_GET_USERS); ) {
69             while (rs.next()) {
70                 var userId = rs.getInt(1);
71                 var userMail = rs.getString(2);
72                 var userRole = new Role(rs.getBoolean(3), rs.getBoolean(4), rs.getBoolean(5));
73                 users.add(new User(userId, userMail, userRole));
74             }
75         }
76
77         return users.toArray(User[]::new);
78     }
79
80     // }}}
81
82     public static void main(String[] args) {
83         // filenames from command line args {{{
84         if (args.length != 2) {
85             System.out.printf("Usage: java src/DbMigrations.java <users.csv> <roles.csv>\n");
86             return;
87         }
88         String filenameUsers = args[0];
89         String filenameRoles = args[1];
90         // }}}
91
92         // read csvs {{{
93         ArrayList<String[]> csvUsers;
94         ArrayList<String[]> csvRoles;
95         try {
96             csvUsers = LoadCSV(filenameUsers);
97             csvRoles = LoadCSV(filenameRoles);
98         } catch (IOException e) {
99             System.out.printf("Expection occured while trying to load CSV: %s\n", e);
100             return;
101         }
102         // }}}
103         
104         // Sparkassen Nutzer aussortieren {{{
105         csvUsers.removeIf(row -> row[1].endsWith("@sparkasse.de"));
106         // }}}
107
108         // process roles {{{
109         // - read roles.csv line by line
110         // - get user_id and role from each line
111         // - make sure user_id is in the HashMap
112         // - if not create default value with no roles
113         // - update the role specified in that line
114         var roles = new HashMap<Integer, Role>();
115         for (var row : csvRoles) {
116             // get id and single role
117             var userId = Integer.parseInt(row[0], 10);
118             var roleStr = row[1];
119
120             // make sure userId is present
121             roles.putIfAbsent(userId, Role.Default);
122
123             // update value by setting one role to true and copying the rest
124             roles.computeIfPresent(
125                     userId,
126                     (id, role) -> {
127                         if (roleStr.equals("read")) return new Role(true, role.write, role.delete);
128                         if (roleStr.equals("write")) return new Role(role.read, true, role.delete);
129                         if (roleStr.equals("delete")) return new Role(role.read, role.write, true);
130                         return role;
131                     });
132         }
133         // }}}
134
135         // OPTIONAL: open db connection for reading {{{
136         if (CONFIG_PRINT_DB) {
137             try (var conn = DriverManager.getConnection(DB_URL)) {
138
139                 var users = getUsers(conn);
140                 System.out.println("Before update:");
141                 for (var user : users) {
142                     System.out.println(user);
143                 }
144
145             } catch (SQLException e) {
146                 System.out.printf("Expection occured while accessing database: %s\n", e);
147                 return;
148             }
149         }
150         // }}}
151
152         // open db connection for updating {{{
153         try (var conn = DriverManager.getConnection(DB_URL);
154              var stmt = conn.prepareStatement(SQL_UPSERT_USER); ) {
155
156             // batching
157             int batchIndex = 0;
158             conn.setAutoCommit(false);
159
160             // update db from csv
161             for (var row : csvUsers) {
162                 var userId = Integer.parseInt(row[0], 10);
163                 var userMail = row[1];
164                 var userRoles = roles.get(userId);
165
166                 User user = new User(userId, userMail, userRoles);
167                 insertUser(stmt, user);
168
169                 // batching
170                 batchIndex += 1;
171                 if (batchIndex > DB_BATCH_SIZE) {
172                     stmt.executeBatch();
173                     batchIndex = 0;
174                 }
175             }
176
177             // commit all outstanding changes
178             stmt.executeBatch();
179             conn.commit();
180         } catch (SQLException e) {
181             System.out.printf("Expection occured while accessing database: %s\n", e);
182             return;
183         }
184         // }}}
185
186         System.out.println("Updated successfully");
187     }
188 }