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

Experimental nested expanded fields idea #35

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lib/messages.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stripe/src/messages/converters.dart';
import 'package:stripe/src/messages/enums.dart';
import 'package:stripe/src/messages/enums/pause_collection_behavior.dart';

export 'package:stripe/src/messages/enums.dart';

Expand All @@ -19,8 +18,8 @@ part 'src/messages/data_list.dart';
part 'src/messages/discount.dart';
part 'src/messages/event.dart';
part 'src/messages/invoice.dart';
part 'src/messages/payment_intent.dart';
part 'src/messages/pause_collection.dart';
part 'src/messages/payment_intent.dart';
part 'src/messages/payment_method.dart';
part 'src/messages/portal_session.dart';
part 'src/messages/price.dart';
Expand Down
9 changes: 9 additions & 0 deletions lib/src/expanded/customer_expanded.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:stripe/messages.dart';

class CustomerExpanded {
final Customer customer;

CustomerExpanded({
required this.customer,
});
}
9 changes: 9 additions & 0 deletions lib/src/expanded/discount_expanded.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:stripe/messages.dart';

class DiscountExpanded {
final Discount discount;

DiscountExpanded({
required this.discount,
});
}
26 changes: 2 additions & 24 deletions lib/src/expanded/invoice_expanded.dart
Original file line number Diff line number Diff line change
@@ -1,36 +1,14 @@
import 'package:stripe/messages.dart';
import 'package:stripe/src/utils/expandable_fields/discounts_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/payment_intent_expandable_field.dart';
import 'package:stripe/src/expanded/discount_expanded.dart';

class InvoiceExpanded {
final Invoice invoice;
final PaymentIntent? paymentIntent;
final List<Discount>? discounts;
final List<DiscountExpanded>? discounts;

InvoiceExpanded({
required this.invoice,
this.paymentIntent,
this.discounts,
});

factory InvoiceExpanded.fromJson(
Map<String, dynamic> json,
Set<InvoiceExpandableField> expand,
) {
PaymentIntent? paymentIntent;
if (expand.contains(InvoiceExpandableField.paymentIntent)) {
paymentIntent = PaymentIntentExpandableField().extract(json);
}

List<Discount>? discounts;
if (expand.contains(InvoiceExpandableField.discounts)) {
discounts = DiscountsExpandableField().extract(json);
}

return InvoiceExpanded(
invoice: Invoice.fromJson(json),
paymentIntent: paymentIntent,
discounts: discounts,
);
}
}
38 changes: 4 additions & 34 deletions lib/src/expanded/subscription_expanded.dart
Original file line number Diff line number Diff line change
@@ -1,48 +1,18 @@
import 'package:stripe/messages.dart';
import 'package:stripe/src/expanded.dart';
import 'package:stripe/src/utils/expandable_fields/customer_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/discounts_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/latest_invoice_expanded_expandable_field.dart';
import 'package:stripe/src/expanded/customer_expanded.dart';
import 'package:stripe/src/expanded/discount_expanded.dart';

class SubscriptionExpanded {
final Subscription subscription;
final List<Discount>? discounts;
final List<DiscountExpanded>? discounts;
final InvoiceExpanded? latestInvoice;
final Customer? customer;
final CustomerExpanded? customer;
Comment on lines 6 to +10
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably the pattern we need to stick with. In most cases the included fields will have nesting of their own, and in order to minimize breaking changes as we add more "expanded" fields -- we'll need to make all nested fields xExpanded:

class ObjExpanded {
  final Obj obj;
  final NestedAExpanded nestedA;
  final NestedB...
}


SubscriptionExpanded({
required this.subscription,
this.discounts,
this.latestInvoice,
this.customer,
});

factory SubscriptionExpanded.fromJson(
Map<String, dynamic> json,
Set<SubscriptionExpandableField> expand,
) {
List<Discount>? discounts;
if (expand.contains(SubscriptionExpandableField.discounts)) {
discounts = const DiscountsExpandableField().extract(json);
}

InvoiceExpanded? latestInvoice;
if (expand.contains(SubscriptionExpandableField.latestInvoice)) {
latestInvoice = const LatestInvoiceExpandedExpandableField(
expand: {InvoiceExpandableField.paymentIntent},
).extract(json);
}

Customer? customer;
if (expand.contains(SubscriptionExpandableField.customer)) {
customer = const CustomerExpandableField().extract(json);
}

return SubscriptionExpanded(
subscription: Subscription.fromJson(json),
discounts: discounts,
latestInvoice: latestInvoice,
customer: customer,
);
}
}
2 changes: 0 additions & 2 deletions lib/src/messages/enums.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export 'enums/expandable_fields/invoice_expandable_field.dart';
export 'enums/expandable_fields/subscription_expandable_field.dart';
export 'enums/payment_behavior.dart';
export 'enums/proration_behavior.dart';
export 'enums/stripe_api_error_type.dart';
Expand Down

This file was deleted.

This file was deleted.

30 changes: 4 additions & 26 deletions lib/src/resources/invoice.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import 'dart:async';

import 'package:stripe/messages.dart';
import 'package:stripe/src/expanded.dart';
import 'package:stripe/src/utils/expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/discounts_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/payment_intent_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/invoice_expandable_field.dart';

import '../client.dart';
import '_resource.dart';
Expand All @@ -23,36 +21,16 @@ class InvoiceResource extends Resource<Invoice> {

Future<InvoiceExpanded> createPreviewExpanded(
CreatePreviewInvoiceRequest request, {
required Set<InvoiceExpandableField> expand,
required InvoiceExpandableField expand,
}) async {
final expandableFields = _expandableFields(expand);
final response = await post(
'$_resourceName/create_preview',
data: {
...request.toJson(),
'expand': expandableFields.map((e) => e.field).toList(),
'expand': expand.innerNestedFields.toList(),
},
);

return InvoiceExpanded.fromJson(response, expand);
}

Iterable<ExpandableField> _expandableFields(
Set<InvoiceExpandableField> fields,
) {
return fields.map(
(field) => _expandableField(field),
);
}

ExpandableField _expandableField(
InvoiceExpandableField field,
) {
switch (field) {
case InvoiceExpandableField.paymentIntent:
return PaymentIntentExpandableField();
case InvoiceExpandableField.discounts:
return DiscountsExpandableField();
}
return expand.parse(response);
}
}
55 changes: 13 additions & 42 deletions lib/src/resources/subscription.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import 'dart:async';

import 'package:stripe/messages.dart';
import 'package:stripe/src/expanded.dart';
import 'package:stripe/src/utils/expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/customer_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/discounts_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/latest_invoice_expanded_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/latest_invoice_expandable_field.dart';
import 'package:stripe/src/utils/expandable_fields/subscription_expandable_field.dart';

import '../client.dart';
import '_resource.dart';
Expand All @@ -19,10 +18,10 @@ class SubscriptionResource extends Resource<Subscription> {
Future<SubscriptionExpanded> create(CreateSubscriptionRequest request) async {
final response = await post(_resourceName, data: request.toJson());

return SubscriptionExpanded.fromJson(response, {
SubscriptionExpandableField.discounts,
SubscriptionExpandableField.latestInvoice,
});
return SubscriptionExpandableField(
discountsExpansion: DiscountsExpandableField(),
latestInvoiceExpansion: LatestInvoiceExpandableField(),
).extract(response)!;
}

Future<Subscription> retrieve(String id) async {
Expand All @@ -32,40 +31,17 @@ class SubscriptionResource extends Resource<Subscription> {

Future<SubscriptionExpanded> retrieveExpanded(
String id, {
required Set<SubscriptionExpandableField> expand,
required SubscriptionExpandableField expand,
}) async {
final expandableFields = _expandableFields(expand);
final response = await get(
'$_resourceName/$id',
queryParameters: {
'expand': expandableFields.map((e) => e.field).toList(),
for (int i = 0; i < expand.innerNestedFields.length; i++)
'expand[$i]': expand.innerNestedFields.elementAt(i),
Comment on lines +39 to +40
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to be extracted into a reusable piece. Maybe a utility on ExpandableField.

},
);

return SubscriptionExpanded.fromJson(response, expand);
}

Iterable<ExpandableField> _expandableFields(
Set<SubscriptionExpandableField> fields,
) {
return fields.map(
(field) => _expandableField(field),
);
}

ExpandableField _expandableField(
SubscriptionExpandableField field,
) {
switch (field) {
case SubscriptionExpandableField.discounts:
return DiscountsExpandableField();
case SubscriptionExpandableField.latestInvoice:
return LatestInvoiceExpandedExpandableField(
expand: {InvoiceExpandableField.paymentIntent},
);
case SubscriptionExpandableField.customer:
return CustomerExpandableField();
}
return expand.parse(response);
}

Future<DataList<Subscription>> list(
Expand All @@ -76,25 +52,20 @@ class SubscriptionResource extends Resource<Subscription> {
}

Future<DataList<SubscriptionExpanded>> listExpanded({
required Set<SubscriptionExpandableField> expand,
required SubscriptionExpandableField expand,
ListSubscriptionsRequest? request,
}) async {
final expandableFields = _expandableFields(expand);

final response = await get(
_resourceName,
queryParameters: {
...?request?.toJson(),
'expand': expandableFields.map((e) => 'data.${e.field}').toList(),
'expand': expand.nestedFields.toList(),
},
);

return DataList<SubscriptionExpanded>.fromJson(
response,
(value) => SubscriptionExpanded.fromJson(
value as Map<String, dynamic>,
expand,
),
(value) => expand.extract(value as Map<String, Object?>)!,
);
}

Expand Down
8 changes: 8 additions & 0 deletions lib/src/utils/expandable_field.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
abstract class ExpandableField<T> {
String get field;

Iterable<String> get innerNestedFields => [];

Iterable<String> get nestedFields {
if (innerNestedFields.isEmpty) return [field];

return innerNestedFields.map((nestedField) => '$field.$nestedField');
}

const ExpandableField();

T extract(Map<String, dynamic> json);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import 'package:stripe/messages.dart';
import 'package:stripe/src/expanded/customer_expanded.dart';
import 'package:stripe/src/utils/expandable_object_field.dart';

class CustomerExpandableField extends ExpandableObjectField<Customer> {
class CustomerExpandableField extends ExpandableObjectField<CustomerExpanded> {
@override
String get field => 'customer';

const CustomerExpandableField();

@override
Customer parse(Map<String, dynamic> object) => Customer.fromJson(object);
CustomerExpanded parse(Map<String, dynamic> object) =>
CustomerExpanded(customer: Customer.fromJson(object));

@override
String replacement(Customer parsedValue) => parsedValue.id;
String replacement(CustomerExpanded parsedValue) => parsedValue.customer.id;
}
11 changes: 7 additions & 4 deletions lib/src/utils/expandable_fields/discounts_expandable_field.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import 'package:stripe/messages.dart';
import 'package:stripe/src/expanded/discount_expanded.dart';
import 'package:stripe/src/utils/expandable_list_field.dart';

class DiscountsExpandableField extends ExpandableListField<Discount> {
class DiscountsExpandableField extends ExpandableListField<DiscountExpanded> {
@override
String get field => 'discounts';

const DiscountsExpandableField();

@override
String elementReplacement(Discount element) => element.id;
String elementReplacement(DiscountExpanded element) => element.discount.id;

@override
Discount parseElement(Map<String, dynamic> element) =>
Discount.fromJson(element);
DiscountExpanded parseElement(Map<String, dynamic> element) =>
DiscountExpanded(
discount: Discount.fromJson(element),
);
}
Loading