🧩 SQL Raw Expressions¶
The SQL value object allows you to embed literal SQL expressions directly in your schema or queries.
It is the official and safe way to express driver-specific SQL functions without Rubik escaping or binding them.
⚙️ Overview¶
Normally, Rubik ORM quotes and binds all values to prevent SQL injection.
However, in some cases — such as CURRENT_TIMESTAMP, NOW(), UUID() or gen_random_uuid() —
you need to embed a literal SQL expression verbatim.
That’s exactly what SQL::raw() is for.
When Rubik detects this type, it injects the expression as-is into the generated SQL, without adding quotes, parameters, or bindings.
🧱 When to Use¶
You can safely use SQL::raw() in:
| Context | Description |
|---|---|
| Column defaults | Define literal defaults such as timestamps or UUIDs |
| Query conditions | Use SQL functions inside WHERE or UPDATE clauses |
| Updates/Inserts | Set system-generated values like NOW() or datetime("now") |
| Schema builder | Add raw defaults or computed values directly in field definitions |
🧮 Example – Column Default¶
use AdaiasMagdiel\Rubik\Column;
use AdaiasMagdiel\Rubik\SQL;
class User extends Model
{
protected static string $table = 'users';
protected static function fields(): array
{
return [
'id' => Column::Integer(primaryKey: true, autoincrement: true),
'name' => Column::Varchar(length: 100, notNull: true),
'email' => Column::Varchar(length: 150, notNull: true, unique: true),
'created_at' => Column::Datetime(default: SQL::raw('CURRENT_TIMESTAMP')),
'updated_at' => Column::Datetime(default: SQL::raw('CURRENT_TIMESTAMP')),
];
}
}
Generated SQL (SQLite):
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
🔍 Example – In Queries¶
You can include raw SQL inside queries seamlessly:
use AdaiasMagdiel\Rubik\SQL;
$users = User::query()
->select([
'id',
'name',
SQL::raw('LENGTH(name) AS name_length'),
])
->all();
SQL generated:
Raw Conditions¶
SQL generated:
💡 Rubik automatically detects
SQLinstances and injects them unescaped.
✏️ Example – Updates with Raw SQL¶
SQL generated:
🧩 Example – Inserts with Raw SQL¶
User::insert([
'name' => 'Anonymous',
'email' => 'anon@example.com',
'created_at' => SQL::raw('datetime("now")'),
]);
Rubik detects the raw SQL expression and includes it directly, without binding.
⚙️ Internals¶
The SQL class is an immutable value object:
final class SQL
{
private string $expr;
public function __construct(string $expr)
{
$this->expr = $expr;
}
public function __toString(): string
{
return $this->expr;
}
public static function raw(string $expr): static
{
return new static($expr);
}
}
Internally, Rubik checks:
This logic is used consistently in:
Columnvalidators and defaultsQuerybuilder (update,where,select)SchemaTraitduring table creation
🧱 Example – Full Model with Raw Defaults¶
use AdaiasMagdiel\Rubik\Column;
use AdaiasMagdiel\Rubik\Model;
use AdaiasMagdiel\Rubik\SQL;
class Product extends Model
{
protected static string $table = 'products';
protected static function fields(): array
{
return [
'id' => Column::Integer(primaryKey: true, autoincrement: true),
'name' => Column::Varchar(length: 255, notNull: true),
'sku' => Column::Varchar(length: 50, unique: true),
'created_at' => Column::Datetime(default: SQL::raw('CURRENT_TIMESTAMP')),
'updated_at' => Column::Datetime(default: SQL::raw('CURRENT_TIMESTAMP')),
];
}
}
🧾 Summary¶
| Context | Example | SQL Output |
|---|---|---|
| Column default | Column::Datetime(default: SQL::raw('CURRENT_TIMESTAMP')) |
DEFAULT CURRENT_TIMESTAMP |
| Query select | SQL::raw('COUNT(*) AS total') |
Adds computed columns |
| WHERE clause | ->where(SQL::raw('DATE(created_at)'), '>=', SQL::raw('DATE("2025-01-01")')) |
Unquoted expressions |
| Update | ->update(['updated_at' => SQL::raw('CURRENT_TIMESTAMP')]) |
Literal update |
| Insert | 'created_at' => SQL::raw('datetime("now")') |
Raw expression |
⚠️ Security Notes¶
SQL::raw() is powerful but must be used carefully.
✅ Safe examples:
- System constants like
CURRENT_TIMESTAMP,NOW() - Internal SQL functions:
LENGTH(),DATE(),UUID()
🚫 Unsafe examples:
- Concatenating user input into
SQL::raw() - Using unvalidated external data
⚠️ Never pass user input directly to
SQL::raw(). It disables escaping, making your query vulnerable to SQL injection.
🧭 See Also¶
- Column Reference — define types and defaults with SQL expressions
- Queries — use raw SQL inside select and where clauses
💡 If you need full control over SQL fragments,
SQL::raw()is your trusted escape hatch — minimal, explicit, and safe when used with care.