### Install Project Dependencies Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Installs all the dependencies listed in `Cargo.toml` for the Rust project. This command should be run after modifying the `Cargo.toml` file. ```bash cargo run ``` -------------------------------- ### Install Rust and Dependencies Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Installs Rust and associated tools like Cargo using a script from the official Rust website. This is a prerequisite for developing Rust applications. ```shell $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` -------------------------------- ### Configure and Run Actix Web Server (Rust) Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Sets up and starts an Actix Web server, integrating the application state for handling requests. It binds the server to a specified URL and port, and configures the application data to be shared across all workers. ```rust use actix_web::{App, HttpServer}; use actix_web::web::Data; use crate::config::app::AppState; mod config; #[actix_web::main] async fn main() -> std::io::Result<()> { let app_data = AppState::new().await; println!("Web Server Online!"); println!("Listening on http://{{}}:{{}}", app_data.config.app.url, app_data.config.app.port); HttpServer::new(move || { App::new() .app_data(Data::new(AppState::new())) }).bind(( app_data.config.app.url, app_data.config.app.port.parse::().unwrap() ))?.run().await } ``` -------------------------------- ### Find a Submission API Endpoint Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/getting-started.md This snippet shows how to define the API endpoint for retrieving a specific gameplay submission by its ID. It outlines the HTTP verb (GET) and the expected route structure. The response example includes details of the submission. ```json { "message": "Submission found.", "submission": { "difficulty": "daniel-reiss", "id": "01abf900-dcc9-4f61-94fe-a353d4e85bf6", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-14T18:34:46.985Z", "player_id": "daniel-reiss", "score": 30005, "song_id": "stone-audioslave" } } ``` -------------------------------- ### Create New Rust Project Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Initializes a new Rust project named 'leaderboard-rust' using Cargo, the Rust build system and package manager. This command sets up the basic project structure. ```shell cargo new leaderboard-rust ``` -------------------------------- ### Submit a Gameplay API Endpoint Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/getting-started.md This snippet defines the API endpoint for submitting a new gameplay score. It specifies the HTTP verb (POST) and the route. The example payload shows the required fields for a submission, and the response example confirms successful creation. ```json { "message": "Submission created successfully", "submission": { "difficulty": "expert", "id": "531be3f3-2d4f-4d7b-bfb3-1366e2a632c4", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-26T13:13:51.331231046Z", "player_id": "startupme", "score": 19999, "song_id": "stone-audioslave" } } ``` -------------------------------- ### Rust ScyllaDB Connection Setup Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Establishes a connection to a ScyllaDB Cloud cluster using the `scylla-rust-driver`. It configures nodes, connection timeout, and authentication details, providing a robust way to interact with the database from a Rust application. ```rust use scylla::{Session, SessionBuilder}; use std::time::Duration; pub struct Database { pub session: Session, } impl Database { pub async fn new(config: &ConnectionDetails) -> Database { let nodes = config.nodes.iter() .filter(|i| !i.is_empty()) .collect::>(); let session: Session = SessionBuilder::new() .known_nodes(nodes) .connection_timeout(Duration::from_secs(5)) .user(config.username.to_string(), config.password.to_string()) .build() .await .expect("Connection Refused. Check your credentials and your IP linked on the ScyllaDB Cloud."); Self { session } } } // Run with: // cargo run -- --username scylla --password your-password \ // "node-0.aws-sa-east-1.1.clusters.scylla.cloud", \ // "node-1.aws-sa-east-1.1.clusters.scylla.cloud", \ // "node-2.aws-sa-east-1.1.clusters.scylla.cloud" ``` -------------------------------- ### GET /submissions/{submission_id} Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/getting-started.md Retrieves a specific gameplay submission using its unique ID. ```APIDOC ## GET /submissions/{submission_id} ### Description Retrieves a specific gameplay submission using its unique ID. ### Method GET ### Endpoint /submissions/{submission_id} ### Parameters #### Path Parameters - **submission_id** (string) - Required - The unique identifier for the submission. ### Response #### Success Response (200) - **message** (string) - Confirmation message. - **submission** (object) - The details of the retrieved submission. - **difficulty** (string) - The difficulty level of the gameplay. - **id** (string) - The unique identifier for the submission. - **instrument** (string) - The instrument played. - **modifiers** (array) - An array of modifiers applied to the gameplay. - **played_at** (string) - The timestamp when the gameplay was played. - **player_id** (string) - The identifier for the player. - **score** (integer) - The score achieved in the gameplay. - **song_id** (string) - The identifier for the song played. #### Response Example ```json { "message": "Submission found.", "submission": { "difficulty": "daniel-reiss", "id": "01abf900-dcc9-4f61-94fe-a353d4e85bf6", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-14T18:34:46.985Z", "player_id": "daniel-reiss", "score": 30005, "song_id": "stone-audioslave" } } ``` ``` -------------------------------- ### Expose App and Config Modules (Rust) Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Makes the 'app' and 'config' modules public within the 'config' module. This is necessary for external modules to access the application state and configuration structures defined within these modules. ```rust // file: src/config/mod.rs pub mod app; pub mod config; ``` -------------------------------- ### Clone and Install Project Dependencies - Shell Source: https://github.com/scylladb/gaming-leaderboard/blob/main/alternator/php/README.MD This snippet shows how to clone the project repository and install its PHP dependencies using Composer. It assumes you have Git and Composer installed on your system. ```shell git clone https://github.com/scylladb/scylla-cloud-getting-started.git cd scylla-cloud-getting-started/alternator/php composer install ``` -------------------------------- ### POST /submissions/{submission_id} Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/getting-started.md Submits a new gameplay score to the API. Note: The endpoint path includes submission_id, but the example payload does not use it, suggesting it might be generated server-side or the path parameter is a placeholder. ```APIDOC ## POST /submissions/{submission_id} ### Description Submits a new gameplay score to the API. Note: The endpoint path includes submission_id, but the example payload does not use it, suggesting it might be generated server-side or the path parameter is a placeholder. ### Method POST ### Endpoint /submissions/{submission_id} ### Parameters #### Path Parameters - **submission_id** (string) - Required - The unique identifier for the submission (may be server-generated). #### Request Body - **song_id** (string) - Required - The identifier for the song played. - **player_id** (string) - Required - The identifier for the player. - **modifiers** (array) - Required - An array of modifiers applied to the gameplay. - **score** (integer) - Required - The score achieved in the gameplay. - **difficulty** (string) - Required - The difficulty level of the gameplay. - **instrument** (string) - Required - The instrument played. ### Request Example ```json { "song_id": "stone-audioslave", "player_id": "startupme", "modifiers": [ "no-modifiers" ], "score": 19999, "difficulty": "expert", "instrument": "guitar" } ``` ### Response #### Success Response (200) - **message** (string) - Confirmation message. - **submission** (object) - The details of the created submission. - **difficulty** (string) - The difficulty level of the gameplay. - **id** (string) - The unique identifier for the submission. - **instrument** (string) - The instrument played. - **modifiers** (array) - An array of modifiers applied to the gameplay. - **played_at** (string) - The timestamp when the gameplay was played. - **player_id** (string) - The identifier for the player. - **score** (integer) - The score achieved in the gameplay. - **song_id** (string) - The identifier for the song played. #### Response Example ```json { "message": "Submission created successfully", "submission": { "difficulty": "expert", "id": "531be3f3-2d4f-4d7b-bfb3-1366e2a632c4", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-26T13:13:51.331231046Z", "player_id": "startupme", "score": 19999, "song_id": "stone-audioslave" } } ``` ``` -------------------------------- ### POST /leaderboard/{song_id} Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/getting-started.md Retrieves the leaderboard for a specific song, with optional filters for instrument, difficulty, and modifiers. ```APIDOC ## POST /leaderboard/{song_id} ### Description Retrieves the leaderboard for a specific song, with optional filters for instrument, difficulty, and modifiers. ### Method POST ### Endpoint /leaderboard/{song_id} ### Parameters #### Path Parameters - **song_id** (string) - Required - The identifier for the song. #### Query Parameters - **instrument** (string) - Optional - Filters the leaderboard by instrument. - **difficulty** (string) - Optional - Filters the leaderboard by difficulty. - **modifiers** (string[]) - Optional - Filters the leaderboard by modifiers (e.g., `modifiers[]=no-modifiers`). ### Response #### Success Response (200) - Returns an array of submission objects, ordered by score (highest first). - **difficulty** (string) - The difficulty level of the gameplay. - **id** (string) - The unique identifier for the submission. - **instrument** (string) - The instrument played. - **modifiers** (array) - An array of modifiers applied to the gameplay. - **played_at** (string) - The timestamp when the gameplay was played. - **player_id** (string) - The identifier for the player. - **score** (integer) - The score achieved in the gameplay. - **song_id** (string) - The identifier for the song played. #### Response Example ```json [ { "difficulty": "expert", "id": "8151cb1c-a1a0-473d-b491-74c7a3988189", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-14T18:34:46.999Z", "player_id": "daniel-reis", "score": 30005, "song_id": "stone-audioslave" }, { "difficulty": "expert", "id": "8e15add1-020e-4a84-90cc-2c48d6c246cb", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-26T13:13:51.346Z", "player_id": "startupme", "score": 19999, "song_id": "stone-audioslave" } ] ``` ``` -------------------------------- ### Configure AppState for Database Connection (Rust) Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Sets up the AppState to manage application data and establish a database connection using Charybdis with ScyllaDB. It configures connection timeouts, user credentials, and keyspace, then creates a CachingSession for ORM queries. ```rust use std::sync::Arc; use std::time::Duration; use dotenvy::dotenv; use scylla::{CachingSession, Session, SessionBuilder}; use crate::config::config::Config; #[derive(Debug, Clone)] pub struct AppState { pub config: Config, pub database: Arc } impl AppState { pub async fn new() -> Self { dotenv().expect(".env file not found"); let config = Config::new(); let session: Session = SessionBuilder::new() .known_nodes(config.database.nodes) .connection_timeout(Duration::from_secs(5)) .user(config.database.username, config.database.password) .build() .await .expect("Connection Refused. Check your credentials and IP linked on the ScyllaDB Cloud."); session.use_keyspace("leaderboard", false).await.expect("Keyspace not found"); AppState { config: Config::new(), database: Arc::new(CachingSession::from(session, config.database.cached_queries)) } } } ``` -------------------------------- ### Configure Environment Variables in Rust Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Defines Rust structs (`App`, `Database`, `Config`) to parse and store environment variables loaded from a `.env` file. The `Config::new()` function reads these variables using `dotenvy::var` and initializes the configuration structure for the application. ```rust // File: src/config/config.rs use serde::Serialize; #[derive(Clone, Debug, Serialize)] pub struct App { pub name: String, pub version: String, pub url: String, pub port: String, } #[derive(Clone, Debug, Serialize)] pub struct Database { pub nodes: Vec, pub username: String, pub password: String, pub cached_queries: usize, pub keyspace: String, } #[derive(Clone, Debug, Serialize)] pub struct Config { pub app: App, pub database: Database } impl Config { pub fn new() -> Self { Config { app: App { name: dotenvy::var("APP_NAME").unwrap(), version: dotenvy::var("APP_VERSION").unwrap(), url: dotenvy::var("APP_URL").unwrap(), port: dotenvy::var("APP_PORT").unwrap(), }, database: Database { nodes: dotenvy::var("SCYLLA_NODES").unwrap().split(',').map(|s| s.to_string()).collect(), username: dotenvy::var("SCYLLA_USERNAME").unwrap(), password: dotenvy::var("SCYLLA_PASSWORD").unwrap(), cached_queries: dotenvy::var("SCYLLA_CACHED_QUERIES").unwrap().parse::().unwrap(), keyspace: dotenvy::var("SCYLLA_KEYSPACE").unwrap() } } } } ``` -------------------------------- ### Configure Environment Variables for ScyllaDB Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Sets up an `.env` file in the project root to store sensitive credentials and application configuration for connecting to a ScyllaDB cluster. This includes database connection details and application settings. ```env # App Config APP_NAME="Gaming Leaderboard" APP_VERSION="0.0.1" APP_URL="0.0.0.0" APP_PORT="8000" # Database Config SCYLLA_NODES="node-0.clusters.scylla.cloud,node-1.clusters.scylla.cloud,node-2.clusters.scylla.cloud" SCYLLA_USERNAME="scylla" SCYLLA_PASSWORD="your-password" SCYLLA_CACHED_QUERIES="15" SCYLLA_KEYSPACE="leaderboard" ``` -------------------------------- ### Retrieve Leaderboard by Song API Endpoint Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/getting-started.md This snippet illustrates how to retrieve a leaderboard for a specific song, with options to filter by instrument, difficulty, and modifiers. It shows the POST verb, route structure, and example query parameters for filtering. The response is an array of submissions ranked by score. ```json [ { "difficulty": "expert", "id": "8151cb1c-a1a0-473d-b491-74c7a3988189", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-14T18:34:46.999Z", "player_id": "daniel-reis", "score": 30005, "song_id": "stone-audioslave" }, { "difficulty": "expert", "id": "8e15add1-020e-4a84-90cc-2c48d6c246cb", "instrument": "guitar", "modifiers": [ "no-modifiers" ], "played_at": "2024-02-26T13:13:51.346Z", "player_id": "startupme", "score": 19999, "song_id": "stone-audioslave" } ] ``` -------------------------------- ### Migrate Database to ScyllaDB Cluster Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Command to migrate database models to a ScyllaDB cluster. It requires user credentials, host information, and the keyspace name. The output shows detected models and executed CQL statements for table creation. ```shell migrate -u scylla -p your-password --host your-node.clusters.scylla.cloud --keyspace leaderboard -d # Detected 'src/models' directory # Detected first migration for: submissions Table! # Running CQL: CREATE TABLE IF NOT EXISTS submissions # ( # difficulty Text, # id Uuid, # instrument Text, # modifiers Frozen < Set < Text > >, # played_at Timestamp, # player_id Text, # score Int, # song_id Text, # PRIMARY KEY ((id) ,played_at) # ) # WITH # CLUSTERING ORDER BY (played_at DESC) # CQL executed successfully! ✅ # Detected first migration for: song_leaderboard Table! # Running CQL: CREATE TABLE IF NOT EXISTS song_leaderboard # ( # difficulty Text, # id Uuid, # instrument Text, # modifiers Frozen < Set < Text > >, # played_at Timestamp, # player_id Text, # score Int, # song_id Text, # PRIMARY KEY ((song_id, modifiers, difficulty, instrument) ,player_id, score) # ) # WITH # CLUSTERING ORDER BY (player_id ASC, score DESC) # CQL executed successfully! ✅ ``` -------------------------------- ### ScyllaDB CQL Queries for Media Player Operations Source: https://github.com/scylladb/gaming-leaderboard/blob/main/rust/README.MD This snippet provides examples of CQL queries used within the Rust media player project for various operations. It includes queries for checking keyspace and table existence, selecting all songs, inserting recently played songs, updating play counts, and deleting songs. ```sql SELECT keyspace_name FROM system_schema.keyspaces WHERE keyspace_name = ? SELECT keyspace_name,table_name FROM system_schema.tables WHERE keyspace_name = ? AND table_name = ? SELECT * FROM songs INSERT INTO recently_played_songs (song_id, listened_at) VALUES (?, ?) UPDATE played_songs_counter SET times_played = times_played + 1 WHERE song_id = ? DELETE FROM songs WHERE id = ? ``` -------------------------------- ### Define Project Dependencies in Cargo.toml Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Specifies the project's dependencies in the `Cargo.toml` file, including web framework (actix-web), ScyllaDB driver (scylla), ORM (charybdis), and utility crates like chrono, dotenvy, serde, and uuid. These are essential for building the leaderboard application. ```toml [package] name = "leaderboard-rust" version = "0.1.0" edition = "2021" [dependencies] actix-web = "4.5.1" charybdis = "0.4.2" chrono = "0.4.34" dotenvy = "0.15.7" scylla = { version = "0.12.0", features = ["time", "chrono"] } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.113" thiserror = "1.0.56" uuid = { version = "1.7.0", features = ["v4"] } log = "0.4.20" ``` -------------------------------- ### Create Submission Model from Request in Rust Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Implements a `from_request` function for the `Submission` model, converting a `SubmissionDTO` into a database-ready `Submission` struct. It generates a unique ID, sets the `played_at` timestamp, and maps fields from the DTO. ```rust use charybdis::macros::charybdis_model; use charybdis::types::{Frozen, Int, Set, Text, Timestamp, Uuid}; use serde::{Deserialize, Serialize}; use crate::http::requests::submission_request::SubmissionDTO; #[charybdis_model( table_name = submissions, partition_keys = [id], clustering_keys = [played_at], global_secondary_indexes = [], local_secondary_indexes = [], table_options = " CLUSTERING ORDER BY (played_at DESC) ", )] #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct Submission { #[serde(default = "Uuid::new_v4")] pub id: Uuid, pub song_id: Text, pub player_id: Text, pub modifiers: Frozen>, pub score: Int, pub difficulty: Text, pub instrument: Text, pub played_at: Timestamp, } impl Submission { pub fn from_request(payload: &SubmissionDTO) -> Self { Submission { id: Uuid::new_v4(), song_id: payload.song_id.to_string(), player_id: payload.player_id.to_string(), difficulty: payload.difficulty.to_string(), instrument: payload.instrument.to_string(), modifiers: payload.modifiers.to_owned(), score: payload.score.to_owned(), played_at: chrono::Utc::now(), ..Default::default() } } } ``` -------------------------------- ### Rust Module Declaration for Requests Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Adds the submission_request module to the main requests module in Rust. This is a common pattern for organizing request-related structs and logic. ```rust //file: src/http/requests/mod.rs pub mod submission_request; ``` -------------------------------- ### Expose Leaderboard and Submission Models (Rust) Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Makes the 'leaderboard' and 'submission' models public within the 'models' module. This allows other parts of the application to import and use these data structures for database interactions. ```rust // file: src/models/mod.rs pub mod leaderboard; pub mod submission; ``` -------------------------------- ### Implement Submission Controller with Actix in Rust Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Handles HTTP POST requests to the `/submissions` endpoint using Actix. It validates the incoming `SubmissionDTO`, converts it to a `Submission` model, inserts it into the ScyllaDB database, and returns the created submission or a bad request error. ```rust use actix_web::{HttpResponse, post, Responder, Result, web}; use charybdis::operations::Insert; use serde_json::json; use validator::Validate; use crate::config::app::AppState; use crate::http::requests::submission_request::SubmissionDTO; use crate::http::SomeError; use crate::models::submission::Submission; #[post("/submissions")] async fn post_submission( data: web::Data, payload: web::Json, ) -> Result { let validated = payload.validate(); let response = match validated { Ok(_) => { let submission = Submission::from_request(&payload); submission.insert().execute(&data.database).await?; HttpResponse::Ok().json(json!(submission)) } Err(err) => HttpResponse::BadRequest().json(json!(err)), }; Ok(response) } ``` -------------------------------- ### Declare Submission Controller Module in Rust Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Declares the `submission_controller` module within the `requests` module in Rust. This is a common pattern for organizing controllers in Actix web applications. ```rust pub mod submission_controller; ``` -------------------------------- ### Clone and Run Rust ScyllaDB Media Player Source: https://github.com/scylladb/gaming-leaderboard/blob/main/rust/README.MD This snippet shows how to clone the ScyllaDB Rust media player project from GitHub and run it using Cargo. It requires Rust to be installed and involves cloning the repository, navigating into the directory, and executing the 'cargo run' command with cluster connection details. ```sh git clone https://github.com/scylladb/scylla-cloud-getting-started.git cd scylla-cloud-getting-started/rust cargo run -- --username scylla --password your-cluster-password "node-0.aws-sa-east-1.1.clusters.scylla.cloud", "node-1.aws-sa-east-1.1.clusters.scylla.cloud", "node-2.aws-sa-east-1.1.clusters.scylla.cloud" ``` -------------------------------- ### Python ScyllaDB Alternator Connection Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Establishes a connection to the ScyllaDB Alternator API using the boto3 library, which provides a DynamoDB-compatible interface. This setup is crucial for interacting with ScyllaDB using DynamoDB tools and SDKs. ```python import boto3 # Connect to ScyllaDB Alternator (DynamoDB-compatible API) dynamodb = boto3.resource( 'dynamodb', endpoint_url='http://localhost:8000', # Replace with your Alternator endpoint region_name='None', aws_access_key_id='None', aws_secret_access_key='None' ) table = dynamodb.Table('songs') ``` -------------------------------- ### Rust Submission Model with Charybdis Macro Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Rust code defining the Submission model for ScyllaDB using the Charybdis macro. It includes a `from_request` function to convert a SubmissionDTO into a Submission model, setting the `played_at` timestamp. ```rust // file: src/models/submission.rs use charybdis::macros::charybdis_model; use charybdis::types::{Frozen, Int, Set, Text, Timestamp, Uuid}; use serde::{Deserialize, Serialize}; use crate::http::requests::submission_request::SubmissionDTO; #[charybdis_model( table_name = submissions, partition_keys = [id], clustering_keys = [played_at], global_secondary_indexes = [], local_secondary_indexes = [], table_options = " CLUSTERING ORDER BY (played_at DESC) ", )] #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct Submission { #[serde(default = "Uuid::new_v4")] pub id: Uuid, pub song_id: Text, pub player_id: Text, pub modifiers: Frozen>, pub score: Int, pub difficulty: Text, pub instrument: Text, pub played_at: Timestamp, } impl Submission { pub fn from_request(payload: &SubmissionDTO) -> Self { Submission { id: Uuid::new_v4(), song_id: payload.song_id.to_string(), player_id: payload.player_id.to_string(), difficulty: payload.difficulty.to_string(), instrument: payload.instrument.to_string(), modifiers: payload.modifiers.to_owned(), score: payload.score.to_owned(), played_at: chrono::Utc::now(), ..Default::default() } } } ``` -------------------------------- ### CQL: Leaderboard Operations Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Provides common CQL queries for managing leaderboard data in ScyllaDB. This includes inserting new submissions into both 'submissions' and 'song_leaderboard' tables, searching for specific submissions, retrieving filtered song leaderboards, getting user submission history, and deleting outdated scores. ```cql -- Insert new submission to both tables INSERT INTO leaderboard.submissions ( submission_id, song_id, player_id, modifiers, score, difficulty, instrument, played_at ) VALUES ( b5ee3f80-40f9-4dfd-9fb6-13a6c94147a3, 'starlight-muse', 'daniel-reis', {'none'}, 1000, 'expert', 'guitar', '2023-11-23 00:00:00' ); INSERT INTO leaderboard.song_leaderboard ( submission_id, song_id, player_id, modifiers, score, difficulty, instrument, played_at ) VALUES ( b5ee3f80-40f9-4dfd-9fb6-13a6c94147a3, 'starlight-muse', 'daniel-reis', {'none'}, 1000, 'expert', 'guitar', '2023-11-23 00:00:00' ); -- Search specific submission SELECT * FROM submissions WHERE submission_id = b5ee3f80-40f9-4dfd-9fb6-13a6c94147a3; -- Get song leaderboard with filters SELECT * FROM leaderboard.song_leaderboard WHERE song_id = 'starlight-muse' AND modifiers = {'none'} AND difficulty = 'expert' AND instrument = 'guitar' LIMIT 10; -- Get user submission history SELECT * FROM leaderboard.user_submissions WHERE player_id = 'daniel-reis' LIMIT 10; -- Delete outdated leaderboard score when user submits higher score DELETE FROM leaderboard.song_leaderboard WHERE song_id = 'starlight-muse' AND modifiers = {'none'} AND difficulty = 'expert' AND instrument = 'guitar' AND player_id = 'daniel-reis' AND score < 1000; ``` -------------------------------- ### Define Leaderboard Model with Charybdis ORM (Rust) Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Defines the 'Leaderboard' data model for ScyllaDB using the Charybdis ORM macro. It specifies table name, partition and clustering keys, and derives necessary traits for serialization and deserialization. This model represents song-specific leaderboards. ```rust // file: src/models/leaderboard.rs use charybdis::macros::charybdis_model; use charybdis::types::{Frozen, Int, Set, Text, Timestamp, Uuid}; use serde::{Deserialize, Serialize}; #[charybdis_model( table_name = song_leaderboard, partition_keys = [song_id, modifiers, difficulty, instrument], clustering_keys = [player_id, score], global_secondary_indexes = [], local_secondary_indexes = [], table_options = " CLUSTERING ORDER BY (score DESC, player_id ASC) ", )] #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct Leaderboard { pub id: Uuid, pub song_id: Text, pub player_id: Text, pub modifiers: Frozen>, pub score: Int, pub difficulty: Text, pub instrument: Text, pub played_at: Timestamp, } ``` -------------------------------- ### Create Songs and Song Counter Tables (CQL) Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Sets up the 'songs' and 'song_counter' tables for the media player application. The 'songs' table uses a UUID partition key and timestamp clustering key, while 'song_counter' uses a counter for play counts. ```cql CREATE TABLE prod_media_player.songs ( id uuid, title text, album text, artist text, created_at timestamp, PRIMARY KEY (id, created_at) ); CREATE TABLE prod_media_player.song_counter ( song_id uuid, times_played counter, PRIMARY KEY (song_id) ); ``` -------------------------------- ### Create ScyllaDB Keyspace for Leaderboard Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/design-and-data-model.md Creates a new ScyllaDB keyspace named 'leaderboard' with network topology strategy and a replication factor of 3. This is the first step in setting up the database schema. ```cql CREATE KEYSPACE leaderboard WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': '3'} AND durable_writes = true; ``` -------------------------------- ### GET /leaderboard/{song_id} - Get Song Leaderboard Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Retrieves leaderboard rankings filtered by song, instrument, difficulty, and modifiers. ```APIDOC ## GET /leaderboard/{song_id} ### Description Retrieves leaderboard rankings filtered by song, instrument, difficulty, and modifiers. ### Method GET ### Endpoint /leaderboard/{song_id} ### Parameters #### Path Parameters - **song_id** (string) - Required - The ID of the song to filter the leaderboard by. #### Query Parameters - **instrument** (string) - Optional - The instrument to filter by. - **difficulty** (string) - Optional - The difficulty level to filter by. - **modifiers** (array of strings) - Optional - Modifiers to filter by. #### Request Body None ### Request Example ```bash curl -X GET "http://localhost:8000/leaderboard/stone-audioslave?instrument=guitar&difficulty=expert&modifiers[]=no-modifiers" ``` ### Response #### Success Response (200) - Returns an array of leaderboard entries. - **difficulty** (string) - The difficulty level. - **id** (string) - The unique ID of the submission. - **instrument** (string) - The instrument used. - **modifiers** (array of strings) - Modifiers applied. - **played_at** (string) - Timestamp of when the song was played. - **player_id** (string) - The ID of the player. - **score** (integer) - The score achieved. - **song_id** (string) - The ID of the song. #### Response Example ```json [ { "difficulty": "expert", "id": "8151cb1c-a1a0-473d-b491-74c7a3988189", "instrument": "guitar", "modifiers": ["no-modifiers"], "played_at": "2024-02-14T18:34:46.999Z", "player_id": "daniel-reis", "score": 30005, "song_id": "stone-audioslave" }, { "difficulty": "expert", "id": "8e15add1-020e-4a84-90cc-2c48d6c246cb", "instrument": "guitar", "modifiers": ["no-modifiers"], "played_at": "2024-02-26T13:13:51.346Z", "player_id": "startupme", "score": 19999, "song_id": "stone-audioslave" } ] ``` ``` -------------------------------- ### Create ScyllaDB 'Leaderboard' Table Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/design-and-data-model.md Defines the 'song_leaderboard' table, optimized for querying song-specific leaderboards. It partitions by song, modifiers, difficulty, and instrument, and clusters by score in descending order. Data is ordered by score DESC and player_id ASC. ```cql CREATE TABLE IF NOT EXISTS leaderboard.song_leaderboard ( submission_id uuid, song_id text, player_id text, modifiers frozen>, score int, difficulty text, instrument text, played_at timestamp, PRIMARY KEY ((song_id, modifiers, difficulty, instrument), score, player_id) ) WITH CLUSTERING ORDER BY (score DESC, player_id ASC); ``` -------------------------------- ### REST API: Get Submission by ID Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Retrieves a specific gameplay submission from the leaderboard using its unique ID. This endpoint accepts a GET request with the submission ID as a path parameter and returns the submission details if found. ```bash # Get a specific submission curl -X GET http://localhost:8000/submissions/01abf900-dcc9-4f61-94fe-a353d4e85bf6 # Response: { "message": "Submission found.", "submission": { "difficulty": "daniel-reiss", "id": "01abf900-dcc9-4f61-94fe-a353d4e85bf6", "instrument": "guitar", "modifiers": ["no-modifiers"], "played_at": "2024-02-14T18:34:46.985Z", "player_id": "daniel-reiss", "score": 30005, "song_id": "stone-audioslave" } } ``` -------------------------------- ### REST API: Get Song Leaderboard Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Retrieves leaderboard rankings for a specific song, allowing filtering by instrument, difficulty, and modifiers. This endpoint uses a GET request with query parameters to specify the filters. The response is a list of submissions ranked by score. ```bash # Get leaderboard for a specific song with filters curl -X GET "http://localhost:8000/leaderboard/stone-audioslave?instrument=guitar&difficulty=expert&modifiers[]=no-modifiers" # Response: [ { "difficulty": "expert", "id": "8151cb1c-a1a0-473d-b491-74c7a3988189", "instrument": "guitar", "modifiers": ["no-modifiers"], "played_at": "2024-02-14T18:34:46.999Z", "player_id": "daniel-reis", "score": 30005, "song_id": "stone-audioslave" }, { "difficulty": "expert", "id": "8e15add1-020e-4a84-90cc-2c48d6c246cb", "instrument": "guitar", "modifiers": ["no-modifiers"], "played_at": "2024-02-26T13:13:51.346Z", "player_id": "startupme", "score": 19999, "song_id": "stone-audioslave" } ] ``` -------------------------------- ### Rust Database Migration for ScyllaDB Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Automatically creates the 'prod_media_player' keyspace and necessary tables (songs, song_counter) if they do not exist upon application startup. This ensures the database schema is ready before the application proceeds. ```rust pub async fn migrate_database(database: &Database) -> Result<(), anyhow::Error> { let keyspace_name = String::from("prod_media_player"); // Verify and create keyspace let validate_keyspace_query = database.session .prepare("SELECT keyspace_name FROM system_schema.keyspaces WHERE keyspace_name=?") .await?; let has_keyspace = database.session .execute(&validate_keyspace_query, (&keyspace_name,)) .await? .rows_num() .unwrap(); if has_keyspace == 0 { let new_keyspace_query = format!( "CREATE KEYSPACE {}\n WITH replication = {{'class': 'NetworkTopologyStrategy', 'replication_factor': '3'}}\n AND durable_writes = true", &keyspace_name ); database.session.query(new_keyspace_query, &[]).await?; } // Create tables if not exists let tables = vec![ ("songs", "CREATE TABLE prod_media_player.songs ( id uuid, title text, album text, artist text, created_at timestamp, PRIMARY KEY (id, created_at) )"), ("song_counter", "CREATE TABLE prod_media_player.song_counter ( song_id uuid, times_played counter, PRIMARY KEY (song_id) )"), ]; for (table_name, table_query) in tables { let has_table = database.session .execute(&validate_table_query, (&keyspace_name, table_name)) .await? .rows_num() .unwrap(); if has_table == 0 { let prepared = database.session.prepare(table_query).await?; database.session.execute(&prepared, &[]).await?; } } Ok(()) } ``` -------------------------------- ### ScyllaDB CQL Schema for Media Player Source: https://github.com/scylladb/gaming-leaderboard/blob/main/rust/README.MD This section details the CQL (Cassandra Query Language) statements used to set up the database schema for the media player project. It includes creating the keyspace 'prod_media_player' with specific replication settings and defining two tables: 'songs' for song metadata and 'song_counter' for tracking play counts. ```sql CREATE KEYSPACE prod_media_player WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': '3'} AND durable_writes = true; CREATE TABLE prod_media_player.songs ( id uuid, title text, album text, artist text, created_at timestamp, PRIMARY KEY (id, created_at) ); CREATE TABLE prod_media_player.song_counter ( song_id uuid, times_played counter, PRIMARY KEY (song_id) ); ``` -------------------------------- ### Create ScyllaDB Keyspaces (CQL) Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Defines the initial keyspace creation for the ScyllaDB Gaming Leaderboard project using NetworkTopologyStrategy for distributed clusters. This is a foundational step for setting up the database schema. ```cql CREATE KEYSPACE prod_media_player WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': '3'} AND durable_writes = true; CREATE KEYSPACE leaderboard WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': '3'} AND durable_writes = true; ``` -------------------------------- ### Delete Outdated Leaderboard Score in ScyllaDB Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/design-and-data-model.md Deletes a specific leaderboard entry from the 'song_leaderboard' table if its score is less than a specified value (1000 in this example). This is used to remove older, lower scores for a given song and player. ```cql DELETE FROM leaderboard.song_leaderboard WHERE song_id = 'starlight-muse' AND modifiers = {'none'} AND difficulty = 'expert' AND instrument = 'guitar' AND player_id = 'daniel-reis' AND score < 1000; ``` -------------------------------- ### Rust Submission Data Transfer Object (DTO) Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/build-with-rust.md Defines a Submission DTO in Rust using Charybdis types and Serde for JSON deserialization. It includes validation attributes for incoming JSON payloads. ```rust // file: src/http/requests/submission_request.rs use charybdis::types::{Frozen, Int, Set, Text}; use serde::Deserialize; use validator::Validate; #[derive(Deserialize, Debug, Validate)] pub struct SubmissionDTO { pub song_id: Text, pub player_id: Text, pub modifiers: Frozen>, pub score: Int, pub difficulty: Text, pub instrument: Text, } ``` -------------------------------- ### Create ScyllaDB 'Submissions' Table Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/design-and-data-model.md Defines the 'submissions' table within the 'leaderboard' keyspace. This table stores individual game submission details, including player, song, score, and modifiers. It uses 'submission_id' and 'played_at' as primary keys. ```cql CREATE TABLE IF NOT EXISTS leaderboard.submissions ( submission_id uuid, song_id text, player_id text, modifiers frozen>, score int, difficulty text, instrument text, played_at timestamp, PRIMARY KEY (submission_id, played_at) ); ``` -------------------------------- ### Create Gaming Leaderboard Tables (CQL) Source: https://context7.com/scylladb/gaming-leaderboard/llms.txt Defines tables for the gaming leaderboard, including 'submissions', 'song_leaderboard', and a materialized view 'user_submissions'. These tables are optimized for score tracking and user history with composite partition keys and clustering orders. ```cql -- Submissions table for storing gameplay records CREATE TABLE IF NOT EXISTS leaderboard.submissions ( submission_id uuid, song_id text, player_id text, modifiers frozen>, score int, difficulty text, instrument text, played_at timestamp, PRIMARY KEY (submission_id, played_at) ); -- Song leaderboard with composite partition key for filtered queries CREATE TABLE IF NOT EXISTS leaderboard.song_leaderboard ( submission_id uuid, song_id text, player_id text, modifiers frozen>, score int, difficulty text, instrument text, played_at timestamp, PRIMARY KEY ((song_id, modifiers, difficulty, instrument), score, player_id) ) WITH CLUSTERING ORDER BY (score DESC, player_id ASC); -- Materialized view for user submission history CREATE MATERIALIZED VIEW leaderboard.user_submissions AS SELECT * FROM leaderboard.submissions WHERE submission_id IS NOT null AND player_id IS NOT null AND played_at IS NOT null PRIMARY KEY ((player_id), played_at, submission_id) WITH CLUSTERING ORDER BY (played_at DESC); ``` -------------------------------- ### Create ScyllaDB Materialized View for User History Source: https://github.com/scylladb/gaming-leaderboard/blob/main/docs/source/design-and-data-model.md Creates a materialized view 'user_submissions' from the 'submissions' table. This view is optimized for retrieving a user's submission history, partitioned by 'player_id' and clustered by 'played_at' in descending order. ```cql CREATE MATERIALIZED VIEW leaderboard.user_submissions AS SELECT * FROM leaderboard.submissions WHERE submission_id IS NOT null AND player_id IS NOT null AND played_at IS NOT null PRIMARY KEY ((player_id), played_at, submission_id) WITH CLUSTERING ORDER BY (played_at DESC); ```