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
159 lines
5.9 KiB
Rust
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()
|
|
}
|
|
}
|