Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ Revision history for pgTAP
and `hasnt_check()`. Also changed `has_unique()` argument types from `TEXT`
to `NAME` so they can share a consistent overload order with the other
constraint assertions. Thanks to @RampantDespair for the PR (#370).
* Added missing `schema, table, columns[]` and `schema, table, column` variants
of `col_isnt_pk()`, `col_is_fk()`, and `col_isnt_fk()`, and established a
consistent overload order for `col_is_pk()`, `col_isnt_pk()`, `col_is_fk()`,
`col_isnt_fk()`, and `col_is_unique()`. Added `col_isnt_unique()` with the
same consistent overload order. Standardized SQL function comments to use
plural `columns[]` for array arguments. Thanks to @RampantDespair for the PR
(#369).

1.3.4 2025-10-04T17:20:28Z
--------------------------
Expand Down
85 changes: 82 additions & 3 deletions doc/pgtap.md
Original file line number Diff line number Diff line change
Expand Up @@ -5231,6 +5231,14 @@ SELECT col_is_pk( 'myschema', 'sometable', 'id' );
SELECT col_is_pk( 'persons', ARRAY['given_name', 'surname'] );
```

For a 3-argument schema-qualified call without a description, use `NAME` or
`NAME[]` casts to distinguish it from the 3-argument
`(table, column(s), description)` overload. For example:

```sql
SELECT col_is_pk( 'myschema', 'sometable'::name, 'pk_name'::name );
```

If the schema is omitted, the table must be visible in the search path. If the
test description is omitted, it will be set to "Column `:table(:column)`
should be a primary key". Note that this test will fail if the table or column
Expand All @@ -5253,6 +5261,8 @@ Will produce something like this:
```sql
SELECT col_isnt_pk( :schema, :table, :columns, :description );
SELECT col_isnt_pk( :schema, :table, :column, :description );
SELECT col_isnt_pk( :schema, :table, :columns );
SELECT col_isnt_pk( :schema, :table, :column );
SELECT col_isnt_pk( :table, :columns, :description );
SELECT col_isnt_pk( :table, :column, :description );
SELECT col_isnt_pk( :table, :columns );
Expand All @@ -5279,11 +5289,21 @@ SELECT col_isnt_pk( :table, :column );
This function is the inverse of `col_is_pk()`. The test passes if the
specified column or columns are not a primary key.

For a 3-argument schema-qualified call without a description, use `NAME` or
`NAME[]` casts to distinguish it from the 3-argument
`(table, column(s), description)` overload. For example:

```sql
SELECT col_isnt_pk( 'myschema', 'sometable'::name, 'pk_name'::name );
```

### `col_is_fk()` ###

```sql
SELECT col_is_fk( :schema, :table, :columns, :description );
SELECT col_is_fk( :schema, :table, :column, :description );
SELECT col_is_fk( :schema, :table, :columns );
SELECT col_is_fk( :schema, :table, :column );
SELECT col_is_fk( :table, :columns, :description );
SELECT col_is_fk( :table, :column, :description );
SELECT col_is_fk( :table, :columns );
Expand Down Expand Up @@ -5316,11 +5336,21 @@ simply list all of the foreign key constraint columns, like so:
# {thingy_id}
# {surname,given_name}

For a 3-argument schema-qualified call without a description, use `NAME` or
`NAME[]` casts to distinguish it from the 3-argument
`(table, column(s), description)` overload. For example:

```sql
SELECT col_is_fk( 'myschema', 'sometable'::name, 'fk_name'::name );
```

### `col_isnt_fk()` ###

```sql
SELECT col_isnt_fk( :schema, :table, :columns, :description );
SELECT col_isnt_fk( :schema, :table, :column, :description );
SELECT col_isnt_fk( :schema, :table, :columns );
SELECT col_isnt_fk( :schema, :table, :column );
SELECT col_isnt_fk( :table, :columns, :description );
SELECT col_isnt_fk( :table, :column, :description );
SELECT col_isnt_fk( :table, :columns );
Expand All @@ -5347,6 +5377,14 @@ SELECT col_isnt_fk( :table, :column );
This function is the inverse of `col_is_fk()`. The test passes if the
specified column or columns are not a foreign key.

For a 3-argument schema-qualified call without a description, use `NAME` or
`NAME[]` casts to distinguish it from the 3-argument
`(table, column(s), description)` overload. For example:

```sql
SELECT col_isnt_fk( 'myschema', 'sometable'::name, 'fk_name'::name );
```

### `fk_ok()` ###

```sql
Expand Down Expand Up @@ -5531,9 +5569,9 @@ SELECT col_is_unique(
);
```

If you omit the description for the 3-argument version, you'll need to cast
the table and column parameters to the `NAME` data type so that PostgreSQL
doesn't resolve the function name as a description. For example:
For a 3-argument schema-qualified call without a description, use `NAME` or
`NAME[]` casts to distinguish it from the 3-argument
`(table, column(s), description)` overload. For example:

```sql
SELECT col_is_unique( 'myschema', 'sometable'::name, 'other_id'::name );
Expand All @@ -5547,6 +5585,47 @@ were actually found, if any:
{first_name,last_name}
want: {email}

### `col_isnt_unique()` ###

```sql
SELECT col_isnt_unique( schema, table, columns, description );
SELECT col_isnt_unique( schema, table, column, description );
SELECT col_isnt_unique( schema, table, columns );
SELECT col_isnt_unique( schema, table, column );
SELECT col_isnt_unique( table, columns, description );
SELECT col_isnt_unique( table, column, description );
SELECT col_isnt_unique( table, columns );
SELECT col_isnt_unique( table, column );
```

**Parameters**

`:schema`
: Schema in which to find the table.

`:table`
: Name of a table not containing the unique constraint.

`:columns`
: Array of the names of the columns that should not have a unique constraint.

`:column`
: Name of the column that should not have a unique constraint.

`:description`
: A short description of the test.

This function is the inverse of `col_is_unique()`. The test passes if the
specified column or columns do not have a unique constraint.

For a 3-argument schema-qualified call without a description, use `NAME` or
`NAME[]` casts to distinguish it from the 3-argument
`(table, column(s), description)` overload. For example:

```sql
SELECT col_isnt_unique( 'myschema', 'sometable'::name, 'other_id'::name );
```

### `has_check()` ###

```sql
Expand Down
2 changes: 1 addition & 1 deletion sql/pgtap--0.92.0--0.93.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ BEGIN
END;
$$ LANGUAGE plpgsql;

-- fk_ok( fk_table, fk_column[], pk_table, pk_column[], description )
-- fk_ok( fk_table, fk_columns[], pk_table, pk_columns[], description )
CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME[], NAME, NAME[], TEXT )
RETURNS TEXT AS $$
DECLARE
Expand Down
2 changes: 1 addition & 1 deletion sql/pgtap--0.94.0--0.95.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ RETURNS TEXT AS $$
SELECT ok( NOT _strict($1), 'Function ' || quote_ident($1) || '() should not be strict' );
$$ LANGUAGE sql;

-- col_is_unique( schema, table, column[] )
-- col_is_unique( schema, table, columns[] )
CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_is_unique( $1, $2, $3, 'Columns ' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should have a unique constraint' );
Expand Down
2 changes: 1 addition & 1 deletion sql/pgtap--1.2.0--1.3.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ BEGIN
END;
$$ LANGUAGE plpgsql;

-- col_is_pk( schema, table, column[] )
-- col_is_pk( schema, table, columns[] )
CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_is_pk( $1, $2, $3, 'Columns ' || quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should be a primary key' );
Expand Down
98 changes: 98 additions & 0 deletions sql/pgtap--1.3.4--1.3.5.sql
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,101 @@ CREATE OR REPLACE FUNCTION hasnt_check ( NAME )
RETURNS TEXT AS $$
SELECT hasnt_check( $1, 'Table ' || quote_ident($1) || ' should not have a check constraint' );
$$ LANGUAGE sql;

-- col_isnt_pk( schema, table, columns[] )
CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_isnt_pk( $1, $2, $3, 'Columns ' || quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should not be a primary key' );
$$ LANGUAGE sql;

-- col_isnt_pk( schema, table, column )
CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME, NAME )
RETURNS TEXT AS $$
SELECT col_isnt_pk( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '(' || quote_ident($3) || ') should not be a primary key' );
$$ LANGUAGE sql;

-- col_is_fk( schema, table, columns[] )
CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_is_fk( $1, $2, $3, 'Columns ' || quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should be a foreign key' );
$$ LANGUAGE sql;

-- col_is_fk( schema, table, column )
CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME, NAME )
RETURNS TEXT AS $$
SELECT col_is_fk( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '(' || quote_ident($3) || ') should be a foreign key' );
$$ LANGUAGE sql;

-- col_isnt_fk( schema, table, columns[] )
CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_isnt_fk( $1, $2, $3, 'Columns ' || quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should not be a foreign key' );
$$ LANGUAGE sql;

-- col_isnt_fk( schema, table, column )
CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME, NAME )
RETURNS TEXT AS $$
SELECT col_isnt_fk( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '(' || quote_ident($3) || ') should not be a foreign key' );
$$ LANGUAGE sql;

-- col_isnt_unique( schema, table, columns[], description )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME, NAME[], TEXT )
RETURNS TEXT AS $$
SELECT ok(
NOT EXISTS (
SELECT 1
FROM _keys($1, $2, 'u') AS keys(key_columns)
WHERE key_columns = $3
),
$4
);
$$ LANGUAGE sql;

-- col_isnt_unique( schema, table, column, description )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME, NAME, TEXT )
RETURNS TEXT AS $$
SELECT col_isnt_unique( $1, $2, ARRAY[$3], $4 );
$$ LANGUAGE sql;

-- col_isnt_unique( schema, table, columns[] )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_isnt_unique( $1, $2, $3, 'Columns ' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should not have a unique constraint' );
$$ LANGUAGE sql;

-- col_isnt_unique( schema, table, column )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME, NAME )
RETURNS TEXT AS $$
SELECT col_isnt_unique( $1, $2, ARRAY[$3], 'Column ' || quote_ident($2) || '(' || quote_ident($3) || ') should not have a unique constraint' );
$$ LANGUAGE sql;

-- col_isnt_unique( table, columns[], description )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME[], TEXT )
RETURNS TEXT AS $$
SELECT ok(
NOT EXISTS (
SELECT 1
FROM _keys($1, 'u') AS keys(key_columns)
WHERE key_columns = $2
),
$3
);
$$ LANGUAGE sql;

-- col_isnt_unique( table, column, description )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME, TEXT )
RETURNS TEXT AS $$
SELECT col_isnt_unique( $1, ARRAY[$2], $3 );
$$ LANGUAGE sql;

-- col_isnt_unique( table, columns[] )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME[] )
RETURNS TEXT AS $$
SELECT col_isnt_unique( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should not have a unique constraint' );
$$ LANGUAGE sql;

-- col_isnt_unique( table, column )
CREATE OR REPLACE FUNCTION col_isnt_unique ( NAME, NAME )
RETURNS TEXT AS $$
SELECT col_isnt_unique( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should not have a unique constraint' );
$$ LANGUAGE sql;
Loading