tenseleyflow/shithub / 08db487

Browse files

S35: ratelimit sqlc — bump/peek/prune queries for rate_limits + signup_ip_throttle

Authored by espadonne
SHA
08db487738fa5acbd37788aaa735333bb2e61b83
Parents
ffd6659
Tree
c83b342

6 changed files

StatusFile+-
A internal/ratelimit/queries/rate_limits.sql 65 0
A internal/ratelimit/sqlc/db.go 25 0
A internal/ratelimit/sqlc/models.go 1989 0
A internal/ratelimit/sqlc/querier.go 39 0
A internal/ratelimit/sqlc/rate_limits.sql.go 152 0
M sqlc.yaml 16 0
internal/ratelimit/queries/rate_limits.sqladded
@@ -0,0 +1,65 @@
1
+-- SPDX-License-Identifier: AGPL-3.0-or-later
2
+--
3
+-- Generic rate-limit counter queries (S35). Two write paths:
4
+--   * BumpRateLimit — atomic UPSERT that rolls the window forward
5
+--                     when stale, increments hits otherwise. Returns
6
+--                     the post-update hits + window_started_at so
7
+--                     the caller can compute Retry-After without a
8
+--                     second round trip.
9
+--   * BumpSignupIPThrottle — same shape against signup_ip_throttle
10
+--                            keyed by inet/CIDR.
11
+--
12
+-- Reads (PeekRateLimit, PeekSignupIPThrottle) are kept around for
13
+-- the admin observability surface; the hot path uses Bump-and-decide.
14
+
15
+-- name: BumpRateLimit :one
16
+-- Roll-or-increment in one statement. The CASE in the UPDATE branch
17
+-- handles the window roll: when the existing window started before
18
+-- (now - $3 interval), we treat it as a new window and reset hits
19
+-- to 1; otherwise we increment in place.
20
+INSERT INTO rate_limits (scope, key, hits, window_started_at)
21
+VALUES (sqlc.arg(scope), sqlc.arg(key), 1, now())
22
+ON CONFLICT (scope, key)
23
+DO UPDATE SET
24
+    hits              = CASE
25
+                          WHEN rate_limits.window_started_at < now() - sqlc.arg(ttl)::interval
26
+                          THEN 1
27
+                          ELSE rate_limits.hits + 1
28
+                        END,
29
+    window_started_at = CASE
30
+                          WHEN rate_limits.window_started_at < now() - sqlc.arg(ttl)::interval
31
+                          THEN now()
32
+                          ELSE rate_limits.window_started_at
33
+                        END
34
+RETURNING hits, window_started_at;
35
+
36
+-- name: PeekRateLimit :one
37
+SELECT scope, key, hits, window_started_at
38
+FROM rate_limits
39
+WHERE scope = $1 AND key = $2;
40
+
41
+-- name: PruneRateLimits :execrows
42
+DELETE FROM rate_limits
43
+WHERE window_started_at < now() - sqlc.arg(retention)::interval;
44
+
45
+-- name: BumpSignupIPThrottle :one
46
+-- Same UPSERT shape against the inet-keyed signup throttle.
47
+INSERT INTO signup_ip_throttle (cidr, hits, window_started_at)
48
+VALUES (sqlc.arg(cidr), 1, now())
49
+ON CONFLICT (cidr)
50
+DO UPDATE SET
51
+    hits              = CASE
52
+                          WHEN signup_ip_throttle.window_started_at < now() - sqlc.arg(ttl)::interval
53
+                          THEN 1
54
+                          ELSE signup_ip_throttle.hits + 1
55
+                        END,
56
+    window_started_at = CASE
57
+                          WHEN signup_ip_throttle.window_started_at < now() - sqlc.arg(ttl)::interval
58
+                          THEN now()
59
+                          ELSE signup_ip_throttle.window_started_at
60
+                        END
61
+RETURNING hits, window_started_at;
62
+
63
+-- name: PruneSignupIPThrottle :execrows
64
+DELETE FROM signup_ip_throttle
65
+WHERE window_started_at < now() - sqlc.arg(retention)::interval;
internal/ratelimit/sqlc/db.goadded
@@ -0,0 +1,25 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+
5
+package ratelimitdb
6
+
7
+import (
8
+	"context"
9
+
10
+	"github.com/jackc/pgx/v5"
11
+	"github.com/jackc/pgx/v5/pgconn"
12
+)
13
+
14
+type DBTX interface {
15
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
16
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
17
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
18
+}
19
+
20
+func New() *Queries {
21
+	return &Queries{}
22
+}
23
+
24
+type Queries struct {
25
+}
internal/ratelimit/sqlc/models.goadded
1989 lines changed — click to load
@@ -0,0 +1,1989 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+
5
+package ratelimitdb
6
+
7
+import (
8
+	"database/sql/driver"
9
+	"fmt"
10
+	"net/netip"
11
+
12
+	"github.com/jackc/pgx/v5/pgtype"
13
+)
14
+
15
+type CheckConclusion string
16
+
17
+const (
18
+	CheckConclusionSuccess        CheckConclusion = "success"
19
+	CheckConclusionFailure        CheckConclusion = "failure"
20
+	CheckConclusionNeutral        CheckConclusion = "neutral"
21
+	CheckConclusionCancelled      CheckConclusion = "cancelled"
22
+	CheckConclusionSkipped        CheckConclusion = "skipped"
23
+	CheckConclusionTimedOut       CheckConclusion = "timed_out"
24
+	CheckConclusionActionRequired CheckConclusion = "action_required"
25
+	CheckConclusionStale          CheckConclusion = "stale"
26
+)
27
+
28
+func (e *CheckConclusion) Scan(src interface{}) error {
29
+	switch s := src.(type) {
30
+	case []byte:
31
+		*e = CheckConclusion(s)
32
+	case string:
33
+		*e = CheckConclusion(s)
34
+	default:
35
+		return fmt.Errorf("unsupported scan type for CheckConclusion: %T", src)
36
+	}
37
+	return nil
38
+}
39
+
40
+type NullCheckConclusion struct {
41
+	CheckConclusion CheckConclusion
42
+	Valid           bool // Valid is true if CheckConclusion is not NULL
43
+}
44
+
45
+// Scan implements the Scanner interface.
46
+func (ns *NullCheckConclusion) Scan(value interface{}) error {
47
+	if value == nil {
48
+		ns.CheckConclusion, ns.Valid = "", false
49
+		return nil
50
+	}
51
+	ns.Valid = true
52
+	return ns.CheckConclusion.Scan(value)
53
+}
54
+
55
+// Value implements the driver Valuer interface.
56
+func (ns NullCheckConclusion) Value() (driver.Value, error) {
57
+	if !ns.Valid {
58
+		return nil, nil
59
+	}
60
+	return string(ns.CheckConclusion), nil
61
+}
62
+
63
+type CheckStatus string
64
+
65
+const (
66
+	CheckStatusQueued     CheckStatus = "queued"
67
+	CheckStatusInProgress CheckStatus = "in_progress"
68
+	CheckStatusCompleted  CheckStatus = "completed"
69
+	CheckStatusPending    CheckStatus = "pending"
70
+)
71
+
72
+func (e *CheckStatus) Scan(src interface{}) error {
73
+	switch s := src.(type) {
74
+	case []byte:
75
+		*e = CheckStatus(s)
76
+	case string:
77
+		*e = CheckStatus(s)
78
+	default:
79
+		return fmt.Errorf("unsupported scan type for CheckStatus: %T", src)
80
+	}
81
+	return nil
82
+}
83
+
84
+type NullCheckStatus struct {
85
+	CheckStatus CheckStatus
86
+	Valid       bool // Valid is true if CheckStatus is not NULL
87
+}
88
+
89
+// Scan implements the Scanner interface.
90
+func (ns *NullCheckStatus) Scan(value interface{}) error {
91
+	if value == nil {
92
+		ns.CheckStatus, ns.Valid = "", false
93
+		return nil
94
+	}
95
+	ns.Valid = true
96
+	return ns.CheckStatus.Scan(value)
97
+}
98
+
99
+// Value implements the driver Valuer interface.
100
+func (ns NullCheckStatus) Value() (driver.Value, error) {
101
+	if !ns.Valid {
102
+		return nil, nil
103
+	}
104
+	return string(ns.CheckStatus), nil
105
+}
106
+
107
+type CollabRole string
108
+
109
+const (
110
+	CollabRoleRead     CollabRole = "read"
111
+	CollabRoleTriage   CollabRole = "triage"
112
+	CollabRoleWrite    CollabRole = "write"
113
+	CollabRoleMaintain CollabRole = "maintain"
114
+	CollabRoleAdmin    CollabRole = "admin"
115
+)
116
+
117
+func (e *CollabRole) Scan(src interface{}) error {
118
+	switch s := src.(type) {
119
+	case []byte:
120
+		*e = CollabRole(s)
121
+	case string:
122
+		*e = CollabRole(s)
123
+	default:
124
+		return fmt.Errorf("unsupported scan type for CollabRole: %T", src)
125
+	}
126
+	return nil
127
+}
128
+
129
+type NullCollabRole struct {
130
+	CollabRole CollabRole
131
+	Valid      bool // Valid is true if CollabRole is not NULL
132
+}
133
+
134
+// Scan implements the Scanner interface.
135
+func (ns *NullCollabRole) Scan(value interface{}) error {
136
+	if value == nil {
137
+		ns.CollabRole, ns.Valid = "", false
138
+		return nil
139
+	}
140
+	ns.Valid = true
141
+	return ns.CollabRole.Scan(value)
142
+}
143
+
144
+// Value implements the driver Valuer interface.
145
+func (ns NullCollabRole) Value() (driver.Value, error) {
146
+	if !ns.Valid {
147
+		return nil, nil
148
+	}
149
+	return string(ns.CollabRole), nil
150
+}
151
+
152
+type IssueKind string
153
+
154
+const (
155
+	IssueKindIssue IssueKind = "issue"
156
+	IssueKindPr    IssueKind = "pr"
157
+)
158
+
159
+func (e *IssueKind) Scan(src interface{}) error {
160
+	switch s := src.(type) {
161
+	case []byte:
162
+		*e = IssueKind(s)
163
+	case string:
164
+		*e = IssueKind(s)
165
+	default:
166
+		return fmt.Errorf("unsupported scan type for IssueKind: %T", src)
167
+	}
168
+	return nil
169
+}
170
+
171
+type NullIssueKind struct {
172
+	IssueKind IssueKind
173
+	Valid     bool // Valid is true if IssueKind is not NULL
174
+}
175
+
176
+// Scan implements the Scanner interface.
177
+func (ns *NullIssueKind) Scan(value interface{}) error {
178
+	if value == nil {
179
+		ns.IssueKind, ns.Valid = "", false
180
+		return nil
181
+	}
182
+	ns.Valid = true
183
+	return ns.IssueKind.Scan(value)
184
+}
185
+
186
+// Value implements the driver Valuer interface.
187
+func (ns NullIssueKind) Value() (driver.Value, error) {
188
+	if !ns.Valid {
189
+		return nil, nil
190
+	}
191
+	return string(ns.IssueKind), nil
192
+}
193
+
194
+type IssueRefSource string
195
+
196
+const (
197
+	IssueRefSourceCommentBody   IssueRefSource = "comment_body"
198
+	IssueRefSourceIssueBody     IssueRefSource = "issue_body"
199
+	IssueRefSourceCommitMessage IssueRefSource = "commit_message"
200
+)
201
+
202
+func (e *IssueRefSource) Scan(src interface{}) error {
203
+	switch s := src.(type) {
204
+	case []byte:
205
+		*e = IssueRefSource(s)
206
+	case string:
207
+		*e = IssueRefSource(s)
208
+	default:
209
+		return fmt.Errorf("unsupported scan type for IssueRefSource: %T", src)
210
+	}
211
+	return nil
212
+}
213
+
214
+type NullIssueRefSource struct {
215
+	IssueRefSource IssueRefSource
216
+	Valid          bool // Valid is true if IssueRefSource is not NULL
217
+}
218
+
219
+// Scan implements the Scanner interface.
220
+func (ns *NullIssueRefSource) Scan(value interface{}) error {
221
+	if value == nil {
222
+		ns.IssueRefSource, ns.Valid = "", false
223
+		return nil
224
+	}
225
+	ns.Valid = true
226
+	return ns.IssueRefSource.Scan(value)
227
+}
228
+
229
+// Value implements the driver Valuer interface.
230
+func (ns NullIssueRefSource) Value() (driver.Value, error) {
231
+	if !ns.Valid {
232
+		return nil, nil
233
+	}
234
+	return string(ns.IssueRefSource), nil
235
+}
236
+
237
+type IssueState string
238
+
239
+const (
240
+	IssueStateOpen   IssueState = "open"
241
+	IssueStateClosed IssueState = "closed"
242
+)
243
+
244
+func (e *IssueState) Scan(src interface{}) error {
245
+	switch s := src.(type) {
246
+	case []byte:
247
+		*e = IssueState(s)
248
+	case string:
249
+		*e = IssueState(s)
250
+	default:
251
+		return fmt.Errorf("unsupported scan type for IssueState: %T", src)
252
+	}
253
+	return nil
254
+}
255
+
256
+type NullIssueState struct {
257
+	IssueState IssueState
258
+	Valid      bool // Valid is true if IssueState is not NULL
259
+}
260
+
261
+// Scan implements the Scanner interface.
262
+func (ns *NullIssueState) Scan(value interface{}) error {
263
+	if value == nil {
264
+		ns.IssueState, ns.Valid = "", false
265
+		return nil
266
+	}
267
+	ns.Valid = true
268
+	return ns.IssueState.Scan(value)
269
+}
270
+
271
+// Value implements the driver Valuer interface.
272
+func (ns NullIssueState) Value() (driver.Value, error) {
273
+	if !ns.Valid {
274
+		return nil, nil
275
+	}
276
+	return string(ns.IssueState), nil
277
+}
278
+
279
+type IssueStateReason string
280
+
281
+const (
282
+	IssueStateReasonCompleted  IssueStateReason = "completed"
283
+	IssueStateReasonNotPlanned IssueStateReason = "not_planned"
284
+	IssueStateReasonReopened   IssueStateReason = "reopened"
285
+	IssueStateReasonDuplicate  IssueStateReason = "duplicate"
286
+)
287
+
288
+func (e *IssueStateReason) Scan(src interface{}) error {
289
+	switch s := src.(type) {
290
+	case []byte:
291
+		*e = IssueStateReason(s)
292
+	case string:
293
+		*e = IssueStateReason(s)
294
+	default:
295
+		return fmt.Errorf("unsupported scan type for IssueStateReason: %T", src)
296
+	}
297
+	return nil
298
+}
299
+
300
+type NullIssueStateReason struct {
301
+	IssueStateReason IssueStateReason
302
+	Valid            bool // Valid is true if IssueStateReason is not NULL
303
+}
304
+
305
+// Scan implements the Scanner interface.
306
+func (ns *NullIssueStateReason) Scan(value interface{}) error {
307
+	if value == nil {
308
+		ns.IssueStateReason, ns.Valid = "", false
309
+		return nil
310
+	}
311
+	ns.Valid = true
312
+	return ns.IssueStateReason.Scan(value)
313
+}
314
+
315
+// Value implements the driver Valuer interface.
316
+func (ns NullIssueStateReason) Value() (driver.Value, error) {
317
+	if !ns.Valid {
318
+		return nil, nil
319
+	}
320
+	return string(ns.IssueStateReason), nil
321
+}
322
+
323
+type MilestoneState string
324
+
325
+const (
326
+	MilestoneStateOpen   MilestoneState = "open"
327
+	MilestoneStateClosed MilestoneState = "closed"
328
+)
329
+
330
+func (e *MilestoneState) Scan(src interface{}) error {
331
+	switch s := src.(type) {
332
+	case []byte:
333
+		*e = MilestoneState(s)
334
+	case string:
335
+		*e = MilestoneState(s)
336
+	default:
337
+		return fmt.Errorf("unsupported scan type for MilestoneState: %T", src)
338
+	}
339
+	return nil
340
+}
341
+
342
+type NullMilestoneState struct {
343
+	MilestoneState MilestoneState
344
+	Valid          bool // Valid is true if MilestoneState is not NULL
345
+}
346
+
347
+// Scan implements the Scanner interface.
348
+func (ns *NullMilestoneState) Scan(value interface{}) error {
349
+	if value == nil {
350
+		ns.MilestoneState, ns.Valid = "", false
351
+		return nil
352
+	}
353
+	ns.Valid = true
354
+	return ns.MilestoneState.Scan(value)
355
+}
356
+
357
+// Value implements the driver Valuer interface.
358
+func (ns NullMilestoneState) Value() (driver.Value, error) {
359
+	if !ns.Valid {
360
+		return nil, nil
361
+	}
362
+	return string(ns.MilestoneState), nil
363
+}
364
+
365
+type NotificationThreadKind string
366
+
367
+const (
368
+	NotificationThreadKindIssue NotificationThreadKind = "issue"
369
+	NotificationThreadKindPr    NotificationThreadKind = "pr"
370
+)
371
+
372
+func (e *NotificationThreadKind) Scan(src interface{}) error {
373
+	switch s := src.(type) {
374
+	case []byte:
375
+		*e = NotificationThreadKind(s)
376
+	case string:
377
+		*e = NotificationThreadKind(s)
378
+	default:
379
+		return fmt.Errorf("unsupported scan type for NotificationThreadKind: %T", src)
380
+	}
381
+	return nil
382
+}
383
+
384
+type NullNotificationThreadKind struct {
385
+	NotificationThreadKind NotificationThreadKind
386
+	Valid                  bool // Valid is true if NotificationThreadKind is not NULL
387
+}
388
+
389
+// Scan implements the Scanner interface.
390
+func (ns *NullNotificationThreadKind) Scan(value interface{}) error {
391
+	if value == nil {
392
+		ns.NotificationThreadKind, ns.Valid = "", false
393
+		return nil
394
+	}
395
+	ns.Valid = true
396
+	return ns.NotificationThreadKind.Scan(value)
397
+}
398
+
399
+// Value implements the driver Valuer interface.
400
+func (ns NullNotificationThreadKind) Value() (driver.Value, error) {
401
+	if !ns.Valid {
402
+		return nil, nil
403
+	}
404
+	return string(ns.NotificationThreadKind), nil
405
+}
406
+
407
+type OrgPlan string
408
+
409
+const (
410
+	OrgPlanFree       OrgPlan = "free"
411
+	OrgPlanTeam       OrgPlan = "team"
412
+	OrgPlanEnterprise OrgPlan = "enterprise"
413
+)
414
+
415
+func (e *OrgPlan) Scan(src interface{}) error {
416
+	switch s := src.(type) {
417
+	case []byte:
418
+		*e = OrgPlan(s)
419
+	case string:
420
+		*e = OrgPlan(s)
421
+	default:
422
+		return fmt.Errorf("unsupported scan type for OrgPlan: %T", src)
423
+	}
424
+	return nil
425
+}
426
+
427
+type NullOrgPlan struct {
428
+	OrgPlan OrgPlan
429
+	Valid   bool // Valid is true if OrgPlan is not NULL
430
+}
431
+
432
+// Scan implements the Scanner interface.
433
+func (ns *NullOrgPlan) Scan(value interface{}) error {
434
+	if value == nil {
435
+		ns.OrgPlan, ns.Valid = "", false
436
+		return nil
437
+	}
438
+	ns.Valid = true
439
+	return ns.OrgPlan.Scan(value)
440
+}
441
+
442
+// Value implements the driver Valuer interface.
443
+func (ns NullOrgPlan) Value() (driver.Value, error) {
444
+	if !ns.Valid {
445
+		return nil, nil
446
+	}
447
+	return string(ns.OrgPlan), nil
448
+}
449
+
450
+type OrgRole string
451
+
452
+const (
453
+	OrgRoleOwner  OrgRole = "owner"
454
+	OrgRoleMember OrgRole = "member"
455
+)
456
+
457
+func (e *OrgRole) Scan(src interface{}) error {
458
+	switch s := src.(type) {
459
+	case []byte:
460
+		*e = OrgRole(s)
461
+	case string:
462
+		*e = OrgRole(s)
463
+	default:
464
+		return fmt.Errorf("unsupported scan type for OrgRole: %T", src)
465
+	}
466
+	return nil
467
+}
468
+
469
+type NullOrgRole struct {
470
+	OrgRole OrgRole
471
+	Valid   bool // Valid is true if OrgRole is not NULL
472
+}
473
+
474
+// Scan implements the Scanner interface.
475
+func (ns *NullOrgRole) Scan(value interface{}) error {
476
+	if value == nil {
477
+		ns.OrgRole, ns.Valid = "", false
478
+		return nil
479
+	}
480
+	ns.Valid = true
481
+	return ns.OrgRole.Scan(value)
482
+}
483
+
484
+// Value implements the driver Valuer interface.
485
+func (ns NullOrgRole) Value() (driver.Value, error) {
486
+	if !ns.Valid {
487
+		return nil, nil
488
+	}
489
+	return string(ns.OrgRole), nil
490
+}
491
+
492
+type PrFileStatus string
493
+
494
+const (
495
+	PrFileStatusAdded    PrFileStatus = "added"
496
+	PrFileStatusModified PrFileStatus = "modified"
497
+	PrFileStatusDeleted  PrFileStatus = "deleted"
498
+	PrFileStatusRenamed  PrFileStatus = "renamed"
499
+	PrFileStatusCopied   PrFileStatus = "copied"
500
+)
501
+
502
+func (e *PrFileStatus) Scan(src interface{}) error {
503
+	switch s := src.(type) {
504
+	case []byte:
505
+		*e = PrFileStatus(s)
506
+	case string:
507
+		*e = PrFileStatus(s)
508
+	default:
509
+		return fmt.Errorf("unsupported scan type for PrFileStatus: %T", src)
510
+	}
511
+	return nil
512
+}
513
+
514
+type NullPrFileStatus struct {
515
+	PrFileStatus PrFileStatus
516
+	Valid        bool // Valid is true if PrFileStatus is not NULL
517
+}
518
+
519
+// Scan implements the Scanner interface.
520
+func (ns *NullPrFileStatus) Scan(value interface{}) error {
521
+	if value == nil {
522
+		ns.PrFileStatus, ns.Valid = "", false
523
+		return nil
524
+	}
525
+	ns.Valid = true
526
+	return ns.PrFileStatus.Scan(value)
527
+}
528
+
529
+// Value implements the driver Valuer interface.
530
+func (ns NullPrFileStatus) Value() (driver.Value, error) {
531
+	if !ns.Valid {
532
+		return nil, nil
533
+	}
534
+	return string(ns.PrFileStatus), nil
535
+}
536
+
537
+type PrMergeMethod string
538
+
539
+const (
540
+	PrMergeMethodMerge  PrMergeMethod = "merge"
541
+	PrMergeMethodSquash PrMergeMethod = "squash"
542
+	PrMergeMethodRebase PrMergeMethod = "rebase"
543
+)
544
+
545
+func (e *PrMergeMethod) Scan(src interface{}) error {
546
+	switch s := src.(type) {
547
+	case []byte:
548
+		*e = PrMergeMethod(s)
549
+	case string:
550
+		*e = PrMergeMethod(s)
551
+	default:
552
+		return fmt.Errorf("unsupported scan type for PrMergeMethod: %T", src)
553
+	}
554
+	return nil
555
+}
556
+
557
+type NullPrMergeMethod struct {
558
+	PrMergeMethod PrMergeMethod
559
+	Valid         bool // Valid is true if PrMergeMethod is not NULL
560
+}
561
+
562
+// Scan implements the Scanner interface.
563
+func (ns *NullPrMergeMethod) Scan(value interface{}) error {
564
+	if value == nil {
565
+		ns.PrMergeMethod, ns.Valid = "", false
566
+		return nil
567
+	}
568
+	ns.Valid = true
569
+	return ns.PrMergeMethod.Scan(value)
570
+}
571
+
572
+// Value implements the driver Valuer interface.
573
+func (ns NullPrMergeMethod) Value() (driver.Value, error) {
574
+	if !ns.Valid {
575
+		return nil, nil
576
+	}
577
+	return string(ns.PrMergeMethod), nil
578
+}
579
+
580
+type PrMergeableState string
581
+
582
+const (
583
+	PrMergeableStateUnknown PrMergeableState = "unknown"
584
+	PrMergeableStateClean   PrMergeableState = "clean"
585
+	PrMergeableStateDirty   PrMergeableState = "dirty"
586
+	PrMergeableStateBlocked PrMergeableState = "blocked"
587
+	PrMergeableStateBehind  PrMergeableState = "behind"
588
+)
589
+
590
+func (e *PrMergeableState) Scan(src interface{}) error {
591
+	switch s := src.(type) {
592
+	case []byte:
593
+		*e = PrMergeableState(s)
594
+	case string:
595
+		*e = PrMergeableState(s)
596
+	default:
597
+		return fmt.Errorf("unsupported scan type for PrMergeableState: %T", src)
598
+	}
599
+	return nil
600
+}
601
+
602
+type NullPrMergeableState struct {
603
+	PrMergeableState PrMergeableState
604
+	Valid            bool // Valid is true if PrMergeableState is not NULL
605
+}
606
+
607
+// Scan implements the Scanner interface.
608
+func (ns *NullPrMergeableState) Scan(value interface{}) error {
609
+	if value == nil {
610
+		ns.PrMergeableState, ns.Valid = "", false
611
+		return nil
612
+	}
613
+	ns.Valid = true
614
+	return ns.PrMergeableState.Scan(value)
615
+}
616
+
617
+// Value implements the driver Valuer interface.
618
+func (ns NullPrMergeableState) Value() (driver.Value, error) {
619
+	if !ns.Valid {
620
+		return nil, nil
621
+	}
622
+	return string(ns.PrMergeableState), nil
623
+}
624
+
625
+type PrReviewSide string
626
+
627
+const (
628
+	PrReviewSideLeft  PrReviewSide = "left"
629
+	PrReviewSideRight PrReviewSide = "right"
630
+)
631
+
632
+func (e *PrReviewSide) Scan(src interface{}) error {
633
+	switch s := src.(type) {
634
+	case []byte:
635
+		*e = PrReviewSide(s)
636
+	case string:
637
+		*e = PrReviewSide(s)
638
+	default:
639
+		return fmt.Errorf("unsupported scan type for PrReviewSide: %T", src)
640
+	}
641
+	return nil
642
+}
643
+
644
+type NullPrReviewSide struct {
645
+	PrReviewSide PrReviewSide
646
+	Valid        bool // Valid is true if PrReviewSide is not NULL
647
+}
648
+
649
+// Scan implements the Scanner interface.
650
+func (ns *NullPrReviewSide) Scan(value interface{}) error {
651
+	if value == nil {
652
+		ns.PrReviewSide, ns.Valid = "", false
653
+		return nil
654
+	}
655
+	ns.Valid = true
656
+	return ns.PrReviewSide.Scan(value)
657
+}
658
+
659
+// Value implements the driver Valuer interface.
660
+func (ns NullPrReviewSide) Value() (driver.Value, error) {
661
+	if !ns.Valid {
662
+		return nil, nil
663
+	}
664
+	return string(ns.PrReviewSide), nil
665
+}
666
+
667
+type PrReviewState string
668
+
669
+const (
670
+	PrReviewStateComment        PrReviewState = "comment"
671
+	PrReviewStateApprove        PrReviewState = "approve"
672
+	PrReviewStateRequestChanges PrReviewState = "request_changes"
673
+)
674
+
675
+func (e *PrReviewState) Scan(src interface{}) error {
676
+	switch s := src.(type) {
677
+	case []byte:
678
+		*e = PrReviewState(s)
679
+	case string:
680
+		*e = PrReviewState(s)
681
+	default:
682
+		return fmt.Errorf("unsupported scan type for PrReviewState: %T", src)
683
+	}
684
+	return nil
685
+}
686
+
687
+type NullPrReviewState struct {
688
+	PrReviewState PrReviewState
689
+	Valid         bool // Valid is true if PrReviewState is not NULL
690
+}
691
+
692
+// Scan implements the Scanner interface.
693
+func (ns *NullPrReviewState) Scan(value interface{}) error {
694
+	if value == nil {
695
+		ns.PrReviewState, ns.Valid = "", false
696
+		return nil
697
+	}
698
+	ns.Valid = true
699
+	return ns.PrReviewState.Scan(value)
700
+}
701
+
702
+// Value implements the driver Valuer interface.
703
+func (ns NullPrReviewState) Value() (driver.Value, error) {
704
+	if !ns.Valid {
705
+		return nil, nil
706
+	}
707
+	return string(ns.PrReviewState), nil
708
+}
709
+
710
+type PrincipalKind string
711
+
712
+const (
713
+	PrincipalKindUser PrincipalKind = "user"
714
+	PrincipalKindOrg  PrincipalKind = "org"
715
+)
716
+
717
+func (e *PrincipalKind) Scan(src interface{}) error {
718
+	switch s := src.(type) {
719
+	case []byte:
720
+		*e = PrincipalKind(s)
721
+	case string:
722
+		*e = PrincipalKind(s)
723
+	default:
724
+		return fmt.Errorf("unsupported scan type for PrincipalKind: %T", src)
725
+	}
726
+	return nil
727
+}
728
+
729
+type NullPrincipalKind struct {
730
+	PrincipalKind PrincipalKind
731
+	Valid         bool // Valid is true if PrincipalKind is not NULL
732
+}
733
+
734
+// Scan implements the Scanner interface.
735
+func (ns *NullPrincipalKind) Scan(value interface{}) error {
736
+	if value == nil {
737
+		ns.PrincipalKind, ns.Valid = "", false
738
+		return nil
739
+	}
740
+	ns.Valid = true
741
+	return ns.PrincipalKind.Scan(value)
742
+}
743
+
744
+// Value implements the driver Valuer interface.
745
+func (ns NullPrincipalKind) Value() (driver.Value, error) {
746
+	if !ns.Valid {
747
+		return nil, nil
748
+	}
749
+	return string(ns.PrincipalKind), nil
750
+}
751
+
752
+type RepoInitStatus string
753
+
754
+const (
755
+	RepoInitStatusInitialized RepoInitStatus = "initialized"
756
+	RepoInitStatusInitPending RepoInitStatus = "init_pending"
757
+	RepoInitStatusInitFailed  RepoInitStatus = "init_failed"
758
+)
759
+
760
+func (e *RepoInitStatus) Scan(src interface{}) error {
761
+	switch s := src.(type) {
762
+	case []byte:
763
+		*e = RepoInitStatus(s)
764
+	case string:
765
+		*e = RepoInitStatus(s)
766
+	default:
767
+		return fmt.Errorf("unsupported scan type for RepoInitStatus: %T", src)
768
+	}
769
+	return nil
770
+}
771
+
772
+type NullRepoInitStatus struct {
773
+	RepoInitStatus RepoInitStatus
774
+	Valid          bool // Valid is true if RepoInitStatus is not NULL
775
+}
776
+
777
+// Scan implements the Scanner interface.
778
+func (ns *NullRepoInitStatus) Scan(value interface{}) error {
779
+	if value == nil {
780
+		ns.RepoInitStatus, ns.Valid = "", false
781
+		return nil
782
+	}
783
+	ns.Valid = true
784
+	return ns.RepoInitStatus.Scan(value)
785
+}
786
+
787
+// Value implements the driver Valuer interface.
788
+func (ns NullRepoInitStatus) Value() (driver.Value, error) {
789
+	if !ns.Valid {
790
+		return nil, nil
791
+	}
792
+	return string(ns.RepoInitStatus), nil
793
+}
794
+
795
+type RepoVisibility string
796
+
797
+const (
798
+	RepoVisibilityPublic  RepoVisibility = "public"
799
+	RepoVisibilityPrivate RepoVisibility = "private"
800
+)
801
+
802
+func (e *RepoVisibility) Scan(src interface{}) error {
803
+	switch s := src.(type) {
804
+	case []byte:
805
+		*e = RepoVisibility(s)
806
+	case string:
807
+		*e = RepoVisibility(s)
808
+	default:
809
+		return fmt.Errorf("unsupported scan type for RepoVisibility: %T", src)
810
+	}
811
+	return nil
812
+}
813
+
814
+type NullRepoVisibility struct {
815
+	RepoVisibility RepoVisibility
816
+	Valid          bool // Valid is true if RepoVisibility is not NULL
817
+}
818
+
819
+// Scan implements the Scanner interface.
820
+func (ns *NullRepoVisibility) Scan(value interface{}) error {
821
+	if value == nil {
822
+		ns.RepoVisibility, ns.Valid = "", false
823
+		return nil
824
+	}
825
+	ns.Valid = true
826
+	return ns.RepoVisibility.Scan(value)
827
+}
828
+
829
+// Value implements the driver Valuer interface.
830
+func (ns NullRepoVisibility) Value() (driver.Value, error) {
831
+	if !ns.Valid {
832
+		return nil, nil
833
+	}
834
+	return string(ns.RepoVisibility), nil
835
+}
836
+
837
+type TeamPrivacy string
838
+
839
+const (
840
+	TeamPrivacyVisible TeamPrivacy = "visible"
841
+	TeamPrivacySecret  TeamPrivacy = "secret"
842
+)
843
+
844
+func (e *TeamPrivacy) Scan(src interface{}) error {
845
+	switch s := src.(type) {
846
+	case []byte:
847
+		*e = TeamPrivacy(s)
848
+	case string:
849
+		*e = TeamPrivacy(s)
850
+	default:
851
+		return fmt.Errorf("unsupported scan type for TeamPrivacy: %T", src)
852
+	}
853
+	return nil
854
+}
855
+
856
+type NullTeamPrivacy struct {
857
+	TeamPrivacy TeamPrivacy
858
+	Valid       bool // Valid is true if TeamPrivacy is not NULL
859
+}
860
+
861
+// Scan implements the Scanner interface.
862
+func (ns *NullTeamPrivacy) Scan(value interface{}) error {
863
+	if value == nil {
864
+		ns.TeamPrivacy, ns.Valid = "", false
865
+		return nil
866
+	}
867
+	ns.Valid = true
868
+	return ns.TeamPrivacy.Scan(value)
869
+}
870
+
871
+// Value implements the driver Valuer interface.
872
+func (ns NullTeamPrivacy) Value() (driver.Value, error) {
873
+	if !ns.Valid {
874
+		return nil, nil
875
+	}
876
+	return string(ns.TeamPrivacy), nil
877
+}
878
+
879
+type TeamRepoRole string
880
+
881
+const (
882
+	TeamRepoRoleRead     TeamRepoRole = "read"
883
+	TeamRepoRoleTriage   TeamRepoRole = "triage"
884
+	TeamRepoRoleWrite    TeamRepoRole = "write"
885
+	TeamRepoRoleMaintain TeamRepoRole = "maintain"
886
+	TeamRepoRoleAdmin    TeamRepoRole = "admin"
887
+)
888
+
889
+func (e *TeamRepoRole) Scan(src interface{}) error {
890
+	switch s := src.(type) {
891
+	case []byte:
892
+		*e = TeamRepoRole(s)
893
+	case string:
894
+		*e = TeamRepoRole(s)
895
+	default:
896
+		return fmt.Errorf("unsupported scan type for TeamRepoRole: %T", src)
897
+	}
898
+	return nil
899
+}
900
+
901
+type NullTeamRepoRole struct {
902
+	TeamRepoRole TeamRepoRole
903
+	Valid        bool // Valid is true if TeamRepoRole is not NULL
904
+}
905
+
906
+// Scan implements the Scanner interface.
907
+func (ns *NullTeamRepoRole) Scan(value interface{}) error {
908
+	if value == nil {
909
+		ns.TeamRepoRole, ns.Valid = "", false
910
+		return nil
911
+	}
912
+	ns.Valid = true
913
+	return ns.TeamRepoRole.Scan(value)
914
+}
915
+
916
+// Value implements the driver Valuer interface.
917
+func (ns NullTeamRepoRole) Value() (driver.Value, error) {
918
+	if !ns.Valid {
919
+		return nil, nil
920
+	}
921
+	return string(ns.TeamRepoRole), nil
922
+}
923
+
924
+type TeamRole string
925
+
926
+const (
927
+	TeamRoleMember     TeamRole = "member"
928
+	TeamRoleMaintainer TeamRole = "maintainer"
929
+)
930
+
931
+func (e *TeamRole) Scan(src interface{}) error {
932
+	switch s := src.(type) {
933
+	case []byte:
934
+		*e = TeamRole(s)
935
+	case string:
936
+		*e = TeamRole(s)
937
+	default:
938
+		return fmt.Errorf("unsupported scan type for TeamRole: %T", src)
939
+	}
940
+	return nil
941
+}
942
+
943
+type NullTeamRole struct {
944
+	TeamRole TeamRole
945
+	Valid    bool // Valid is true if TeamRole is not NULL
946
+}
947
+
948
+// Scan implements the Scanner interface.
949
+func (ns *NullTeamRole) Scan(value interface{}) error {
950
+	if value == nil {
951
+		ns.TeamRole, ns.Valid = "", false
952
+		return nil
953
+	}
954
+	ns.Valid = true
955
+	return ns.TeamRole.Scan(value)
956
+}
957
+
958
+// Value implements the driver Valuer interface.
959
+func (ns NullTeamRole) Value() (driver.Value, error) {
960
+	if !ns.Valid {
961
+		return nil, nil
962
+	}
963
+	return string(ns.TeamRole), nil
964
+}
965
+
966
+type TransactionalEmailStatus string
967
+
968
+const (
969
+	TransactionalEmailStatusQueued      TransactionalEmailStatus = "queued"
970
+	TransactionalEmailStatusSent        TransactionalEmailStatus = "sent"
971
+	TransactionalEmailStatusSoftBounced TransactionalEmailStatus = "soft_bounced"
972
+	TransactionalEmailStatusHardBounced TransactionalEmailStatus = "hard_bounced"
973
+	TransactionalEmailStatusDropped     TransactionalEmailStatus = "dropped"
974
+)
975
+
976
+func (e *TransactionalEmailStatus) Scan(src interface{}) error {
977
+	switch s := src.(type) {
978
+	case []byte:
979
+		*e = TransactionalEmailStatus(s)
980
+	case string:
981
+		*e = TransactionalEmailStatus(s)
982
+	default:
983
+		return fmt.Errorf("unsupported scan type for TransactionalEmailStatus: %T", src)
984
+	}
985
+	return nil
986
+}
987
+
988
+type NullTransactionalEmailStatus struct {
989
+	TransactionalEmailStatus TransactionalEmailStatus
990
+	Valid                    bool // Valid is true if TransactionalEmailStatus is not NULL
991
+}
992
+
993
+// Scan implements the Scanner interface.
994
+func (ns *NullTransactionalEmailStatus) Scan(value interface{}) error {
995
+	if value == nil {
996
+		ns.TransactionalEmailStatus, ns.Valid = "", false
997
+		return nil
998
+	}
999
+	ns.Valid = true
1000
+	return ns.TransactionalEmailStatus.Scan(value)
1001
+}
1002
+
1003
+// Value implements the driver Valuer interface.
1004
+func (ns NullTransactionalEmailStatus) Value() (driver.Value, error) {
1005
+	if !ns.Valid {
1006
+		return nil, nil
1007
+	}
1008
+	return string(ns.TransactionalEmailStatus), nil
1009
+}
1010
+
1011
+type TransferPrincipalKind string
1012
+
1013
+const (
1014
+	TransferPrincipalKindUser TransferPrincipalKind = "user"
1015
+	TransferPrincipalKindOrg  TransferPrincipalKind = "org"
1016
+)
1017
+
1018
+func (e *TransferPrincipalKind) Scan(src interface{}) error {
1019
+	switch s := src.(type) {
1020
+	case []byte:
1021
+		*e = TransferPrincipalKind(s)
1022
+	case string:
1023
+		*e = TransferPrincipalKind(s)
1024
+	default:
1025
+		return fmt.Errorf("unsupported scan type for TransferPrincipalKind: %T", src)
1026
+	}
1027
+	return nil
1028
+}
1029
+
1030
+type NullTransferPrincipalKind struct {
1031
+	TransferPrincipalKind TransferPrincipalKind
1032
+	Valid                 bool // Valid is true if TransferPrincipalKind is not NULL
1033
+}
1034
+
1035
+// Scan implements the Scanner interface.
1036
+func (ns *NullTransferPrincipalKind) Scan(value interface{}) error {
1037
+	if value == nil {
1038
+		ns.TransferPrincipalKind, ns.Valid = "", false
1039
+		return nil
1040
+	}
1041
+	ns.Valid = true
1042
+	return ns.TransferPrincipalKind.Scan(value)
1043
+}
1044
+
1045
+// Value implements the driver Valuer interface.
1046
+func (ns NullTransferPrincipalKind) Value() (driver.Value, error) {
1047
+	if !ns.Valid {
1048
+		return nil, nil
1049
+	}
1050
+	return string(ns.TransferPrincipalKind), nil
1051
+}
1052
+
1053
+type TransferStatus string
1054
+
1055
+const (
1056
+	TransferStatusPending  TransferStatus = "pending"
1057
+	TransferStatusAccepted TransferStatus = "accepted"
1058
+	TransferStatusDeclined TransferStatus = "declined"
1059
+	TransferStatusCanceled TransferStatus = "canceled"
1060
+	TransferStatusExpired  TransferStatus = "expired"
1061
+)
1062
+
1063
+func (e *TransferStatus) Scan(src interface{}) error {
1064
+	switch s := src.(type) {
1065
+	case []byte:
1066
+		*e = TransferStatus(s)
1067
+	case string:
1068
+		*e = TransferStatus(s)
1069
+	default:
1070
+		return fmt.Errorf("unsupported scan type for TransferStatus: %T", src)
1071
+	}
1072
+	return nil
1073
+}
1074
+
1075
+type NullTransferStatus struct {
1076
+	TransferStatus TransferStatus
1077
+	Valid          bool // Valid is true if TransferStatus is not NULL
1078
+}
1079
+
1080
+// Scan implements the Scanner interface.
1081
+func (ns *NullTransferStatus) Scan(value interface{}) error {
1082
+	if value == nil {
1083
+		ns.TransferStatus, ns.Valid = "", false
1084
+		return nil
1085
+	}
1086
+	ns.Valid = true
1087
+	return ns.TransferStatus.Scan(value)
1088
+}
1089
+
1090
+// Value implements the driver Valuer interface.
1091
+func (ns NullTransferStatus) Value() (driver.Value, error) {
1092
+	if !ns.Valid {
1093
+		return nil, nil
1094
+	}
1095
+	return string(ns.TransferStatus), nil
1096
+}
1097
+
1098
+type WatchLevel string
1099
+
1100
+const (
1101
+	WatchLevelAll           WatchLevel = "all"
1102
+	WatchLevelParticipating WatchLevel = "participating"
1103
+	WatchLevelIgnore        WatchLevel = "ignore"
1104
+)
1105
+
1106
+func (e *WatchLevel) Scan(src interface{}) error {
1107
+	switch s := src.(type) {
1108
+	case []byte:
1109
+		*e = WatchLevel(s)
1110
+	case string:
1111
+		*e = WatchLevel(s)
1112
+	default:
1113
+		return fmt.Errorf("unsupported scan type for WatchLevel: %T", src)
1114
+	}
1115
+	return nil
1116
+}
1117
+
1118
+type NullWatchLevel struct {
1119
+	WatchLevel WatchLevel
1120
+	Valid      bool // Valid is true if WatchLevel is not NULL
1121
+}
1122
+
1123
+// Scan implements the Scanner interface.
1124
+func (ns *NullWatchLevel) Scan(value interface{}) error {
1125
+	if value == nil {
1126
+		ns.WatchLevel, ns.Valid = "", false
1127
+		return nil
1128
+	}
1129
+	ns.Valid = true
1130
+	return ns.WatchLevel.Scan(value)
1131
+}
1132
+
1133
+// Value implements the driver Valuer interface.
1134
+func (ns NullWatchLevel) Value() (driver.Value, error) {
1135
+	if !ns.Valid {
1136
+		return nil, nil
1137
+	}
1138
+	return string(ns.WatchLevel), nil
1139
+}
1140
+
1141
+type WebhookContentType string
1142
+
1143
+const (
1144
+	WebhookContentTypeJson WebhookContentType = "json"
1145
+	WebhookContentTypeForm WebhookContentType = "form"
1146
+)
1147
+
1148
+func (e *WebhookContentType) Scan(src interface{}) error {
1149
+	switch s := src.(type) {
1150
+	case []byte:
1151
+		*e = WebhookContentType(s)
1152
+	case string:
1153
+		*e = WebhookContentType(s)
1154
+	default:
1155
+		return fmt.Errorf("unsupported scan type for WebhookContentType: %T", src)
1156
+	}
1157
+	return nil
1158
+}
1159
+
1160
+type NullWebhookContentType struct {
1161
+	WebhookContentType WebhookContentType
1162
+	Valid              bool // Valid is true if WebhookContentType is not NULL
1163
+}
1164
+
1165
+// Scan implements the Scanner interface.
1166
+func (ns *NullWebhookContentType) Scan(value interface{}) error {
1167
+	if value == nil {
1168
+		ns.WebhookContentType, ns.Valid = "", false
1169
+		return nil
1170
+	}
1171
+	ns.Valid = true
1172
+	return ns.WebhookContentType.Scan(value)
1173
+}
1174
+
1175
+// Value implements the driver Valuer interface.
1176
+func (ns NullWebhookContentType) Value() (driver.Value, error) {
1177
+	if !ns.Valid {
1178
+		return nil, nil
1179
+	}
1180
+	return string(ns.WebhookContentType), nil
1181
+}
1182
+
1183
+type WebhookDeliveryStatus string
1184
+
1185
+const (
1186
+	WebhookDeliveryStatusPending         WebhookDeliveryStatus = "pending"
1187
+	WebhookDeliveryStatusSucceeded       WebhookDeliveryStatus = "succeeded"
1188
+	WebhookDeliveryStatusFailedRetry     WebhookDeliveryStatus = "failed_retry"
1189
+	WebhookDeliveryStatusFailedPermanent WebhookDeliveryStatus = "failed_permanent"
1190
+)
1191
+
1192
+func (e *WebhookDeliveryStatus) Scan(src interface{}) error {
1193
+	switch s := src.(type) {
1194
+	case []byte:
1195
+		*e = WebhookDeliveryStatus(s)
1196
+	case string:
1197
+		*e = WebhookDeliveryStatus(s)
1198
+	default:
1199
+		return fmt.Errorf("unsupported scan type for WebhookDeliveryStatus: %T", src)
1200
+	}
1201
+	return nil
1202
+}
1203
+
1204
+type NullWebhookDeliveryStatus struct {
1205
+	WebhookDeliveryStatus WebhookDeliveryStatus
1206
+	Valid                 bool // Valid is true if WebhookDeliveryStatus is not NULL
1207
+}
1208
+
1209
+// Scan implements the Scanner interface.
1210
+func (ns *NullWebhookDeliveryStatus) Scan(value interface{}) error {
1211
+	if value == nil {
1212
+		ns.WebhookDeliveryStatus, ns.Valid = "", false
1213
+		return nil
1214
+	}
1215
+	ns.Valid = true
1216
+	return ns.WebhookDeliveryStatus.Scan(value)
1217
+}
1218
+
1219
+// Value implements the driver Valuer interface.
1220
+func (ns NullWebhookDeliveryStatus) Value() (driver.Value, error) {
1221
+	if !ns.Valid {
1222
+		return nil, nil
1223
+	}
1224
+	return string(ns.WebhookDeliveryStatus), nil
1225
+}
1226
+
1227
+type WebhookOwnerKind string
1228
+
1229
+const (
1230
+	WebhookOwnerKindRepo WebhookOwnerKind = "repo"
1231
+	WebhookOwnerKindOrg  WebhookOwnerKind = "org"
1232
+)
1233
+
1234
+func (e *WebhookOwnerKind) Scan(src interface{}) error {
1235
+	switch s := src.(type) {
1236
+	case []byte:
1237
+		*e = WebhookOwnerKind(s)
1238
+	case string:
1239
+		*e = WebhookOwnerKind(s)
1240
+	default:
1241
+		return fmt.Errorf("unsupported scan type for WebhookOwnerKind: %T", src)
1242
+	}
1243
+	return nil
1244
+}
1245
+
1246
+type NullWebhookOwnerKind struct {
1247
+	WebhookOwnerKind WebhookOwnerKind
1248
+	Valid            bool // Valid is true if WebhookOwnerKind is not NULL
1249
+}
1250
+
1251
+// Scan implements the Scanner interface.
1252
+func (ns *NullWebhookOwnerKind) Scan(value interface{}) error {
1253
+	if value == nil {
1254
+		ns.WebhookOwnerKind, ns.Valid = "", false
1255
+		return nil
1256
+	}
1257
+	ns.Valid = true
1258
+	return ns.WebhookOwnerKind.Scan(value)
1259
+}
1260
+
1261
+// Value implements the driver Valuer interface.
1262
+func (ns NullWebhookOwnerKind) Value() (driver.Value, error) {
1263
+	if !ns.Valid {
1264
+		return nil, nil
1265
+	}
1266
+	return string(ns.WebhookOwnerKind), nil
1267
+}
1268
+
1269
+type AuthAuditLog struct {
1270
+	ID         int64
1271
+	ActorID    pgtype.Int8
1272
+	Action     string
1273
+	TargetType string
1274
+	TargetID   pgtype.Int8
1275
+	Meta       []byte
1276
+	CreatedAt  pgtype.Timestamptz
1277
+}
1278
+
1279
+type AuthThrottle struct {
1280
+	ID              int64
1281
+	Scope           string
1282
+	Identifier      string
1283
+	Hits            int32
1284
+	WindowStartedAt pgtype.Timestamptz
1285
+}
1286
+
1287
+type BranchProtectionRule struct {
1288
+	ID                             int64
1289
+	RepoID                         int64
1290
+	Pattern                        string
1291
+	PreventForcePush               bool
1292
+	PreventDeletion                bool
1293
+	RequirePrForPush               bool
1294
+	AllowedPusherUserIds           []int64
1295
+	RequireSignedCommits           bool
1296
+	StatusChecksRequired           []string
1297
+	CreatedAt                      pgtype.Timestamptz
1298
+	UpdatedAt                      pgtype.Timestamptz
1299
+	CreatedByUserID                pgtype.Int8
1300
+	RequiredReviewCount            int32
1301
+	DismissStaleReviewsOnPush      bool
1302
+	RequireCodeOwnerReview         bool
1303
+	DismissStaleStatusChecksOnPush bool
1304
+}
1305
+
1306
+type CheckRun struct {
1307
+	ID          int64
1308
+	SuiteID     int64
1309
+	RepoID      int64
1310
+	HeadSha     string
1311
+	Name        string
1312
+	Status      CheckStatus
1313
+	Conclusion  NullCheckConclusion
1314
+	StartedAt   pgtype.Timestamptz
1315
+	CompletedAt pgtype.Timestamptz
1316
+	DetailsUrl  string
1317
+	Output      []byte
1318
+	ExternalID  pgtype.Text
1319
+	CreatedAt   pgtype.Timestamptz
1320
+	UpdatedAt   pgtype.Timestamptz
1321
+}
1322
+
1323
+type CheckSuite struct {
1324
+	ID         int64
1325
+	RepoID     int64
1326
+	HeadSha    string
1327
+	AppSlug    string
1328
+	Status     CheckStatus
1329
+	Conclusion NullCheckConclusion
1330
+	CreatedAt  pgtype.Timestamptz
1331
+	UpdatedAt  pgtype.Timestamptz
1332
+}
1333
+
1334
+type CodeSearchContent struct {
1335
+	RepoID      int64
1336
+	RefName     string
1337
+	Path        string
1338
+	ContentTsv  interface{}
1339
+	ContentTrgm string
1340
+}
1341
+
1342
+type CodeSearchPath struct {
1343
+	RepoID  int64
1344
+	RefName string
1345
+	Path    string
1346
+	Tsv     interface{}
1347
+}
1348
+
1349
+type DomainEvent struct {
1350
+	ID          int64
1351
+	ActorUserID pgtype.Int8
1352
+	Kind        string
1353
+	RepoID      pgtype.Int8
1354
+	SourceKind  string
1355
+	SourceID    int64
1356
+	Public      bool
1357
+	Payload     []byte
1358
+	CreatedAt   pgtype.Timestamptz
1359
+}
1360
+
1361
+type DomainEventsProcessed struct {
1362
+	Consumer    string
1363
+	LastEventID int64
1364
+	UpdatedAt   pgtype.Timestamptz
1365
+}
1366
+
1367
+type EmailVerification struct {
1368
+	ID          int64
1369
+	UserEmailID int64
1370
+	TokenHash   []byte
1371
+	ExpiresAt   pgtype.Timestamptz
1372
+	UsedAt      pgtype.Timestamptz
1373
+	CreatedAt   pgtype.Timestamptz
1374
+}
1375
+
1376
+type Issue struct {
1377
+	ID                int64
1378
+	RepoID            int64
1379
+	Number            int64
1380
+	Kind              IssueKind
1381
+	Title             string
1382
+	Body              string
1383
+	BodyHtmlCached    pgtype.Text
1384
+	MdPipelineVersion int32
1385
+	AuthorUserID      pgtype.Int8
1386
+	State             IssueState
1387
+	StateReason       NullIssueStateReason
1388
+	Locked            bool
1389
+	LockReason        pgtype.Text
1390
+	MilestoneID       pgtype.Int8
1391
+	CreatedAt         pgtype.Timestamptz
1392
+	UpdatedAt         pgtype.Timestamptz
1393
+	EditedAt          pgtype.Timestamptz
1394
+	ClosedAt          pgtype.Timestamptz
1395
+	ClosedByUserID    pgtype.Int8
1396
+}
1397
+
1398
+type IssueAssignee struct {
1399
+	IssueID          int64
1400
+	UserID           int64
1401
+	AssignedAt       pgtype.Timestamptz
1402
+	AssignedByUserID pgtype.Int8
1403
+}
1404
+
1405
+type IssueComment struct {
1406
+	ID                int64
1407
+	IssueID           int64
1408
+	AuthorUserID      pgtype.Int8
1409
+	Body              string
1410
+	BodyHtmlCached    pgtype.Text
1411
+	MdPipelineVersion int32
1412
+	CreatedAt         pgtype.Timestamptz
1413
+	UpdatedAt         pgtype.Timestamptz
1414
+	EditedAt          pgtype.Timestamptz
1415
+}
1416
+
1417
+type IssueEvent struct {
1418
+	ID          int64
1419
+	IssueID     int64
1420
+	ActorUserID pgtype.Int8
1421
+	Kind        string
1422
+	Meta        []byte
1423
+	RefTargetID pgtype.Int8
1424
+	CreatedAt   pgtype.Timestamptz
1425
+}
1426
+
1427
+type IssueLabel struct {
1428
+	IssueID         int64
1429
+	LabelID         int64
1430
+	AppliedAt       pgtype.Timestamptz
1431
+	AppliedByUserID pgtype.Int8
1432
+}
1433
+
1434
+type IssueReference struct {
1435
+	ID             int64
1436
+	SourceIssueID  pgtype.Int8
1437
+	TargetIssueID  int64
1438
+	SourceKind     IssueRefSource
1439
+	SourceObjectID pgtype.Int8
1440
+	CreatedAt      pgtype.Timestamptz
1441
+}
1442
+
1443
+type IssuesSearch struct {
1444
+	IssueID      int64
1445
+	RepoID       int64
1446
+	Kind         IssueKind
1447
+	State        IssueState
1448
+	AuthorUserID pgtype.Int8
1449
+	Tsv          interface{}
1450
+}
1451
+
1452
+type Job struct {
1453
+	ID          int64
1454
+	Kind        string
1455
+	Payload     []byte
1456
+	RunAt       pgtype.Timestamptz
1457
+	Attempts    int32
1458
+	MaxAttempts int32
1459
+	LastError   pgtype.Text
1460
+	LockedBy    pgtype.Text
1461
+	LockedAt    pgtype.Timestamptz
1462
+	CompletedAt pgtype.Timestamptz
1463
+	FailedAt    pgtype.Timestamptz
1464
+	CreatedAt   pgtype.Timestamptz
1465
+}
1466
+
1467
+type Label struct {
1468
+	ID          int64
1469
+	RepoID      int64
1470
+	Name        string
1471
+	Color       string
1472
+	Description string
1473
+	CreatedAt   pgtype.Timestamptz
1474
+}
1475
+
1476
+type Meta struct {
1477
+	Key       string
1478
+	Value     []byte
1479
+	UpdatedAt pgtype.Timestamptz
1480
+}
1481
+
1482
+type Milestone struct {
1483
+	ID          int64
1484
+	RepoID      int64
1485
+	Title       string
1486
+	Description string
1487
+	State       MilestoneState
1488
+	DueOn       pgtype.Timestamptz
1489
+	CreatedAt   pgtype.Timestamptz
1490
+	ClosedAt    pgtype.Timestamptz
1491
+}
1492
+
1493
+type Notification struct {
1494
+	ID              int64
1495
+	RecipientUserID int64
1496
+	Kind            string
1497
+	Reason          string
1498
+	RepoID          pgtype.Int8
1499
+	ThreadKind      NullNotificationThreadKind
1500
+	ThreadID        pgtype.Int8
1501
+	SourceEventID   pgtype.Int8
1502
+	Unread          bool
1503
+	LastEventAt     pgtype.Timestamptz
1504
+	LastActorUserID pgtype.Int8
1505
+	Summary         []byte
1506
+	CreatedAt       pgtype.Timestamptz
1507
+	UpdatedAt       pgtype.Timestamptz
1508
+}
1509
+
1510
+type NotificationEmailLog struct {
1511
+	ID              int64
1512
+	RecipientUserID int64
1513
+	NotificationID  pgtype.Int8
1514
+	ThreadKind      NullNotificationThreadKind
1515
+	ThreadID        pgtype.Int8
1516
+	SentAt          pgtype.Timestamptz
1517
+	MessageID       pgtype.Text
1518
+}
1519
+
1520
+type NotificationThread struct {
1521
+	RecipientUserID int64
1522
+	ThreadKind      NotificationThreadKind
1523
+	ThreadID        int64
1524
+	Subscribed      bool
1525
+	Reason          string
1526
+	UpdatedAt       pgtype.Timestamptz
1527
+}
1528
+
1529
+type Org struct {
1530
+	ID                    int64
1531
+	Slug                  string
1532
+	DisplayName           string
1533
+	Description           string
1534
+	AvatarObjectKey       pgtype.Text
1535
+	Location              string
1536
+	Website               string
1537
+	BillingEmail          string
1538
+	Plan                  OrgPlan
1539
+	AllowMemberRepoCreate bool
1540
+	CreatedByUserID       pgtype.Int8
1541
+	SuspendedAt           pgtype.Timestamptz
1542
+	SuspendedReason       pgtype.Text
1543
+	DeletedAt             pgtype.Timestamptz
1544
+	CreatedAt             pgtype.Timestamptz
1545
+	UpdatedAt             pgtype.Timestamptz
1546
+}
1547
+
1548
+type OrgInvitation struct {
1549
+	ID              int64
1550
+	OrgID           int64
1551
+	InvitedByUserID pgtype.Int8
1552
+	TargetUserID    pgtype.Int8
1553
+	TargetEmail     pgtype.Text
1554
+	Role            OrgRole
1555
+	TokenHash       []byte
1556
+	ExpiresAt       pgtype.Timestamptz
1557
+	AcceptedAt      pgtype.Timestamptz
1558
+	DeclinedAt      pgtype.Timestamptz
1559
+	CanceledAt      pgtype.Timestamptz
1560
+	CreatedAt       pgtype.Timestamptz
1561
+}
1562
+
1563
+type OrgMember struct {
1564
+	OrgID           int64
1565
+	UserID          int64
1566
+	Role            OrgRole
1567
+	InvitedByUserID pgtype.Int8
1568
+	JoinedAt        pgtype.Timestamptz
1569
+}
1570
+
1571
+type PasswordReset struct {
1572
+	ID        int64
1573
+	UserID    int64
1574
+	TokenHash []byte
1575
+	ExpiresAt pgtype.Timestamptz
1576
+	UsedAt    pgtype.Timestamptz
1577
+	CreatedAt pgtype.Timestamptz
1578
+}
1579
+
1580
+type PrReview struct {
1581
+	ID                int64
1582
+	PrIssueID         int64
1583
+	AuthorUserID      pgtype.Int8
1584
+	State             PrReviewState
1585
+	Body              string
1586
+	BodyHtmlCached    pgtype.Text
1587
+	SubmittedAt       pgtype.Timestamptz
1588
+	DismissedAt       pgtype.Timestamptz
1589
+	DismissedByUserID pgtype.Int8
1590
+	DismissalReason   string
1591
+}
1592
+
1593
+type PrReviewComment struct {
1594
+	ID                int64
1595
+	PrIssueID         int64
1596
+	ReviewID          pgtype.Int8
1597
+	AuthorUserID      pgtype.Int8
1598
+	FilePath          string
1599
+	Side              PrReviewSide
1600
+	OriginalCommitSha string
1601
+	OriginalLine      int32
1602
+	OriginalPosition  int32
1603
+	CurrentPosition   pgtype.Int4
1604
+	Body              string
1605
+	BodyHtmlCached    pgtype.Text
1606
+	InReplyToID       pgtype.Int8
1607
+	Pending           bool
1608
+	ResolvedAt        pgtype.Timestamptz
1609
+	ResolvedByUserID  pgtype.Int8
1610
+	CreatedAt         pgtype.Timestamptz
1611
+	UpdatedAt         pgtype.Timestamptz
1612
+	EditedAt          pgtype.Timestamptz
1613
+}
1614
+
1615
+type PrReviewRequest struct {
1616
+	ID                  int64
1617
+	PrIssueID           int64
1618
+	RequestedUserID     pgtype.Int8
1619
+	RequestedTeamID     pgtype.Int8
1620
+	RequestedByUserID   pgtype.Int8
1621
+	RequestedAt         pgtype.Timestamptz
1622
+	DismissedAt         pgtype.Timestamptz
1623
+	SatisfiedByReviewID pgtype.Int8
1624
+}
1625
+
1626
+type Principal struct {
1627
+	Slug string
1628
+	Kind PrincipalKind
1629
+	ID   int64
1630
+}
1631
+
1632
+type PullRequest struct {
1633
+	IssueID            int64
1634
+	BaseRef            string
1635
+	HeadRef            string
1636
+	HeadRepoID         int64
1637
+	BaseOid            string
1638
+	HeadOid            string
1639
+	Draft              bool
1640
+	Mergeable          pgtype.Bool
1641
+	MergeableState     PrMergeableState
1642
+	MergeCommitSha     pgtype.Text
1643
+	MergedAt           pgtype.Timestamptz
1644
+	MergedByUserID     pgtype.Int8
1645
+	MergeMethod        NullPrMergeMethod
1646
+	BaseOidAtMerge     pgtype.Text
1647
+	HeadOidAtMerge     pgtype.Text
1648
+	LastSynchronizedAt pgtype.Timestamptz
1649
+}
1650
+
1651
+type PullRequestCommit struct {
1652
+	PrID           int64
1653
+	Sha            string
1654
+	Position       int32
1655
+	AuthorName     string
1656
+	AuthorEmail    string
1657
+	CommitterName  string
1658
+	CommitterEmail string
1659
+	Subject        string
1660
+	Body           string
1661
+	AuthoredAt     pgtype.Timestamptz
1662
+	CommittedAt    pgtype.Timestamptz
1663
+}
1664
+
1665
+type PullRequestFile struct {
1666
+	PrID      int64
1667
+	Path      string
1668
+	Status    PrFileStatus
1669
+	OldPath   pgtype.Text
1670
+	Additions int32
1671
+	Deletions int32
1672
+	Changes   int32
1673
+}
1674
+
1675
+type PushEvent struct {
1676
+	ID           int64
1677
+	RepoID       int64
1678
+	PusherUserID pgtype.Int8
1679
+	BeforeSha    string
1680
+	AfterSha     string
1681
+	Ref          string
1682
+	Protocol     string
1683
+	RequestID    string
1684
+	ProcessedAt  pgtype.Timestamptz
1685
+	CreatedAt    pgtype.Timestamptz
1686
+}
1687
+
1688
+type RateLimit struct {
1689
+	Scope           string
1690
+	Key             string
1691
+	Hits            int32
1692
+	WindowStartedAt pgtype.Timestamptz
1693
+}
1694
+
1695
+type Repo struct {
1696
+	ID                 int64
1697
+	OwnerUserID        pgtype.Int8
1698
+	OwnerOrgID         pgtype.Int8
1699
+	Name               string
1700
+	Description        string
1701
+	Visibility         RepoVisibility
1702
+	DefaultBranch      string
1703
+	IsArchived         bool
1704
+	ArchivedAt         pgtype.Timestamptz
1705
+	DeletedAt          pgtype.Timestamptz
1706
+	DiskUsedBytes      int64
1707
+	ForkOfRepoID       pgtype.Int8
1708
+	LicenseKey         pgtype.Text
1709
+	PrimaryLanguage    pgtype.Text
1710
+	HasIssues          bool
1711
+	HasPulls           bool
1712
+	CreatedAt          pgtype.Timestamptz
1713
+	UpdatedAt          pgtype.Timestamptz
1714
+	DefaultBranchOid   pgtype.Text
1715
+	AllowSquashMerge   bool
1716
+	AllowRebaseMerge   bool
1717
+	AllowMergeCommit   bool
1718
+	DefaultMergeMethod PrMergeMethod
1719
+	StarCount          int64
1720
+	WatcherCount       int64
1721
+	ForkCount          int64
1722
+	InitStatus         RepoInitStatus
1723
+	LastIndexedOid     pgtype.Text
1724
+}
1725
+
1726
+type RepoCollaborator struct {
1727
+	RepoID        int64
1728
+	UserID        int64
1729
+	Role          CollabRole
1730
+	AddedAt       pgtype.Timestamptz
1731
+	AddedByUserID pgtype.Int8
1732
+}
1733
+
1734
+type RepoIssueCounter struct {
1735
+	RepoID     int64
1736
+	NextNumber int64
1737
+}
1738
+
1739
+type RepoRedirect struct {
1740
+	OldOwnerUserID pgtype.Int8
1741
+	OldOwnerOrgID  pgtype.Int8
1742
+	OldName        string
1743
+	RepoID         int64
1744
+	RedirectedAt   pgtype.Timestamptz
1745
+}
1746
+
1747
+type RepoTopic struct {
1748
+	RepoID    int64
1749
+	Topic     string
1750
+	CreatedAt pgtype.Timestamptz
1751
+}
1752
+
1753
+type RepoTransferRequest struct {
1754
+	ID              int64
1755
+	RepoID          int64
1756
+	FromUserID      int64
1757
+	ToPrincipalKind TransferPrincipalKind
1758
+	ToPrincipalID   int64
1759
+	CreatedBy       int64
1760
+	CreatedAt       pgtype.Timestamptz
1761
+	ExpiresAt       pgtype.Timestamptz
1762
+	Status          TransferStatus
1763
+	AcceptedAt      pgtype.Timestamptz
1764
+	DeclinedAt      pgtype.Timestamptz
1765
+	CanceledAt      pgtype.Timestamptz
1766
+}
1767
+
1768
+type ReposSearch struct {
1769
+	RepoID int64
1770
+	Tsv    interface{}
1771
+}
1772
+
1773
+type SignupIpThrottle struct {
1774
+	Cidr            netip.Addr
1775
+	Hits            int32
1776
+	WindowStartedAt pgtype.Timestamptz
1777
+}
1778
+
1779
+type Star struct {
1780
+	UserID    int64
1781
+	RepoID    int64
1782
+	StarredAt pgtype.Timestamptz
1783
+}
1784
+
1785
+type Team struct {
1786
+	ID              int64
1787
+	OrgID           int64
1788
+	Slug            string
1789
+	DisplayName     string
1790
+	Description     string
1791
+	ParentTeamID    pgtype.Int8
1792
+	Privacy         TeamPrivacy
1793
+	CreatedByUserID pgtype.Int8
1794
+	CreatedAt       pgtype.Timestamptz
1795
+	UpdatedAt       pgtype.Timestamptz
1796
+}
1797
+
1798
+type TeamMember struct {
1799
+	TeamID        int64
1800
+	UserID        int64
1801
+	Role          TeamRole
1802
+	AddedByUserID pgtype.Int8
1803
+	AddedAt       pgtype.Timestamptz
1804
+}
1805
+
1806
+type TeamRepoAccess struct {
1807
+	TeamID        int64
1808
+	RepoID        int64
1809
+	Role          TeamRepoRole
1810
+	AddedByUserID pgtype.Int8
1811
+	AddedAt       pgtype.Timestamptz
1812
+}
1813
+
1814
+type TransactionalEmailLog struct {
1815
+	ID              int64
1816
+	RecipientUserID pgtype.Int8
1817
+	RecipientEmail  string
1818
+	Kind            string
1819
+	Subject         string
1820
+	ProviderID      string
1821
+	Status          TransactionalEmailStatus
1822
+	ErrorSummary    pgtype.Text
1823
+	SentAt          pgtype.Timestamptz
1824
+	DeliveredAt     pgtype.Timestamptz
1825
+}
1826
+
1827
+type User struct {
1828
+	ID                int64
1829
+	Username          string
1830
+	DisplayName       string
1831
+	PrimaryEmailID    pgtype.Int8
1832
+	PasswordHash      string
1833
+	PasswordAlgo      string
1834
+	PasswordUpdatedAt pgtype.Timestamptz
1835
+	EmailVerified     bool
1836
+	LastLoginAt       pgtype.Timestamptz
1837
+	SuspendedAt       pgtype.Timestamptz
1838
+	SuspendedReason   pgtype.Text
1839
+	DeletedAt         pgtype.Timestamptz
1840
+	CreatedAt         pgtype.Timestamptz
1841
+	UpdatedAt         pgtype.Timestamptz
1842
+	Bio               string
1843
+	Location          string
1844
+	Website           string
1845
+	Company           string
1846
+	Pronouns          string
1847
+	AvatarObjectKey   pgtype.Text
1848
+	Theme             string
1849
+	SessionEpoch      int32
1850
+	IsSiteAdmin       bool
1851
+}
1852
+
1853
+type UserEmail struct {
1854
+	ID                    int64
1855
+	UserID                int64
1856
+	Email                 string
1857
+	IsPrimary             bool
1858
+	Verified              bool
1859
+	VerificationTokenHash []byte
1860
+	VerificationSentAt    pgtype.Timestamptz
1861
+	VerifiedAt            pgtype.Timestamptz
1862
+	CreatedAt             pgtype.Timestamptz
1863
+}
1864
+
1865
+type UserNotificationPref struct {
1866
+	UserID    int64
1867
+	Key       string
1868
+	Value     []byte
1869
+	UpdatedAt pgtype.Timestamptz
1870
+}
1871
+
1872
+type UserRecoveryCode struct {
1873
+	ID          int64
1874
+	UserID      int64
1875
+	CodeHash    []byte
1876
+	UsedAt      pgtype.Timestamptz
1877
+	GeneratedAt pgtype.Timestamptz
1878
+	CreatedAt   pgtype.Timestamptz
1879
+}
1880
+
1881
+type UserSshKey struct {
1882
+	ID                int64
1883
+	UserID            int64
1884
+	Title             string
1885
+	FingerprintSha256 string
1886
+	KeyType           string
1887
+	KeyBits           int32
1888
+	PublicKey         string
1889
+	LastUsedAt        pgtype.Timestamptz
1890
+	LastUsedIp        *netip.Addr
1891
+	CreatedAt         pgtype.Timestamptz
1892
+}
1893
+
1894
+type UserToken struct {
1895
+	ID          int64
1896
+	UserID      int64
1897
+	Name        string
1898
+	TokenHash   []byte
1899
+	TokenPrefix string
1900
+	Scopes      []string
1901
+	ExpiresAt   pgtype.Timestamptz
1902
+	LastUsedAt  pgtype.Timestamptz
1903
+	LastUsedIp  *netip.Addr
1904
+	RevokedAt   pgtype.Timestamptz
1905
+	CreatedAt   pgtype.Timestamptz
1906
+}
1907
+
1908
+type UserTotp struct {
1909
+	ID              int64
1910
+	UserID          int64
1911
+	SecretEncrypted []byte
1912
+	SecretNonce     []byte
1913
+	ConfirmedAt     pgtype.Timestamptz
1914
+	LastUsedCounter int64
1915
+	CreatedAt       pgtype.Timestamptz
1916
+	UpdatedAt       pgtype.Timestamptz
1917
+}
1918
+
1919
+type UsernameRedirect struct {
1920
+	OldUsername string
1921
+	UserID      int64
1922
+	ChangedAt   pgtype.Timestamptz
1923
+}
1924
+
1925
+type UsersSearch struct {
1926
+	UserID int64
1927
+	Tsv    interface{}
1928
+}
1929
+
1930
+type Watch struct {
1931
+	UserID    int64
1932
+	RepoID    int64
1933
+	Level     WatchLevel
1934
+	UpdatedAt pgtype.Timestamptz
1935
+}
1936
+
1937
+type Webhook struct {
1938
+	ID                   int64
1939
+	OwnerKind            WebhookOwnerKind
1940
+	OwnerID              int64
1941
+	Url                  string
1942
+	ContentType          WebhookContentType
1943
+	Events               []string
1944
+	SecretCiphertext     []byte
1945
+	SecretNonce          []byte
1946
+	Active               bool
1947
+	SslVerification      bool
1948
+	ConsecutiveFailures  int32
1949
+	AutoDisableThreshold int32
1950
+	DisabledAt           pgtype.Timestamptz
1951
+	DisabledReason       pgtype.Text
1952
+	LastSuccessAt        pgtype.Timestamptz
1953
+	LastFailureAt        pgtype.Timestamptz
1954
+	CreatedByUserID      pgtype.Int8
1955
+	CreatedAt            pgtype.Timestamptz
1956
+	UpdatedAt            pgtype.Timestamptz
1957
+}
1958
+
1959
+type WebhookDelivery struct {
1960
+	ID                int64
1961
+	WebhookID         int64
1962
+	EventKind         string
1963
+	EventID           pgtype.Int8
1964
+	DeliveryUuid      pgtype.UUID
1965
+	Payload           []byte
1966
+	RequestHeaders    []byte
1967
+	RequestBody       []byte
1968
+	ResponseStatus    pgtype.Int4
1969
+	ResponseHeaders   []byte
1970
+	ResponseBody      []byte
1971
+	ResponseTruncated bool
1972
+	StartedAt         pgtype.Timestamptz
1973
+	CompletedAt       pgtype.Timestamptz
1974
+	Attempt           int32
1975
+	MaxAttempts       int32
1976
+	NextRetryAt       pgtype.Timestamptz
1977
+	Status            WebhookDeliveryStatus
1978
+	IdempotencyKey    string
1979
+	ErrorSummary      pgtype.Text
1980
+	RedeliverOf       pgtype.Int8
1981
+}
1982
+
1983
+type WebhookEventsPending struct {
1984
+	ID        int64
1985
+	RepoID    int64
1986
+	EventKind string
1987
+	Payload   []byte
1988
+	CreatedAt pgtype.Timestamptz
1989
+}
internal/ratelimit/sqlc/querier.goadded
@@ -0,0 +1,39 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+
5
+package ratelimitdb
6
+
7
+import (
8
+	"context"
9
+
10
+	"github.com/jackc/pgx/v5/pgtype"
11
+)
12
+
13
+type Querier interface {
14
+	// SPDX-License-Identifier: AGPL-3.0-or-later
15
+	//
16
+	// Generic rate-limit counter queries (S35). Two write paths:
17
+	//   * BumpRateLimit — atomic UPSERT that rolls the window forward
18
+	//                     when stale, increments hits otherwise. Returns
19
+	//                     the post-update hits + window_started_at so
20
+	//                     the caller can compute Retry-After without a
21
+	//                     second round trip.
22
+	//   * BumpSignupIPThrottle — same shape against signup_ip_throttle
23
+	//                            keyed by inet/CIDR.
24
+	//
25
+	// Reads (PeekRateLimit, PeekSignupIPThrottle) are kept around for
26
+	// the admin observability surface; the hot path uses Bump-and-decide.
27
+	// Roll-or-increment in one statement. The CASE in the UPDATE branch
28
+	// handles the window roll: when the existing window started before
29
+	// (now - $3 interval), we treat it as a new window and reset hits
30
+	// to 1; otherwise we increment in place.
31
+	BumpRateLimit(ctx context.Context, db DBTX, arg BumpRateLimitParams) (BumpRateLimitRow, error)
32
+	// Same UPSERT shape against the inet-keyed signup throttle.
33
+	BumpSignupIPThrottle(ctx context.Context, db DBTX, arg BumpSignupIPThrottleParams) (BumpSignupIPThrottleRow, error)
34
+	PeekRateLimit(ctx context.Context, db DBTX, arg PeekRateLimitParams) (RateLimit, error)
35
+	PruneRateLimits(ctx context.Context, db DBTX, retention pgtype.Interval) (int64, error)
36
+	PruneSignupIPThrottle(ctx context.Context, db DBTX, retention pgtype.Interval) (int64, error)
37
+}
38
+
39
+var _ Querier = (*Queries)(nil)
internal/ratelimit/sqlc/rate_limits.sql.goadded
@@ -0,0 +1,152 @@
1
+// Code generated by sqlc. DO NOT EDIT.
2
+// versions:
3
+//   sqlc v1.31.1
4
+// source: rate_limits.sql
5
+
6
+package ratelimitdb
7
+
8
+import (
9
+	"context"
10
+	"net/netip"
11
+
12
+	"github.com/jackc/pgx/v5/pgtype"
13
+)
14
+
15
+const bumpRateLimit = `-- name: BumpRateLimit :one
16
+
17
+INSERT INTO rate_limits (scope, key, hits, window_started_at)
18
+VALUES ($1, $2, 1, now())
19
+ON CONFLICT (scope, key)
20
+DO UPDATE SET
21
+    hits              = CASE
22
+                          WHEN rate_limits.window_started_at < now() - $3::interval
23
+                          THEN 1
24
+                          ELSE rate_limits.hits + 1
25
+                        END,
26
+    window_started_at = CASE
27
+                          WHEN rate_limits.window_started_at < now() - $3::interval
28
+                          THEN now()
29
+                          ELSE rate_limits.window_started_at
30
+                        END
31
+RETURNING hits, window_started_at
32
+`
33
+
34
+type BumpRateLimitParams struct {
35
+	Scope string
36
+	Key   string
37
+	Ttl   pgtype.Interval
38
+}
39
+
40
+type BumpRateLimitRow struct {
41
+	Hits            int32
42
+	WindowStartedAt pgtype.Timestamptz
43
+}
44
+
45
+// SPDX-License-Identifier: AGPL-3.0-or-later
46
+//
47
+// Generic rate-limit counter queries (S35). Two write paths:
48
+//   - BumpRateLimit — atomic UPSERT that rolls the window forward
49
+//     when stale, increments hits otherwise. Returns
50
+//     the post-update hits + window_started_at so
51
+//     the caller can compute Retry-After without a
52
+//     second round trip.
53
+//   - BumpSignupIPThrottle — same shape against signup_ip_throttle
54
+//     keyed by inet/CIDR.
55
+//
56
+// Reads (PeekRateLimit, PeekSignupIPThrottle) are kept around for
57
+// the admin observability surface; the hot path uses Bump-and-decide.
58
+// Roll-or-increment in one statement. The CASE in the UPDATE branch
59
+// handles the window roll: when the existing window started before
60
+// (now - $3 interval), we treat it as a new window and reset hits
61
+// to 1; otherwise we increment in place.
62
+func (q *Queries) BumpRateLimit(ctx context.Context, db DBTX, arg BumpRateLimitParams) (BumpRateLimitRow, error) {
63
+	row := db.QueryRow(ctx, bumpRateLimit, arg.Scope, arg.Key, arg.Ttl)
64
+	var i BumpRateLimitRow
65
+	err := row.Scan(&i.Hits, &i.WindowStartedAt)
66
+	return i, err
67
+}
68
+
69
+const bumpSignupIPThrottle = `-- name: BumpSignupIPThrottle :one
70
+INSERT INTO signup_ip_throttle (cidr, hits, window_started_at)
71
+VALUES ($1, 1, now())
72
+ON CONFLICT (cidr)
73
+DO UPDATE SET
74
+    hits              = CASE
75
+                          WHEN signup_ip_throttle.window_started_at < now() - $2::interval
76
+                          THEN 1
77
+                          ELSE signup_ip_throttle.hits + 1
78
+                        END,
79
+    window_started_at = CASE
80
+                          WHEN signup_ip_throttle.window_started_at < now() - $2::interval
81
+                          THEN now()
82
+                          ELSE signup_ip_throttle.window_started_at
83
+                        END
84
+RETURNING hits, window_started_at
85
+`
86
+
87
+type BumpSignupIPThrottleParams struct {
88
+	Cidr netip.Addr
89
+	Ttl  pgtype.Interval
90
+}
91
+
92
+type BumpSignupIPThrottleRow struct {
93
+	Hits            int32
94
+	WindowStartedAt pgtype.Timestamptz
95
+}
96
+
97
+// Same UPSERT shape against the inet-keyed signup throttle.
98
+func (q *Queries) BumpSignupIPThrottle(ctx context.Context, db DBTX, arg BumpSignupIPThrottleParams) (BumpSignupIPThrottleRow, error) {
99
+	row := db.QueryRow(ctx, bumpSignupIPThrottle, arg.Cidr, arg.Ttl)
100
+	var i BumpSignupIPThrottleRow
101
+	err := row.Scan(&i.Hits, &i.WindowStartedAt)
102
+	return i, err
103
+}
104
+
105
+const peekRateLimit = `-- name: PeekRateLimit :one
106
+SELECT scope, key, hits, window_started_at
107
+FROM rate_limits
108
+WHERE scope = $1 AND key = $2
109
+`
110
+
111
+type PeekRateLimitParams struct {
112
+	Scope string
113
+	Key   string
114
+}
115
+
116
+func (q *Queries) PeekRateLimit(ctx context.Context, db DBTX, arg PeekRateLimitParams) (RateLimit, error) {
117
+	row := db.QueryRow(ctx, peekRateLimit, arg.Scope, arg.Key)
118
+	var i RateLimit
119
+	err := row.Scan(
120
+		&i.Scope,
121
+		&i.Key,
122
+		&i.Hits,
123
+		&i.WindowStartedAt,
124
+	)
125
+	return i, err
126
+}
127
+
128
+const pruneRateLimits = `-- name: PruneRateLimits :execrows
129
+DELETE FROM rate_limits
130
+WHERE window_started_at < now() - $1::interval
131
+`
132
+
133
+func (q *Queries) PruneRateLimits(ctx context.Context, db DBTX, retention pgtype.Interval) (int64, error) {
134
+	result, err := db.Exec(ctx, pruneRateLimits, retention)
135
+	if err != nil {
136
+		return 0, err
137
+	}
138
+	return result.RowsAffected(), nil
139
+}
140
+
141
+const pruneSignupIPThrottle = `-- name: PruneSignupIPThrottle :execrows
142
+DELETE FROM signup_ip_throttle
143
+WHERE window_started_at < now() - $1::interval
144
+`
145
+
146
+func (q *Queries) PruneSignupIPThrottle(ctx context.Context, db DBTX, retention pgtype.Interval) (int64, error) {
147
+	result, err := db.Exec(ctx, pruneSignupIPThrottle, retention)
148
+	if err != nil {
149
+		return 0, err
150
+	}
151
+	return result.RowsAffected(), nil
152
+}
sqlc.yamlmodified
@@ -209,3 +209,19 @@ sql:
209209
         emit_exact_table_names: false
210210
         emit_empty_slices: true
211211
         emit_methods_with_db_argument: true
212
+
213
+  - engine: postgresql
214
+    schema: internal/migrationsfs/migrations
215
+    queries: internal/ratelimit/queries
216
+    gen:
217
+      go:
218
+        package: ratelimitdb
219
+        out: internal/ratelimit/sqlc
220
+        sql_package: pgx/v5
221
+        emit_json_tags: false
222
+        emit_pointers_for_null_types: false
223
+        emit_prepared_queries: false
224
+        emit_interface: true
225
+        emit_exact_table_names: false
226
+        emit_empty_slices: true
227
+        emit_methods_with_db_argument: true