Query builder macros
The toSqlFor(), bindingsFor(), and toRawSqlFor() macros transpile a query from its own connection's dialect, on both the base query builder and Eloquent. Disable them with the macros config key.
toSqlFor
Returns parameterized SQL for the target dialect:
$query = User::where('email', 'like', '%@example.com')->orderBy('id');
$query->toSqlFor('sqlsrv');
// 'SELECT * FROM [users] WHERE [email] LIKE ? ORDER BY [id] ASC'
The source dialect is inferred from the query's connection, so cross-database code just works.
bindingsFor
Returns bindings in the order the new SQL uses them:
$query->bindingsFor('sqlsrv');
// ['%@example.com']
Why a separate method? Some rewrites move or repeat placeholders:
- SQL Server puts the limit first as
TOP (?)
ILIKE becomes LOWER(a) LIKE LOWER(?) in MySQL, duplicating a binding
Each ? is tracked through the transpile, so the returned array always lines up with toSqlFor().
toRawSqlFor
Returns SQL with bindings interpolated, for debugging and logging:
$query->toRawSqlFor('mysql');
// "SELECT * FROM `users` WHERE `email` LIKE '%@example.com' ORDER BY `id` ASC"
transpileQuery
For raw SQL strings with bindings, use transpileQuery() directly:
use Kwasii\LaravelSqlParser\Facades\LaravelSqlParser as Sql;
$result = Sql::transpileQuery($sql, $bindings, $from, $to);
// ['sql' => ..., 'bindings' => [...]]
How it works: each real ? placeholder is temporarily replaced with a named marker (:__lsp0, :__lsp1, ...), transpiled, then mapped back to ? in the order they appear in the output. A ? inside a string literal, identifier, or comment is left alone — only genuine placeholder tokens are tracked.
Sql::transpileQuery('SELECT * FROM t WHERE a = ? AND b = ?', [1, 2], 'mysql', 'postgres');
// ['sql' => 'SELECT * FROM t WHERE a = $1 AND b = $2', 'bindings' => [1, 2]]
Note: ? inside strings is not treated as a placeholder. Token-aware scanning means 'what?' stays intact.
Disabling macros
// config/laravel-sql-parser.php
'macros' => false,