-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdatabase_persistence.rb
More file actions
458 lines (386 loc) · 15 KB
/
database_persistence.rb
File metadata and controls
458 lines (386 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
require 'pg'
module Filterable
private
def summary_unfiltered
sql = <<~SQL
SELECT (SELECT COUNT(place) FROM matches WHERE place = 1 AND player_id = $1) AS wins,
ROUND(AVG(matches.place)) AS avg_place, SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims, SUM(place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN match_types ON matches.match_type_id = match_types.id
JOIN seasons ON matches.season_id = seasons.id
WHERE players.id = $1
GROUP BY players.username
ORDER BY points;
SQL
end
def summary_filtered_season_type
sql = <<~SQL
SELECT (SELECT COUNT(place) FROM matches WHERE place = 1 AND player_id = $1 AND
season_id = $2 AND match_type_id = $3) AS wins,
ROUND(AVG(matches.place)) AS avg_place, SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims, SUM(place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN match_types ON matches.match_type_id = match_types.id
JOIN seasons ON matches.season_id = seasons.id
WHERE players.id = $1 AND seasons.id = $2 AND match_types.id = $3
GROUP BY players.username
ORDER BY points;
SQL
end
def summary_filtered_season
sql = <<~SQL
SELECT (SELECT COUNT(place) FROM matches WHERE place = 1 AND player_id = $1 AND
season_id = $2) AS wins,
ROUND(AVG(matches.place)) AS avg_place, SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims, SUM(place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN match_types ON matches.match_type_id = match_types.id
JOIN seasons ON matches.season_id = seasons.id
WHERE players.id = $1 AND seasons.id = $2
GROUP BY players.username
ORDER BY points;
SQL
end
def summary_filtered_type
sql = <<~SQL
SELECT (SELECT COUNT(place) FROM matches WHERE place = 1 AND player_id = $1 AND
match_type_id = $2) AS wins,
ROUND(AVG(matches.place)) AS avg_place, SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims, SUM(place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN match_types ON matches.match_type_id = match_types.id
JOIN seasons ON matches.season_id = seasons.id
WHERE players.id = $1 AND match_types.id = $2
GROUP BY players.username
ORDER BY points;
SQL
end
def match_unfiltered
sql = <<~SQL
SELECT (EXTRACT(month from date_played) || '/' || EXTRACT(day FROM date_played) || '/' || EXTRACT(year FROM date_played)) AS date,
(SELECT COUNT(matches.id) FROM matches WHERE player_id = $1) AS entries,
matches.place AS place, matches.elims AS elims, match_types.match_type AS type, (place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN seasons ON matches.season_id = seasons.id
JOIN match_types ON matches.match_type_id = match_types.id
WHERE players.id = $1
ORDER BY date_played
LIMIT 10 OFFSET $2;
SQL
end
def match_filtered_type
sql = <<~SQL
SELECT (EXTRACT(month from date_played) || '/' || EXTRACT(day FROM date_played) || '/' || EXTRACT(year FROM date_played)) AS date,
(SELECT COUNT(matches.id) FROM matches WHERE player_id = $1 AND match_type_id = $2) AS entries,
matches.place AS place, matches.elims AS elims, match_types.match_type AS type, (place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN seasons ON matches.season_id = seasons.id
JOIN match_types ON matches.match_type_id = match_types.id
WHERE players.id = $1 AND match_types.id = $2
ORDER BY date_played
LIMIT 10 OFFSET $3;
SQL
end
def match_filtered_season
sql = <<~SQL
SELECT (EXTRACT(month from date_played) || '/' || EXTRACT(day FROM date_played) || '/' || EXTRACT(year FROM date_played)) AS date,
(SELECT COUNT(matches.id) FROM matches WHERE player_id = $1 AND season_id = $2) AS entries,
matches.place AS place, matches.elims AS elims, match_types.match_type AS type, (place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN seasons ON matches.season_id = seasons.id
JOIN match_types ON matches.match_type_id = match_types.id
WHERE players.id = $1 AND seasons.id = $2
ORDER BY date_played
LIMIT 10 OFFSET $3;
SQL
end
def match_filtered_season_type
sql = <<~SQL
SELECT (EXTRACT(month from date_played) || '/' || EXTRACT(day FROM date_played) || '/' || EXTRACT(year FROM date_played)) AS date,
(SELECT COUNT(matches.id) FROM matches
WHERE player_id = $1 AND season_id = $2 AND match_type_id = $3) AS entries,
matches.place AS place, matches.elims AS elims, match_types.match_type AS type, (place_points + elim_points) AS points
FROM matches JOIN players ON matches.player_id = players.id
JOIN seasons ON matches.season_id = seasons.id
JOIN match_types ON matches.match_type_id = match_types.id
WHERE players.id = $1 AND seasons.id = $2 AND match_types.id = $3
ORDER BY date_played
LIMIT 10 OFFSET $4;
SQL
end
def leaderboard_unfiltered
sql = <<~SQL
SELECT matches.player_id, players.username AS user,
SUM(place_points + elim_points) AS points,
(SELECT winners FROM (SELECT player_id, COUNT(place) AS winners FROM matches WHERE place = 1 GROUP BY player_id) AS win_count WHERE win_count.player_id = matches.player_id) AS wins,
ROUND(AVG(matches.place)) AS avg_place,
SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims,
COUNT(matches.player_id) AS played
FROM players JOIN matches ON players.id = matches.player_id
GROUP BY players.username, matches.player_id;
SQL
end
def leaderboard_filtered_type
sql = <<~SQL
SELECT matches.player_id, players.username AS user,
SUM(place_points + elim_points) AS points,
(SELECT winners FROM (SELECT player_id, COUNT(place) AS winners FROM matches WHERE place = 1 AND match_type_id = $1 GROUP BY player_id) AS win_count WHERE win_count.player_id = matches.player_id) AS wins,
ROUND(AVG(matches.place)) AS avg_place,
SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims,
COUNT(matches.player_id) AS played
FROM players JOIN matches ON players.id = matches.player_id
WHERE match_type_id = $1
GROUP BY players.username, matches.player_id;
SQL
end
def leaderboard_filtered_season
sql = <<~SQL
SELECT matches.player_id, players.username AS user,
SUM(place_points + elim_points) AS points,
(SELECT winners FROM (SELECT player_id, COUNT(place) AS winners FROM matches WHERE place = 1 AND season_id = $1 GROUP BY player_id) AS win_count WHERE win_count.player_id = matches.player_id) AS wins,
ROUND(AVG(matches.place)) AS avg_place,
SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims,
COUNT(matches.player_id) AS played
FROM players JOIN matches ON players.id = matches.player_id
WHERE season_id = $1
GROUP BY players.username, matches.player_id;
SQL
end
def leaderboard_filtered_season_type
sql = <<~SQL
SELECT matches.player_id, players.username AS user,
SUM(place_points + elim_points) AS points,
(SELECT winners FROM (SELECT player_id, COUNT(place) AS winners FROM matches WHERE place = 1 AND season_id = $1 AND match_type_id = $2 GROUP BY player_id) AS win_count WHERE win_count.player_id = matches.player_id) AS wins,
ROUND(AVG(matches.place)) AS avg_place,
SUM(matches.elims) AS elims,
ROUND(AVG(matches.elims)) AS avg_elims,
COUNT(matches.player_id) AS played
FROM players JOIN matches ON players.id = matches.player_id
WHERE season_id = $1 AND match_type_id = $2
GROUP BY players.username, matches.player_id;
SQL
end
end
module Hashable
private
def last_ten_hash(tuple)
{ username: tuple['username'],
place: tuple['place'].to_i,
elims: tuple['elims'].to_i,
match_type: tuple['match_type'].capitalize,
points: tuple['points'].to_i }
end
def summary_hash(tuple)
{ wins: tuple['wins'],
avg_place: tuple['avg_place'],
elims: tuple['elims'],
avg_elims: tuple['avg_elims'],
points: tuple['points'] }
end
def match_hash(tuple)
{ date: tuple['date'],
place: tuple['place'],
elims: tuple['elims'],
type: tuple['type'],
points: tuple['points'],
entries: tuple['entries'].to_i }
end
def leaderboard_hash(tuple)
{ user: tuple['user'],
points: tuple['points'].to_i,
wins: tuple['wins'].to_i,
avg_place: tuple['avg_place'].to_i,
elims: tuple['elims'].to_i,
avg_elims: tuple['avg_elims'].to_i,
played: tuple['played'].to_i }
end
end
class DatabasePersistence
include Filterable
include Hashable
def initialize
@db = connect_to_database
end
def disconnect
db.close
end
def query(statement, *params)
db.exec_params(statement, params)
end
def get_users
sql = <<~SQL
SELECT username, pass, question FROM players;
SQL
result = query(sql)
result.map do |tuple|
{ username: tuple['username'], pass: tuple['pass'], question: tuple['question'] }
end
end
def add_new_player(username, password, question)
sql = <<~SQL
INSERT INTO players (username, pass, question)
VALUES ($1, $2, $3);
SQL
query(sql, username, password, question)
end
def get_last_ten
sql = <<~SQL
SELECT players.username, matches.place, matches.elims, match_types.match_type,
(matches.elim_points + matches.place_points) AS points
FROM players JOIN matches ON players.id = matches.player_id
JOIN match_types ON match_types.id = matches.match_type_id
ORDER BY matches.date_played DESC
LIMIT 10;
SQL
result = query(sql)
result.map do |tuple|
last_ten_hash(tuple)
end
end
def update_password(username, password)
sql = <<~SQL
UPDATE players SET pass = $1
WHERE username = $2;
SQL
query(sql, password, username)
end
def get_season
sql = 'SELECT season FROM seasons WHERE active = true;'
result = query(sql)
result.map { |tuple| tuple['season'] }.first
end
def get_seasons
sql = 'SELECT season, active FROM seasons ORDER BY season ASC;'
result = query(sql)
result.map { |tuple| {number: tuple['season'], active: tuple['active']} }
end
def is_admin?(user)
sql = 'SELECT admin FROM players WHERE username = $1;'
result = query(sql, user)
admin = result.map { |tuple| {admin: tuple['admin']} }
admin.first[:admin] == 't'
end
def get_summary(user, season, type)
user_id = get_user_id(user)
season_id = get_season_id(season)
type_id = get_type_id(type)
if season == 'all' && type == 'combined'
sql = summary_unfiltered
result = query(sql, user_id)
elsif season == 'all'
sql = summary_filtered_type
result = query(sql, user_id, type_id)
elsif type == 'combined'
sql = summary_filtered_season
result = query(sql, user_id, season_id)
else
sql = summary_filtered_season_type
result = query(sql, user_id, season_id, type_id)
end
result.map { |tuple| summary_hash(tuple) }
end
def get_match(user, season, type, offset)
user_id = get_user_id(user)
season_id = get_season_id(season)
type_id = get_type_id(type)
if season == 'all' && type == 'combined'
sql = match_unfiltered
result = query(sql, user_id, offset)
elsif season == 'all'
sql = match_filtered_type
result = query(sql, user_id, type_id, offset)
elsif type == 'combined'
sql = match_filtered_season
result = query(sql, user_id, season_id, offset)
else
sql = match_filtered_season_type
result = query(sql, user_id, season_id, type_id, offset)
end
result.map { |tuple| match_hash(tuple) }
end
def get_elim_points
sql = 'SELECT point_value FROM elim_points;'
result = query(sql)
result.map { |tuple| tuple['point_value'] }.first.to_i
end
def get_place_points(place)
sql = 'SELECT point_value FROM place_points WHERE ($1)::integer <@ place;'
result = query(sql, place.to_i)
result.map { |tuple| tuple['point_value'] }.first.to_i
end
def add_stats(user, type, season, place_points, elim_points, place, elims)
user_id = get_user_id(user)
type_id = get_type_id(type)
season_id = get_season_id(season)
sql = <<~SQL
INSERT INTO matches (player_id, match_type_id, season_id, place_points,
elim_points, place, elims) VALUES ($1, $2, $3, $4, $5, $6, $7);
SQL
result = query(sql, user_id, type_id, season_id, place_points, elim_points, place, elims)
end
def update_active_season(season)
deactivate_sql = 'UPDATE seasons SET active = false;'
activate_sql = 'UPDATE seasons SET active = true WHERE season = $1;'
query(deactivate_sql)
query(activate_sql, season)
end
def add_new_season(season)
sql = 'INSERT INTO seasons (season) VALUES ($1);'
query(sql, season)
end
def get_all_players
sql = 'SELECT username FROM players;'
result = query(sql)
result.map { |tuple| {name: tuple['username']} }
end
def get_leaderboard_stats(type, season)
season_id = get_season_id(season)
type_id = get_type_id(type)
if season == 'all' && type == 'combined'
sql = leaderboard_unfiltered
result = query(sql)
elsif season == 'all'
sql = leaderboard_filtered_type
result = query(sql, type_id)
elsif type == 'combined'
sql = leaderboard_filtered_season
result = query(sql, season_id)
else
sql = leaderboard_filtered_season_type
result = query(sql, season_id, type_id)
end
result.map do |tuple|
leaderboard_hash(tuple)
end
end
private #-----------------------------------------------------------------------------------------
attr_reader :db
def connect_to_database
if Sinatra::Base.production?
PG.connect(ENV['DATABASE_URL'])
else
PG.connect(dbname: "fort_test")
end
end
def get_user_id(user)
sql = 'SELECT id FROM players WHERE username = $1;'
result = query(sql, user)
result.map { |tuple| {id: tuple['id']} }.first[:id]
end
def get_season_id(season)
return 0 if season == 'all'
sql = 'SELECT id FROM seasons WHERE season = $1;'
result = query(sql, season)
result.map { |tuple| {id: tuple['id']} }.first[:id]
end
def get_type_id(type)
return 0 if type == 'combined'
sql = 'SELECT id FROM match_types WHERE match_type = $1;'
result = query(sql, type)
result.map { |tuple| {id: tuple['id']} }.first[:id]
end
end