Skip to content

Commit

Permalink
Update constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
cjburkey01 committed Jun 14, 2024
1 parent e0cec19 commit e916c13
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ CREATE TABLE IF NOT EXISTS chunk_data (
owner_uuid TEXT NOT NULL,
default_local_permissions INTEGER,
FOREIGN KEY(owner_uuid) REFERENCES player_data(player_uuid)
FOREIGN KEY(owner_uuid)
REFERENCES player_data(player_uuid)
ON DELETE CASCADE
) STRICT
""");

Expand All @@ -57,11 +59,35 @@ CREATE TABLE IF NOT EXISTS chunk_permissions (
other_player_uuid TEXT NOT NULL,
permission_bits INTEGER NOT NULL,
PRIMARY KEY(chunk_id, other_player_uuid)
FOREIGN KEY(chunk_id) REFERENCES chunk_data(chunk_id),
FOREIGN KEY(other_player_uuid) REFERENCES player_data(player_uuid)
PRIMARY KEY(chunk_id, other_player_uuid),
FOREIGN KEY(chunk_id)
REFERENCES chunk_data(chunk_id)
ON DELETE CASCADE,
FOREIGN KEY(other_player_uuid)
REFERENCES player_data(player_uuid)
ON DELETE CASCADE
) STRICT
""");

// Global data storage in case we need it later.
// For now, stores an integer representing which version of the table schema we currently use.
// This is in case we need to perform some change that can't be checked easily, such as foreign key constraints.
if (!tableExists("claimchunk_global_info")) {
Q2Sql.executeUpdate(
"""
CREATE TABLE claimchunk_global_info (
key TEXT PRIMARY KEY NOT NULL,
value TEXT NOT NULL
) STRICT
""");
Q2Sql.executeUpdate(
"""
INSERT INTO claimchunk_global_info
(key, value)
VALUES ("claimchunk_table_schema", "1")
""");
}
}

// Whenever a column is added or moved or transformed or whatever, add a
Expand Down Expand Up @@ -97,13 +123,59 @@ public static boolean columnExists(String tableName, String columnName) {
try (PreparedStatement statement =
connection.prepareStatement(
"""
SELECT COUNT(*) FROM pragma_table_info(?) WHERE name=?
SELECT COUNT(*)
FROM pragma_table_info(?)
WHERE name=?
""")) {
statement.setString(1, tableName);
statement.setString(2, columnName);
ResultSet resultSet = statement.executeQuery();
int count = resultSet.next() ? resultSet.getInt(1) : 0;
return count > 0;
return resultSet.next() && resultSet.getInt(1) > 0;
}
});
}

public static boolean tableExists(String tableName) {
return SqlClosure.sqlExecute(
connection -> {
try (PreparedStatement statement =
connection.prepareStatement(
"""
SELECT COUNT(*)
FROM sqlite_master
WHERE type='table' AND name=?
""")) {
statement.setString(1, tableName);
ResultSet resultSet = statement.executeQuery();
return resultSet.next() && resultSet.getInt(1) > 0;
}
});
}

/**
* @return The reported schema version in the ClaimChunk database, or {@code -1} if the value
* doesn't exist or isn't an integer.
*/
public static int getSchemaVersion() {
return SqlClosure.sqlExecute(
connection -> {
try (ResultSet resultSet =
Q2Sql.executeQuery(
connection,
"""
SELECT value
FROM claimchunk_global_info
WHERE key="claimchunk_table_schema"
""")) {
if (resultSet.next()) {
String strResult = resultSet.getString(1);
try {
// Parse int will fail on null, so don't gotta null check
return Integer.parseInt(strResult);
} catch (Exception ignored) {
}
}
return -1;
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.sqlite.SQLiteConfig;
import org.sqlite.SQLiteDataSource;

import java.io.Closeable;
Expand All @@ -22,6 +23,8 @@

public record SqLiteWrapper(File dbFile, boolean usesTransactionManager) implements Closeable {

// TODO: ERROR HANDLING! WE DON'T DO SHIT RN!

private static final String SELECT_CHUNK_ID_SQL =
"""
(
Expand All @@ -47,7 +50,9 @@ public SqLiteWrapper(@NotNull File dbFile, boolean usesTransactionManager) {

// Make sure the SQLite driver exists and get it in the classpath
// for the DriverManager to search.
SQLiteDataSource dataSource = new SQLiteDataSource();
SQLiteConfig config = new SQLiteConfig();
config.enforceForeignKeys(true);
SQLiteDataSource dataSource = new SQLiteDataSource(config);
dataSource.setUrl("jdbc:sqlite:" + dbFile);
if (usesTransactionManager) q2o.initializeTxSimple(dataSource);
else q2o.initializeTxNone(dataSource);
Expand Down
38 changes: 31 additions & 7 deletions src/test/java/com/cjburkey/claimchunk/TestSQLPlease.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,23 @@ class TestSQLPlease {
void ensureColumnExistsMethodWorks() {
// Must create the wrapper to initialize (and deinitialize) connection
try (TestQlWrap ignoredWrapper = new TestQlWrap()) {
assert SqLiteTableMigrationManager.tableExists("player_data");

// Make sure that instantiating SqLiteWrapper created the tables
assert SqLiteTableMigrationManager.columnExists("player_data", "player_uuid");
assert SqLiteTableMigrationManager.columnExists("chunk_data", "owner_uuid");
assert SqLiteTableMigrationManager.columnExists("chunk_permissions", "permission_bits");
assert SqLiteTableMigrationManager.columnExists(
"chunk_data", "default_local_permissions");
assert !SqLiteTableMigrationManager.columnExists("chunk_hell", "permission_bits");
assert !SqLiteTableMigrationManager.columnExists("player_data", "fake_col");
}
}

@Test
void ensureSchemaVersionIsValid() {
try (TestQlWrap ignoredWrapper = new TestQlWrap()) {
// -1 value represents an error, the initial version of the schema starts at 1 (I decided), so 0 is invalid and we shouldn't get it.
assert SqLiteTableMigrationManager.getSchemaVersion() > 0;
}
}

@Test
void ensureMigrationWorks() throws IOException {
File dbFile = randomDbFile();
Expand Down Expand Up @@ -99,6 +105,24 @@ void ensureNoDataLoss() {
// Make fake accessors and permissions
UUID accessorUuid1 = UUID.randomUUID();
UUID accessorUuid2 = UUID.randomUUID();
wrapper.sql.addPlayer(
new FullPlayerData(
accessorUuid1,
"blajsd",
"g4g4",
System.currentTimeMillis(),
false,
0,
new ChunkPlayerPermissions(0)));
wrapper.sql.addPlayer(
new FullPlayerData(
accessorUuid2,
"nlfjkdsf",
"4vsrg",
System.currentTimeMillis(),
false,
0,
new ChunkPlayerPermissions(0)));
ChunkPlayerPermissions permissions1 = new ChunkPlayerPermissions(0b11111111);
ChunkPlayerPermissions permissions2 = new ChunkPlayerPermissions(0b10101101);

Expand All @@ -109,11 +133,11 @@ void ensureNoDataLoss() {
chunkData.playerPermissions.put(accessorUuid2, permissions2);
wrapper.sql.addClaimedChunk(chunkData);

// Make sure both players get loaded
// Make sure all four players get loaded
Collection<FullPlayerData> players = wrapper.sql.getAllPlayers();
assertEquals(2, players.size());
assertEquals(4, players.size());
assert players.stream()
.allMatch(ply -> ply.player.equals(ply1Uuid) || ply.player.equals(ply2Uuid));
.allMatch(ply -> ply.player.equals(ply1Uuid) || ply.player.equals(ply2Uuid) || ply.player.equals(accessorUuid1) || ply.player.equals(accessorUuid2));
assert players.stream().anyMatch(ply -> "queenshit".equals(ply.chunkName));

// Load the chunk after adding it
Expand Down

0 comments on commit e916c13

Please sign in to comment.