sqlpage/
lib.rs

1#![deny(clippy::pedantic)]
2#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
3
4//! [SQLPage](https://sql-page.com) is a high-performance web server that converts SQL queries
5//! into dynamic web applications by rendering [handlebars templates](https://sql-page.com/custom_components.sql)
6//! with data coming from SQL queries declared in `.sql` files.
7//!
8//! # Overview
9//!
10//! `SQLPage` is a web server that lets you build data-centric applications using only SQL queries.
11//! It automatically converts database queries into professional-looking web pages using pre-built components
12//! for common UI patterns like [tables](https://sql-page.com/component.sql?component=table),
13//! [charts](https://sql-page.com/component.sql?component=chart),
14//! [forms](https://sql-page.com/component.sql?component=form), and more.
15//!
16//! # Key Features
17//!
18//! - **SQL-Only Development**: Build full web applications without HTML, CSS, or JavaScript
19//! - **Built-in Components**: Rich library of [pre-made UI components](https://sql-page.com/documentation.sql)
20//! - **Security**: Protection against [SQL injection, XSS and other vulnerabilities](https://sql-page.com/safety.sql)
21//! - **Performance**: [Optimized request handling and rendering](https://sql-page.com/performance.sql)
22//! - **Database Support**: Works with `SQLite`, `PostgreSQL`, `MySQL`, and MS SQL Server
23//!
24//! # Architecture
25//!
26//! The crate is organized into several key modules:
27//!
28//! - [`webserver`]: Core HTTP server implementation using actix-web
29//! - [`render`]: Component rendering system, streaming rendering of the handlebars templates with data
30//! - [`templates`]: Pre-defined UI component definitions
31//! - [`file_cache`]: Caching layer for SQL file parsing
32//! - [`filesystem`]: Abstract interface for disk and DB-stored files
33//! - [`app_config`]: Configuration and environment handling
34//!
35//! # Query Processing Pipeline
36//!
37//! When processing a request, `SQLPage`:
38//!
39//! 1. Parses the SQL using sqlparser-rs. Once a SQL file is parsed, it is cached for later reuse.
40//! 2. Executes queries through sqlx.
41//! 3. Finds the requested component's handlebars template in the database or in the filesystem.
42//! 4. Maps results to the component template, using handlebars-rs.
43//! 5. Streams rendered HTML to the client.
44//!
45//! # Extended Functionality
46//!
47//! - [Custom SQL Functions](https://sql-page.com/functions.sql)
48//! - [Custom Components](https://sql-page.com/custom_components.sql)
49//! - [Authentication & Sessions](https://sql-page.com/examples/authentication)
50//! - [File Uploads](https://sql-page.com/examples/handle_picture_upload.sql)
51//!
52//! # Example
53//!
54//! ```sql
55//! -- Open a data list component
56//! SELECT 'list' as component, 'Users' as title;
57//!
58//! -- Populate it with data
59//! SELECT
60//!     name as title,
61//!     email as description
62//! FROM users
63//! ORDER BY created_at DESC;
64//! ```
65//!
66//! For more examples and documentation, visit:
67//! - [Getting Started Guide](https://sql-page.com/get%20started.sql)
68//! - [Component Reference](https://sql-page.com/components.sql)
69//! - [Example Gallery](https://sql-page.com/examples/tabs)
70
71extern crate core;
72
73pub mod app_config;
74pub mod dynamic_component;
75pub mod file_cache;
76pub mod filesystem;
77pub mod render;
78pub mod template_helpers;
79pub mod templates;
80pub mod utils;
81pub mod webserver;
82
83use crate::app_config::AppConfig;
84use crate::filesystem::FileSystem;
85use crate::webserver::database::ParsedSqlFile;
86use crate::webserver::oidc::OidcState;
87use file_cache::FileCache;
88use std::path::{Path, PathBuf};
89use std::sync::Arc;
90use templates::AllTemplates;
91use webserver::Database;
92
93/// `TEMPLATES_DIR` is the directory where .handlebars files are stored
94/// When a template is requested, it is looked up in `sqlpage/templates/component_name.handlebars` in the database,
95/// or in `$SQLPAGE_CONFIGURATION_DIRECTORY/templates/component_name.handlebars` in the filesystem.
96pub const TEMPLATES_DIR: &str = "sqlpage/templates/";
97pub const MIGRATIONS_DIR: &str = "migrations";
98pub const ON_CONNECT_FILE: &str = "on_connect.sql";
99pub const ON_RESET_FILE: &str = "on_reset.sql";
100
101pub struct AppState {
102    pub db: Database,
103    all_templates: AllTemplates,
104    sql_file_cache: FileCache<ParsedSqlFile>,
105    file_system: FileSystem,
106    config: AppConfig,
107    pub oidc_state: Option<Arc<OidcState>>,
108}
109
110impl AppState {
111    pub async fn init(config: &AppConfig) -> anyhow::Result<Self> {
112        let db = Database::init(config).await?;
113        Self::init_with_db(config, db).await
114    }
115    pub async fn init_with_db(config: &AppConfig, db: Database) -> anyhow::Result<Self> {
116        let all_templates = AllTemplates::init(config)?;
117        let mut sql_file_cache = FileCache::new();
118        let file_system = FileSystem::init(&config.web_root, &db).await;
119        sql_file_cache.add_static(
120            PathBuf::from("index.sql"),
121            ParsedSqlFile::new(&db, include_str!("../index.sql"), Path::new("index.sql")),
122        );
123
124        let oidc_state = crate::webserver::oidc::initialize_oidc_state(config).await?;
125
126        Ok(AppState {
127            db,
128            all_templates,
129            sql_file_cache,
130            file_system,
131            config: config.clone(),
132            oidc_state,
133        })
134    }
135}
136
137impl std::fmt::Debug for AppState {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        f.debug_struct("AppState").finish()
140    }
141}