Drop problems from server + draft DB cleaning functions
[vchess.git] / server / models / Game.js
CommitLineData
00f2759e
BA
1var db = require("../utils/database");
2
3/*
4 * Structure table Games:
5 * id: game id (int)
6 * vid: integer (variant id)
ab4f4bf2
BA
7 * fenStart: varchar (initial position)
8 * fen: varchar (current position)
a9b131f1 9 * timeControl: string
00f2759e
BA
10 * score: varchar (result)
11 *
12 * Structure table Players:
13 * gid: ref game id
14 * uid: ref user id
15 * color: character
16 *
17 * Structure table Moves:
ab4f4bf2 18 * gid: ref game id
f41ce580 19 * squares: varchar (description)
ab4f4bf2 20 * message: text
00f2759e
BA
21 * played: datetime
22 * idx: integer
00f2759e
BA
23 */
24
ab4f4bf2 25const GameModel =
00f2759e 26{
a9b131f1 27 create: function(vid, fen, timeControl, players, cb)
ab4f4bf2 28 {
88667455 29 db.serialize(function() {
ab4f4bf2 30 let query =
d431028c
BA
31 "INSERT INTO Games (vid, fenStart, fen, score, timeControl, created)"
32 + " VALUES (" + vid + ",'" + fen + "','" + fen + "','*','"
33 + timeControl + "'," + Date.now() + ")";
8c564f46 34 db.run(query, function(err) {
cf742aaf
BA
35 if (!!err)
36 return cb(err);
8c564f46
BA
37 players.forEach((p,idx) => {
38 const color = (idx==0 ? "w" : "b");
2be5d614
BA
39 query =
40 "INSERT INTO Players VALUES " +
f41ce580 41 "(" + this.lastID + "," + p.id + ",'" + color + "')";
2be5d614
BA
42 db.run(query);
43 });
44 cb(null, {gid: this.lastID});
00f2759e
BA
45 });
46 });
ab4f4bf2 47 },
00f2759e 48
ab4f4bf2
BA
49 // TODO: queries here could be async, and wait for all to complete
50 getOne: function(id, cb)
51 {
52 db.serialize(function() {
f41ce580 53 // TODO: optimize queries?
ab4f4bf2 54 let query =
f41ce580
BA
55 "SELECT g.id, g.vid, g.fen, g.fenStart, g.timeControl, g.score, " +
56 "v.name AS vname " +
57 "FROM Games g " +
58 "JOIN Variants v " +
59 " ON g.vid = v.id " +
60 "WHERE g.id = " + id;
ab4f4bf2
BA
61 db.get(query, (err,gameInfo) => {
62 if (!!err)
63 return cb(err);
00f2759e 64 query =
f41ce580
BA
65 "SELECT p.uid, p.color, u.name " +
66 "FROM Players p " +
67 "JOIN Users u " +
68 " ON p.uid = u.id " +
69 "WHERE p.gid = " + id;
fd7aea36 70 db.all(query, (err2,players) => {
ab4f4bf2
BA
71 if (!!err2)
72 return cb(err2);
73 query =
92b82def 74 "SELECT squares, message, played, idx " +
ab4f4bf2
BA
75 "FROM Moves " +
76 "WHERE gid = " + id;
fd7aea36 77 db.all(query, (err3,moves) => {
ab4f4bf2
BA
78 if (!!err3)
79 return cb(err3);
fd7aea36
BA
80 const game = Object.assign({},
81 gameInfo,
82 {
83 players: players,
84 moves: moves
85 }
86 );
ab4f4bf2
BA
87 return cb(null, game);
88 });
00f2759e
BA
89 });
90 });
91 });
ab4f4bf2 92 },
00f2759e 93
5d04793e 94 getByUser: function(uid, excluded, cb)
ab4f4bf2
BA
95 {
96 db.serialize(function() {
97 // Next query is fine because a player appear at most once in a game
98 const query =
99 "SELECT gid " +
100 "FROM Players " +
5d04793e 101 "WHERE uid " + (excluded ? "<>" : "=") + " " + uid;
afd3240d 102 db.all(query, (err,gameIds) => {
ab4f4bf2
BA
103 if (!!err)
104 return cb(err);
098cd7f1 105 gameIds = gameIds || []; //might be empty
ab4f4bf2 106 let gameArray = [];
afd3240d
BA
107 for (let i=0; i<gameIds.length; i++)
108 {
109 GameModel.getOne(gameIds[i]["gid"], (err2,game) => {
ab4f4bf2
BA
110 if (!!err2)
111 return cb(err2);
112 gameArray.push(game);
afd3240d
BA
113 // Call callback function only when gameArray is complete:
114 if (i == gameIds.length - 1)
115 return cb(null, gameArray);
ab4f4bf2 116 });
afd3240d 117 }
ab4f4bf2
BA
118 });
119 });
120 },
121
411d23cd
BA
122 getPlayers: function(id, cb)
123 {
124 db.serialize(function() {
125 const query =
126 "SELECT id " +
127 "FROM Players " +
128 "WHERE gid = " + id;
129 db.all(query, (err,players) => {
130 return cb(err, players);
131 });
132 });
133 },
134
3d55deea 135 // obj can have fields move, fen and/or score
f41ce580 136 update: function(id, obj)
3d55deea 137 {
f41ce580 138 db.parallelize(function() {
3d55deea
BA
139 let query =
140 "UPDATE Games " +
141 "SET ";
3d55deea 142 if (!!obj.fen)
afc42601 143 query += "fen = '" + obj.fen + "',";
3d55deea 144 if (!!obj.score)
afc42601 145 query += "score = '" + obj.score + "',";
3d55deea 146 query = query.slice(0,-1); //remove last comma
afc42601 147 query += " WHERE id = " + id;
f41ce580
BA
148 db.run(query);
149 if (!!obj.move)
150 {
afc42601 151 const m = obj.move;
f41ce580 152 query =
92b82def 153 "INSERT INTO Moves (gid, squares, message, played, idx) VALUES " +
f41ce580 154 "(" + id + ",'" + JSON.stringify(m.squares) + "','" + m.message +
92b82def 155 "'," + m.played + "," + m.idx + ")";
f41ce580
BA
156 db.run(query);
157 }
3d55deea
BA
158 });
159 },
160
ab4f4bf2
BA
161 remove: function(id)
162 {
163 db.parallelize(function() {
164 let query =
165 "DELETE FROM Games " +
166 "WHERE id = " + id;
167 db.run(query);
168 query =
169 "DELETE FROM Players " +
170 "WHERE gid = " + id;
171 db.run(query);
172 query =
173 "DELETE FROM Moves " +
174 "WHERE gid = " + id;
175 db.run(query);
176 });
177 },
d431028c
BA
178
179 cleanGamesDb: function()
180 {
181 const tsNow = Date.now();
182 // 86400000 = 24 hours in milliseconds
183 const day = 86400000;
184 db.serialize(function() {
185 let query =
186 "SELECT id,score " +
187 "FROM Games ";
188 db.all(query, (err,games) => {
189 games.forEach(g => {
190 query =
191 "SELECT max(played) AS lastMaj " +
192 "FROM Moves " +
193 "WHERE gid = " + g.id;
194 db.get(query, (err2,updated) {
195 if (!updated && tsNow - g.created > 7*day)
196 return GameModel.remove(g.id);
197 const lastMaj = updated.lastMaj;
198 if (g.score != "*" && tsNow - lastMaj > 7*day ||
199 g.score == "*" && tsNow - lastMaj > 91*day)
200 {
201 GameModel.remove(g.id);
202 }
203 });
204 });
205 });
206 });
207 },
00f2759e 208}
ab4f4bf2
BA
209
210module.exports = GameModel;