emiliopedrollo/laravel-postgres-extended-schema

View on GitHub
src/Pedrollo/Database/Schema/Grammars/PostgresGrammar.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php

namespace Pedrollo\Database\Schema\Grammars;

use Illuminate\Database\Query\Expression;
use Illuminate\Support\Fluent;
use Illuminate\Database\Schema\Blueprint as BaseBlueprint;

/**
 * Class PostgresGrammar
 * @package Pedrollo\Database\Schema\Grammars
 */
class PostgresGrammar extends \Illuminate\Database\Schema\Grammars\PostgresGrammar
{
     /**
     * Check if the type is uuid, use internal guid
     *
     * @param  string $type
     * @return \Doctrine\DBAL\Types\Type
     */
    protected function getDoctrineColumnType($type)
    {
        if($type === 'uuid') {
            $type = 'guid';
        }

        return parent::getDoctrineColumnType($type);
    }

    /**
     * Create the column definition for a character type.
     *
     * @param Fluent $column
     * @return string
     */
    protected function typeCharacter(Fluent $column)
    {
        return "character({$column->length})";
    }

    /**
     * Create the column definition for a hstore type.
     *
     * @param Fluent $column
     * @return string
     */
    protected function typeHstore(Fluent $column)
    {
        return "hstore";
    }

    /**
     * Create the column definition for a uuid type.
     *
     * @param Fluent $column
     * @return string
     */
    protected function typeUuid(Fluent $column)
    {
        return "uuid";
    }

    /**
     * Create the column definition for a jsonb type.
     *
     * @param Fluent $column
     * @return string
     */
    protected function typeJsonb(Fluent $column)
    {
        return "jsonb";
    }

    /**
     * Create the column definition for an IPv4 or IPv6 address.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeIpAddress(Fluent $column)
    {
        return 'inet';
    }
    /**
     * Create the column definition for a CIDR notation-style netmask.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeNetmask(Fluent $column)
    {
        return 'cidr';
    }

    /**
     * Create the column definition for a MAC address.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeMacAddress(Fluent $column)
    {
        return 'macaddr';
    }

    /**
     * Create the column definition for a 2D geometric point (x, y), x and y are floating-point numbers.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typePoint(Fluent $column)
    {
        return 'point';
    }

    /**
     * Create the column definition for a line represented as a standard linear equation Ax + By + C = 0.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeLine(Fluent $column)
    {
        return 'line';
    }

    /**
     * Create the column definition for a line segment represented by two points (x1, y1), (x2, y2).
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeLineSegment(Fluent $column)
    {
        return 'lseg';
    }

    /**
     * Create the column definition for a path represented as a list of points (x1, y1), (x2, y2), ..., (xn, yn).
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typePath(Fluent $column)
    {
        return 'path';
    }

    /**
     * Create the column definition for a box represented by opposite corners of the box as points (x1, y1), (x2, y2).
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeBox(Fluent $column)
    {
        return 'box';
    }

    /**
     * Create the column definition for a polygon represented by a list of points (vertices of the polygon).
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typePolygon(Fluent $column)
    {
        return 'polygon';
    }

    /**
     * Create the column definition for a circle represented by a center point and a radius <(x, y), r>
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeCircle(Fluent $column)
    {
        return 'circle';
    }

    /**
     * Create the column definition for storing amounts of currency with a fixed fractional precision.
     *
     * This will store values in the range of: -92233720368547758.08 to +92233720368547758.07. (92 quadrillion).
     * Output is locale-sensitive, see lc_monetary setting of PostgreSQL instance/s.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeMoney(Fluent $column)
    {
        return 'money';
    }

    /**
     * Create the column definition for an int4range type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeInt4range(Fluent $column)
    {
        return "int4range";
    }

    /**
     * Create the column definition for an int8range type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeInt8range(Fluent $column)
    {
        return "int8range";
    }

    /**
     * Create the column definition for an numrange type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeNumrange(Fluent $column)
    {
        return "numrange";
    }

    /**
     * Create the column definition for an tsrange type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeTsrange(Fluent $column)
    {
        return "tsrange";
    }

    /**
     * Create the column definition for an tstzrange type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeTstzrange(Fluent $column)
    {
        return "tstzrange";
    }

    /**
     * Create the column definition for an daterange type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeDaterange(Fluent $column)
    {
        return "daterange";
    }

    /**
     * Create the column definition for a Text Search Vector type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeTsvector(Fluent $column)
    {
        return "tsvector";
    }

    /**
     * Create the column definition for a Bytea type.
     *
     * @param Fluent $column
     *
     * @return string
     */
    protected function typeBytea(Fluent $column)
    {
        return "bytea";
    }

    /**
     * @param mixed $value
     * @return mixed|string
     */
    protected function getDefaultValue($value)
    {
        if($this->isUuidGenerator($value)) return strval($value);

        return parent::getDefaultValue($value);
    }

    /**
     * Check if string matches on of uuid_generate functions
     *
     * @param mixed $value
     * @return bool
     */
    protected function isUuidGenerator(mixed $value)
    {
        return is_string($value) && str_starts_with($value, 'uuid_generate_v');
    }

    public function compileWith(BaseBlueprint $blueprint, Fluent $command){
        if (is_string($command->value)) {
            $value = $this->wrap($command->value);
        } elseif (is_bool($command->value)) {
            $value = ($command->value?'true':'false');
        } else $value = ((string) $command->value);

        return sprintf('alter table %s set (%s = %s)',
            $this->wrapTable($blueprint),
            $command->key,
            $value
        );
    }

    /**
     * Compile create table query.
     *
     * @param BaseBlueprint $blueprint
     * @param  \Illuminate\Support\Fluent $command
     * @return array|string
     */
    public function compileCreate(BaseBlueprint $blueprint, Fluent $command)
    {
        $sql = parent::compileCreate($blueprint, $command);

        $addToSql = function($string) use (&$sql) {
            (is_string($sql) ? $sql .= $string : $sql[0] .= $string);
        };

        if (isset($blueprint->inherits)) {
            $addToSql(' inherits ("'.$blueprint->inherits.'")');
        }
        if (isset($blueprint->partition_expressions)) {

            $expressions = join(', ',array_map(function ($expression) {
                return $expression instanceof Expression
                    ? $expression->getValue($this)
                    : '"'.$expression.'"';
            },$blueprint->partition_expressions));

            $addToSql(' partition by '.$blueprint->partition_type.' ('.$expressions.')');
        }
        return $sql;
    }

    /**
     * Create the column definition for a bit type.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeBit(Fluent $column)
    {
        return "bit({$column->length})";
    }

    /**
     * Compile a unique key command.
     *
     * @param  \Illuminate\Database\Schema\Blueprint  $blueprint
     * @param  \Illuminate\Support\Fluent  $command
     * @return string
     */
    public function compileUnique(BaseBlueprint $blueprint, Fluent $command)
    {
        return sprintf( 'create unique index %s on %s (%s) %s',
            $this->wrap($command->index),
            $this->wrapTable($blueprint),
            $this->columnize($command->columns),
            isset($command->algorithm)?$command->algorithm:''
        );
    }

    /**
     * Compile a plain index key command.
     *
     * @param  \Illuminate\Database\Schema\Blueprint  $blueprint
     * @param  \Pedrollo\Database\IndexDefinition  $command
     * @return string
     */
    public function compileIndex(BaseBlueprint $blueprint, Fluent $command)
    {
        return preg_replace('/\s+/',' ',
            sprintf('create %s index %s %s on %s %s (%s) %s %s',
                $command->unique ? 'unique' : '',
                $command->concurrently ? 'concurrently' : '',
                $this->wrap($command->index),
                $this->wrapTable($blueprint),
                $command->algorithm ? 'using '.$command->algorithm : '',
                $this->columnize($command->columns),
                $command->distinctNulls ? '' : 'nulls not distinct',
                $command->where ? 'where '.$command->where : ''
            )
        );
    }
}