mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 19:04:02 +00:00
refactor(time): migrate runtime time handling to Temporal
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { and, eq, inArray, sql } from 'drizzle-orm'
|
||||
|
||||
import { createDbClient, schema } from '@household/db'
|
||||
import { instantFromDatabaseValue, instantToDate } from '@household/domain'
|
||||
import type {
|
||||
AnonymousFeedbackModerationStatus,
|
||||
AnonymousFeedbackRepository
|
||||
@@ -49,11 +50,14 @@ export function createDbAnonymousFeedbackRepository(
|
||||
},
|
||||
|
||||
async getRateLimitSnapshot(memberId, acceptedSince) {
|
||||
const acceptedSinceIso = acceptedSince.toISOString()
|
||||
const acceptedSinceIso = acceptedSince.toString()
|
||||
|
||||
const rows = await db
|
||||
.select({
|
||||
acceptedCountSince: sql<string>`count(*) filter (where ${schema.anonymousMessages.createdAt} >= ${acceptedSinceIso}::timestamptz)`,
|
||||
earliestAcceptedAtSince: sql<
|
||||
string | Date | null
|
||||
>`min(${schema.anonymousMessages.createdAt}) filter (where ${schema.anonymousMessages.createdAt} >= ${acceptedSinceIso}::timestamptz)`,
|
||||
lastAcceptedAt: sql<string | Date | null>`max(${schema.anonymousMessages.createdAt})`
|
||||
})
|
||||
.from(schema.anonymousMessages)
|
||||
@@ -65,16 +69,13 @@ export function createDbAnonymousFeedbackRepository(
|
||||
)
|
||||
)
|
||||
|
||||
const earliestAcceptedAtSinceRaw = rows[0]?.earliestAcceptedAtSince ?? null
|
||||
const lastAcceptedAtRaw = rows[0]?.lastAcceptedAt ?? null
|
||||
|
||||
return {
|
||||
acceptedCountSince: Number(rows[0]?.acceptedCountSince ?? '0'),
|
||||
lastAcceptedAt:
|
||||
lastAcceptedAtRaw instanceof Date
|
||||
? lastAcceptedAtRaw
|
||||
: typeof lastAcceptedAtRaw === 'string'
|
||||
? new Date(lastAcceptedAtRaw)
|
||||
: null
|
||||
earliestAcceptedAtSince: instantFromDatabaseValue(earliestAcceptedAtSinceRaw),
|
||||
lastAcceptedAt: instantFromDatabaseValue(lastAcceptedAtRaw)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -146,7 +147,7 @@ export function createDbAnonymousFeedbackRepository(
|
||||
postedChatId: input.postedChatId,
|
||||
postedThreadId: input.postedThreadId,
|
||||
postedMessageId: input.postedMessageId,
|
||||
postedAt: input.postedAt,
|
||||
postedAt: instantToDate(input.postedAt),
|
||||
failureReason: null
|
||||
})
|
||||
.where(eq(schema.anonymousMessages.id, input.submissionId))
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { and, desc, eq, gte, isNotNull, isNull, lte, or, sql } from 'drizzle-orm'
|
||||
import { and, desc, eq, gte, isNotNull, isNull, lt, lte, or, sql } from 'drizzle-orm'
|
||||
|
||||
import { createDbClient, schema } from '@household/db'
|
||||
import type { FinanceRepository } from '@household/ports'
|
||||
import type { CurrencyCode } from '@household/domain'
|
||||
import {
|
||||
instantFromDatabaseValue,
|
||||
instantToDate,
|
||||
nowInstant,
|
||||
type CurrencyCode
|
||||
} from '@household/domain'
|
||||
|
||||
function toCurrencyCode(raw: string): CurrencyCode {
|
||||
const normalized = raw.trim().toUpperCase()
|
||||
@@ -171,7 +176,7 @@ export function createDbFinanceRepository(
|
||||
await db
|
||||
.update(schema.billingCycles)
|
||||
.set({
|
||||
closedAt
|
||||
closedAt: instantToDate(closedAt)
|
||||
})
|
||||
.where(eq(schema.billingCycles.id, cycleId))
|
||||
},
|
||||
@@ -265,7 +270,8 @@ export function createDbFinanceRepository(
|
||||
|
||||
return rows.map((row) => ({
|
||||
...row,
|
||||
currency: toCurrencyCode(row.currency)
|
||||
currency: toCurrencyCode(row.currency),
|
||||
createdAt: instantFromDatabaseValue(row.createdAt)!
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -284,8 +290,8 @@ export function createDbFinanceRepository(
|
||||
eq(schema.purchaseMessages.householdId, householdId),
|
||||
isNotNull(schema.purchaseMessages.senderMemberId),
|
||||
isNotNull(schema.purchaseMessages.parsedAmountMinor),
|
||||
gte(schema.purchaseMessages.messageSentAt, start),
|
||||
lte(schema.purchaseMessages.messageSentAt, end)
|
||||
gte(schema.purchaseMessages.messageSentAt, instantToDate(start)),
|
||||
lt(schema.purchaseMessages.messageSentAt, instantToDate(end))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -294,7 +300,7 @@ export function createDbFinanceRepository(
|
||||
payerMemberId: row.payerMemberId!,
|
||||
amountMinor: row.amountMinor!,
|
||||
description: row.description,
|
||||
occurredAt: row.occurredAt
|
||||
occurredAt: instantFromDatabaseValue(row.occurredAt)
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -316,7 +322,7 @@ export function createDbFinanceRepository(
|
||||
inputHash: snapshot.inputHash,
|
||||
totalDueMinor: snapshot.totalDueMinor,
|
||||
currency: snapshot.currency,
|
||||
computedAt: new Date(),
|
||||
computedAt: instantToDate(nowInstant()),
|
||||
metadata: snapshot.metadata
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
|
||||
import { createDbClient, schema } from '@household/db'
|
||||
import { instantToDate, nowInstant } from '@household/domain'
|
||||
import {
|
||||
HOUSEHOLD_TOPIC_ROLES,
|
||||
type HouseholdConfigurationRepository,
|
||||
@@ -138,7 +139,7 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
.set({
|
||||
telegramChatType: input.telegramChatType,
|
||||
title: nextTitle,
|
||||
updatedAt: new Date()
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
})
|
||||
.where(eq(schema.householdTelegramChats.telegramChatId, input.telegramChatId))
|
||||
|
||||
@@ -256,7 +257,7 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
set: {
|
||||
telegramThreadId: input.telegramThreadId,
|
||||
topicName: input.topicName?.trim() || null,
|
||||
updatedAt: new Date()
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
}
|
||||
})
|
||||
.returning({
|
||||
@@ -348,7 +349,7 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
set: {
|
||||
token: input.token,
|
||||
createdByTelegramUserId: input.createdByTelegramUserId ?? null,
|
||||
updatedAt: new Date()
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
}
|
||||
})
|
||||
.returning({
|
||||
@@ -448,7 +449,7 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
displayName: input.displayName,
|
||||
username: input.username?.trim() || null,
|
||||
languageCode: input.languageCode?.trim() || null,
|
||||
updatedAt: new Date()
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
}
|
||||
})
|
||||
.returning({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
|
||||
import { createDbClient, schema } from '@household/db'
|
||||
import { instantFromDatabaseValue, instantToDate, nowInstant, Temporal } from '@household/domain'
|
||||
import type {
|
||||
TelegramPendingActionRecord,
|
||||
TelegramPendingActionRepository,
|
||||
@@ -20,7 +21,7 @@ function mapPendingAction(row: {
|
||||
telegramChatId: string
|
||||
action: string
|
||||
payload: unknown
|
||||
expiresAt: Date | null
|
||||
expiresAt: Date | string | null
|
||||
}): TelegramPendingActionRecord {
|
||||
return {
|
||||
telegramUserId: row.telegramUserId,
|
||||
@@ -30,7 +31,7 @@ function mapPendingAction(row: {
|
||||
row.payload && typeof row.payload === 'object' && !Array.isArray(row.payload)
|
||||
? (row.payload as Record<string, unknown>)
|
||||
: {},
|
||||
expiresAt: row.expiresAt
|
||||
expiresAt: instantFromDatabaseValue(row.expiresAt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +53,8 @@ export function createDbTelegramPendingActionRepository(databaseUrl: string): {
|
||||
telegramChatId: input.telegramChatId,
|
||||
action: input.action,
|
||||
payload: input.payload,
|
||||
expiresAt: input.expiresAt,
|
||||
updatedAt: new Date()
|
||||
expiresAt: input.expiresAt ? instantToDate(input.expiresAt) : null,
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: [
|
||||
@@ -63,8 +64,8 @@ export function createDbTelegramPendingActionRepository(databaseUrl: string): {
|
||||
set: {
|
||||
action: input.action,
|
||||
payload: input.payload,
|
||||
expiresAt: input.expiresAt,
|
||||
updatedAt: new Date()
|
||||
expiresAt: input.expiresAt ? instantToDate(input.expiresAt) : null,
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
}
|
||||
})
|
||||
.returning({
|
||||
@@ -84,7 +85,7 @@ export function createDbTelegramPendingActionRepository(databaseUrl: string): {
|
||||
},
|
||||
|
||||
async getPendingAction(telegramChatId, telegramUserId) {
|
||||
const now = new Date()
|
||||
const now = nowInstant()
|
||||
const rows = await db
|
||||
.select({
|
||||
telegramUserId: schema.telegramPendingActions.telegramUserId,
|
||||
@@ -107,7 +108,8 @@ export function createDbTelegramPendingActionRepository(databaseUrl: string): {
|
||||
return null
|
||||
}
|
||||
|
||||
if (row.expiresAt && row.expiresAt.getTime() <= now.getTime()) {
|
||||
const expiresAt = instantFromDatabaseValue(row.expiresAt)
|
||||
if (expiresAt && Temporal.Instant.compare(expiresAt, now) <= 0) {
|
||||
await db
|
||||
.delete(schema.telegramPendingActions)
|
||||
.where(
|
||||
@@ -120,7 +122,16 @@ export function createDbTelegramPendingActionRepository(databaseUrl: string): {
|
||||
return null
|
||||
}
|
||||
|
||||
return mapPendingAction(row)
|
||||
return {
|
||||
telegramUserId: row.telegramUserId,
|
||||
telegramChatId: row.telegramChatId,
|
||||
action: parsePendingActionType(row.action),
|
||||
payload:
|
||||
row.payload && typeof row.payload === 'object' && !Array.isArray(row.payload)
|
||||
? (row.payload as Record<string, unknown>)
|
||||
: {},
|
||||
expiresAt
|
||||
}
|
||||
},
|
||||
|
||||
async clearPendingAction(telegramChatId, telegramUserId) {
|
||||
|
||||
Reference in New Issue
Block a user