From d1aa19e4c3002c1e77b3a91a864b8c5114418fe6 Mon Sep 17 00:00:00 2001 From: j Date: Tue, 26 Mar 2024 22:53:00 -0400 Subject: [PATCH] updated database service --- src/db/services/Database.ts | 174 ++++++++++-------------------------- 1 file changed, 47 insertions(+), 127 deletions(-) diff --git a/src/db/services/Database.ts b/src/db/services/Database.ts index 48537f2..082c9fe 100644 --- a/src/db/services/Database.ts +++ b/src/db/services/Database.ts @@ -1,6 +1,6 @@ import { Database } from 'sqlite'; -import { Comment } from '../../rdrama/models/Comment'; import { DatabaseInitializer } from '../initializeDatabase'; +import GameState from '../../game/gameState'; /** * Service for interacting with the SQLite database for operations related to comments and user mentions. @@ -27,136 +27,56 @@ export class DatabaseService { } /** - * Inserts a new user mention into the database. - * This static method adds a record of a user being mentioned in a comment. - * + * Loads an existing game state for a given author from the database. + * If an existing game state is found, it returns a new GameState instance initialized with the stored values. + * If no game state exists for the given author, it returns null, indicating that a new game state needs to be initialized. + * * @example - * await DatabaseService.insertUserMention({ - * rdrama_comment_id: 456, - * username: 'mentionedUser', - * message: 'You were mentioned in a comment.' - * }); - * - * @param {Object} mention - The user mention object to insert. - * @param {number} mention.rdrama_comment_id - The ID of the comment from the r/Drama platform. - * @param {string} mention.username - The mentioned Reddit username. - * @param {string} [mention.message] - The content of the message sent to the mentioned user. - * @throws {Error} Will throw an error if the insert operation fails. + * const gameState = await DatabaseService.loadGameState(authorId); + * if (gameState) { + * console.log('Game state loaded successfully.'); + * } else { + * console.log('No existing game state found. Initializing a new game.'); + * } + * + * @param {number} authorId - The unique identifier for the author of the game. + * @returns {Promise} A promise that resolves to a GameState instance if found, or null if no existing game state is present. + * @throws {Error} Will throw an error if the database operation fails. */ - public static async insertUserMention(mention: { rdrama_comment_id: number; username: string; message?: string }): Promise { - const db = await DatabaseService.getDatabase() - const sql = `INSERT INTO user_mentions (rdrama_comment_id, username, message) VALUES (?, ?, ?)`; - await db.run(sql, [mention.rdrama_comment_id, mention.username, mention.message]); - } - - /** - * Queries the database to check if a username has been mentioned. - * - * @example - * const mentioned = await DatabaseService.userMentionExists('exampleUser'); - * console.log(mentioned ? 'User has been mentioned.' : 'User has not been mentioned.'); - * - * @param {string} username - The username to search for. - * @returns {Promise} A boolean indicating whether the username has been mentioned. - * @throws {Error} Will throw an error if the query operation fails. - */ - public static async userMentionExists(username: string): Promise { - const db = await DatabaseService.getDatabase() - const sql = `SELECT 1 FROM user_mentions WHERE username = ?`; - const result = await db.get(sql, [username]); - return !!result; - } - - /** - * Inserts or updates the OAuth token in the database for a specific service. - * - * @example - * await DatabaseService.upsertOAuthToken('https://oauth.reddit.com', { - * access_token: 'abc123', - * token_type: 'bearer', - * expires_in: 3600, - * scope: 'read' - * }); - * - * @param {string} token_identifier - A unique identifier for the token, typically the service's base URL. - * @param {Object} tokenData - The OAuth token data including access_token, token_type, expires_in, and scope. - * @throws {Error} Will throw an error if the upsert operation fails. - */ - public static async upsertOAuthToken(token_identifier: string, tokenData: any) { - const db = await DatabaseService.getDatabase() - const { access_token, token_type, expires_in, scope } = tokenData; - const expiryTimestamp = Math.floor(Date.now() / 1000) + expires_in; - console.log('token_identifier', token_identifier) - console.log('access_token', `${access_token.substring(0, 5)}XXXXX`) - console.log('token_type', token_type) - console.log('expires_in', expires_in) - console.log('scope', scope) - - await db.run(` - INSERT INTO oauth_tokens (token_identifier, access_token, token_type, expires_in, expiry_timestamp, scope) - VALUES (?, ?, ?, ?, ?, ?) - ON CONFLICT(token_identifier) DO UPDATE SET - access_token = excluded.access_token, - token_type = excluded.token_type, - expires_in = excluded.expires_in, - expiry_timestamp = excluded.expiry_timestamp, - scope = excluded.scope - `, [token_identifier, access_token, token_type, expires_in, expiryTimestamp, scope]); - } - - /** - * Retrieves the current, unexpired OAuth token for a specific service. - * - * @example - * const token = await DatabaseService.getCurrentOAuthToken('https://oauth.reddit.com'); - * console.log(token ? `Current token: ${token.access_token}` : 'No valid token found.'); - * - * @param {string} token_identifier - The unique identifier for the token, typically the service's base URL. - * @returns {Promise} The current OAuth token data or null if expired or not found. - * @throws {Error} Will throw an error if the query operation fails. - */ - public static async getCurrentOAuthToken(token_identifier: string) { - const db = await DatabaseService.getDatabase() - const tokenRow = await db.get(` - SELECT access_token, token_type, scope, expiry_timestamp FROM oauth_tokens - WHERE token_identifier = ? - `, token_identifier); - - return tokenRow || null; - } - - /** - * Checks if the cooldown period has passed since the last notification was sent, allowing for a new notification to be sent. - * - * @example - * const canSend = await DatabaseService.canSendNotification(); - * console.log(canSend ? 'Can send a new notification.' : 'Still in cooldown period.'); - * - * @returns {Promise} True if the cooldown period has passed, allowing new notifications to be sent. - * @throws {Error} Will throw an error if the check operation fails. - */ - public static async canSendNotification(): Promise { - const db = await DatabaseService.getDatabase() - const cooldownHours = process.env.NOTIFICATION_COOLDOWN_HOURS || 4; - const sql = ` - SELECT MAX(sent_time) as last_notification_time - FROM user_mentions - `; - const result = await db.get(sql); - - if (!result || !result.last_notification_time) { - // No notifications have been sent yet, or unable to retrieve the last sent time. - return true; + public static async loadGameState(authorId: number): Promise { + const db = await DatabaseService.getDatabase(); + const sql = `SELECT data FROM game_state WHERE authorId = ?`; + const row = await db.get(sql, [authorId]); + if (row) { + return JSON.parse(row.data) as GameState; // Assuming GameState constructor can take authorId and a partial state object + } else { + return null; // Or return a new GameState with defaults } + } - const lastNotificationTime = new Date(result.last_notification_time).getTime(); - const currentTime = new Date(new Date().toISOString().slice(0, 19).replace('T', ' ')).getTime(); - const timeElapsed = currentTime - lastNotificationTime; - //console.log('timeElapsed', timeElapsed) - const cooldownPeriod = +cooldownHours * 60 * 60 * 1000; // Convert hours to milliseconds - //console.log('cooldownPeriod', cooldownPeriod) - - return timeElapsed >= cooldownPeriod; + /** + * Saves the current game state for a given author to the database. + * If an existing game state for the author exists, it updates the stored values. If no game state exists, it inserts a new record. + * This method ensures the game state is persisted between sessions, allowing players to resume their game at any time. + * + * @example + * await DatabaseService.saveGameState(authorId, gameState); + * console.log('Game state saved successfully.'); + * + * @param {number} authorId - The unique identifier for the author of the game. + * @param {GameState} gameState - The current game state to be saved. + * @returns {Promise} A promise that resolves when the game state is successfully saved. + * @throws {Error} Will throw an error if the save operation fails. + */ + public static async saveGameState(authorId: number, gameState: GameState): Promise { + const db = await DatabaseService.getDatabase(); + const data = JSON.stringify(gameState); + const sql = ` + INSERT INTO game_state (authorId, data) VALUES (?, ?) + ON CONFLICT(authorId) DO UPDATE SET + data = excluded.data; + `; + await db.run(sql, [authorId, data]); } }