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

supabase / storage / 27017816367

05 Jun 2026 01:30PM UTC coverage: 76.416% (+0.07%) from 76.349%
27017816367

Pull #1137

github

web-flow
Merge 6baa49ea5 into 6de414076
Pull Request #1137: fix: add multigres into acceptance matrix

4506 of 6460 branches covered (69.75%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

8853 of 11022 relevant lines covered (80.32%)

368.96 hits per line

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

56.92
/src/http/plugins/vector.ts
1
import { getTenantConfig, multitenantKnex } from '@internal/database'
2
import { deriveVectorDatabaseUrl } from '@internal/database/vector-store-url'
3
import { ERRORS } from '@internal/errors'
4
import {
5
  BucketScopedSingleShard,
6
  KnexShardStoreFactory,
7
  ShardCatalog,
8
  Sharder,
9
  SingleShard,
10
} from '@internal/sharding'
11
import {
12
  createS3VectorClient,
13
  createVectorTransactionKnexResolver,
14
  KnexVectorMetadataDB,
15
  PgVectorStore,
16
  S3Vector,
17
  VectorStore,
18
  VectorStoreManager,
19
} from '@storage/protocols/vector'
20
import { FastifyInstance } from 'fastify'
21
import fastifyPlugin from 'fastify-plugin'
22
import Knex from 'knex'
23
import { getConfig } from '../../config'
24

25
declare module 'fastify' {
26
  interface FastifyRequest {
27
    s3Vector: VectorStoreManager
28
  }
29
}
30

31
export const s3vector = fastifyPlugin(async function (fastify: FastifyInstance) {
29✔
32
  const config = getConfig()
280✔
33
  const {
34
    vectorBucketProvider,
35
    vectorDatabaseCreate,
36
    vectorDatabaseURL,
37
    vectorS3Buckets,
38
    isMultitenant,
39
    databaseApplicationName,
40
  } = config
280✔
41

42
  // S3 mode: build a singleton client+adapter at boot.
43
  let s3Adapter: S3Vector | undefined
44
  if (vectorBucketProvider === 's3' && vectorS3Buckets.length > 0) {
280✔
45
    s3Adapter = new S3Vector(createS3VectorClient())
279✔
46
  }
47

48
  // pgvector + single-tenant: VECTOR_DATABASE_URL is the maintenance URL the
49
  // migration runner used to CREATE DATABASE; the runtime pool targets the
50
  // derived `storage_vectors` database on the same server. When
51
  // VECTOR_DATABASE_CREATE=false, the runtime pool targets VECTOR_DATABASE_URL
52
  // directly.
53
  let stPgVectorAdapter: PgVectorStore | undefined
54
  if (vectorBucketProvider === 'pgvector' && !isMultitenant && vectorDatabaseURL) {
280!
NEW
55
    const connectionString = vectorDatabaseCreate
×
56
      ? deriveVectorDatabaseUrl(vectorDatabaseURL)
57
      : vectorDatabaseURL
UNCOV
58
    const vectorKnex = Knex({
×
59
      client: 'pg',
60
      connection: {
61
        connectionString,
62
        application_name: databaseApplicationName,
63
      },
64
      pool: { min: 0, max: 10 },
65
    })
66
    stPgVectorAdapter = new PgVectorStore(vectorKnex)
×
67
    fastify.addHook('onClose', async () => {
×
68
      await vectorKnex.destroy()
×
69
    })
70
  }
71

72
  const featureEnabled =
73
    (vectorBucketProvider === 's3' && Boolean(s3Adapter)) ||
280!
74
    (vectorBucketProvider === 'pgvector' && (isMultitenant || Boolean(stPgVectorAdapter)))
75

76
  fastify.addHook('preHandler', async (req) => {
280✔
77
    if (!featureEnabled) {
151✔
78
      throw ERRORS.FeatureNotEnabled('vector', 'Vector service not configured')
1✔
79
    }
80

81
    const { vectorMaxBucketsCount, vectorMaxIndexesCount } = config
150✔
82

83
    let maxBucketCount = vectorMaxBucketsCount
150✔
84
    let maxIndexCount = vectorMaxIndexesCount
150✔
85

86
    if (isMultitenant) {
150!
87
      const { features } = await getTenantConfig(req.tenantId)
×
88
      maxBucketCount = features?.vectorBuckets?.maxBuckets || vectorMaxBucketsCount
×
89
      maxIndexCount = features?.vectorBuckets?.maxIndexes || vectorMaxIndexesCount
×
90
    }
91

92
    const db = req.db.pool.acquire()
150✔
93
    const store = new KnexVectorMetadataDB(db)
150✔
94

95
    // Pick the adapter. In multi-tenant pgvector mode the adapter binds to the
96
    // request's own tenant pool (vectors live in the tenant DB); ST pgvector
97
    // uses the singleton; s3 uses the singleton S3 client.
98
    let adapter: VectorStore
99
    if (vectorBucketProvider === 'pgvector') {
150!
100
      adapter = isMultitenant
×
101
        ? new PgVectorStore(createVectorTransactionKnexResolver(db))
102
        : stPgVectorAdapter!
103
    } else {
104
      adapter = s3Adapter!
150✔
105
    }
106

107
    let shard: Sharder
108
    if (vectorBucketProvider === 'pgvector') {
150!
109
      shard = new BucketScopedSingleShard({
×
110
        keyPrefix: 'pgvector__',
111
        capacity: Number.MAX_SAFE_INTEGER,
112
      })
113
    } else if (isMultitenant) {
150!
114
      shard = new ShardCatalog(new KnexShardStoreFactory(multitenantKnex))
×
115
    } else {
116
      shard = new SingleShard({
150✔
117
        shardKey: vectorS3Buckets[0],
118
        capacity: 10000,
119
      })
120
    }
121

122
    req.s3Vector = new VectorStoreManager(adapter, store, shard, {
150✔
123
      tenantId: req.tenantId,
124
      maxBucketCount,
125
      maxIndexCount,
126
    })
127
  })
128
})
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