vlr-stats-scraper 1.4.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/main.mjs CHANGED
@@ -1,91 +1,166 @@
1
1
  #!/usr/bin/env node
2
- import promptSync from 'prompt-sync';
3
- import { scrapeWebsite } from './scripts/player-link-scraper.mjs';
4
- import scrapePlayer from './scripts/player-info-scraper.mjs';
2
+ import promptSync from 'prompt-sync'
3
+ import { scrapeWebsite } from './scripts/player-link-scraper.mjs'
4
+ import scrapePlayer from './scripts/player-info-scraper.mjs'
5
5
  import {
6
6
  savePlayer,
7
7
  saveEvent,
8
- addPlayerToEvent,
9
8
  getEventByName,
9
+ getEventId,
10
+ getPlayersByEvent,
10
11
  emptyEvent,
11
12
  clearEvent,
12
13
  clearDatabase,
13
- } from './scripts/db.mjs';
14
+ searchPlayers,
15
+ } from './scripts/db.mjs'
14
16
 
15
- const args = process.argv.slice(2);
17
+ const args = process.argv.slice(2)
18
+
19
+ function printPlayerStats(player) {
20
+ // Players saved from the database belong to an event; ones scraped live don't.
21
+ const event = player.event_name ? ` (${player.event_name}${player.event_year ? `, ${player.event_year}` : ''})` : ''
22
+ console.log(`\n${player.name}${event}`)
23
+ console.log(` Team: ${player.team ?? 'Free agent'}`)
24
+ console.log(` Past teams: ${player.past_teams?.length ? player.past_teams.join(', ') : 'None'}`)
25
+ console.log(` Nationality: ${player.nationality || 'Unknown'}`)
26
+ console.log(` Region: ${player.region ?? 'Unknown'}`)
27
+ console.log(` Winnings: ${player.winnings ?? 'Unknown'}`)
28
+ // Older saves stored agents as raw <img> tags, so pull the name out of the alt text.
29
+ const agents = (player.most_played_agents ?? []).map(agent => agent?.match(/alt="([^"]*)"/)?.[1] ?? agent)
30
+ console.log(` Top agents: ${agents.join(', ') || 'None'}`)
31
+ console.log(` Avg K:D: ${Number(player.avg_kda).toFixed(2)}`)
32
+ if (player.stats?.length) {
33
+ console.table(player.stats)
34
+ }
35
+ }
36
+
37
+ // Manually adds one player to an event that's already saved.
38
+ if (args[0] === '--player') {
39
+ const [, query, eventName, eventYear, regionArg] = args
40
+ if (!query?.startsWith('http') || !eventName || !eventYear) {
41
+ console.error('Usage: valstats --player <vlr.gg player link> <event-name> <year> [region]')
42
+ process.exit(1)
43
+ }
44
+
45
+ // Look the event up before scraping so a typo doesn't waste a scrape.
46
+ const eventId = getEventId(eventName, parseInt(eventYear, 10))
47
+ if (!eventId) {
48
+ console.error(`No event named "${eventName}" (${eventYear}) in players.db`)
49
+ process.exit(1)
50
+ }
51
+
52
+ // Without a region argument, use the region the event's other players were saved with.
53
+ const region = regionArg ?? getPlayersByEvent(eventName)[0]?.region ?? null
54
+
55
+ const url = query.includes('timespan=') ? query : query.replace(/\/?$/, '/?timespan=all')
56
+ const player = await scrapePlayer(url, region)
57
+ if (!player) {
58
+ console.error(`Couldn't scrape a player from ${query}`)
59
+ process.exit(1)
60
+ }
61
+ savePlayer(eventId, player)
62
+ console.log(`Saved ${player.name} to players.db under "${eventName}" (${eventYear})`)
63
+ printPlayerStats(player)
64
+ process.exit(0)
65
+ }
66
+
67
+ if (args[0] === '--search') {
68
+ const query = args[1]
69
+ if (!query) {
70
+ console.error('Usage: valstats --search <name | vlr.gg player link>')
71
+ process.exit(1)
72
+ }
73
+
74
+ // A vlr.gg link is scraped live anything else is searched for in players.db.
75
+ if (query.startsWith('http')) {
76
+ const url = query.includes('timespan=') ? query : query.replace(/\/?$/, '/?timespan=all')
77
+ const player = await scrapePlayer(url, null)
78
+ if (!player) {
79
+ console.error(`Couldn't scrape a player from ${query}`)
80
+ process.exit(1)
81
+ }
82
+ printPlayerStats(player)
83
+ process.exit(0)
84
+ }
85
+
86
+ const players = searchPlayers(query)
87
+ if (!players.length) {
88
+ console.error(`No players matching "${query}" in players.db (pass a vlr.gg player link to scrape them live)`)
89
+ process.exit(1)
90
+ }
91
+ console.log(`${players.length} player${players.length === 1 ? '' : 's'} matching "${query}":`)
92
+ players.forEach(printPlayerStats)
93
+ process.exit(0)
94
+ }
16
95
 
17
96
  if (args[0] === '--clear') {
18
- const prompt = promptSync();
19
- const answer = prompt('This deletes every event and player in players.db. Type "yes" to continue: ');
97
+ const prompt = promptSync()
98
+ const answer = prompt('This deletes every event and player in players.db. Type "yes" to continue: ')
20
99
  if (answer?.trim().toLowerCase() === 'yes') {
21
- clearDatabase();
22
- console.log('Cleared players.db');
100
+ clearDatabase()
101
+ console.log('Cleared players.db')
23
102
  } else {
24
- console.log('Cancelled');
103
+ console.log('Cancelled')
25
104
  }
26
- process.exit(0);
105
+ process.exit(0)
27
106
  }
28
107
 
29
108
  if (args[0] === '--clear-event') {
30
- const name = args[1];
109
+ const name = args[1]
31
110
  if (!name) {
32
- console.error('Usage: valstats --clear-event <event-name>');
33
- process.exit(1);
111
+ console.error('Usage: valstats --clear-event <event-name>')
112
+ process.exit(1)
34
113
  }
35
114
  if (clearEvent(name)) {
36
- console.log(`Removed "${name}" and its players from players.db`);
115
+ console.log(`Removed "${name}" and its players from players.db`)
37
116
  } else {
38
- console.error(`No event named "${name}" in players.db`);
39
- process.exit(1);
117
+ console.error(`No event named "${name}" in players.db`)
118
+ process.exit(1)
40
119
  }
41
- process.exit(0);
120
+ process.exit(0)
42
121
  }
43
122
 
44
- const [link, year, eventName] = args;
123
+ const [link, year, eventName] = args
45
124
 
46
125
  if (!link || !year || !eventName) {
47
- console.error('Usage: valstats <link> <year> <event-name>');
48
- console.error(' valstats --clear-event <event-name>');
49
- console.error(' valstats --clear');
50
- process.exit(1);
126
+ console.error('Usage: valstats <link> <year> <event-name>')
127
+ console.error(' valstats --player <vlr.gg player link> <event-name> <year> [region]')
128
+ console.error(' valstats --search <name | vlr.gg player link>')
129
+ console.error(' valstats --clear-event <event-name>')
130
+ console.error(' valstats --clear')
131
+ process.exit(1)
51
132
  }
52
133
 
53
- const isStage = eventName.toLowerCase().includes('stage');
134
+ // Scrape first so a failed scrape doesn't wipe an event that's already saved.
135
+ const scraped = await scrapeWebsite(link)
54
136
 
55
- let region = null;
56
- if (isStage) {
57
- const prompt = promptSync();
58
- region = prompt('Enter the region: ');
137
+ if (!scraped) {
138
+ console.error(`Couldn't get the player list from ${link}`)
139
+ process.exit(1)
59
140
  }
60
141
 
142
+ const { playerLinks, region } = scraped
143
+ console.log(`Found ${playerLinks.length} players, region: ${region ?? 'unknown'}`)
144
+
61
145
  // Re-adding an event + year that's already saved replaces its old players.
62
- const existing = getEventByName(eventName);
146
+ const existing = getEventByName(eventName)
63
147
  if (existing && existing.year === parseInt(year, 10)) {
64
- emptyEvent(eventName);
65
- console.log(`"${eventName}" (${year}) is already in players.db, replacing it`);
148
+ emptyEvent(eventName)
149
+ console.log(`"${eventName}" (${year}) is already in players.db, replacing it`)
66
150
  }
67
151
 
68
152
  const eventId = saveEvent({
69
153
  name: eventName,
70
154
  url: link,
71
- region,
72
155
  year: parseInt(year, 10),
73
156
  stage: null,
74
- });
75
-
76
- const links = await scrapeWebsite(link);
77
-
78
- if (!links) {
79
- console.error(`Couldn't get the player list from ${link}`);
80
- process.exit(1);
81
- }
157
+ })
82
158
 
83
- for (const playerLink of links) {
84
- const player = await scrapePlayer(playerLink, region);
159
+ for (const playerLink of playerLinks) {
160
+ const player = await scrapePlayer(playerLink, region)
85
161
  if (player) {
86
- savePlayer(player);
87
- addPlayerToEvent(eventId, player.name);
88
- console.log(`Saved ${player.name} to players.db under "${eventName}"`);
89
- console.log(player);
162
+ savePlayer(eventId, player)
163
+ console.log(`Saved ${player.name} to players.db under "${eventName}"`)
164
+ console.log(player)
90
165
  }
91
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vlr-stats-scraper",
3
- "version": "1.4.1",
3
+ "version": "2.0.0",
4
4
  "description": "Scrapes player stats from vlr.gg and stores them in a local SQLite database, grouped by tournament or stage.",
5
5
  "homepage": "https://github.com/OverYander/VLR-Webscraper#readme",
6
6
  "bugs": {
package/scripts/db.mjs CHANGED
@@ -1,34 +1,16 @@
1
- import Database from 'better-sqlite3';
2
- import path from 'path';
1
+ import Database from 'better-sqlite3'
2
+ import path from 'path'
3
3
 
4
- const db = new Database(path.join(process.cwd(), 'players.db'));
4
+ const db = new Database(path.join(process.cwd(), 'players.db'))
5
+ db.pragma('foreign_keys = ON')
5
6
 
6
- db.exec(`
7
- CREATE TABLE IF NOT EXISTS players (
8
- name TEXT PRIMARY KEY,
9
- team TEXT,
10
- past_teams TEXT,
11
- winnings TEXT,
12
- most_played_agents TEXT,
13
- avg_kda REAL,
14
- nationality TEXT,
15
- region TEXT,
16
- stats TEXT
17
- )
18
- `);
19
-
20
- const existingPlayerColumns = db.prepare('PRAGMA table_info(players)').all().map(col => col.name);
21
- if (!existingPlayerColumns.includes('stats')) {
22
- db.exec('ALTER TABLE players ADD COLUMN stats TEXT');
23
- }
24
-
25
- const existingTableNames = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all().map(t => t.name);
7
+ const existingTableNames = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all().map(t => t.name)
26
8
  if (existingTableNames.includes('tournaments') && !existingTableNames.includes('events')) {
27
- db.exec('ALTER TABLE tournaments RENAME TO events');
9
+ db.exec('ALTER TABLE tournaments RENAME TO events')
28
10
  }
29
11
  if (existingTableNames.includes('tournament_players') && !existingTableNames.includes('event_players')) {
30
- db.exec('ALTER TABLE tournament_players RENAME TO event_players');
31
- db.exec('ALTER TABLE event_players RENAME COLUMN tournament_id TO event_id');
12
+ db.exec('ALTER TABLE tournament_players RENAME TO event_players')
13
+ db.exec('ALTER TABLE event_players RENAME COLUMN tournament_id TO event_id')
32
14
  }
33
15
 
34
16
  db.exec(`
@@ -36,32 +18,72 @@ db.exec(`
36
18
  id INTEGER PRIMARY KEY AUTOINCREMENT,
37
19
  name TEXT UNIQUE NOT NULL,
38
20
  url TEXT,
39
- region TEXT,
40
21
  year INTEGER,
41
22
  stage INTEGER
42
23
  )
43
- `);
24
+ `)
44
25
 
45
- const existingEventColumns = db.prepare('PRAGMA table_info(events)').all().map(col => col.name);
26
+ const existingEventColumns = db.prepare('PRAGMA table_info(events)').all().map(col => col.name)
46
27
  if (!existingEventColumns.includes('year')) {
47
- db.exec('ALTER TABLE events ADD COLUMN year INTEGER');
28
+ db.exec('ALTER TABLE events ADD COLUMN year INTEGER')
48
29
  }
49
30
  if (!existingEventColumns.includes('stage')) {
50
- db.exec('ALTER TABLE events ADD COLUMN stage INTEGER');
31
+ db.exec('ALTER TABLE events ADD COLUMN stage INTEGER')
32
+ }
33
+ // Region is stored on each player, not on the event.
34
+ if (existingEventColumns.includes('region')) {
35
+ db.exec('ALTER TABLE events DROP COLUMN region')
51
36
  }
52
37
 
53
- db.exec(`
54
- CREATE TABLE IF NOT EXISTS event_players (
55
- event_id INTEGER NOT NULL REFERENCES events(id),
56
- player_name TEXT NOT NULL REFERENCES players(name),
57
- PRIMARY KEY (event_id, player_name)
38
+ // Each row is a player as they were in one event, so the same player can have a row per event
39
+ // with different stats.
40
+ const createPlayersTableSql = (tableName) => `
41
+ CREATE TABLE IF NOT EXISTS ${tableName} (
42
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43
+ event_id INTEGER NOT NULL REFERENCES events(id) ON DELETE CASCADE,
44
+ name TEXT NOT NULL,
45
+ team TEXT,
46
+ past_teams TEXT,
47
+ winnings TEXT,
48
+ most_played_agents TEXT,
49
+ avg_kda REAL,
50
+ nationality TEXT,
51
+ region TEXT,
52
+ stats TEXT,
53
+ UNIQUE (event_id, name)
58
54
  )
59
- `);
55
+ `
56
+
57
+ // Older databases kept one shared row per player and linked them to events through event_players.
58
+ // Copy each of those links into its own per-event player row.
59
+ const existingPlayerColumns = db.prepare('PRAGMA table_info(players)').all().map(col => col.name)
60
+ if (existingPlayerColumns.length && !existingPlayerColumns.includes('event_id')) {
61
+ db.transaction(() => {
62
+ if (!existingPlayerColumns.includes('stats')) {
63
+ db.exec('ALTER TABLE players ADD COLUMN stats TEXT')
64
+ }
65
+ db.exec(createPlayersTableSql('players_new'))
66
+ db.exec(`
67
+ INSERT INTO players_new (event_id, name, team, past_teams, winnings, most_played_agents, avg_kda, nationality, region, stats)
68
+ SELECT event_players.event_id, players.name, players.team, players.past_teams, players.winnings,
69
+ players.most_played_agents, players.avg_kda, players.nationality, players.region, players.stats
70
+ FROM event_players
71
+ JOIN players ON players.name = event_players.player_name
72
+ JOIN events ON events.id = event_players.event_id
73
+ `)
74
+ db.exec('DROP TABLE event_players')
75
+ db.exec('DROP TABLE players')
76
+ db.exec('ALTER TABLE players_new RENAME TO players')
77
+ })()
78
+ }
79
+
80
+ db.exec(createPlayersTableSql('players'))
81
+ db.exec('DROP TABLE IF EXISTS event_players')
60
82
 
61
83
  const upsertPlayerStmt = db.prepare(`
62
- INSERT INTO players (name, team, past_teams, winnings, most_played_agents, avg_kda, nationality, region, stats)
63
- VALUES (@name, @team, @past_teams, @winnings, @most_played_agents, @avg_kda, @nationality, @region, @stats)
64
- ON CONFLICT(name) DO UPDATE SET
84
+ INSERT INTO players (event_id, name, team, past_teams, winnings, most_played_agents, avg_kda, nationality, region, stats)
85
+ VALUES (@event_id, @name, @team, @past_teams, @winnings, @most_played_agents, @avg_kda, @nationality, @region, @stats)
86
+ ON CONFLICT(event_id, name) DO UPDATE SET
65
87
  team = excluded.team,
66
88
  past_teams = excluded.past_teams,
67
89
  winnings = excluded.winnings,
@@ -70,136 +92,142 @@ const upsertPlayerStmt = db.prepare(`
70
92
  nationality = excluded.nationality,
71
93
  region = excluded.region,
72
94
  stats = excluded.stats
73
- `);
95
+ `)
74
96
 
75
97
  const upsertEventStmt = db.prepare(`
76
- INSERT INTO events (name, url, region, year, stage)
77
- VALUES (@name, @url, @region, @year, @stage)
98
+ INSERT INTO events (name, url, year, stage)
99
+ VALUES (@name, @url, @year, @stage)
78
100
  ON CONFLICT(name) DO UPDATE SET
79
101
  url = excluded.url,
80
- region = excluded.region,
81
102
  year = excluded.year,
82
103
  stage = excluded.stage
83
- `);
104
+ `)
84
105
 
85
- const linkPlayerToEventStmt = db.prepare(`
86
- INSERT OR IGNORE INTO event_players (event_id, player_name)
87
- VALUES (@eventId, @playerName)
88
- `);
106
+ // Every player query also pulls in the event's name and year, newest event first.
107
+ const selectPlayersSql = `
108
+ SELECT players.*, events.name AS event_name, events.year AS event_year FROM players
109
+ JOIN events ON events.id = players.event_id
110
+ `
111
+ const newestFirst = 'ORDER BY events.year DESC, players.id DESC'
89
112
 
90
113
  function rowToPlayer(row) {
91
- if (!row) return null;
114
+ if (!row) return null
92
115
  return {
93
116
  ...row,
94
117
  past_teams: JSON.parse(row.past_teams),
95
118
  most_played_agents: JSON.parse(row.most_played_agents),
96
119
  stats: JSON.parse(row.stats),
97
- };
120
+ }
98
121
  }
99
122
 
100
- function savePlayer(player) {
123
+ // Saves a player's stats for one event, replacing any earlier save of them in that same event.
124
+ // Returns the player row's id.
125
+ function savePlayer(eventId, player) {
101
126
  upsertPlayerStmt.run({
102
127
  ...player,
128
+ event_id: eventId,
103
129
  past_teams: JSON.stringify(player.past_teams),
104
130
  most_played_agents: JSON.stringify(player.most_played_agents),
105
131
  stats: JSON.stringify(player.stats),
106
- });
132
+ })
133
+ return db.prepare('SELECT id FROM players WHERE event_id = ? AND name = ?').get(eventId, player.name).id
107
134
  }
108
135
 
136
+ function getPlayerById(id) {
137
+ return rowToPlayer(db.prepare(`${selectPlayersSql} WHERE players.id = ?`).get(id))
138
+ }
139
+
140
+ // The player as they were in their most recent event.
109
141
  function getPlayer(name) {
110
- return rowToPlayer(db.prepare('SELECT * FROM players WHERE name = ?').get(name));
142
+ return rowToPlayer(db.prepare(`${selectPlayersSql} WHERE players.name = ? ${newestFirst} LIMIT 1`).get(name))
143
+ }
144
+
145
+ // Every saved version of a player, one per event, newest first.
146
+ function getPlayerHistory(name) {
147
+ return db.prepare(`${selectPlayersSql} WHERE players.name = ? ${newestFirst}`).all(name).map(rowToPlayer)
148
+ }
149
+
150
+ // Case-insensitive prefix match, e.g. "nat" finds "nats" but not "gnat". Returns one row per event.
151
+ function searchPlayers(query) {
152
+ return db.prepare(`${selectPlayersSql} WHERE players.name LIKE ? ESCAPE '\\' ORDER BY players.name, events.year DESC, players.id DESC`)
153
+ .all(`${query.replace(/[\\%_]/g, '\\$&')}%`)
154
+ .map(rowToPlayer)
111
155
  }
112
156
 
113
157
  function getAllPlayers() {
114
- return db.prepare('SELECT * FROM players').all().map(rowToPlayer);
158
+ return db.prepare(selectPlayersSql).all().map(rowToPlayer)
115
159
  }
116
160
 
117
161
  function getRandomPlayer() {
118
- return rowToPlayer(db.prepare('SELECT * FROM players ORDER BY RANDOM() LIMIT 1').get());
162
+ return rowToPlayer(db.prepare(`${selectPlayersSql} ORDER BY RANDOM() LIMIT 1`).get())
119
163
  }
120
164
 
165
+
121
166
  // Creates the event (tournament, stage, etc.) if it doesn't exist yet, and returns its id either way.
122
- function saveEvent({ name, url, region, year, stage }) {
167
+ function saveEvent({ name, url, year, stage }) {
123
168
  upsertEventStmt.run({
124
169
  name,
125
170
  url: url ?? null,
126
- region: region ?? null,
127
171
  year: year ?? null,
128
172
  stage: stage ?? null,
129
- });
130
- return db.prepare('SELECT id FROM events WHERE name = ?').get(name).id;
131
- }
132
-
133
- function addPlayerToEvent(eventId, playerName) {
134
- linkPlayerToEventStmt.run({ eventId, playerName });
173
+ })
174
+ return db.prepare('SELECT id FROM events WHERE name = ?').get(name).id
135
175
  }
136
176
 
137
177
  function getEvents() {
138
- return db.prepare('SELECT * FROM events').all();
178
+ return db.prepare('SELECT * FROM events').all()
139
179
  }
140
180
 
141
181
  function getEventByName(name) {
142
- return db.prepare('SELECT * FROM events WHERE name = ?').get(name);
182
+ return db.prepare('SELECT * FROM events WHERE name = ?').get(name)
183
+ }
184
+
185
+ function getEventId(name, year) {
186
+ return db.prepare('SELECT id FROM events WHERE name = ? AND year = ?').get(name, year)?.id
143
187
  }
144
188
 
145
189
  function getPlayersByEvent(eventName) {
146
- return db.prepare(`
147
- SELECT players.* FROM players
148
- JOIN event_players ON event_players.player_name = players.name
149
- JOIN events ON events.id = event_players.event_id
150
- WHERE events.name = ?
151
- `).all(eventName).map(rowToPlayer);
190
+ return db.prepare(`${selectPlayersSql} WHERE events.name = ?`).all(eventName).map(rowToPlayer)
152
191
  }
153
192
 
154
193
  function getRandomPlayerFromEvent(eventName) {
155
- return rowToPlayer(db.prepare(`
156
- SELECT players.* FROM players
157
- JOIN event_players ON event_players.player_name = players.name
158
- JOIN events ON events.id = event_players.event_id
159
- WHERE events.name = ?
160
- ORDER BY RANDOM() LIMIT 1
161
- `).get(eventName));
194
+ return rowToPlayer(db.prepare(`${selectPlayersSql} WHERE events.name = ? ORDER BY RANDOM() LIMIT 1`).get(eventName))
162
195
  }
163
196
 
164
- // Deletes players that no longer belong to any event.
165
- function deleteOrphanedPlayers() {
166
- db.prepare('DELETE FROM players WHERE name NOT IN (SELECT player_name FROM event_players)').run();
197
+ // Removes every player from an event but keeps the event itself, so it can be re-scraped.
198
+ function emptyEvent(eventName) {
199
+ const event = getEventByName(eventName)
200
+ if (!event) return false
201
+ db.prepare('DELETE FROM players WHERE event_id = ?').run(event.id)
202
+ return true
167
203
  }
168
204
 
169
- // Removes every player from an event but keeps the event itself, so it can be re-scraped.
170
- // Players that are still in other events are kept.
171
- const emptyEvent = db.transaction((eventName) => {
172
- const event = getEventByName(eventName);
173
- if (!event) return false;
174
- db.prepare('DELETE FROM event_players WHERE event_id = ?').run(event.id);
175
- deleteOrphanedPlayers();
176
- return true;
177
- });
178
-
179
- // Removes an event and its players. Players that are still in other events are kept.
180
- const clearEvent = db.transaction((eventName) => {
181
- if (!emptyEvent(eventName)) return false;
182
- db.prepare('DELETE FROM events WHERE name = ?').run(eventName);
183
- return true;
184
- });
205
+ // Removes an event and its players.
206
+ function clearEvent(eventName) {
207
+ // The event's players are deleted along with it (ON DELETE CASCADE).
208
+ return db.prepare('DELETE FROM events WHERE name = ?').run(eventName).changes > 0
209
+ }
185
210
 
186
211
  // Wipes every event and player from the database.
187
212
  const clearDatabase = db.transaction(() => {
188
- db.exec('DELETE FROM event_players; DELETE FROM events; DELETE FROM players;');
189
- });
213
+ db.exec('DELETE FROM players; DELETE FROM events;')
214
+ })
190
215
 
191
216
  export {
192
217
  savePlayer,
218
+ getPlayerById,
193
219
  getPlayer,
220
+ getPlayerHistory,
221
+ searchPlayers,
194
222
  getAllPlayers,
195
223
  getRandomPlayer,
196
224
  saveEvent,
197
- addPlayerToEvent,
198
225
  getEvents,
199
226
  getEventByName,
227
+ getEventId,
200
228
  getPlayersByEvent,
201
229
  getRandomPlayerFromEvent,
202
230
  emptyEvent,
203
231
  clearEvent,
204
232
  clearDatabase,
205
- };
233
+ }