Skip to content

Commit 81fb5fa

Browse files
authored
fix: exclude soft deleted catalogs from count (#1200)
1 parent fbbb7c2 commit 81fb5fa

3 files changed

Lines changed: 66 additions & 2 deletions

File tree

src/storage/protocols/iceberg/metastore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export interface Metastore<Tnx = unknown> {
9191
): Promise<T>
9292

9393
assignCatalog(param: { bucketName: string; bucketId: string; tenantId: string }): Promise<Catalog>
94-
countCatalogs(params: { tenantId: string; limit: number }): Promise<number>
94+
countCatalogs(params: { tenantId: string; limit: number; deleted?: boolean }): Promise<number>
9595
countNamespaces(param: { tenantId: string; limit: number }): Promise<number>
9696
countTables(params: { namespaceId: string; tenantId?: string; limit: number }): Promise<number>
9797
countResources(params: {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import { PgMetastore } from './pg'
3+
4+
function createMetastore(query: ReturnType<typeof vi.fn>) {
5+
return new PgMetastore({ query } as never, {
6+
multiTenant: false,
7+
schema: 'storage',
8+
})
9+
}
10+
11+
function getLastStatement(query: ReturnType<typeof vi.fn>): string {
12+
const [statement] = query.mock.calls.at(-1) || []
13+
14+
if (!statement) {
15+
throw new Error('No query calls found')
16+
}
17+
18+
if (typeof statement === 'string') {
19+
return statement
20+
}
21+
22+
if (typeof statement === 'object' && 'text' in statement) {
23+
return String(statement.text)
24+
}
25+
26+
throw new Error('Expected a PgStatement query with text property')
27+
}
28+
29+
describe('PgMetastore.countCatalogs', () => {
30+
it('excludes soft-deleted catalogs by default', async () => {
31+
const query = vi.fn().mockResolvedValue({ rows: [{ count: 5 }] })
32+
const metastore = createMetastore(query)
33+
34+
await metastore.countCatalogs({
35+
tenantId: 'tenant-id',
36+
limit: 100,
37+
})
38+
39+
const statement = getLastStatement(query)
40+
expect(statement).toContain('deleted_at IS NULL')
41+
})
42+
43+
it('includes soft-deleted catalogs when deleted parameter is true', async () => {
44+
const query = vi.fn().mockResolvedValue({ rows: [{ count: 10 }] })
45+
const metastore = createMetastore(query)
46+
47+
await metastore.countCatalogs({
48+
tenantId: 'tenant-id',
49+
limit: 100,
50+
deleted: true,
51+
})
52+
53+
const statement = getLastStatement(query)
54+
expect(statement).not.toContain('deleted_at IS NULL')
55+
})
56+
})

src/storage/protocols/iceberg/pg.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,19 @@ export class PgMetastore implements Metastore<PgTransaction> {
205205
return catalog
206206
}
207207

208-
async countCatalogs(params: { tenantId: string; limit: number }): Promise<number> {
208+
async countCatalogs(params: {
209+
tenantId: string
210+
limit: number
211+
deleted?: boolean
212+
}): Promise<number> {
209213
const values: unknown[] = []
210214
const conditions: string[] = []
211215
this.addTenantCondition(conditions, values, params.tenantId)
212216

217+
if (!params.deleted) {
218+
conditions.push('deleted_at IS NULL')
219+
}
220+
213221
return this.countRows('iceberg_catalogs', conditions, values, params.limit)
214222
}
215223

0 commit comments

Comments
 (0)