@coursebuilder/adapter-drizzle 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/dist/{chunk-XXZQBN6S.js → chunk-2CI3IGR2.js} +4 -4
  2. package/dist/{chunk-3LWFRGZT.js → chunk-3RJVKNXB.js} +458 -381
  3. package/dist/{chunk-NXFHRDLS.js → chunk-53266VWH.js} +3 -3
  4. package/dist/{chunk-OIUOQ3TT.js → chunk-57CX5SOI.js} +2 -2
  5. package/dist/{chunk-75V6F7LZ.js → chunk-5HT43CVZ.js} +2 -2
  6. package/dist/{chunk-SFJM6FKE.js → chunk-BX5SO2JG.js} +2 -2
  7. package/dist/{chunk-LSOPFMDB.js → chunk-FNYW3XKR.js} +3 -3
  8. package/dist/{chunk-V6QEDDFG.js → chunk-GLPDG7UE.js} +2 -2
  9. package/dist/{chunk-VNI36MMC.js → chunk-H736K5TN.js} +1 -1
  10. package/dist/{chunk-6CBAFOL3.js → chunk-J4LBG2TH.js} +2 -2
  11. package/dist/{chunk-JD4KFACE.js → chunk-JKOYOL7A.js} +2 -2
  12. package/dist/{chunk-TMQIGK3N.js → chunk-MBB4GIJI.js} +2 -2
  13. package/dist/{chunk-27KREOQW.js → chunk-PJHGIRZM.js} +2 -2
  14. package/dist/{chunk-L2TQQYG4.js → chunk-PPBEA4EM.js} +2 -2
  15. package/dist/{chunk-ULABK6XG.js → chunk-Q5WENQT6.js} +3 -3
  16. package/dist/{chunk-H4MXNDWO.js → chunk-V23SCQL7.js} +2 -2
  17. package/dist/{chunk-NZDLUQWP.js → chunk-VDVCCU7D.js} +2 -2
  18. package/dist/{chunk-IN6G6MTW.js → chunk-VXZRMVNY.js} +2 -2
  19. package/dist/{chunk-XSXWLOIN.js → chunk-WQ7UXKZC.js} +920 -482
  20. package/dist/{chunk-JKRFXYAR.js → chunk-Y7QZGEPT.js} +2 -2
  21. package/dist/index.js +20 -21
  22. package/dist/lib/mysql/index.cjs +926 -465
  23. package/dist/lib/mysql/index.cjs.map +1 -1
  24. package/dist/lib/mysql/index.d.cts +6143 -0
  25. package/dist/lib/mysql/index.d.ts +41 -9
  26. package/dist/lib/mysql/index.js +20 -21
  27. package/dist/lib/mysql/schemas/auth/accounts.cjs.map +1 -1
  28. package/dist/lib/mysql/schemas/auth/accounts.d.cts +184 -0
  29. package/dist/lib/mysql/schemas/auth/accounts.js +10 -11
  30. package/dist/lib/mysql/schemas/auth/permissions.d.cts +98 -0
  31. package/dist/lib/mysql/schemas/auth/permissions.js +2 -2
  32. package/dist/lib/mysql/schemas/auth/role-permissions.cjs.map +1 -1
  33. package/dist/lib/mysql/schemas/auth/role-permissions.d.cts +89 -0
  34. package/dist/lib/mysql/schemas/auth/role-permissions.js +11 -12
  35. package/dist/lib/mysql/schemas/auth/roles.cjs.map +1 -1
  36. package/dist/lib/mysql/schemas/auth/roles.d.cts +100 -0
  37. package/dist/lib/mysql/schemas/auth/roles.js +10 -11
  38. package/dist/lib/mysql/schemas/auth/sessions.cjs.map +1 -1
  39. package/dist/lib/mysql/schemas/auth/sessions.d.cts +52 -0
  40. package/dist/lib/mysql/schemas/auth/sessions.js +11 -12
  41. package/dist/lib/mysql/schemas/auth/user-permissions.cjs.map +1 -1
  42. package/dist/lib/mysql/schemas/auth/user-permissions.d.cts +89 -0
  43. package/dist/lib/mysql/schemas/auth/user-permissions.js +10 -11
  44. package/dist/lib/mysql/schemas/auth/user-roles.cjs.map +1 -1
  45. package/dist/lib/mysql/schemas/auth/user-roles.d.cts +89 -0
  46. package/dist/lib/mysql/schemas/auth/user-roles.js +10 -11
  47. package/dist/lib/mysql/schemas/auth/users.cjs +1 -1
  48. package/dist/lib/mysql/schemas/auth/users.cjs.map +1 -1
  49. package/dist/lib/mysql/schemas/auth/users.d.cts +106 -0
  50. package/dist/lib/mysql/schemas/auth/users.js +10 -11
  51. package/dist/lib/mysql/schemas/auth/verification-tokens.d.cts +60 -0
  52. package/dist/lib/mysql/schemas/auth/verification-tokens.js +2 -2
  53. package/dist/lib/mysql/schemas/commerce/coupon.cjs +180 -17
  54. package/dist/lib/mysql/schemas/commerce/coupon.cjs.map +1 -1
  55. package/dist/lib/mysql/schemas/commerce/coupon.d.cts +172 -0
  56. package/dist/lib/mysql/schemas/commerce/coupon.d.ts +6 -2
  57. package/dist/lib/mysql/schemas/commerce/coupon.js +12 -2
  58. package/dist/lib/mysql/schemas/commerce/merchant-account.d.cts +72 -0
  59. package/dist/lib/mysql/schemas/commerce/merchant-account.js +2 -2
  60. package/dist/lib/mysql/schemas/commerce/merchant-charge.d.cts +108 -0
  61. package/dist/lib/mysql/schemas/commerce/merchant-charge.js +2 -2
  62. package/dist/lib/mysql/schemas/commerce/merchant-coupon.d.cts +84 -0
  63. package/dist/lib/mysql/schemas/commerce/merchant-coupon.js +2 -2
  64. package/dist/lib/mysql/schemas/commerce/merchant-customer.d.cts +84 -0
  65. package/dist/lib/mysql/schemas/commerce/merchant-customer.js +2 -2
  66. package/dist/lib/mysql/schemas/commerce/merchant-price.d.cts +96 -0
  67. package/dist/lib/mysql/schemas/commerce/merchant-price.js +2 -2
  68. package/dist/lib/mysql/schemas/commerce/merchant-product.d.cts +84 -0
  69. package/dist/lib/mysql/schemas/commerce/merchant-product.js +2 -2
  70. package/dist/lib/mysql/schemas/commerce/merchant-session.d.cts +48 -0
  71. package/dist/lib/mysql/schemas/commerce/merchant-session.js +2 -2
  72. package/dist/lib/mysql/schemas/commerce/price.cjs +4 -1
  73. package/dist/lib/mysql/schemas/commerce/price.cjs.map +1 -1
  74. package/dist/lib/mysql/schemas/commerce/price.d.cts +101 -0
  75. package/dist/lib/mysql/schemas/commerce/price.d.ts +1 -1
  76. package/dist/lib/mysql/schemas/commerce/price.js +10 -11
  77. package/dist/lib/mysql/schemas/commerce/product.cjs +4 -1
  78. package/dist/lib/mysql/schemas/commerce/product.cjs.map +1 -1
  79. package/dist/lib/mysql/schemas/commerce/product.d.cts +114 -0
  80. package/dist/lib/mysql/schemas/commerce/product.d.ts +12 -0
  81. package/dist/lib/mysql/schemas/commerce/product.js +10 -11
  82. package/dist/lib/mysql/schemas/commerce/purchase-user-transfer.d.cts +132 -0
  83. package/dist/lib/mysql/schemas/commerce/purchase-user-transfer.js +2 -2
  84. package/dist/lib/mysql/schemas/commerce/purchase.cjs +14 -2
  85. package/dist/lib/mysql/schemas/commerce/purchase.cjs.map +1 -1
  86. package/dist/lib/mysql/schemas/commerce/purchase.d.cts +225 -0
  87. package/dist/lib/mysql/schemas/commerce/purchase.d.ts +2 -1
  88. package/dist/lib/mysql/schemas/commerce/purchase.js +10 -11
  89. package/dist/lib/mysql/schemas/commerce/upgradable-products.cjs +3 -0
  90. package/dist/lib/mysql/schemas/commerce/upgradable-products.cjs.map +1 -1
  91. package/dist/lib/mysql/schemas/commerce/upgradable-products.d.cts +101 -0
  92. package/dist/lib/mysql/schemas/commerce/upgradable-products.js +11 -12
  93. package/dist/lib/mysql/schemas/communication/communication-channel.d.cts +96 -0
  94. package/dist/lib/mysql/schemas/communication/communication-channel.js +2 -2
  95. package/dist/lib/mysql/schemas/communication/communication-preference-types.d.cts +96 -0
  96. package/dist/lib/mysql/schemas/communication/communication-preference-types.js +2 -2
  97. package/dist/lib/mysql/schemas/communication/communication-preferences.cjs.map +1 -1
  98. package/dist/lib/mysql/schemas/communication/communication-preferences.d.cts +150 -0
  99. package/dist/lib/mysql/schemas/communication/communication-preferences.js +10 -11
  100. package/dist/lib/mysql/schemas/content/content-contributions.cjs.map +1 -1
  101. package/dist/lib/mysql/schemas/content/content-contributions.d.cts +114 -0
  102. package/dist/lib/mysql/schemas/content/content-contributions.js +10 -11
  103. package/dist/lib/mysql/schemas/content/content-resource-product.cjs +3 -0
  104. package/dist/lib/mysql/schemas/content/content-resource-product.cjs.map +1 -1
  105. package/dist/lib/mysql/schemas/content/content-resource-product.d.cts +101 -0
  106. package/dist/lib/mysql/schemas/content/content-resource-product.js +10 -11
  107. package/dist/lib/mysql/schemas/content/content-resource-resource.cjs.map +1 -1
  108. package/dist/lib/mysql/schemas/content/content-resource-resource.d.cts +101 -0
  109. package/dist/lib/mysql/schemas/content/content-resource-resource.js +10 -11
  110. package/dist/lib/mysql/schemas/content/content-resource.cjs.map +1 -1
  111. package/dist/lib/mysql/schemas/content/content-resource.d.cts +103 -0
  112. package/dist/lib/mysql/schemas/content/content-resource.js +10 -11
  113. package/dist/lib/mysql/schemas/content/contribution-types.d.cts +110 -0
  114. package/dist/lib/mysql/schemas/content/contribution-types.js +2 -2
  115. package/dist/lib/mysql/schemas/content/resource-progress.cjs +1 -1
  116. package/dist/lib/mysql/schemas/content/resource-progress.cjs.map +1 -1
  117. package/dist/lib/mysql/schemas/content/resource-progress.d.cts +84 -0
  118. package/dist/lib/mysql/schemas/content/resource-progress.d.ts +1 -1
  119. package/dist/lib/mysql/schemas/content/resource-progress.js +2 -2
  120. package/dist/lib/mysql/utils.cjs.map +1 -1
  121. package/dist/lib/mysql/utils.d.cts +12 -0
  122. package/dist/lib/mysql/utils.js +1 -1
  123. package/dist/lib/mysql/utils.js.map +1 -1
  124. package/dist/lib/utils.d.cts +22 -0
  125. package/dist/lib/utils.d.ts +1 -1
  126. package/dist/lib/utils.js +1 -1
  127. package/package.json +5 -5
  128. package/src/lib/mysql/index.ts +464 -113
  129. package/src/lib/mysql/schemas/commerce/coupon.ts +18 -2
  130. package/src/lib/mysql/schemas/commerce/price.ts +1 -1
  131. package/src/lib/mysql/schemas/commerce/product.ts +1 -0
  132. package/src/lib/mysql/schemas/commerce/purchase.ts +6 -1
  133. package/src/lib/mysql/schemas/content/resource-progress.ts +1 -1
  134. package/dist/chunk-QK6CINAJ.js +0 -60
@@ -1,6 +1,16 @@
1
1
  import type { AdapterSession, AdapterUser } from '@auth/core/adapters'
2
2
  import { addSeconds, isAfter } from 'date-fns'
3
- import { and, asc, eq, inArray, not, notInArray, or, sql } from 'drizzle-orm'
3
+ import {
4
+ and,
5
+ asc,
6
+ eq,
7
+ inArray,
8
+ isNotNull,
9
+ isNull,
10
+ not,
11
+ or,
12
+ sql,
13
+ } from 'drizzle-orm'
4
14
  import {
5
15
  mysqlTable as defaultMySqlTableFn,
6
16
  MySqlDatabase,
@@ -18,6 +28,7 @@ import {
18
28
  MerchantCoupon,
19
29
  merchantCouponSchema,
20
30
  MerchantCustomer,
31
+ merchantPriceSchema,
21
32
  MerchantProduct,
22
33
  merchantProductSchema,
23
34
  Price,
@@ -29,6 +40,7 @@ import {
29
40
  PurchaseUserTransfer,
30
41
  PurchaseUserTransferState,
31
42
  ResourceProgress,
43
+ resourceProgressSchema,
32
44
  UpgradableProduct,
33
45
  upgradableProductSchema,
34
46
  User,
@@ -38,7 +50,10 @@ import {
38
50
  ContentResourceResourceSchema,
39
51
  ContentResourceSchema,
40
52
  } from '@coursebuilder/core/schemas/content-resource-schema'
53
+ import { merchantAccountSchema } from '@coursebuilder/core/schemas/merchant-account-schema'
54
+ import { merchantCustomerSchema } from '@coursebuilder/core/schemas/merchant-customer-schema'
41
55
  import { VideoResourceSchema } from '@coursebuilder/core/schemas/video-resource'
56
+ import { validateCoupon } from '@coursebuilder/core/utils/validate-coupon'
42
57
 
43
58
  import {
44
59
  getAccountsRelationsSchema,
@@ -73,7 +88,10 @@ import {
73
88
  getUsersSchema,
74
89
  } from './schemas/auth/users.js'
75
90
  import { getVerificationTokensSchema } from './schemas/auth/verification-tokens.js'
76
- import { getCouponSchema } from './schemas/commerce/coupon.js'
91
+ import {
92
+ getCouponRelationsSchema,
93
+ getCouponSchema,
94
+ } from './schemas/commerce/coupon.js'
77
95
  import { getMerchantAccountSchema } from './schemas/commerce/merchant-account.js'
78
96
  import { getMerchantChargeSchema } from './schemas/commerce/merchant-charge.js'
79
97
  import { getMerchantCouponSchema } from './schemas/commerce/merchant-coupon.js'
@@ -143,6 +161,7 @@ export function getCourseBuilderSchema(mysqlTable: MySqlTableFn) {
143
161
  usersRelations: getUsersRelationsSchema(mysqlTable),
144
162
  verificationTokens: getVerificationTokensSchema(mysqlTable),
145
163
  coupon: getCouponSchema(mysqlTable),
164
+ couponRelations: getCouponRelationsSchema(mysqlTable),
146
165
  merchantAccount: getMerchantAccountSchema(mysqlTable),
147
166
  merchantCharge: getMerchantChargeSchema(mysqlTable),
148
167
  merchantCoupon: getMerchantCouponSchema(mysqlTable),
@@ -212,10 +231,186 @@ export function mySqlDrizzleAdapter(
212
231
  prices,
213
232
  products,
214
233
  upgradableProducts,
234
+ resourceProgress,
215
235
  } = createTables(tableFn)
216
236
 
217
237
  return {
218
238
  client,
239
+ async redeemFullPriceCoupon(options) {
240
+ const {
241
+ email: baseEmail,
242
+ couponId,
243
+ productIds,
244
+ currentUserId,
245
+ redeemingProductId,
246
+ } = options
247
+ const email = String(baseEmail).replace(' ', '+')
248
+
249
+ const coupon = await this.getCouponWithBulkPurchases(couponId)
250
+
251
+ const productId =
252
+ (coupon && (coupon.restrictedToProductId as string)) ||
253
+ redeemingProductId
254
+
255
+ if (!productId) throw new Error(`unable-to-find-any-product-id`)
256
+
257
+ const couponValidation = validateCoupon(coupon, productIds)
258
+
259
+ if (coupon && couponValidation.isRedeemable) {
260
+ // if the Coupon is the Bulk Coupon of a Bulk Purchase,
261
+ // then a bulk coupon is being redeemed
262
+ const bulkCouponRedemption = Boolean(
263
+ coupon.bulkCouponPurchases[0]?.bulkCouponId,
264
+ )
265
+
266
+ const { user } = await this.findOrCreateUser(email)
267
+
268
+ if (!user) throw new Error(`unable-to-create-user-${email}`)
269
+
270
+ const currentUser = currentUserId
271
+ ? await this.getUserById(currentUserId)
272
+ : null
273
+
274
+ const redeemingForCurrentUser = currentUser?.id === user.id
275
+
276
+ // To prevent double-purchasing, check if this user already has a
277
+ // Purchase record for this product that is valid and wasn't a bulk
278
+ // coupon purchase.
279
+ const existingPurchases =
280
+ await this.getExistingNonBulkValidPurchasesOfProduct({
281
+ userId: user.id,
282
+ productId,
283
+ })
284
+
285
+ if (existingPurchases.length > 0)
286
+ throw new Error(`already-purchased-${email}`)
287
+
288
+ const purchaseId = `purchase-${v4()}`
289
+
290
+ await this.createPurchase({
291
+ id: purchaseId,
292
+ userId: user.id,
293
+ couponId: bulkCouponRedemption ? null : coupon.id,
294
+ redeemedBulkCouponId: bulkCouponRedemption ? coupon.id : null,
295
+ productId,
296
+ totalAmount: '0',
297
+ metadata: {
298
+ couponUsedId: bulkCouponRedemption ? null : coupon.id,
299
+ },
300
+ })
301
+
302
+ const newPurchase = await this.getPurchase(purchaseId)
303
+
304
+ await this.incrementCouponUsedCount(coupon.id)
305
+
306
+ await this.createPurchaseTransfer({
307
+ sourceUserId: user.id,
308
+ purchaseId: purchaseId,
309
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7),
310
+ })
311
+
312
+ return { purchase: newPurchase, redeemingForCurrentUser }
313
+ }
314
+
315
+ return null
316
+ },
317
+ createPurchaseTransfer: async (options) => {
318
+ const id = `put_${v4()}`
319
+ await client.insert(purchaseUserTransfer).values({
320
+ id,
321
+ purchaseId: options.purchaseId,
322
+ sourceUserId: options.sourceUserId,
323
+ expiresAt: options.expiresAt,
324
+ })
325
+ },
326
+ incrementCouponUsedCount: async (couponId) => {
327
+ await client
328
+ .update(coupon)
329
+ .set({ usedCount: sql`${coupon.usedCount} + 1` })
330
+ .where(eq(coupon.id, couponId))
331
+ },
332
+ getExistingNonBulkValidPurchasesOfProduct: async ({
333
+ userId,
334
+ productId,
335
+ }) => {
336
+ const existingPurchases = await client.query.purchases.findMany({
337
+ where: and(
338
+ eq(purchaseTable.userId, userId),
339
+ productId ? eq(purchaseTable.productId, productId) : undefined,
340
+ eq(purchaseTable.status, 'Valid'),
341
+ isNull(purchaseTable.bulkCouponId),
342
+ ),
343
+ })
344
+
345
+ return z.array(purchaseSchema).parse(existingPurchases)
346
+ },
347
+ createMerchantCustomer: async (options) => {
348
+ await client.insert(merchantCustomer).values({
349
+ id: `mc_${v4()}`,
350
+ identifier: options.identifier,
351
+ merchantAccountId: options.merchantAccountId,
352
+ userId: options.userId,
353
+ status: 1,
354
+ })
355
+ return merchantCustomerSchema.parse(
356
+ await client.query.merchantCustomer.findFirst({
357
+ where: eq(merchantCustomer.identifier, options.identifier),
358
+ }),
359
+ )
360
+ },
361
+ getMerchantAccount: async (options) => {
362
+ return merchantAccountSchema.parse(
363
+ await client.query.merchantAccount.findFirst({
364
+ where: eq(merchantAccount.label, options.provider),
365
+ }),
366
+ )
367
+ },
368
+ getMerchantPriceForProductId: async (productId) => {
369
+ const merchantPriceData = await client.query.merchantPrice.findFirst({
370
+ where: eq(merchantPrice.merchantProductId, productId),
371
+ })
372
+
373
+ const parsedMerchantPrice =
374
+ merchantPriceSchema.safeParse(merchantPriceData)
375
+
376
+ if (!parsedMerchantPrice.success) {
377
+ console.error(
378
+ 'Error parsing merchant price',
379
+ JSON.stringify(parsedMerchantPrice.error),
380
+ )
381
+ return null
382
+ }
383
+
384
+ return parsedMerchantPrice.data
385
+ },
386
+ getMerchantProductForProductId: async (productId) => {
387
+ const merchantProductData = await client.query.merchantProduct.findFirst({
388
+ where: eq(merchantProduct.productId, productId),
389
+ })
390
+
391
+ if (!merchantProductData) return null
392
+ return merchantProductSchema.parse(merchantProductData)
393
+ },
394
+ getMerchantCustomerForUserId: async (userId) => {
395
+ const merchantCustomerData =
396
+ await client.query.merchantCustomer.findFirst({
397
+ where: eq(merchantCustomer.userId, userId),
398
+ })
399
+
400
+ if (!merchantCustomerData) return null
401
+ return merchantCustomerSchema.parse(merchantCustomerData)
402
+ },
403
+ getUpgradableProducts: async (options) => {
404
+ const { upgradableFromId, upgradableToId } = options
405
+ return z.array(upgradableProductSchema).parse(
406
+ await client.query.upgradableProducts.findMany({
407
+ where: and(
408
+ eq(upgradableProducts.upgradableFromId, upgradableFromId),
409
+ eq(upgradableProducts.upgradableToId, upgradableToId),
410
+ ),
411
+ }),
412
+ )
413
+ },
219
414
  availableUpgradesForProduct(
220
415
  purchases: any,
221
416
  productId: string,
@@ -240,11 +435,56 @@ export function mySqlDrizzleAdapter(
240
435
  }): Promise<void> {
241
436
  throw new Error('Method not implemented.')
242
437
  },
243
- completeLessonProgressForUser(options: {
438
+ async completeLessonProgressForUser(options: {
244
439
  userId: string
245
440
  lessonId?: string
246
441
  }): Promise<ResourceProgress | null> {
247
- throw new Error('Method not implemented.')
442
+ if (!options.lessonId) {
443
+ throw new Error('No lessonId provided')
444
+ }
445
+
446
+ let lessonProgress = await client.query.resourceProgress.findFirst({
447
+ where: and(
448
+ eq(resourceProgress.userId, options.userId),
449
+ eq(resourceProgress.contentResourceId, options.lessonId),
450
+ ),
451
+ })
452
+
453
+ const now = new Date()
454
+
455
+ if (lessonProgress) {
456
+ if (!lessonProgress.completedAt) {
457
+ await client
458
+ .update(resourceProgress)
459
+ .set({
460
+ completedAt: now,
461
+ updatedAt: now,
462
+ })
463
+ .where(eq(resourceProgress.contentResourceId, options.lessonId))
464
+ }
465
+ } else {
466
+ await client.insert(resourceProgress).values({
467
+ userId: options.userId,
468
+ contentResourceId: options.lessonId,
469
+ completedAt: now,
470
+ updatedAt: now,
471
+ })
472
+ }
473
+ lessonProgress = await client.query.resourceProgress.findFirst({
474
+ where: and(
475
+ eq(resourceProgress.userId, options.userId),
476
+ eq(resourceProgress.contentResourceId, options.lessonId),
477
+ ),
478
+ })
479
+ const parsedLessonProgress =
480
+ resourceProgressSchema.safeParse(lessonProgress)
481
+
482
+ if (!parsedLessonProgress.success) {
483
+ console.error('Error parsing lesson progress', lessonProgress)
484
+ return null
485
+ }
486
+
487
+ return parsedLessonProgress.data
248
488
  },
249
489
  couponForIdOrCode(options: {
250
490
  code?: string
@@ -279,7 +519,7 @@ export function mySqlDrizzleAdapter(
279
519
  )
280
520
 
281
521
  const existingPurchaseForCharge = existingMerchantCharge
282
- ? await client.query.purchase.findFirst({
522
+ ? await client.query.purchases.findFirst({
283
523
  where: eq(
284
524
  purchaseTable.merchantChargeId,
285
525
  existingMerchantCharge.id,
@@ -293,13 +533,13 @@ export function mySqlDrizzleAdapter(
293
533
  : null
294
534
 
295
535
  if (existingPurchaseForCharge) {
296
- return purchaseSchema.parse(existingPurchaseForCharge)
536
+ return existingPurchaseForCharge.id
297
537
  }
298
538
 
299
- const merchantChargeId = v4()
300
- const purchaseId = v4()
539
+ const merchantChargeId = `mc_${v4()}`
540
+ const purchaseId = `purch_${v4()}`
301
541
 
302
- const newMerchantCharge = trx.insert(merchantCharge).values({
542
+ const newMerchantCharge = await client.insert(merchantCharge).values({
303
543
  id: merchantChargeId,
304
544
  userId,
305
545
  identifier: stripeChargeId,
@@ -329,9 +569,20 @@ export function mySqlDrizzleAdapter(
329
569
  eq(purchaseTable.userId, userId),
330
570
  ),
331
571
  )
332
- .then((res) => res[0] ?? null),
572
+ .where(
573
+ and(
574
+ eq(coupon.restrictedToProductId, productId),
575
+ eq(purchaseTable.userId, userId),
576
+ ),
577
+ )
578
+ .then((res) => {
579
+ console.log({ res })
580
+ return res[0]?.coupons ?? null
581
+ }),
333
582
  )
334
583
 
584
+ console.log({ existingBulkCoupon })
585
+
335
586
  const isBulkPurchase =
336
587
  quantity > 1 ||
337
588
  Boolean(existingBulkCoupon) ||
@@ -346,7 +597,7 @@ export function mySqlDrizzleAdapter(
346
597
  existingBulkCoupon !== null ? existingBulkCoupon.id : v4()
347
598
 
348
599
  if (existingBulkCoupon !== null) {
349
- couponToUpdate = trx
600
+ couponToUpdate = await client
350
601
  .update(coupon)
351
602
  .set({
352
603
  maxUses: (existingBulkCoupon?.maxUses || 0) + quantity,
@@ -361,7 +612,7 @@ export function mySqlDrizzleAdapter(
361
612
  )
362
613
  : null
363
614
 
364
- couponToUpdate = await trx.insert(coupon).values({
615
+ couponToUpdate = await client.insert(coupon).values({
365
616
  id: bulkCouponId as string,
366
617
  percentageDiscount: '1.0',
367
618
  restrictedToProductId: productId,
@@ -376,13 +627,17 @@ export function mySqlDrizzleAdapter(
376
627
  }
377
628
  }
378
629
 
379
- const merchantSessionId = v4()
630
+ const merchantSessionId = `ms_${v4()}`
380
631
 
381
- const newMerchantSession = trx.insert(merchantSession).values({
382
- id: merchantSessionId,
383
- identifier: checkoutSessionId,
384
- merchantAccountId,
385
- })
632
+ const newMerchantSession = await client
633
+ .insert(merchantSession)
634
+ .values({
635
+ id: merchantSessionId,
636
+ identifier: checkoutSessionId,
637
+ merchantAccountId,
638
+ })
639
+
640
+ console.log({ newMerchantSession })
386
641
 
387
642
  const merchantCouponUsed = stripeCouponId
388
643
  ? await client.query.merchantCoupon.findFirst({
@@ -390,6 +645,8 @@ export function mySqlDrizzleAdapter(
390
645
  })
391
646
  : null
392
647
 
648
+ console.log({ merchantCouponUsed })
649
+
393
650
  const pppMerchantCoupon = appliedPPPStripeCouponId
394
651
  ? await client.query.merchantCoupon.findFirst({
395
652
  where: and(
@@ -399,12 +656,14 @@ export function mySqlDrizzleAdapter(
399
656
  })
400
657
  : null
401
658
 
659
+ console.log({ pppMerchantCoupon })
660
+
402
661
  const newPurchaseStatus =
403
662
  merchantCouponUsed?.type === 'ppp' || pppMerchantCoupon
404
663
  ? 'Restricted'
405
664
  : 'Valid'
406
665
 
407
- const newPurchase = trx.insert(purchaseTable).values({
666
+ const newPurchase = await client.insert(purchaseTable).values({
408
667
  id: purchaseId,
409
668
  status: newPurchaseStatus,
410
669
  userId,
@@ -418,12 +677,14 @@ export function mySqlDrizzleAdapter(
418
677
  couponId: usedCouponId || null,
419
678
  })
420
679
 
680
+ console.log({ newPurchase })
681
+
421
682
  const oneWeekInMilliseconds = 1000 * 60 * 60 * 24 * 7
422
683
 
423
- const newPurchaseUserTransfer = trx
684
+ const newPurchaseUserTransfer = await client
424
685
  .insert(purchaseUserTransfer)
425
686
  .values({
426
- id: v4(),
687
+ id: `put_${v4()}`,
427
688
  purchaseId: purchaseId as string,
428
689
  expiresAt: existingPurchase
429
690
  ? new Date()
@@ -431,13 +692,19 @@ export function mySqlDrizzleAdapter(
431
692
  sourceUserId: userId,
432
693
  })
433
694
 
434
- await Promise.all([
435
- newMerchantCharge,
436
- newPurchase,
437
- newPurchaseUserTransfer,
438
- newMerchantSession,
439
- ...(couponToUpdate ? [couponToUpdate] : []),
440
- ])
695
+ console.log({ newPurchaseUserTransfer })
696
+
697
+ // const result = await Promise.all([
698
+ // newMerchantCharge,
699
+ // newPurchase,
700
+ // newPurchaseUserTransfer,
701
+ // newMerchantSession,
702
+ // ...(couponToUpdate ? [couponToUpdate] : []),
703
+ // ])
704
+ //
705
+ // console.log('result', { result })
706
+
707
+ console.log('inside', { purchaseId })
441
708
 
442
709
  return purchaseId
443
710
  } catch (error) {
@@ -447,27 +714,79 @@ export function mySqlDrizzleAdapter(
447
714
  }
448
715
  })
449
716
 
450
- return purchaseSchema.parse(
717
+ console.log('putside', { purchaseId })
718
+
719
+ const parsedPurchase = purchaseSchema.safeParse(
451
720
  await client.query.purchases.findFirst({
452
721
  where: eq(purchaseTable.id, purchaseId as string),
453
722
  }),
454
723
  )
724
+
725
+ if (!parsedPurchase.success) {
726
+ console.error(
727
+ 'Error parsing purchase',
728
+ parsedPurchase,
729
+ JSON.stringify(parsedPurchase, null, 2),
730
+ )
731
+ throw new Error('Error parsing purchase')
732
+ }
733
+
734
+ return parsedPurchase.data
455
735
  },
456
- findOrCreateMerchantCustomer(options: {
736
+ async findOrCreateMerchantCustomer(options: {
457
737
  user: User
458
738
  identifier: string
459
739
  merchantAccountId: string
460
740
  }): Promise<MerchantCustomer | null> {
461
- throw new Error('Method not implemented.')
741
+ const merchantCustomer = merchantCustomerSchema
742
+ .nullable()
743
+ .optional()
744
+ .parse(
745
+ await client.query.merchantCustomer.findFirst({
746
+ where: (merchantCustomer, { eq }) =>
747
+ eq(merchantCustomer.identifier, options.identifier),
748
+ }),
749
+ )
750
+
751
+ if (merchantCustomer) {
752
+ return merchantCustomer
753
+ }
754
+
755
+ return await this.createMerchantCustomer({
756
+ identifier: options.identifier,
757
+ merchantAccountId: options.merchantAccountId,
758
+ userId: options.user.id,
759
+ })
462
760
  },
463
- findOrCreateUser(
761
+ async findOrCreateUser(
464
762
  email: string,
465
763
  name?: string | null,
466
764
  ): Promise<{
467
765
  user: User
468
766
  isNewUser: boolean
469
767
  }> {
470
- throw new Error('Method not implemented.')
768
+ const user = await this.getUserByEmail?.(email)
769
+
770
+ if (!user) {
771
+ const newUser = await this.createUser?.({
772
+ id: `u_${v4()}`,
773
+ email,
774
+ name,
775
+ emailVerified: null,
776
+ })
777
+ if (!newUser) {
778
+ throw new Error('Could not create user')
779
+ }
780
+ return {
781
+ user: newUser as User,
782
+ isNewUser: true,
783
+ }
784
+ }
785
+
786
+ return {
787
+ user: user as User,
788
+ isNewUser: false,
789
+ }
471
790
  },
472
791
  async getCoupon(couponIdOrCode: string): Promise<Coupon | null> {
473
792
  return couponSchema.nullable().parse(
@@ -508,10 +827,19 @@ export function mySqlDrizzleAdapter(
508
827
  getLessonProgresses(): Promise<ResourceProgress[]> {
509
828
  throw new Error('Method not implemented.')
510
829
  },
511
- getMerchantCharge(
830
+ async getMerchantCharge(
512
831
  merchantChargeId: string,
513
832
  ): Promise<MerchantCharge | null> {
514
- throw new Error('Method not implemented.')
833
+ const mCharge = await client.query.merchantCharge.findFirst({
834
+ where: eq(merchantCharge.id, merchantChargeId),
835
+ })
836
+ console.log('mCharge', mCharge)
837
+ const parsed = merchantChargeSchema.safeParse(mCharge)
838
+ if (!parsed.success) {
839
+ console.error('Error parsing merchantCharge', mCharge)
840
+ return null
841
+ }
842
+ return parsed.data
515
843
  },
516
844
  async getMerchantCouponsForTypeAndPercent(params: {
517
845
  type: string
@@ -612,77 +940,7 @@ export function mySqlDrizzleAdapter(
612
940
 
613
941
  return purchaseSchema.parse(newPurchase)
614
942
  },
615
- async getPurchaseDetails(
616
- purchaseId: string,
617
- userId: string,
618
- ): Promise<{
619
- purchase?: Purchase
620
- existingPurchase?: Purchase & { product?: Product | null }
621
- availableUpgrades: UpgradableProduct[]
622
- }> {
623
- const allPurchases = await this.getPurchasesForUser(userId)
624
- const thePurchase = await client.query.purchases.findFirst({
625
- where: and(
626
- eq(purchaseTable.id, purchaseId),
627
- eq(purchaseTable.userId, userId),
628
- ),
629
- with: {
630
- user: true,
631
- product: true,
632
- bulkCoupon: true,
633
- },
634
- })
635
943
 
636
- const parsedPurchase = purchaseSchema.safeParse(thePurchase)
637
-
638
- if (!parsedPurchase.success) {
639
- console.error('Error parsing purchase', parsedPurchase)
640
- return {
641
- availableUpgrades: [],
642
- }
643
- }
644
-
645
- const purchaseCanUpgrade = ['Valid', 'Restricted'].includes(
646
- parsedPurchase.data.state || '',
647
- )
648
-
649
- if (!purchaseCanUpgrade) {
650
- return {
651
- availableUpgrades: [],
652
- }
653
- }
654
-
655
- const availableUpgrades = await client.query.upgradableProducts.findMany({
656
- where: and(
657
- eq(
658
- upgradableProducts.upgradableFromId,
659
- parsedPurchase.data.product?.id as string,
660
- ),
661
- not(
662
- inArray(
663
- upgradableProducts.upgradableToId,
664
- allPurchases.map((p) => p.product?.id as string),
665
- ),
666
- ),
667
- ),
668
- with: {
669
- upgradableTo: true,
670
- upgradableFrom: true,
671
- },
672
- })
673
-
674
- const existingPurchase = allPurchases.find(
675
- (p) => p.product?.id === parsedPurchase.data.product?.id,
676
- )
677
-
678
- return Promise.resolve({
679
- availableUpgrades: z
680
- .array(upgradableProductSchema)
681
- .parse(availableUpgrades),
682
- existingPurchase,
683
- purchase: parsedPurchase.data,
684
- })
685
- },
686
944
  async getPurchaseForStripeCharge(
687
945
  stripeChargeId: string,
688
946
  ): Promise<Purchase | null> {
@@ -697,7 +955,9 @@ export function mySqlDrizzleAdapter(
697
955
  eq(merchantCharge.id, purchaseTable.merchantChargeId),
698
956
  ),
699
957
  )
700
- .then((res) => res[0] ?? null),
958
+ .then((res) => {
959
+ return res[0]?.purchases ?? null
960
+ }),
701
961
  )
702
962
 
703
963
  if (!purchase.success) {
@@ -747,12 +1007,106 @@ export function mySqlDrizzleAdapter(
747
1007
  const parsedPurchases = z.array(purchaseSchema).safeParse(userPurchases)
748
1008
 
749
1009
  if (!parsedPurchases.success) {
750
- console.error('Error parsing purchases', parsedPurchases)
1010
+ console.error(
1011
+ 'Error parsing purchases',
1012
+ JSON.stringify(parsedPurchases.error),
1013
+ )
751
1014
  return []
752
1015
  }
753
1016
 
754
1017
  return parsedPurchases.data
755
1018
  },
1019
+ async getPurchaseDetails(
1020
+ purchaseId: string,
1021
+ userId: string,
1022
+ ): Promise<{
1023
+ purchase?: Purchase
1024
+ existingPurchase?: Purchase & { product?: Product | null }
1025
+ availableUpgrades: UpgradableProduct[]
1026
+ }> {
1027
+ const visiblePurchaseStates = ['Valid', 'Refunded', 'Restricted']
1028
+
1029
+ const userPurchases = await client.query.purchases.findMany({
1030
+ where: and(
1031
+ eq(purchaseTable.userId, userId),
1032
+ inArray(purchaseTable.status, visiblePurchaseStates),
1033
+ ),
1034
+ with: {
1035
+ user: true,
1036
+ product: true,
1037
+ bulkCoupon: true,
1038
+ },
1039
+ orderBy: asc(purchaseTable.createdAt),
1040
+ })
1041
+
1042
+ const parsedPurchases = z.array(purchaseSchema).safeParse(userPurchases)
1043
+
1044
+ const allPurchases = parsedPurchases.success ? parsedPurchases.data : []
1045
+
1046
+ console.log('🦦', { allPurchases })
1047
+
1048
+ const thePurchase = await client.query.purchases.findFirst({
1049
+ where: and(
1050
+ eq(purchaseTable.id, purchaseId),
1051
+ eq(purchaseTable.userId, userId),
1052
+ ),
1053
+ with: {
1054
+ user: true,
1055
+ product: true,
1056
+ bulkCoupon: true,
1057
+ },
1058
+ })
1059
+
1060
+ const parsedPurchase = purchaseSchema.safeParse(thePurchase)
1061
+
1062
+ if (!parsedPurchase.success) {
1063
+ console.error('Error parsing purchase', parsedPurchase)
1064
+ return {
1065
+ availableUpgrades: [],
1066
+ }
1067
+ }
1068
+
1069
+ console.log('🦦', { parsedPurchase: parsedPurchase.data })
1070
+
1071
+ const purchaseCanUpgrade = ['Valid', 'Restricted'].includes(
1072
+ parsedPurchase.data.state || '',
1073
+ )
1074
+
1075
+ let availableUpgrades: any[] = []
1076
+
1077
+ if (purchaseCanUpgrade) {
1078
+ availableUpgrades = await client.query.upgradableProducts.findMany({
1079
+ where: and(
1080
+ eq(
1081
+ upgradableProducts.upgradableFromId,
1082
+ parsedPurchase.data.product?.id as string,
1083
+ ),
1084
+ not(
1085
+ inArray(
1086
+ upgradableProducts.upgradableToId,
1087
+ allPurchases.map((p) => p.product?.id as string),
1088
+ ),
1089
+ ),
1090
+ ),
1091
+ with: {
1092
+ upgradableTo: true,
1093
+ upgradableFrom: true,
1094
+ },
1095
+ })
1096
+ }
1097
+
1098
+ const existingPurchase = allPurchases.find(
1099
+ (p) => p.product?.id === parsedPurchase.data.product?.id,
1100
+ )
1101
+
1102
+ return Promise.resolve({
1103
+ availableUpgrades: z
1104
+ .array(upgradableProductSchema)
1105
+ .parse(availableUpgrades),
1106
+ existingPurchase,
1107
+ purchase: parsedPurchase.data,
1108
+ })
1109
+ },
756
1110
  async getUserById(userId: string): Promise<User | null> {
757
1111
  return userSchema.nullable().parse(
758
1112
  await client.query.users.findFirst({
@@ -788,19 +1142,16 @@ export function mySqlDrizzleAdapter(
788
1142
  ),
789
1143
  })
790
1144
 
791
- const purchasesMade = z.array(z.string()).parse(
1145
+ const productsPurchased = z.array(z.string()).parse(
792
1146
  purchases.map((purchase) => {
793
1147
  return purchase.productId
794
1148
  }),
795
1149
  )
796
1150
 
797
- if (purchasesMade.length === 0) return []
1151
+ if (productsPurchased.length === 0) return []
798
1152
 
799
1153
  const foundPrices = await client.query.prices.findMany({
800
- where: and(
801
- eq(prices.productId, bundleId),
802
- inArray(prices.productId, purchasesMade),
803
- ),
1154
+ where: inArray(prices.productId, productsPurchased),
804
1155
  })
805
1156
 
806
1157
  return z.array(priceSchema).parse(foundPrices)