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