Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 6x 28x 4x 4x 2x 4x 4x 2x 1x 2x 3x 2x 2x 4x 4x 2x 2x 1x | import { eq, and, desc, asc, sql } from "drizzle-orm";
import type { DrizzleD1Database } from "drizzle-orm/d1";
import * as schema from "../db/schema";
import type { PushSubscription, NewPushSubscription } from "../db/schema";
const MAX_ACTIVE_SUBSCRIPTIONS = 10;
export class PushSubscriptionsDal {
constructor(private db: DrizzleD1Database<typeof schema>) {}
async upsert(data: NewPushSubscription): Promise<PushSubscription> {
// Enforce max active subscription limit
const activeCount = await this.getActiveCount(data.userId);
if (activeCount >= MAX_ACTIVE_SUBSCRIPTIONS) {
await this.deactivateOldest(data.userId);
}
const result = await this.db
.insert(schema.pushSubscriptions)
.values(data)
.onConflictDoUpdate({
target: [schema.pushSubscriptions.userId, schema.pushSubscriptions.endpoint],
set: {
p256dh: data.p256dh,
auth: data.auth,
userAgent: data.userAgent,
isActive: true,
lastActiveAt: new Date(),
},
})
.returning();
return result[0];
}
async findActiveByUser(userId: string): Promise<PushSubscription[]> {
return this.db
.select()
.from(schema.pushSubscriptions)
.where(
and(
eq(schema.pushSubscriptions.userId, userId),
eq(schema.pushSubscriptions.isActive, true),
),
)
.orderBy(desc(schema.pushSubscriptions.dateCreated));
}
async findAll(): Promise<PushSubscription[]> {
return this.db
.select()
.from(schema.pushSubscriptions)
.orderBy(desc(schema.pushSubscriptions.dateCreated))
.limit(100);
}
async deactivateByEndpoint(userId: string, endpoint: string): Promise<void> {
await this.db
.update(schema.pushSubscriptions)
.set({ isActive: false })
.where(
and(
eq(schema.pushSubscriptions.userId, userId),
eq(schema.pushSubscriptions.endpoint, endpoint),
),
);
}
async deactivate(id: string): Promise<void> {
await this.db
.update(schema.pushSubscriptions)
.set({ isActive: false })
.where(eq(schema.pushSubscriptions.id, id));
}
async deactivateAllForUser(userId: string): Promise<void> {
await this.db
.update(schema.pushSubscriptions)
.set({ isActive: false })
.where(eq(schema.pushSubscriptions.userId, userId));
}
async updateLastActive(id: string): Promise<void> {
await this.db
.update(schema.pushSubscriptions)
.set({ lastActiveAt: new Date() })
.where(eq(schema.pushSubscriptions.id, id));
}
private async getActiveCount(userId: string): Promise<number> {
const result = await this.db
.select({ count: sql<number>`count(*)` })
.from(schema.pushSubscriptions)
.where(
and(
eq(schema.pushSubscriptions.userId, userId),
eq(schema.pushSubscriptions.isActive, true),
),
);
return result[0]?.count ?? 0;
}
private async deactivateOldest(userId: string): Promise<void> {
// Find the oldest active subscription by lastActiveAt ASC
const oldest = await this.db
.select({ id: schema.pushSubscriptions.id })
.from(schema.pushSubscriptions)
.where(
and(
eq(schema.pushSubscriptions.userId, userId),
eq(schema.pushSubscriptions.isActive, true),
),
)
.orderBy(asc(schema.pushSubscriptions.lastActiveAt))
.limit(1);
if (oldest[0]) {
await this.deactivate(oldest[0].id);
}
}
}
|