はじめに
表題通り、PostgreSQLが持つ基本の型を拡張するドメイン型を作成します。
今回は、tsrangeを拡張します。
ドメイン型 (Domain Type)って何??
-
概要
- 既存の型(例:
integer
,tsrange
)に対して制約を追加した「ラッパー型」
- 既存の型(例:
-
メリット
- 再利用性:同じ制約を何度も書かずに済む
- 一貫性:制約を変更すると、ドメインを使っているすべての列に自動適用
- 可読性:型名から用途や制約内容が直感的にわかる
-
定義例
CREATE DOMAIN positive_int AS integer
CHECK (VALUE > 0);
実践
今回はtsrange
を拡張します
-- tsrange のラッパー型を定義
CREATE DOMAIN tsrange_wrap AS tsrange
CHECK (
-- 無限端点でないこと
NOT lower_inf(VALUE)
AND NOT upper_inf(VALUE)
-- 空範囲でないこと
AND NOT isempty(VALUE)
-- 左端は inclusive ([)
AND lower_inc(VALUE)
-- 右端は exclusive ())
AND NOT upper_inc(VALUE)
);
-- テーブル定義で直接使用
CREATE TABLE calendar_events (
id serial PRIMARY KEY,
title text NOT NULL,
time_range tsrange_wrap NOT NULL
);
→型がちゃんとtsrange_wrapになっていることを確認できます。
実行結果
では実際に実行していきます!
-- 成功例(すべてのドメイン制約を満たす: finite・非空・左端 [・右端 ))
INSERT INTO calendar_events (title, time_range)
VALUES (
'Valid Event',
'[2025-06-01 09:00,2025-06-01 11:00)'::tsrange_wrap
);
------------------------------------------------------------
-- 失敗例1:左端が開区間 ‘(’ のため lower_inc(VALUE) が FALSE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
'NG 左開放',
'(2025-06-01 09:00,2025-06-01 11:00)'::tsrange_wrap
);
-- ERROR: value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"
------------------------------------------------------------
-- 失敗例2:右端が閉区間 ‘]’ のため NOT upper_inc(VALUE) が FALSE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
'NG 右閉鎖',
'[2025-06-01 09:00,2025-06-01 11:00]'::tsrange_wrap
);
-- ERROR: value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"
------------------------------------------------------------
-- 失敗例3:上限が無限大 ‘)’ のため upper_inf(VALUE) が TRUE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
'NG 無限端点',
'[2025-06-01 09:00,)'::tsrange_wrap
);
-- ERROR: value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"
------------------------------------------------------------
-- 失敗例4:空レンジ ‘empty’ のため isempty(VALUE) が TRUE
------------------------------------------------------------
INSERT INTO calendar_events (title, time_range)
VALUES (
'NG 空レンジ',
'empty'::tsrange_wrap
);
-- ERROR: value for domain tsrange_wrap violates check constraint "tsrange_wrap_check"