From 04fa85abd10a7070ee57683d88caf4462ca82056 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Thu, 16 Jul 2026 16:47:31 -0500 Subject: [PATCH] Bump count_nulls to 1.0.0, add basic CI No functional SQL changes since 0.9.6 (see sql/count_nulls--0.9.6--1.0.0.sql). Version bump plus a starter CI workflow using pgxn/pgxn-tools across the supported PostgreSQL matrix. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 17 ++++++ META.in.json | 4 +- META.json | 4 +- count_nulls.control | 2 +- sql/count_nulls--0.9.6--1.0.0.sql | 1 + sql/count_nulls--1.0.0.sql | 87 +++++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 sql/count_nulls--0.9.6--1.0.0.sql create mode 100644 sql/count_nulls--1.0.0.sql diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d4aaec9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,17 @@ +name: CI +on: [push, pull_request] +jobs: + test: + strategy: + matrix: + pg: [17, 16, 15, 14, 13, 12, 11, 10] + name: 🐘 PostgreSQL ${{ matrix.pg }} + runs-on: ubuntu-latest + container: pgxn/pgxn-tools + steps: + - name: Start PostgreSQL ${{ matrix.pg }} + run: pg-start ${{ matrix.pg }} + - name: Check out the repo + uses: actions/checkout@v4 + - name: Test on PostgreSQL ${{ matrix.pg }} + run: pg-build-test diff --git a/META.in.json b/META.in.json index 6bfa55c..c730255 100644 --- a/META.in.json +++ b/META.in.json @@ -16,7 +16,7 @@ "name": "count_nulls", "X_comment": "REQUIRED. Version of the distribution. http://pgxn.org/spec/#version", - "version": "0.9.7", + "version": "1.0.0", "X_comment": "REQUIRED. Short description of distribution.", "abstract": "Count the number of null arguments", @@ -43,7 +43,7 @@ "file": "sql/count_nulls.sql", "X_comment": "REQUIRED. Version the extension is at.", - "version": "0.9.6", + "version": "1.0.0", "X_comment": "Optional: \"abstract\": Description of the extension.", "abstract": "Count the number of null arguments", diff --git a/META.json b/META.json index 4bfc36b..19c84e1 100644 --- a/META.json +++ b/META.json @@ -16,7 +16,7 @@ "name": "count_nulls", "X_comment": "REQUIRED. Version of the distribution. http://pgxn.org/spec/#version", - "version": "0.9.7", + "version": "1.0.0", "X_comment": "REQUIRED. Short description of distribution.", "abstract": "Count the number of null arguments", @@ -43,7 +43,7 @@ "file": "sql/count_nulls.sql", "X_comment": "REQUIRED. Version the extension is at.", - "version": "0.9.6", + "version": "1.0.0", "X_comment": "Optional: \"abstract\": Description of the extension.", "abstract": "Count the number of null arguments", diff --git a/count_nulls.control b/count_nulls.control index 14eaa22..c5c5c28 100644 --- a/count_nulls.control +++ b/count_nulls.control @@ -1,4 +1,4 @@ # count_nulls extension comment = 'Count the number of null arguments' -default_version = '0.9.6' +default_version = '1.0.0' relocatable = false diff --git a/sql/count_nulls--0.9.6--1.0.0.sql b/sql/count_nulls--0.9.6--1.0.0.sql new file mode 100644 index 0000000..dc73d7b --- /dev/null +++ b/sql/count_nulls--0.9.6--1.0.0.sql @@ -0,0 +1 @@ +-- No actual SQL changes to this version bump diff --git a/sql/count_nulls--1.0.0.sql b/sql/count_nulls--1.0.0.sql new file mode 100644 index 0000000..ef7c3b5 --- /dev/null +++ b/sql/count_nulls--1.0.0.sql @@ -0,0 +1,87 @@ +/* DO NOT EDIT - AUTO-GENERATED FILE */ +CREATE OR REPLACE FUNCTION null_count( + VARIADIC argument anyarray +) RETURNS int LANGUAGE sql IMMUTABLE AS $body$ + SELECT sum( CASE WHEN a IS NULL THEN 1 ELSE 0 END )::int + FROM unnest( $1 ) a +$body$; + +CREATE OR REPLACE FUNCTION null_count( + argument jsonb +) RETURNS int LANGUAGE sql IMMUTABLE AS $body$ +SELECT count(*)::int + FROM jsonb_each_text( $1 ) a + WHERE value IS NULL +$body$; +CREATE OR REPLACE FUNCTION null_count( + argument json +) RETURNS int LANGUAGE sql IMMUTABLE AS 'SELECT @extschema@.null_count($1::jsonb)'; + +CREATE OR REPLACE FUNCTION null_count_trigger( +) RETURNS trigger LANGUAGE plpgsql IMMUTABLE AS $body$ +DECLARE + c_msg CONSTANT text := coalesce( + nullif( TG_ARGV[1], 'null' ) + , format( '%s must contain %s NULL fields', TG_RELID::regclass, TG_ARGV[0] ) + ); +BEGIN + IF TG_NARGS NOT BETWEEN 1 AND 2 THEN + RAISE '% usage: number of NULL columns[, error message]', TG_NAME; + END IF; + -- Casing intentional for cut/paste/replace/ + IF nullif(TG_ARGV[0], 'null') IS null THEN + RAISE '%: first argument must not be null', TG_NAME; + END IF; + + IF @extschema@.null_count( row_to_json(NEW) ) <> TG_ARGV[0]::int THEN + RAISE '%', c_msg; + END IF; + + RETURN NEW; +END +$body$; + + +CREATE OR REPLACE FUNCTION not_null_count( + VARIADIC argument anyarray +) RETURNS int LANGUAGE sql IMMUTABLE AS $body$ + SELECT sum( CASE WHEN a IS NOT NULL THEN 1 ELSE 0 END )::int + FROM unnest( $1 ) a +$body$; + +CREATE OR REPLACE FUNCTION not_null_count( + argument jsonb +) RETURNS int LANGUAGE sql IMMUTABLE AS $body$ +SELECT count(*)::int + FROM jsonb_each_text( $1 ) a + WHERE value IS NOT NULL +$body$; +CREATE OR REPLACE FUNCTION not_null_count( + argument json +) RETURNS int LANGUAGE sql IMMUTABLE AS 'SELECT @extschema@.not_null_count($1::jsonb)'; + +CREATE OR REPLACE FUNCTION not_null_count_trigger( +) RETURNS trigger LANGUAGE plpgsql IMMUTABLE AS $body$ +DECLARE + c_msg CONSTANT text := coalesce( + nullif( TG_ARGV[1], 'null' ) + , format( '%s must contain %s NOT NULL fields', TG_RELID::regclass, TG_ARGV[0] ) + ); +BEGIN + IF TG_NARGS NOT BETWEEN 1 AND 2 THEN + RAISE '% usage: number of NOT NULL columns[, error message]', TG_NAME; + END IF; + -- Casing intentional for cut/paste/replace/ + IF nullif(TG_ARGV[0], 'null') IS null THEN + RAISE '%: first argument must not be null', TG_NAME; + END IF; + + IF @extschema@.not_null_count( row_to_json(NEW) ) <> TG_ARGV[0]::int THEN + RAISE '%', c_msg; + END IF; + + RETURN NEW; +END +$body$; + +-- vi: expandtab sw=2 ts=2