@fairmint/canton-fairmint-sdk 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.d.ts +26 -0
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.js +219 -0
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.d.ts +30 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.js +208 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.d.ts +9 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.js +21 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.d.ts +95 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.js +592 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.d.ts +26 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.js +190 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.d.ts +41 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.js +467 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.d.ts +48 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.js +419 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.d.ts +25 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.js +206 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.d.ts +11 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.js +54 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmintDbClient.d.ts +87 -132
- package/dist/clients/postgres-db-api/fairmintDbClient.d.ts.map +1 -1
- package/dist/clients/postgres-db-api/fairmintDbClient.js +183 -2973
- package/dist/clients/postgres-db-api/fairmintDbClient.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimeSeriesRepository = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
/**
|
|
7
|
+
* Repository for time series data analytics.
|
|
8
|
+
*/
|
|
9
|
+
class TimeSeriesRepository extends base_1.BaseRepository {
|
|
10
|
+
getTimeSeriesConfig(timeRange, column, timePeriod, customStartDate, startParamIndex = 1) {
|
|
11
|
+
let interval;
|
|
12
|
+
let timeFilter;
|
|
13
|
+
let timeSeriesStart;
|
|
14
|
+
let timeSeriesEnd = 'NOW()';
|
|
15
|
+
let timeRangeInterval;
|
|
16
|
+
const paramValues = [];
|
|
17
|
+
let nextParamIndex = startParamIndex;
|
|
18
|
+
switch (timeRange) {
|
|
19
|
+
case '15m':
|
|
20
|
+
interval = 'minute';
|
|
21
|
+
timeFilter = `${column} >= NOW() - INTERVAL '15 minutes'`;
|
|
22
|
+
timeRangeInterval = '15 minutes';
|
|
23
|
+
timeSeriesStart = "NOW() - INTERVAL '15 minutes'";
|
|
24
|
+
break;
|
|
25
|
+
case '1h':
|
|
26
|
+
interval = 'minute';
|
|
27
|
+
timeFilter = `${column} >= NOW() - INTERVAL '1 hour'`;
|
|
28
|
+
timeRangeInterval = '1 hour';
|
|
29
|
+
timeSeriesStart = "NOW() - INTERVAL '1 hour'";
|
|
30
|
+
break;
|
|
31
|
+
case '6h':
|
|
32
|
+
interval = 'minute';
|
|
33
|
+
timeFilter = `${column} >= NOW() - INTERVAL '6 hours'`;
|
|
34
|
+
timeRangeInterval = '6 hours';
|
|
35
|
+
timeSeriesStart = "NOW() - INTERVAL '6 hours'";
|
|
36
|
+
break;
|
|
37
|
+
case '1d':
|
|
38
|
+
interval = 'hour';
|
|
39
|
+
timeFilter = `${column} >= NOW() - INTERVAL '1 day'`;
|
|
40
|
+
timeRangeInterval = '1 day';
|
|
41
|
+
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
42
|
+
break;
|
|
43
|
+
case '7d':
|
|
44
|
+
interval = 'hour';
|
|
45
|
+
timeFilter = `${column} >= NOW() - INTERVAL '7 days'`;
|
|
46
|
+
timeRangeInterval = '7 days';
|
|
47
|
+
timeSeriesStart = "NOW() - INTERVAL '7 days'";
|
|
48
|
+
break;
|
|
49
|
+
case '30d':
|
|
50
|
+
interval = 'day';
|
|
51
|
+
timeFilter = `${column} >= NOW() - INTERVAL '30 days'`;
|
|
52
|
+
timeRangeInterval = '30 days';
|
|
53
|
+
timeSeriesStart = "NOW() - INTERVAL '30 days'";
|
|
54
|
+
break;
|
|
55
|
+
case 'last-month':
|
|
56
|
+
interval = 'day';
|
|
57
|
+
timeFilter = `${column} >= date_trunc('month', current_date - interval '1 month') AND ${column} < date_trunc('month', current_date)`;
|
|
58
|
+
timeRangeInterval = '1 month';
|
|
59
|
+
timeSeriesStart =
|
|
60
|
+
"date_trunc('month', current_date - interval '1 month')";
|
|
61
|
+
timeSeriesEnd = "date_trunc('month', current_date)";
|
|
62
|
+
break;
|
|
63
|
+
case 'all':
|
|
64
|
+
interval = 'day';
|
|
65
|
+
timeFilter = '1=1';
|
|
66
|
+
timeRangeInterval = '100 years';
|
|
67
|
+
timeSeriesStart = "'2023-01-01'::timestamp";
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
interval = 'hour';
|
|
71
|
+
timeFilter = `${column} >= NOW() - INTERVAL '1 day'`;
|
|
72
|
+
timeRangeInterval = '1 day';
|
|
73
|
+
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
74
|
+
}
|
|
75
|
+
// If custom start date is provided, override the timeFilter and time series start/end
|
|
76
|
+
// Use parameterized queries to prevent SQL injection
|
|
77
|
+
if (timePeriod === 'custom-start' && customStartDate) {
|
|
78
|
+
const customStartWithSeconds = `${customStartDate}:00`;
|
|
79
|
+
paramValues.push(customStartWithSeconds);
|
|
80
|
+
const customStartParam = `$${nextParamIndex}`;
|
|
81
|
+
nextParamIndex++;
|
|
82
|
+
timeFilter = `${column} >= ${customStartParam}::timestamp AND ${column} < (${customStartParam}::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
83
|
+
timeSeriesStart = `${customStartParam}::timestamp`;
|
|
84
|
+
timeSeriesEnd = `(${customStartParam}::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
interval,
|
|
88
|
+
timeFilter,
|
|
89
|
+
timeSeriesStart,
|
|
90
|
+
timeSeriesEnd,
|
|
91
|
+
timeRangeInterval,
|
|
92
|
+
paramValues,
|
|
93
|
+
nextParamIndex,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async getTransferTimeSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate) {
|
|
97
|
+
const config = this.getTimeSeriesConfig(timeRange, 'created_at', timePeriod, customStartDate);
|
|
98
|
+
const { interval, timeFilter, timeSeriesStart, timeSeriesEnd, paramValues, } = config;
|
|
99
|
+
const query = `
|
|
100
|
+
WITH time_series AS (
|
|
101
|
+
SELECT generate_series(
|
|
102
|
+
date_trunc('${interval}', ${timeSeriesStart}),
|
|
103
|
+
date_trunc('${interval}', ${timeSeriesEnd}),
|
|
104
|
+
INTERVAL '1 ${interval}'
|
|
105
|
+
) AS timestamp
|
|
106
|
+
),
|
|
107
|
+
transfer_data AS (
|
|
108
|
+
SELECT
|
|
109
|
+
date_trunc('${interval}', created_at) AS timestamp,
|
|
110
|
+
COUNT(*) as count,
|
|
111
|
+
COALESCE(SUM(transfer_amount), 0) as amount
|
|
112
|
+
FROM canton_transfers
|
|
113
|
+
WHERE ${timeFilter}
|
|
114
|
+
AND status IN ('pending', 'submitted', 'confirmed')
|
|
115
|
+
GROUP BY date_trunc('${interval}', created_at)
|
|
116
|
+
)
|
|
117
|
+
SELECT
|
|
118
|
+
ts.timestamp::text,
|
|
119
|
+
COALESCE(td.count, 0) as count,
|
|
120
|
+
COALESCE(td.amount, 0) as amount
|
|
121
|
+
FROM time_series ts
|
|
122
|
+
LEFT JOIN transfer_data td ON ts.timestamp = td.timestamp
|
|
123
|
+
ORDER BY ts.timestamp ASC
|
|
124
|
+
`;
|
|
125
|
+
const result = await this.pool.query(query, paramValues);
|
|
126
|
+
return result.rows.map(row => ({
|
|
127
|
+
timestamp: row.timestamp,
|
|
128
|
+
count: parseInt(row.count, 10),
|
|
129
|
+
amount: parseFloat(row.amount),
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
async getRewardCouponTimeSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, couponStatus = 'all') {
|
|
133
|
+
const config = this.getTimeSeriesConfig(timeRange, 'tx_record_time', timePeriod, customStartDate);
|
|
134
|
+
const { interval, timeFilter, timeSeriesStart, timeSeriesEnd, paramValues, } = config;
|
|
135
|
+
let { nextParamIndex } = config;
|
|
136
|
+
// Add party filter if provided using parameterized query
|
|
137
|
+
let partyCondition = '';
|
|
138
|
+
if (partyFilter) {
|
|
139
|
+
partyCondition = ` AND beneficiary_party_id = $${nextParamIndex}`;
|
|
140
|
+
paramValues.push(partyFilter);
|
|
141
|
+
nextParamIndex++;
|
|
142
|
+
}
|
|
143
|
+
// Add status filter based on couponStatus
|
|
144
|
+
let statusCondition = '';
|
|
145
|
+
if (couponStatus === 'created') {
|
|
146
|
+
statusCondition = ` AND status = 'created'`;
|
|
147
|
+
}
|
|
148
|
+
else if (couponStatus === 'archived') {
|
|
149
|
+
statusCondition = ` AND status = 'archived'`;
|
|
150
|
+
}
|
|
151
|
+
const query = `
|
|
152
|
+
WITH time_series AS (
|
|
153
|
+
SELECT generate_series(
|
|
154
|
+
date_trunc('${interval}', ${timeSeriesStart}),
|
|
155
|
+
date_trunc('${interval}', ${timeSeriesEnd}),
|
|
156
|
+
INTERVAL '1 ${interval}'
|
|
157
|
+
) AS timestamp
|
|
158
|
+
),
|
|
159
|
+
coupon_data AS (
|
|
160
|
+
SELECT
|
|
161
|
+
date_trunc('${interval}', tx_record_time) AS timestamp,
|
|
162
|
+
COUNT(*) as count,
|
|
163
|
+
COALESCE(SUM(app_reward_amount), 0) as amount,
|
|
164
|
+
COALESCE(SUM(coupon_amount), 0) as coupon_amount
|
|
165
|
+
FROM canton_app_reward_coupons
|
|
166
|
+
WHERE ${timeFilter}${partyCondition}${statusCondition}
|
|
167
|
+
GROUP BY date_trunc('${interval}', tx_record_time)
|
|
168
|
+
)
|
|
169
|
+
SELECT
|
|
170
|
+
ts.timestamp::text,
|
|
171
|
+
COALESCE(cd.count, 0) as count,
|
|
172
|
+
COALESCE(cd.amount, 0) as amount,
|
|
173
|
+
COALESCE(cd.coupon_amount, 0) as coupon_amount
|
|
174
|
+
FROM time_series ts
|
|
175
|
+
LEFT JOIN coupon_data cd ON ts.timestamp = cd.timestamp
|
|
176
|
+
ORDER BY ts.timestamp ASC
|
|
177
|
+
`;
|
|
178
|
+
const result = await this.pool.query(query, paramValues);
|
|
179
|
+
return result.rows.map(row => ({
|
|
180
|
+
timestamp: row.timestamp,
|
|
181
|
+
count: parseInt(row.count, 10),
|
|
182
|
+
amount: parseFloat(row.amount),
|
|
183
|
+
couponAmount: parseFloat(row.coupon_amount),
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
async getRewardCouponRoundSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, couponStatus = 'all') {
|
|
187
|
+
let timeRangeInterval;
|
|
188
|
+
let timeFilter;
|
|
189
|
+
const paramValues = [];
|
|
190
|
+
let nextParamIndex = 1;
|
|
191
|
+
switch (timeRange) {
|
|
192
|
+
case '15m':
|
|
193
|
+
timeRangeInterval = '15 minutes';
|
|
194
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '15 minutes'";
|
|
195
|
+
break;
|
|
196
|
+
case '1h':
|
|
197
|
+
timeRangeInterval = '1 hour';
|
|
198
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 hour'";
|
|
199
|
+
break;
|
|
200
|
+
case '6h':
|
|
201
|
+
timeRangeInterval = '6 hours';
|
|
202
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '6 hours'";
|
|
203
|
+
break;
|
|
204
|
+
case '1d':
|
|
205
|
+
timeRangeInterval = '1 day';
|
|
206
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
207
|
+
break;
|
|
208
|
+
case '7d':
|
|
209
|
+
timeRangeInterval = '7 days';
|
|
210
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '7 days'";
|
|
211
|
+
break;
|
|
212
|
+
case '30d':
|
|
213
|
+
timeRangeInterval = '30 days';
|
|
214
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '30 days'";
|
|
215
|
+
break;
|
|
216
|
+
case 'last-month':
|
|
217
|
+
timeRangeInterval = '1 month';
|
|
218
|
+
timeFilter =
|
|
219
|
+
"tx_record_time >= date_trunc('month', current_date - interval '1 month') AND tx_record_time < date_trunc('month', current_date)";
|
|
220
|
+
break;
|
|
221
|
+
case 'all':
|
|
222
|
+
timeRangeInterval = '100 years';
|
|
223
|
+
timeFilter = '1=1';
|
|
224
|
+
break;
|
|
225
|
+
default:
|
|
226
|
+
timeRangeInterval = '1 day';
|
|
227
|
+
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
228
|
+
}
|
|
229
|
+
// Use parameterized query for customStartDate to prevent SQL injection
|
|
230
|
+
if (timePeriod === 'custom-start' && customStartDate) {
|
|
231
|
+
const customStartWithSeconds = `${customStartDate}:00`;
|
|
232
|
+
paramValues.push(customStartWithSeconds);
|
|
233
|
+
const customStartParam = `$${nextParamIndex}`;
|
|
234
|
+
nextParamIndex++;
|
|
235
|
+
timeFilter = `tx_record_time >= ${customStartParam}::timestamp AND tx_record_time < (${customStartParam}::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
236
|
+
}
|
|
237
|
+
// Add party filter if provided using parameterized query
|
|
238
|
+
let partyCondition = '';
|
|
239
|
+
if (partyFilter) {
|
|
240
|
+
partyCondition = ` AND beneficiary_party_id = $${nextParamIndex}`;
|
|
241
|
+
paramValues.push(partyFilter);
|
|
242
|
+
nextParamIndex++;
|
|
243
|
+
}
|
|
244
|
+
// Add status filter based on couponStatus
|
|
245
|
+
let statusCondition = '';
|
|
246
|
+
if (couponStatus === 'created') {
|
|
247
|
+
statusCondition = ` AND status = 'created'`;
|
|
248
|
+
}
|
|
249
|
+
else if (couponStatus === 'archived') {
|
|
250
|
+
statusCondition = ` AND status = 'archived'`;
|
|
251
|
+
}
|
|
252
|
+
const query = `
|
|
253
|
+
WITH time_filtered AS (
|
|
254
|
+
SELECT round_number
|
|
255
|
+
FROM canton_app_reward_coupons
|
|
256
|
+
WHERE ${timeFilter}${partyCondition}${statusCondition}
|
|
257
|
+
),
|
|
258
|
+
round_bounds AS (
|
|
259
|
+
SELECT
|
|
260
|
+
COALESCE(MIN(round_number), 0) AS min_round,
|
|
261
|
+
COALESCE(MAX(round_number), 0) AS max_round
|
|
262
|
+
FROM time_filtered
|
|
263
|
+
),
|
|
264
|
+
rounds AS (
|
|
265
|
+
SELECT generate_series(
|
|
266
|
+
GREATEST((SELECT min_round FROM round_bounds), 0),
|
|
267
|
+
GREATEST((SELECT max_round FROM round_bounds), 0)
|
|
268
|
+
) AS round
|
|
269
|
+
WHERE (SELECT max_round FROM round_bounds) > 0
|
|
270
|
+
),
|
|
271
|
+
coupon_data AS (
|
|
272
|
+
SELECT
|
|
273
|
+
round_number AS round,
|
|
274
|
+
MIN(tx_record_time) AS timestamp,
|
|
275
|
+
COUNT(*) AS count,
|
|
276
|
+
COALESCE(SUM(app_reward_amount), 0) AS amount,
|
|
277
|
+
COALESCE(SUM(coupon_amount), 0) AS coupon_amount
|
|
278
|
+
FROM canton_app_reward_coupons
|
|
279
|
+
WHERE round_number IN (SELECT round FROM rounds)${partyCondition}${statusCondition}
|
|
280
|
+
GROUP BY round_number
|
|
281
|
+
)
|
|
282
|
+
SELECT
|
|
283
|
+
r.round,
|
|
284
|
+
cd.timestamp,
|
|
285
|
+
COALESCE(cd.count, 0) AS count,
|
|
286
|
+
COALESCE(cd.amount, 0) AS amount,
|
|
287
|
+
COALESCE(cd.coupon_amount, 0) AS coupon_amount
|
|
288
|
+
FROM rounds r
|
|
289
|
+
LEFT JOIN coupon_data cd ON cd.round = r.round
|
|
290
|
+
ORDER BY r.round ASC
|
|
291
|
+
`;
|
|
292
|
+
const result = await this.pool.query(query, paramValues);
|
|
293
|
+
return result.rows.map(row => ({
|
|
294
|
+
timestamp: row.timestamp
|
|
295
|
+
? new Date(row.timestamp).toISOString()
|
|
296
|
+
: new Date().toISOString(),
|
|
297
|
+
count: parseInt(row.count, 10),
|
|
298
|
+
amount: parseFloat(row.amount),
|
|
299
|
+
couponAmount: parseFloat(row.coupon_amount),
|
|
300
|
+
round: typeof row.round === 'number' ? row.round : parseInt(row.round, 10),
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
303
|
+
async getAppMarkerTimeSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, _statusFilter) {
|
|
304
|
+
const config = this.getTimeSeriesConfig(timeRange, 'tx_record_time', timePeriod, customStartDate);
|
|
305
|
+
const { interval, timeFilter, timeSeriesStart, timeSeriesEnd, paramValues, } = config;
|
|
306
|
+
let { nextParamIndex } = config;
|
|
307
|
+
// Add party filter if provided using parameterized query
|
|
308
|
+
let partyCondition = '';
|
|
309
|
+
if (partyFilter) {
|
|
310
|
+
partyCondition = ` AND beneficiary_party_id = $${nextParamIndex}`;
|
|
311
|
+
paramValues.push(partyFilter);
|
|
312
|
+
nextParamIndex++;
|
|
313
|
+
}
|
|
314
|
+
const query = `
|
|
315
|
+
WITH time_series AS (
|
|
316
|
+
SELECT generate_series(
|
|
317
|
+
date_trunc('${interval}', ${timeSeriesStart}),
|
|
318
|
+
date_trunc('${interval}', ${timeSeriesEnd}),
|
|
319
|
+
INTERVAL '1 ${interval}'
|
|
320
|
+
) AS timestamp
|
|
321
|
+
),
|
|
322
|
+
marker_data AS (
|
|
323
|
+
SELECT
|
|
324
|
+
date_trunc('${interval}', tx_record_time) AS timestamp,
|
|
325
|
+
COUNT(*) FILTER (WHERE status = 'archived') as archived_count,
|
|
326
|
+
COUNT(*) FILTER (WHERE status = 'created') as created_count,
|
|
327
|
+
COALESCE(SUM(weight) FILTER (WHERE status = 'archived'), 0) as archived_weight,
|
|
328
|
+
COALESCE(SUM(weight) FILTER (WHERE status = 'created'), 0) as created_weight
|
|
329
|
+
FROM canton_app_markers
|
|
330
|
+
WHERE ${timeFilter}${partyCondition}
|
|
331
|
+
GROUP BY date_trunc('${interval}', tx_record_time)
|
|
332
|
+
)
|
|
333
|
+
SELECT
|
|
334
|
+
ts.timestamp::text,
|
|
335
|
+
COALESCE(md.archived_count, 0) as archived_count,
|
|
336
|
+
COALESCE(md.created_count, 0) as created_count,
|
|
337
|
+
COALESCE(md.archived_count, 0) + COALESCE(md.created_count, 0) as count,
|
|
338
|
+
COALESCE(md.archived_weight, 0) as archived_weight,
|
|
339
|
+
COALESCE(md.created_weight, 0) as created_weight,
|
|
340
|
+
0 as amount,
|
|
341
|
+
0 as coupon_amount
|
|
342
|
+
FROM time_series ts
|
|
343
|
+
LEFT JOIN marker_data md ON ts.timestamp = md.timestamp
|
|
344
|
+
ORDER BY ts.timestamp ASC
|
|
345
|
+
`;
|
|
346
|
+
const result = await this.pool.query(query, paramValues);
|
|
347
|
+
return result.rows.map(row => ({
|
|
348
|
+
timestamp: row.timestamp,
|
|
349
|
+
count: parseInt(row.count, 10),
|
|
350
|
+
archivedCount: parseInt(row.archived_count, 10),
|
|
351
|
+
createdCount: parseInt(row.created_count, 10),
|
|
352
|
+
archivedWeight: parseFloat(row.archived_weight),
|
|
353
|
+
createdWeight: parseFloat(row.created_weight),
|
|
354
|
+
amount: 0,
|
|
355
|
+
couponAmount: 0,
|
|
356
|
+
}));
|
|
357
|
+
}
|
|
358
|
+
async getAppMarkerRoundSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, _statusFilter) {
|
|
359
|
+
// Since app markers don't have a round_number, return current timestamp with mock data
|
|
360
|
+
const paramValues = [];
|
|
361
|
+
let nextParamIndex = 1;
|
|
362
|
+
// Add party filter if provided using parameterized query
|
|
363
|
+
let partyCondition = '';
|
|
364
|
+
if (partyFilter) {
|
|
365
|
+
partyCondition = ` AND beneficiary_party_id = $${nextParamIndex}`;
|
|
366
|
+
paramValues.push(partyFilter);
|
|
367
|
+
nextParamIndex++;
|
|
368
|
+
}
|
|
369
|
+
const query = `
|
|
370
|
+
SELECT
|
|
371
|
+
NOW()::text as timestamp,
|
|
372
|
+
COUNT(*) as count,
|
|
373
|
+
COUNT(*) FILTER (WHERE status = 'archived') as archived_count,
|
|
374
|
+
COUNT(*) FILTER (WHERE status = 'created') as created_count,
|
|
375
|
+
COALESCE(SUM(weight) FILTER (WHERE status = 'archived'), 0) as archived_weight,
|
|
376
|
+
COALESCE(SUM(weight) FILTER (WHERE status = 'created'), 0) as created_weight
|
|
377
|
+
FROM canton_app_markers
|
|
378
|
+
WHERE 1=1${partyCondition}
|
|
379
|
+
`;
|
|
380
|
+
const result = await this.pool.query(query, paramValues);
|
|
381
|
+
const row = result.rows[0] || {
|
|
382
|
+
count: 0,
|
|
383
|
+
archived_count: 0,
|
|
384
|
+
created_count: 0,
|
|
385
|
+
archived_weight: 0,
|
|
386
|
+
created_weight: 0,
|
|
387
|
+
};
|
|
388
|
+
return [
|
|
389
|
+
{
|
|
390
|
+
timestamp: new Date().toISOString(),
|
|
391
|
+
count: parseInt(row.count, 10),
|
|
392
|
+
round: 0,
|
|
393
|
+
archivedCount: parseInt(row.archived_count, 10),
|
|
394
|
+
createdCount: parseInt(row.created_count, 10),
|
|
395
|
+
archivedWeight: parseFloat(row.archived_weight),
|
|
396
|
+
createdWeight: parseFloat(row.created_weight),
|
|
397
|
+
},
|
|
398
|
+
];
|
|
399
|
+
}
|
|
400
|
+
async getMonthlyTransferTotal(monthStart, monthEnd) {
|
|
401
|
+
const query = `
|
|
402
|
+
SELECT COALESCE(SUM(transfer_amount), 0) as total_amount
|
|
403
|
+
FROM canton_transfers
|
|
404
|
+
WHERE tx_record_time >= $1
|
|
405
|
+
AND tx_record_time <= $2
|
|
406
|
+
AND status IN ($3, $4)
|
|
407
|
+
`;
|
|
408
|
+
const result = await this.pool.query(query, [
|
|
409
|
+
monthStart,
|
|
410
|
+
monthEnd,
|
|
411
|
+
types_1.TransferStatus.CONFIRMED,
|
|
412
|
+
types_1.TransferStatus.PENDING,
|
|
413
|
+
]);
|
|
414
|
+
const totalAmount = parseFloat(result.rows[0].total_amount);
|
|
415
|
+
return totalAmount;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
exports.TimeSeriesRepository = TimeSeriesRepository;
|
|
419
|
+
//# sourceMappingURL=time-series.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-series.js","sourceRoot":"","sources":["../../../../src/clients/postgres-db-api/fairmint-db/time-series.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseRepository } from './base';
|
|
2
|
+
import { type CantonTransfer } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Repository for Canton Transfer operations.
|
|
5
|
+
*/
|
|
6
|
+
export declare class TransfersRepository extends BaseRepository {
|
|
7
|
+
insertCantonTransfer(transfer: CantonTransfer): Promise<CantonTransfer>;
|
|
8
|
+
getCantonTransfer(id: number): Promise<CantonTransfer | null>;
|
|
9
|
+
getCantonTransferByTrackingId(apiTrackingId: string): Promise<CantonTransfer | null>;
|
|
10
|
+
getSubmittedTransfers(): Promise<CantonTransfer[]>;
|
|
11
|
+
updateCantonTransfer(id: number, updates: Partial<CantonTransfer>): Promise<CantonTransfer | null>;
|
|
12
|
+
getMonthlyTransferTotal(senderPartyId: string, startDate?: Date, endDate?: Date): Promise<number>;
|
|
13
|
+
getMonthlyPaymentTotalForParty(partyId: string, roundDurationMinutes?: number): Promise<{
|
|
14
|
+
totalSent: number;
|
|
15
|
+
remainingAllowance: number;
|
|
16
|
+
}>;
|
|
17
|
+
getRemainingRoundsInMonth(roundDurationMinutes?: number): number;
|
|
18
|
+
getMonthlyPaymentTotalsForParties(partyIds: string[]): Promise<Map<string, number>>;
|
|
19
|
+
getLifetimePaymentStatisticsForParties(partyIds: string[]): Promise<Map<string, {
|
|
20
|
+
paymentCount: number;
|
|
21
|
+
totalValueSent: number;
|
|
22
|
+
totalFeesPaid: number;
|
|
23
|
+
}>>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=transfers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfers.d.ts","sourceRoot":"","sources":["../../../../src/clients/postgres-db-api/fairmint-db/transfers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/D;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;IAC/C,oBAAoB,CACxB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,cAAc,CAAC;IAgCpB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAQ7D,6BAA6B,CACjC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAQ3B,qBAAqB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAUlD,oBAAoB,CACxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAgC3B,uBAAuB,CAC3B,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,IAAI,EAChB,OAAO,CAAC,EAAE,IAAI,GACb,OAAO,CAAC,MAAM,CAAC;IA2BZ,8BAA8B,CAClC,OAAO,EAAE,MAAM,EACf,oBAAoB,SAAK,GACxB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAE,CAAC;IAc7D,yBAAyB,CAAC,oBAAoB,SAAK,GAAG,MAAM;IAqBtD,iCAAiC,CACrC,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAmDzB,sCAAsC,CAC1C,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CACR,GAAG,CACD,MAAM,EACN;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CACxE,CACF;CAiDF"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransfersRepository = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
/**
|
|
7
|
+
* Repository for Canton Transfer operations.
|
|
8
|
+
*/
|
|
9
|
+
class TransfersRepository extends base_1.BaseRepository {
|
|
10
|
+
async insertCantonTransfer(transfer) {
|
|
11
|
+
const query = `
|
|
12
|
+
INSERT INTO canton_transfers (
|
|
13
|
+
api_tracking_id, api_expires_at,
|
|
14
|
+
transfer_sender_party_id, transfer_receiver_party_id, transfer_amount,
|
|
15
|
+
transfer_description, transfer_burned_amount, receiver_holding_cids,
|
|
16
|
+
sender_change_cids, tx_update_id, tx_record_time,
|
|
17
|
+
status, app_reward_coupon_id
|
|
18
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
19
|
+
RETURNING *
|
|
20
|
+
`;
|
|
21
|
+
const values = [
|
|
22
|
+
transfer.api_tracking_id,
|
|
23
|
+
transfer.api_expires_at,
|
|
24
|
+
transfer.transfer_sender_party_id,
|
|
25
|
+
transfer.transfer_receiver_party_id,
|
|
26
|
+
transfer.transfer_amount,
|
|
27
|
+
transfer.transfer_description,
|
|
28
|
+
transfer.transfer_burned_amount,
|
|
29
|
+
transfer.receiver_holding_cids,
|
|
30
|
+
transfer.sender_change_cids,
|
|
31
|
+
transfer.tx_update_id,
|
|
32
|
+
transfer.tx_record_time,
|
|
33
|
+
transfer.status,
|
|
34
|
+
transfer.app_reward_coupon_id,
|
|
35
|
+
];
|
|
36
|
+
const result = await this.pool.query(query, values);
|
|
37
|
+
return this.mapTransferFromDb(result.rows[0]);
|
|
38
|
+
}
|
|
39
|
+
async getCantonTransfer(id) {
|
|
40
|
+
const query = 'SELECT * FROM canton_transfers WHERE id = $1';
|
|
41
|
+
const result = await this.pool.query(query, [id]);
|
|
42
|
+
return result.rows.length > 0
|
|
43
|
+
? this.mapTransferFromDb(result.rows[0])
|
|
44
|
+
: null;
|
|
45
|
+
}
|
|
46
|
+
async getCantonTransferByTrackingId(apiTrackingId) {
|
|
47
|
+
const query = 'SELECT * FROM canton_transfers WHERE api_tracking_id = $1';
|
|
48
|
+
const result = await this.pool.query(query, [apiTrackingId]);
|
|
49
|
+
return result.rows.length > 0
|
|
50
|
+
? this.mapTransferFromDb(result.rows[0])
|
|
51
|
+
: null;
|
|
52
|
+
}
|
|
53
|
+
async getSubmittedTransfers() {
|
|
54
|
+
const query = `
|
|
55
|
+
SELECT * FROM canton_transfers
|
|
56
|
+
WHERE status = $1
|
|
57
|
+
ORDER BY created_at ASC
|
|
58
|
+
`;
|
|
59
|
+
const result = await this.pool.query(query, [types_1.TransferStatus.SUBMITTED]);
|
|
60
|
+
return result.rows.map(row => this.mapTransferFromDb(row));
|
|
61
|
+
}
|
|
62
|
+
async updateCantonTransfer(id, updates) {
|
|
63
|
+
const setClauses = [];
|
|
64
|
+
const values = [];
|
|
65
|
+
let paramIndex = 1;
|
|
66
|
+
// Build dynamic update query
|
|
67
|
+
Object.entries(updates).forEach(([key, value]) => {
|
|
68
|
+
if (key !== 'id' && key !== 'created_at') {
|
|
69
|
+
setClauses.push(`${this.toSnakeCase(key)} = $${paramIndex}`);
|
|
70
|
+
values.push(value);
|
|
71
|
+
paramIndex++;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (setClauses.length === 0) {
|
|
75
|
+
throw new Error('No valid fields to update');
|
|
76
|
+
}
|
|
77
|
+
values.push(id);
|
|
78
|
+
const query = `
|
|
79
|
+
UPDATE canton_transfers
|
|
80
|
+
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
81
|
+
WHERE id = $${paramIndex}
|
|
82
|
+
RETURNING *
|
|
83
|
+
`;
|
|
84
|
+
const result = await this.pool.query(query, values);
|
|
85
|
+
return result.rows.length > 0
|
|
86
|
+
? this.mapTransferFromDb(result.rows[0])
|
|
87
|
+
: null;
|
|
88
|
+
}
|
|
89
|
+
async getMonthlyTransferTotal(senderPartyId, startDate, endDate) {
|
|
90
|
+
const now = new Date();
|
|
91
|
+
const effectiveStartDate = startDate || new Date(now.getFullYear(), now.getMonth(), 1);
|
|
92
|
+
const effectiveEndDate = endDate || new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
|
93
|
+
const query = `
|
|
94
|
+
SELECT COALESCE(SUM(transfer_amount), 0) as total
|
|
95
|
+
FROM canton_transfers
|
|
96
|
+
WHERE transfer_sender_party_id = $1
|
|
97
|
+
AND created_at >= $2
|
|
98
|
+
AND created_at <= $3
|
|
99
|
+
AND status IN ($4, $5)
|
|
100
|
+
`;
|
|
101
|
+
const result = await this.pool.query(query, [
|
|
102
|
+
senderPartyId,
|
|
103
|
+
effectiveStartDate,
|
|
104
|
+
effectiveEndDate,
|
|
105
|
+
types_1.TransferStatus.SUBMITTED,
|
|
106
|
+
types_1.TransferStatus.CONFIRMED,
|
|
107
|
+
]);
|
|
108
|
+
return parseFloat(result.rows[0].total);
|
|
109
|
+
}
|
|
110
|
+
async getMonthlyPaymentTotalForParty(partyId, roundDurationMinutes = 10) {
|
|
111
|
+
// Get the current monthly total (value already sent this month)
|
|
112
|
+
const totalSent = await this.getMonthlyTransferTotal(partyId);
|
|
113
|
+
// Calculate remaining allowance
|
|
114
|
+
const remainingAllowance = this.getRemainingRoundsInMonth(roundDurationMinutes);
|
|
115
|
+
return {
|
|
116
|
+
totalSent,
|
|
117
|
+
remainingAllowance,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
getRemainingRoundsInMonth(roundDurationMinutes = 10) {
|
|
121
|
+
const now = new Date();
|
|
122
|
+
// Get end of current month
|
|
123
|
+
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
|
124
|
+
// Calculate remaining minutes
|
|
125
|
+
const remainingMs = endOfMonth.getTime() - now.getTime();
|
|
126
|
+
const remainingMinutes = remainingMs / (1000 * 60);
|
|
127
|
+
// Calculate remaining rounds
|
|
128
|
+
return Math.floor(remainingMinutes / roundDurationMinutes);
|
|
129
|
+
}
|
|
130
|
+
async getMonthlyPaymentTotalsForParties(partyIds) {
|
|
131
|
+
if (partyIds.length === 0) {
|
|
132
|
+
return new Map();
|
|
133
|
+
}
|
|
134
|
+
const now = new Date();
|
|
135
|
+
const startDate = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
136
|
+
const endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
|
137
|
+
// Build parameterized query with array of party IDs
|
|
138
|
+
const query = `
|
|
139
|
+
SELECT
|
|
140
|
+
transfer_sender_party_id as party_id,
|
|
141
|
+
COALESCE(SUM(transfer_amount), 0) as total
|
|
142
|
+
FROM canton_transfers
|
|
143
|
+
WHERE transfer_sender_party_id = ANY($1)
|
|
144
|
+
AND created_at >= $2
|
|
145
|
+
AND created_at <= $3
|
|
146
|
+
AND status IN ($4, $5)
|
|
147
|
+
GROUP BY transfer_sender_party_id
|
|
148
|
+
`;
|
|
149
|
+
const result = await this.pool.query(query, [
|
|
150
|
+
partyIds,
|
|
151
|
+
startDate,
|
|
152
|
+
endDate,
|
|
153
|
+
types_1.TransferStatus.SUBMITTED,
|
|
154
|
+
types_1.TransferStatus.CONFIRMED,
|
|
155
|
+
]);
|
|
156
|
+
// Convert to Map
|
|
157
|
+
const totalsMap = new Map();
|
|
158
|
+
// Initialize all party IDs with 0
|
|
159
|
+
partyIds.forEach(id => totalsMap.set(id, 0));
|
|
160
|
+
// Update with actual values from query
|
|
161
|
+
result.rows.forEach(row => {
|
|
162
|
+
totalsMap.set(row.party_id, parseFloat(row.total));
|
|
163
|
+
});
|
|
164
|
+
return totalsMap;
|
|
165
|
+
}
|
|
166
|
+
async getLifetimePaymentStatisticsForParties(partyIds) {
|
|
167
|
+
if (partyIds.length === 0) {
|
|
168
|
+
return new Map();
|
|
169
|
+
}
|
|
170
|
+
// Calculate total value sent and payment count
|
|
171
|
+
const query = `
|
|
172
|
+
SELECT
|
|
173
|
+
transfer_sender_party_id as party_id,
|
|
174
|
+
COUNT(*) as payment_count,
|
|
175
|
+
COALESCE(SUM(transfer_amount), 0) as total_value_sent
|
|
176
|
+
FROM canton_transfers
|
|
177
|
+
WHERE transfer_sender_party_id = ANY($1)
|
|
178
|
+
AND status IN ($2, $3)
|
|
179
|
+
GROUP BY transfer_sender_party_id
|
|
180
|
+
`;
|
|
181
|
+
const result = await this.pool.query(query, [
|
|
182
|
+
partyIds,
|
|
183
|
+
types_1.TransferStatus.SUBMITTED,
|
|
184
|
+
types_1.TransferStatus.CONFIRMED,
|
|
185
|
+
]);
|
|
186
|
+
// Convert to Map
|
|
187
|
+
const statsMap = new Map();
|
|
188
|
+
// Initialize all party IDs with zeros
|
|
189
|
+
partyIds.forEach(id => statsMap.set(id, {
|
|
190
|
+
paymentCount: 0,
|
|
191
|
+
totalValueSent: 0,
|
|
192
|
+
totalFeesPaid: 0,
|
|
193
|
+
}));
|
|
194
|
+
// Update with actual values from query
|
|
195
|
+
result.rows.forEach(row => {
|
|
196
|
+
statsMap.set(row.party_id, {
|
|
197
|
+
paymentCount: parseInt(row.payment_count, 10),
|
|
198
|
+
totalValueSent: parseFloat(row.total_value_sent),
|
|
199
|
+
totalFeesPaid: 0, // TODO: Calculate this when fee tracking is implemented
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
return statsMap;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.TransfersRepository = TransfersRepository;
|
|
206
|
+
//# sourceMappingURL=transfers.js.map
|