diff --git a/.cargo/config.toml b/.cargo/config.toml
index d22ed76a..9247b719 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -5,3 +5,6 @@
# set by the user, and this is a good thing. If the user already set some
# LIBSQLITE3_FLAGS, he probably knows what he is doing.
LIBSQLITE3_FLAGS = "-DSQLITE_ENABLE_MATH_FUNCTIONS"
+
+[build]
+rustflags = []
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dcb77d5e..8c11db3f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,9 +29,12 @@ jobs:
- run: npm test
- name: Set up cargo cache
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
+ with:
+ shared-key: rust-sqlpage-proj-test
+ save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo fmt --all -- --check
- run: cargo clippy --all-targets --all-features -- -D warnings
- - run: cargo test
+ - run: cargo test --features odbc-static
- name: Upload Linux binary
uses: actions/upload-artifact@v4
with:
@@ -42,23 +45,43 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- database: ["postgres", "mysql", "mssql"]
+ include:
+ - database: postgres
+ container: postgres
+ db_url: "postgres://root:Password123!@127.0.0.1/sqlpage"
+ - database: mysql
+ container: mysql
+ db_url: "mysql://root:Password123!@127.0.0.1/sqlpage"
+ - database: mssql
+ container: mssql
+ db_url: "mssql://root:Password123!@127.0.0.1/sqlpage"
+ - database: odbc
+ container: postgres
+ db_url: "Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!"
+ setup_odbc: true
steps:
- uses: actions/checkout@v4
- name: Set up cargo cache
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
+ with:
+ shared-key: rust-sqlpage-proj-test
+ save-if: false
+ - name: Install PostgreSQL ODBC driver
+ if: matrix.setup_odbc
+ run: sudo apt-get install -y odbc-postgresql
- name: Start database container
- run: docker compose up --wait ${{ matrix.database }}
+ run: docker compose up --wait ${{ matrix.container }}
- name: Show container logs
if: failure()
- run: docker compose logs ${{ matrix.database }}
+ run: docker compose logs ${{ matrix.container }}
- name: Run tests against ${{ matrix.database }}
timeout-minutes: 5
- run: cargo test
+ run: cargo test --features odbc-static
env:
- DATABASE_URL: ${{ matrix.database }}://root:Password123!@127.0.0.1/sqlpage
+ DATABASE_URL: ${{ matrix.db_url }}
RUST_BACKTRACE: 1
- RUST_LOG: sqlpage=debug
+ MALLOC_CHECK_: 3
+ MALLOC_PERTURB_: 10
windows_test:
runs-on: windows-latest
@@ -73,7 +96,7 @@ jobs:
RUST_BACKTRACE: 1
- name: Upload Windows binary
uses: actions/upload-artifact@v4
- with:
+ with:
name: sqlpage-windows-debug
path: "target/debug/sqlpage.exe"
diff --git a/.github/workflows/official-site.yml b/.github/workflows/official-site.yml
index 0ec66068..3ad48ef3 100644
--- a/.github/workflows/official-site.yml
+++ b/.github/workflows/official-site.yml
@@ -8,7 +8,7 @@ on:
concurrency: site-deploy
jobs:
- deploy:
+ deploy_official_site:
runs-on: ubuntu-latest
steps:
- name: Cloning repo
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 72fb4cd6..7865ab24 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -20,10 +20,8 @@ jobs:
node-version: lts/*
cache: 'npm'
cache-dependency-path: ./tests/end-to-end/package-lock.json
- - name: Install dependencies
- run: |
- npm ci
- npx playwright install --with-deps chromium
+ - run: sudo apt-get update && sudo apt-get install -y unixodbc-dev
+ - run: npm ci && npx playwright install --with-deps chromium
- name: build sqlpage
run: cargo build
working-directory: ./examples/official-site
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index de671e73..e32cf37e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -24,8 +24,10 @@ jobs:
- os: windows-latest
binary_extension: .exe
target: x86_64-pc-windows-msvc
+ features: ""
- os: macos-latest
target: x86_64-apple-darwin
+ features: "odbc-static"
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
@@ -35,7 +37,7 @@ jobs:
- name: Set up cargo cache
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
- name: Build
- run: cargo build --profile superoptimized --locked --target ${{ matrix.target }}
+ run: cargo build --profile superoptimized --locked --target ${{ matrix.target }} --features "${{ matrix.features }}"
- name: Upload unsigned Windows artifact
if: matrix.os == 'windows-latest'
id: upload_unsigned
@@ -57,6 +59,9 @@ jobs:
github-artifact-id: ${{ steps.upload_unsigned.outputs.artifact-id }}
wait-for-completion: true
output-artifact-directory: './signed-windows'
+ wait-for-completion-timeout-in-seconds: 7200
+ service-unavailable-timeout-in-seconds: 1800
+ download-signed-artifact-timeout-in-seconds: 1800
- name: Upload signed Windows artifact
if: matrix.os == 'windows-latest'
@@ -87,7 +92,7 @@ jobs:
- name: Set up cargo cache
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
- name: Build
- run: cargo build --profile superoptimized --locked --target x86_64-unknown-linux-gnu
+ run: cargo build --profile superoptimized --locked --target x86_64-unknown-linux-gnu --features "odbc-static"
- uses: actions/upload-artifact@v4
with:
name: sqlpage ubuntu-latest
@@ -145,5 +150,6 @@ jobs:
- uses: actions/checkout@v4
- name: Set up cargo cache
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
+ - run: sudo apt-get update && sudo apt-get install -y unixodbc-dev
- name: Publish to crates.io
run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}
diff --git a/.gitignore b/.gitignore
index a1a6898f..9cf4a906 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.DS_STORE
/target
sqlpage.db
.idea/
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..ababedd5
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,47 @@
+Core Concept: User writes .sql files, SQLPage executes queries, results mapped to handlebars UI components,
+HTML streamed to client
+
+## Validation
+
+### When working on rust code
+Mandatory formatting (rust): `cargo fmt --all`
+Mandatory linting: `cargo clippy --all-targets --all-features -- -D warnings`
+
+### When working on css or js
+Frontend formatting: `npm run format`
+
+More about testing: see [github actions](./.github/workflows/ci.yml).
+Project structure: see [contribution guide](./CONTRIBUTING.md)
+
+NEVER reformat/lint/touch files unrelated to your task. Always run tests/lints/format before stopping when you changed code.
+
+### Testing
+
+```
+cargo test # tests with inmemory sqlite by default
+```
+
+For other databases, see [docker testing setup](./docker-compose.yml)
+
+```
+docker compose up -d mssql # or postgres or mysql
+DATABASE_URL='mssql://root:Password123!@localhost/sqlpage' cargo test # all dbms use the same user:pass and db name
+```
+
+### Documentation
+
+Components and functions are documented in [official website](./examples/official-site/sqlpage/migrations/); one migration per component and per function. You CAN update existing migrations, the official site database is recreated from scratch on each deployment.
+
+official documentation website sql tables:
+ - `component(name,description,icon,introduced_in_version)` -- icon name from tabler icon
+ - `parameter(top_level BOOLEAN, name, component REFERENCES component(name), description, description_md, type, optional BOOLEAN)` parameter types: BOOLEAN, COLOR, HTML, ICON, INTEGER, JSON, REAL, TEXT, TIMESTAMP, URL
+ - `example(component REFERENCES component(name), description, properties JSON)`
+
+#### Project Conventions
+
+- Components: defined in `./sqlpage/templates/*.handlebars`
+- Functions: `src/webserver/database/sqlpage_functions/functions.rs` registered with `make_function!`.
+- [Configuration](./configuration.md): see [AppConfig](./src/app_config.rs)
+- Routing: file-based in `src/webserver/routing.rs`; not found handled via `src/default_404.sql`.
+- Follow patterns from similar modules before introducing new abstractions.
+- frontend: see [css](./sqlpage/sqlpage.css) and [js](./sqlpage/sqlpage.js)
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 124126a3..067dfe10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,115 @@
# CHANGELOG.md
+## unreleased
+ - fix: `sqlpage.variables()` now does not return json objects with duplicate keys when post, get and set variables of the same name are present. The semantics of the returned values remains the same (precedence: set > post > get).
+
+## 0.41.0 (2025-12-28)
+ - **New Function**: `sqlpage.oidc_logout_url(redirect_uri)` - Generates a secure logout URL for OIDC-authenticated users with support for [RP-Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout)
+ - Fix compatibility with Auth0 for OpenID-Connect authentification. See https://github.com/ramosbugs/openidconnect-rs/issues/23
+ - updated sql parser: https://github.com/apache/datafusion-sqlparser-rs/blob/main/changelog/0.60.0.md
+ - updated apexcharts to 5.3.6:
+ - https://github.com/apexcharts/apexcharts.js/compare/v5.3.0...v5.3.6
+ - https://github.com/apexcharts/apexcharts.js/releases/tag/v5.3.6
+ - re-add the `lime` color option to charts
+ - update default chart color palette; use [Open Colors](https://yeun.github.io/open-color/)
+ -
+ - re-enable text drop shadow in chart data labels
+
+## 0.40.0 (2025-11-28)
+ - OIDC login redirects now use HTTP 303 responses so POST submissions are converted to safe GET requests before reaching the identity provider, fixing incorrect reuse of the original POST (HTTP 307) that could break standard auth flows.
+ - SQLPage now respects [HTTP accept headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept) for JSON. You can now easily process the contents of any existing sql page programmatically with:
+ - `curl -H "Accept: application/json" http://example.com/page.sql`: returns a json array
+ - `curl -H "Accept: application/x-ndjson" http://example.com/page.sql`: returns one json object per line.
+ - Fixed a bug in `sqlpage.link`: a link with no path (link to the current page) and no url parameter now works as expected. It used to keep the existing url parameters instead of removing them. `sqlpage.link('', '{}')` now returns `'?'` instead of the empty string.
+ - `sqlpage.fetch(null)` and `sqlpage.fetch_with_meta(null)` now return `null` instead of throwing an error.
+ - **New Function**: `sqlpage.set_variable(name, value)`
+ - Returns a URL with the specified variable set to the given value, preserving other existing variables.
+ - This is a shorthand for `sqlpage.link(sqlpage.path(), json_patch(sqlpage.variables('get'), json_object(name, value)))`.
+ - **Variable System Improvements**: URL and POST parameters are now immutable, preventing accidental modification. User-defined variables created with `SET` remain mutable.
+ - **BREAKING**: `$variable` no longer accesses POST parameters. Use `:variable` instead.
+ - **What changed**: Previously, `$x` would return a POST parameter value if no GET parameter named `x` existed.
+ - **Fix**: Replace `$x` with `:x` when you need to access form field values.
+ - **Example**: Change `SELECT $username` to `SELECT :username` when reading form submissions.
+ - **BREAKING**: `SET $name` no longer makes GET (URL) parameters inaccessible when a URL parameter with the same name exists.
+ - **What changed**: `SET $name = 'value'` would previously overwrite the URL parameter `$name`. Now it creates an independent SET variable that shadows the URL parameter.
+ - **Fix**: This is generally the desired behavior. If you need to access the original URL parameter after setting a variable with the same name, extract it from the JSON returned by `sqlpage.variables('get')`.
+ - **Example**: If your URL is `page.sql?name=john`, and you do `SET $name = 'modified'`, then:
+ - `$name` will be `'modified'` (the SET variable)
+ - The original URL parameter is still preserved and accessible:
+ - `sqlpage.variables('get')->>'name'` returns `'john'`
+ - **New behavior**: Variable lookup now follows this precedence:
+ - `$variable` checks SET variables first, then URL parameters
+ - SET variables always shadow URL/POST parameters with the same name
+ - **New sqlpage.variables() filters**:
+ - `sqlpage.variables('get')` returns only URL parameters as JSON
+ - `sqlpage.variables('post')` returns only POST parameters as JSON
+ - `sqlpage.variables('set')` returns only user-defined SET variables as JSON
+ - `sqlpage.variables()` returns all variables merged together, with SET variables taking precedence
+ - **Deprecation warnings**: Using `$var` when both a URL parameter and POST parameter exist with the same name now shows a warning. In a future version, you'll need to explicitly choose between `$var` (URL) and `:var` (POST).
+ - Improved performance of `sqlpage.run_sql`.
+ - On a simple test that just runs 4 run_sql calls, the new version is about 2.7x faster (15,708 req/s vs 5,782 req/s) with lower latency (0.637 ms vs 1.730 ms per request).
+ - add support for postgres range types
+
+## v0.39.1 (2025-11-08)
+ - More precise server timing tracking to debug performance issues
+ - Fix missing server timing header in some cases
+ - Implement nice error messages for some header-related errors such as invalid header values.
+ - `compress_responses` is now set to `false` by default in the configuration.
+ - When response compression is enabled, additional buffering is needed. Users reported a better experience with pages that load more progressively, reducing the time before the pages' shell is rendered.
+ - When SQLPage is deployed behind a reverse proxy, compressing responses between sqlpage and the proxy is wasteful.
+ - In the table component, allow simple objects in custom_actions instead of requiring arrays of objects.
+ - Fatser icon loading. Previously, even a page containing a single icon required downloading and parsing a ~2MB file. This resulted in a delay where pages initially appeared with a blank space before icons appeared. Icons are now inlined inside pages and appear instantaneously.
+ - Updated tabler icons to 3.35
+ - Fix inaccurate ODBC warnings
+ - Added support for Microsoft SQL Server named instances: `mssql://user:pass@localhost/db?instance_name=xxx`
+ - Added a detailed [performance guide](https://sql-page.com/blog?post=Performance+Guide) to the docs.
+
+## v0.39.0 (2025-10-28)
+ - Ability to execute sql for URL paths with another extension. If you create sitemap.xml.sql, it will be executed for example.com/sitemap.xml
+ - Display source line info in errors even when the database does not return a precise error position. In this case, the entire problematic SQL statement is referenced.
+ - The shell with a vertical sidebar can now have "active" elements, just like the horizontal header bar.
+ - New `edit_url`, `delete_url`, and `custom_actions` properties in the [table](https://sql-page.com/component.sql?component=table) component to easily add nice icon buttons to a table.
+ - SQLPage now sets the [`Server-Timing` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing) in development. So when you have a page that loads slowly, you can open your browser's network inspector, click on the slow request, then open the timing tab to understand where it's spending its time.
+ -
+ - Fixed a memory corruption issue in the builtin odbc driver manager
+ - ODBC: fix using globally installed system drivers by their name in debian-based linux distributions.
+ - New [login](https://sql-page.com/component.sql?component=table) component.
+
+
+## v0.38.0
+ - Added support for the Open Database Connectivity (ODBC) standard.
+ - This makes SQLPage compatible with many new databases, including:
+ - [*ClickHouse*](https://github.com/ClickHouse/clickhouse-odbc),
+ - [*MongoDB*](https://www.mongodb.com/docs/atlas/data-federation/query/sql/drivers/odbc/connect),
+ - [*DuckDB*](https://duckdb.org/docs/stable/clients/odbc/overview.html), and through it [many other data sources](https://duckdb.org/docs/stable/data/data_sources),
+ - [*Oracle*](https://www.oracle.com/database/technologies/releasenote-odbc-ic.html),
+ - [*Snowflake*](https://docs.snowflake.com/en/developer-guide/odbc/odbc),
+ - [*BigQuery*](https://cloud.google.com/bigquery/docs/reference/odbc-jdbc-drivers),
+ - [*IBM DB2*](https://www.ibm.com/support/pages/db2-odbc-cli-driver-download-and-installation-information),
+ - [*Trino*](https://docs.starburst.io/clients/odbc/odbc-v2.html), and through it [many other data sources](https://trino.io/docs/current/connector.html)
+ - Added a new `sqlpage.hmac()` function for cryptographic HMAC (Hash-based Message Authentication Code) operations.
+ - Create and verify secure signatures for webhooks (Shopify, Stripe, GitHub, etc.)
+ - Generate tamper-proof tokens for API authentication
+ - Secure download links and temporary access codes
+ - Supports SHA-256 (default) and SHA-512 algorithms
+ - Output formats: hexadecimal (default) or base64 (e.g., `sha256-base64`)
+ - See the [function documentation](https://sql-page.com/functions.sql?function=hmac) for detailed examples
+ - Fixed a slight spacing issue in the list components empty value display.
+ - Improved performance of setting a variable to a literal value. `SET x = 'hello'` is now executed locally by SQLPage and does not send anything to the database. This completely removes the cost of extracting static values into variables for cleaner SQL files.
+ - Enable arbitrary precision in the internal representation of numbers. This guarantees zero precision loss when the database returns very large or very small DECIMAL or NUMERIC values.
+
+## v0.37.1
+ - fixed decoding of UUID values
+ - Fixed handling of NULL values in `sqlpage.link`. They were encoded as the string `'null'` instead of being omitted from the link's parameters.
+ - Enable submenu autoclosing (on click) in the shell. This is not ideal, but this prevents a bug introduced in v0.36.0 where the page would scroll back to the top when clicking anywhere on the page after navigating from a submenu. The next version will fix this properly. See https://github.com/sqlpage/SQLPage/issues/1011
+ - Adopt the new nice visual errors introduced in v0.37.1 for "403 Forbidden" and "429 Too Many Requests" errors.
+ - Fix a bug in oidc login flows. When two tabs in the same browser initiated a login at the same time, an infinite redirect loop could be triggered. This mainly occured when restoring open tabs after a period of inactivity, often in mobile browsers.
+ - Multiple small sql parser improvements.
+ - Adds support for MERGE queries inside CTEs, and MERGE queries with a RETURNING clause.
+ - https://github.com/apache/datafusion-sqlparser-rs/blob/main/changelog/0.59.0.md
+
## v0.37.0
- - We now cryptographically sign the Windows app during releases, which proves the file hasn’t been tampered with. Once the production certificate is active, Windows will show a "verified publisher" and should stop showing screens saying "This app might harm your device", "Windows protected your PC" or "Are you sure you want to run this application ?".
+ - We now cryptographically sign the Windows app during releases, which proves the file hasn’t been tampered with. Once the production certificate is active, Windows will show a "verified publisher" and should stop showing screens saying "This app might harm your device", "Windows protected your PC" or "Are you sure you want to run this application ?".
- Thanks to https://signpath.io for providing us with a windows signing certificate !
- Added a new parameter `encoding` to the [fetch](https://sql-page.com/functions.sql?function=fetch) function:
- All [standard web encodings](https://encoding.spec.whatwg.org/#concept-encoding-get) are supported.
@@ -27,7 +135,7 @@
- The form component now considers numbers and their string representation as equal when comparing the `value` parameter and the values from the `options` parameter in dropdowns. This makes it easier to use variables (which are always strings) in the value parameter in order to preserve a dropdown field value across page reloads. The following is now valid:
- ```sql
select 'form' as component;
- select
+ select
'select' as type,
true as create_new,
true as dropdown,
@@ -42,17 +150,17 @@
## v0.36.0
- added support for the MONEY and SMALLMONEY types in MSSQL.
- - include [math functions](https://sqlite.org/lang_mathfunc.html) in the builtin sqlite3 database.
+ - include [math functions](https://sqlite.org/lang_mathfunc.html) in the builtin sqlite3 database.
- the sqlpage binary can now help you create new empty migration files from the command line:
```
❯ ./sqlpage create-migration my_new_table
Migration file created: sqlpage/migrations/20250627095944_my_new_table.sql
- ```
+ ```
- New [modal](https://sql-page.com/component.sql?component=modal) component
- In bar charts: Sort chart categories by name instead of first appearance. This is useful when displaying cumulative bar charts with some series missing data for some x values.
- Updated tabler to v1.4 https://github.com/tabler/tabler/releases/tag/%40tabler%2Fcore%401.4.0
- Updated tabler-icons to v3.34 (19 new icons) https://tabler.io/changelog#/changelog/tabler-icons-3.34
- - Added support for partially private sites when using OIDC single sign-on:
+ - Added support for partially private sites when using OIDC single sign-on:
- The same SQLPage application can now have both publicly accessible and private pages accessible to users authenticated with SSO.
- This allows easily creating a "log in page" that redirects to the OIDC provider.
- See the [configuration](./configuration.md) for `oidc_protected_paths`
@@ -136,84 +244,84 @@
## v0.34 (2025-03-23)
### ✨ Top Features at a Glance
-- **Safer deletion flows** in lists
-- **Better table styling control** with CSS updates
-- **Right-to-Left language support**
-- **HTML-enhanced Markdown** in text components
-- **Sticky table footers** for better data presentation
+- **Safer deletion flows** in lists
+- **Better table styling control** with CSS updates
+- **Right-to-Left language support**
+- **HTML-enhanced Markdown** in text components
+- **Sticky table footers** for better data presentation
### 🔒 Security First
-#### **POST-based Deletions**
-List component's `delete_link` now uses secure POST requests:
+#### **POST-based Deletions**
+List component's `delete_link` now uses secure POST requests:
```sql
SELECT 'list' AS component;
SELECT 'Delete me' AS title, 'delete_item.sql?id=77' AS delete_link;
```
*Prevents accidental deletions by web crawlers and follows REST best practices*
-#### **Protected Internal Files**
-- Files/folders starting with `.` (e.g., `.utils/`) are now inaccessible
+#### **Protected Internal Files**
+- Files/folders starting with `.` (e.g., `.utils/`) are now inaccessible
- Perfect for internal scripts used with `sqlpage.run_sql()`
### 🎨 UI & Component Upgrades
-#### **Table Styling Revolution**
+#### **Table Styling Revolution**
```css
/* Before: .price | After: */
-._col_price {
+._col_price {
background: #f8f9fa;
border-right: 2px solid #dee2e6;
}
```
-- New CSS class pattern: `._col_{column_name}`
-- Fixes [#830](https://github.com/sqlpage/SQLPage/issues/830)
+- New CSS class pattern: `._col_{column_name}`
+- Fixes [#830](https://github.com/sqlpage/SQLPage/issues/830)
-#### **Column component**
+#### **Column component**
```sql
SELECT 'columns' AS component;
SELECT 'View details' AS title; -- No button shown
```
-- Columns without button text now hide empty buttons
+- Columns without button text now hide empty buttons
- Cleaner interfaces by default
-#### **Sticky Table Footers**
+#### **Sticky Table Footers**
```sql
-SELECT
+SELECT
'table' AS component,
true AS freeze_footers;
-SELECT
+SELECT
'Total' AS label,
SUM(price) AS value,
true AS _sqlpage_footer;
```
-- Keep summary rows visible during scroll
+- Keep summary rows visible during scroll
- Use `_sqlpage_footer` on your final data row
### 🌍 Internationalization
-#### **Right-to-Left Support**
+#### **Right-to-Left Support**
```sql
SELECT 'shell' AS component, true AS rtl;
```
-- Enable RTL mode per page via shell component
+- Enable RTL mode per page via shell component
- Perfect for Arabic, Hebrew, and Persian content
### 📝 Content Handling
-#### **Rich Text Power**
+#### **Rich Text Power**
```sql
SELECT 'text' AS component,
'
{{description}}
+ {{/if}} +SQL queries sort, filter, and aggregate millions of rows in milliseconds. No more slow spreadsheet formulas or memory limitations. Your app remains smooth and responsive even @@ -1054,7 +1391,7 @@
SQLPage connects to the database engine you already rely on today. + Keep your data in place and surface it through a + friendly interface that stays in sync. + If you don't have a DB yet, SQLPage comes with a built-in query engine. +
+Through ODBC you can plug SQLPage into any warehouses and enterprise engines.
+