findByAccount(int,int)   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 7
dl 0
loc 7
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
/*
2
 * This file is part of Araknemu.
3
 *
4
 * Araknemu is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * Araknemu is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with Araknemu.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2020 Vincent Quatrevieux
18
 */
19
20
package fr.quatrevieux.araknemu.data.living.repository.implementation.sql;
21
22
import fr.arakne.utils.value.Colors;
23
import fr.arakne.utils.value.constant.Gender;
24
import fr.arakne.utils.value.constant.Race;
25
import fr.quatrevieux.araknemu.core.dbal.executor.QueryExecutor;
26
import fr.quatrevieux.araknemu.core.dbal.repository.EntityNotFoundException;
27
import fr.quatrevieux.araknemu.core.dbal.repository.Record;
28
import fr.quatrevieux.araknemu.core.dbal.repository.RepositoryException;
29
import fr.quatrevieux.araknemu.core.dbal.repository.RepositoryUtils;
30
import fr.quatrevieux.araknemu.data.living.entity.player.Player;
31
import fr.quatrevieux.araknemu.data.living.repository.player.PlayerRepository;
32
import fr.quatrevieux.araknemu.data.transformer.Transformer;
33
import fr.quatrevieux.araknemu.data.value.Position;
34
import fr.quatrevieux.araknemu.data.value.ServerCharacters;
35
import fr.quatrevieux.araknemu.game.chat.ChannelType;
36
import fr.quatrevieux.araknemu.game.world.creature.characteristics.MutableCharacteristics;
37
38
import java.sql.ResultSet;
39
import java.sql.SQLException;
40
import java.util.ArrayList;
41
import java.util.Collection;
42
import java.util.Set;
43
44
final class SqlPlayerRepository implements PlayerRepository {
45
    private final QueryExecutor executor;
46
    private final Transformer<MutableCharacteristics> characteristicsTransformer;
47
    private final Transformer<Set<ChannelType>> channelsTransformer;
48
49
    private final RepositoryUtils<Player> utils;
50
51 1
    public SqlPlayerRepository(QueryExecutor executor, Transformer<MutableCharacteristics> characteristicsTransformer, Transformer<Set<ChannelType>> channelsTransformer) {
52 1
        this.executor = executor;
53 1
        this.characteristicsTransformer = characteristicsTransformer;
54 1
        this.channelsTransformer = channelsTransformer;
55 1
        this.utils = new RepositoryUtils<>(this.executor, new SqlPlayerRepository.Loader());
56 1
    }
57
58
    @Override
59
    public void initialize() throws RepositoryException {
60
        try {
61 1
            executor.query(
62
                "CREATE TABLE PLAYER (" +
63
                    "PLAYER_ID INTEGER PRIMARY KEY AUTOINCREMENT," +
64
                    "ACCOUNT_ID INTEGER," +
65
                    "SERVER_ID INTEGER," +
66
                    "PLAYER_NAME VARCHAR(32)," +
67
                    "RACE INTEGER(2)," +
68
                    "SEX INTEGER(1)," +
69
                    "COLOR1 INTEGER," +
70
                    "COLOR2 INTEGER," +
71
                    "COLOR3 INTEGER," +
72
                    "PLAYER_LEVEL INTEGER," +
73
                    "PLAYER_STATS TEXT," +
74
                    "MAP_ID INTEGER," +
75
                    "CELL_ID INTEGER," +
76
                    "CHANNELS VARCHAR(16)," +
77
                    "BOOST_POINTS INTEGER," +
78
                    "SPELL_POINTS INTEGER," +
79
                    "LIFE_POINTS INTEGER," +
80
                    "PLAYER_EXPERIENCE BIGINT," +
81
                    "SAVED_MAP_ID INTEGER," +
82
                    "SAVED_CELL_ID INTEGER," +
83
                    "PLAYER_KAMAS BIGINT," +
84
                    "UNIQUE (PLAYER_NAME, SERVER_ID)" +
85
                ")"
86
            );
87
88 1
            executor.query("CREATE INDEX IDX_ACC_SRV ON PLAYER (ACCOUNT_ID, SERVER_ID)");
89
        } catch (SQLException e) {
90
            throw new RepositoryException(e);
91 1
        }
92 1
    }
93
94
    @Override
95
    public void destroy() throws RepositoryException {
96
        try {
97 1
            executor.query("DROP TABLE PLAYER");
98
        } catch (SQLException e) {
99
            throw new RepositoryException(e);
100 1
        }
101 1
    }
102
103
    @Override
104
    public Player add(Player entity) throws RepositoryException {
105 1
        return utils.update(
106
            "INSERT INTO PLAYER " +
107
                "(ACCOUNT_ID, SERVER_ID, PLAYER_NAME, RACE, SEX, COLOR1, COLOR2, COLOR3, PLAYER_LEVEL, PLAYER_STATS, MAP_ID, CELL_ID, CHANNELS, BOOST_POINTS, SPELL_POINTS, LIFE_POINTS, PLAYER_EXPERIENCE, SAVED_MAP_ID, SAVED_CELL_ID, PLAYER_KAMAS) " +
108
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
109
            stmt -> {
110 1
                stmt.setInt(1,     entity.accountId());
111 1
                stmt.setInt(2,     entity.serverId());
112 1
                stmt.setString(3,  entity.name());
113 1
                stmt.setInt(4,     entity.race().ordinal());
114 1
                stmt.setInt(5,     entity.gender().ordinal());
115 1
                stmt.setInt(6,     entity.colors().color1());
116 1
                stmt.setInt(7,     entity.colors().color2());
117 1
                stmt.setInt(8,     entity.colors().color3());
118 1
                stmt.setInt(9,     entity.level());
119 1
                stmt.setString(10, characteristicsTransformer.serialize(entity.stats()));
120 1
                stmt.setInt(11,    entity.position().map());
121 1
                stmt.setInt(12,    entity.position().cell());
122 1
                stmt.setString(13, channelsTransformer.serialize(entity.channels()));
123 1
                stmt.setInt(14,    entity.boostPoints());
124 1
                stmt.setInt(15,    entity.spellPoints());
125 1
                stmt.setInt(16,    entity.life());
126 1
                stmt.setLong(17,   entity.experience());
127 1
                stmt.setInt(18,    entity.savedPosition().map());
128 1
                stmt.setInt(19,    entity.savedPosition().cell());
129 1
                stmt.setLong(20,   entity.kamas());
130 1
            },
131
            entity
132
        );
133
    }
134
135
    @Override
136
    public void delete(Player entity) throws RepositoryException {
137 1
        if (utils.update("DELETE FROM PLAYER WHERE PLAYER_ID = ?", rs -> rs.setInt(1, entity.id())) < 1) {
138 1
            throw new EntityNotFoundException();
139
        }
140 1
    }
141
142
    @Override
143
    public Player get(Player entity) throws RepositoryException {
144 1
        return utils.findOne(
145
            "SELECT * FROM PLAYER WHERE PLAYER_ID = ?",
146 1
            stmt -> stmt.setInt(1, entity.id())
147
        );
148
    }
149
150
    @Override
151
    public boolean has(Player entity) throws RepositoryException {
152 1
        return utils.aggregate(
153
            "SELECT COUNT(*) FROM PLAYER WHERE PLAYER_ID = ?",
154 1
            stmt -> stmt.setInt(1, entity.id())
155
        ) > 0;
156
    }
157
158
    @Override
159
    public Collection<Player> findByAccount(int accountId, int serverId) {
160 1
        return utils.findAll(
161
            "SELECT * FROM PLAYER WHERE ACCOUNT_ID = ? AND SERVER_ID = ?",
162
            stmt -> {
163 1
                stmt.setInt(1, accountId);
164 1
                stmt.setInt(2, serverId);
165 1
            }
166
        );
167
    }
168
169
    @Override
170
    public boolean nameExists(int serverId, String name) {
171 1
        return utils.aggregate(
172
            "SELECT COUNT(*) FROM PLAYER WHERE PLAYER_NAME = ? AND SERVER_ID = ?",
173
            stmt -> {
174 1
                stmt.setString(1, name);
175 1
                stmt.setInt(2, serverId);
176 1
            }
177
        ) > 0;
178
    }
179
180
    @Override
181
    public int accountCharactersCount(Player player) {
182 1
        return utils.aggregate(
183
            "SELECT COUNT(*) FROM PLAYER WHERE ACCOUNT_ID = ? AND SERVER_ID = ?",
184
            stmt -> {
185 1
                stmt.setInt(1, player.accountId());
186 1
                stmt.setInt(2, player.serverId());
187 1
            }
188
        );
189
    }
190
191
    @Override
192
    public Collection<ServerCharacters> accountCharactersCount(int accountId) {
193
        try {
194 1
            return executor.prepare(
195
                "SELECT SERVER_ID, COUNT(*) FROM PLAYER WHERE ACCOUNT_ID = ? GROUP BY SERVER_ID",
196
                stmt -> {
197 1
                    stmt.setInt(1, accountId);
198
199 1
                    try (ResultSet rs = stmt.executeQuery()) {
200 1
                        final Collection<ServerCharacters> list = new ArrayList<>();
201
202 1
                        while (rs.next()) {
203 1
                            list.add(
204
                                new ServerCharacters(
205 1
                                    rs.getInt("SERVER_ID"),
206 1
                                    rs.getInt("COUNT(*)")
207
                                )
208
                            );
209
                        }
210
211 1
                        return list;
212
                    }
213
                }
214
            );
215
        } catch (SQLException e) {
216
            throw new RepositoryException("Cannot load characters count", e);
217
        }
218
    }
219
220
    @Override
221
    public Collection<ServerCharacters> serverCharactersCountByAccountPseudo(String accountPseudo) {
222
        try {
223 1
            return executor.prepare(
224
                "SELECT SERVER_ID, COUNT(*) FROM PLAYER P JOIN ACCOUNT A ON P.ACCOUNT_ID = A.ACCOUNT_ID WHERE A.PSEUDO = ? GROUP BY SERVER_ID",
225
                stmt -> {
226 1
                    stmt.setString(1, accountPseudo);
227
228 1
                    try (ResultSet rs = stmt.executeQuery()) {
229 1
                        final Collection<ServerCharacters> list = new ArrayList<>();
230
231 1
                        while (rs.next()) {
232 1
                            list.add(new ServerCharacters(rs.getInt("SERVER_ID"), rs.getInt("COUNT(*)")));
233
                        }
234
235 1
                        return list;
236
                    }
237
                }
238
            );
239
        } catch (SQLException e) {
240
            throw new RepositoryException("Cannot load characters count", e);
241
        }
242
    }
243
244
    @Override
245
    public Player getForGame(Player player) {
246 1
        return utils.findOne(
247
            "SELECT * FROM PLAYER WHERE PLAYER_ID = ? AND ACCOUNT_ID = ? AND SERVER_ID = ?",
248
            stmt -> {
249 1
                stmt.setInt(1, player.id());
250 1
                stmt.setInt(2, player.accountId());
251 1
                stmt.setInt(3, player.serverId());
252 1
            }
253
        );
254
    }
255
256
    @Override
257
    public void save(Player player) {
258 1
        final int rows = utils.update(
259
            "UPDATE PLAYER SET " +
260
                "PLAYER_LEVEL = ?, PLAYER_STATS = ?, MAP_ID = ?, CELL_ID = ?, CHANNELS = ?, BOOST_POINTS = ?, SPELL_POINTS = ?, LIFE_POINTS = ?, PLAYER_EXPERIENCE = ?, SAVED_MAP_ID = ?, SAVED_CELL_ID = ?, PLAYER_KAMAS = ? " +
261
                "WHERE PLAYER_ID = ?",
262
            stmt -> {
263 1
                stmt.setInt(1,    player.level());
264 1
                stmt.setString(2, characteristicsTransformer.serialize(player.stats()));
265 1
                stmt.setInt(3,    player.position().map());
266 1
                stmt.setInt(4,    player.position().cell());
267 1
                stmt.setString(5, channelsTransformer.serialize(player.channels()));
268 1
                stmt.setInt(6,    player.boostPoints());
269 1
                stmt.setInt(7,    player.spellPoints());
270 1
                stmt.setInt(8,    player.life());
271 1
                stmt.setLong(9,   player.experience());
272 1
                stmt.setInt(10,   player.savedPosition().map());
273 1
                stmt.setInt(11,   player.savedPosition().cell());
274 1
                stmt.setLong(12,  player.kamas());
275 1
                stmt.setInt(13,   player.id());
276 1
            }
277
        );
278
279 1
        if (rows != 1) {
280 1
            throw new EntityNotFoundException();
281
        }
282 1
    }
283
284 1
    private class Loader implements RepositoryUtils.Loader<Player> {
0 ignored issues
show
Comprehensibility introduced by
Class or interface names should not shadow other classes or interfaces. In general, shadowing is a bad practice as it makes code harder to understand. Consider renaming this class.
Loading history...
285 1
        private final Gender[] genders = Gender.values();
286
287
        @Override
288
        public Player create(Record record) throws SQLException {
289 1
            return new Player(
290 1
                record.getInt("PLAYER_ID"),
291 1
                record.getInt("ACCOUNT_ID"),
292 1
                record.getInt("SERVER_ID"),
293 1
                record.getString("PLAYER_NAME"),
294 1
                Race.byId(record.getPositiveInt("RACE")),
295 1
                record.getArrayValue("SEX", genders),
296 1
                createColors(record),
297 1
                record.getPositiveInt("PLAYER_LEVEL"),
298 1
                record.unserialize("PLAYER_STATS", characteristicsTransformer),
299
                new Position(
300 1
                    record.getNonNegativeInt("MAP_ID"),
301 1
                    record.getNonNegativeInt("CELL_ID")
302
                ),
303 1
                record.unserialize("CHANNELS", channelsTransformer),
304 1
                record.getNonNegativeInt("BOOST_POINTS"),
305 1
                record.getNonNegativeInt("SPELL_POINTS"),
306 1
                record.getNonNegativeInt("LIFE_POINTS"),
307 1
                record.getNonNegativeLong("PLAYER_EXPERIENCE"),
308
                new Position(
309 1
                    record.getNonNegativeInt("SAVED_MAP_ID"),
310 1
                    record.getNonNegativeInt("SAVED_CELL_ID")
311
                ),
312 1
                record.getNonNegativeLong("PLAYER_KAMAS")
313
            );
314
        }
315
316
        @Override
317
        public Player fillKeys(Player entity, ResultSet keys) throws SQLException {
318 1
            return entity.withId(keys.getInt(1));
319
        }
320
321
        @SuppressWarnings("argument") // Ignore invalid colors error
322
        private Colors createColors(Record record) throws SQLException {
323 1
            return new Colors(
324 1
                record.getInt("COLOR1"),
325 1
                record.getInt("COLOR2"),
326 1
                record.getInt("COLOR3")
327
            );
328
        }
329
    }
330
}
331