douglasshuang

douglasshuang

High Performance PostgreSQL for Rails: `NOT NULL` constraint not part of domain as stated (page 90)

The book states the following:

The main difference for domains compared with enums is that the NOT NULL constraint portion is part of the domain.

This is incorrect. The domain has a CHECK constraint for valid non-NULL values, but the NOT NULL constraint is part of the column declaration and can be removed independently of the domain, as follows:

owner@localhost:5432 rideshare_development# ALTER TABLE vehicles ALTER COLUMN status DROP NOT NULL;
ALTER TABLE
owner@localhost:5432 rideshare_development# UPDATE vehicles SET status = NULL;
UPDATE 4
owner@localhost:5432 rideshare_development# SELECT DISTINCT(status) from vehicles;
 status
--------

(1 row)

owner@localhost:5432 rideshare_development# \d vehicles
                                        Table "rideshare.vehicles"
   Column   |              Type              | Collation | Nullable |               Default
------------+--------------------------------+-----------+----------+--------------------------------------
 id         | bigint                         |           | not null | nextval('vehicles_id_seq'::regclass)
 name       | character varying              |           | not null |
 created_at | timestamp(6) without time zone |           | not null |
 updated_at | timestamp(6) without time zone |           | not null |
 status     | vehicle_statuses               |           |          | 'draft'::text
Indexes:
    "vehicles_pkey" PRIMARY KEY, btree (id)
    "index_vehicles_on_name" UNIQUE, btree (name)
Referenced by:
    TABLE "vehicle_reservations" CONSTRAINT "fk_rails_7edc8e666a" FOREIGN KEY (vehicle_id) REFERENCES vehicles(id)

owner@localhost:5432 rideshare_development# \dD vehicle_statuses
                                                           List of domains
  Schema   |       Name       | Type | Collation | Nullable | Default |                             Check
-----------+------------------+------+-----------+----------+---------+---------------------------------------------------------------
 rideshare | vehicle_statuses | text |           |          |         | CHECK (VALUE = ANY (ARRAY['draft'::text, 'published'::text]))
(1 row)

Marked As Solved

andatki

andatki

Author of High Performance PostgreSQL for Rails

Hi @douglasshuang. You’re bringing up a great point here. I want to make a correction to the book text based on this to help readers.

Here’s the domain definition in the book:

-- This is the existing domain in the book.
CREATE DOMAIN vehicle_statuses AS TEXT
CONSTRAINT valid_vehicle_statuses
CHECK (VALUE IN ('draft', 'published') );

This omits a NOT NULL constraint in the domain definition. If we were to add a NOT NULL to the domain like this:

-- Create a new domain called vehicle_statuses_not_null and include a NOT NULL
CREATE DOMAIN vehicle_statuses_not_null AS TEXT
CONSTRAINT valid_vehicle_statuses
CHECK (VALUE IN ('draft', 'published') )
NOT NULL;

Then the domain will enforce the not null.

Here’s an example:

-- Add column “status_new_domain”  that uses the domain above with NOT NULL.
-- Empty out the table rows so we can try inserting
ALTER TABLE vehicles
ADD COLUMN status_new_domain vehicle_statuses_not_null;

-- Describe the domains. Notice the nullable property has the NOT NULL constraint.
owner@[local]:5432 rideshare_development# \dD
                                                               List of domains
 Schema   |           Name            | Type | Collation | Nullable | Default |                             Check
-----------+---------------------------+------+-----------+----------+---------+---------------------------------------------------------------
rideshare | vehicle_statuses_not_null | text |           | not null |         | CHECK (VALUE = ANY (ARRAY['draft'::text, 'published'::text]))


-- Describe the vehicles table. Only showing the “status_new_domain” column.
-- Notice here that status_new_domain shows as nullable
-- i.e. we don't see the NOT NULL from the domain, confusing!
\d vehicles
owner@[local]:5432 rideshare_development# \d vehicles
                                           Table "rideshare.vehicles"
     Column       |              Type              | Collation | Nullable |               Default
-------------------+--------------------------------+-----------+----------+--------------------------------------
status_new_domain | vehicle_statuses_not_null      |           |          |

owner@[local]:5432 rideshare_development# insert into vehicles (name) values ('draft');
ERROR:  domain vehicle_statuses_not_null does not allow null values


-- Try to insert a null value in status_new_domain
owner@[local]:5432 rideshare_development# insert into vehicles (name, status_new_domain) values ('draft', null);
ERROR:  domain vehicle_statuses_not_null does not allow null values

If we add an additional NOT NULL to the column on the table, that’s more clear. Then describing the table shows it as NOT NULL.

After considering this more since you’ve brought it up, using not null constraints in Domains to illustrate the difference between an Enum and a Domain type feels like a poor choice for learning materials. It’s useful but more like an edge case.

I would like to expand on this in a better example as a blog post, or possibly in a future iteration of the book. I think focusing on the base data type for a Domain for example, and the behavior and the functionality it brings over an Enum, would be a better example for learning the differences. We could note this gotcha with NOT NULL constraints as the documentation does.

To make a targeted correction in the book, I think we’ll add a NOT NULL constraint to the domain definition though, and a warning about the implicit behavior, to keep the changes minimal.

Docs: PostgreSQL: Documentation: 17: CREATE DOMAIN

What do you think?

Thanks again for noticing this and spending the time to write up this issue!

Where Next?

Popular Pragmatic Bookshelf topics Top

jesse050717
Title: Web Development with Clojure, Third Edition, pg 116 Hi - I just started chapter 5 and I am stuck on page 116 while trying to star...
New
mikecargal
Title: Hands-On Rust (Chap 8 (Adding a Heads Up Display) It looks like ​.with_simple_console_no_bg​(SCREEN_WIDTH*2, SCREEN_HEIGHT*2...
New
rmurray10127
Title: Intuitive Python: docker run… denied error (page 2) Attempted to run the docker command in both CLI and Powershell PS C:\Users\r...
New
adamwoolhether
When trying to generate the protobuf .go file, I receive this error: Unknown flag: --go_opt libprotoc 3.12.3 MacOS 11.3.1 Googling ...
New
jskubick
I found an issue in Chapter 7 regarding android:backgroundTint vs app:backgroundTint. How to replicate: load chapter-7 from zipfile i...
New
digitalbias
Title: Build a Weather Station with Elixir and Nerves: Problem connecting to Postgres with Grafana on (page 64) If you follow the defau...
New
brunogirin
When trying to run tox in parallel as explained on page 151, I got the following error: tox: error: argument -p/–parallel: expected one...
New
mert
AWDWR 7, page 152, page 153: Hello everyone, I’m a little bit lost on the hotwire part. I didn’t fully understand it. On page 152 @rub...
New
EdBorn
Title: Agile Web Development with Rails 7: (page 70) I am running windows 11 pro with rails 7.0.3 and ruby 3.1.2p20 (2022-04-12 revision...
New
Keton
When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New

Other popular topics Top

New
PragmaticBookshelf
Brace yourself for a fun challenge: build a photorealistic 3D renderer from scratch! In just a couple of weeks, build a ray tracer that r...
New
AstonJ
I ended up cancelling my Moonlander order as I think it’s just going to be a bit too bulky for me. I think the Planck and the Preonic (o...
New
Margaret
Hello everyone! This thread is to tell you about what authors from The Pragmatic Bookshelf are writing on Medium.
1147 29994 760
New
AstonJ
Was just curious to see if any were around, found this one: I got 51/100: Not sure if it was meant to buy I am sure at times the b...
New
PragmaticBookshelf
Author Spotlight Rebecca Skinner @RebeccaSkinner Welcome to our latest author spotlight, where we sit down with Rebecca Skinner, auth...
New
New
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New
RobertRichards
Hair Salon Games for Girls Fun Girls Hair Saloon game is mainly developed for kids. This game allows users to select virtual avatars to ...
New

Sub Categories: