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

supabase / storage / 13284148400

12 Feb 2025 11:18AM UTC coverage: 76.487% (-0.8%) from 77.287%
13284148400

Pull #626

github

web-flow
Merge 2cf393098 into 6f58fe236
Pull Request #626: feat: search objects v2

1286 of 1830 branches covered (70.27%)

Branch coverage included in aggregate %.

311 of 685 new or added lines in 18 files covered. (45.4%)

8 existing lines in 3 files now uncovered.

15408 of 19996 relevant lines covered (77.06%)

156.4 hits per line

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

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

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

1✔
28
const { dbMigrationStrategy, isMultitenant } = getConfig()
1✔
29

1✔
30
export const db = fastifyPlugin(
1✔
31
  async function db(fastify) {
1✔
32
    fastify.register(migrations)
1,845✔
33

1,845✔
34
    fastify.decorateRequest('db', null)
1,845✔
35

1,845✔
36
    fastify.addHook('preHandler', async (request) => {
1,845✔
37
      const adminUser = await getServiceKeyUser(request.tenantId)
99✔
38
      const userPayload =
99✔
39
        request.jwtPayload ?? (await verifyJWT<{ role?: string }>(request.jwt, adminUser.jwtSecret))
99!
40

99✔
41
      request.db = await getPostgresConnection({
99✔
42
        user: {
99✔
43
          payload: userPayload,
99✔
44
          jwt: request.jwt,
99✔
45
        },
99✔
46
        superUser: adminUser,
99✔
47
        tenantId: request.tenantId,
99✔
48
        host: request.headers['x-forwarded-host'] as string,
99✔
49
        headers: request.headers,
99✔
50
        path: request.url,
99✔
51
        method: request.method,
99✔
52
        operation: () => request.operation?.type,
99✔
53
      })
99✔
54
    })
1,845✔
55

1,845✔
56
    fastify.addHook('onSend', async (request, reply, payload) => {
1,845✔
57
      if (request.db) {
112✔
58
        request.db.dispose().catch((e) => {
99✔
59
          logSchema.error(request.log, 'Error disposing db connection', {
×
60
            type: 'db-connection',
×
61
            error: e,
×
62
          })
×
63
        })
99✔
64
      }
99✔
65
      return payload
112✔
66
    })
1,845✔
67

1,845✔
68
    fastify.addHook('onTimeout', async (request) => {
1,845✔
69
      if (request.db) {
×
70
        request.db.dispose().catch((e) => {
×
71
          logSchema.error(request.log, 'Error disposing db connection', {
×
72
            type: 'db-connection',
×
73
            error: e,
×
74
          })
×
75
        })
×
76
      }
×
77
    })
1,845✔
78

1,845✔
79
    fastify.addHook('onRequestAbort', async (request) => {
1,845✔
80
      if (request.db) {
2✔
81
        request.db.dispose().catch((e) => {
2✔
82
          logSchema.error(request.log, 'Error disposing db connection', {
×
83
            type: 'db-connection',
×
84
            error: e,
×
85
          })
×
86
        })
2✔
87
      }
2✔
88
    })
1,845✔
89
  },
1,845✔
90
  { name: 'db-init' }
1✔
91
)
1✔
92

1✔
93
interface DbSuperUserPluginOptions {
1✔
94
  disableHostCheck?: boolean
1✔
95
  maxConnections?: number
1✔
96
}
1✔
97

1✔
98
export const dbSuperUser = fastifyPlugin<DbSuperUserPluginOptions>(
1✔
99
  async function dbSuperUser(fastify, opts) {
1✔
100
    fastify.register(migrations)
615✔
101
    fastify.decorateRequest('db', null)
615✔
102

615✔
103
    fastify.addHook('preHandler', async (request) => {
615✔
104
      const adminUser = await getServiceKeyUser(request.tenantId)
9✔
105

9✔
106
      request.db = await getPostgresConnection({
9✔
107
        user: adminUser,
9✔
108
        superUser: adminUser,
9✔
109
        tenantId: request.tenantId,
9✔
110
        host: request.headers['x-forwarded-host'] as string,
9✔
111
        path: request.url,
9✔
112
        method: request.method,
9✔
113
        headers: request.headers,
9✔
114
        disableHostCheck: opts.disableHostCheck,
9✔
115
        maxConnections: opts.maxConnections,
9✔
116
        operation: () => request.operation?.type,
9✔
117
      })
9✔
118
    })
615✔
119

615✔
120
    fastify.addHook('onSend', async (request, reply, payload) => {
615✔
121
      if (request.db) {
11✔
122
        request.db.dispose().catch((e) => {
9✔
123
          logSchema.error(request.log, 'Error disposing db connection', {
×
124
            type: 'db-connection',
×
125
            error: e,
×
126
          })
×
127
        })
9✔
128
      }
9✔
129

11✔
130
      return payload
11✔
131
    })
615✔
132

615✔
133
    fastify.addHook('onTimeout', async (request) => {
615✔
134
      if (request.db) {
×
135
        request.db.dispose().catch((e) => {
×
136
          logSchema.error(request.log, 'Error disposing db connection', {
×
137
            type: 'db-connection',
×
138
            error: e,
×
139
          })
×
140
        })
×
141
      }
×
142
    })
615✔
143

615✔
144
    fastify.addHook('onRequestAbort', async (request) => {
615✔
145
      if (request.db) {
×
146
        request.db.dispose().catch((e) => {
×
147
          logSchema.error(request.log, 'Error disposing db connection', {
×
148
            type: 'db-connection',
×
149
            error: e,
×
150
          })
×
151
        })
×
152
      }
×
153
    })
615✔
154
  },
615✔
155
  { name: 'db-superuser-init' }
1✔
156
)
1✔
157

1✔
158
/**
1✔
159
 * Handle database migration for multitenant applications when a request is made
1✔
160
 */
1✔
161
export const migrations = fastifyPlugin(
1✔
162
  async function migrations(fastify) {
1✔
163
    fastify.addHook('preHandler', async (req) => {
2,460✔
164
      if (isMultitenant) {
108!
165
        const { migrationVersion } = await getTenantConfig(req.tenantId)
×
166
        req.latestMigration = migrationVersion
×
167
        return
×
168
      }
×
169

108✔
170
      req.latestMigration = await lastLocalMigrationName()
108✔
171
    })
2,460✔
172

2,460✔
173
    if (dbMigrationStrategy === MultitenantMigrationStrategy.ON_REQUEST) {
2,460✔
174
      const migrationsMutex = createMutexByKey()
2,460✔
175

2,460✔
176
      fastify.addHook('preHandler', async (request) => {
2,460✔
177
        // migrations are handled via async migrations
108✔
178
        if (!isMultitenant) {
108✔
179
          return
108✔
180
        }
108✔
181

×
182
        const tenant = await getTenantConfig(request.tenantId)
×
183
        const migrationsUpToDate = await areMigrationsUpToDate(request.tenantId)
×
184

×
185
        if (tenant.syncMigrationsDone || migrationsUpToDate) {
108!
186
          return
×
187
        }
×
188

×
189
        await migrationsMutex(request.tenantId, async () => {
×
190
          const tenant = await getTenantConfig(request.tenantId)
×
191

×
192
          if (tenant.syncMigrationsDone) {
×
193
            return
×
194
          }
×
195

×
196
          await runMigrationsOnTenant(tenant.databaseUrl, request.tenantId)
×
197
          await updateTenantMigrationsState(request.tenantId)
×
198
          tenant.syncMigrationsDone = true
×
199
        })
×
200
      })
2,460✔
201
    }
2,460✔
202

2,460✔
203
    if (dbMigrationStrategy === MultitenantMigrationStrategy.PROGRESSIVE) {
2,460!
204
      fastify.addHook('preHandler', async (request) => {
×
205
        if (!isMultitenant) {
×
206
          return
×
207
        }
×
208

×
209
        const tenant = await getTenantConfig(request.tenantId)
×
210
        const migrationsUpToDate = await areMigrationsUpToDate(request.tenantId)
×
211

×
212
        // migrations are up to date
×
213
        if (tenant.syncMigrationsDone || migrationsUpToDate) {
×
214
          return
×
215
        }
×
216

×
NEW
217
        progressiveMigrations.addTenant(request.tenantId)
×
218
      })
×
219
    }
×
220
  },
2,460✔
221
  { name: 'db-migrations' }
1✔
222
)
1✔
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