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

View File

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

View File

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

View File

@ -25,6 +25,8 @@ class Join extends Fragment {
public /*string|QueryBuilder*/ $table; public /*string|QueryBuilder*/ $table;
public ? string $alias;
public string $field; public string $field;
public /*string|QueryBuilder*/ $value; public /*string|QueryBuilder*/ $value;
@ -45,6 +47,6 @@ class Join extends Fragment {
public function render() : string 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; public int $order = 95;
protected int $offset = 0; public int $offset = 0;
public function set($offset) : self public string $rows = "";
public function set(int $offset) : self
{ {
$this->offset = $offset; $this->offset = $offset;
@ -24,7 +26,7 @@ class Offset extends Fragment {
} }
return $this->renderSegments([ 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 ( ! $this->getFragment(Query\Update::class) ) {
if ( $schema ) { if ( $schema ) {
$table = "\"$schema\".$table"; $table = "$schema.$table";
} }
if ( $database ) { if ( $database ) {
$table = "\"$database\".$table"; $table = "$database.$table";
} }
$update = new Query\Update(); $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 public function from(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
{ {
if ( $schema ) { if ( $schema ) {
$table = "\"$schema\".$table"; $table = "$schema.$table";
} }
if ( $database ) { if ( $database ) {
@ -252,14 +252,18 @@ class QueryBuilder
return $this; 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); $join = new Query\Join($this);
$this->push($join); $this->push($join);
$join->set($type, $table, $field, $value); $join->set($type, $table, $field, $value);
$join->outer = $outer; $join->outer = $outer;
$join->alias = $alias;
return $this; return $this;
} }

View File

@ -181,9 +181,16 @@ class Repository
return $this; 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; return $this;
} }
@ -455,7 +462,6 @@ class Repository
$searchRequest->count = $searchRequest->filter( clone $this ) $searchRequest->count = $searchRequest->filter( clone $this )
->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) ->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND)
->likes($searchRequest->likes(), Query\Where::CONDITION_OR) ->likes($searchRequest->likes(), Query\Where::CONDITION_OR)
->orders($searchRequest->orders())
->groups($searchRequest->groups()) ->groups($searchRequest->groups())
->count(); ->count();