Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
Split from components
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfy-j committed Feb 3, 2017
1 parent 8ca3d89 commit 9e33807
Show file tree
Hide file tree
Showing 136 changed files with 341 additions and 2 deletions.
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
},
"require-dev": {
"phpunit/phpunit": "~5.0",
"mockery/mockery": "^0.9.4",
"vlucas/phpdotenv": "^2.1"
"mockery/mockery": "^0.9.4"
},
"autoload": {
"psr-4": {
Expand Down
36 changes: 36 additions & 0 deletions source/Spiral/Database/Drivers/Postgres/Schemas/PostgresIndex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* Spiral, Core Components
*
* @author Wolfy-J
*/

namespace Spiral\Database\Drivers\Postgres\Schemas;

use Spiral\Database\Schemas\Prototypes\AbstractIndex;

class PostgresIndex extends AbstractIndex
{
/**
* @param string $table Table name.
* @param array $schema
*
* @return PostgresIndex
*/
public static function createInstance(string $table, array $schema): self
{
$index = new self($table, $schema['indexname']);
$index->type = strpos($schema['indexdef'], ' UNIQUE ') ? self::UNIQUE : self::NORMAL;

if (preg_match('/\(([^)]+)\)/', $schema['indexdef'], $matches)) {
$columns = explode(',', $matches[1]);

foreach ($columns as $column) {
//Postgres adds quotes to all columns with uppercase letters
$index->columns[] = trim($column, ' "\'');
}
}

return $index;
}
}
221 changes: 221 additions & 0 deletions source/Spiral/Database/Drivers/Postgres/Schemas/PostgresTable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
<?php
/**
* Spiral, Core Components
*
* @author Wolfy-J
*/

namespace Spiral\Database\Drivers\Postgres\Schemas;

use Psr\Log\LoggerInterface;
use Spiral\Database\Entities\AbstractHandler as Behaviour;
use Spiral\Database\Schemas\Prototypes\AbstractColumn;
use Spiral\Database\Schemas\Prototypes\AbstractIndex;
use Spiral\Database\Schemas\Prototypes\AbstractReference;
use Spiral\Database\Schemas\Prototypes\AbstractTable;


class PostgresTable extends AbstractTable
{
/**
* Found table sequences.
*
* @var array
*/
private $sequences = [];

/**
* Sequence object name usually defined only for primary keys and required by ORM to correctly
* resolve inserted row id.
*
* @var string|null
*/
private $primarySequence = null;

/**
* Sequence object name usually defined only for primary keys and required by ORM to correctly
* resolve inserted row id.
*
* @return string|null
*/
public function getSequence()
{
return $this->primarySequence;
}

/**
* {@inheritdoc}
*
* SQLServer will reload schemas after successful savw.
*/
public function save(
int $behaviour = Behaviour::DO_ALL,
LoggerInterface $logger = null,
bool $reset = true
) {
parent::save($behaviour, $logger, $reset);

if ($reset) {
foreach ($this->fetchColumns() as $column) {
$currentColumn = $this->current->findColumn($column->getName());
if (!empty($currentColumn) && $column->compare($currentColumn)) {
//Ensure constrained columns
$this->current->registerColumn($column);
}
}
}
}


/**
* {@inheritdoc}
*/
protected function fetchColumns(): array
{
//Required for constraints fetch
$tableOID = $this->driver->query('SELECT oid FROM pg_class WHERE relname = ?', [
$this->getName(),
])->fetchColumn();

$query = $this->driver->query(
'SELECT * FROM information_schema.columns JOIN pg_type ON (pg_type.typname = columns.udt_name) WHERE table_name = ?',
[$this->getName()]
);

$result = [];
foreach ($query->bind('column_name', $name) as $schema) {
if (preg_match(
'/^nextval\([\'"]([a-z0-9_"]+)[\'"](?:::regclass)?\)$/i',
$schema['column_default'],
$matches
)) {
//Column is sequential
$this->sequences[$name] = $matches[1];
}

$result[] = PostgresColumn::createInstance(
$this->getName(),
$schema + ['tableOID' => $tableOID],
$this->driver
);
}

return $result;
}

/**
* {@inheritdoc}
*/
protected function fetchIndexes(bool $all = false): array
{
$query = "SELECT * FROM pg_indexes WHERE schemaname = 'public' AND tablename = ?";

$result = [];
foreach ($this->driver->query($query, [$this->getName()]) as $schema) {
$conType = $this->driver->query(
'SELECT contype FROM pg_constraint WHERE conname = ?',
[$schema['indexname']]
)->fetchColumn();

if ($conType == 'p') {
//Skipping primary keys
continue;
}

$result[] = PostgresIndex::createInstance($this->getName(), $schema);
}

return $result;
}

/**
* {@inheritdoc}
*/
protected function fetchReferences(): array
{
//Mindblowing
$query = 'SELECT tc.constraint_name, tc.table_name, kcu.column_name, rc.update_rule, '
. 'rc.delete_rule, ccu.table_name AS foreign_table_name, '
. "ccu.column_name AS foreign_column_name\n"
. "FROM information_schema.table_constraints AS tc\n"
. "JOIN information_schema.key_column_usage AS kcu\n"
. " ON tc.constraint_name = kcu.constraint_name\n"
. "JOIN information_schema.constraint_column_usage AS ccu\n"
. " ON ccu.constraint_name = tc.constraint_name\n"
. "JOIN information_schema.referential_constraints AS rc\n"
. " ON rc.constraint_name = tc.constraint_name\n"
. "WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name = ?";

$result = [];

foreach ($this->driver->query($query, [$this->getName()]) as $schema) {
$result[] = PostgresReference::createInstance(
$this->getName(),
$this->getPrefix(),
$schema
);
}

return $result;
}

/**
* {@inheritdoc}
*/
protected function fetchPrimaryKeys(): array
{
$query = "SELECT * FROM pg_indexes WHERE schemaname = 'public' AND tablename = ?";

foreach ($this->driver->query($query, [$this->getName()]) as $schema) {
$conType = $this->driver->query(
'SELECT contype FROM pg_constraint WHERE conname = ?',
[$schema['indexname']]
)->fetchColumn();

if ($conType != 'p') {
//Skipping primary keys
continue;
}

//To simplify definitions
$index = PostgresIndex::createInstance($this->getName(), $schema);

if (is_array($this->primarySequence) && count($index->getColumns()) === 1) {
$column = $index->getColumns()[0];

if (isset($this->sequences[$column])) {
//We found our primary sequence
$this->primarySequence = $this->sequences[$column];
}
}

return $index->getColumns();
}

return [];
}

/**
* {@inheritdoc}
*/
protected function createColumn(string $name): AbstractColumn
{
return new PostgresColumn($this->getName(), $name, $this->driver->getTimezone());
}

/**
* {@inheritdoc}
*/
protected function createIndex(string $name): AbstractIndex
{
return new PostgresIndex($this->getName(), $name);
}

/**
* {@inheritdoc}
*/
protected function createForeign(string $name): AbstractReference
{
return new PostgresReference($this->getName(), $this->getPrefix(), $name);
}
}
65 changes: 65 additions & 0 deletions source/Spiral/Database/Injections/Fragment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* Spiral Framework.
*
* @license MIT
* @author Anton Titov (Wolfy-J)
*/

namespace Spiral\Database\Injections;

/**
* Default implementation of SQLFragmentInterface, provides ability to inject custom SQL code into
* query builders. Usually used to mock database specific functions.
*
* Example: ...->where('time_created', '>', new SQLFragment("NOW()"));
*/
class Fragment implements FragmentInterface
{
/**
* @var string
*/
protected $statement = null;

/**
* @param string $statement
*/
public function __construct(string $statement)
{
$this->statement = $statement;
}

/**
* {@inheritdoc}
*/
public function sqlStatement(): string
{
return $this->statement;
}

/**
* {@inheritdoc}
*/
public function __toString(): string
{
return $this->sqlStatement();
}

/**
* @return array
*/
public function __debugInfo()
{
return ['statement' => $this->sqlStatement()];
}

/**
* @param array $an_array
*
* @return Fragment
*/
public static function __set_state(array $an_array): Fragment
{
return new static($an_array['statement']);
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 18 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/**
* Spiral Framework, SpiralScout LLC.
*
* @author Anton Titov (Wolfy-J)
*/
define('SPIRAL_INITIAL_TIME', microtime(true));

error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', true);
mb_internal_encoding('UTF-8');

//Composer
require dirname(__DIR__) . '/vendor/autoload.php';

//File component fixtures
define('FIXTURE_DIRECTORY', __DIR__ . '/Files/fixtures/');
define('ENABLE_PROFILING', getenv('PROFILING') ?? false);

0 comments on commit 9e33807

Please sign in to comment.