Skip to content

Commit 8497b14

Browse files
committed
feat: add is_vanished optimization with lazy hydration
1 parent bb99e8f commit 8497b14

17 files changed

Lines changed: 137 additions & 50 deletions

migrations/20260410_230000_add_is_vanished_to_users_table.js

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,12 @@ exports.up = async function (knex) {
66
await knex.raw(`
77
UPDATE users u
88
SET is_vanished = true
9-
FROM events e
10-
WHERE u.pubkey = e.event_pubkey
11-
AND e.event_kind = 62
12-
AND e.deleted_at IS NULL
13-
`)
14-
15-
await knex.raw(`
16-
INSERT INTO users (pubkey, is_admitted, balance, is_vanished, created_at, updated_at)
17-
SELECT DISTINCT e.event_pubkey, false, 0, true, NOW(), NOW()
18-
FROM events e
19-
LEFT JOIN users u ON u.pubkey = e.event_pubkey
20-
WHERE e.event_kind = 62
21-
AND e.deleted_at IS NULL
22-
AND u.pubkey IS NULL
9+
WHERE EXISTS (
10+
SELECT 1 FROM events e
11+
WHERE e.event_pubkey = u.pubkey
12+
AND e.event_kind = 62
13+
AND e.deleted_at IS NULL
14+
)
2315
`)
2416
}
2517

src/@types/repositories.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ export interface IUserRepository {
4747
findByPubkey(pubkey: Pubkey, client?: DatabaseClient): Promise<User | undefined>
4848
upsert(user: Partial<User>, client?: DatabaseClient): Promise<number>
4949
getBalanceByPubkey(pubkey: Pubkey, client?: DatabaseClient): Promise<bigint>
50+
isVanished(pubkey: Pubkey, client?: DatabaseClient): Promise<boolean>
51+
setVanished(pubkey: Pubkey, vanished: boolean, client?: DatabaseClient): Promise<number>
5052
}

src/@types/user.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Pubkey } from './base'
33
export interface User {
44
pubkey: Pubkey
55
isAdmitted: boolean
6+
isVanished: boolean
67
balance: bigint
78
tosAcceptedAt?: Date | null
89
createdAt: Date
@@ -12,6 +13,7 @@ export interface User {
1213
export interface DBUser {
1314
pubkey: Buffer
1415
is_admitted: boolean
16+
is_vanished: boolean
1517
balance: bigint
1618
created_at: Date
1719
updated_at: Date

src/factories/controllers/get-admission-check-controller-factory.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
import { getMasterDbClient, getReadReplicaDbClient } from '../../database/client'
12
import { createSettings } from '../settings-factory'
2-
import { getMasterDbClient } from '../../database/client'
3+
import { EventRepository } from '../../repositories/event-repository'
34
import { GetSubmissionCheckController } from '../../controllers/admission/get-admission-check-controller'
45
import { slidingWindowRateLimiterFactory } from '../rate-limiter-factory'
56
import { UserRepository } from '../../repositories/user-repository'
67

78
export const createGetAdmissionCheckController = () => {
89
const dbClient = getMasterDbClient()
9-
const userRepository = new UserRepository(dbClient)
10+
const readReplicaDbClient = getReadReplicaDbClient()
11+
const eventRepository = new EventRepository(dbClient, readReplicaDbClient)
12+
const userRepository = new UserRepository(dbClient, eventRepository)
1013

1114
return new GetSubmissionCheckController(
1215
userRepository,

src/factories/controllers/post-invoice-controller-factory.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
import { getMasterDbClient, getReadReplicaDbClient } from '../../database/client'
12
import { createPaymentsService } from '../payments-service-factory'
23
import { createSettings } from '../settings-factory'
3-
import { getMasterDbClient } from '../../database/client'
4+
import { EventRepository } from '../../repositories/event-repository'
45
import { IController } from '../../@types/controllers'
56
import { PostInvoiceController } from '../../controllers/invoices/post-invoice-controller'
67
import { slidingWindowRateLimiterFactory } from '../rate-limiter-factory'
78
import { UserRepository } from '../../repositories/user-repository'
89

910
export const createPostInvoiceController = (): IController => {
1011
const dbClient = getMasterDbClient()
11-
const userRepository = new UserRepository(dbClient)
12+
const readReplicaDbClient = getReadReplicaDbClient()
13+
const eventRepository = new EventRepository(dbClient, readReplicaDbClient)
14+
const userRepository = new UserRepository(dbClient, eventRepository)
1215
const paymentsService = createPaymentsService()
1316

1417
return new PostInvoiceController(

src/factories/event-strategy-factory.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { IEventRepository, IUserRepository } from '../@types/repositories'
12
import { isDeleteEvent, isEphemeralEvent, isParameterizedReplaceableEvent, isReplaceableEvent, isRequestToVanishEvent } from '../utils/event'
23
import { DefaultEventStrategy } from '../handlers/event-strategies/default-event-strategy'
34
import { DeleteEventStrategy } from '../handlers/event-strategies/delete-event-strategy'
45
import { EphemeralEventStrategy } from '../handlers/event-strategies/ephemeral-event-strategy'
56
import { Event } from '../@types/event'
67
import { Factory } from '../@types/base'
7-
import { IEventRepository } from '../@types/repositories'
88
import { IEventStrategy } from '../@types/message-handlers'
99
import { IWebSocketAdapter } from '../@types/adapters'
1010
import { ParameterizedReplaceableEventStrategy } from '../handlers/event-strategies/parameterized-replaceable-event-strategy'
@@ -13,10 +13,11 @@ import { VanishEventStrategy } from '../handlers/event-strategies/vanish-event-s
1313

1414
export const eventStrategyFactory = (
1515
eventRepository: IEventRepository,
16+
userRepository: IUserRepository,
1617
): Factory<IEventStrategy<Event, Promise<void>>, [Event, IWebSocketAdapter]> =>
1718
([event, adapter]: [Event, IWebSocketAdapter]) => {
1819
if (isRequestToVanishEvent(event)) {
19-
return new VanishEventStrategy(adapter, eventRepository)
20+
return new VanishEventStrategy(adapter, eventRepository, userRepository)
2021
} else if (isReplaceableEvent(event)) {
2122
return new ReplaceableEventStrategy(adapter, eventRepository)
2223
} else if (isEphemeralEvent(event)) {

src/factories/message-handler-factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const messageHandlerFactory = (
1717
{
1818
return new EventMessageHandler(
1919
adapter,
20-
eventStrategyFactory(eventRepository),
20+
eventStrategyFactory(eventRepository, userRepository),
2121
eventRepository,
2222
userRepository,
2323
createSettings,

src/factories/payments-service-factory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export const createPaymentsService = () => {
1010
const dbClient = getMasterDbClient()
1111
const rrDbClient = getReadReplicaDbClient()
1212
const invoiceRepository = new InvoiceRepository(dbClient)
13-
const userRepository = new UserRepository(dbClient)
14-
const paymentsProcessor = createPaymentsProcessor()
1513
const eventRepository = new EventRepository(dbClient, rrDbClient)
14+
const userRepository = new UserRepository(dbClient, eventRepository)
15+
const paymentsProcessor = createPaymentsProcessor()
1616

1717
return new PaymentsService(
1818
dbClient,

src/factories/static-mirroring.worker-factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const staticMirroringWorkerFactory = () => {
88
const dbClient = getMasterDbClient()
99
const readReplicaDbClient = getReadReplicaDbClient()
1010
const eventRepository = new EventRepository(dbClient, readReplicaDbClient)
11-
const userRepository = new UserRepository(dbClient)
11+
const userRepository = new UserRepository(dbClient, eventRepository)
1212

1313
return new StaticMirroringWorker(
1414
eventRepository,

src/factories/worker-factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const workerFactory = (): AppWorker => {
1616
const dbClient = getMasterDbClient()
1717
const readReplicaDbClient = getReadReplicaDbClient()
1818
const eventRepository = new EventRepository(dbClient, readReplicaDbClient)
19-
const userRepository = new UserRepository(dbClient)
19+
const userRepository = new UserRepository(dbClient, eventRepository)
2020

2121
const settings = createSettings()
2222

0 commit comments

Comments
 (0)