From 712c83354db783c0262f71abbc5bb752b14d2c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armand=20M=C3=A9grot?= Date: Tue, 14 Jan 2025 15:27:10 +0100 Subject: [PATCH 1/2] 3-state boolean columns emphasis on NOT NULL constraint --- README.adoc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/README.adoc b/README.adoc index 4f1fc57..aa76006 100644 --- a/README.adoc +++ b/README.adoc @@ -1167,19 +1167,30 @@ And you'll have to consider the fact that most non-trivial apps share a database === 3-state Boolean [[three-state-boolean]] -With SQL databases, if a boolean column is not given a default value, it will have three possible values: `true`, `false` and `NULL`. +With SQL databases, if a boolean column is nullable, it will have three possible values: `true`, `false` and `NULL`. Boolean operators https://en.wikipedia.org/wiki/Three-valued_logic[work in unexpected ways] with `NULL`. For example in SQL queries, `true AND NULL` is `NULL` (not false), `true AND NULL OR false` is `NULL` (not false). This can make SQL queries return unexpected results. -To avoid such situations, boolean columns should always have a default value and a `NOT NULL` constraint. +To avoid such situations, boolean columns should always have a `NOT NULL` constraint. + +Note that when adding a boolean column to an existing table, a default value should be put in place. Otherwise the `NOT NULL` constraint will break for existing rows. [source,ruby] ---- -# bad - boolean without a default value +# bad - boolean column on a new table without a `NOT NULL` constraint +create_table :users do |t| + t.boolean :active +end + +# bad - adding a boolean without a `NOT NULL` constraint or without a default value add_column :users, :active, :boolean +add_column :users, :active, :boolean, null: false -# good - boolean with a default value (`false` or `true`) and with restricted `NULL` +# good - boolean with a `NOT NULL` constraint, and a default value (`false` or `true`) for existing tables +create_table :users do |t| + t.boolean :active, null: false +end add_column :users, :active, :boolean, default: true, null: false add_column :users, :admin, :boolean, default: false, null: false ---- From 9b4ee4632beefa2845894a703ad043e0128d8a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armand=20M=C3=A9grot?= Date: Tue, 14 Jan 2025 17:03:27 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Phil Pirozhkov --- README.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.adoc b/README.adoc index aa76006..e347614 100644 --- a/README.adoc +++ b/README.adoc @@ -1183,14 +1183,16 @@ create_table :users do |t| t.boolean :active end -# bad - adding a boolean without a `NOT NULL` constraint or without a default value +# bad - adding a boolean column without a `NOT NULL` constraint or without a default value to an existing table add_column :users, :active, :boolean add_column :users, :active, :boolean, null: false -# good - boolean with a `NOT NULL` constraint, and a default value (`false` or `true`) for existing tables +# good - boolean column with a `NOT NULL` constraint for new tables create_table :users do |t| t.boolean :active, null: false end + +# good - boolean column with a `NOT NULL` constraint, and a default value (`false` or `true`) for existing tables add_column :users, :active, :boolean, default: true, null: false add_column :users, :admin, :boolean, default: false, null: false ----