mass player collection testing is now possible

This commit is contained in:
Christian 'ketura' McCarty
2022-10-30 02:55:05 -05:00
parent 03751d6b9d
commit 564cf6d633
14 changed files with 210 additions and 21 deletions

View File

@@ -2,6 +2,10 @@
ALTER TABLE collection ADD CONSTRAINT fk_collection_player_id FOREIGN KEY (player_id) REFERENCES player(id);
ALTER TABLE collection ADD `extra_info` VARCHAR(5000) NULL;
ALTER TABLE collection ADD CONSTRAINT uq_collection_player_type UNIQUE (player_id, type);
CREATE TABLE `collection_entries` (
`collection_id` int(11) NOT NULL,
@@ -15,4 +19,27 @@ CREATE TABLE `collection_entries` (
`notes` varchar(100) DEFAULT NULL,
PRIMARY KEY (`collection_id`, `product`),
CONSTRAINT `collection_entries_ibfk_1` FOREIGN KEY (`collection_id`) REFERENCES `collection` (`id`)
) ;
) ;
SELECT *
FROM collection c
WHERE player_id = 31040
SELECT *
FROM collection_entries
WHERE collection_id = 64643
SELECT *
FROM player p
LEFT JOIN collection c
ON c.player_id = p.id
WHERE c.id IS NULL
ORDER BY p.name
SELECT count(*)
FROM collection_entries
GROUP BY collection_id

View File

@@ -42,6 +42,13 @@ public class DBDefs {
}
public static class Collection {
public int id;
public int player_id;
public String type;
public String extra_info;
}
public static class CollectionEntry {
public int collection_id;
public int quantity;
@@ -53,4 +60,9 @@ public class DBDefs {
public LocalDateTime modified_date;
public String notes;
}
public static class Player {
public int id;
public String name;
}
}

View File

@@ -1,6 +1,7 @@
package com.gempukku.lotro.collection;
import com.gempukku.lotro.cache.Cached;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.db.CollectionDAO;
import com.gempukku.lotro.game.CardCollection;
import org.apache.commons.collections.map.LRUMap;
@@ -8,6 +9,7 @@ import org.apache.commons.collections.map.LRUMap;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CachedCollectionDAO implements CollectionDAO, Cached {
@@ -60,8 +62,13 @@ public class CachedCollectionDAO implements CollectionDAO, Cached {
}
@Override
public void addToCollection(int playerId, String type, CardCollection collection, String source) {
_delegate.addToCollection(playerId, type, collection, source);
public List<DBDefs.Collection> getAllCollectionsForPlayer(int playerId) {
return _delegate.getAllCollectionsForPlayer(playerId);
}
@Override
public void addToCollectionContents(int playerId, String type, CardCollection collection, String source) {
_delegate.addToCollectionContents(playerId, type, collection, source);
String id = constructCacheKey(playerId, type);
if(!_playerCollections.containsKey(id)) {
_playerCollections.put(id, collection);
@@ -73,7 +80,7 @@ public class CachedCollectionDAO implements CollectionDAO, Cached {
}
@Override
public void removeFromCollection(int playerId, String type, CardCollection collection, String source) {
_delegate.removeFromCollection(playerId, type, collection, source);
public void removeFromCollectionContents(int playerId, String type, CardCollection collection, String source) {
_delegate.removeFromCollectionContents(playerId, type, collection, source);
}
}

View File

@@ -1,6 +1,7 @@
package com.gempukku.lotro.db;
import com.gempukku.lotro.cache.Cached;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.game.Player;
import org.apache.commons.collections.map.LRUMap;
@@ -132,6 +133,11 @@ public class CachedPlayerDAO implements PlayerDAO, Cached {
_delegate.updateLastLoginIp(login, remoteAddr);
}
@Override
public List<DBDefs.Player> getAllPlayers() {
return _delegate.getAllPlayers();
}
@Override
public boolean updateLastReward(Player player, int previousReward, int currentReward) throws SQLException {
boolean updated = _delegate.updateLastReward(player, previousReward, currentReward);

View File

@@ -1,9 +1,11 @@
package com.gempukku.lotro.db;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.game.CardCollection;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public interface CollectionDAO {
@@ -15,7 +17,9 @@ public interface CollectionDAO {
void convertCollection(int playerId, String type) throws SQLException, IOException;
void addToCollection(int playerId, String type, CardCollection collection, String source);
List<DBDefs.Collection> getAllCollectionsForPlayer(int playerId);
void removeFromCollection(int playerId, String type, CardCollection collection, String source);
void addToCollectionContents(int playerId, String type, CardCollection collection, String source);
void removeFromCollectionContents(int playerId, String type, CardCollection collection, String source);
}

View File

@@ -1,7 +1,9 @@
package com.gempukku.lotro.db;
import com.gempukku.lotro.collection.CollectionSerializer;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.game.CardCollection;
import org.json.simple.JSONObject;
import org.sql2o.Query;
import org.sql2o.Sql2o;
@@ -11,6 +13,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DbCollectionDAO implements CollectionDAO {
@@ -92,6 +95,30 @@ public class DbCollectionDAO implements CollectionDAO {
public int ID;
}
@Override
public List<DBDefs.Collection> getAllCollectionsForPlayer(int playerId) {
try {
Sql2o db = new Sql2o(_dbAccess.getDataSource());
try (org.sql2o.Connection conn = db.open()) {
String sql = """
SELECT
id, player_id, type, extra_info
FROM collection
WHERE player_id = :playerID
""";
List<DBDefs.Collection> result = conn.createQuery(sql)
.addParameter("playerID", playerId)
.executeAndFetch(DBDefs.Collection.class);
return result;
}
} catch (Exception ex) {
throw new RuntimeException("Unable to retrieve collection types", ex);
}
}
public int getCollectionID(int playerId, String type) {
try {
@@ -119,45 +146,72 @@ public class DbCollectionDAO implements CollectionDAO {
}
}
public void updateCollection(int playerId, String type, CardCollection collection, String source) {
public void upsertCollection(int playerId, String type, CardCollection collection) {
String sql = """
INSERT INTO collection(player_id, type, extra_info)
VALUES (:playerId, :type, :extraInfo)
ON DUPLICATE KEY UPDATE extra_info = :extraInfo;
""";
String json = "";
try {
Sql2o db = new Sql2o(_dbAccess.getDataSource());
var jsonObj = new JSONObject();
jsonObj.putAll(collection.getExtraInformation());
json = jsonObj.toJSONString();
try (org.sql2o.Connection conn = db.beginTransaction()) {
Query query = conn.createQuery(sql, true);
query.addParameter("playerId", playerId)
.addParameter("type", type)
.addParameter("extraInfo", json);
query.executeUpdate();
conn.commit();
}
} catch (Exception ex) {
throw new RuntimeException("Unable to upsert collection", ex);
}
}
public void updateCollectionContents(int playerId, String type, CardCollection collection, String source) {
String sql = """
INSERT INTO collection_entries(collection_id, quantity, product_type, product, source)
VALUES (:collid, :quantity, :type, :product, :source)
ON DUPLICATE KEY UPDATE quantity = :quantity, source = :source;
""";
String error = "Unable to update product via upsert into collection_entries.";
updateCollection(playerId, type, collection, source, sql, error);
updateCollectionContents(playerId, type, collection, source, sql, error);
}
public void addToCollection(int playerId, String type, CardCollection collection, String source) {
public void addToCollectionContents(int playerId, String type, CardCollection collection, String source) {
String sql = """
INSERT INTO collection_entries(collection_id, quantity, product_type, product, source)
VALUES (:collid, :quantity, :type, :product, :source)
ON DUPLICATE KEY UPDATE quantity = quantity + :quantity, source = :source;
""";
String error = "Unable to add product via upsert into collection_entries.";
updateCollection(playerId, type, collection, source, sql, error);
updateCollectionContents(playerId, type, collection, source, sql, error);
}
public void removeFromCollection(int playerId, String type, CardCollection collection, String source) {
public void removeFromCollectionContents(int playerId, String type, CardCollection collection, String source) {
String sql = """
INSERT INTO collection_entries(collection_id, quantity, product_type, product, source)
VALUES (:collid, :quantity, :type, :product, :source)
ON DUPLICATE KEY UPDATE quantity = GREATEST(quantity - :quantity, 0), source = :source;
""";
String error = "Unable to remove product via upsert into collection_entries.";
updateCollection(playerId, type, collection, source, sql, error);
updateCollectionContents(playerId, type, collection, source, sql, error);
}
public void convertCollection(int playerId, String type) throws SQLException, IOException {
CardCollection oldCollection = getPlayerCollection(playerId, type);
updateCollection(playerId, type, oldCollection, "Initial Convert");
updateCollectionContents(playerId, type, oldCollection, "Initial Convert");
}
//TODO:
// - Convert currency to an extra info entry
// - add data field to the original collection table to hold the extra info as json
// + Convert currency to an extra info entry
// + add data field to the original collection table to hold the extra info as json
// - create player-looping function to convert all collections and see if it blows up via test
// - add CollectionsManager mirror functions to read/writing into the new table
// - write unit tests to convert and compare a bajillion collections
@@ -165,7 +219,8 @@ public class DbCollectionDAO implements CollectionDAO {
// - test a: draft, new art card reward, my cards reward, pack openings
// - write script to back up db and delete the old binary blob column
// - write script to convert all leagues to use IDs instead of names
private void updateCollection(int playerId, String type, CardCollection collection, String source, String sql, String error) {
private void updateCollectionContents(int playerId, String type, CardCollection collection, String source, String sql, String error) {
upsertCollection(playerId, type, collection);
int collID = getCollectionID(playerId, type);
try {

View File

@@ -1,6 +1,8 @@
package com.gempukku.lotro.db;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.game.Player;
import org.sql2o.Sql2o;
import java.security.MessageDigest;
import java.sql.Connection;
@@ -318,4 +320,23 @@ public class DbPlayerDAO implements PlayerDAO {
}
}
}
@Override
public List<DBDefs.Player> getAllPlayers() {
try {
Sql2o db = new Sql2o(_dbAccess.getDataSource());
try (org.sql2o.Connection conn = db.open()) {
String sql = "SELECT id, name FROM player";
List<DBDefs.Player> result = conn.createQuery(sql)
.executeAndFetch(DBDefs.Player.class);
return result;
}
} catch (Exception ex) {
throw new RuntimeException("Unable to retrieve players", ex);
}
}
}

View File

@@ -1,5 +1,6 @@
package com.gempukku.lotro.db;
import com.gempukku.lotro.common.DBDefs;
import com.gempukku.lotro.game.Player;
import java.sql.SQLException;
@@ -32,4 +33,6 @@ public interface PlayerDAO {
public boolean registerUser(String login, String password, String remoteAddr) throws SQLException, LoginInvalidException;
public void updateLastLoginIp(String login, String remoteAddr) throws SQLException;
List<DBDefs.Player> getAllPlayers();
}

View File

@@ -22,8 +22,15 @@ public class DefaultCardCollection implements MutableCardCollection {
_extraInformation.putAll(cardCollection.getExtraInformation());
}
public synchronized void setExtraInformation(Map<String, Object> extraInformation) {
_extraInformation = extraInformation;
public synchronized void setExtraInformation(Map<String, Object> extraInfo) {
_extraInformation.putAll(extraInfo);
//Some deserialization defaults to making the currency a Long rather than an Integer
if(extraInfo.containsKey(CurrencyKey)) {
var input = extraInfo.get(CurrencyKey);
if(input instanceof Long linput) {
_extraInformation.put(CurrencyKey, linput.intValue());
}
}
}
@Override

View File

@@ -74,7 +74,7 @@ public class CollectionSerializerTest {
assertEquals(3, resultCollection.getItemCount("15_2"));
assertEquals(3, resultCollection.getItemCount("15_4*"));
assertEquals(2, resultCollection.getItemCount("FotR - Booster"));
assertEquals(1, resultCollection.getExtraInformation().size());
assertEquals(2, resultCollection.getExtraInformation().size());
assertEquals("b", resultCollection.getExtraInformation().get("a"));
} finally {
IOUtils.closeQuietly(is);
@@ -93,7 +93,8 @@ public class CollectionSerializerTest {
assertEquals(12, resultCollection.getCurrency());
assertEquals(1, Iterables.size(resultCollection.getAll()));
assertEquals(2, resultCollection.getItemCount("15_4*"));
assertEquals(1, resultCollection.getExtraInformation().size());
//added entry + the default currency storage
assertEquals(2, resultCollection.getExtraInformation().size());
assertEquals("b", resultCollection.getExtraInformation().get("a"));
}

View File

@@ -0,0 +1,46 @@
package com.gempukku.lotro.collection;
import com.gempukku.lotro.db.DbAccess;
import com.gempukku.lotro.db.DbCollectionDAO;
import com.gempukku.lotro.db.DbPlayerDAO;
import com.gempukku.lotro.game.CardNotFoundException;
import com.gempukku.lotro.logic.decisions.DecisionResultInvalidException;
import org.junit.Test;
import java.io.IOException;
import java.sql.SQLException;
// Tidings of Erebor
public class NewCollectionManagerTests
{
private static DbAccess dbAccess = new DbAccess("jdbc:mysql://localhost:35001/gemp_db",
"root", "rootpass", false);
@Test
public void ConvertCollectionTest() throws DecisionResultInvalidException, CardNotFoundException, IOException, SQLException {
var collDAO = new DbCollectionDAO(dbAccess, new CollectionSerializer());
collDAO.convertCollection(31040, "trophy");
}
@Test
public void ConvertAllPlayerCollectionsTest() throws DecisionResultInvalidException, CardNotFoundException, IOException, SQLException {
var collDAO = new DbCollectionDAO(dbAccess, new CollectionSerializer());
var playerDAO = new DbPlayerDAO(dbAccess);
var players = playerDAO.getAllPlayers();
for (var player : players) {
var collections = collDAO.getAllCollectionsForPlayer(player.id);
for(var coll : collections) {
collDAO.convertCollection(player.id, coll.type);
}
}
}
}