From 5ef3987b3f0682c4a704051b7036b0995059eae9 Mon Sep 17 00:00:00 2001 From: test Date: Wed, 4 Sep 2024 09:22:51 +1000 Subject: [PATCH] Update schema --- .../java/link/locutus/discord/db/WarDB.java | 160 ++++++----- src/main/resources/schema.graphqls | 266 ++++++++++++++++-- 2 files changed, 333 insertions(+), 93 deletions(-) diff --git a/src/main/java/link/locutus/discord/db/WarDB.java b/src/main/java/link/locutus/discord/db/WarDB.java index 592f6547..5bdd4e11 100644 --- a/src/main/java/link/locutus/discord/db/WarDB.java +++ b/src/main/java/link/locutus/discord/db/WarDB.java @@ -70,9 +70,10 @@ public class WarDB extends DBMainV2 { private final ActiveWarHandler activeWars = new ActiveWarHandler(this); - private final ObjectOpenHashSet warsById; - private final Int2ObjectOpenHashMap warsByAllianceId; - private final Int2ObjectOpenHashMap warsByNationId; + private final ObjectOpenHashSet warsById = new ObjectOpenHashSet<>(); + private final Int2ObjectOpenHashMap warsByAllianceId = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectOpenHashMap warsByNationId = new Int2ObjectOpenHashMap<>(); + private final Object warsByNationLock = new Object(); private final Int2ObjectOpenHashMap> attacksByWarId2 = new Int2ObjectOpenHashMap<>(); private ConflictManager conflictManager; public WarDB() throws SQLException { @@ -81,9 +82,6 @@ public WarDB() throws SQLException { public WarDB(String name) throws SQLException { super(Settings.INSTANCE.DATABASE, name); - warsById = new ObjectOpenHashSet<>(); - warsByAllianceId = new Int2ObjectOpenHashMap<>(); - warsByNationId = new Int2ObjectOpenHashMap<>(); } public List getLegacyVictory() { @@ -412,7 +410,7 @@ private void setWar(DBWar war) { if (war.getDefender_aa() != 0) ArrayUtil.addElement(DBWar.class, warsByAllianceId, war.getDefender_aa(), war); } - synchronized (warsByNationId) { + synchronized (warsByNationLock) { ArrayUtil.addElement(DBWar.class, warsByNationId, war.getAttacker_id(), war); ArrayUtil.addElement(DBWar.class, warsByNationId, war.getDefender_id(), war); } @@ -421,14 +419,17 @@ private void setWar(DBWar war) { } } - private void setWars(List allWars, boolean clear) { - synchronized (this.warsByAllianceId) { - synchronized (this.warsByNationId) { - synchronized (warsById) { + private void setWars(List allWars, boolean clear, boolean sync) { if (clear) { - warsById.clear(); - warsByAllianceId.clear(); - warsByNationId.clear(); + synchronized (warsById) { + warsById.clear(); + } + synchronized (warsByAllianceId) { + warsByAllianceId.clear(); + } + synchronized (warsByNationLock) { + warsByNationId.clear(); + } } Int2IntOpenHashMap numWarsByAlliance = new Int2IntOpenHashMap(); Int2IntOpenHashMap numWarsByNation = new Int2IntOpenHashMap(); @@ -438,38 +439,49 @@ private void setWars(List allWars, boolean clear) { numWarsByNation.addTo(war.getAttacker_id(), 1); numWarsByNation.addTo(war.getDefender_id(), 1); } - warsById.addAll(allWars); - for (DBWar war : allWars) { - if (war.getAttacker_aa() != 0) setWar(war, war.getAttacker_aa(), numWarsByAlliance.addTo(war.getAttacker_aa(), -1) + 1, this.warsByAllianceId); - if (war.getDefender_aa() != 0) setWar(war, war.getDefender_aa(), numWarsByAlliance.addTo(war.getDefender_aa(), -1) + 1, this.warsByAllianceId); - setWar(war, war.getAttacker_id(), numWarsByNation.addTo(war.getAttacker_id(), -1) + 1, this.warsByNationId); - setWar(war, war.getDefender_id(), numWarsByNation.addTo(war.getDefender_id(), -1) + 1, this.warsByNationId); + synchronized (warsById) { + warsById.addAll(allWars); } + if (sync) { + synchronized (warsByNationLock) { + for (DBWar war : allWars) { + setWar(war, war.getAttacker_id(), numWarsByNation.get(war.getAttacker_id()), this.warsByNationId); + setWar(war, war.getDefender_id(), numWarsByNation.get(war.getDefender_id()), this.warsByNationId); } } + synchronized (warsByAllianceId) { + for (DBWar war : allWars) { + if (war.getAttacker_aa() != 0) setWar(war, war.getAttacker_aa(), numWarsByAlliance.get(war.getAttacker_aa()), this.warsByAllianceId); + if (war.getDefender_aa() != 0) setWar(war, war.getDefender_aa(), numWarsByAlliance.get(war.getDefender_aa()), this.warsByAllianceId); + } + } + } else { + for (DBWar war : allWars) { + if (war.getAttacker_aa() != 0) setWar(war, war.getAttacker_aa(), numWarsByAlliance.get(war.getAttacker_aa()), this.warsByAllianceId); + if (war.getDefender_aa() != 0) setWar(war, war.getDefender_aa(), numWarsByAlliance.get(war.getDefender_aa()), this.warsByAllianceId); + setWar(war, war.getAttacker_id(), numWarsByNation.get(war.getAttacker_id()), this.warsByNationId); + setWar(war, war.getDefender_id(), numWarsByNation.get(war.getDefender_id()), this.warsByNationId); + } } } - private void setWar(DBWar war, int id, int remaining, Int2ObjectOpenHashMap map) { - map.merge(id, war, (o, o2) -> { - if (o == null) { - if (remaining <= 1) { - return o2; - } - ObjectOpenHashSet result = new ObjectOpenHashSet<>(); - result.add(o2); - return result; + private void setWar(DBWar war, int id, int size, Int2ObjectOpenHashMap map) { + if (size == 1) { + map.put(id, war); + } else { + Object o = map.get(id); + if (o instanceof ObjectOpenHashSet set) { + set.add(war); + } else if (o == null) { + ObjectOpenHashSet set = new ObjectOpenHashSet<>(size); + set.add(war); + map.put(id, set); } else if (o instanceof DBWar oldWar) { - ObjectOpenHashSet array = new ObjectOpenHashSet<>(remaining + 1); - array.add(oldWar); - array.add(o2); - return array; + throw new IllegalStateException("Multiple wars for " + id + ": " + oldWar + " and " + war); } else { - ObjectOpenHashSet array = (ObjectOpenHashSet) o; - array.add(o2); - return array; + throw new IllegalStateException("Unknown object for " + id + ": " + o); } - }); + } } public void loadWarCityCountsLegacy() throws IOException, ParseException { @@ -583,7 +595,7 @@ public void loadWars(int turns) { } }); if (!wars.isEmpty()) { - setWars(wars, false); + setWars(wars, false, false); } if (!saveWars.isEmpty()) { saveWars(saveWars, false); @@ -824,7 +836,7 @@ public Set getWarsForNationOrAlliance(Set nations, Set } } if (nations != null && !nations.isEmpty()) { - synchronized (warsByNationId) { + synchronized (warsByNationLock) { for (int id : nations) { Object wars = warsByNationId.get(id); if (wars != null) { @@ -858,7 +870,7 @@ public Map getWarsForNationOrAlliance(Predicate nations } } if (nations != null) { - synchronized (warsByNationId) { + synchronized (warsByNationLock) { for (Map.Entry entry : warsByNationId.entrySet()) { if (nations.test(entry.getKey())) { if (warFilter != null) { @@ -903,7 +915,7 @@ public List getAttacks(Set nationIds, long cuttoffMs) { public List getAttacks(Set nationIds, long start, long end) { Set allWars = new ObjectOpenHashSet<>(); long startWithExpire = TimeUtil.getTimeFromTurn(TimeUtil.getTurn(start) - 60); - synchronized (warsByNationId) { + synchronized (warsByNationLock) { for (int nationId : nationIds) { Object natWars = warsByNationId.get(nationId); if (natWars != null) { @@ -925,7 +937,7 @@ public List getAttacksEither(Set nationIds, long cuttof public List getAttacksEither(Set nationIds, long start, long end) { Set allWars = new LinkedHashSet<>(); long startWithExpire = TimeUtil.getTimeFromTurn(TimeUtil.getTurn(start) - 60); - synchronized (warsByNationId) { + synchronized (warsByNationLock) { for (int nationId : nationIds) { Object natWars = warsByNationId.get(nationId); if (natWars != null) { @@ -945,7 +957,7 @@ public List getAttacksAny(Set nationIds, long cuttoffMs public List getAttacksAny(Set nationIds, long start, long end) { Set allWars = new LinkedHashSet<>(); long startWithExpire = TimeUtil.getTimeFromTurn(TimeUtil.getTurn(start) - 60); - synchronized (warsByNationId) { + synchronized (warsByNationLock) { for (int nationId : nationIds) { Object natWars = warsByNationId.get(nationId); if (natWars != null) { @@ -2017,7 +2029,7 @@ public DBWar getWar(int warId) { public List getWars(int nation1, int nation2, long start, long end) { List list = new ArrayList<>(); - synchronized (warsByNationId) { + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation1); if (wars != null) { ArrayUtil.iterateElements(DBWar.class, wars, dbWar -> { @@ -2049,17 +2061,18 @@ public Set getWarsByNation(int nation, WarStatus status) { } return wars; } - synchronized (warsByNationId) { + Set list; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation); if (wars == null) return Collections.emptySet(); - Set list = new ObjectOpenHashSet<>(); + list = new ObjectOpenHashSet<>(); ArrayUtil.iterateElements(DBWar.class, wars, dbWar -> { if (dbWar.getStatus() == status) { list.add(dbWar); } }); - return list; } + return list; } public Set getActiveWarsByAlliance(Set attackerAA, Set defenderAA) { @@ -2075,23 +2088,27 @@ public Set getWarsByAlliance(int attacker) { } public Set getWarsByNation(int nationId) { - synchronized (warsByNationId) { - return ArrayUtil.toSet(DBWar.class, warsByNationId.get(nationId)); + Set result; + synchronized (warsByNationLock) { + Object amt = warsByNationId.get(nationId); + result = ArrayUtil.toSet(DBWar.class, amt); } + return result; } public Set getWarsByNationMatching(int nationId, Predicate filter) { - synchronized (warsByNationId) { + Set list; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nationId); if (wars == null) return Collections.emptySet(); - Set list = new ObjectOpenHashSet<>(); + list = new ObjectOpenHashSet<>(); ArrayUtil.iterateElements(DBWar.class, wars, dbWar -> { if (filter.test(dbWar)) { list.add(dbWar); } }); - return list; } + return list; } public DBWar getLastOffensiveWar(int nation) { @@ -2126,16 +2143,17 @@ public Set getWarsByNation(int nation, WarStatus... statuses) { if (statuses.length == 1) return getWarsByNation(nation, statuses[0]); Set statusSet = new HashSet<>(Arrays.asList(statuses)); - synchronized (warsByNationId) { + Set set; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation); - Set set = new ObjectOpenHashSet<>(); + set = new ObjectOpenHashSet<>(); ArrayUtil.iterateElements(DBWar.class, wars, dbWar -> { if (statusSet.contains(dbWar.getStatus())) { set.add(dbWar); } }); - return set; } + return set; } public Set getActiveWars(Set alliances, WarStatus... statuses) { @@ -2630,7 +2648,7 @@ public void loadAttacks(boolean loadInactive, boolean loadActive) { // Map> result = new Int2ObjectOpenHashMap<>(); // // attacks start within 5 days after a war // long cutoff = TimeUtil.getTimeFromTurn(TimeUtil.getTurn(startDate) + 60); -// synchronized (warsByNationId) { +// synchronized (warsByNationLock) { // Map warMap = warsByNationId.get(nationId); // if (warMap != null) { // for (DBWar war : warMap.values()) { @@ -2869,40 +2887,50 @@ public List getAttacksByWars(Collection wars, long start, public int countWarsByNation(int nation_id, long date, Long endDate) { if (endDate == null || endDate == Long.MAX_VALUE) return countWarsByNation(nation_id, date); - synchronized (warsByNationId) { + int result; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation_id); - return ArrayUtil.countElements(DBWar.class, wars, f -> f.getDate() >= date && f.getDate() <= endDate); + result = ArrayUtil.countElements(DBWar.class, wars, f -> f.getDate() >= date && f.getDate() <= endDate); } + return result; } public int countWarsByNation(int nation_id, long date) { if (date == 0) { - synchronized (warsByNationId) { + int result; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation_id); - return ArrayUtil.countElements(DBWar.class, wars); + result = ArrayUtil.countElements(DBWar.class, wars); } + return result; } - synchronized (warsByNationId) { + int result; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation_id); if (wars == null) return 0; - return ArrayUtil.countElements(DBWar.class, wars, war -> war.getDate() > date); + result = ArrayUtil.countElements(DBWar.class, wars, war -> war.getDate() > date); } + return result; } public int countOffWarsByNation(int nation_id, long startDate, long endDate) { - synchronized (warsByNationId) { + int result; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation_id); if (wars == null) return 0; - return ArrayUtil.countElements(DBWar.class, wars, war -> war.getAttacker_id() == nation_id && war.getDate() > startDate && war.getDate() < endDate); + result = ArrayUtil.countElements(DBWar.class, wars, war -> war.getAttacker_id() == nation_id && war.getDate() > startDate && war.getDate() < endDate); } + return result; } public int countDefWarsByNation(int nation_id, long startDate, long endDate) { - synchronized (warsByNationId) { + int result; + synchronized (warsByNationLock) { Object wars = warsByNationId.get(nation_id); if (wars == null) return 0; - return ArrayUtil.countElements(DBWar.class, wars, war -> war.getDefender_id() == nation_id && war.getDate() > startDate && war.getDate() < endDate); + result = ArrayUtil.countElements(DBWar.class, wars, war -> war.getDefender_id() == nation_id && war.getDate() > startDate && war.getDate() < endDate); } + return result; } public int countWarsByAlliance(int alliance_id, long date) { diff --git a/src/main/resources/schema.graphqls b/src/main/resources/schema.graphqls index 7f0a865d..8034651b 100644 --- a/src/main/resources/schema.graphqls +++ b/src/main/resources/schema.graphqls @@ -1676,6 +1676,9 @@ type War { # Date and time the war was declared date: DateTimeAuto + # When the war was ended through victory, peace, or expiration + end_date: DateTimeAuto + # Reason given for the war reason: String @@ -2164,6 +2167,164 @@ type CityInfraDamage { infrastructure: Float } +type Award { + name: String + image: String +} + +# Order by clause for Alliance.bulletins.orderBy. +input AllianceBulletinsOrderByOrderByClause { + # The column that is used for ordering. + column: AllianceBulletinsOrderByColumn! + + # The direction that is used for ordering. + order: SortOrder! +} + +# Allowed column names for Alliance.bulletins.orderBy. +enum AllianceBulletinsOrderByColumn { + ID + DATE + LAST_EDIT_DATE + ACCOUNT_ID +} + +type Bulletin { + # ID of the bulletin + id: ID! + + # ID of the nation that posted the bulletin + nation_id: ID! + + # Nation that posted the bulletin + nation: Nation + + # ID of the alliance the bulletin was posted to, null if type is 1 + alliance_id: ID + + # Alliance the bulletin was posted to, null if type is 1 + alliance: Alliance + + # Type of bulletin: nation (1) or alliance (2) + type: Int! + + # Headline/title of the bulletin + headline: String! + + # Excerpt of the bulletin that is shown + excerpt: String + + # Banner image of the bulletin + image: String + + # Content of the bulletin + body: String + + # Who the bulletin was written by, may be different from the nation's leader name + author: String + + # Whether or not the bulletin is pinned + pinned: Boolean! + + # How many likes the bulletin has + like_count: Int + + # Whether or not the bulletin has replies enabled + replies_enabled: Boolean! + + # Whether or not the bulletin was locked by moderators + locked: Boolean! + + # When the bulletin was posted + date: DateTimeAuto! + + # When the bulletin was last updated + edit_date: DateTimeAuto! + + # Whether or not the bulletin has been archived by the poster + archived: Boolean! + + # The bulletins replies + replies( + # Limits number of fetched items. Maximum allowed value: 500. + first: Int = 50 + + # The offset from which items are returned. + page: Int + ): BulletinReplyPaginator +} + +# A paginated list of BulletinReply items. +type BulletinReplyPaginator { + # Pagination information about the list of items. + paginatorInfo: PaginatorInfo! + + # A list of BulletinReply items. + data: [BulletinReply!]! +} + +# Information about pagination using a fully featured paginator. +type PaginatorInfo { + # Number of items in the current page. + count: Int! + + # Index of the current page. + currentPage: Int! + + # Index of the first item in the current page. + firstItem: Int + + # Are there more pages after this one? + hasMorePages: Boolean! + + # Index of the last item in the current page. + lastItem: Int + + # Index of the last available page. + lastPage: Int! + + # Number of items per page. + perPage: Int! + + # Number of total available items. + total: Int! +} + +type BulletinReply { + # ID of the reply + id: ID! + + # Date that the reply was posted + date: DateTimeAuto! + + # ID of the nation posting the reply + nation_id: ID! + + # Nation posting the reply + nation: Nation + + # ID of the bulleting replied to + bulletin_id: ID! + + # Bulletin that was replied to + bulletin: Bulletin + + # Content of the reply + message: String! + + # Date that the reply was last edited + edit_date: DateTimeAuto + + # Name of the nation posting the reply + nation_name: String! + + # Name of the leader posting the reply + leader_name: String! + + # Number of likes the reply has received + like_count: Int +} + enum WarPolicy { ATTRITION TURTLE @@ -2816,6 +2977,40 @@ enum GovernmentType { THEOCRATIC_DEMOCRACY THEOCRATIC_DICTATORSHIP THEOCRATIC_REPUBLIC +MINDHIVE +} + +# Order by clause for Nation.bulletins.orderBy. +input NationBulletinsOrderByOrderByClause { + # The column that is used for ordering. + column: NationBulletinsOrderByColumn! + + # The direction that is used for ordering. + order: SortOrder! +} + +# Allowed column names for Nation.bulletins.orderBy. +enum NationBulletinsOrderByColumn { + ID + DATE + LAST_EDIT_DATE +} + +# Order by clause for Nation.bulletin_replies.orderBy. +input NationBulletinRepliesOrderByOrderByClause { + # The column that is used for ordering. + column: NationBulletinRepliesOrderByColumn! + + # The direction that is used for ordering. + order: SortOrder! +} + +# Allowed column names for Nation.bulletin_replies.orderBy. +enum NationBulletinRepliesOrderByColumn { + ID + DATE + EDIT_DATE + BULLETIN_ID } type ApiKeyPermissions { @@ -3049,33 +3244,6 @@ type NationPaginator { data: [Nation!]! } -# Information about pagination using a fully featured paginator. -type PaginatorInfo { - # Number of items in the current page. - count: Int! - - # Index of the current page. - currentPage: Int! - - # Index of the first item in the current page. - firstItem: Int - - # Are there more pages after this one? - hasMorePages: Boolean! - - # Index of the last item in the current page. - lastItem: Int - - # Index of the last available page. - lastPage: Int! - - # Number of items per page. - perPage: Int! - - # Number of total available items. - total: Int! -} - # Order by clause for Query.alliances.orderBy. input QueryAlliancesOrderByOrderByClause { # The column that is used for ordering. @@ -3725,6 +3893,50 @@ type BannedNation { days_left: Int } +# Order by clause for Query.bulletins.orderBy. +input QueryBulletinsOrderByOrderByClause { + # The column that is used for ordering. + column: QueryBulletinsOrderByColumn! + + # The direction that is used for ordering. + order: SortOrder! +} + +# Allowed column names for Query.bulletins.orderBy. +enum QueryBulletinsOrderByColumn { + ID + DATE + LAST_EDIT_DATE + ACCOUNT_ID +} + +# A paginated list of Bulletin items. +type BulletinPaginator { + # Pagination information about the list of items. + paginatorInfo: PaginatorInfo! + + # A list of Bulletin items. + data: [Bulletin!]! +} + +# Order by clause for Query.bulletin_replies.orderBy. +input QueryBulletinRepliesOrderByOrderByClause { + # The column that is used for ordering. + column: QueryBulletinRepliesOrderByColumn! + + # The direction that is used for ordering. + order: SortOrder! +} + +# Allowed column names for Query.bulletin_replies.orderBy. +enum QueryBulletinRepliesOrderByColumn { + ID + DATE + EDIT_DATE + ACCOUNT_ID + BULLETIN_ID +} + type Mutation { bankDeposit( money: Float = 0.0