forked from Split-Naira/SplitNaira
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPayoutHistoryService.ts
More file actions
140 lines (123 loc) · 4.11 KB
/
Copy pathPayoutHistoryService.ts
File metadata and controls
140 lines (123 loc) · 4.11 KB
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* Payout history service refactored to read from PostgreSQL database (#321).
*/
import { getDataSource } from "./database.js";
import { TransactionRecord } from "../entities/Transaction.js";
import { logger } from "./logger.js";
import { Like } from "typeorm";
export interface PayoutRecord {
id: string;
roundId: string;
recipient: string;
amount: string;
token: string;
timestamp: number;
txHash: string;
status: 'pending' | 'completed' | 'failed';
}
export interface PayoutHistoryIndex {
getPayouts(filters?: PayoutFilters): Promise<PayoutRecord[]>;
getPayoutById(id: string): Promise<PayoutRecord | null>;
getPayoutsByRound(roundId: string): Promise<PayoutRecord[]>;
getPayoutsByRecipient(recipient: string): Promise<PayoutRecord[]>;
searchPayouts(query: string): Promise<PayoutRecord[]>;
reindex(): Promise<void>;
backfill(fromRound?: number): Promise<void>;
/** Release in-memory resources. Call on graceful shutdown. */
destroy(): void;
}
export interface PayoutFilters {
startDate?: number;
endDate?: number;
recipient?: string;
status?: 'pending' | 'completed' | 'failed';
limit?: number;
offset?: number;
}
export interface PayoutIndexConfig {
storageFile: string;
reindexInterval: number;
maxCacheSize: number;
}
export function createPayoutHistoryService(_config?: Partial<PayoutIndexConfig>): PayoutHistoryIndex {
return {
async getPayouts(filters) {
try {
const repo = getDataSource().getRepository(TransactionRecord);
const query = repo.createQueryBuilder("transaction");
if (filters?.recipient) {
query.andWhere("transaction.recipient = :recipient", { recipient: filters.recipient });
}
if (filters?.status) {
query.andWhere("transaction.status = :status", { status: filters.status });
}
if (filters?.startDate !== undefined) {
query.andWhere("transaction.timestamp >= :startDate", { startDate: filters.startDate });
}
if (filters?.endDate !== undefined) {
query.andWhere("transaction.timestamp <= :endDate", { endDate: filters.endDate });
}
query.orderBy("transaction.timestamp", "DESC");
if (filters?.offset !== undefined) {
query.skip(filters.offset);
}
if (filters?.limit !== undefined) {
query.take(filters.limit);
}
const records = await query.getMany();
return records as PayoutRecord[];
} catch (error) {
logger.error("Error fetching payouts from database", { error });
return [];
}
},
async getPayoutById(id) {
try {
const repo = getDataSource().getRepository(TransactionRecord);
const record = await repo.findOneBy({ id });
return (record as PayoutRecord) ?? null;
} catch (error) {
logger.error("Error fetching payout by ID", { id, error });
return null;
}
},
async getPayoutsByRound(roundId) {
try {
const repo = getDataSource().getRepository(TransactionRecord);
const records = await repo.findBy({ roundId });
return records as PayoutRecord[];
} catch (error) {
logger.error("Error fetching payouts by round", { roundId, error });
return [];
}
},
async getPayoutsByRecipient(recipient) {
return this.getPayouts({ recipient });
},
async searchPayouts(query) {
try {
const repo = getDataSource().getRepository(TransactionRecord);
const records = await repo.find({
where: [
{ recipient: Like(`%${query}%`) },
{ txHash: Like(`%${query}%`) },
{ roundId: Like(`%${query}%`) }
]
});
return records as PayoutRecord[];
} catch (error) {
logger.error("Error searching payouts", { query, error });
return [];
}
},
async reindex() {
logger.info("Reindexing database payout history...");
},
async backfill(fromRound) {
logger.info(`Backfilling from round ${fromRound ?? 0}`);
},
destroy() {
// Database connection lifetime is managed globally. No-op.
}
};
}