efureev/laravel-support-db

View on GitHub
src/Schema/Postgres/Blueprint.php

Summary

Maintainability
B
5 hrs
Test Coverage
A
100%
<?php

declare(strict_types=1);

namespace Php\Support\Laravel\Database\Schema\Postgres;

use Illuminate\Database\Query\Expression;
use Illuminate\Database\Schema\Blueprint as BaseBlueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Fluent;
use Php\Support\Laravel\Database\Schema\Definitions\ColumnDefinition;
use Php\Support\Laravel\Database\Schema\Definitions\LikeDefinition;
use Php\Support\Laravel\Database\Schema\Definitions\PartialDefinition;
use Php\Support\Laravel\Database\Schema\Definitions\UniqueDefinition;
use Php\Support\Laravel\Database\Schema\Definitions\ViewDefinition;
use Php\Support\Laravel\Database\Schema\Postgres\Builders\Indexes\PartialBuilder;
use Php\Support\Laravel\Database\Schema\Postgres\Builders\Indexes\Unique\UniqueBuilder;

class Blueprint extends BaseBlueprint
{
    public function bit(string $column, int $length): ColumnDefinition
    {
        return $this->addColumn('bit', $column, compact('length'));
    }

    /**
     * Almost like 'decimal' type, but can be with variable precision (by default)
     *
     * @param string $column
     * @param int|null $precision
     * @param int|null $scale
     *
     * @return ColumnDefinition
     */
    public function numeric(string $column, ?int $precision = null, ?int $scale = null): Fluent
    {
        return $this->addColumn('numeric', $column, compact('precision', 'scale'));
    }

    public function generateUUID(string $column = 'id', bool|callable|Expression|null $default = true): ColumnDefinition
    {
        $defCol = $this->addColumn('uuid', $column);
        if ($default === false) {
            return $defCol;
        }

        DB::statement('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";');

        switch (true) {
            case $default === true:
                $defaultExpression = new Expression('uuid_generate_v4()');
                break;

            case is_callable($default):
                $defaultExpression = new Expression($default($column));
                break;

            case $default === null:
                $defaultExpression = null;
                $defCol->nullable();
                break;
            case $default instanceof Expression:
                $defaultExpression = $default;
                break;
        }


        return $defCol->default($defaultExpression);
    }


    public function primaryUUID(string $column = 'id', $generate = true): ColumnDefinition
    {
        return $this->generateUUID($column, $generate)->primary();
    }

    /**
     * Create a new date range column on the table.
     */
    public function dateRange(string $column): ColumnDefinition
    {
        return $this->addColumn('dateRange', $column);
    }

    public function tsRange(string $column): ColumnDefinition
    {
        return $this->addColumn('tsrange', $column);
    }

    public function timestampRange(string $column): ColumnDefinition
    {
        return $this->tsRange($column);
    }

    /**
     * Create a new ip network column on the table.
     */
    public function ipNetwork(string $column): ColumnDefinition
    {
        return $this->addColumn('ipNetwork', $column);
    }

    /**
     * Create a new POINT type column
     *
     * @param string $column
     *
     * @return ColumnDefinition
     */
    public function geoPoint(string $column): ColumnDefinition
    {
        return $this->addColumn('geoPoint', $column);
    }

    /**
     * Create a new PATH type column
     */
    public function geoPath(string $column): ColumnDefinition
    {
        return $this->addColumn('geoPath', $column);
    }

    /**
     * Create a new xml column on the table.
     */
    public function xml(string $column): ColumnDefinition
    {
        return $this->addColumn('xml', $column);
    }

    /**
     * Create a new uuid[] column
     */
    public function uuidArray(string $column): ColumnDefinition
    {
        return $this->addColumn('uuidArray', $column);
    }

    /**
     * Create a new int[] column
     *
     * @param string $column
     *
     * @return ColumnDefinition
     */
    public function intArray(string $column): ColumnDefinition
    {
        return $this->addColumn('intArray', $column);
    }

    /**
     * Add a new column to the blueprint.
     *
     * @param string $type
     * @param string $name
     * @param array $parameters
     */
    public function addColumn($type, $name, array $parameters = []): ColumnDefinition
    {
        return $this->addColumnDefinition(
            new ColumnDefinition(
                array_merge(compact('type', 'name'), $parameters)
            )
        );
    }

    /**
     * @param string $view
     * @param string $select
     * @param bool $materialize
     *
     * @return ViewDefinition|Fluent
     */
    public function createView(string $view, string $select, bool $materialize = false): Fluent
    {
        return $this->addCommand('createView', compact('view', 'select', 'materialize'));
    }

    public function createViewOrReplace(string $view, string $select, bool $materialize = false): Fluent
    {
        return $this->addCommand('createViewOrReplace', compact('view', 'select', 'materialize'));
    }

    public function dropView(string $view): Fluent
    {
        return $this->addCommand('dropView', compact('view'));
    }

    public function ifNotExists(): Fluent
    {
        return $this->addCommand('ifNotExists');
    }

    /**
     * @param array|string $index
     * @param string|null $type unique|primary
     * @return bool
     */
    public function hasIndex(array|string $index, ?string $type = null): bool
    {
        return Schema::hasIndex($this->getTable(), $index, $type);
    }

    /**
     * @return LikeDefinition
     */
    public function like(string $table): Fluent
    {
        return $this->addCommand('like', compact('table'));
    }

    /**
     * Create a new table from a source-table and fill it with a data from SELECT-query from the source-table
     * and without dependencies (Indexes, etc.)
     *
     * @param string $fromSelect
     *
     * @return Fluent
     *
     * @example `$table->fromSelect('select t1.id, t1.name from src_table t1');`
     */
    public function fromSelect(string $fromSelect): Fluent
    {
        return $this->addCommand('fromSelect', compact('fromSelect'));
    }

    /**
     * Create a new table coping from a source-table with a data and without dependencies (Indexes, etc.)
     *
     * @param string $fromTable
     *
     * @return Fluent
     *
     * @example `$table->fromTable('source_table');`
     */
    public function fromTable(string $fromTable): Fluent
    {
        return $this->addCommand('fromTable', compact('fromTable'));
    }

    /**
     * @param array|string $columns
     * @param string|null $index
     * @param string|null $algorithm
     *
     * @return UniqueDefinition|UniqueBuilder
     */
    public function uniquePartial($columns, ?string $index = null, ?string $algorithm = null): Fluent
    {
        $columns = (array)$columns;

        $index = $index ?: $this->createIndexName('unique', $columns);

        return $this->addExtendedCommand(
            UniqueBuilder::class,
            'uniquePartial',
            compact('columns', 'index', 'algorithm')
        );
    }

    /**
     * @param array|string $columns
     * @param string|null $index
     * @param string|null $algorithm
     *
     * @return PartialDefinition|PartialBuilder
     */
    public function partial($columns, ?string $index = null, ?string $algorithm = null): Fluent
    {
        $columns = (array)$columns;

        $index = $index ?: $this->createIndexName('partial', $columns);

        return $this->addExtendedCommand(
            PartialBuilder::class,
            'partial',
            compact('columns', 'index', 'algorithm')
        );
    }

    public function ginIndex($columns, ?string $name = null): Fluent
    {
        return $this->indexCommand('index', $columns, $name, 'gin');
    }

    public function dropUniquePartial($index): Fluent
    {
        return $this->dropIndexCommand('dropIndex', 'unique', $index);
    }

    public function dropPartial($index): Fluent
    {
        return $this->dropIndexCommand('dropIndex', 'partial', $index);
    }

    private function addExtendedCommand(string $fluent, string $name, array $parameters = []): Fluent
    {
        $command          = new $fluent(array_merge(compact('name'), $parameters));
        $this->commands[] = $command;

        return $command;
    }
}