After a bit of digging into the source code and reading the forums I found a quite good workaround based on this forum post. The basic idea is to use custom database function syntax, catch and parse a special virtual function before executing the query:
UserModel::query()->where("PG_JSON_PATH(\"data->>'email'\") = :email:");
For this to work we need a specialized Postgres adapter (the one below also uses this hack to sneak in sub queries as in the original post):
class Postgresql93 extends \Phalcon\Db\Adapter\Pdo\Postgresql
{
public function query($sqlStatement, $bindParams = null, $bindTypes = null)
{
$sqlStatement = $this->handle93syntax($sqlStatement);
return parent::query($sqlStatement, $bindParams, $bindTypes);
}
private function handle93syntax($sqlStatement)
{
$specials = join('|', ['SUB_QUERY', 'PG_JSON_PATH']);
$pattern = "/($specials)[\\s]*\\([\\s]*\\'(.*)\\'[\\s]*\\)/";
$sqlStatement = preg_replace_callback(
$pattern,
function(array $matches){
$content = str_replace("''", "'", $matches[2]);
return $content;
},
$sqlStatement
);
return $sqlStatement;
}
}