Files
sqlpage--sqlpage/src/lib.rs
T
wehub-resource-sync d718c5a372
CI / compile_and_lint (push) Failing after 0s
CI / docker_build (linux/amd64, -linux-amd64-duckdb, duckdb) (push) Failing after 0s
CI / docker_build (linux/arm64, -linux-arm64, minimal) (push) Failing after 2s
CI / docker_build (linux/arm64, -linux-arm64-duckdb, duckdb) (push) Failing after 1s
CI / docker_build (linux/amd64, minimal) (push) Failing after 1s
CI / test (, sqlite, sqlite::memory:) (push) Has been skipped
CI / test (mssql, mssql, mssql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (mysql, mysql, mysql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (oracle, oracle, Driver=Oracle 21 ODBC driver;Dbq=//127.0.0.1:1521/FREEPDB1;Uid=root;Pwd=Password123!) (push) Has been skipped
CI / test (postgres, odbc, Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!, true) (push) Has been skipped
CI / test (postgres, postgres, postgres://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / playwright (push) Has been skipped
CI / docker_build (linux/arm/v7, -linux-arm-v7, minimal) (push) Failing after 0s
CI / hurl_examples (push) Failing after 8s
deploy website / deploy_official_site (push) Failing after 1s
CI / hurl (${{ matrix.example }}) (push) Has been skipped
CI / docker_push (duckdb) (push) Has been cancelled
CI / docker_push (minimal) (push) Has been cancelled
CI / windows_test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:31:57 +08:00

159 lines
5.9 KiB
Rust

#![deny(clippy::pedantic)]
#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
//! [SQLPage](https://sql-page.com) is a high-performance web server that converts SQL queries
//! into dynamic web applications by rendering [handlebars templates](https://sql-page.com/custom_components.sql)
//! with data coming from SQL queries declared in `.sql` files.
//!
//! # Overview
//!
//! `SQLPage` is a web server that lets you build data-centric applications using only SQL queries.
//! It automatically converts database queries into professional-looking web pages using pre-built components
//! for common UI patterns like [tables](https://sql-page.com/component.sql?component=table),
//! [charts](https://sql-page.com/component.sql?component=chart),
//! [forms](https://sql-page.com/component.sql?component=form), and more.
//!
//! # Key Features
//!
//! - **SQL-Only Development**: Build full web applications without HTML, CSS, or JavaScript
//! - **Built-in Components**: Rich library of [pre-made UI components](https://sql-page.com/documentation.sql)
//! - **Security**: Protection against [SQL injection, XSS and other vulnerabilities](https://sql-page.com/safety.sql)
//! - **Performance**: [Optimized request handling and rendering](https://sql-page.com/performance.sql)
//! - **Database Support**: Works with `SQLite`, `PostgreSQL`, `MySQL`, and MS SQL Server
//!
//! # Architecture
//!
//! The crate is organized into several key modules:
//!
//! - [`webserver`]: Core HTTP server implementation using actix-web
//! - [`render`]: Component rendering system, streaming rendering of the handlebars templates with data
//! - [`templates`]: Pre-defined UI component definitions
//! - [`file_cache`]: Caching layer for SQL file parsing
//! - [`filesystem`]: Abstract interface for disk and DB-stored files
//! - [`app_config`]: Configuration and environment handling
//!
//! # Query Processing Pipeline
//!
//! When processing a request, `SQLPage`:
//!
//! 1. Parses the SQL using sqlparser-rs. Once a SQL file is parsed, it is cached for later reuse.
//! 2. Executes queries through sqlx.
//! 3. Finds the requested component's handlebars template in the database or in the filesystem.
//! 4. Maps results to the component template, using handlebars-rs.
//! 5. Streams rendered HTML to the client.
//!
//! # Extended Functionality
//!
//! - [Custom SQL Functions](https://sql-page.com/functions.sql)
//! - [Custom Components](https://sql-page.com/custom_components.sql)
//! - [Authentication & Sessions](https://sql-page.com/examples/authentication)
//! - [File Uploads](https://sql-page.com/examples/handle_picture_upload.sql)
//!
//! # Example
//!
//! ```sql
//! -- Open a data list component
//! SELECT 'list' as component, 'Users' as title;
//!
//! -- Populate it with data
//! SELECT
//! name as title,
//! email as description
//! FROM users
//! ORDER BY created_at DESC;
//! ```
//!
//! For more examples and documentation, visit:
//! - [Getting Started Guide](https://sql-page.com/get%20started.sql)
//! - [Component Reference](https://sql-page.com/components.sql)
//! - [Example Gallery](https://sql-page.com/examples/tabs)
extern crate core;
pub mod app_config;
pub mod cli;
pub mod dynamic_component;
pub mod file_cache;
pub mod filesystem;
pub mod render;
pub mod telemetry;
pub mod telemetry_metrics;
pub mod template_helpers;
pub mod templates;
pub mod utils;
pub mod webserver;
use crate::app_config::AppConfig;
use crate::filesystem::FileSystem;
use crate::webserver::database::ParsedSqlFile;
use crate::webserver::oidc::OidcState;
use file_cache::FileCache;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use telemetry_metrics::TelemetryMetrics;
use templates::AllTemplates;
use webserver::Database;
/// `TEMPLATES_DIR` is the directory where .handlebars files are stored
/// When a template is requested, it is looked up in `sqlpage/templates/component_name.handlebars` in the database,
/// or in `$SQLPAGE_CONFIGURATION_DIRECTORY/templates/component_name.handlebars` in the filesystem.
pub const TEMPLATES_DIR: &str = "sqlpage/templates/";
pub const MIGRATIONS_DIR: &str = "migrations";
pub const ON_CONNECT_FILE: &str = "on_connect.sql";
pub const ON_RESET_FILE: &str = "on_reset.sql";
pub const DEFAULT_404_FILE: &str = "default_404.sql";
pub struct AppState {
pub db: Database,
all_templates: AllTemplates,
sql_file_cache: FileCache<ParsedSqlFile>,
file_system: FileSystem,
config: AppConfig,
pub oidc_state: Option<Arc<OidcState>>,
pub telemetry_metrics: TelemetryMetrics,
}
impl AppState {
pub async fn init(config: &AppConfig) -> anyhow::Result<Self> {
let db = Database::init(config).await?;
Self::init_with_db(config, db).await
}
pub async fn init_with_db(config: &AppConfig, db: Database) -> anyhow::Result<Self> {
let all_templates = AllTemplates::init(config)?;
let mut sql_file_cache = FileCache::new();
let file_system = FileSystem::init(&config.web_root, &db).await;
sql_file_cache.add_static(
PathBuf::from("index.sql"),
ParsedSqlFile::new(&db, include_str!("index.sql"), Path::new("index.sql")),
);
sql_file_cache.add_static(
PathBuf::from(DEFAULT_404_FILE),
ParsedSqlFile::new(
&db,
include_str!("default_404.sql"),
Path::new(DEFAULT_404_FILE),
),
);
let oidc_state = crate::webserver::oidc::initialize_oidc_state(config).await?;
let telemetry_metrics =
TelemetryMetrics::new(&db.connection, db.info.database_type.otel_name());
Ok(AppState {
db,
all_templates,
sql_file_cache,
file_system,
config: config.clone(),
oidc_state,
telemetry_metrics,
})
}
}
impl std::fmt::Debug for AppState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AppState").finish()
}
}