Skip to content

Commit

Permalink
Better string enums (#1675)
Browse files Browse the repository at this point in the history
  • Loading branch information
ob-stripe committed Jul 18, 2019
1 parent 39d8e2f commit 456d8fd
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 32 deletions.
2 changes: 1 addition & 1 deletion src/Stripe.net/Services/Customers/CustomerCreateOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public class CustomerCreateOptions : BaseOptions
public decimal? TaxPercent { get; set; }

[JsonProperty("trial_end")]
public AnyOf<DateTime?, SubscriptionTrialEnd?> TrialEnd { get; set; }
public AnyOf<DateTime?, SubscriptionTrialEnd> TrialEnd { get; set; }

[JsonProperty("validate")]
public bool? Validate { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class UpcomingInvoiceListLineItemsOptions : ListOptions
/// <see cref="Stripe.SubscriptionBillingCycleAnchor"/>.
/// </summary>
[JsonProperty("subscription_billing_cycle_anchor")]
public AnyOf<DateTime?, SubscriptionBillingCycleAnchor?> SubscriptionBillingCycleAnchor { get; set; }
public AnyOf<DateTime?, SubscriptionBillingCycleAnchor> SubscriptionBillingCycleAnchor { get; set; }

/// <summary>
/// Boolean indicating whether this subscription should cancel at the end of the current
Expand Down
2 changes: 1 addition & 1 deletion src/Stripe.net/Services/Invoices/UpcomingInvoiceOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class UpcomingInvoiceOptions : BaseOptions
/// <see cref="Stripe.SubscriptionBillingCycleAnchor"/>.
/// </summary>
[JsonProperty("subscription_billing_cycle_anchor")]
public AnyOf<DateTime?, SubscriptionBillingCycleAnchor?> SubscriptionBillingCycleAnchor { get; set; }
public AnyOf<DateTime?, SubscriptionBillingCycleAnchor> SubscriptionBillingCycleAnchor { get; set; }

/// <summary>
/// Boolean indicating whether this subscription should cancel at the end of the current
Expand Down
2 changes: 1 addition & 1 deletion src/Stripe.net/Services/Plans/PlanTierOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public class PlanTierOptions : INestedOptions
/// tier.
/// </summary>
[JsonProperty("up_to")]
public AnyOf<long?, PlanTierUpTo?> UpTo { get; set; }
public AnyOf<long?, PlanTierUpTo> UpTo { get; set; }
}
}
15 changes: 7 additions & 8 deletions src/Stripe.net/Services/Plans/PlanTierUpTo.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
namespace Stripe
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

[JsonConverter(typeof(StringEnumConverter))]
public enum PlanTierUpTo
public class PlanTierUpTo : StringEnum
{
/// <summary>Use this value to define a fallback tier.</summary>
[EnumMember(Value = "inf")]
Inf,
public static readonly PlanTierUpTo Inf = new PlanTierUpTo("inf");

private PlanTierUpTo(string value)
: base(value)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
namespace Stripe
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

[JsonConverter(typeof(StringEnumConverter))]
public enum SubscriptionBillingCycleAnchor
public class SubscriptionBillingCycleAnchor : StringEnum
{
/// <summary>Resets the subscription's billing cycle anchor to the current time.</summary>
[EnumMember(Value = "now")]
Now,
public static readonly SubscriptionBillingCycleAnchor Now
= new SubscriptionBillingCycleAnchor("now");

/// <summary>Leaves the subscription's billing cycle anchor unchanged.</summary>
[EnumMember(Value = "unchanged")]
Unchanged,
public static readonly SubscriptionBillingCycleAnchor Unchanged
= new SubscriptionBillingCycleAnchor("unchanged");

private SubscriptionBillingCycleAnchor(string value)
: base(value)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public abstract class SubscriptionSharedOptions : BaseOptions
/// immediately.
/// </summary>
[JsonProperty("trial_end")]
public AnyOf<DateTime?, SubscriptionTrialEnd?> TrialEnd { get; set; }
public AnyOf<DateTime?, SubscriptionTrialEnd> TrialEnd { get; set; }

/// <summary>
/// Boolean. Decide whether to use the default trial on the plan when creating a subscription.
Expand Down
15 changes: 7 additions & 8 deletions src/Stripe.net/Services/Subscriptions/SubscriptionTrialEnd.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
namespace Stripe
{
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

[JsonConverter(typeof(StringEnumConverter))]
public enum SubscriptionTrialEnd
public class SubscriptionTrialEnd : StringEnum
{
/// <summary>Special value used to end a customer's trial immediately.</summary>
[EnumMember(Value = "now")]
Now,
public static readonly SubscriptionTrialEnd Now = new SubscriptionTrialEnd("now");

private SubscriptionTrialEnd(string value)
: base(value)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class SubscriptionUpdateOptions : SubscriptionSharedOptions
/// <a href="https://stripe.com/docs/billing/subscriptions/billing-cycle">documentation</a>.
/// </summary>
[JsonProperty("billing_cycle_anchor")]
public SubscriptionBillingCycleAnchor? BillingCycleAnchor { get; set; }
public SubscriptionBillingCycleAnchor BillingCycleAnchor { get; set; }

/// <summary>
/// List of subscription items, each with an attached plan.
Expand Down
46 changes: 46 additions & 0 deletions src/Stripe.net/Services/_base/StringEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
namespace Stripe
{
/// <summary>
/// Abstract base class for string enum parameters.
/// </summary>
/// <remarks>
/// This class is used to define request parameters that can only take certain string values.
/// We use it instead of defining a regular <c>enum</c> with
/// <see cref="System.Runtime.Serialization.EnumMemberAttribute"/> annotations for
/// serialization because <c>enum</c> is really an integer under the hood. This can be
/// problematic in some cases, like when a parameter can be an integer OR a string enum (e.g.
/// <see cref="PlanTierOptions.UpTo"/>).
/// </remarks>
/// <example>
/// This sample shows how to define a new string enum type.
/// <code>
/// public class FooBar : StringEnum
/// {
/// public static readonly FooBar Foo = new FooBar("foo");
/// public static readonly FooBar Bar = new FooBar("bar");
///
/// private FooBar(string value) : base(value) {}
/// }
/// </code>
/// </example>
public abstract class StringEnum
{
/// <summary>Initializes a new instance of the <see cref="StringEnum"/> class.</summary>
/// <param name="value">The serialized value for the instance.</param>
protected StringEnum(string value)
{
this.Value = value;
}

/// <summary>Gets or sets the serialized value.</summary>
/// <returns>The serialized value.</returns>
public string Value { get; protected set; }

/// <summary>Returns the serialized value.</summary>
/// <returns>The serialized value.</returns>
public override string ToString()
{
return this.Value;
}
}
}
18 changes: 18 additions & 0 deletions src/StripeTests/Infrastructure/FormEncoding/FormEncoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,24 @@ public void CreateQueryString()
},
want = "string="
},

// StringEnum
new
{
data = new TestOptions
{
StringEnum = TestOptions.TestStringEnum.Foo,
},
want = "string_enum=foo"
},
new
{
data = new TestOptions
{
StringEnum = null,
},
want = string.Empty,
},
};

foreach (var testCase in testCases)
Expand Down
13 changes: 13 additions & 0 deletions src/StripeTests/Infrastructure/TestData/TestOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,18 @@ public enum TestEnum

[JsonProperty("string")]
public string String { get; set; }

[JsonProperty("string_enum")]
public TestStringEnum StringEnum { get; set; }

public class TestStringEnum : StringEnum
{
public static readonly TestStringEnum Foo = new TestStringEnum("foo");

private TestStringEnum(string value)
: base(value)
{
}
}
}
}

0 comments on commit 456d8fd

Please sign in to comment.