Skip to content

Commit

Permalink
Merge pull request #5 from supabase/or/lint-no-primary-key
Browse files Browse the repository at this point in the history
Add lint for no primary key
  • Loading branch information
olirice authored Mar 5, 2024
2 parents 29d03df + 3cf7972 commit c5080d9
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 28 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ __pycache__/
*.py[cod]
*$py.class

# test artifacts
regression.diffs
regression.out

# C extensions
*.so

Expand Down
24 changes: 3 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,34 +43,16 @@ Detects if calls to auth.function() in RLS policies are being unnecessarily re-e
- Level: WARN
- Facing: EXTERNAL

## TODO Lints

The following are lints on the TODO list with a WIP associated query showing how to get at "some" of the data.

### tables_missing_primary_key
### 0004_no_primary_key

Detect tables without a primary key.

- Level: INFO
- Facing: EXTERNAL

## TODO Lints

```sql
SELECT n.nspname as schema_name,
c.relname as table_name
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND NOT EXISTS (
SELECT 1
FROM pg_catalog.pg_constraint con
WHERE con.conrelid = c.oid
AND con.contype = 'p'
)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast';
```
The following are lints on the TODO list with a WIP associated query showing how to get at "some" of the data.

### unused_indexes

Expand Down
2 changes: 1 addition & 1 deletion bin/installcheck
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ else
fi

# Execute the test fixtures
psql -v ON_ERROR_STOP= -f test/fixtures.sql -f lints/0001*.sql -f lints/0002*.sql -f lints/0003*.sql -d contrib_regression
psql -v ON_ERROR_STOP= -f test/fixtures.sql -f lints/0001*.sql -f lints/0002*.sql -f lints/0003*.sql -f lints/0004*.sql -d contrib_regression

# Run tests
${REGRESS} --use-existing --dbname=contrib_regression --inputdir=${TESTDIR} ${TESTS}
36 changes: 36 additions & 0 deletions lints/0004_no_primary_key.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
create view lint."0004_no_primary_key" as

select
'no_primary_key' as name,
'INFO' as level,
'EXTERNAL' as facing,
'Detects if a table does not have a primary key. Tables without a primary key can be inefficient to interact with at scale.' as description,
format(
'Table "%s.%s" does not have a primary key',
pgns.nspname,
pgc.relname
) as detail,
null as remediation,
null as metadata,
format(
'no_primary_key_%s_%s',
pgns.nspname,
pgc.relname
) as cache_key
from
pg_class pgc
join pg_namespace pgns
on pgns.oid = pgc.relnamespace
left join pg_index pgi
on pgi.indrelid = pgc.oid
where
pgc.relkind = 'r' -- regular tables
and pgns.nspname not in (
'pg_catalog', 'information_schema', 'auth', 'storage', 'vault', 'pgsodium'
)
group by
pgc.oid,
pgns.nspname,
pgc.relname
having
max(coalesce(pgi.indisprimary, false)::int) = 0;
23 changes: 23 additions & 0 deletions test/expected/0004_no_primary_key.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
begin;
-- No issues
select * from lint."0004_no_primary_key";
name | level | facing | description | detail | remediation | metadata | cache_key
------+-------+--------+-------------+--------+-------------+----------+-----------
(0 rows)

-- Table with a primary key
create table public.foo (
id int primary key
);
-- Table with a primary key
create table public.bar (
id int
);
-- Only the "bar" table is listed
select * from lint."0004_no_primary_key";
name | level | facing | description | detail | remediation | metadata | cache_key
----------------+-------+----------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+-------------+----------+---------------------------
no_primary_key | INFO | EXTERNAL | Detects if a table does not have a primary key. Tables without a primary key can be inefficient to interact with at scale. | Table "public.bar" does not have a primary key | | | no_primary_key_public_bar
(1 row)

rollback;
6 changes: 0 additions & 6 deletions test/expected/select_one.out

This file was deleted.

19 changes: 19 additions & 0 deletions test/sql/0004_no_primary_key.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
begin;

-- No issues
select * from lint."0004_no_primary_key";

-- Table with a primary key
create table public.foo (
id int primary key
);

-- Table with a primary key
create table public.bar (
id int
);

-- Only the "bar" table is listed
select * from lint."0004_no_primary_key";

rollback;

0 comments on commit c5080d9

Please sign in to comment.