db.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import pg from 'pg'
  2. const { Pool } = pg
  3. export const pool = new Pool({
  4. connectionString: process.env.DATABASE_URL || 'postgresql://xinghen:xinghen@localhost:5432/xinghen'
  5. })
  6. export const mapUser = (r: any) => ({
  7. id: r.id,
  8. phone: r.phone,
  9. role: r.role || 'USER',
  10. organization: r.organization || '',
  11. wechat: r.wechat || '',
  12. contactName: r.contact_name || '',
  13. bio: r.bio || '',
  14. createdAt: r.created_at,
  15. updatedAt: r.updated_at
  16. })
  17. export const mapAsset = (r: any) => ({
  18. id: r.id,
  19. courseId: r.course_id,
  20. episodeId: r.episode_id || null,
  21. originalName: r.original_name,
  22. size: Number(r.size),
  23. mimeType: r.mime_type,
  24. url: `/uploads/${r.stored_name}`,
  25. createdAt: r.created_at
  26. })
  27. export const mapInstructor = (r: any) => ({
  28. id: r.id,
  29. name: r.name,
  30. organization: r.organization || '',
  31. introduction: r.introduction || '',
  32. imageUrl: r.image_stored_name ? `/uploads/${r.image_stored_name}` : null
  33. })
  34. export const mapDeliverable = (r: any) => ({
  35. id: r.id,
  36. courseId: r.course_id,
  37. episodeId: r.episode_id || null,
  38. originalName: r.original_name,
  39. size: Number(r.size),
  40. mimeType: r.mime_type,
  41. url: `/uploads/${r.stored_name}`,
  42. createdAt: r.created_at
  43. })
  44. export const mapEpisode = (r: any, assets: any[] = [], deliverables: any[] = []) => ({
  45. id: r.id,
  46. courseId: r.course_id,
  47. episodeNumber: Number(r.episode_number) || 1,
  48. title: r.title,
  49. summary: r.summary || '',
  50. lectureNotes: r.lecture_notes || '',
  51. createdAt: r.created_at,
  52. updatedAt: r.updated_at,
  53. assets: assets.map(mapAsset),
  54. deliverables: deliverables.map(mapDeliverable)
  55. })
  56. export const mapCourse = (
  57. r: any,
  58. assets: any[] = [],
  59. instructors: any[] = [],
  60. deliverables: any[] = [],
  61. creatorUser: any = null,
  62. episodes: any[] = []
  63. ) => {
  64. const mappedAssets = assets.map(mapAsset)
  65. const mappedDeliverables = deliverables.map(mapDeliverable)
  66. // 为每个分集关联专属的 assets 与 deliverables
  67. const mappedEpisodes = episodes.map((epRow) => {
  68. const epAssets = assets.filter((a) => a.episode_id === epRow.id)
  69. const epDeliverables = deliverables.filter((d) => d.episode_id === epRow.id)
  70. return mapEpisode(epRow, epAssets, epDeliverables)
  71. })
  72. return {
  73. id: r.id,
  74. userId: r.user_id,
  75. name: r.name,
  76. category: r.category || '',
  77. audience: r.audience || '',
  78. description: r.description || '',
  79. status: r.status,
  80. productionNotes: r.production_notes || '',
  81. createdAt: r.created_at,
  82. submittedAt: r.submitted_at || null,
  83. completedAt: r.completed_at || null,
  84. assets: mappedAssets,
  85. episodes: mappedEpisodes,
  86. instructors: instructors.map(mapInstructor),
  87. deliverables: mappedDeliverables,
  88. creator: creatorUser ? mapUser(creatorUser) : (r.user_phone ? {
  89. id: r.user_id,
  90. phone: r.user_phone,
  91. role: r.user_role || 'USER',
  92. organization: r.user_organization || '',
  93. wechat: r.user_wechat || '',
  94. contactName: r.user_contact_name || '',
  95. bio: r.user_bio || '',
  96. createdAt: r.user_created_at
  97. } : undefined)
  98. }
  99. }