mirror of
https://github.com/silverstripe/silverstripe-postgresql
synced 2024-10-22 17:05:45 +02:00
Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
091a4c2416 | ||
|
b37c19d6d5 | ||
|
24dbdeb564 | ||
|
a60fc4cf24 | ||
|
d2fbce5319 | ||
|
beb0f84f2d | ||
|
6d5c35116a | ||
|
41fd4718a2 | ||
|
448828c20a | ||
|
faf9d033ff | ||
|
d7b4ccb202 | ||
|
c9bce8fe57 | ||
|
4bbabf2421 | ||
|
22e3951244 | ||
|
321d0d853b | ||
|
84e13ffde3 | ||
|
17e9f5388c | ||
|
222f20529c | ||
|
c46272e751 | ||
|
afec73997a | ||
|
d3c8e2915e | ||
|
a709a741b0 | ||
|
dd4df9800b | ||
|
082742ad23 | ||
|
a7c3450d43 | ||
|
0be39423a3 | ||
|
3d50b3f9ec | ||
|
3e38f845e3 | ||
|
4e3d3df565 | ||
|
753d73e1fe | ||
|
beed6c7fb7 | ||
|
bf4fb87a01 | ||
|
66376db094 | ||
|
d607a2bfa9 | ||
|
f2ec228c72 | ||
|
82f8a06afa | ||
|
75f4a35f71 | ||
|
08c8293328 | ||
|
0ffaf90512 | ||
|
04000ad878 | ||
|
3d6920c121 | ||
|
b6bab3561f |
25
.github/workflows/ci.yml
vendored
Normal file
25
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI
|
||||
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
|
||||
with:
|
||||
# set phpunit to false to prevent automatic generation of mysql phpunit jobs
|
||||
phpunit: false
|
||||
extra_jobs: |
|
||||
- php: 7.4
|
||||
db: pgsql
|
||||
phpunit: true
|
||||
composer_args: --prefer-lowest
|
||||
- php: 8.0
|
||||
db: pgsql
|
||||
phpunit: true
|
||||
- php: 8.1
|
||||
db: pgsql
|
||||
phpunit: true
|
16
.github/workflows/dispatch-ci.yml
vendored
Normal file
16
.github/workflows/dispatch-ci.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
name: Dispatch CI
|
||||
|
||||
on:
|
||||
# At 12:20 PM UTC, only on Thursday and Friday
|
||||
schedule:
|
||||
- cron: '20 12 * * 4,5'
|
||||
|
||||
jobs:
|
||||
dispatch-ci:
|
||||
name: Dispatch CI
|
||||
# Only run cron on the silverstripe account
|
||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dispatch CI
|
||||
uses: silverstripe/gha-dispatch-ci@v1
|
17
.github/workflows/keepalive.yml
vendored
Normal file
17
.github/workflows/keepalive.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: Keepalive
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# The 4th of every month at 10:50am UTC
|
||||
schedule:
|
||||
- cron: '50 10 4 * *'
|
||||
|
||||
jobs:
|
||||
keepalive:
|
||||
name: Keepalive
|
||||
# Only run cron on the silverstripe account
|
||||
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Keepalive
|
||||
uses: silverstripe/gha-keepalive@v1
|
@ -1,15 +0,0 @@
|
||||
inherit: true
|
||||
|
||||
build:
|
||||
nodes:
|
||||
analysis:
|
||||
tests:
|
||||
override: [php-scrutinizer-run]
|
||||
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
duplication: true
|
||||
|
||||
filter:
|
||||
paths: [code/*, tests/*]
|
43
.travis.yml
43
.travis.yml
@ -1,43 +0,0 @@
|
||||
language: php
|
||||
|
||||
dist: trusty
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
php:
|
||||
- 5.6
|
||||
|
||||
env:
|
||||
global:
|
||||
- DB="PGSQL"
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: 5.6
|
||||
env:
|
||||
- PHPUNIT_TEST=framework
|
||||
- php: 5.6
|
||||
env:
|
||||
- PHPUNIT_TEST=postgresql
|
||||
- PHPCS_TEST=1
|
||||
|
||||
before_script:
|
||||
# Init PHP
|
||||
- phpenv rehash
|
||||
- phpenv config-rm xdebug.ini
|
||||
- export PATH=~/.composer/vendor/bin:$PATH
|
||||
- echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
|
||||
# Install composer dependencies
|
||||
- composer validate
|
||||
- composer require --no-update silverstripe/recipe-cms:4.3.x-dev
|
||||
- composer install --prefer-source --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
|
||||
- if [[ $PHPCS_TEST ]]; then composer global require squizlabs/php_codesniffer:^3 --prefer-dist --no-interaction --no-progress --no-suggest -o; fi
|
||||
|
||||
script:
|
||||
- if [[ $PHPUNIT_TEST == postgresql ]]; then vendor/bin/phpunit ./tests; fi
|
||||
- if [[ $PHPUNIT_TEST == framework ]]; then vendor/bin/phpunit ./vendor/silverstripe/framework/tests/php; fi
|
||||
- if [[ $PHPCS_TEST ]]; then composer run-script lint; fi
|
49
README.md
49
README.md
@ -1,35 +1,54 @@
|
||||
# PostgreSQL Module Module
|
||||
|
||||
[![Build Status](https://travis-ci.org/silverstripe/silverstripe-postgresql.png?branch=master)](https://travis-ci.org/silverstripe/silverstripe-postgresql)
|
||||
[![SilverStripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||
|
||||
## Maintainer Contact
|
||||
|
||||
* Sam Minnee (Nickname: sminnee) <sam@silverstripe.com>
|
||||
[![CI](https://github.com/silverstripe/silverstripe-postgresql/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-postgresql/actions/workflows/ci.yml)
|
||||
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||
|
||||
## Requirements
|
||||
|
||||
* SilverStripe 4.0
|
||||
* PostgreSQL 8.3.x or greater must be installed
|
||||
* PostgreSQL <8.3.0 may work if T-Search is manually installed
|
||||
* Known to work on OS X Leopard, Windows Server 2008 R2 and Linux
|
||||
* Silverstripe 4.0
|
||||
* PostgreSQL >=9.2
|
||||
* Note: PostgreSQL 10 has not been tested
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install via composer `composer require silverstripe/postgresql` or extract the contents
|
||||
so they reside as a `postgresql` directory inside your SilverStripe project code
|
||||
2. Open the installer by browsing to install.php, e.g. http://localhost/silverstripe/install.php
|
||||
3. Select PostgreSQL in the database list and enter your database details
|
||||
```
|
||||
composer require silverstripe/postgresql
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment file
|
||||
|
||||
Add the following settings to your `.env` file:
|
||||
|
||||
```
|
||||
SS_DATABASE_CLASS=PostgreSQLDatabase
|
||||
SS_DATABASE_USERNAME=
|
||||
SS_DATABASE_PASSWORD=
|
||||
```
|
||||
|
||||
See [environment variables](https://docs.silverstripe.org/en/4/getting_started/environment_management) for more details. Note that a database will automatically be created via `dev/build`.
|
||||
|
||||
### Through the installer
|
||||
|
||||
Open the installer by browsing to install.php, e.g. http://localhost/install.php
|
||||
Select PostgreSQL in the database list and enter your database details
|
||||
|
||||
## Usage Overview
|
||||
|
||||
See docs/en for more information about configuring the module.
|
||||
See [docs/en](docs/en/README.md) for more information about configuring the module.
|
||||
|
||||
## Known issues
|
||||
|
||||
All column and table names must be double-quoted. PostgreSQL automatically
|
||||
lower-cases columns, and your queries will fail if you don't.
|
||||
|
||||
Collations have known issues when installed on Alpine, MacOS X and BSD derivatives
|
||||
(see [PostgreSQL FAQ](https://wiki.postgresql.org/wiki/FAQ#Why_do_my_strings_sort_incorrectly.3F)).
|
||||
We do not support such installations, although they still may work correctly for you.
|
||||
As a workaround for PostgreSQL 10+ you could manually switch to ICU collations (e.g. und-x-icu).
|
||||
There are no known workarounds for PostgreSQL <10.
|
||||
|
||||
Ts_vector columns are not automatically detected by the built-in search
|
||||
filters. That means if you're doing a search through the CMS on a ModelAdmin
|
||||
object, it will use LIKE queries which are very slow. If you're writing your
|
||||
|
@ -448,7 +448,7 @@ class PostgreSQLDatabase extends Database
|
||||
|
||||
// Could parameterise this, but convention is only to to so for where conditions
|
||||
$query->addFrom(array(
|
||||
'tsearch' => ", to_tsquery('" . self::search_language() . "', $keywords) AS q"
|
||||
'q' => ", to_tsquery('" . self::search_language() . "', $keywords)"
|
||||
));
|
||||
$query->setSelect(array());
|
||||
|
||||
|
@ -58,8 +58,10 @@ class PostgreSQLQuery extends Query
|
||||
|
||||
public function seek($row)
|
||||
{
|
||||
pg_result_seek($this->handle, $row);
|
||||
return $this->nextRecord();
|
||||
// Specifying the zero-th record here will reset the pointer
|
||||
$result = pg_fetch_array($this->handle, $row, PGSQL_NUM);
|
||||
|
||||
return $this->parseResult($result);
|
||||
}
|
||||
|
||||
public function numRecords()
|
||||
@ -73,26 +75,35 @@ class PostgreSQLQuery extends Query
|
||||
|
||||
// Correct non-string types
|
||||
if ($row) {
|
||||
$record = [];
|
||||
|
||||
foreach ($row as $i => $v) {
|
||||
$k = $this->columnNames[$i];
|
||||
$record[$k] = $v;
|
||||
$type = pg_field_type($this->handle, $i);
|
||||
if (isset(self::$typeMapping[$type])) {
|
||||
if ($type === 'bool' && $record[$k] === 't') {
|
||||
$record[$k] = 1;
|
||||
|
||||
// Note that boolean 'f' will be converted to 0 by this
|
||||
} else {
|
||||
settype($record[$k], self::$typeMapping[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $record;
|
||||
return $this->parseResult($row);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @return array
|
||||
*/
|
||||
protected function parseResult(array $row)
|
||||
{
|
||||
$record = [];
|
||||
|
||||
foreach ($row as $i => $v) {
|
||||
$k = $this->columnNames[$i];
|
||||
$record[$k] = $v;
|
||||
$type = pg_field_type($this->handle, $i);
|
||||
if (isset(self::$typeMapping[$type])) {
|
||||
if ($type === 'bool' && $record[$k] === 't') {
|
||||
$record[$k] = 1;
|
||||
|
||||
// Note that boolean 'f' will be converted to 0 by this
|
||||
} else {
|
||||
settype($record[$k], self::$typeMapping[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
|
@ -494,9 +494,15 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
// First, we split the column specifications into parts
|
||||
// TODO: this returns an empty array for the following string: int(11) not null auto_increment
|
||||
// on second thoughts, why is an auto_increment field being passed through?
|
||||
|
||||
$pattern = '/^([\w(\,)]+)\s?((?:not\s)?null)?\s?(default\s[\w\.\']+)?\s?(check\s[\w()\'",\s]+)?$/i';
|
||||
$pattern = '/^([\w(\,)]+)\s?((?:not\s)?null)?\s?(default\s[\w\.\'\\\\]+)?\s?(check\s[\w()\'",\s\\\\]+)?$/i';
|
||||
preg_match($pattern, $colSpec, $matches);
|
||||
// example value this regex is expected to parse:
|
||||
// varchar(255) not null default 'SS\Test\Player' check ("ClassName" in ('SS\Test\Player', 'Player', null))
|
||||
// split into:
|
||||
// * varchar(255)
|
||||
// * not null
|
||||
// * default 'SS\Test\Player'
|
||||
// * check ("ClassName" in ('SS\Test\Player', 'Player', null))
|
||||
|
||||
if (sizeof($matches) == 0) {
|
||||
return '';
|
||||
@ -537,8 +543,8 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
if ($this->hasTable("{$tableName}_Live")) {
|
||||
$updateConstraint .= "UPDATE \"{$tableName}_Live\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
}
|
||||
if ($this->hasTable("{$tableName}_versions")) {
|
||||
$updateConstraint .= "UPDATE \"{$tableName}_versions\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
if ($this->hasTable("{$tableName}_Versions")) {
|
||||
$updateConstraint .= "UPDATE \"{$tableName}_Versions\" SET \"$colName\"='$default' WHERE \"$colName\" NOT IN ($constraint_values);";
|
||||
}
|
||||
|
||||
$this->query($updateConstraint);
|
||||
@ -560,8 +566,17 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
|
||||
public function renameTable($oldTableName, $newTableName)
|
||||
{
|
||||
$constraints = $this->getConstraintForTable($oldTableName);
|
||||
$this->query("ALTER TABLE \"$oldTableName\" RENAME TO \"$newTableName\"");
|
||||
|
||||
if ($constraints) {
|
||||
foreach ($constraints as $old) {
|
||||
$new = preg_replace('/^' . $oldTableName . '/', $newTableName, $old);
|
||||
$this->query("ALTER TABLE \"$newTableName\" RENAME CONSTRAINT \"$old\" TO \"$new\";");
|
||||
}
|
||||
}
|
||||
unset(self::$cached_fieldlists[$oldTableName]);
|
||||
unset(self::$cached_constraints[$oldTableName]);
|
||||
}
|
||||
|
||||
public function checkAndRepairTable($tableName)
|
||||
@ -843,7 +858,9 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
$argList = array();
|
||||
$nextArg = "";
|
||||
foreach ($bytes as $byte) {
|
||||
if ($byte == "00") {
|
||||
if ($byte == '\x') {
|
||||
continue;
|
||||
} elseif ($byte == "00") {
|
||||
$argList[] = $nextArg;
|
||||
$nextArg = "";
|
||||
} else {
|
||||
@ -961,6 +978,28 @@ class PostgreSQLSchemaManager extends DBSchemaManager
|
||||
return self::$cached_constraints[$constraint];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of constraints for the provided table name.
|
||||
* @param string $tableName
|
||||
* @return array
|
||||
*/
|
||||
private function getConstraintForTable($tableName)
|
||||
{
|
||||
// Note the PostgreSQL `like` operator is case sensitive
|
||||
$constraints = $this->preparedQuery(
|
||||
"
|
||||
SELECT conname
|
||||
FROM pg_catalog.pg_constraint r
|
||||
INNER JOIN pg_catalog.pg_namespace n
|
||||
ON r.connamespace = n.oid
|
||||
WHERE r.contype = 'c' AND conname like ? AND n.nspname = ?
|
||||
ORDER BY 1;",
|
||||
array($tableName . '_%', $this->database->currentSchema())
|
||||
)->column('conname');
|
||||
|
||||
return $constraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to return the field names and datatypes for the particular table
|
||||
*
|
||||
|
@ -15,16 +15,12 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"silverstripe/framework": "^4",
|
||||
"silverstripe/framework": "^4.10",
|
||||
"silverstripe/vendor-plugin": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"2.x-dev": "2.2.x-dev"
|
||||
}
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"squizlabs/php_codesniffer": "^3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@ -1,86 +1,5 @@
|
||||
# PostgreSQL Database Module
|
||||
|
||||
SilverStripe now has tentative support for PostgreSQL ('Postgres').
|
||||
|
||||
## Requirements
|
||||
|
||||
SilverStripe 2.4.0 or greater. (PostgreSQL support is NOT available
|
||||
in 2.3.).
|
||||
|
||||
SilverStripe supports Postgres versions 8.3.x, 8.4.x and onwards.
|
||||
Postgres 8.3.0 launched in February 2008, so SilverStripe has a fairly
|
||||
modern but not bleeding edge Postgres version requirement.
|
||||
|
||||
Support for 8.2.x is theoretically possible if you're willing to manually
|
||||
install T-search. 8.2.x has not been tested either, so there may be other
|
||||
compatibility issues. The EnterpriseDB versions of Postgres also work, if
|
||||
you'd prefer a tuned version.
|
||||
|
||||
## Installation
|
||||
|
||||
You have three options to install PostgreSQL support with SilverStripe.
|
||||
|
||||
### Option 1 - Installer
|
||||
|
||||
The first option is to use the installer. However, this is currently only
|
||||
supported since SilverStripe 2.4.0 beta2 (or using the daily builds).
|
||||
|
||||
1. Set up SilverStripe somewhere where you can start the installer - you
|
||||
should only see one database “MySQL” to install with.
|
||||
2. Download a copy of the “postgresql” module from here:
|
||||
http://silverstripe.org/postgresql-module
|
||||
3. Extract the archive you downloaded. Rename the directory from
|
||||
“postgresql-trunk-rxxxx” to “postgresql” and copy it into the SilverStripe
|
||||
directory you just set up
|
||||
4. Open the installer once again, and a new option “PostgreSQL” should appear.
|
||||
You can now proceed through the installation without having to change any code.
|
||||
|
||||
### Option 2 - Manual
|
||||
|
||||
The second option is to setup PostgreSQL support manually. This can be achieved
|
||||
by following these instructions:
|
||||
|
||||
1. Set up a fresh working copy of SilverStripe
|
||||
2. Download a copy of the “postgresql” module from here: http://silverstripe.org/postgresql-module
|
||||
3. Extract the archive you downloaded. Rename the directory from
|
||||
“postgresql-trunk-rxxxx” to “postgresql” and copy it into the SilverStripe
|
||||
directory you just set up.
|
||||
4. Open up your mysite/_config.php file and add (or update) the $databaseConfig
|
||||
array like so:
|
||||
|
||||
> $databaseConfig = array(
|
||||
> 'type' => 'PostgreSQLDatabase',
|
||||
> 'server' => '[server address e.g. localhost]',
|
||||
> 'username' => 'postgres',
|
||||
> 'password' => 'mypassword',
|
||||
> 'database' => 'SS_mysite'
|
||||
> );
|
||||
|
||||
Finally, visit dev/build so that SilverStripe can build the database schema and
|
||||
default records.
|
||||
|
||||
### Option 3 - Environment file
|
||||
|
||||
Finally, the third option is to change your environment to point to
|
||||
PostgreSQLDatabase as a database class. Do this if you're currently using an
|
||||
_ss_environment.php file.
|
||||
|
||||
1. Download a copy of the “postgresql” module from here: http://silverstripe.org/postgresql-module
|
||||
2. Extract the archive you downloaded. Rename the directory from
|
||||
postgresql-trunk-rxxxx” to “postgresql” and copy it into your SS directory
|
||||
3. Add the following to your existing _ss_environment.php file:
|
||||
|
||||
> define('SS_DATABASE_CLASS', 'PostgreSQLDatabase');
|
||||
|
||||
Last steps:
|
||||
|
||||
1. Ensure your SS_DATABASE_USERNAME and SS_DATABASE_PASSWORD defines in
|
||||
_ss_environment.php are correct to the PostgreSQL server.
|
||||
2. Ensure that your mysite/_config.php file has a database name defined, such
|
||||
as “SS_mysite”.
|
||||
3. Visit dev/build so that SilverStripe can build the database schema and
|
||||
default records
|
||||
|
||||
## Features
|
||||
|
||||
Here is a quick list of what's different in the Postgres module (a full
|
||||
@ -300,22 +219,4 @@ Otherwise this extension will try to connect to "postgres" Database to check DB
|
||||
connection, no matter what you entered in the "Database Name" field during
|
||||
installation.
|
||||
|
||||
Make sure you have set the "search_path" correct for your database user.
|
||||
|
||||
## Known Issues
|
||||
|
||||
All column and table names must be double-quoted. PostgreSQL automatically
|
||||
lower-cases columns, and your queries will fail if you don't.
|
||||
|
||||
Ts_vector columns are not automatically detected by the built-in search filters.
|
||||
That means if you're doing a search through the CMS on a ModelAdmin object, it
|
||||
will use LIKE queries which are very slow.
|
||||
|
||||
If you're writing your own front-end search system, you can specify the columns
|
||||
to use for search purposes, and you get the full benefits of T-Search.
|
||||
|
||||
If you are using unsupported modules, there may be instances of MySQL-specific
|
||||
SQL queries which will need to be made database-agnostic where possible.
|
||||
|
||||
|
||||
|
||||
Make sure you have set the "search_path" correct for your database user.
|
@ -2,6 +2,9 @@
|
||||
<ruleset name="SilverStripe">
|
||||
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||
|
||||
<file>code</file>
|
||||
<file>tests</file>
|
||||
|
||||
<!-- base rules are PSR-2 -->
|
||||
<rule ref="PSR2" >
|
||||
<!-- Current exclusions -->
|
||||
|
@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
|
||||
|
||||
<testsuite name="Default">
|
||||
|
138
tests/PostgreSQLSchemaManagerTest.php
Normal file
138
tests/PostgreSQLSchemaManagerTest.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\PostgreSQL\Tests;
|
||||
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\ORM\Connect\Database;
|
||||
use SilverStripe\ORM\Connect\DatabaseException;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\PostgreSQL\PostgreSQLConnector;
|
||||
use SilverStripe\PostgreSQL\PostgreSQLSchemaManager;
|
||||
|
||||
class PostgreSQLSchemaManagerTest extends SapphireTest
|
||||
{
|
||||
|
||||
protected $usesTransactions = false;
|
||||
|
||||
public function testAlterTable()
|
||||
{
|
||||
try {
|
||||
/** @var PostgreSQLSchemaManager $dbSchema */
|
||||
$dbSchema = DB::get_schema();
|
||||
$dbSchema->quiet();
|
||||
|
||||
$this->createSS3Table();
|
||||
|
||||
try {
|
||||
DB::query('INSERT INTO "ClassNamesUpgrade" ("ClassName") VALUES (\'App\MySite\FooBar\')');
|
||||
$this->assertFalse(true, 'SS3 Constaint should have blocked the previous insert.');
|
||||
} catch (DatabaseException $ex) {
|
||||
}
|
||||
|
||||
$dbSchema->schemaUpdate(function () use ($dbSchema) {
|
||||
$dbSchema->requireTable(
|
||||
'ClassNamesUpgrade',
|
||||
[
|
||||
'ID' => 'PrimaryKey',
|
||||
'ClassName' => 'Enum(array("App\\\\MySite\\\\FooBar"))',
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
DB::query('INSERT INTO "ClassNamesUpgrade" ("ClassName") VALUES (\'App\MySite\FooBar\')');
|
||||
$count = DB::query('SELECT count(*) FROM "ClassNamesUpgrade" WHERE "ClassName" = \'App\MySite\FooBar\'')
|
||||
->value();
|
||||
|
||||
$this->assertEquals(1, $count);
|
||||
} finally {
|
||||
DB::query('DROP TABLE IF EXISTS "ClassNamesUpgrade"');
|
||||
DB::query('DROP SEQUENCE IF EXISTS "ClassNamesUpgrade_ID_seq"');
|
||||
}
|
||||
}
|
||||
|
||||
private function createSS3Table()
|
||||
{
|
||||
DB::query(<<<SQL
|
||||
CREATE SEQUENCE "ClassNamesUpgrade_ID_seq" start 1 increment 1;
|
||||
CREATE TABLE "ClassNamesUpgrade"
|
||||
(
|
||||
"ID" bigint NOT NULL DEFAULT nextval('"ClassNamesUpgrade_ID_seq"'::regclass),
|
||||
"ClassName" character varying(255) DEFAULT 'ClassNamesUpgrade'::character varying,
|
||||
CONSTRAINT "ClassNamesUpgrade_pkey" PRIMARY KEY ("ID"),
|
||||
CONSTRAINT "ClassNamesUpgrade_ClassName_check" CHECK ("ClassName"::text = ANY (ARRAY['FooBar'::character varying::text]))
|
||||
)
|
||||
WITH (
|
||||
OIDS=FALSE
|
||||
);
|
||||
SQL
|
||||
);
|
||||
}
|
||||
|
||||
public function testRenameTable()
|
||||
{
|
||||
try {
|
||||
/** @var PostgreSQLSchemaManager $dbSchema */
|
||||
$dbSchema = DB::get_schema();
|
||||
$dbSchema->quiet();
|
||||
|
||||
$this->createSS3VersionedTable();
|
||||
|
||||
$this->assertConstraintCount(1, 'ClassNamesUpgrade_versioned_ClassName_check');
|
||||
|
||||
$dbSchema->schemaUpdate(function () use ($dbSchema) {
|
||||
$dbSchema->renameTable(
|
||||
'ClassNamesUpgrade_versioned',
|
||||
'ClassNamesUpgrade_Versioned'
|
||||
);
|
||||
});
|
||||
|
||||
$this->assertTableCount(0, 'ClassNamesUpgrade_versioned');
|
||||
$this->assertTableCount(1, 'ClassNamesUpgrade_Versioned');
|
||||
$this->assertConstraintCount(0, 'ClassNamesUpgrade_versioned_ClassName_check');
|
||||
$this->assertConstraintCount(1, 'ClassNamesUpgrade_Versioned_ClassName_check');
|
||||
} finally {
|
||||
DB::query('DROP TABLE IF EXISTS "ClassNamesUpgrade_Versioned"');
|
||||
DB::query('DROP TABLE IF EXISTS "ClassNamesUpgrade_versioned"');
|
||||
DB::query('DROP SEQUENCE IF EXISTS "ClassNamesUpgrade_versioned_ID_seq"');
|
||||
}
|
||||
}
|
||||
|
||||
private function assertConstraintCount($expected, $constraintName)
|
||||
{
|
||||
$count = DB::prepared_query(
|
||||
'SELECT count(*) FROM pg_catalog.pg_constraint WHERE conname like ?',
|
||||
[$constraintName]
|
||||
)->value();
|
||||
|
||||
$this->assertEquals($expected, $count);
|
||||
}
|
||||
|
||||
private function assertTableCount($expected, $tableName)
|
||||
{
|
||||
$count = DB::prepared_query(
|
||||
'SELECT count(*) FROM pg_catalog.pg_tables WHERE "tablename" like ?',
|
||||
[$tableName]
|
||||
)->value();
|
||||
|
||||
$this->assertEquals($expected, $count);
|
||||
}
|
||||
|
||||
private function createSS3VersionedTable()
|
||||
{
|
||||
DB::query(<<<SQL
|
||||
CREATE SEQUENCE "ClassNamesUpgrade_versioned_ID_seq" start 1 increment 1;
|
||||
CREATE TABLE "ClassNamesUpgrade_versioned"
|
||||
(
|
||||
"ID" bigint NOT NULL DEFAULT nextval('"ClassNamesUpgrade_versioned_ID_seq"'::regclass),
|
||||
"ClassName" character varying(255) DEFAULT 'ClassNamesUpgrade'::character varying,
|
||||
CONSTRAINT "ClassNamesUpgrade_pkey" PRIMARY KEY ("ID"),
|
||||
CONSTRAINT "ClassNamesUpgrade_versioned_ClassName_check" CHECK ("ClassName"::text = ANY (ARRAY['FooBar'::character varying::text]))
|
||||
)
|
||||
WITH (
|
||||
OIDS=FALSE
|
||||
);
|
||||
SQL
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user