# Available range types

# daterange

Let's imagine we want to use daterange column in our Laravel application.

# Migrations

First, let's add it in our migration files.

public function up(): void
    {
        Schema::create(
            'table',
            static function (Blueprint $table) {
                $table->id();
                // ...
                $table->dateRange('date_range');
                // you can add any modifications
                // $table->dateRange('date_range')->nullable();
                // $table->dateRange('date_range')->default('[2010-01-01,2010-01-02)');
            }
        );
    }

# Model property casting

Next, we should define cast for this column in our model class.

use Belamov\PostgresRange\Casts\DateRangeCast;

class SomeModel extends Model
{
    // ...
    protected $casts = [
        'date_range' => DateRangeCast::class,
    ];
    // ...
}

Now, whenever we access date_range attribute in our model, it will return Belamov\PostgresRange\Ranges\DateRange instance

# DateRange object

WARNING

DateRange object is automatically canonicalizable

Initialization:

use Belamov\PostgresRange\Ranges\DateRange;

$range = new DateRange('2010-01-10', '2010-01-15', '[', ')');

TIP

Note that you can initialize DateRange object either with strings, or with any objects that implement DateTime interface for example with Carbonobjects

$range = new DateRange(Carbon::parse('2010-01-10'), Carbon::now(), '[', ')')

API:

$range->from(); // CarbonImmutable object
$range->to(); // CarbonImmutable object
(string) $range; // [2010-01-10,2010-01-15)
$range->forSql(); // '[2010-01-10,2010-01-15)'::daterange

Updating or creating model:

$model->update(['date_range' => $range]);
$model->date_range; // DateRange object
$model->date_range->from(); // CarbonImmutable object
$model->date_range->to(); // CarbonImmutable object

# tsrange

Let's imagine we want to use tsrange column in our Laravel application.

# Migrations

First, let's add it in our migration files.

public function up(): void
    {
        Schema::create(
            'table',
            static function (Blueprint $table) {
                $table->id();
                // ...
                $table->timestampRange('timestamp_range');
                // you can add any modifications
                // $table->timestampRange('timestamp_range')->nullable();
                // $table->timestampRange('timestamp_range')->default('[2010-01-01 14:30:30,2010-01-02 14:30:30)');
            }
        );
    }

# Model property casting

Next, we should define cast for this column in our model class.

use Belamov\PostgresRange\Casts\TimestampRangeCast;

class SomeModel extends Model
{
    // ...
    protected $casts = [
        'timestamp_range' => TimestampRangeCast::class,
    ];
    // ...
}

Now, whenever we access timestamp_range attribute in our model, it will return Belamov\PostgresRange\Ranges\TimestampRange instance

# TimestampRange object

Initialization:

use Belamov\PostgresRange\Ranges\TimestampRange;

$range = new TimestampRange('2010-01-01 14:30:30', '2010-01-02 14:30:30', '[', ')');

TIP

Note that you can initialize TimestampRange object either with strings, or with any objects that implement DateTime interface for example with Carbon objects

$range = new TimestampRange(Carbon::parse('2010-01-01 14:30:30'), Carbon::now(), '[', ')')

API:

$range->from(); // CarbonImmutable object
$range->to(); // CarbonImmutable object
(string) $range; // [2010-01-01 14:30:30,2010-01-02 14:30:30)
$range->forSql(); // '[2010-01-01 14:30:30,2010-01-02 14:30:30)'::tsrange

Model updating or creating:

$model->update(['timestamp_range' => $range]);
$model->timestamp_range; // TimestampRange object
$model->timestamp_range->from(); // CarbonImmutable object
$model->timestamp_range->to(); // CarbonImmutable object

# numrange

Let's imagine we want to use numrange column in our Laravel application.

# Migrations

First, let's add it in our migration files.

public function up(): void
    {
        Schema::create(
            'table',
            static function (Blueprint $table) {
                $table->id();
                // ...
                $table->floatRange('float_range');
                // you can add any modifications
                // $table->timestampRange('float_range')->nullable();
                // $table->timestampRange('float_range')->default('[1.5,2.5)');
            }
        );
    }

# Model property casting

Next, we should define cast for this column in our model class.

use Belamov\PostgresRange\Casts\FloatRangeCast;

class SomeModel extends Model
{
    // ...
    protected $casts = [
        'float_range' => FloatRangeCast::class,
    ];
    // ...
}

Now, whenever we access float_range attribute in our model, it will return Belamov\PostgresRange\Ranges\FloatRange instance

# FloatRange object

Initialization:

use Belamov\PostgresRange\Ranges\FloatRange;

$range = new FloatRange(1.5, 2.5, '[', ')');

API:

$range->from(); // 1.5
$range->to(); // 2.5
(string) $range; // [1.5,2.5)
$range->forSql(); // '[1.5,2.5)'::numrange

Model updating or creating:

$model->update(['float_range' => $range]);
$model->float_range; // FloatRange object
$model->float_range->from(); // 1.5
$model->float_range->to(); // 2.5

# intrange

Let's imagine we want to use int4range or int8range column in our Laravel application.

# Migrations

First, let's add it in our migration files.

public function up(): void
    {
        Schema::create(
            'table',
            static function (Blueprint $table) {
                $table->id();
                // ...
                $table->integerRange('integer_range'); //for int4range
                $table->bigIntegerRange('integer_range'); //for int8range

                // you can add any modifications
                // $table->integerRange('integer_range')->nullable();
                // $table->integerRange('integer_range')->default('[10,20)');
                // $table->bigIntegerRange('integer_range')->nullable();
                // $table->bigIntegerRange('integer_range')->default('[10,20)');
            }
        );
    }

# Model property casting

Next, we should define cast for this column in our model class.

use Belamov\PostgresRange\Casts\IntegerRangeCast;

class SomeModel extends Model
{
    // ...
    protected $casts = [
        'integer_range' => IntegerRangeCast::class,
    ];
    // ...
}

Now, whenever we access integer_range attribute in our model, it will return Belamov\PostgresRange\Ranges\IntegerRange instance

# IntegerRange object

WARNING

IntegerRange object is automatically canonicalizable

Initialization:

use Belamov\PostgresRange\Ranges\IntegerRange;

$range = new IntegerRange(10, 20, '[', ')');

API:

$range->from(); // 10
$range->to(); // 20
(string) $range; // [10,20)
$range->forSql(); // '[10,20)'

Model updating or creating:

$model->update(['integer_range' => $range]);
$model->integer_range; // IntegerRange object
$model->integer_range->from(); // 10
$model->integer_range->to(); // 20

# timerange

Postgres doesn't support timerange type, so this package will define it.

Type definition happens whenever you call $table->timeRange(); in your migration files.

But all sql scripts are idempotent, so this scripts may be run multiple times.

Type definition implemented in this way:

CREATE OR REPLACE FUNCTION time_subtype_diff(x time, y time) RETURNS float8 AS
'SELECT EXTRACT(EPOCH FROM (x - y))' LANGUAGE sql STRICT IMMUTABLE;


DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'timerange') THEN
        CREATE TYPE timerange AS RANGE (
            subtype = time,
            subtype_diff = time_subtype_diff
        );
    END IF;
END$$

Type name and comparing function name are configurable:

  • with env variables:
    TIMERANGE_TYPENAME=timerange
    TIMERANGE_SUBTYPE_DIFF_FUNCTION_NAME=time_subtype_diff
    
  • or with config file:
    php artisan vendor:publish --provider="Belamov\PostgresRange\PostgresRangeServiceProvider" --tag="config"
    
    in config/postges-range.php:
    return [
        'timerange_typename' =>  'timerange',
        'timerange_subtype_diff_function_name' => 'time_subtype_diff',
    ];
    

Let's imagine we want to use that custom defined timerange type in our Laravel application.

# Migrations

First, let's add it in our migration files.

public function up(): void
    {
        Schema::create(
            'table',
            static function (Blueprint $table) {
                $table->id();
                // ...
                $table->timeRange('time_range');

                // you can add any modifications
                // $table->timeRange('time_range')->nullable();
                // $table->timeRange('time_range')->default('[14:30:30,15:30:30)');
            }
        );
    }

# Model property casting

Next, we should define cast for this column in our model class.

use Belamov\PostgresRange\Casts\TimeRangeCast;

class SomeModel extends Model
{
    // ...
    protected $casts = [
        'time_range' => TimeRangeCast::class,
    ];
    // ...
}

Now, whenever we access time_range attribute in our model, it will return Belamov\PostgresRange\Ranges\TimeRange instance

# TimeRange object

Initialization:

use Belamov\PostgresRange\Ranges\TimeRange;

$range = new TimeRange('14:30:30', '15:30:30', '[', ')');

TIP

Note that you can initialize TimeRange object either with strings, or with any objects that implement DateTime interface for example with Carbon objects

$range = new TimestampRange(Carbon::parse('14:30:30'), Carbon::now(), '[', ')')

API:

$range->from(); // 14:30:30
$range->to(); // 15:30:30
(string) $range; // [14:30:30,15:30:30)
$range->forSql(); // '[14:30:30,15:30:30)'::timerange 
// (if you haven't change timerange typename in config)

Model updating or creating:

$model->update(['time_range' => $range]);
$model->time_range; // TimeRange object
$model->time_range->from(); // '14:30:30'
$model->time_range->to(); // '15:30:30'

# Canonicalizable ranges

The built-in range types int4range, int8range, and daterange all use a canonical form that includes the lower bound and excludes the upper bound; that is, [). (More in official documentation)

So to reflect this behaviour DateRange and IntegerRange object will be canonialized during initialization like so:

When lower boundary is exclusive:

$range = new IntegerRange(10, 20, '(', ')');
$range->from(); // 11
$range->to(); // 20
(string) $range; // '[11,20)'

$range = new DateRange($from, $to, '(', ')');
$range->from(); // equals $from->addDay()
$range->to(); // equals $to
(string) $range; // '[2010-01-11,2010-01-15)'

When upper boundary is inclusive:

$range = new IntegerRange(10, 20, '[', ']');
$range->from(); // 10
$range->to(); // 21
(string) $range; // '[10,21)'

$range = new DateRange($from, $to, '[', ']');
$range->from(); // equals $from
$range->to(); // equals $to->addDay()
(string) $range; // '[2010-01-10,2010-01-16)'