Skip to content

Commit 74aa8b7

Browse files
committed
Add explicit names to all indexes, raise max_name_length to 63
- Add name= to 46 Index objects across 7 packages using {table}_{column(s)}_idx convention - Raise Index.max_name_length from 30 (Django legacy) to 63 (Postgres NAMEDATALEN - 1) - Generate RenameIndex migrations for all renamed indexes (instant ALTER INDEX RENAME, no locks) - Add index naming convention to plain-postgres rule
1 parent b256268 commit 74aa8b7

17 files changed

Lines changed: 450 additions & 48 deletions

.claude/rules/plain-postgres.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Run `uv run plain docs postgres --section querying` for full patterns with code
6262
## Schema Design
6363

6464
- Index fields used in `.filter()` and `.order_by()`
65+
- `Index` requires a `name` argument — use `{table}_{column(s)}_idx` (e.g., `plainjobs_jobrequest_priority_idx`, `plainobserver_log_trace_id_timestamp_idx`)
6566
- Use `UniqueConstraint` in constraints, not `unique=True` on fields
6667
- Choose `on_delete` deliberately: CASCADE for children, PROTECT for referenced data
6768
- No `allow_null` on string fields — use `default=""`
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Generated by Plain 0.127.2 on 2026-03-25 20:19
2+
3+
from plain.postgres import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("plaincache", "0001_initial"),
9+
]
10+
11+
operations = [
12+
migrations.RenameIndex(
13+
model_name="cacheditem",
14+
new_name="plaincache_cacheditem_expires_at_idx",
15+
old_name="plaincache__expires_5a9119_idx",
16+
),
17+
]

plain-cache/plain/cache/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ class CachedItem(postgres.Model):
3333

3434
model_options = postgres.Options(
3535
indexes=[
36-
postgres.Index(fields=["expires_at"]),
36+
postgres.Index(
37+
name="plaincache_cacheditem_expires_at_idx", fields=["expires_at"]
38+
),
3739
],
3840
constraints=[
3941
postgres.UniqueConstraint(
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Generated by Plain 0.127.2 on 2026-03-25 20:19
2+
3+
from plain.postgres import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("plainjobs", "0009_remove_jobprocess_plainjobs_j_job_cla_19f3c1_idx_and_more"),
9+
]
10+
11+
operations = [
12+
migrations.RenameIndex(
13+
model_name="jobprocess",
14+
new_name="plainjobs_jobprocess_created_at_idx",
15+
old_name="plainjobs_j_created_04fbb8_idx",
16+
),
17+
migrations.RenameIndex(
18+
model_name="jobprocess",
19+
new_name="plainjobs_jobprocess_queue_idx",
20+
old_name="plainjobs_j_queue_d07d21_idx",
21+
),
22+
migrations.RenameIndex(
23+
model_name="jobprocess",
24+
new_name="plainjobs_jobprocess_concurrency_key_idx",
25+
old_name="plainjobs_j_concurr_ad4464_idx",
26+
),
27+
migrations.RenameIndex(
28+
model_name="jobprocess",
29+
new_name="plainjobs_jobprocess_started_at_idx",
30+
old_name="plainjobs_j_started_5cd62a_idx",
31+
),
32+
migrations.RenameIndex(
33+
model_name="jobprocess",
34+
new_name="plainjobs_jobprocess_job_request_uuid_idx",
35+
old_name="plainjobs_j_job_req_32b6eb_idx",
36+
),
37+
migrations.RenameIndex(
38+
model_name="jobprocess",
39+
new_name="plainjobs_jobprocess_trace_id_idx",
40+
old_name="plainjobs_j_trace_i_9f93c8_idx",
41+
),
42+
migrations.RenameIndex(
43+
model_name="jobprocess",
44+
new_name="plainjobs_jobprocess_uuid_idx",
45+
old_name="plainjobs_j_uuid_cd8cd3_idx",
46+
),
47+
migrations.RenameIndex(
48+
model_name="jobrequest",
49+
new_name="plainjobs_jobrequest_priority_idx",
50+
old_name="plainjobs_j_priorit_fd4fac_idx",
51+
),
52+
migrations.RenameIndex(
53+
model_name="jobrequest",
54+
new_name="plainjobs_jobrequest_created_at_idx",
55+
old_name="plainjobs_j_created_1eeb20_idx",
56+
),
57+
migrations.RenameIndex(
58+
model_name="jobrequest",
59+
new_name="plainjobs_jobrequest_queue_idx",
60+
old_name="plainjobs_j_queue_b34b5a_idx",
61+
),
62+
migrations.RenameIndex(
63+
model_name="jobrequest",
64+
new_name="plainjobs_jobrequest_start_at_idx",
65+
old_name="plainjobs_j_start_a_f3b8da_idx",
66+
),
67+
migrations.RenameIndex(
68+
model_name="jobrequest",
69+
new_name="plainjobs_jobrequest_concurrency_key_idx",
70+
old_name="plainjobs_j_concurr_c10926_idx",
71+
),
72+
migrations.RenameIndex(
73+
model_name="jobrequest",
74+
new_name="plainjobs_jobrequest_trace_id_idx",
75+
old_name="plainjobs_j_trace_i_194003_idx",
76+
),
77+
migrations.RenameIndex(
78+
model_name="jobrequest",
79+
new_name="plainjobs_jobrequest_uuid_idx",
80+
old_name="plainjobs_j_uuid_c41c85_idx",
81+
),
82+
migrations.RenameIndex(
83+
model_name="jobresult",
84+
new_name="plainjobs_jobresult_created_at_idx",
85+
old_name="plainjobs_j_created_7978bf_idx",
86+
),
87+
migrations.RenameIndex(
88+
model_name="jobresult",
89+
new_name="plainjobs_jobresult_job_process_uuid_idx",
90+
old_name="plainjobs_j_job_pro_751a64_idx",
91+
),
92+
migrations.RenameIndex(
93+
model_name="jobresult",
94+
new_name="plainjobs_jobresult_started_at_idx",
95+
old_name="plainjobs_j_started_6fb2ce_idx",
96+
),
97+
migrations.RenameIndex(
98+
model_name="jobresult",
99+
new_name="plainjobs_jobresult_ended_at_idx",
100+
old_name="plainjobs_j_ended_a_648f25_idx",
101+
),
102+
migrations.RenameIndex(
103+
model_name="jobresult",
104+
new_name="plainjobs_jobresult_status_idx",
105+
old_name="plainjobs_j_status_1ef683_idx",
106+
),
107+
migrations.RenameIndex(
108+
model_name="jobresult",
109+
new_name="plainjobs_jobresult_job_request_uuid_idx",
110+
old_name="plainjobs_j_job_req_3ddecf_idx",
111+
),
112+
migrations.RenameIndex(
113+
model_name="jobresult",
114+
new_name="plainjobs_jobresult_job_class_idx",
115+
old_name="plainjobs_j_job_cla_8791b4_idx",
116+
),
117+
migrations.RenameIndex(
118+
model_name="jobresult",
119+
new_name="plainjobs_jobresult_queue_idx",
120+
old_name="plainjobs_j_queue_0a2178_idx",
121+
),
122+
migrations.RenameIndex(
123+
model_name="jobresult",
124+
new_name="plainjobs_jobresult_trace_id_idx",
125+
old_name="plainjobs_j_trace_i_02f370_idx",
126+
),
127+
migrations.RenameIndex(
128+
model_name="jobresult",
129+
new_name="plainjobs_jobresult_uuid_idx",
130+
old_name="plainjobs_j_uuid_b33b4c_idx",
131+
),
132+
]

plain-jobs/plain/jobs/models.py

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,24 @@ class JobRequest(postgres.Model):
7979
model_options = postgres.Options(
8080
ordering=["-priority", "-created_at"],
8181
indexes=[
82-
postgres.Index(fields=["priority"]),
83-
postgres.Index(fields=["created_at"]),
84-
postgres.Index(fields=["queue"]),
85-
postgres.Index(fields=["start_at"]),
86-
postgres.Index(fields=["concurrency_key"]),
87-
postgres.Index(fields=["trace_id"]),
88-
postgres.Index(fields=["uuid"]),
82+
postgres.Index(
83+
name="plainjobs_jobrequest_priority_idx", fields=["priority"]
84+
),
85+
postgres.Index(
86+
name="plainjobs_jobrequest_created_at_idx", fields=["created_at"]
87+
),
88+
postgres.Index(name="plainjobs_jobrequest_queue_idx", fields=["queue"]),
89+
postgres.Index(
90+
name="plainjobs_jobrequest_start_at_idx", fields=["start_at"]
91+
),
92+
postgres.Index(
93+
name="plainjobs_jobrequest_concurrency_key_idx",
94+
fields=["concurrency_key"],
95+
),
96+
postgres.Index(
97+
name="plainjobs_jobrequest_trace_id_idx", fields=["trace_id"]
98+
),
99+
postgres.Index(name="plainjobs_jobrequest_uuid_idx", fields=["uuid"]),
89100
# Used for job grouping queries
90101
postgres.Index(
91102
name="job_request_concurrency_key",
@@ -188,13 +199,25 @@ class JobProcess(postgres.Model):
188199
model_options = postgres.Options(
189200
ordering=["-created_at"],
190201
indexes=[
191-
postgres.Index(fields=["created_at"]),
192-
postgres.Index(fields=["queue"]),
193-
postgres.Index(fields=["concurrency_key"]),
194-
postgres.Index(fields=["started_at"]),
195-
postgres.Index(fields=["job_request_uuid"]),
196-
postgres.Index(fields=["trace_id"]),
197-
postgres.Index(fields=["uuid"]),
202+
postgres.Index(
203+
name="plainjobs_jobprocess_created_at_idx", fields=["created_at"]
204+
),
205+
postgres.Index(name="plainjobs_jobprocess_queue_idx", fields=["queue"]),
206+
postgres.Index(
207+
name="plainjobs_jobprocess_concurrency_key_idx",
208+
fields=["concurrency_key"],
209+
),
210+
postgres.Index(
211+
name="plainjobs_jobprocess_started_at_idx", fields=["started_at"]
212+
),
213+
postgres.Index(
214+
name="plainjobs_jobprocess_job_request_uuid_idx",
215+
fields=["job_request_uuid"],
216+
),
217+
postgres.Index(
218+
name="plainjobs_jobprocess_trace_id_idx", fields=["trace_id"]
219+
),
220+
postgres.Index(name="plainjobs_jobprocess_uuid_idx", fields=["uuid"]),
198221
# Used for job grouping queries
199222
postgres.Index(
200223
name="job_concurrency_key",
@@ -533,16 +556,32 @@ class JobResult(postgres.Model):
533556
model_options = postgres.Options(
534557
ordering=["-created_at"],
535558
indexes=[
536-
postgres.Index(fields=["created_at"]),
537-
postgres.Index(fields=["job_process_uuid"]),
538-
postgres.Index(fields=["started_at"]),
539-
postgres.Index(fields=["ended_at"]),
540-
postgres.Index(fields=["status"]),
541-
postgres.Index(fields=["job_request_uuid"]),
542-
postgres.Index(fields=["job_class"]),
543-
postgres.Index(fields=["queue"]),
544-
postgres.Index(fields=["trace_id"]),
545-
postgres.Index(fields=["uuid"]),
559+
postgres.Index(
560+
name="plainjobs_jobresult_created_at_idx", fields=["created_at"]
561+
),
562+
postgres.Index(
563+
name="plainjobs_jobresult_job_process_uuid_idx",
564+
fields=["job_process_uuid"],
565+
),
566+
postgres.Index(
567+
name="plainjobs_jobresult_started_at_idx", fields=["started_at"]
568+
),
569+
postgres.Index(
570+
name="plainjobs_jobresult_ended_at_idx", fields=["ended_at"]
571+
),
572+
postgres.Index(name="plainjobs_jobresult_status_idx", fields=["status"]),
573+
postgres.Index(
574+
name="plainjobs_jobresult_job_request_uuid_idx",
575+
fields=["job_request_uuid"],
576+
),
577+
postgres.Index(
578+
name="plainjobs_jobresult_job_class_idx", fields=["job_class"]
579+
),
580+
postgres.Index(name="plainjobs_jobresult_queue_idx", fields=["queue"]),
581+
postgres.Index(
582+
name="plainjobs_jobresult_trace_id_idx", fields=["trace_id"]
583+
),
584+
postgres.Index(name="plainjobs_jobresult_uuid_idx", fields=["uuid"]),
546585
],
547586
constraints=[
548587
postgres.UniqueConstraint(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Generated by Plain 0.127.2 on 2026-03-25 20:19
2+
3+
from plain.postgres import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("plainobserver", "0008_remove_log_plainobserv_trace_i_c64ee0_idx_and_more"),
9+
]
10+
11+
operations = [
12+
migrations.RenameIndex(
13+
model_name="log",
14+
new_name="plainobserver_log_trace_id_timestamp_idx",
15+
old_name="plainobserv_trace_i_fcfb7d_idx",
16+
),
17+
migrations.RenameIndex(
18+
model_name="log",
19+
new_name="plainobserver_log_trace_id_span_id_idx",
20+
old_name="plainobserv_trace_i_1166af_idx",
21+
),
22+
migrations.RenameIndex(
23+
model_name="log",
24+
new_name="plainobserver_log_timestamp_idx",
25+
old_name="plainobserv_timesta_64f0dc_idx",
26+
),
27+
migrations.RenameIndex(
28+
model_name="span",
29+
new_name="plainobserver_span_span_id_idx",
30+
old_name="plainobserv_span_id_e7ade3_idx",
31+
),
32+
migrations.RenameIndex(
33+
model_name="span",
34+
new_name="plainobserver_span_start_time_idx",
35+
old_name="plainobserv_start_t_cb47a3_idx",
36+
),
37+
migrations.RenameIndex(
38+
model_name="trace",
39+
new_name="plainobserver_trace_trace_id_idx",
40+
old_name="plainobserv_trace_i_075b48_idx",
41+
),
42+
migrations.RenameIndex(
43+
model_name="trace",
44+
new_name="plainobserver_trace_start_time_idx",
45+
old_name="plainobserv_start_t_636c80_idx",
46+
),
47+
migrations.RenameIndex(
48+
model_name="trace",
49+
new_name="plainobserver_trace_request_id_idx",
50+
old_name="plainobserv_request_d1d5b2_idx",
51+
),
52+
migrations.RenameIndex(
53+
model_name="trace",
54+
new_name="plainobserver_trace_session_id_idx",
55+
old_name="plainobserv_session_350f42_idx",
56+
),
57+
]

plain-observer/plain/observer/models.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,18 @@ class Trace(postgres.Model):
7979
)
8080
],
8181
indexes=[
82-
postgres.Index(fields=["trace_id"]),
83-
postgres.Index(fields=["start_time"]),
84-
postgres.Index(fields=["request_id"]),
85-
postgres.Index(fields=["session_id"]),
82+
postgres.Index(
83+
name="plainobserver_trace_trace_id_idx", fields=["trace_id"]
84+
),
85+
postgres.Index(
86+
name="plainobserver_trace_start_time_idx", fields=["start_time"]
87+
),
88+
postgres.Index(
89+
name="plainobserver_trace_request_id_idx", fields=["request_id"]
90+
),
91+
postgres.Index(
92+
name="plainobserver_trace_session_id_idx", fields=["session_id"]
93+
),
8694
],
8795
)
8896

@@ -351,8 +359,10 @@ class Span(postgres.Model):
351359
)
352360
],
353361
indexes=[
354-
postgres.Index(fields=["span_id"]),
355-
postgres.Index(fields=["start_time"]),
362+
postgres.Index(name="plainobserver_span_span_id_idx", fields=["span_id"]),
363+
postgres.Index(
364+
name="plainobserver_span_start_time_idx", fields=["start_time"]
365+
),
356366
],
357367
)
358368

@@ -532,8 +542,15 @@ class Log(postgres.Model):
532542
model_options = postgres.Options(
533543
ordering=["timestamp"],
534544
indexes=[
535-
postgres.Index(fields=["trace", "timestamp"]),
536-
postgres.Index(fields=["trace", "span"]),
537-
postgres.Index(fields=["timestamp"]),
545+
postgres.Index(
546+
name="plainobserver_log_trace_id_timestamp_idx",
547+
fields=["trace", "timestamp"],
548+
),
549+
postgres.Index(
550+
name="plainobserver_log_trace_id_span_id_idx", fields=["trace", "span"]
551+
),
552+
postgres.Index(
553+
name="plainobserver_log_timestamp_idx", fields=["timestamp"]
554+
),
538555
],
539556
)

0 commit comments

Comments
 (0)