> For the complete documentation index, see [llms.txt](https://docs.lingoql.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lingoql.com/sub0/extras.md).

# Extras

### SQL timestamp behavior

When you set `with_timestamps: true`, Sub0 updates timestamp fields automatically.

#### Inserts and updates

Sub0 applies these changes during `INSERT` and `UPDATE` queries.

```jsx
// Handles these cases:

// UPDATE query - adds updated_at if not present
INPUT: "UPDATE users SET name = 'John', email = 'john@example.com'";
Result: "UPDATE users SET updated_at = CURRENT_TIMESTAMP, name = 'John', email = 'john@example.com'"

// INSERT query - adds both created_at and updated_at
INPUT: "INSERT INTO users (name, email) VALUES ('John', 'john@example.com');";
Result: "INSERT INTO users (name, email, created_at, updated_at) VALUES ('John', 'john@example.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);"

// Query with semicolon
INPUT: "UPDATE products SET price = 100 WHERE id = 1;";
Result: "UPDATE products SET updated_at = CURRENT_TIMESTAMP, price = 100 WHERE id = 1;"
```

#### Deletes with soft delete

When you set `soft_delete: true`, `DELETE` queries are converted into `UPDATE` queries that set `deleted_at`.

```jsx
// Handles these cases:

// Basic DELETE with WHERE
INPUT: "DELETE FROM users WHERE id = 1";
Result: "UPDATE users SET deleted_at = CURRENT_TIMESTAMP WHERE id = 1 AND deleted_at IS NULL")

// DELETE with semicolon
INPUT: "DELETE FROM products WHERE status = 'inactive';";
Result: "UPDATE products SET deleted_at = CURRENT_TIMESTAMP WHERE status = 'inactive' AND deleted_at IS NULL;"

// DELETE without WHERE
INPUT: "DELETE FROM temp_data";
Result: "UPDATE temp_data SET deleted_at = CURRENT_TIMESTAMP WHERE deleted_at IS NULL"

// Already has deleted_at IS NULL in WHERE
INPUT: "DELETE FROM orders WHERE user_id = 5 AND deleted_at IS NULL";
Result: "UPDATE orders SET deleted_at = CURRENT_TIMESTAMP WHERE user_id = 5 AND deleted_at IS NULL"

// Already targets deleted records (deleted_at IS NOT NULL) - returns None
INPUT: "DELETE FROM logs WHERE deleted_at IS NOT NULL AND created_at < '2023-01-01'";
Result: NOTHING CHANGES! YOUR ORIGINAL QUERY STAYS THE SAME.

// Already converted to UPDATE with deleted_at - returns None
INPUT: "UPDATE users SET deleted_at = CURRENT_TIMESTAMP WHERE id = 1";
Result: NOTHING CHANGES! YOUR ORIGINAL QUERY STAYS THE SAME.
```

#### Select queries with soft delete

When soft delete is enabled, select queries exclude deleted records by appending `deleted_at IS NULL` where needed.

```jsx
// Subquery in WHERE
INPUT: "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100)";
Result: "SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100) AND deleted_at IS NULL"

// Multiple AND/OR conditions
INPUT: "SELECT * FROM products WHERE (category = 'electronics' OR category = 'computers') AND price > 500";
Result: "SELECT * FROM products WHERE (category = 'electronics' OR category = 'computers') AND price > 500 AND deleted_at IS NULL"

// UNION query
INPUT: "SELECT id, name FROM active_users UNION SELECT id, name FROM inactive_users";
Result: "SELECT id, name FROM active_users WHERE deleted_at IS NULL UNION SELECT id, name FROM inactive_users WHERE deleted_at IS NULL"

// JOIN with multiple tables
INPUT: "SELECT u.name, o.total, p.name FROM users u JOIN orders o ON u.id = o.user_id JOIN products p ON o.product_id = p.id WHERE o.status = 'complete'";
Result: "SELECT u.name, o.total, p.name FROM users u JOIN orders o ON u.id = o.user_id JOIN products p ON o.product_id = p.id WHERE o.status = 'complete' AND deleted_at IS NULL"

// Query with GROUP BY and HAVING
INPUT: "SELECT category, COUNT(*) as count FROM products GROUP BY category HAVING COUNT(*) > 10";
Result: "SELECT category, COUNT(*) as count FROM products WHERE deleted_at IS NULL GROUP BY category HAVING COUNT(*) > 10"

// Nested subquery in SELECT
INPUT: "SELECT id, (SELECT COUNT(*) FROM orders WHERE user_id = users.id) as order_count FROM users";
Result: "SELECT id, (SELECT COUNT(*) FROM orders WHERE user_id = users.id) as order_count FROM users WHERE deleted_at IS NULL"

// Query with CASE statement
INPUT: "SELECT id, name, CASE WHEN status = 'active' THEN 'Yes' ELSE 'No' END as is_active FROM users";
Result: "SELECT id, name, CASE WHEN status = 'active' THEN 'Yes' ELSE 'No' END as is_active FROM users WHERE deleted_at IS NULL"

// Anything other than these (or combination of these or already has deleted_at clause), your original query gets executed!  
```

### Deployment safety

LingoQL, including Sub0, uses a **blue-green deployment strategy**.

New deployments are provisioned, warmed up, and health-checked in isolation. Traffic only shifts after the new version is stable.

If something goes wrong:

* Traffic is instantly routed back to the previous healthy version
* No requests are dropped
* No downtime is introduced

This gives you:

* **Zero-downtime deployments**
* **Safe rollbacks**
* **Continuous availability for production systems**

Sub0 makes repeated production deploys safer by default.

***

### Built-in database safety enforcement

Sub0 also includes database execution safeguards to reduce accidental or destructive data loss.

By default, Sub0 does **not** allow destructive database operations through API actionables. That includes unrestricted `DROP`, mass `TRUNCATE`, `ALTER`, `RENAME`, and unsafe schema mutations.

All incoming queries are analyzed before execution:

* Dangerous or destructive queries are **automatically flagged**
* The request **fails safely before execution**
* No partial writes or side effects occur

To execute destructive database operations, access the database directly with tools such as:

* pgAdmin
* Adminer
* phpMyAdmin
* Native database clients

This helps ensure:

* Production APIs cannot accidentally destroy data
* Blast radius is tightly controlled
* Destructive actions require deliberate, privileged access

***

### Safety by default

Sub0 is designed so unsafe states are not exposed through APIs. Deployment risk, execution risk, and data-destruction risk are constrained at the system level.

> With Sub0, safety is enforced behavior.

***

### Staying up to date

Sub0 is updated continuously with performance improvements, new capabilities, and security updates. You are notified when a new version is available.

To run the latest version of Sub0, redeploy your application:

* **Soft redeploy** — restarts the runtime with the latest Sub0 build without resetting state
* **Hard redeploy** — performs a full restart and reinitialization with the latest Sub0 build

No manual upgrades or migrations are required.

***

### Release schedule

* **Updates are published weekly**
* **Release day:** Friday
* **Release time:** 00:00 UTC

Redeploying after a release automatically pulls in the newest Sub0 runtime.

***

Sub0 keeps upgrades predictable and low-friction, so you can move fast without version drift.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.lingoql.com/sub0/extras.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
