• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / storage / 28591991730

02 Jul 2026 01:00PM UTC coverage: 78.877% (+0.06%) from 78.821%
28591991730

Pull #1193

github

web-flow
Merge 24e8f5321 into 3ce1ad0bc
Pull Request #1193: fix: replace mutex with single flight pattern

5106 of 7036 branches covered (72.57%)

Branch coverage included in aggregate %.

80 of 95 new or added lines in 9 files covered. (84.21%)

2 existing lines in 2 files now uncovered.

10103 of 12246 relevant lines covered (82.5%)

420.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/src/http/plugins/db.ts
1
import { createSingleFlightByKey } from '@internal/concurrency'
2
import {
3
  getPostgresConnection,
4
  getServiceKeyUser,
5
  getTenantConfig,
6
  PgTenantConnection,
7
} from '@internal/database'
8
import {
9
  areMigrationsUpToDate,
10
  DBMigration,
11
  lastLocalMigrationName,
12
  progressiveMigrations,
13
  runMigrationsOnTenant,
14
  updateTenantMigrationsState,
15
} from '@internal/database/migrations'
16
import { ERRORS } from '@internal/errors'
17
import { logSchema } from '@internal/monitoring'
18
import fastifyPlugin from 'fastify-plugin'
19
import { getConfig, MultitenantMigrationStrategy } from '../../config'
20

21
declare module 'fastify' {
22
  interface FastifyRequest {
23
    db: PgTenantConnection
24
    latestMigration?: keyof typeof DBMigration
25
  }
26
}
27

28
const { databaseEnableQueryCancellation, dbMigrationStrategy, isMultitenant, dbMigrationFreezeAt } =
44✔
29
  getConfig()
30

31
const migrationSingleFlight = createSingleFlightByKey<void>()
44✔
32

33
export const db = fastifyPlugin(
44✔
34
  async function db(fastify) {
35
    fastify.register(migrations)
4,967✔
36

37
    fastify.decorateRequest('db')
4,967✔
38

39
    fastify.addHook('preHandler', async (request) => {
4,967✔
40
      const adminUser = await getServiceKeyUser(request.tenantId)
1,047✔
41
      const userPayload = request.jwtPayload
1,047✔
42

43
      if (!userPayload) {
1,047!
44
        throw ERRORS.AccessDenied('JWT payload is missing')
×
45
      }
46

47
      request.db = await getPostgresConnection({
1,047✔
48
        user: {
49
          payload: userPayload,
50
          jwt: request.jwt,
51
        },
52
        superUser: adminUser,
53
        tenantId: request.tenantId,
54
        host: request.headers['x-forwarded-host'] as string,
55
        headers: request.headers,
56
        path: request.url,
57
        method: request.method,
58
        operation: () => request.operation?.type,
2,299✔
59
      })
60

61
      // Connect abort signal to DB connection for query cancellation
62
      if (databaseEnableQueryCancellation && request.signals) {
1,045✔
63
        request.db.setAbortSignal(request.signals.disconnect.signal)
1✔
64
      }
65
    })
66

67
    fastify.addHook('onSend', async (request, reply, payload) => {
4,967✔
68
      disposeRequestConnections(request)
1,046✔
69
      return payload
1,046✔
70
    })
71

72
    fastify.addHook('onTimeout', async (request) => {
4,967✔
73
      disposeRequestConnections(request)
×
74
    })
75

76
    fastify.addHook('onRequestAbort', async (request) => {
4,967✔
77
      disposeRequestConnections(request)
×
78
    })
79
  },
80
  { name: 'db-init' }
81
)
82

83
interface DbSuperUserPluginOptions {
84
  disableHostCheck?: boolean
85
}
86

87
export const dbSuperUser = fastifyPlugin<DbSuperUserPluginOptions>(
44✔
88
  async function dbSuperUser(fastify, opts) {
89
    fastify.register(migrations)
1,788✔
90
    fastify.decorateRequest('db')
1,788✔
91

92
    fastify.addHook('preHandler', async (request) => {
1,788✔
93
      const adminUser = await getServiceKeyUser(request.tenantId)
215✔
94

95
      request.db = await getPostgresConnection({
215✔
96
        user: adminUser,
97
        superUser: adminUser,
98
        tenantId: request.tenantId,
99
        host: request.headers['x-forwarded-host'] as string,
100
        path: request.url,
101
        method: request.method,
102
        headers: request.headers,
103
        disableHostCheck: opts.disableHostCheck,
104
        operation: () => request.operation?.type,
65✔
105
      })
106

107
      // Connect abort signal to DB connection for query cancellation
108
      if (databaseEnableQueryCancellation && request.signals) {
215✔
109
        request.db.setAbortSignal(request.signals.disconnect.signal)
1✔
110
      }
111
    })
112

113
    fastify.addHook('onSend', async (request, reply, payload) => {
1,788✔
114
      disposeRequestConnections(request)
278✔
115
      return payload
278✔
116
    })
117

118
    fastify.addHook('onTimeout', async (request) => {
1,788✔
119
      disposeRequestConnections(request)
×
120
    })
121

122
    fastify.addHook('onRequestAbort', async (request) => {
1,788✔
123
      disposeRequestConnections(request)
1✔
124
    })
125
  },
126
  { name: 'db-superuser-init' }
127
)
128

129
function disposeRequestConnections(request: {
130
  db?: PgTenantConnection
131
  log: Parameters<typeof logSchema.error>[0]
132
  tenantId: string
133
  id: string
134
  sbReqId?: string
135
}) {
136
  request.db?.dispose().catch((e) => {
1,325✔
137
    logSchema.error(request.log, 'Error disposing db connection', {
×
138
      type: 'db-connection',
139
      tenantId: request.tenantId,
140
      project: request.tenantId,
141
      reqId: request.id,
142
      sbReqId: request.sbReqId,
143
      error: e,
144
    })
145
  })
146
}
147

148
/**
149
 * Handle database migration for multitenant applications when a request is made
150
 */
151
export const migrations = fastifyPlugin(
44✔
152
  async function migrations(fastify) {
153
    fastify.addHook('preHandler', async (req) => {
6,755✔
154
      if (isMultitenant) {
1,264✔
155
        const { migrationVersion } = await getTenantConfig(req.tenantId)
16✔
156
        req.latestMigration = migrationVersion
16✔
157
        return
16✔
158
      }
159

160
      req.latestMigration = await lastLocalMigrationName()
1,248✔
161
    })
162

163
    if (dbMigrationStrategy === MultitenantMigrationStrategy.ON_REQUEST) {
6,755✔
164
      fastify.addHook('preHandler', async (request) => {
6,748✔
165
        // migrations are handled via async migrations
166
        if (!isMultitenant) {
1,257✔
167
          return
1,241✔
168
        }
169

170
        const tenant = await getTenantConfig(request.tenantId)
16✔
171
        if (tenant.syncMigrationsDone) {
16✔
172
          return
3✔
173
        }
174

175
        await migrationSingleFlight(request.tenantId, async () => {
13✔
176
          if (await areMigrationsUpToDate(request.tenantId)) {
10✔
177
            tenant.syncMigrationsDone = true
1✔
178
            return
1✔
179
          }
180

181
          await runMigrationsOnTenant({
9✔
182
            databaseUrl: tenant.databaseUrl,
183
            tenantId: request.tenantId,
184
            upToMigration: dbMigrationFreezeAt,
185
          })
186
          await updateTenantMigrationsState(request.tenantId)
8✔
187
          tenant.syncMigrationsDone = true
8✔
188
        })
189
      })
190
    }
191

192
    if (dbMigrationStrategy === MultitenantMigrationStrategy.PROGRESSIVE) {
6,755✔
193
      fastify.addHook('preHandler', async (request) => {
7✔
194
        if (!isMultitenant) {
7!
195
          return
7✔
196
        }
197

198
        const tenant = await getTenantConfig(request.tenantId)
×
NEW
199
        if (tenant.syncMigrationsDone) {
×
NEW
200
          return
×
201
        }
202

203
        // migrations are up to date
NEW
204
        if (await areMigrationsUpToDate(request.tenantId)) {
×
NEW
205
          tenant.syncMigrationsDone = true
×
UNCOV
206
          return
×
207
        }
208

209
        progressiveMigrations.addTenant(request.tenantId)
×
210
      })
211
    }
212
  },
213
  { name: 'db-migrations' }
214
)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc