- Fixed the QueryBuilder's escaping problem - adapters are now responsible for escaping identifiers.

- Added a MsSQL offset query fragment. There is still a problem with the way the Repository must act within another adapter.
This commit is contained in:
Dave Mc Nicoll 2020-04-14 09:47:09 -04:00
parent 3ff97f3bf0
commit 026a0f4f83
8 changed files with 75 additions and 26 deletions

View File

@ -7,7 +7,8 @@ use PDO,
class PdoObject extends PDO {
public function select(string $sql, array $parameters = []): PDOStatement {
public function select(string $sql, array $parameters = []): PDOStatement
{
try {
if (false !== ( $statement = $this->prepare($sql) )) {
$statement = $this->execute($statement, $parameters, false);
@ -21,7 +22,8 @@ class PdoObject extends PDO {
}
}
public function runQuery(string $sql, array $parameters = []): ? PDOStatement {
public function runQuery(string $sql, array $parameters = []): ? PDOStatement
{
try {
if (false !== ( $statement = $this->prepare($sql) )) {
return $this->execute($statement, $parameters, true);
@ -34,7 +36,8 @@ class PdoObject extends PDO {
return null;
}
public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true): ? PDOStatement {
public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true): ? PDOStatement
{
try {
if ( ! $this->inTransaction() ) {
$this->beginTransaction();
@ -56,10 +59,9 @@ class PdoObject extends PDO {
catch (\PDOException $e) {
$this->rollback();
throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters));
throw $e;
}
return null;
}
}

View File

@ -44,17 +44,13 @@ abstract class Sql {
{
switch(true) {
case is_object($value):
# @TODO Make sure the object is a Field
return (string) $value;
break;
case is_string($value):
$value = "\"$value\"";
break;
return "'$value'";
case is_null($value):
$value = "NULL";
break;
return "NULL";
}
return $value;

View File

@ -95,8 +95,8 @@ trait EntityTrait {
$relationAlias = uniqid("relation_");
$repository->select("{$repository->alias}.*")
->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName() . " $bridgeAlias", $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey))
->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName() . " $relationAlias", $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias))
->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey), $bridgeAlias)
->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName(), $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias), $relationAlias)
->where( static::field($bridgeRelation->foreignKey, $relationAlias), $this->{$bridgeRelation->foreignKey} );
$this->$name = call_user_func([ $repository, $relationRelation->function ]);
@ -105,8 +105,8 @@ trait EntityTrait {
$repository = $relationRelation->entity::repository();
$repository->select("$bridgeAlias.*")
->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName() . " $bridgeAlias", $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey))
->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName() . " $relationAlias", $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias))
->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey), $bridgeAlias)
->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName(), $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias), $relationAlias)
->where( static::field($bridgeRelation->foreignKey, $relationAlias), $this->{$bridgeRelation->foreignKey} );
$bridgeName = $relation->bridgeField;

View File

@ -25,6 +25,8 @@ class Join extends Fragment {
public /*string|QueryBuilder*/ $table;
public ? string $alias;
public string $field;
public /*string|QueryBuilder*/ $value;
@ -45,6 +47,6 @@ class Join extends Fragment {
public function render() : string
{
return $this->renderSegments([ $this->side, static::SQL_TOKEN, $this->table, $this->attachment, $this->field, "=", $this->value ]);
return $this->renderSegments([ $this->side, static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->field, "=", $this->value ]);
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Ulmus\Query\MsSQL;
class Offset extends \Ulmus\Query\Fragment {
const SQL_TOKEN = "OFFSET %s ROWS FETCH NEXT %s ROWS ONLY";
public int $order = 95;
public int $offset;
public int $limit;
public function set(int $offset, int $limit) : self
{
$this->offset = $offset;
$this->limit = $limit;
return $this;
}
public function render() : string
{
if ( $this->offset < 0 ) {
throw new \Exception("An error occured trying to render the OFFSET fragment ; given value has to be > 0. Received {$this->offset}");
}
if ( $this->limit < 0 ) {
throw new \Exception("An error occured trying to render the LIMIT fragment ; given value has to be > 0. Received {$this->limit}");
}
return $this->renderSegments([
sprintf(static::SQL_TOKEN, $this->offset, $this->limit)
]);
}
}

View File

@ -8,9 +8,11 @@ class Offset extends Fragment {
public int $order = 95;
protected int $offset = 0;
public int $offset = 0;
public string $rows = "";
public function set($offset) : self
public function set(int $offset) : self
{
$this->offset = $offset;
@ -24,7 +26,7 @@ class Offset extends Fragment {
}
return $this->renderSegments([
static::SQL_TOKEN, $this->offset,
static::SQL_TOKEN, $this->offset, $this->rows
]);
}
}

View File

@ -79,11 +79,11 @@ class QueryBuilder
{
if ( ! $this->getFragment(Query\Update::class) ) {
if ( $schema ) {
$table = "\"$schema\".$table";
$table = "$schema.$table";
}
if ( $database ) {
$table = "\"$database\".$table";
$table = "$database.$table";
}
$update = new Query\Update();
@ -121,7 +121,7 @@ class QueryBuilder
public function from(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
{
if ( $schema ) {
$table = "\"$schema\".$table";
$table = "$schema.$table";
}
if ( $database ) {
@ -252,14 +252,18 @@ class QueryBuilder
return $this;
}
public function join(string $type, /*string | QueryBuilder*/ $table, $field, $value, bool $outer = false) : self
public function join(string $type, /*string | QueryBuilder*/ $table, $field, $value, bool $outer = false, ? string $alias = null) : self
{
$join = new Query\Join($this);
$this->push($join);
$join->set($type, $table, $field, $value);
$join->outer = $outer;
$join->alias = $alias;
return $this;
}

View File

@ -181,9 +181,16 @@ class Repository
return $this;
}
public function join(string $type, $table, $field, $value) : self
public function join(string $type, $table, $field, $value, ? string $alias = null) : self
{
$this->queryBuilder->join($type, $this->escapeTable($table), $field, $value);
$this->queryBuilder->join($type, $this->escapeTable($table), $field, $value, false, $alias);
return $this;
}
public function outerJoin(string $type, $table, $field, $value, ? string $alias = null) : self
{
$this->queryBuilder->join($type, $this->escapeTable($table), $field, $value, true, $alias);
return $this;
}
@ -455,7 +462,6 @@ class Repository
$searchRequest->count = $searchRequest->filter( clone $this )
->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND)
->likes($searchRequest->likes(), Query\Where::CONDITION_OR)
->orders($searchRequest->orders())
->groups($searchRequest->groups())
->count();