f802b58ca3cf71f89f7b5ef6c8b0f57c95382c66
[cfb.git] / prod / net / jaekl / cfb / db / Schema.java
1 package net.jaekl.cfb.db;
2
3 // Copyright (C) 2015 Christian Jaekl
4
5 import java.sql.Connection;
6 import java.sql.DatabaseMetaData;
7 import java.sql.ResultSet;
8 import java.sql.SQLException;
9 import java.util.ArrayList;
10 import java.util.HashSet;
11 import java.util.Locale;
12
13 import net.jaekl.cfb.db.driver.DbDriver;
14
15 public class Schema {
16         String m_name;
17         DbDriver m_driver;
18         ArrayList<Table> m_tables;
19         ArrayList<Sequence> m_sequences;
20         
21         public Schema(String name, DbDriver driver) {
22                 m_name = name;
23                 m_driver = driver;
24                 m_tables = new ArrayList<Table>();
25                 m_sequences = new ArrayList<Sequence>();
26         }
27         
28         public boolean ensureDbInitialized(Connection con) throws SQLException {
29                 assert(null != con);
30                 
31                 if (allTablesPresent(con)) {
32                         return true;
33                 }
34                 
35                 if (!createAllTables(con)) {
36                         return false;
37                 }
38                 
39                 if (!createAllSequences(con)) { 
40                         return false;
41                 }
42                 
43                 return true;
44         }
45         
46         boolean allTablesPresent(Connection con) throws SQLException 
47         {
48                 assert(null != con);
49                 
50                 DatabaseMetaData dbmd = con.getMetaData();
51                 HashSet<String> extantTables = new HashSet<String>();
52                 
53                 try (ResultSet rs = dbmd.getTables(null, null, null, new String[]{"TABLE"})) {
54                         while (rs.next()) {
55                                 extantTables.add(rs.getString(3).toUpperCase(Locale.CANADA));
56                         }
57                 }
58                 
59                 for (Table table : m_tables) {
60                         String name = table.getName().toUpperCase(Locale.CANADA);
61                         if ( ! extantTables.contains(name) ) {
62                                 // One or more tables missing
63                                 return false;
64                         }
65                 }
66                 
67                 // We could be more thorough here, and check that the expected columns are in place.
68                 // Also, eventually, some sort of DB schema versioning will be needed.
69                 
70                 return true;            
71         }
72         
73         boolean createAllTables(Connection con) throws SQLException {
74                 for (Table table : m_tables) {
75                         if (!m_driver.createTable(con, table)) {
76                                 return false;
77                         }
78                 }
79                 return true;
80         }
81         
82         boolean createAllSequences(Connection con) throws SQLException {
83                 for (Sequence seq : m_sequences) {
84                         if (!m_driver.createSequence(con, seq)) {
85                                 return false;
86                         }
87                 }
88                 return true;
89         }
90         
91         void addTable(Table table) {
92                 m_tables.add(table);
93         }
94         
95         // Add a list of tables.
96         // Define each table in the list as follows:
97         // {
98         //   { table_name },
99         //   { column_name, type, width (-1 for default), null/not_null }
100         // }
101         void addTables(Object[][][] tables) 
102         {
103                 for (Object[][] table : tables) {
104                         addTable(Table.construct(table));
105                 }
106         }
107         
108         void addSequence(Sequence seq) {
109                 m_sequences.add(seq);
110         }
111 }