Triggers + EntityLog

This commit is contained in:
2021-04-08 18:29:47 +02:00
parent 140f428491
commit 43d9a65def
20 changed files with 741 additions and 334 deletions

View File

@@ -4,6 +4,8 @@ namespace Driver\SQL\Query;
use Driver\SQL\Column\Column;
use Driver\SQL\Constraint\Constraint;
use Driver\SQL\Constraint\ForeignKey;
use Driver\SQL\Constraint\PrimaryKey;
use Driver\SQL\SQL;
class AlterTable extends Query {
@@ -52,13 +54,48 @@ class AlterTable extends Query {
return $this;
}
public function execute(): bool {
return $this->sql->executeAlter($this);
}
public function getAction(): string { return $this->action; }
public function getColumn(): ?Column { return $this->column; }
public function getConstraint(): ?Constraint { return $this->constraint; }
public function getTable(): string { return $this->table; }
public function build(array &$params, Query $context = NULL): ?string {
$tableName = $this->sql->tableName($this->getTable());
$action = $this->getAction();
$column = $this->getColumn();
$constraint = $this->getConstraint();
$query = "ALTER TABLE $tableName $action ";
if ($column) {
$query .= "COLUMN ";
if ($action === "DROP") {
$query .= $this->sql->columnName($column->getName());
} else {
// ADD or modify
$query .= $this->sql->getColumnDefinition($column);
}
} else if ($constraint) {
if ($action === "DROP") {
if ($constraint instanceof PrimaryKey) {
$query .= "PRIMARY KEY";
} else if ($constraint instanceof ForeignKey) {
// TODO: how can we pass the constraint name here?
$this->sql->setLastError("DROP CONSTRAINT foreign key is not supported yet.");
return null;
}
} else if ($action === "ADD") {
$query .= "CONSTRAINT ";
$query .= $this->sql->getConstraintDefinition($constraint);
} else if ($action === "MODIFY") {
$this->sql->setLastError("MODIFY CONSTRAINT foreign key is not supported.");
return null;
}
} else {
$this->sql->setLastError("ALTER TABLE requires at least a column or a constraint.");
return null;
}
return $query;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Driver\SQL\Query;
use Driver\SQL\Column\Column;
use Driver\SQL\SQL;
class CreateProcedure extends Query {
private string $name;
private array $parameters;
private array $statements;
private $returns;
public function __construct(SQL $sql, string $procName) {
parent::__construct($sql);
$this->name = $procName;
$this->parameters = [];
$this->statements = [];
$this->returns = NULL;
}
public function param(Column $parameter): CreateProcedure {
$this->parameters[] = $parameter;
return $this;
}
public function returns($column): CreateProcedure {
$this->returns = $column;
return $this;
}
public function exec(array $statements): CreateProcedure {
$this->statements = $statements;
return $this;
}
public function build(array &$params, Query $context = NULL): ?string {
$head = $this->sql->getProcedureHead($this);
$body = $this->sql->getProcedureBody($this);
$tail = $this->sql->getProcedureTail();
return "$head BEGIN $body END; $tail";
}
public function getName(): string { return $this->name; }
public function getParameters(): array { return $this->parameters; }
public function getReturns() { return $this->returns; }
public function getStatements(): array { return $this->statements; }
}

View File

@@ -86,12 +86,31 @@ class CreateTable extends Query {
return $this;
}
public function execute(): bool {
return $this->sql->executeCreateTable($this);
}
public function ifNotExists(): bool { return $this->ifNotExists; }
public function getTableName(): string { return $this->tableName; }
public function getColumns(): array { return $this->columns; }
public function getConstraints(): array { return $this->constraints; }
public function build(array &$params): ?string {
$tableName = $this->sql->tableName($this->getTableName());
$ifNotExists = $this->ifNotExists() ? " IF NOT EXISTS" : "";
$entries = array();
foreach ($this->getColumns() as $column) {
$entries[] = ($tmp = $this->sql->getColumnDefinition($column));
if (is_null($tmp)) {
return false;
}
}
foreach ($this->getConstraints() as $constraint) {
$entries[] = ($tmp = $this->sql->getConstraintDefinition($constraint));
if (is_null($tmp)) {
return false;
}
}
$entries = implode(",", $entries);
return "CREATE TABLE$ifNotExists $tableName ($entries)";
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Driver\SQL\Query;
use Api\User\Create;
use Driver\SQL\SQL;
class CreateTrigger extends Query {
private string $name;
private string $time;
private string $event;
private string $tableName;
private ?CreateProcedure $procedure;
public function __construct(SQL $sql, string $triggerName) {
parent::__construct($sql);
$this->name = $triggerName;
$this->time = "AFTER";
$this->tableName = "";
$this->event = "";
$this->procedure = null;
}
public function before(): CreateTrigger {
$this->time = "BEFORE";
return $this;
}
public function after(): CreateTrigger {
$this->time = "AFTER";
return $this;
}
public function update(string $table): CreateTrigger {
$this->tableName = $table;
$this->event = "UPDATE";
return $this;
}
public function insert(string $table): CreateTrigger {
$this->tableName = $table;
$this->event = "INSERT";
return $this;
}
public function delete(string $table): CreateTrigger {
$this->tableName = $table;
$this->event = "DELETE";
return $this;
}
public function exec(CreateProcedure $procedure): CreateTrigger {
$this->procedure = $procedure;
return $this;
}
public function getName(): string { return $this->name; }
public function getTime(): string { return $this->time; }
public function getEvent(): string { return $this->event; }
public function getTable(): string { return $this->tableName; }
public function getProcedure(): CreateProcedure { return $this->procedure; }
public function build(array &$params, Query $context = NULL): ?string {
$name = $this->sql->tableName($this->getName());
$time = $this->getTime();
$event = $this->getEvent();
$tableName = $this->sql->tableName($this->getTable());
$params = array();
$query = "CREATE TRIGGER $name $time $event ON $tableName FOR EACH ROW ";
$triggerBody = $this->sql->createTriggerBody($this);
if ($triggerBody === null) {
return null;
}
$query .= $triggerBody;
return $query;
}
}

View File

@@ -21,10 +21,12 @@ class Delete extends Query {
return $this;
}
public function execute(): bool {
return $this->sql->executeDelete($this);
}
public function getTable(): string { return $this->table; }
public function getConditions(): array { return $this->conditions; }
public function build(array &$params, Query $context = NULL): ?string {
$table = $this->sql->tableName($this->getTable());
$where = $this->sql->getWhereClause($this->getConditions(), $params);
return "DELETE FROM $table$where";
}
}

View File

@@ -19,11 +19,11 @@ class Drop extends Query {
$this->table = $table;
}
public function execute(): bool {
return $this->sql->executeDrop($this);
}
public function getTable(): string {
return $this->table;
}
public function build(array &$params, Query $context = NULL): ?string {
return "DROP TABLE " . $this->sql->tableName($this->getTable());
}
}

View File

@@ -37,8 +37,9 @@ class Insert extends Query {
return $this;
}
public function execute(): bool {
return $this->sql->executeInsert($this);
public function execute() {
$fetchResult = !empty($this->sql->getReturning($this->returning));
return $this->sql->executeQuery($this, $fetchResult);
}
public function getTableName(): string { return $this->tableName; }
@@ -46,4 +47,42 @@ class Insert extends Query {
public function getRows(): array { return $this->rows; }
public function onDuplicateKey(): ?Strategy { return $this->onDuplicateKey; }
public function getReturning(): ?string { return $this->returning; }
public function build(array &$params, Query $context = NULL): ?string {
$tableName = $this->sql->tableName($this->getTableName());
$columns = $this->getColumns();
$rows = $this->getRows();
if (empty($rows)) {
$this->sql->setLastError("No rows to insert given.");
return null;
}
if (is_null($columns) || empty($columns)) {
$columnStr = "";
} else {
$columnStr = " (" . $this->sql->columnName($columns) . ")";
}
$values = array();
foreach ($rows as $row) {
$rowPlaceHolder = array();
foreach ($row as $val) {
$rowPlaceHolder[] = $this->sql->addValue($val, $params);
}
$values[] = "(" . implode(",", $rowPlaceHolder) . ")";
}
$values = implode(",", $values);
$onDuplicateKey = $this->sql->getOnDuplicateStrategy($this->onDuplicateKey(), $params);
if ($onDuplicateKey === FALSE) {
return null;
}
$returningCol = $this->getReturning();
$returning = $this->sql->getReturning($returningCol);
return "INSERT INTO $tableName$columnStr VALUES $values$onDuplicateKey$returning";
}
}

View File

@@ -20,6 +20,9 @@ abstract class Query {
}
// can actually return bool|array (depending on success and query type)
public abstract function execute();
public function execute() {
return $this->sql->executeQuery($this);
}
public abstract function build(array &$params): ?string;
}

View File

@@ -4,6 +4,7 @@ namespace Driver\SQL\Query;
use Driver\SQL\Condition\CondOr;
use Driver\SQL\Join;
use Driver\SQL\SQL;
class Select extends Query {
@@ -81,7 +82,7 @@ class Select extends Query {
}
public function execute() {
return $this->sql->executeSelect($this);
return $this->sql->executeQuery($this, true);
}
public function getColumns(): array { return $this->columns; }
@@ -94,4 +95,46 @@ class Select extends Query {
public function getOffset(): int { return $this->offset; }
public function getGroupBy(): array { return $this->groupColumns; }
public function build(array &$params, Query $context = NULL): ?string {
$columns = $this->sql->columnName($this->getColumns());
$tables = $this->getTables();
if (!$tables) {
return "SELECT $columns";
}
$tables = $this->sql->tableName($tables);
$where = $this->sql->getWhereClause($this->getConditions(), $params);
$joinStr = "";
$joins = $this->getJoins();
if (!empty($joins)) {
foreach ($joins as $join) {
$type = $join->getType();
$joinTable = $this->sql->tableName($join->getTable());
$columnA = $this->sql->columnName($join->getColumnA());
$columnB = $this->sql->columnName($join->getColumnB());
$tableAlias = ($join->getTableAlias() ? " " . $join->getTableAlias() : "");
$joinStr .= " $type JOIN $joinTable$tableAlias ON $columnA=$columnB";
}
}
$groupBy = "";
$groupColumns = $this->getGroupBy();
if (!empty($groupColumns)) {
$groupBy = " GROUP BY " . $this->sql->columnName($groupColumns);
}
$orderBy = "";
$orderColumns = $this->getOrderBy();
if (!empty($orderColumns)) {
$orderBy = " ORDER BY " . $this->sql->columnName($orderColumns);
$orderBy .= ($this->isOrderedAscending() ? " ASC" : " DESC");
}
$limit = ($this->getLimit() > 0 ? (" LIMIT " . $this->getLimit()) : "");
$offset = ($this->getOffset() > 0 ? (" OFFSET " . $this->getOffset()) : "");
return "SELECT $columns FROM $tables$joinStr$where$groupBy$orderBy$limit$offset";
}
}

View File

@@ -13,9 +13,9 @@ class Truncate extends Query {
$this->tableName = $name;
}
public function execute(): bool {
return $this->sql->executeTruncate($this);
}
public function getTable(): string { return $this->tableName; }
public function build(array &$params, Query $context = NULL): ?string {
return "TRUNCATE " . $this->sql->tableName($this->getTable());
}
}

View File

@@ -28,11 +28,20 @@ class Update extends Query {
return $this;
}
public function execute() {
return $this->sql->executeUpdate($this);
}
public function getTable(): string { return $this->table; }
public function getConditions(): array { return $this->conditions; }
public function getValues(): array { return $this->values; }
public function build(array &$params, Query $context = NULL): ?string {
$table = $this->sql->tableName($this->getTable());
$valueStr = array();
foreach($this->getValues() as $key => $val) {
$valueStr[] = $this->sql->columnName($key) . "=" . $this->sql->addValue($val, $params);
}
$valueStr = implode(",", $valueStr);
$where = $this->sql->getWhereClause($this->getConditions(), $params);
return "UPDATE $table SET $valueStr$where";
}
}