Database Guide: Architecture and Data Management
The database is a critical component of the Multi-Language Compiler, serving as the persistent storage layer for all code executions. Its primary role is to create a historical record of every code snippet that is processed by the backend. This guide details the technology, schema, and interaction patterns used to manage and store data effectively.
2. Technology Stack
The data tier is built on a modern and robust technology stack:
Database System: PostgreSQL, a powerful, open-source object-relational database system known for its reliability, feature robustness, and performance.
ORM (Object-Relational Mapper): Prisma, a next-generation ORM for Node.js and TypeScript (used here for its powerful schema management and migration tools) that integrates seamlessly with the Rust backend through the
prisma-client-rustcrate.
3. Database Schema Definition
The entire database schema is declaratively defined in a single file, which serves as the single source of truth for the data models.
Location:
db/prisma/schema.prisma
The schema defines one primary model: CodeSnippet. This model represents a single, complete record of a code execution event.
generator client {
provider = "cargo prisma" // Generates the Rust client
output = "../src/prisma.rs"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model CodeSnippet {
id Int @id @default(autoincrement())
code String
language String
output String
executionTime Int
createdAt DateTime @default(now())
}Fields Explained:
id
Int
A unique, auto-incrementing integer that serves as the Primary Key.
code
String
Stores the exact source code string that was submitted by the user.
language
String
Stores the language of the submitted code (e.g., "rust", "python").
output
String
Stores the complete captured output (stdout or stderr) from the execution.
executionTime
Int
Records the execution time of the code in milliseconds.
createdAt
DateTime
A timestamp automatically set to the moment the record is created.
4. Database Interaction in Code
The Rust backend is responsible for all communication with the database. It uses the prisma-client-rust crate, which provides a type-safe and idiomatic way to perform database queries.
4.1. Prisma Client Initialization
Before any queries can be made, the Prisma client is initialized within the Rust application. This is typically handled in main.rs.
4.2. Storing Data: The create Operation
After every code execution, a new record is created in the CodeSnippet table. The following function from main.rs demonstrates exactly how this is done.
Location:
src/main.rs(within thecompile_codehandler)
Code Explanation:
Execute Code: The
compile_codefunction first executes the user's code and captures theoutputandexecution_time.Process Output: It checks if the execution was successful. It populates a
resultstring withstdouton success, or anerrorstring withstderron failure.Prepare for Storage: A
db_outputvariable is created to hold whichever string (result or error) is non-empty. This is what will be stored in the database'soutputcolumn.Create Record: The
db.code_snippet().create(...)function is called.This is a type-safe function generated by Prisma based on your schema.
It takes all the required fields (
code,language,output,executionTime) as arguments.The
vec![]is for any optional fields that are not being set.
Execute Query: The
.exec().await?part sends theINSERTquery to the PostgreSQL database and awaits its completion.
5. Database Migrations
Prisma provides a powerful and straightforward system for managing changes to the database schema over time.
Location of Migrations:
db/prisma/migrations/
This directory contains subdirectories for each migration, each with a migration.sql file that holds the raw SQL commands needed to update the database schema.
How to Manage Migrations
All migration commands should be run from the root of the repository.
Creating a New Migration: Whenever you make a change to the
schema.prismafile, you can create a new migration by running:
This command will:
Compare the current schema to the database state.
Generate a new SQL migration file.
Apply the new migration to your development database.
Applying Migrations to Other Environments (e.g., Production): To apply all pending migrations to a database, you can run:
6. Setup and Connection
The connection between the application and the database is configured using an environment variable.
Configuration File:
.env(at the root of the project)
You must have a .env file containing the connection string for your PostgreSQL database.
Last updated