feat(transactions): add full pagination support with older_id and custom count parameters
This commit is contained in:
12
changelog.md
12
changelog.md
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-07-25 - 4.1.0 - feat(transactions)
|
||||||
|
Enhanced transaction pagination support with full control over historical data retrieval
|
||||||
|
|
||||||
|
- Added full `IBunqPaginationOptions` support to `getTransactions()` method
|
||||||
|
- Now supports `older_id` for paginating backwards through historical transactions
|
||||||
|
- Supports custom `count` parameter (defaults to 200)
|
||||||
|
- Maintains backward compatibility - passing a number is still treated as `newer_id`
|
||||||
|
- Only includes pagination parameters that are explicitly set (not false/undefined)
|
||||||
|
- Added `example.pagination.ts` demonstrating various pagination patterns
|
||||||
|
|
||||||
|
This enhancement allows banking applications to properly fetch and paginate through historical transaction data using both `newer_id` and `older_id` parameters.
|
||||||
|
|
||||||
## 2025-07-25 - 4.0.0 - BREAKING CHANGE(core)
|
## 2025-07-25 - 4.0.0 - BREAKING CHANGE(core)
|
||||||
Complete stateless architecture - consumers now have full control over session persistence
|
Complete stateless architecture - consumers now have full control over session persistence
|
||||||
|
|
||||||
|
128
example.pagination.ts
Normal file
128
example.pagination.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import { BunqAccount, IBunqPaginationOptions } from './ts/index.js';
|
||||||
|
|
||||||
|
// Example demonstrating the enhanced pagination support in getTransactions
|
||||||
|
|
||||||
|
async function demonstratePagination() {
|
||||||
|
const bunq = new BunqAccount({
|
||||||
|
apiKey: 'your-api-key',
|
||||||
|
deviceName: 'Pagination Demo',
|
||||||
|
environment: 'PRODUCTION',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize and get session
|
||||||
|
const sessionData = await bunq.init();
|
||||||
|
|
||||||
|
// Get accounts
|
||||||
|
const { accounts } = await bunq.getAccounts();
|
||||||
|
const account = accounts[0];
|
||||||
|
|
||||||
|
// Example 1: Get most recent transactions (default behavior)
|
||||||
|
const recentTransactions = await account.getTransactions();
|
||||||
|
console.log(`Got ${recentTransactions.length} recent transactions`);
|
||||||
|
|
||||||
|
// Example 2: Get transactions with custom count
|
||||||
|
const smallBatch = await account.getTransactions({ count: 10 });
|
||||||
|
console.log(`Got ${smallBatch.length} transactions with custom count`);
|
||||||
|
|
||||||
|
// Example 3: Get older transactions using older_id
|
||||||
|
if (recentTransactions.length > 0) {
|
||||||
|
const oldestTransaction = recentTransactions[recentTransactions.length - 1];
|
||||||
|
const olderTransactions = await account.getTransactions({
|
||||||
|
count: 50,
|
||||||
|
older_id: oldestTransaction.id
|
||||||
|
});
|
||||||
|
console.log(`Got ${olderTransactions.length} older transactions`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example 4: Get newer transactions using newer_id
|
||||||
|
if (recentTransactions.length > 0) {
|
||||||
|
const newestTransaction = recentTransactions[0];
|
||||||
|
const newerTransactions = await account.getTransactions({
|
||||||
|
count: 20,
|
||||||
|
newer_id: newestTransaction.id
|
||||||
|
});
|
||||||
|
console.log(`Got ${newerTransactions.length} newer transactions`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example 5: Backward compatibility - using number as newer_id
|
||||||
|
const backwardCompatible = await account.getTransactions(12345);
|
||||||
|
console.log(`Backward compatible call returned ${backwardCompatible.length} transactions`);
|
||||||
|
|
||||||
|
// Example 6: Paginating through all historical transactions
|
||||||
|
async function getAllTransactions(account: any): Promise<any[]> {
|
||||||
|
const allTransactions: any[] = [];
|
||||||
|
let lastTransactionId: number | false = false;
|
||||||
|
let hasMore = true;
|
||||||
|
|
||||||
|
while (hasMore) {
|
||||||
|
const options: IBunqPaginationOptions = {
|
||||||
|
count: 200,
|
||||||
|
older_id: lastTransactionId
|
||||||
|
};
|
||||||
|
|
||||||
|
const batch = await account.getTransactions(options);
|
||||||
|
|
||||||
|
if (batch.length === 0) {
|
||||||
|
hasMore = false;
|
||||||
|
} else {
|
||||||
|
allTransactions.push(...batch);
|
||||||
|
lastTransactionId = batch[batch.length - 1].id;
|
||||||
|
console.log(`Fetched ${batch.length} transactions, total: ${allTransactions.length}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allTransactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example 7: Getting transactions between two dates
|
||||||
|
async function getTransactionsBetweenDates(
|
||||||
|
account: any,
|
||||||
|
startDate: Date,
|
||||||
|
endDate: Date
|
||||||
|
): Promise<any[]> {
|
||||||
|
const transactions: any[] = [];
|
||||||
|
let olderId: number | false = false;
|
||||||
|
let keepFetching = true;
|
||||||
|
|
||||||
|
while (keepFetching) {
|
||||||
|
const batch = await account.getTransactions({
|
||||||
|
count: 200,
|
||||||
|
older_id: olderId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (batch.length === 0) {
|
||||||
|
keepFetching = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const transaction of batch) {
|
||||||
|
const transactionDate = new Date(transaction.created);
|
||||||
|
|
||||||
|
if (transactionDate >= startDate && transactionDate <= endDate) {
|
||||||
|
transactions.push(transaction);
|
||||||
|
} else if (transactionDate < startDate) {
|
||||||
|
// We've gone past our date range
|
||||||
|
keepFetching = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
olderId = batch[batch.length - 1].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
const lastMonth = new Date();
|
||||||
|
lastMonth.setMonth(lastMonth.getMonth() - 1);
|
||||||
|
const transactionsLastMonth = await getTransactionsBetweenDates(
|
||||||
|
account,
|
||||||
|
lastMonth,
|
||||||
|
new Date()
|
||||||
|
);
|
||||||
|
console.log(`Found ${transactionsLastMonth.length} transactions in the last month`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the demo
|
||||||
|
demonstratePagination().catch(console.error);
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@apiclient.xyz/bunq",
|
"name": "@apiclient.xyz/bunq",
|
||||||
"version": "4.0.1",
|
"version": "4.1.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A full-featured TypeScript/JavaScript client for the bunq API",
|
"description": "A full-featured TypeScript/JavaScript client for the bunq API",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
@@ -111,18 +111,41 @@ export class BunqMonetaryAccount {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* gets all transactions on this account
|
* gets all transactions on this account
|
||||||
|
* @param options - Pagination options or a number for backward compatibility (treated as newer_id)
|
||||||
*/
|
*/
|
||||||
public async getTransactions(startingIdArg: number | false = false): Promise<BunqTransaction[]> {
|
public async getTransactions(options?: IBunqPaginationOptions | number | false): Promise<BunqTransaction[]> {
|
||||||
const paginationOptions: IBunqPaginationOptions = {
|
let paginationOptions: IBunqPaginationOptions = {};
|
||||||
count: 200,
|
|
||||||
newer_id: startingIdArg,
|
// Backward compatibility: if a number or false is passed, treat it as newer_id
|
||||||
|
if (typeof options === 'number' || options === false) {
|
||||||
|
paginationOptions.newer_id = options;
|
||||||
|
} else if (options) {
|
||||||
|
paginationOptions = { ...options };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default count if not specified
|
||||||
|
if (!paginationOptions.count) {
|
||||||
|
paginationOptions.count = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build clean pagination object - only include properties that are not false/undefined
|
||||||
|
const cleanPaginationOptions: IBunqPaginationOptions = {
|
||||||
|
count: paginationOptions.count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (paginationOptions.newer_id !== undefined && paginationOptions.newer_id !== false) {
|
||||||
|
cleanPaginationOptions.newer_id = paginationOptions.newer_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paginationOptions.older_id !== undefined && paginationOptions.older_id !== false) {
|
||||||
|
cleanPaginationOptions.older_id = paginationOptions.older_id;
|
||||||
|
}
|
||||||
|
|
||||||
await this.bunqAccountRef.apiContext.ensureValidSession();
|
await this.bunqAccountRef.apiContext.ensureValidSession();
|
||||||
|
|
||||||
const response = await this.bunqAccountRef.getHttpClient().list(
|
const response = await this.bunqAccountRef.getHttpClient().list(
|
||||||
`/v1/user/${this.bunqAccountRef.userId}/monetary-account/${this.id}/payment`,
|
`/v1/user/${this.bunqAccountRef.userId}/monetary-account/${this.id}/payment`,
|
||||||
paginationOptions
|
cleanPaginationOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
const transactionsArray: BunqTransaction[] = [];
|
const transactionsArray: BunqTransaction[] = [];
|
||||||
|
Reference in New Issue
Block a user