@@ -16,64 +16,71 @@ export default async function createSubscription(
1616 opts : Options ,
1717 client : PoolClient | null // useful to allow null for unit testing, but must be explicit
1818) : Promise < number > {
19- const db = client ?? ( await getPoolClient ( ) ) ;
19+ let db : PoolClient | null = client ;
2020 // some consistency checks below. It's very likely this should always hold,
2121 // since data isn't user supplied, but it's still good to be careful.
2222
23- if ( ! ( await isValidAccount ( opts . account_id ) ) ) {
24- throw Error ( "account_id must be valid" ) ;
25- }
26- const costValue = toDecimal ( opts . cost ) ;
27- if ( costValue . eq ( 0 ) || costValue . lt ( 0 ) ) {
28- throw Error ( "cost must be positive" ) ;
29- }
30- if ( opts . interval != "month" && opts . interval != "year" ) {
31- throw Error ( "interval must be month or year" ) ;
32- }
33- if ( ! isDate ( opts . current_period_start ) ) {
34- throw Error ( "current_period_start must be a Date" ) ;
35- }
36- if ( ! isDate ( opts . current_period_end ) ) {
37- throw Error ( "current_period_end must be a Date" ) ;
38- }
39- if ( opts . current_period_start >= opts . current_period_end ) {
40- throw Error ( "start must be before end" ) ;
41- }
42- if (
43- opts . latest_purchase_id != null &&
44- ( ! is_integer ( opts . latest_purchase_id ) || opts . latest_purchase_id < 0 )
45- ) {
46- throw Error (
47- "if specified, latest_purchase_id must be a nonnegative integer"
48- ) ;
49- }
50- const metadata = opts . metadata as Metadata ;
51- const metadataType = ( opts . metadata as { type ?: string } ) ?. type ;
52- if ( typeof metadata != "object" || ! metadataType ) {
53- throw Error ( "metadata must be a nontrivial object with type field" ) ;
54- }
55- if ( metadataType != "membership" ) {
56- throw Error ( `unsupported subscription metadata type "${ metadataType } "` ) ;
57- }
58- if ( metadataType == "membership" && ! ( metadata as MembershipMetadata ) . class ) {
59- throw Error ( "membership metadata must include class" ) ;
60- }
23+ try {
24+ if ( ! ( await isValidAccount ( opts . account_id ) ) ) {
25+ throw Error ( "account_id must be valid" ) ;
26+ }
27+ const costValue = toDecimal ( opts . cost ) ;
28+ if ( costValue . eq ( 0 ) || costValue . lt ( 0 ) ) {
29+ throw Error ( "cost must be positive" ) ;
30+ }
31+ if ( opts . interval != "month" && opts . interval != "year" ) {
32+ throw Error ( "interval must be month or year" ) ;
33+ }
34+ if ( ! isDate ( opts . current_period_start ) ) {
35+ throw Error ( "current_period_start must be a Date" ) ;
36+ }
37+ if ( ! isDate ( opts . current_period_end ) ) {
38+ throw Error ( "current_period_end must be a Date" ) ;
39+ }
40+ if ( opts . current_period_start >= opts . current_period_end ) {
41+ throw Error ( "start must be before end" ) ;
42+ }
43+ if (
44+ opts . latest_purchase_id != null &&
45+ ( ! is_integer ( opts . latest_purchase_id ) || opts . latest_purchase_id < 0 )
46+ ) {
47+ throw Error (
48+ "if specified, latest_purchase_id must be a nonnegative integer"
49+ ) ;
50+ }
51+ const metadata = opts . metadata as Metadata ;
52+ const metadataType = ( opts . metadata as { type ?: string } ) ?. type ;
53+ if ( typeof metadata != "object" || ! metadataType ) {
54+ throw Error ( "metadata must be a nontrivial object with type field" ) ;
55+ }
56+ if ( metadataType != "membership" ) {
57+ throw Error ( `unsupported subscription metadata type "${ metadataType } "` ) ;
58+ }
59+ if (
60+ metadataType == "membership" &&
61+ ! ( metadata as MembershipMetadata ) . class
62+ ) {
63+ throw Error ( "membership metadata must include class" ) ;
64+ }
6165
62- const { rows } = await db . query (
63- "INSERT INTO subscriptions (account_id,created,cost,interval,current_period_start,current_period_end,latest_purchase_id,status,metadata) VALUES($1,NOW(),$2,$3,$4,$5,$6,'active',$7) RETURNING id" ,
64- [
65- opts . account_id ,
66- moneyToDbString ( costValue ) ,
67- opts . interval ,
68- opts . current_period_start ,
69- opts . current_period_end ,
70- opts . latest_purchase_id ,
71- opts . metadata ,
72- ]
73- ) ;
74- const { id } = rows [ 0 ] ;
75- if ( client == null ) {
76- db . release ( ) ;
66+ db = db ?? ( await getPoolClient ( ) ) ;
67+ const { rows } = await db . query (
68+ "INSERT INTO subscriptions (account_id,created,cost,interval,current_period_start,current_period_end,latest_purchase_id,status,metadata) VALUES($1,NOW(),$2,$3,$4,$5,$6,'active',$7) RETURNING id" ,
69+ [
70+ opts . account_id ,
71+ moneyToDbString ( costValue ) ,
72+ opts . interval ,
73+ opts . current_period_start ,
74+ opts . current_period_end ,
75+ opts . latest_purchase_id ,
76+ opts . metadata ,
77+ ]
78+ ) ;
79+ const { id } = rows [ 0 ] ;
80+ return id ;
81+ } finally {
82+ if ( client == null && db != null ) {
83+ db . release ( ) ;
84+ }
7785 }
78- return id ;
7986}
0 commit comments