Commit | Line | Data |
---|---|---|
c5c47010 | 1 | const db = require("../utils/database"); |
58e7b94e | 2 | const UserModel = require("./User"); |
00f2759e BA |
3 | |
4 | /* | |
5 | * Structure table Games: | |
6 | * id: game id (int) | |
7 | * vid: integer (variant id) | |
ab4f4bf2 BA |
8 | * fenStart: varchar (initial position) |
9 | * fen: varchar (current position) | |
0234201f BA |
10 | * white: integer |
11 | * black: integer | |
71468011 | 12 | * cadence: string |
00f2759e | 13 | * score: varchar (result) |
dcd68c41 | 14 | * scoreMsg: varchar ("Time", "Mutual agreement"...) |
83494c7f | 15 | * created: datetime |
dfeb96ea | 16 | * drawOffer: char ('w','b' or '' for none) |
0234201f | 17 | * rematchOffer: char (similar to drawOffer) |
eb2d61de | 18 | * options: varchar |
0234201f BA |
19 | * deletedByWhite: boolean |
20 | * deletedByBlack: boolean | |
1ef65040 BA |
21 | * chatReadWhite: datetime |
22 | * chatReadBlack: datetime | |
00f2759e BA |
23 | * |
24 | * Structure table Moves: | |
ab4f4bf2 | 25 | * gid: ref game id |
f41ce580 | 26 | * squares: varchar (description) |
00f2759e BA |
27 | * played: datetime |
28 | * idx: integer | |
3837d4f7 BA |
29 | * |
30 | * Structure table Chats: | |
31 | * gid: game id (int) | |
32 | * msg: varchar | |
33 | * name: varchar | |
3837d4f7 | 34 | * added: datetime |
00f2759e BA |
35 | */ |
36 | ||
937c24ab BA |
37 | const GameModel = { |
38 | ||
58e7b94e | 39 | checkGameInfo: function(g) { |
866842c3 BA |
40 | return ( |
41 | g.vid.toString().match(/^[0-9]+$/) && | |
42 | g.cadence.match(/^[0-9dhms +]+$/) && | |
43 | g.fen.match(/^[a-zA-Z0-9, /-]*$/) && | |
44 | g.players.length == 2 && | |
f14572c4 | 45 | g.players.every(p => p.id.toString().match(/^[0-9]+$/)) |
866842c3 | 46 | ); |
58e7b94e BA |
47 | }, |
48 | ||
4a209313 BA |
49 | incrementCounter: function(vid, cb) { |
50 | db.serialize(function() { | |
51 | let query = | |
52 | "UPDATE GameStat " + | |
53 | "SET total = total + 1 " + | |
54 | "WHERE vid = " + vid; | |
55 | db.run(query, cb); | |
56 | }); | |
57 | }, | |
58 | ||
eb2d61de | 59 | create: function(vid, fen, options, cadence, players, cb) { |
dac39588 BA |
60 | db.serialize(function() { |
61 | let query = | |
71468011 | 62 | "INSERT INTO Games " + |
0234201f | 63 | "(" + |
eb2d61de | 64 | "vid, fenStart, fen, options, " + |
0234201f BA |
65 | "white, black, " + |
66 | "cadence, created" + | |
67 | ") " + | |
71468011 | 68 | "VALUES " + |
0234201f | 69 | "(" + |
eb2d61de | 70 | vid + ",'" + fen + "','" + fen + "',?," + |
f14572c4 | 71 | players[0].id + "," + players[1].id + "," + |
0234201f BA |
72 | "'" + cadence + "'," + Date.now() + |
73 | ")"; | |
eb2d61de | 74 | db.run(query, options, function(err) { |
f14572c4 | 75 | cb(err, { id: this.lastID }); |
dac39588 BA |
76 | }); |
77 | }); | |
78 | }, | |
00f2759e | 79 | |
71468011 | 80 | // TODO: some queries here could be async |
0234201f | 81 | getOne: function(id, cb) { |
866842c3 | 82 | // NOTE: ignoring errors (shouldn't happen at this stage) |
dac39588 | 83 | db.serialize(function() { |
dac39588 | 84 | let query = |
0234201f | 85 | "SELECT " + |
eaa5ad3e | 86 | "id, vid, fen, fenStart, cadence, created, " + |
eb2d61de | 87 | "white, black, options, score, scoreMsg, " + |
eaa5ad3e BA |
88 | "chatReadWhite, chatReadBlack, drawOffer, rematchOffer " + |
89 | "FROM Games " + | |
90 | "WHERE id = " + id; | |
aae89b49 | 91 | db.get(query, (err, gameInfo) => { |
f14572c4 BA |
92 | if (!gameInfo) { |
93 | cb(err || { errmsg: "Game not found" }, undefined); | |
94 | return; | |
95 | } | |
dac39588 | 96 | query = |
f14572c4 BA |
97 | "SELECT id, name " + |
98 | "FROM Users " + | |
99 | "WHERE id IN (" + gameInfo.white + "," + gameInfo.black + ")"; | |
100 | db.all(query, (err2, players) => { | |
101 | if (players[0].id == gameInfo.black) players = players.reverse(); | |
102 | // The original players' IDs info isn't required anymore | |
103 | delete gameInfo["white"]; | |
104 | delete gameInfo["black"]; | |
aae89b49 | 105 | query = |
f14572c4 BA |
106 | "SELECT squares, played, idx " + |
107 | "FROM Moves " + | |
aae89b49 | 108 | "WHERE gid = " + id; |
f14572c4 BA |
109 | db.all(query, (err3, moves) => { |
110 | query = | |
111 | "SELECT msg, name, added " + | |
112 | "FROM Chats " + | |
113 | "WHERE gid = " + id; | |
114 | db.all(query, (err4, chats) => { | |
115 | const game = Object.assign( | |
f14572c4 BA |
116 | { |
117 | players: players, | |
118 | moves: moves, | |
119 | chats: chats | |
eaa5ad3e BA |
120 | }, |
121 | gameInfo | |
f14572c4 BA |
122 | ); |
123 | cb(null, game); | |
124 | }); | |
aae89b49 | 125 | }); |
dac39588 BA |
126 | }); |
127 | }); | |
128 | }); | |
129 | }, | |
00f2759e | 130 | |
0234201f BA |
131 | // For display on Hall: no need for moves or chats |
132 | getObserved: function(uid, cursor, cb) { | |
133 | db.serialize(function() { | |
134 | let query = | |
3d9745ae | 135 | "SELECT id, vid, cadence, options, created, score, white, black " + |
6c7cbfed BA |
136 | "FROM Games " + |
137 | "WHERE created < " + cursor + " "; | |
138 | if (uid > 0) { | |
139 | query += | |
140 | " AND white <> " + uid + " " + | |
141 | " AND black <> " + uid + " "; | |
142 | } | |
0234201f BA |
143 | query += |
144 | "ORDER BY created DESC " + | |
145 | "LIMIT 20"; //TODO: 20 hard-coded... | |
146 | db.all(query, (err, games) => { | |
81b71035 | 147 | games = games || []; |
0234201f BA |
148 | // Query players names |
149 | let pids = {}; | |
150 | games.forEach(g => { | |
151 | if (!pids[g.white]) pids[g.white] = true; | |
152 | if (!pids[g.black]) pids[g.black] = true; | |
153 | }); | |
154 | UserModel.getByIds(Object.keys(pids), (err2, users) => { | |
81b71035 | 155 | users = users || []; |
0234201f BA |
156 | let names = {}; |
157 | users.forEach(u => { names[u.id] = u.name; }); | |
158 | cb( | |
f14572c4 | 159 | err, |
0234201f BA |
160 | games.map( |
161 | g => { | |
162 | return { | |
163 | id: g.id, | |
f14572c4 | 164 | vid: g.vid, |
0234201f | 165 | cadence: g.cadence, |
3d9745ae | 166 | options: g.options, |
0234201f BA |
167 | created: g.created, |
168 | score: g.score, | |
f14572c4 BA |
169 | players: [ |
170 | { id: g.white, name: names[g.white] }, | |
171 | { id: g.black, name: names[g.black] } | |
172 | ] | |
0234201f BA |
173 | }; |
174 | } | |
175 | ) | |
176 | ); | |
177 | }); | |
178 | }); | |
179 | }); | |
180 | }, | |
181 | ||
182 | // For display on MyGames: registered user only | |
183 | getRunning: function(uid, cb) { | |
184 | db.serialize(function() { | |
aae89b49 | 185 | let query = |
3d9745ae | 186 | "SELECT id, vid, cadence, options, created, white, black " + |
eaa5ad3e | 187 | "FROM Games " + |
f14572c4 | 188 | "WHERE score = '*' AND (white = " + uid + " OR black = " + uid + ")"; |
0234201f | 189 | db.all(query, (err, games) => { |
81b71035 | 190 | games = games || []; |
0234201f | 191 | // Get movesCount (could be done in // with next query) |
aae89b49 | 192 | query = |
0234201f BA |
193 | "SELECT gid, COUNT(*) AS nbMoves " + |
194 | "FROM Moves " + | |
195 | "WHERE gid IN " + "(" + games.map(g => g.id).join(",") + ") " + | |
196 | "GROUP BY gid"; | |
197 | db.all(query, (err, mstats) => { | |
198 | let movesCounts = {}; | |
199 | mstats.forEach(ms => { movesCounts[ms.gid] = ms.nbMoves; }); | |
200 | // Query player names | |
201 | let pids = {}; | |
202 | games.forEach(g => { | |
203 | if (!pids[g.white]) pids[g.white] = true; | |
204 | if (!pids[g.black]) pids[g.black] = true; | |
205 | }); | |
f14572c4 | 206 | UserModel.getByIds(Object.keys(pids), (err2, users) => { |
81b71035 | 207 | users = users || []; |
0234201f BA |
208 | let names = {}; |
209 | users.forEach(u => { names[u.id] = u.name; }); | |
210 | cb( | |
f14572c4 | 211 | null, |
0234201f BA |
212 | games.map( |
213 | g => { | |
214 | return { | |
215 | id: g.id, | |
d807470f | 216 | vid: g.vid, |
f14572c4 | 217 | cadence: g.cadence, |
3d9745ae | 218 | options: g.options, |
0234201f BA |
219 | created: g.created, |
220 | score: g.score, | |
f14572c4 BA |
221 | movesCount: movesCounts[g.id] || 0, |
222 | players: [ | |
223 | { id: g.white, name: names[g.white] }, | |
224 | { id: g.black, name: names[g.black] } | |
225 | ] | |
0234201f BA |
226 | }; |
227 | } | |
228 | ) | |
aae89b49 | 229 | ); |
aae89b49 BA |
230 | }); |
231 | }); | |
232 | }); | |
0234201f BA |
233 | }); |
234 | }, | |
235 | ||
236 | // These games could be deleted on some side. movesCount not required | |
237 | getCompleted: function(uid, cursor, cb) { | |
dac39588 | 238 | db.serialize(function() { |
0234201f | 239 | let query = |
3d9745ae | 240 | "SELECT id, vid, cadence, options, created, score, scoreMsg, " + |
eaa5ad3e BA |
241 | "white, black, deletedByWhite, deletedByBlack " + |
242 | "FROM Games " + | |
0234201f | 243 | "WHERE " + |
11589e7c BA |
244 | " score <> '*' AND" + |
245 | " created < " + cursor + " AND" + | |
0234201f | 246 | " (" + |
11589e7c BA |
247 | " (" + |
248 | " white = " + uid + " AND" + | |
249 | " (deletedByWhite IS NULL OR NOT deletedByWhite)" + | |
250 | " )" + | |
251 | " OR " + | |
252 | " (" + | |
253 | " black = " + uid + " AND" + | |
254 | " (deletedByBlack IS NULL OR NOT deletedByBlack)" + | |
255 | " )" + | |
0234201f BA |
256 | " ) "; |
257 | query += | |
258 | "ORDER BY created DESC " + | |
259 | "LIMIT 20"; | |
260 | db.all(query, (err, games) => { | |
81b71035 | 261 | games = games || []; |
0234201f BA |
262 | // Query player names |
263 | let pids = {}; | |
264 | games.forEach(g => { | |
265 | if (!pids[g.white]) pids[g.white] = true; | |
266 | if (!pids[g.black]) pids[g.black] = true; | |
267 | }); | |
f14572c4 | 268 | UserModel.getByIds(Object.keys(pids), (err2, users) => { |
81b71035 | 269 | users = users || []; |
0234201f BA |
270 | let names = {}; |
271 | users.forEach(u => { names[u.id] = u.name; }); | |
272 | cb( | |
f14572c4 | 273 | null, |
0234201f BA |
274 | games.map( |
275 | g => { | |
276 | return { | |
277 | id: g.id, | |
eaa5ad3e | 278 | vid: g.vid, |
f14572c4 | 279 | cadence: g.cadence, |
3d9745ae | 280 | options: g.options, |
0234201f BA |
281 | created: g.created, |
282 | score: g.score, | |
283 | scoreMsg: g.scoreMsg, | |
f14572c4 BA |
284 | players: [ |
285 | { id: g.white, name: names[g.white] }, | |
286 | { id: g.black, name: names[g.black] } | |
287 | ], | |
0234201f BA |
288 | deletedByWhite: g.deletedByWhite, |
289 | deletedByBlack: g.deletedByBlack | |
290 | }; | |
291 | } | |
292 | ) | |
293 | ); | |
294 | }); | |
dac39588 BA |
295 | }); |
296 | }); | |
297 | }, | |
ab4f4bf2 | 298 | |
0234201f | 299 | getPlayers: function(id, cb) { |
411d23cd BA |
300 | db.serialize(function() { |
301 | const query = | |
0234201f BA |
302 | "SELECT white, black " + |
303 | "FROM Games " + | |
f14572c4 BA |
304 | "WHERE id = " + id; |
305 | db.get(query, (err, players) => { | |
411d23cd BA |
306 | return cb(err, players); |
307 | }); | |
308 | }); | |
309 | }, | |
310 | ||
0234201f | 311 | checkGameUpdate: function(obj) { |
58e7b94e | 312 | // Check all that is possible (required) in obj: |
866842c3 BA |
313 | return ( |
314 | ( | |
8be8238c | 315 | !obj.move || !!(obj.move.idx.toString().match(/^[0-9]+$/)) |
866842c3 | 316 | ) && ( |
188b4a8f | 317 | !obj.drawOffer || !!(obj.drawOffer.match(/^[wbtn]$/)) |
c292ebb2 BA |
318 | ) && ( |
319 | !obj.rematchOffer || !!(obj.rematchOffer.match(/^[wbn]$/)) | |
866842c3 | 320 | ) && ( |
5c4ea2bb | 321 | !obj.fen || !!(obj.fen.match(/^[a-zA-Z0-9,.:{}\[\]" /-]*$/)) |
866842c3 | 322 | ) && ( |
188b4a8f | 323 | !obj.score || !!(obj.score.match(/^[012?*\/-]+$/)) |
1ef65040 | 324 | ) && ( |
077ba344 | 325 | !obj.chatRead || ['w','b'].includes(obj.chatRead) |
866842c3 | 326 | ) && ( |
188b4a8f | 327 | !obj.scoreMsg || !!(obj.scoreMsg.match(/^[a-zA-Z ]+$/)) |
866842c3 BA |
328 | ) && ( |
329 | !obj.chat || UserModel.checkNameEmail({name: obj.chat.name}) | |
330 | ) | |
331 | ); | |
58e7b94e BA |
332 | }, |
333 | ||
866842c3 | 334 | // obj can have fields move, chat, fen, drawOffer and/or score + message |
0234201f | 335 | update: function(id, obj, cb) { |
dac39588 | 336 | db.parallelize(function() { |
f14572c4 | 337 | let updateQuery = |
3d55deea BA |
338 | "UPDATE Games " + |
339 | "SET "; | |
3837d4f7 | 340 | let modifs = ""; |
633959bf | 341 | // NOTE: if drawOffer is set, we should check that it's player's turn |
dfeb96ea | 342 | // A bit overcomplicated. Let's trust the client on that for now... |
f14572c4 BA |
343 | if (!!obj.drawOffer) { |
344 | if (obj.drawOffer == "n") | |
345 | // Special "None" update | |
633959bf BA |
346 | obj.drawOffer = ""; |
347 | modifs += "drawOffer = '" + obj.drawOffer + "',"; | |
348 | } | |
f14572c4 BA |
349 | if (!!obj.rematchOffer) { |
350 | if (obj.rematchOffer == "n") | |
351 | // Special "None" update | |
c292ebb2 BA |
352 | obj.rematchOffer = ""; |
353 | modifs += "rematchOffer = '" + obj.rematchOffer + "',"; | |
354 | } | |
f14572c4 | 355 | if (!!obj.fen) modifs += "fen = '" + obj.fen + "',"; |
aae89b49 BA |
356 | if (!!obj.deletedBy) { |
357 | const myColor = obj.deletedBy == 'w' ? "White" : "Black"; | |
358 | modifs += "deletedBy" + myColor + " = true,"; | |
359 | } | |
1ef65040 BA |
360 | if (!!obj.chatRead) { |
361 | const myColor = obj.chatRead == 'w' ? "White" : "Black"; | |
362 | modifs += "chatRead" + myColor + " = " + Date.now() + ","; | |
363 | } | |
f14572c4 BA |
364 | if (!!obj.score) { |
365 | modifs += "score = '" + obj.score + "'," + | |
366 | "scoreMsg = '" + obj.scoreMsg + "',"; | |
3837d4f7 | 367 | } |
f14572c4 BA |
368 | const finishAndSendQuery = () => { |
369 | modifs = modifs.slice(0, -1); //remove last comma | |
370 | if (modifs.length > 0) { | |
371 | updateQuery += modifs + " WHERE id = " + id; | |
372 | db.run(updateQuery); | |
373 | } | |
374 | cb(null); | |
375 | }; | |
376 | if (!!obj.move || (!!obj.score && obj.scoreMsg == "Time")) { | |
377 | // Security: only update moves if index is right, | |
378 | // and score with scoreMsg "Time" if really lost on time. | |
379 | let query = | |
380 | "SELECT MAX(idx) AS maxIdx, MAX(played) AS lastPlayed " + | |
fb68b0c2 BA |
381 | "FROM Moves " + |
382 | "WHERE gid = " + id; | |
f14572c4 BA |
383 | db.get(query, (err, ret) => { |
384 | if (!!obj.move ) { | |
385 | if (!ret.maxIdx || ret.maxIdx + 1 == obj.move.idx) { | |
386 | query = | |
387 | "INSERT INTO Moves (gid, squares, played, idx) VALUES " + | |
388 | "(" + id + ",?," + Date.now() + "," + obj.move.idx + ")"; | |
389 | db.run(query, JSON.stringify(obj.move.squares)); | |
390 | finishAndSendQuery(); | |
58aedcd1 BA |
391 | } |
392 | else cb({ errmsg: "Wrong move index" }); | |
393 | } | |
394 | else { | |
f14572c4 BA |
395 | if (ret.maxIdx < 2) cb({ errmsg: "Time not over" }); |
396 | else { | |
397 | // We also need the game cadence | |
398 | query = | |
399 | "SELECT cadence " + | |
400 | "FROM Games " + | |
401 | "WHERE id = " + id; | |
402 | db.get(query, (err2, ret2) => { | |
1112f1fd | 403 | const daysTc = parseInt(ret2.cadence.match(/^[0-9]+/)[0]); |
f14572c4 BA |
404 | if (Date.now() - ret.lastPlayed > daysTc * 24 * 3600 * 1000) |
405 | finishAndSendQuery(); | |
406 | else cb({ errmsg: "Time not over" }); | |
407 | }); | |
408 | } | |
fb68b0c2 | 409 | } |
fb68b0c2 | 410 | }); |
58aedcd1 BA |
411 | } |
412 | else finishAndSendQuery(); | |
f14572c4 BA |
413 | // NOTE: chat and delchat are mutually exclusive |
414 | if (!!obj.chat) { | |
415 | const query = | |
dac39588 | 416 | "INSERT INTO Chats (gid, msg, name, added) VALUES (" |
41c80bb6 | 417 | + id + ",?,'" + obj.chat.name + "'," + Date.now() + ")"; |
58e7b94e | 418 | db.run(query, obj.chat.msg); |
58aedcd1 BA |
419 | } |
420 | else if (obj.delchat) { | |
f14572c4 | 421 | const query = |
db1f1f9a BA |
422 | "DELETE " + |
423 | "FROM Chats " + | |
424 | "WHERE gid = " + id; | |
23ecf008 | 425 | db.run(query); |
db1f1f9a | 426 | } |
aae89b49 BA |
427 | if (!!obj.deletedBy) { |
428 | // Did my opponent delete it too? | |
429 | let selection = | |
430 | "deletedBy" + | |
431 | (obj.deletedBy == 'w' ? "Black" : "White") + | |
432 | " AS deletedByOpp"; | |
f14572c4 | 433 | const query = |
aae89b49 BA |
434 | "SELECT " + selection + " " + |
435 | "FROM Games " + | |
436 | "WHERE id = " + id; | |
437 | db.get(query, (err,ret) => { | |
438 | // If yes: just remove game | |
439 | if (!!ret.deletedByOpp) GameModel.remove(id); | |
440 | }); | |
441 | } | |
3d55deea BA |
442 | }); |
443 | }, | |
444 | ||
0234201f BA |
445 | remove: function(id_s) { |
446 | const suffix = | |
447 | Array.isArray(id_s) | |
448 | ? " IN (" + id_s.join(",") + ")" | |
449 | : " = " + id_s; | |
dac39588 BA |
450 | db.parallelize(function() { |
451 | let query = | |
452 | "DELETE FROM Games " + | |
0234201f | 453 | "WHERE id " + suffix; |
dac39588 BA |
454 | db.run(query); |
455 | query = | |
456 | "DELETE FROM Moves " + | |
0234201f | 457 | "WHERE gid " + suffix; |
dac39588 BA |
458 | db.run(query); |
459 | query = | |
460 | "DELETE FROM Chats " + | |
0234201f | 461 | "WHERE gid " + suffix; |
dac39588 BA |
462 | db.run(query); |
463 | }); | |
464 | }, | |
d431028c | 465 | |
0234201f | 466 | cleanGamesDb: function() { |
d431028c BA |
467 | const tsNow = Date.now(); |
468 | // 86400000 = 24 hours in milliseconds | |
469 | const day = 86400000; | |
470 | db.serialize(function() { | |
471 | let query = | |
7ec05c0e | 472 | "SELECT id, created, cadence, score " + |
0234201f BA |
473 | "FROM Games"; |
474 | db.all(query, (err, games) => { | |
475 | query = | |
476 | "SELECT gid, count(*) AS nbMoves, MAX(played) AS lastMaj " + | |
477 | "FROM Moves " + | |
478 | "GROUP BY gid"; | |
6f2f9437 | 479 | db.all(query, (err2, mstats) => { |
0234201f BA |
480 | // Reorganize moves data to avoid too many array lookups: |
481 | let movesGroups = {}; | |
482 | mstats.forEach(ms => { | |
483 | movesGroups[ms.gid] = { | |
484 | nbMoves: ms.nbMoves, | |
485 | lastMaj: ms.lastMaj | |
486 | }; | |
487 | }); | |
488 | // Remove games still not really started, | |
7ec05c0e | 489 | // with no action in the last 2 weeks, or result != '*': |
0234201f | 490 | let toRemove = []; |
7ec05c0e | 491 | let lostOnTime = [ [], [] ]; |
0234201f BA |
492 | games.forEach(g => { |
493 | if ( | |
494 | ( | |
495 | !movesGroups[g.id] && | |
7ec05c0e | 496 | (g.score != '*' || tsNow - g.created > 14*day) |
0234201f BA |
497 | ) |
498 | || | |
499 | ( | |
b49527c4 | 500 | !!movesGroups[g.id] && |
0234201f | 501 | movesGroups[g.id].nbMoves == 1 && |
7ec05c0e | 502 | (g.score != '*' || tsNow - movesGroups[g.id].lastMaj > 14*day) |
0234201f BA |
503 | ) |
504 | ) { | |
505 | toRemove.push(g.id); | |
d431028c | 506 | } |
7ec05c0e BA |
507 | // Set score if lost on time and >= 2 moves: |
508 | else if ( | |
b5ead37a | 509 | g.score == '*' && |
7ec05c0e BA |
510 | !!movesGroups[g.id] && |
511 | movesGroups[g.id].nbMoves >= 2 && | |
512 | tsNow - movesGroups[g.id].lastMaj > | |
513 | // cadence in days * nb seconds per day: | |
514 | parseInt(g.cadence.slice(0, -1), 10) * day | |
515 | ) { | |
516 | lostOnTime[movesGroups[g.id].nbMoves % 2].push(g.id); | |
517 | } | |
d431028c | 518 | }); |
0234201f | 519 | if (toRemove.length > 0) GameModel.remove(toRemove); |
7ec05c0e BA |
520 | if (lostOnTime.some(l => l.length > 0)) { |
521 | db.parallelize(function() { | |
522 | for (let i of [0, 1]) { | |
523 | if (lostOnTime[i].length > 0) { | |
524 | const score = (i == 0 ? "0-1" : "1-0"); | |
525 | const query = | |
526 | "UPDATE Games " + | |
527 | "SET score = '" + score + "', scoreMsg = 'Time' " + | |
528 | "WHERE id IN (" + lostOnTime[i].join(',') + ")"; | |
529 | db.run(query); | |
530 | } | |
531 | } | |
532 | }); | |
533 | } | |
d431028c BA |
534 | }); |
535 | }); | |
536 | }); | |
0234201f | 537 | } |
937c24ab BA |
538 | |
539 | }; | |
ab4f4bf2 BA |
540 | |
541 | module.exports = GameModel; |