History

Fix migration 0008 parser stack overflow on macOS bun:sqlite (#745)

* Fix migration 0008 parser stack overflow on macOS bun:sqlite Migration 0008 inlined a 41-deep nested replace() chain (8 dash-collapse replaces wrapping lower(33 single-char replaces wrapping the raw input)) to slugify header names into slot_keys. Bun's lemon SQL parser stack overflows at PREPARE time on the compiled CLI binary on macOS, so users upgrading on Mac couldn't start the CLI at all (the Linux test matrix in CI never exercised the failing path). Replace the deep chain with a temp __slug_norm table populated once at the top of the migration via a series of shallow UPDATE statements (one per replacement), then reference the precomputed slug via flat scalar subqueries everywhere. Semantics verified equivalent against 25 inputs covering case, punctuation, whitespace, dashes-only and unicode. Add structural lint that scans every drizzle migration file and rejects any nested-function call > 20 deep. Catches the regression class on Linux CI without needing macOS in the matrix. * Drop changeset, swap throw for typed expect to satisfy oxlint - Remove .changeset/fix-migration-0008-parser-overflow.md: the existing .changeset/executor-1.4.16.md (still in main, consumed when the open Version Packages PR merges) is enough to ship 1.4.16 with this fix included. - Replace throw new Error(...) in migration-nesting.test.ts with a shaped expect(...).toEqual({...}) that prints file/line/fn/depth in the diff. Satisfies oxlint's no-error-constructor / no-try-catch-or-throw rules without losing the diagnostic.

Rhys Sullivan committed 6 months ago

Commit baf3bd41 parent 69af8b82 files · +228 −34Browse files

Unified · Split

2 files
  1. apps/local/drizzle/0008_scoped_credentials_cutover.sql +120 −34
  2. apps/local/src/server/migration-nesting.test.ts +108 −0
apps/local/drizzle/0008_scoped_credentials_cutover.sql+120−34
@@ -1,3 +1,86 @@
1--
2-- Slug-normalization staging table.
3--
4-- 0008 originally inlined a 41-deep `replace(replace(... lower(...) ...))`
5-- chain everywhere it derived a slot_key from a header / param / oauth
6-- scheme name. bun:sqlite's lemon parser stack overflows on that depth on
7-- platforms with smaller thread stacks (notably the compiled CLI binary on
8-- macOS), so we precompute slugs once into a temp table and reference them
9-- via flat scalar subqueries below.
10--
11CREATE TEMP TABLE `__slug_norm` (
12 `raw` text PRIMARY KEY,
13 `slug` text NOT NULL DEFAULT ''
14);--> statement-breakpoint
15
16INSERT OR IGNORE INTO `__slug_norm` (`raw`)
17SELECT DISTINCT `raw` FROM (
18 SELECT h.`key` AS `raw` FROM `openapi_source` s, json_each(s.`headers`) h
19 WHERE s.`headers` IS NOT NULL AND h.`type` = 'object'
20 UNION
21 SELECT json_extract(s.`oauth2`, '$.securitySchemeName') FROM `openapi_source` s
22 WHERE s.`oauth2` IS NOT NULL
23 UNION
24 SELECT `name` FROM `openapi_source_query_param` WHERE `name` IS NOT NULL
25 UNION
26 SELECT `name` FROM `openapi_source_spec_fetch_header` WHERE `name` IS NOT NULL
27 UNION
28 SELECT `name` FROM `openapi_source_spec_fetch_query_param` WHERE `name` IS NOT NULL
29 UNION
30 SELECT `name` FROM `graphql_source_header` WHERE `name` IS NOT NULL
31 UNION
32 SELECT `name` FROM `graphql_source_query_param` WHERE `name` IS NOT NULL
33 UNION
34 SELECT `name` FROM `mcp_source_header` WHERE `name` IS NOT NULL
35 UNION
36 SELECT `name` FROM `mcp_source_query_param` WHERE `name` IS NOT NULL
37) WHERE `raw` IS NOT NULL AND `raw` != '';--> statement-breakpoint
38
39UPDATE `__slug_norm` SET `slug` = lower(trim(`raw`));--> statement-breakpoint
40UPDATE `__slug_norm` SET `slug` = replace(`slug`, char(9), '-');--> statement-breakpoint
41UPDATE `__slug_norm` SET `slug` = replace(`slug`, char(10), '-');--> statement-breakpoint
42UPDATE `__slug_norm` SET `slug` = replace(`slug`, char(13), '-');--> statement-breakpoint
43UPDATE `__slug_norm` SET `slug` = replace(`slug`, ' ', '-');--> statement-breakpoint
44UPDATE `__slug_norm` SET `slug` = replace(`slug`, '_', '-');--> statement-breakpoint
45UPDATE `__slug_norm` SET `slug` = replace(`slug`, '.', '-');--> statement-breakpoint
46UPDATE `__slug_norm` SET `slug` = replace(`slug`, ':', '-');--> statement-breakpoint
47UPDATE `__slug_norm` SET `slug` = replace(`slug`, '/', '-');--> statement-breakpoint
48UPDATE `__slug_norm` SET `slug` = replace(`slug`, '@', '-');--> statement-breakpoint
49UPDATE `__slug_norm` SET `slug` = replace(`slug`, '+', '-');--> statement-breakpoint
50UPDATE `__slug_norm` SET `slug` = replace(`slug`, '&', '-');--> statement-breakpoint
51UPDATE `__slug_norm` SET `slug` = replace(`slug`, '?', '-');--> statement-breakpoint
52UPDATE `__slug_norm` SET `slug` = replace(`slug`, '#', '-');--> statement-breakpoint
53UPDATE `__slug_norm` SET `slug` = replace(`slug`, '%', '-');--> statement-breakpoint
54UPDATE `__slug_norm` SET `slug` = replace(`slug`, '$', '-');--> statement-breakpoint
55UPDATE `__slug_norm` SET `slug` = replace(`slug`, ',', '-');--> statement-breakpoint
56UPDATE `__slug_norm` SET `slug` = replace(`slug`, ';', '-');--> statement-breakpoint
57UPDATE `__slug_norm` SET `slug` = replace(`slug`, '(', '-');--> statement-breakpoint
58UPDATE `__slug_norm` SET `slug` = replace(`slug`, ')', '-');--> statement-breakpoint
59UPDATE `__slug_norm` SET `slug` = replace(`slug`, '[', '-');--> statement-breakpoint
60UPDATE `__slug_norm` SET `slug` = replace(`slug`, ']', '-');--> statement-breakpoint
61UPDATE `__slug_norm` SET `slug` = replace(`slug`, '{', '-');--> statement-breakpoint
62UPDATE `__slug_norm` SET `slug` = replace(`slug`, '}', '-');--> statement-breakpoint
63UPDATE `__slug_norm` SET `slug` = replace(`slug`, '=', '-');--> statement-breakpoint
64UPDATE `__slug_norm` SET `slug` = replace(`slug`, '~', '-');--> statement-breakpoint
65UPDATE `__slug_norm` SET `slug` = replace(`slug`, '!', '-');--> statement-breakpoint
66UPDATE `__slug_norm` SET `slug` = replace(`slug`, char(34), '-');--> statement-breakpoint
67UPDATE `__slug_norm` SET `slug` = replace(`slug`, char(39), '-');--> statement-breakpoint
68UPDATE `__slug_norm` SET `slug` = replace(`slug`, char(92), '-');--> statement-breakpoint
69UPDATE `__slug_norm` SET `slug` = replace(`slug`, '|', '-');--> statement-breakpoint
70UPDATE `__slug_norm` SET `slug` = replace(`slug`, '*', '-');--> statement-breakpoint
71UPDATE `__slug_norm` SET `slug` = replace(`slug`, '<', '-');--> statement-breakpoint
72UPDATE `__slug_norm` SET `slug` = replace(`slug`, '>', '-');--> statement-breakpoint
73UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
74UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
75UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
76UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
77UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
78UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
79UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
80UPDATE `__slug_norm` SET `slug` = replace(`slug`, '--', '-');--> statement-breakpoint
81UPDATE `__slug_norm` SET `slug` = trim(`slug`, '-');--> statement-breakpoint
82UPDATE `__slug_norm` SET `slug` = CASE WHEN `slug` = '' THEN 'default' ELSE `slug` END;--> statement-breakpoint
83
1-- local scoped credential/source-slot/OAuth cutover.84-- local scoped credential/source-slot/OAuth cutover.
2-- Squashes the PR-local migration chain into one runtime schema transition.85-- Squashes the PR-local migration chain into one runtime schema transition.
3-- 0008_add_credential_binding.sql86-- 0008_add_credential_binding.sql
@@ -101,7 +184,7 @@ INSERT INTO `__openapi_header_slot_preflight` (`scope_id`, `source_id`, `slot_ke · 97 unmodified lines
101SELECT184SELECT
102 s.`scope_id`,185 s.`scope_id`,
103 s.`id`,186 s.`id`,
104 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`187 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default') AS `slot_key`
105FROM `openapi_source` s, json_each(s.`headers`) h188FROM `openapi_source` s, json_each(s.`headers`) h
106WHERE s.`headers` IS NOT NULL189WHERE s.`headers` IS NOT NULL
107 AND h.`type` = 'object'190 AND h.`type` = 'object'
@@ -115,7 +198,7 @@ WITH header_rows AS ( · 7 unmodified lines
115 s.`scope_id`,198 s.`scope_id`,
116 s.`id` AS `source_id`,199 s.`id` AS `source_id`,
117 h.`key` AS `name`,200 h.`key` AS `name`,
118 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,201 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default') AS `slot_key`,
119 json_extract(h.`value`, '$.secretId') AS `secret_id`202 json_extract(h.`value`, '$.secretId') AS `secret_id`
120 FROM `openapi_source` s, json_each(s.`headers`) h203 FROM `openapi_source` s, json_each(s.`headers`) h
121 WHERE s.`headers` IS NOT NULL204 WHERE s.`headers` IS NOT NULL
@@ -161,7 +244,7 @@ SET `headers` = ( · 39 unmodified lines
161 AND json_extract(h.`value`, '$.prefix') IS NOT NULL244 AND json_extract(h.`value`, '$.prefix') IS NOT NULL
162 THEN json_object(245 THEN json_object(
163 'kind', 'binding',246 'kind', 'binding',
164 'slot', 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),247 'slot', 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default'),
165 'prefix', json_extract(h.`value`, '$.prefix')248 'prefix', json_extract(h.`value`, '$.prefix')
166 )249 )
167 WHEN h.`type` = 'object'250 WHEN h.`type` = 'object'
@@ -169,7 +252,7 @@ SET `headers` = ( · 1 unmodified line
169 AND json_extract(h.`value`, '$.secretId') IS NOT NULL252 AND json_extract(h.`value`, '$.secretId') IS NOT NULL
170 THEN json_object(253 THEN json_object(
171 'kind', 'binding',254 'kind', 'binding',
172 'slot', 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default')255 'slot', 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default')
173 )256 )
174 WHEN h.`type` IN ('object', 'array') THEN json(h.`value`)257 WHEN h.`type` IN ('object', 'array') THEN json(h.`value`)
175 ELSE h.`value`258 ELSE h.`value`
@@ -186,7 +269,7 @@ WITH oauth_rows AS ( · 10 unmodified lines
186 s.`scope_id`,269 s.`scope_id`,
187 s.`id` AS `source_id`,270 s.`id` AS `source_id`,
188 json_extract(s.`oauth2`, '$.securitySchemeName') AS `security_scheme_name`,271 json_extract(s.`oauth2`, '$.securitySchemeName') AS `security_scheme_name`,
189 'oauth2:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(json_extract(s.`oauth2`, '$.securitySchemeName')), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') || ':client-id' AS `client_id_slot`,272 'oauth2:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = json_extract(s.`oauth2`, '$.securitySchemeName')), 'default') || ':client-id' AS `client_id_slot`,
190 json_extract(s.`oauth2`, '$.clientIdSecretId') AS `client_id_secret_id`,273 json_extract(s.`oauth2`, '$.clientIdSecretId') AS `client_id_secret_id`,
191 json_extract(s.`oauth2`, '$.connectionId') AS `connection_id`274 json_extract(s.`oauth2`, '$.connectionId') AS `connection_id`
192 FROM `openapi_source` s275 FROM `openapi_source` s
@@ -225,7 +308,7 @@ WITH oauth_rows AS ( · 32 unmodified lines
225 SELECT308 SELECT
226 s.`scope_id`,309 s.`scope_id`,
227 s.`id` AS `source_id`,310 s.`id` AS `source_id`,
228 'oauth2:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(json_extract(s.`oauth2`, '$.securitySchemeName')), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') || ':client-secret' AS `client_secret_slot`,311 'oauth2:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = json_extract(s.`oauth2`, '$.securitySchemeName')), 'default') || ':client-secret' AS `client_secret_slot`,
229 json_extract(s.`oauth2`, '$.clientSecretSecretId') AS `client_secret_secret_id`312 json_extract(s.`oauth2`, '$.clientSecretSecretId') AS `client_secret_secret_id`
230 FROM `openapi_source` s313 FROM `openapi_source` s
231 WHERE s.`oauth2` IS NOT NULL314 WHERE s.`oauth2` IS NOT NULL
@@ -263,7 +346,7 @@ WITH oauth_rows AS ( · 31 unmodified lines
263 SELECT346 SELECT
264 s.`scope_id`,347 s.`scope_id`,
265 s.`id` AS `source_id`,348 s.`id` AS `source_id`,
266 'oauth2:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(json_extract(s.`oauth2`, '$.securitySchemeName')), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') || ':connection' AS `connection_slot`,349 'oauth2:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = json_extract(s.`oauth2`, '$.securitySchemeName')), 'default') || ':connection' AS `connection_slot`,
267 json_extract(s.`oauth2`, '$.connectionId') AS `connection_id`350 json_extract(s.`oauth2`, '$.connectionId') AS `connection_id`
268 FROM `openapi_source` s351 FROM `openapi_source` s
269 WHERE s.`oauth2` IS NOT NULL352 WHERE s.`oauth2` IS NOT NULL
@@ -304,13 +387,13 @@ SET `oauth2` = json_object( · 34 unmodified lines
304 'tokenUrl', json_extract(`oauth2`, '$.tokenUrl'),387 'tokenUrl', json_extract(`oauth2`, '$.tokenUrl'),
305 'authorizationUrl', json_extract(`oauth2`, '$.authorizationUrl'),388 'authorizationUrl', json_extract(`oauth2`, '$.authorizationUrl'),
306 'issuerUrl', json_extract(`oauth2`, '$.issuerUrl'),389 'issuerUrl', json_extract(`oauth2`, '$.issuerUrl'),
307 'clientIdSlot', 'oauth2:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(json_extract(`oauth2`, '$.securitySchemeName')), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') || ':client-id',390 'clientIdSlot', 'oauth2:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = json_extract(`oauth2`, '$.securitySchemeName')), 'default') || ':client-id',
308 'clientSecretSlot',391 'clientSecretSlot',
309 CASE392 CASE
310 WHEN json_extract(`oauth2`, '$.clientSecretSecretId') IS NULL THEN NULL393 WHEN json_extract(`oauth2`, '$.clientSecretSecretId') IS NULL THEN NULL
311 ELSE 'oauth2:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(json_extract(`oauth2`, '$.securitySchemeName')), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') || ':client-secret'394 ELSE 'oauth2:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = json_extract(`oauth2`, '$.securitySchemeName')), 'default') || ':client-secret'
312 END,395 END,
313 'connectionSlot', 'oauth2:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(json_extract(`oauth2`, '$.securitySchemeName')), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') || ':connection',396 'connectionSlot', 'oauth2:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = json_extract(`oauth2`, '$.securitySchemeName')), 'default') || ':connection',
314 'scopes', json(COALESCE(json_extract(`oauth2`, '$.scopes'), '[]'))397 'scopes', json(COALESCE(json_extract(`oauth2`, '$.scopes'), '[]'))
315)398)
316WHERE `oauth2` IS NOT NULL399WHERE `oauth2` IS NOT NULL
@@ -328,7 +411,7 @@ INSERT INTO `__openapi_query_param_slot_preflight` (`scope_id`, `source_id`, `sl · 11 unmodified lines
328SELECT411SELECT
329 r.`scope_id`,412 r.`scope_id`,
330 r.`source_id`,413 r.`source_id`,
331 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(r.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`414 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = r.`name`), 'default') AS `slot_key`
332FROM `openapi_source_query_param` r415FROM `openapi_source_query_param` r
333WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL;--> statement-breakpoint416WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL;--> statement-breakpoint
334 417
@@ -338,7 +421,7 @@ WITH rows AS ( · 3 unmodified lines
338 SELECT421 SELECT
339 r.`scope_id`,422 r.`scope_id`,
340 r.`source_id`,423 r.`source_id`,
341 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(r.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,424 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = r.`name`), 'default') AS `slot_key`,
342 r.`secret_id`425 r.`secret_id`
343 FROM `openapi_source_query_param` r426 FROM `openapi_source_query_param` r
344 WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL427 WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL
@@ -374,7 +457,7 @@ ALTER TABLE `openapi_source_query_param` ADD `slot_key` text;--> statement-break · 29 unmodified lines
374ALTER TABLE `openapi_source_query_param` ADD `prefix` text;--> statement-breakpoint457ALTER TABLE `openapi_source_query_param` ADD `prefix` text;--> statement-breakpoint
375UPDATE `openapi_source_query_param`458UPDATE `openapi_source_query_param`
376SET459SET
377 `slot_key` = 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),460 `slot_key` = 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
378 `prefix` = `secret_prefix`,461 `prefix` = `secret_prefix`,
379 `kind` = 'binding'462 `kind` = 'binding'
380WHERE `kind` = 'secret';--> statement-breakpoint463WHERE `kind` = 'secret';--> statement-breakpoint
@@ -393,7 +476,7 @@ INSERT INTO `__openapi_spec_fetch_header_slot_preflight` (`scope_id`, `source_id · 12 unmodified lines
393SELECT476SELECT
394 r.`scope_id`,477 r.`scope_id`,
395 r.`source_id`,478 r.`source_id`,
396 'spec_fetch_header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(r.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`479 'spec_fetch_header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = r.`name`), 'default') AS `slot_key`
397FROM `openapi_source_spec_fetch_header` r480FROM `openapi_source_spec_fetch_header` r
398WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL;--> statement-breakpoint481WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL;--> statement-breakpoint
399 482
@@ -403,7 +486,7 @@ WITH rows AS ( · 3 unmodified lines
403 SELECT486 SELECT
404 r.`scope_id`,487 r.`scope_id`,
405 r.`source_id`,488 r.`source_id`,
406 'spec_fetch_header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(r.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,489 'spec_fetch_header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = r.`name`), 'default') AS `slot_key`,
407 r.`secret_id`490 r.`secret_id`
408 FROM `openapi_source_spec_fetch_header` r491 FROM `openapi_source_spec_fetch_header` r
409 WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL492 WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL
@@ -439,7 +522,7 @@ ALTER TABLE `openapi_source_spec_fetch_header` ADD `slot_key` text;--> statement · 29 unmodified lines
439ALTER TABLE `openapi_source_spec_fetch_header` ADD `prefix` text;--> statement-breakpoint522ALTER TABLE `openapi_source_spec_fetch_header` ADD `prefix` text;--> statement-breakpoint
440UPDATE `openapi_source_spec_fetch_header`523UPDATE `openapi_source_spec_fetch_header`
441SET524SET
442 `slot_key` = 'spec_fetch_header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),525 `slot_key` = 'spec_fetch_header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
443 `prefix` = `secret_prefix`,526 `prefix` = `secret_prefix`,
444 `kind` = 'binding'527 `kind` = 'binding'
445WHERE `kind` = 'secret';--> statement-breakpoint528WHERE `kind` = 'secret';--> statement-breakpoint
@@ -458,7 +541,7 @@ INSERT INTO `__openapi_spec_fetch_query_param_slot_preflight` (`scope_id`, `sour · 12 unmodified lines
458SELECT541SELECT
459 r.`scope_id`,542 r.`scope_id`,
460 r.`source_id`,543 r.`source_id`,
461 'spec_fetch_query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(r.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`544 'spec_fetch_query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = r.`name`), 'default') AS `slot_key`
462FROM `openapi_source_spec_fetch_query_param` r545FROM `openapi_source_spec_fetch_query_param` r
463WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL;--> statement-breakpoint546WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL;--> statement-breakpoint
464 547
@@ -468,7 +551,7 @@ WITH rows AS ( · 3 unmodified lines
468 SELECT551 SELECT
469 r.`scope_id`,552 r.`scope_id`,
470 r.`source_id`,553 r.`source_id`,
471 'spec_fetch_query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(r.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,554 'spec_fetch_query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = r.`name`), 'default') AS `slot_key`,
472 r.`secret_id`555 r.`secret_id`
473 FROM `openapi_source_spec_fetch_query_param` r556 FROM `openapi_source_spec_fetch_query_param` r
474 WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL557 WHERE r.`kind` = 'secret' AND r.`secret_id` IS NOT NULL
@@ -504,7 +587,7 @@ ALTER TABLE `openapi_source_spec_fetch_query_param` ADD `slot_key` text;--> stat · 29 unmodified lines
504ALTER TABLE `openapi_source_spec_fetch_query_param` ADD `prefix` text;--> statement-breakpoint587ALTER TABLE `openapi_source_spec_fetch_query_param` ADD `prefix` text;--> statement-breakpoint
505UPDATE `openapi_source_spec_fetch_query_param`588UPDATE `openapi_source_spec_fetch_query_param`
506SET589SET
507 `slot_key` = 'spec_fetch_query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),590 `slot_key` = 'spec_fetch_query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
508 `prefix` = `secret_prefix`,591 `prefix` = `secret_prefix`,
509 `kind` = 'binding'592 `kind` = 'binding'
510WHERE `kind` = 'secret';--> statement-breakpoint593WHERE `kind` = 'secret';--> statement-breakpoint
@@ -562,7 +645,7 @@ INSERT INTO `__graphql_header_slot_preflight` (`scope_id`, `source_id`, `slot_ke · 51 unmodified lines
562SELECT645SELECT
563 h.`scope_id`,646 h.`scope_id`,
564 h.`source_id`,647 h.`source_id`,
565 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`648 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`name`), 'default') AS `slot_key`
566FROM `graphql_source_header` h649FROM `graphql_source_header` h
567WHERE h.`kind` = 'secret'650WHERE h.`kind` = 'secret'
568 AND h.`secret_id` IS NOT NULL;--> statement-breakpoint651 AND h.`secret_id` IS NOT NULL;--> statement-breakpoint
@@ -574,7 +657,7 @@ WITH header_rows AS ( · 5 unmodified lines
574 h.`scope_id`,657 h.`scope_id`,
575 h.`source_id`,658 h.`source_id`,
576 h.`name`,659 h.`name`,
577 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,660 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`name`), 'default') AS `slot_key`,
578 h.`secret_id`,661 h.`secret_id`,
579 h.`secret_prefix`662 h.`secret_prefix`
580 FROM `graphql_source_header` h663 FROM `graphql_source_header` h
@@ -603,7 +686,7 @@ FROM header_rows r;--> statement-breakpoint · 22 unmodified lines
603UPDATE `graphql_source_header`686UPDATE `graphql_source_header`
604SET687SET
605 `kind` = 'binding',688 `kind` = 'binding',
606 `slot_key` = 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),689 `slot_key` = 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
607 `prefix` = `secret_prefix`,690 `prefix` = `secret_prefix`,
608 `text_value` = NULL691 `text_value` = NULL
609WHERE `kind` = 'secret'692WHERE `kind` = 'secret'
@@ -627,7 +710,7 @@ INSERT INTO `__graphql_query_param_slot_preflight` (`scope_id`, `source_id`, `sl · 17 unmodified lines
627SELECT710SELECT
628 q.`scope_id`,711 q.`scope_id`,
629 q.`source_id`,712 q.`source_id`,
630 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(q.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`713 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = q.`name`), 'default') AS `slot_key`
631FROM `graphql_source_query_param` q714FROM `graphql_source_query_param` q
632WHERE q.`kind` = 'secret'715WHERE q.`kind` = 'secret'
633 AND q.`secret_id` IS NOT NULL;--> statement-breakpoint716 AND q.`secret_id` IS NOT NULL;--> statement-breakpoint
@@ -639,7 +722,7 @@ WITH query_param_rows AS ( · 5 unmodified lines
639 q.`scope_id`,722 q.`scope_id`,
640 q.`source_id`,723 q.`source_id`,
641 q.`name`,724 q.`name`,
642 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(q.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,725 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = q.`name`), 'default') AS `slot_key`,
643 q.`secret_id`,726 q.`secret_id`,
644 q.`secret_prefix`727 q.`secret_prefix`
645 FROM `graphql_source_query_param` q728 FROM `graphql_source_query_param` q
@@ -668,7 +751,7 @@ FROM query_param_rows r;--> statement-breakpoint · 22 unmodified lines
668UPDATE `graphql_source_query_param`751UPDATE `graphql_source_query_param`
669SET752SET
670 `kind` = 'binding',753 `kind` = 'binding',
671 `slot_key` = 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),754 `slot_key` = 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
672 `prefix` = `secret_prefix`,755 `prefix` = `secret_prefix`,
673 `text_value` = NULL756 `text_value` = NULL
674WHERE `kind` = 'secret'757WHERE `kind` = 'secret'
@@ -818,7 +901,7 @@ INSERT INTO `__mcp_header_slot_preflight` (`scope_id`, `source_id`, `slot_key`) · 143 unmodified lines
818SELECT901SELECT
819 h.`scope_id`,902 h.`scope_id`,
820 h.`source_id`,903 h.`source_id`,
821 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`904 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`name`), 'default') AS `slot_key`
822FROM `mcp_source_header` h905FROM `mcp_source_header` h
823WHERE h.`kind` = 'secret'906WHERE h.`kind` = 'secret'
824 AND h.`secret_id` IS NOT NULL;--> statement-breakpoint907 AND h.`secret_id` IS NOT NULL;--> statement-breakpoint
@@ -830,7 +913,7 @@ WITH header_rows AS ( · 5 unmodified lines
830 h.`scope_id`,913 h.`scope_id`,
831 h.`source_id`,914 h.`source_id`,
832 h.`name`,915 h.`name`,
833 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,916 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`name`), 'default') AS `slot_key`,
834 h.`secret_id`,917 h.`secret_id`,
835 h.`secret_prefix`918 h.`secret_prefix`
836 FROM `mcp_source_header` h919 FROM `mcp_source_header` h
@@ -859,7 +942,7 @@ FROM header_rows r;--> statement-breakpoint · 22 unmodified lines
859UPDATE `mcp_source_header`942UPDATE `mcp_source_header`
860SET943SET
861 `kind` = 'binding',944 `kind` = 'binding',
862 `slot_key` = 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),945 `slot_key` = 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
863 `prefix` = `secret_prefix`,946 `prefix` = `secret_prefix`,
864 `text_value` = NULL947 `text_value` = NULL
865WHERE `kind` = 'secret'948WHERE `kind` = 'secret'
@@ -883,7 +966,7 @@ INSERT INTO `__mcp_query_param_slot_preflight` (`scope_id`, `source_id`, `slot_k · 17 unmodified lines
883SELECT966SELECT
884 q.`scope_id`,967 q.`scope_id`,
885 q.`source_id`,968 q.`source_id`,
886 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(q.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`969 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = q.`name`), 'default') AS `slot_key`
887FROM `mcp_source_query_param` q970FROM `mcp_source_query_param` q
888WHERE q.`kind` = 'secret'971WHERE q.`kind` = 'secret'
889 AND q.`secret_id` IS NOT NULL;--> statement-breakpoint972 AND q.`secret_id` IS NOT NULL;--> statement-breakpoint
@@ -895,7 +978,7 @@ WITH query_param_rows AS ( · 5 unmodified lines
895 q.`scope_id`,978 q.`scope_id`,
896 q.`source_id`,979 q.`source_id`,
897 q.`name`,980 q.`name`,
898 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(q.`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,981 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = q.`name`), 'default') AS `slot_key`,
899 q.`secret_id`,982 q.`secret_id`,
900 q.`secret_prefix`983 q.`secret_prefix`
901 FROM `mcp_source_query_param` q984 FROM `mcp_source_query_param` q
@@ -924,7 +1007,7 @@ FROM query_param_rows r;--> statement-breakpoint · 22 unmodified lines
924UPDATE `mcp_source_query_param`1007UPDATE `mcp_source_query_param`
925SET1008SET
926 `kind` = 'binding',1009 `kind` = 'binding',
927 `slot_key` = 'query_param:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(`name`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default'),1010 `slot_key` = 'query_param:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = `name`), 'default'),
928 `prefix` = `secret_prefix`,1011 `prefix` = `secret_prefix`,
929 `text_value` = NULL1012 `text_value` = NULL
930WHERE `kind` = 'secret'1013WHERE `kind` = 'secret'
@@ -1038,7 +1121,7 @@ INSERT INTO `__openapi_header_row_slot_preflight` (`scope_id`, `source_id`, `slo · 107 unmodified lines
1038SELECT1121SELECT
1039 s.`scope_id`,1122 s.`scope_id`,
1040 s.`id`,1123 s.`id`,
1041 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`1124 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default') AS `slot_key`
1042FROM `openapi_source` s, json_each(s.`headers`) h1125FROM `openapi_source` s, json_each(s.`headers`) h
1043WHERE s.`headers` IS NOT NULL1126WHERE s.`headers` IS NOT NULL
1044 AND h.`type` = 'object'1127 AND h.`type` = 'object'
@@ -1052,7 +1135,7 @@ WITH header_rows AS ( · 7 unmodified lines
1052 s.`scope_id`,1135 s.`scope_id`,
1053 s.`id` AS `source_id`,1136 s.`id` AS `source_id`,
1054 h.`key` AS `name`,1137 h.`key` AS `name`,
1055 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default') AS `slot_key`,1138 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default') AS `slot_key`,
1056 json_extract(h.`value`, '$.secretId') AS `secret_id`1139 json_extract(h.`value`, '$.secretId') AS `secret_id`
1057 FROM `openapi_source` s, json_each(s.`headers`) h1140 FROM `openapi_source` s, json_each(s.`headers`) h
1058 WHERE s.`headers` IS NOT NULL1141 WHERE s.`headers` IS NOT NULL
@@ -1110,7 +1193,7 @@ SELECT · 51 unmodified lines
1110 WHEN h.`type` = 'object' AND json_extract(h.`value`, '$.kind') = 'binding'1193 WHEN h.`type` = 'object' AND json_extract(h.`value`, '$.kind') = 'binding'
1111 THEN json_extract(h.`value`, '$.slot')1194 THEN json_extract(h.`value`, '$.slot')
1112 WHEN h.`type` = 'object' AND json_extract(h.`value`, '$.secretId') IS NOT NULL1195 WHEN h.`type` = 'object' AND json_extract(h.`value`, '$.secretId') IS NOT NULL
1113 THEN 'header:' || COALESCE(NULLIF(trim(replace(replace(replace(replace(replace(replace(replace(replace(lower(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(trim(h.`key`), char(9), '-'), char(10), '-'), char(13), '-'), ' ', '-'), '_', '-'), '.', '-'), ':', '-'), '/', '-'), '@', '-'), '+', '-'), '&', '-'), '?', '-'), '#', '-'), '%', '-'), '$', '-'), ',', '-'), ';', '-'), '(', '-'), ')', '-'), '[', '-'), ']', '-'), '{', '-'), '}', '-'), '=', '-'), '~', '-'), '!', '-'), char(34), '-'), char(39), '-'), char(92), '-'), '|', '-'), '*', '-'), '<', '-'), '>', '-')), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '--', '-'), '-'), ''), 'default')1196 THEN 'header:' || COALESCE((SELECT `slug` FROM `__slug_norm` WHERE `raw` = h.`key`), 'default')
1114 ELSE NULL1197 ELSE NULL
1115 END,1198 END,
1116 CASE1199 CASE
@@ -1132,3 +1215,6 @@ WHERE s.`headers` IS NOT NULL · 15 unmodified lines
1132);--> statement-breakpoint1215);--> statement-breakpoint
1133 1216
1134ALTER TABLE `openapi_source` DROP COLUMN `headers`;1217ALTER TABLE `openapi_source` DROP COLUMN `headers`;
1218
1219--> statement-breakpoint
1220DROP TABLE `__slug_norm`;
apps/local/src/server/migration-nesting.test.ts+108−0
@@ -0,0 +1,108 @@
1// Lint: reject migration SQL that nests a single function call too deeply.
2//
3// bun:sqlite's lemon parser stack overflows at PREPARE time when an
4// expression nests too deep, and the limit is platform-dependent — the
5// macOS-built compiled CLI binary trips around ~40 levels while Linux can
6// go further. Our test matrix only runs on Linux today, so a regression
7// won't surface in CI; this lint catches the class of bug structurally
8// instead. Cap is 20 (well above any legitimate nested-function call we
9// have today, well below the macOS bun:sqlite parser limit).
10import { describe, expect, it } from "@effect/vitest";
11import { readdirSync, readFileSync } from "node:fs";
12import { join } from "node:path";
13
14const MIGRATIONS_FOLDER = join(import.meta.dirname, "../../drizzle");
15const MAX_NESTING = 20;
16
17// Walk the SQL char-by-char tracking the call-stack of nested function
18// names. A "function call" is any IDENT immediately followed by `(`.
19// Returns { fn, depth } for the deepest single-name nest found, or null.
20const findDeepestNest = (sql: string) => {
21 const stack: string[] = [];
22 let worst: { fn: string; depth: number; offset: number } | null = null;
23 let i = 0;
24 while (i < sql.length) {
25 const ch = sql[i];
26 // Skip line comments
27 if (ch === "-" && sql[i + 1] === "-") {
28 const eol = sql.indexOf("\n", i);
29 i = eol < 0 ? sql.length : eol + 1;
30 continue;
31 }
32 // Skip string literals (single- and double-quoted, backtick identifiers)
33 if (ch === "'" || ch === '"' || ch === "`") {
34 const quote = ch;
35 i++;
36 while (i < sql.length) {
37 if (sql[i] === quote) {
38 if (sql[i + 1] === quote) {
39 i += 2;
40 continue;
41 }
42 i++;
43 break;
44 }
45 i++;
46 }
47 continue;
48 }
49 if (ch === "(") {
50 // Walk back to find an IDENT immediately preceding this paren
51 let j = i - 1;
52 while (j >= 0 && /\s/u.test(sql[j])) j--;
53 let end = j;
54 while (j >= 0 && /[A-Za-z0-9_]/u.test(sql[j])) j--;
55 const name = sql.slice(j + 1, end + 1).toLowerCase();
56 stack.push(name || "(");
57 // Count consecutive same-name frames in the stack
58 let same = 0;
59 for (let k = stack.length - 1; k >= 0; k--) {
60 if (stack[k] === stack[stack.length - 1]) same++;
61 else break;
62 }
63 if (name && (worst === null || same > worst.depth)) {
64 worst = { fn: name, depth: same, offset: i };
65 }
66 i++;
67 continue;
68 }
69 if (ch === ")") {
70 stack.pop();
71 i++;
72 continue;
73 }
74 i++;
75 }
76 return worst;
77};
78
79describe("drizzle migration SQL structural lint", () => {
80 const files = readdirSync(MIGRATIONS_FOLDER)
81 .filter((f) => f.endsWith(".sql"))
82 .sort();
83
84 for (const f of files) {
85 it(`${f} keeps nested-function depth under ${MAX_NESTING}`, () => {
86 const sql = readFileSync(join(MIGRATIONS_FOLDER, f), "utf-8");
87 const worst = findDeepestNest(sql);
88 const summary =
89 worst === null
90 ? { ok: true as const }
91 : {
92 ok: worst.depth < MAX_NESTING,
93 file: f,
94 line: sql.slice(0, worst.offset).split("\n").length,
95 fn: worst.fn,
96 depth: worst.depth,
97 };
98 // The expectation is `summary.ok === true`. The full `summary` object is
99 // matched (not just `.ok`) so the failure diff prints file/line/fn/depth
100 // — bun:sqlite's lemon parser stack overflows on the compiled macOS CLI
101 // binary around depth 40, and the project's test matrix is Linux-only,
102 // so the diff is the breadcrumb that tells you which migration to
103 // refactor (precompute into a temp table à la 0008's __slug_norm, or
104 // split the expression into multiple shallow steps).
105 expect(summary).toEqual({ ...summary, ok: true });
106 });
107 }
108});