Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement iteration API, in addition to pagination API #235

Merged
merged 13 commits into from
Nov 17, 2021
Merged
26 changes: 26 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const nockfulTests = ['iteration'];

function createProject(displayName, testRegex, rest) {
return Object.assign({}, rest, {
testEnvironment: 'node',
setupFilesAfterEnv: ['jest-bluster'],
displayName,
testRegex
});
}

const projects = [
createProject('nockless tests', `/tests/(?!${nockfulTests.join('|')}).*/.+\\.test\\.[jt]s$`)
];

// Only execute the Nockful tests on Node.js 8+.
if (parseInt(process.version.substring(1)) >= 8) {
projects.push(createProject('nockful tests', `/tests/(?:${nockfulTests.join('|')}).*/.+\\.test\\.[jt]s$`));
}

module.exports = {
projects,
transform: {
'\\.[jt]s$': 'babel-jest'
}
};
25 changes: 3 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,35 +62,16 @@
"eslint-plugin-prettier": "^3.4.0",
"jest": "24.9.0",
"jest-bluster": "^1.0.1",
"nock": "^13.2.1",
"nock-record": "^0.3.9",
"prettier": "^2.3.2",
"rollup": "^2.55.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"ruply": "^1.0.0",
"typescript": "^4.3.5"
},
"jest": {
"testEnvironment": "node",
"moduleDirectories": [
"node_modules",
"dist",
"src"
],
"moduleFileExtensions": [
"ts",
"js"
],
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
"^.+\\.pem$": "<rootDir>/tests/unit/__stubs__/fileTransformer.js"
},
"testMatch": [
"<rootDir>/tests/**/*.test.ts"
],
"setupFilesAfterEnv": [
"jest-bluster"
]
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
Expand Down
17 changes: 2 additions & 15 deletions src/binders/Binder.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
// If support for Node.js < 10.0.0 is ever dropped, this import can be removed.
import { URL } from 'url';

import parseQueryInUrl from '../communication/parseQueryInUrl';
import List from '../data/list/List';
import buildFromEntries from '../plumbing/buildFromEntries';
import Maybe from '../types/Maybe';

/**
* Returns the parsed search parameters from the passed URL. For example: `'https://example.com?id=5'` is converted to
* `{ id: 5 }` (and `'https://example.com'` is converted to `{}`).
*
* If multiple parameters have the same key (`'https://example.com?id=5&id=6'`), exactly one of them will be
* represented in the returned object.
*/
function parseQueryInUrl(url: string) {
return buildFromEntries(new URL(url).searchParams);
}
/**
* A binder is the interface for a certain type of information. There is a binder for orders, and one for customers, et
* cetera.
Expand All @@ -23,7 +10,7 @@ export default class Binder<R, T extends R> {
/**
* Injects `nextPage`, `nextPageCursor`, `previousPage`, and `previousPageCursor` into the passed list.
*/
protected injectPaginationHelpers<P>(input: Array<T> & Pick<List<T>, 'count' | 'links'>, list: (parameters: P) => Promise<List<T>>, selfParameters: P): List<T> {
protected injectPaginationHelpers<P>(input: Array<T> & Pick<List<T>, 'count' | 'links'>, list: (parameters: P) => Promise<List<T>>, selfParameters: P = {} as P): List<T> {
const { links } = input;
let nextPage: Maybe<() => Promise<List<T>>>;
let nextPageCursor: Maybe<string>;
Expand Down
2 changes: 1 addition & 1 deletion src/binders/applePay/ApplePayBinder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import NetworkClient from '../../communication/NetworkClient';
import ApplePaySession from '../../data/applePaySession/ApplePaySession';
import NetworkClient from '../../NetworkClient';
import renege from '../../plumbing/renege';
import Callback from '../../types/Callback';
import { RequestPaymentSessionParameters } from './parameters';
Expand Down
15 changes: 14 additions & 1 deletion src/binders/chargebacks/ChargebacksBinder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import Chargeback, { ChargebackData, transform } from '../../data/chargebacks/Chargeback';
import List from '../../data/list/List';
import HelpfulIterator from '../../plumbing/HelpfulIterator';
import renege from '../../plumbing/renege';
import TransformingNetworkClient from '../../TransformingNetworkClient';
import Callback from '../../types/Callback';
import InnerBinder from '../InnerBinder';
import { ListParameters } from './parameters';
Expand Down Expand Up @@ -48,4 +49,16 @@ export default class ChargebacksBinder extends InnerBinder<ChargebackData, Charg
if (renege(this, this.page, ...arguments)) return;
return this.networkClient.list<ChargebackData, Chargeback>(pathSegment, 'chargebacks', parameters).then(result => this.injectPaginationHelpers(result, this.page, parameters));
}

/**
* Retrieve all received chargebacks. If the payment-specific endpoint is used, only chargebacks for that specific payment are returned.
*
* The results are paginated. See pagination for more information.
*
* @since 3.6.0
* @see https://docs.mollie.com/reference/v2/chargebacks-api/list-chargebacks
*/
public iterate(parameters?: Omit<ListParameters, 'limit'>): HelpfulIterator<Chargeback> {
return this.networkClient.iterate<ChargebackData, Chargeback>(pathSegment, 'chargebacks', { ...parameters, limit: 64 });
}
}
4 changes: 2 additions & 2 deletions src/binders/chargebacks/parameters.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChargebackEmbed } from '../../data/chargebacks/Chargeback';
import { CommonListParameters } from '../../types/parameters';
import { PaginationParameters } from '../../types/parameters';

export type ListParameters = CommonListParameters & {
export type ListParameters = PaginationParameters & {
embed?: ChargebackEmbed[];
};
16 changes: 14 additions & 2 deletions src/binders/customers/CustomersBinder.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import Customer, { CustomerData } from '../../data/customers/Customer';
import List from '../../data/list/List';
import ApiError from '../../errors/ApiError';
import checkId from '../../plumbing/checkId';
import renege from '../../plumbing/renege';
import TransformingNetworkClient from '../../TransformingNetworkClient';
import Callback from '../../types/Callback';
import Binder from '../Binder';
import { CreateParameters, DeleteParameters, GetParameters, ListParameters, UpdateParameters } from './parameters';
Expand Down Expand Up @@ -84,11 +84,23 @@ export default class CustomersBinder extends Binder<CustomerData, Customer> {
*/
public page(parameters?: ListParameters): Promise<List<Customer>>;
public page(parameters: ListParameters, callback: Callback<List<Customer>>): void;
public page(parameters: ListParameters = {}) {
public page(parameters?: ListParameters) {
if (renege(this, this.page, ...arguments)) return;
return this.networkClient.list<CustomerData, Customer>(pathSegment, 'customers', parameters).then(result => this.injectPaginationHelpers(result, this.page, parameters));
}

/**
* Retrieve all customers created.
*
* The results are paginated. See pagination for more information.
*
* @since 3.6.0
* @see https://docs.mollie.com/reference/v2/customers-api/list-customers
*/
public iterate(parameters?: Omit<ListParameters, 'limit'>) {
return this.networkClient.iterate<CustomerData, Customer>(pathSegment, 'customers', { ...parameters, limit: 64 });
}

/**
* Update an existing customer.
*
Expand Down
20 changes: 19 additions & 1 deletion src/binders/customers/mandates/CustomerMandatesBinder.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import TransformingNetworkClient from '../../../communication/TransformingNetworkClient';
import { MandateData } from '../../../data/customers/mandates/data';
import Mandate from '../../../data/customers/mandates/Mandate';
import List from '../../../data/list/List';
import ApiError from '../../../errors/ApiError';
import checkId from '../../../plumbing/checkId';
import renege from '../../../plumbing/renege';
import TransformingNetworkClient from '../../../TransformingNetworkClient';
import Callback from '../../../types/Callback';
import InnerBinder from '../../InnerBinder';
import { CreateParameters, GetParameters, ListParameters, RevokeParameters } from './parameters';
Expand Down Expand Up @@ -119,6 +119,24 @@ export default class CustomerMandatesBinder extends InnerBinder<MandateData, Man
return this.networkClient.list<MandateData, Mandate>(getPathSegments(customerId), 'mandates', query).then(result => this.injectPaginationHelpers(result, this.page, parameters ?? {}));
}

/**
* Retrieve all mandates for the given `customerId`, ordered from newest to oldest.
*
* The results are paginated. See pagination for more information.
*
* @since 3.6.0
* @see https://docs.mollie.com/reference/v2/mandates-api/list-mandates
*/
public iterate(parameters: Omit<ListParameters, 'limit'>) {
// parameters ?? {} is used here, because in case withParent is used, parameters could be omitted.
const customerId = this.getParentId((parameters ?? {}).customerId);
if (!checkId(customerId, 'customer')) {
throw new ApiError('The customer id is invalid');
}
const { customerId: _, ...query } = parameters ?? {};
return this.networkClient.iterate<MandateData, Mandate>(getPathSegments(customerId), 'mandates', { ...query, limit: 64 });
}

/**
* Revoke a customer's mandate. You will no longer be able to charge the consumer's bank account or credit card with this mandate and all connected subscriptions will be canceled.
*
Expand Down
4 changes: 2 additions & 2 deletions src/binders/customers/mandates/parameters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MandateData } from '../../../data/customers/mandates/data';
import { CommonListParameters } from '../../../types/parameters';
import { PaginationParameters } from '../../../types/parameters';

interface ContextParameters {
customerId: string;
Expand Down Expand Up @@ -55,6 +55,6 @@ export type CreateParameters = ContextParameters &

export type GetParameters = ContextParameters;

export type ListParameters = ContextParameters & CommonListParameters;
export type ListParameters = ContextParameters & PaginationParameters;

export type RevokeParameters = ContextParameters;
4 changes: 2 additions & 2 deletions src/binders/customers/parameters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CustomerData } from '../../data/customers/Customer';
import { CommonListParameters } from '../../types/parameters';
import { PaginationParameters } from '../../types/parameters';
import PickOptional from '../../types/PickOptional';

interface ContextParameters {
Expand All @@ -10,7 +10,7 @@ export type CreateParameters = ContextParameters & PickOptional<CustomerData, 'n

export type GetParameters = ContextParameters;

export type ListParameters = ContextParameters & CommonListParameters;
export type ListParameters = ContextParameters & PaginationParameters;

export type UpdateParameters = ContextParameters & PickOptional<CustomerData, 'name' | 'email' | 'locale' | 'metadata'>;

Expand Down
18 changes: 17 additions & 1 deletion src/binders/customers/payments/CustomerPaymentsBinder.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import TransformingNetworkClient from '../../../communication/TransformingNetworkClient';
import List from '../../../data/list/List';
import { PaymentData } from '../../../data/payments/data';
import Payment from '../../../data/payments/Payment';
import ApiError from '../../../errors/ApiError';
import checkId from '../../../plumbing/checkId';
import renege from '../../../plumbing/renege';
import TransformingNetworkClient from '../../../TransformingNetworkClient';
import Callback from '../../../types/Callback';
import InnerBinder from '../../InnerBinder';
import { CreateParameters, ListParameters } from './parameters';
Expand Down Expand Up @@ -78,4 +78,20 @@ export default class CustomerPaymentsBinder extends InnerBinder<PaymentData, Pay
const { customerId: _, ...query } = parameters ?? {};
return this.networkClient.list<PaymentData, Payment>(getPathSegments(customerId), 'payments', query).then(result => this.injectPaginationHelpers(result, this.page, parameters ?? {}));
}

/**
* Retrieve all Payments linked to the Customer.
*
* @since 3.6.0
* @see https://docs.mollie.com/reference/v2/customers-api/list-customer-payments
*/
public iterate(parameters: Omit<ListParameters, 'limit'>) {
// parameters ?? {} is used here, because in case withParent is used, parameters could be omitted.
const customerId = this.getParentId((parameters ?? {}).customerId);
if (!checkId(customerId, 'customer')) {
throw new ApiError('The customer id is invalid');
}
const { customerId: _, ...query } = parameters ?? {};
return this.networkClient.iterate<PaymentData, Payment>(getPathSegments(customerId), 'payments', { ...query, limit: 64 });
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import TransformingNetworkClient from '../../../communication/TransformingNetworkClient';
import List from '../../../data/list/List';
import { SubscriptionData } from '../../../data/subscription/data';
import Subscription from '../../../data/subscription/Subscription';
import ApiError from '../../../errors/ApiError';
import checkId from '../../../plumbing/checkId';
import renege from '../../../plumbing/renege';
import TransformingNetworkClient from '../../../TransformingNetworkClient';
import Callback from '../../../types/Callback';
import InnerBinder from '../../InnerBinder';
import { CancelParameters, CreateParameters, GetParameters, ListParameters, UpdateParameters } from './parameters';
Expand Down Expand Up @@ -114,6 +114,22 @@ export default class CustomerSubscriptionsBinder extends InnerBinder<Subscriptio
.then(result => this.injectPaginationHelpers(result, this.page, parameters ?? {}));
}

/**
* Retrieve all subscriptions of a customer.
*
* @since 3.6.0
* @see https://docs.mollie.com/reference/v2/subscriptions-api/list-subscriptions
*/
public iterate(parameters: ListParameters) {
// parameters ?? {} is used here, because in case withParent is used, parameters could be omitted.
const customerId = this.getParentId((parameters ?? {}).customerId);
if (!checkId(customerId, 'customer')) {
throw new ApiError('The customer id is invalid');
}
const { customerId: _, ...query } = parameters ?? {};
return this.networkClient.iterate<SubscriptionData, Subscription>(getPathSegments(customerId), 'subscriptions', { ...query, limit: 64 });
}

/**
* Some fields of a subscription can be updated by calling `PATCH` on the resource endpoint. Each field is optional.
*
Expand Down
4 changes: 2 additions & 2 deletions src/binders/customers/subscriptions/parameters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SubscriptionData } from '../../../data/subscription/data';
import { CommonListParameters } from '../../../types/parameters';
import { PaginationParameters } from '../../../types/parameters';
import PickOptional from '../../../types/PickOptional';

interface ContextParameters {
Expand All @@ -13,7 +13,7 @@ export type CreateParameters = ContextParameters &

export type GetParameters = ContextParameters;

export type ListParameters = ContextParameters & CommonListParameters;
export type ListParameters = ContextParameters & PaginationParameters;

export type UpdateParameters = ContextParameters &
Pick<SubscriptionData, 'mandateId'> &
Expand Down
2 changes: 1 addition & 1 deletion src/binders/methods/MethodsBinder.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import List from '../../data/list/List';
import { MethodData } from '../../data/methods/data';
import Method from '../../data/methods/Method';
import renege from '../../plumbing/renege';
import TransformingNetworkClient from '../../TransformingNetworkClient';
import Callback from '../../types/Callback';
import Binder from '../Binder';
import { GetParameters, ListParameters } from './parameters';
Expand Down
2 changes: 1 addition & 1 deletion src/binders/onboarding/OnboardingBinder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import { OnboardingData } from '../../data/onboarding/data';
import Onboarding from '../../data/onboarding/Onboarding';
import renege from '../../plumbing/renege';
import TransformingNetworkClient from '../../TransformingNetworkClient';
import Callback from '../../types/Callback';
import Binder from '../Binder';
import { SubmitParameters } from './parameters';
Expand Down
16 changes: 14 additions & 2 deletions src/binders/orders/OrdersBinder.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import TransformingNetworkClient from '../../communication/TransformingNetworkClient';
import List from '../../data/list/List';
import { OrderData } from '../../data/orders/data';
import Order from '../../data/orders/Order';
import ApiError from '../../errors/ApiError';
import checkId from '../../plumbing/checkId';
import renege from '../../plumbing/renege';
import TransformingNetworkClient from '../../TransformingNetworkClient';
import Callback from '../../types/Callback';
import Binder from '../Binder';
import { CancelParameters, CreateParameters, GetParameters, ListParameters, UpdateParameters } from './parameters';
Expand Down Expand Up @@ -124,11 +124,23 @@ export default class OrdersBinder extends Binder<OrderData, Order> {
*/
public page(parameters?: ListParameters): Promise<List<Order>>;
public page(parameters: ListParameters, callback: Callback<List<Order>>): void;
public page(parameters: ListParameters = {}) {
public page(parameters?: ListParameters) {
if (renege(this, this.page, ...arguments)) return;
return this.networkClient.list<OrderData, Order>(pathSegment, 'orders', parameters).then(result => this.injectPaginationHelpers(result, this.page, parameters));
}

/**
* Retrieve all orders.
*
* The results are paginated. See pagination for more information.
*
* @since 3.6.0
* @see https://docs.mollie.com/reference/v2/orders-api/list-orders
*/
public iterate(parameters?: Omit<ListParameters, 'limit'>) {
return this.networkClient.iterate<OrderData, Order>(pathSegment, 'orders', { ...parameters, limit: 64 });
}

/**
* This endpoint can be used to update the billing and/or shipping address of an order.
*
Expand Down
2 changes: 1 addition & 1 deletion src/binders/orders/orderlines/OrderLinesBinder.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import TransformingNetworkClient from '../../../communication/TransformingNetworkClient';
import { OrderData } from '../../../data/orders/data';
import Order from '../../../data/orders/Order';
import ApiError from '../../../errors/ApiError';
import checkId from '../../../plumbing/checkId';
import renege from '../../../plumbing/renege';
import TransformingNetworkClient from '../../../TransformingNetworkClient';
import Callback from '../../../types/Callback';
import InnerBinder from '../../InnerBinder';
import { CancelParameters, UpdateParameters } from './parameters';
Expand Down
Loading