jorgex-stack 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRD.md +310 -297
- package/README.md +68 -56
- package/dist/cli.js +37 -3
- package/package.json +1 -1
- package/stack/agents/code-simplifier.md +21 -10
- package/stack/agents/implementer.md +1 -0
- package/stack/agents/orchestrator.md +194 -192
- package/stack/agents/security-auditor.md +7 -0
- package/stack/agents/silent-failure-hunter.md +7 -0
- package/stack/agents/test-analyzer.md +7 -0
- package/stack/agents/tester.md +71 -71
- package/stack/agents/type-design-analyzer.md +1 -1
- package/stack/commands/lean-audit.md +59 -0
- package/stack/commands/xreview.md +82 -80
- package/stack/hooks/hooks.json +18 -18
- package/stack/scripts/post-pr-review.cjs +159 -156
- package/stack/skills/diagnose/SKILL.md +117 -117
- package/stack/skills/diagnose/scripts/hitl-loop.template.sh +41 -41
- package/stack/skills/find-skills/SKILL.md +133 -133
- package/stack/skills/lean-code/SKILL.md +69 -0
- package/stack/skills/mcp-builder/LICENSE.txt +201 -201
- package/stack/skills/mcp-builder/SKILL.md +236 -236
- package/stack/skills/mcp-builder/reference/evaluation.md +601 -601
- package/stack/skills/mcp-builder/reference/mcp_best_practices.md +249 -249
- package/stack/skills/mcp-builder/reference/node_mcp_server.md +969 -969
- package/stack/skills/mcp-builder/reference/python_mcp_server.md +718 -718
- package/stack/skills/mcp-builder/scripts/connections.py +151 -151
- package/stack/skills/mcp-builder/scripts/evaluation.py +373 -373
- package/stack/skills/mcp-builder/scripts/example_evaluation.xml +22 -22
- package/stack/skills/mcp-builder/scripts/requirements.txt +2 -2
- package/stack/skills/obsidian-cli/SKILL.md +106 -106
- package/stack/skills/obsidian-markdown/SKILL.md +196 -196
- package/stack/skills/obsidian-markdown/references/CALLOUTS.md +58 -58
- package/stack/skills/obsidian-markdown/references/EMBEDS.md +63 -63
- package/stack/skills/obsidian-markdown/references/PROPERTIES.md +61 -61
- package/stack/skills/react-doctor/SKILL.md +19 -19
- package/stack/skills/skill-creator/LICENSE.txt +201 -201
- package/stack/skills/skill-creator/agents/analyzer.md +274 -274
- package/stack/skills/skill-creator/agents/comparator.md +202 -202
- package/stack/skills/skill-creator/agents/grader.md +223 -223
- package/stack/skills/skill-creator/assets/eval_review.html +146 -146
- package/stack/skills/skill-creator/eval-viewer/generate_review.py +471 -471
- package/stack/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
- package/stack/skills/skill-creator/references/schemas.md +430 -430
- package/stack/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
- package/stack/skills/skill-creator/scripts/generate_report.py +326 -326
- package/stack/skills/skill-creator/scripts/improve_description.py +248 -248
- package/stack/skills/skill-creator/scripts/package_skill.py +136 -136
- package/stack/skills/skill-creator/scripts/quick_validate.py +102 -102
- package/stack/skills/skill-creator/scripts/run_eval.py +310 -310
- package/stack/skills/skill-creator/scripts/run_loop.py +332 -332
- package/stack/skills/skill-creator/scripts/utils.py +47 -47
- package/stack/skills/supabase/SKILL.md +135 -135
- package/stack/skills/supabase/assets/feedback-issue-template.md +17 -17
- package/stack/skills/supabase/references/skill-feedback.md +17 -17
- package/stack/skills/supabase-postgres-best-practices/SKILL.md +64 -64
- package/stack/skills/supabase-postgres-best-practices/references/_contributing.md +170 -170
- package/stack/skills/supabase-postgres-best-practices/references/_sections.md +39 -39
- package/stack/skills/supabase-postgres-best-practices/references/_template.md +34 -34
- package/stack/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -55
- package/stack/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -49
- package/stack/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -46
- package/stack/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -44
- package/stack/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -41
- package/stack/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -46
- package/stack/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -54
- package/stack/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -53
- package/stack/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -50
- package/stack/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -50
- package/stack/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -56
- package/stack/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -68
- package/stack/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -50
- package/stack/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -54
- package/stack/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -45
- package/stack/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -55
- package/stack/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -55
- package/stack/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -44
- package/stack/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -40
- package/stack/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -48
- package/stack/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -43
- package/stack/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -45
- package/stack/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -80
- package/stack/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -46
- package/stack/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -59
- package/stack/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -55
- package/stack/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -55
- package/stack/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -61
- package/stack/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -54
- package/stack/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -50
- package/stack/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -63
- package/stack/skills/tdd/SKILL.md +109 -109
- package/stack/skills/tdd/deep-modules.md +33 -33
- package/stack/skills/tdd/interface-design.md +31 -31
- package/stack/skills/tdd/mocking.md +59 -59
- package/stack/skills/tdd/refactoring.md +10 -10
- package/stack/skills/tdd/tests.md +61 -61
- package/stack/skills/to-issues/SKILL.md +83 -83
- package/stack/skills/to-prd/SKILL.md +72 -72
- package/upstreams.json +96 -96
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Use Partial Indexes for Filtered Queries
|
|
3
|
-
impact: HIGH
|
|
4
|
-
impactDescription: 5-20x smaller indexes, faster writes and queries
|
|
5
|
-
tags: indexes, partial-index, query-optimization, storage
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Use Partial Indexes for Filtered Queries
|
|
9
|
-
|
|
10
|
-
Partial indexes only include rows matching a WHERE condition, making them smaller and faster when queries consistently filter on the same condition.
|
|
11
|
-
|
|
12
|
-
**Incorrect (full index includes irrelevant rows):**
|
|
13
|
-
|
|
14
|
-
```sql
|
|
15
|
-
-- Index includes all rows, even soft-deleted ones
|
|
16
|
-
create index users_email_idx on users (email);
|
|
17
|
-
|
|
18
|
-
-- Query always filters active users
|
|
19
|
-
select * from users where email = 'user@example.com' and deleted_at is null;
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Correct (partial index matches query filter):**
|
|
23
|
-
|
|
24
|
-
```sql
|
|
25
|
-
-- Index only includes active users
|
|
26
|
-
create index users_active_email_idx on users (email)
|
|
27
|
-
where deleted_at is null;
|
|
28
|
-
|
|
29
|
-
-- Query uses the smaller, faster index
|
|
30
|
-
select * from users where email = 'user@example.com' and deleted_at is null;
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Common use cases for partial indexes:
|
|
34
|
-
|
|
35
|
-
```sql
|
|
36
|
-
-- Only pending orders (status rarely changes once completed)
|
|
37
|
-
create index orders_pending_idx on orders (created_at)
|
|
38
|
-
where status = 'pending';
|
|
39
|
-
|
|
40
|
-
-- Only non-null values
|
|
41
|
-
create index products_sku_idx on products (sku)
|
|
42
|
-
where sku is not null;
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Reference: [Partial Indexes](https://www.postgresql.org/docs/current/indexes-partial.html)
|
|
1
|
+
---
|
|
2
|
+
title: Use Partial Indexes for Filtered Queries
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: 5-20x smaller indexes, faster writes and queries
|
|
5
|
+
tags: indexes, partial-index, query-optimization, storage
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Partial Indexes for Filtered Queries
|
|
9
|
+
|
|
10
|
+
Partial indexes only include rows matching a WHERE condition, making them smaller and faster when queries consistently filter on the same condition.
|
|
11
|
+
|
|
12
|
+
**Incorrect (full index includes irrelevant rows):**
|
|
13
|
+
|
|
14
|
+
```sql
|
|
15
|
+
-- Index includes all rows, even soft-deleted ones
|
|
16
|
+
create index users_email_idx on users (email);
|
|
17
|
+
|
|
18
|
+
-- Query always filters active users
|
|
19
|
+
select * from users where email = 'user@example.com' and deleted_at is null;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (partial index matches query filter):**
|
|
23
|
+
|
|
24
|
+
```sql
|
|
25
|
+
-- Index only includes active users
|
|
26
|
+
create index users_active_email_idx on users (email)
|
|
27
|
+
where deleted_at is null;
|
|
28
|
+
|
|
29
|
+
-- Query uses the smaller, faster index
|
|
30
|
+
select * from users where email = 'user@example.com' and deleted_at is null;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Common use cases for partial indexes:
|
|
34
|
+
|
|
35
|
+
```sql
|
|
36
|
+
-- Only pending orders (status rarely changes once completed)
|
|
37
|
+
create index orders_pending_idx on orders (created_at)
|
|
38
|
+
where status = 'pending';
|
|
39
|
+
|
|
40
|
+
-- Only non-null values
|
|
41
|
+
create index products_sku_idx on products (sku)
|
|
42
|
+
where sku is not null;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Reference: [Partial Indexes](https://www.postgresql.org/docs/current/indexes-partial.html)
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Add Constraints Safely in Migrations
|
|
3
|
-
impact: HIGH
|
|
4
|
-
impactDescription: Prevents migration failures and enables idempotent schema changes
|
|
5
|
-
tags: constraints, migrations, schema, alter-table
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Add Constraints Safely in Migrations
|
|
9
|
-
|
|
10
|
-
PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail.
|
|
11
|
-
|
|
12
|
-
**Incorrect (causes syntax error):**
|
|
13
|
-
|
|
14
|
-
```sql
|
|
15
|
-
-- ERROR: syntax error at or near "not" (SQLSTATE 42601)
|
|
16
|
-
alter table public.profiles
|
|
17
|
-
add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id);
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Correct (idempotent constraint creation):**
|
|
21
|
-
|
|
22
|
-
```sql
|
|
23
|
-
-- Use DO block to check before adding
|
|
24
|
-
do $$
|
|
25
|
-
begin
|
|
26
|
-
if not exists (
|
|
27
|
-
select 1 from pg_constraint
|
|
28
|
-
where conname = 'profiles_birthchart_id_unique'
|
|
29
|
-
and conrelid = 'public.profiles'::regclass
|
|
30
|
-
) then
|
|
31
|
-
alter table public.profiles
|
|
32
|
-
add constraint profiles_birthchart_id_unique unique (birthchart_id);
|
|
33
|
-
end if;
|
|
34
|
-
end $$;
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
For all constraint types:
|
|
38
|
-
|
|
39
|
-
```sql
|
|
40
|
-
-- Check constraints
|
|
41
|
-
do $$
|
|
42
|
-
begin
|
|
43
|
-
if not exists (
|
|
44
|
-
select 1 from pg_constraint
|
|
45
|
-
where conname = 'check_age_positive'
|
|
46
|
-
) then
|
|
47
|
-
alter table users add constraint check_age_positive check (age > 0);
|
|
48
|
-
end if;
|
|
49
|
-
end $$;
|
|
50
|
-
|
|
51
|
-
-- Foreign keys
|
|
52
|
-
do $$
|
|
53
|
-
begin
|
|
54
|
-
if not exists (
|
|
55
|
-
select 1 from pg_constraint
|
|
56
|
-
where conname = 'profiles_birthchart_id_fkey'
|
|
57
|
-
) then
|
|
58
|
-
alter table profiles
|
|
59
|
-
add constraint profiles_birthchart_id_fkey
|
|
60
|
-
foreign key (birthchart_id) references birthcharts(id);
|
|
61
|
-
end if;
|
|
62
|
-
end $$;
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Check if constraint exists:
|
|
66
|
-
|
|
67
|
-
```sql
|
|
68
|
-
-- Query to check constraint existence
|
|
69
|
-
select conname, contype, pg_get_constraintdef(oid)
|
|
70
|
-
from pg_constraint
|
|
71
|
-
where conrelid = 'public.profiles'::regclass;
|
|
72
|
-
|
|
73
|
-
-- contype values:
|
|
74
|
-
-- 'p' = PRIMARY KEY
|
|
75
|
-
-- 'f' = FOREIGN KEY
|
|
76
|
-
-- 'u' = UNIQUE
|
|
77
|
-
-- 'c' = CHECK
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)
|
|
1
|
+
---
|
|
2
|
+
title: Add Constraints Safely in Migrations
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevents migration failures and enables idempotent schema changes
|
|
5
|
+
tags: constraints, migrations, schema, alter-table
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Add Constraints Safely in Migrations
|
|
9
|
+
|
|
10
|
+
PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail.
|
|
11
|
+
|
|
12
|
+
**Incorrect (causes syntax error):**
|
|
13
|
+
|
|
14
|
+
```sql
|
|
15
|
+
-- ERROR: syntax error at or near "not" (SQLSTATE 42601)
|
|
16
|
+
alter table public.profiles
|
|
17
|
+
add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (idempotent constraint creation):**
|
|
21
|
+
|
|
22
|
+
```sql
|
|
23
|
+
-- Use DO block to check before adding
|
|
24
|
+
do $$
|
|
25
|
+
begin
|
|
26
|
+
if not exists (
|
|
27
|
+
select 1 from pg_constraint
|
|
28
|
+
where conname = 'profiles_birthchart_id_unique'
|
|
29
|
+
and conrelid = 'public.profiles'::regclass
|
|
30
|
+
) then
|
|
31
|
+
alter table public.profiles
|
|
32
|
+
add constraint profiles_birthchart_id_unique unique (birthchart_id);
|
|
33
|
+
end if;
|
|
34
|
+
end $$;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For all constraint types:
|
|
38
|
+
|
|
39
|
+
```sql
|
|
40
|
+
-- Check constraints
|
|
41
|
+
do $$
|
|
42
|
+
begin
|
|
43
|
+
if not exists (
|
|
44
|
+
select 1 from pg_constraint
|
|
45
|
+
where conname = 'check_age_positive'
|
|
46
|
+
) then
|
|
47
|
+
alter table users add constraint check_age_positive check (age > 0);
|
|
48
|
+
end if;
|
|
49
|
+
end $$;
|
|
50
|
+
|
|
51
|
+
-- Foreign keys
|
|
52
|
+
do $$
|
|
53
|
+
begin
|
|
54
|
+
if not exists (
|
|
55
|
+
select 1 from pg_constraint
|
|
56
|
+
where conname = 'profiles_birthchart_id_fkey'
|
|
57
|
+
) then
|
|
58
|
+
alter table profiles
|
|
59
|
+
add constraint profiles_birthchart_id_fkey
|
|
60
|
+
foreign key (birthchart_id) references birthcharts(id);
|
|
61
|
+
end if;
|
|
62
|
+
end $$;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Check if constraint exists:
|
|
66
|
+
|
|
67
|
+
```sql
|
|
68
|
+
-- Query to check constraint existence
|
|
69
|
+
select conname, contype, pg_get_constraintdef(oid)
|
|
70
|
+
from pg_constraint
|
|
71
|
+
where conrelid = 'public.profiles'::regclass;
|
|
72
|
+
|
|
73
|
+
-- contype values:
|
|
74
|
+
-- 'p' = PRIMARY KEY
|
|
75
|
+
-- 'f' = FOREIGN KEY
|
|
76
|
+
-- 'u' = UNIQUE
|
|
77
|
+
-- 'c' = CHECK
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Choose Appropriate Data Types
|
|
3
|
-
impact: HIGH
|
|
4
|
-
impactDescription: 50% storage reduction, faster comparisons
|
|
5
|
-
tags: data-types, schema, storage, performance
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Choose Appropriate Data Types
|
|
9
|
-
|
|
10
|
-
Using the right data types reduces storage, improves query performance, and prevents bugs.
|
|
11
|
-
|
|
12
|
-
**Incorrect (wrong data types):**
|
|
13
|
-
|
|
14
|
-
```sql
|
|
15
|
-
create table users (
|
|
16
|
-
id int, -- Will overflow at 2.1 billion
|
|
17
|
-
email varchar(255), -- Unnecessary length limit
|
|
18
|
-
created_at timestamp, -- Missing timezone info
|
|
19
|
-
is_active varchar(5), -- String for boolean
|
|
20
|
-
price varchar(20) -- String for numeric
|
|
21
|
-
);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
**Correct (appropriate data types):**
|
|
25
|
-
|
|
26
|
-
```sql
|
|
27
|
-
create table users (
|
|
28
|
-
id bigint generated always as identity primary key, -- 9 quintillion max
|
|
29
|
-
email text, -- No artificial limit, same performance as varchar
|
|
30
|
-
created_at timestamptz, -- Always store timezone-aware timestamps
|
|
31
|
-
is_active boolean default true, -- 1 byte vs variable string length
|
|
32
|
-
price numeric(10,2) -- Exact decimal arithmetic
|
|
33
|
-
);
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Key guidelines:
|
|
37
|
-
|
|
38
|
-
```sql
|
|
39
|
-
-- IDs: use bigint, not int (future-proofing)
|
|
40
|
-
-- Strings: use text, not varchar(n) unless constraint needed
|
|
41
|
-
-- Time: use timestamptz, not timestamp
|
|
42
|
-
-- Money: use numeric, not float (precision matters)
|
|
43
|
-
-- Enums: use text with check constraint or create enum type
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Reference: [Data Types](https://www.postgresql.org/docs/current/datatype.html)
|
|
1
|
+
---
|
|
2
|
+
title: Choose Appropriate Data Types
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: 50% storage reduction, faster comparisons
|
|
5
|
+
tags: data-types, schema, storage, performance
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Choose Appropriate Data Types
|
|
9
|
+
|
|
10
|
+
Using the right data types reduces storage, improves query performance, and prevents bugs.
|
|
11
|
+
|
|
12
|
+
**Incorrect (wrong data types):**
|
|
13
|
+
|
|
14
|
+
```sql
|
|
15
|
+
create table users (
|
|
16
|
+
id int, -- Will overflow at 2.1 billion
|
|
17
|
+
email varchar(255), -- Unnecessary length limit
|
|
18
|
+
created_at timestamp, -- Missing timezone info
|
|
19
|
+
is_active varchar(5), -- String for boolean
|
|
20
|
+
price varchar(20) -- String for numeric
|
|
21
|
+
);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (appropriate data types):**
|
|
25
|
+
|
|
26
|
+
```sql
|
|
27
|
+
create table users (
|
|
28
|
+
id bigint generated always as identity primary key, -- 9 quintillion max
|
|
29
|
+
email text, -- No artificial limit, same performance as varchar
|
|
30
|
+
created_at timestamptz, -- Always store timezone-aware timestamps
|
|
31
|
+
is_active boolean default true, -- 1 byte vs variable string length
|
|
32
|
+
price numeric(10,2) -- Exact decimal arithmetic
|
|
33
|
+
);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Key guidelines:
|
|
37
|
+
|
|
38
|
+
```sql
|
|
39
|
+
-- IDs: use bigint, not int (future-proofing)
|
|
40
|
+
-- Strings: use text, not varchar(n) unless constraint needed
|
|
41
|
+
-- Time: use timestamptz, not timestamp
|
|
42
|
+
-- Money: use numeric, not float (precision matters)
|
|
43
|
+
-- Enums: use text with check constraint or create enum type
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Reference: [Data Types](https://www.postgresql.org/docs/current/datatype.html)
|
package/stack/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Index Foreign Key Columns
|
|
3
|
-
impact: HIGH
|
|
4
|
-
impactDescription: 10-100x faster JOINs and CASCADE operations
|
|
5
|
-
tags: foreign-key, indexes, joins, schema
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Index Foreign Key Columns
|
|
9
|
-
|
|
10
|
-
Postgres does not automatically index foreign key columns. Missing indexes cause slow JOINs and CASCADE operations.
|
|
11
|
-
|
|
12
|
-
**Incorrect (unindexed foreign key):**
|
|
13
|
-
|
|
14
|
-
```sql
|
|
15
|
-
create table orders (
|
|
16
|
-
id bigint generated always as identity primary key,
|
|
17
|
-
customer_id bigint references customers(id) on delete cascade,
|
|
18
|
-
total numeric(10,2)
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
-- No index on customer_id!
|
|
22
|
-
-- JOINs and ON DELETE CASCADE both require full table scan
|
|
23
|
-
select * from orders where customer_id = 123; -- Seq Scan
|
|
24
|
-
delete from customers where id = 123; -- Locks table, scans all orders
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**Correct (indexed foreign key):**
|
|
28
|
-
|
|
29
|
-
```sql
|
|
30
|
-
create table orders (
|
|
31
|
-
id bigint generated always as identity primary key,
|
|
32
|
-
customer_id bigint references customers(id) on delete cascade,
|
|
33
|
-
total numeric(10,2)
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
-- Always index the FK column
|
|
37
|
-
create index orders_customer_id_idx on orders (customer_id);
|
|
38
|
-
|
|
39
|
-
-- Now JOINs and cascades are fast
|
|
40
|
-
select * from orders where customer_id = 123; -- Index Scan
|
|
41
|
-
delete from customers where id = 123; -- Uses index, fast cascade
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Find missing FK indexes:
|
|
45
|
-
|
|
46
|
-
```sql
|
|
47
|
-
select
|
|
48
|
-
conrelid::regclass as table_name,
|
|
49
|
-
a.attname as fk_column
|
|
50
|
-
from pg_constraint c
|
|
51
|
-
join pg_attribute a on a.attrelid = c.conrelid and a.attnum = any(c.conkey)
|
|
52
|
-
where c.contype = 'f'
|
|
53
|
-
and not exists (
|
|
54
|
-
select 1 from pg_index i
|
|
55
|
-
where i.indrelid = c.conrelid and a.attnum = any(i.indkey)
|
|
56
|
-
);
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Reference: [Foreign Keys](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK)
|
|
1
|
+
---
|
|
2
|
+
title: Index Foreign Key Columns
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: 10-100x faster JOINs and CASCADE operations
|
|
5
|
+
tags: foreign-key, indexes, joins, schema
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Index Foreign Key Columns
|
|
9
|
+
|
|
10
|
+
Postgres does not automatically index foreign key columns. Missing indexes cause slow JOINs and CASCADE operations.
|
|
11
|
+
|
|
12
|
+
**Incorrect (unindexed foreign key):**
|
|
13
|
+
|
|
14
|
+
```sql
|
|
15
|
+
create table orders (
|
|
16
|
+
id bigint generated always as identity primary key,
|
|
17
|
+
customer_id bigint references customers(id) on delete cascade,
|
|
18
|
+
total numeric(10,2)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- No index on customer_id!
|
|
22
|
+
-- JOINs and ON DELETE CASCADE both require full table scan
|
|
23
|
+
select * from orders where customer_id = 123; -- Seq Scan
|
|
24
|
+
delete from customers where id = 123; -- Locks table, scans all orders
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Correct (indexed foreign key):**
|
|
28
|
+
|
|
29
|
+
```sql
|
|
30
|
+
create table orders (
|
|
31
|
+
id bigint generated always as identity primary key,
|
|
32
|
+
customer_id bigint references customers(id) on delete cascade,
|
|
33
|
+
total numeric(10,2)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
-- Always index the FK column
|
|
37
|
+
create index orders_customer_id_idx on orders (customer_id);
|
|
38
|
+
|
|
39
|
+
-- Now JOINs and cascades are fast
|
|
40
|
+
select * from orders where customer_id = 123; -- Index Scan
|
|
41
|
+
delete from customers where id = 123; -- Uses index, fast cascade
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Find missing FK indexes:
|
|
45
|
+
|
|
46
|
+
```sql
|
|
47
|
+
select
|
|
48
|
+
conrelid::regclass as table_name,
|
|
49
|
+
a.attname as fk_column
|
|
50
|
+
from pg_constraint c
|
|
51
|
+
join pg_attribute a on a.attrelid = c.conrelid and a.attnum = any(c.conkey)
|
|
52
|
+
where c.contype = 'f'
|
|
53
|
+
and not exists (
|
|
54
|
+
select 1 from pg_index i
|
|
55
|
+
where i.indrelid = c.conrelid and a.attnum = any(i.indkey)
|
|
56
|
+
);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Reference: [Foreign Keys](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK)
|
package/stack/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Use Lowercase Identifiers for Compatibility
|
|
3
|
-
impact: MEDIUM
|
|
4
|
-
impactDescription: Avoid case-sensitivity bugs with tools, ORMs, and AI assistants
|
|
5
|
-
tags: naming, identifiers, case-sensitivity, schema, conventions
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Use Lowercase Identifiers for Compatibility
|
|
9
|
-
|
|
10
|
-
PostgreSQL folds unquoted identifiers to lowercase. Quoted mixed-case identifiers require quotes forever and cause issues with tools, ORMs, and AI assistants that may not recognize them.
|
|
11
|
-
|
|
12
|
-
**Incorrect (mixed-case identifiers):**
|
|
13
|
-
|
|
14
|
-
```sql
|
|
15
|
-
-- Quoted identifiers preserve case but require quotes everywhere
|
|
16
|
-
CREATE TABLE "Users" (
|
|
17
|
-
"userId" bigint PRIMARY KEY,
|
|
18
|
-
"firstName" text,
|
|
19
|
-
"lastName" text
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
-- Must always quote or queries fail
|
|
23
|
-
SELECT "firstName" FROM "Users" WHERE "userId" = 1;
|
|
24
|
-
|
|
25
|
-
-- This fails - Users becomes users without quotes
|
|
26
|
-
SELECT firstName FROM Users;
|
|
27
|
-
-- ERROR: relation "users" does not exist
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Correct (lowercase snake_case):**
|
|
31
|
-
|
|
32
|
-
```sql
|
|
33
|
-
-- Unquoted lowercase identifiers are portable and tool-friendly
|
|
34
|
-
CREATE TABLE users (
|
|
35
|
-
user_id bigint PRIMARY KEY,
|
|
36
|
-
first_name text,
|
|
37
|
-
last_name text
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
-- Works without quotes, recognized by all tools
|
|
41
|
-
SELECT first_name FROM users WHERE user_id = 1;
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Common sources of mixed-case identifiers:
|
|
45
|
-
|
|
46
|
-
```sql
|
|
47
|
-
-- ORMs often generate quoted camelCase - configure them to use snake_case
|
|
48
|
-
-- Migrations from other databases may preserve original casing
|
|
49
|
-
-- Some GUI tools quote identifiers by default - disable this
|
|
50
|
-
|
|
51
|
-
-- If stuck with mixed-case, create views as a compatibility layer
|
|
52
|
-
CREATE VIEW users AS SELECT "userId" AS user_id, "firstName" AS first_name FROM "Users";
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Reference: [Identifiers and Key Words](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)
|
|
1
|
+
---
|
|
2
|
+
title: Use Lowercase Identifiers for Compatibility
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Avoid case-sensitivity bugs with tools, ORMs, and AI assistants
|
|
5
|
+
tags: naming, identifiers, case-sensitivity, schema, conventions
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Lowercase Identifiers for Compatibility
|
|
9
|
+
|
|
10
|
+
PostgreSQL folds unquoted identifiers to lowercase. Quoted mixed-case identifiers require quotes forever and cause issues with tools, ORMs, and AI assistants that may not recognize them.
|
|
11
|
+
|
|
12
|
+
**Incorrect (mixed-case identifiers):**
|
|
13
|
+
|
|
14
|
+
```sql
|
|
15
|
+
-- Quoted identifiers preserve case but require quotes everywhere
|
|
16
|
+
CREATE TABLE "Users" (
|
|
17
|
+
"userId" bigint PRIMARY KEY,
|
|
18
|
+
"firstName" text,
|
|
19
|
+
"lastName" text
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- Must always quote or queries fail
|
|
23
|
+
SELECT "firstName" FROM "Users" WHERE "userId" = 1;
|
|
24
|
+
|
|
25
|
+
-- This fails - Users becomes users without quotes
|
|
26
|
+
SELECT firstName FROM Users;
|
|
27
|
+
-- ERROR: relation "users" does not exist
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Correct (lowercase snake_case):**
|
|
31
|
+
|
|
32
|
+
```sql
|
|
33
|
+
-- Unquoted lowercase identifiers are portable and tool-friendly
|
|
34
|
+
CREATE TABLE users (
|
|
35
|
+
user_id bigint PRIMARY KEY,
|
|
36
|
+
first_name text,
|
|
37
|
+
last_name text
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
-- Works without quotes, recognized by all tools
|
|
41
|
+
SELECT first_name FROM users WHERE user_id = 1;
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Common sources of mixed-case identifiers:
|
|
45
|
+
|
|
46
|
+
```sql
|
|
47
|
+
-- ORMs often generate quoted camelCase - configure them to use snake_case
|
|
48
|
+
-- Migrations from other databases may preserve original casing
|
|
49
|
+
-- Some GUI tools quote identifiers by default - disable this
|
|
50
|
+
|
|
51
|
+
-- If stuck with mixed-case, create views as a compatibility layer
|
|
52
|
+
CREATE VIEW users AS SELECT "userId" AS user_id, "firstName" AS first_name FROM "Users";
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Reference: [Identifiers and Key Words](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)
|