aboutsummaryrefslogtreecommitdiffstats
path: root/src/scripts/migrate.ts
blob: 903f119318154bd7beeb5705366fbe58a25ef46b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// @ts-nocheck
import { randomId } from '@/lib/api'
import { getPrisma } from '@/lib/prisma'
import { Prisma } from '@prisma/client'
import { Client } from 'pg'

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'

async function main() {
  withClient(async (client) => {
    const prisma = await getPrisma()

    // console.log('Deleting all groups…')
    // await prisma.group.deleteMany({})

    const { rows: groupRows } = await client.query<{
      id: string
      name: string
      currency: string
      created_at: Date
    }>('select id, name, currency, created_at from groups')

    const existingGroups = (
      await prisma.group.findMany({ select: { id: true } })
    ).map((group) => group.id)

    for (const groupRow of groupRows) {
      const participants: Prisma.ParticipantCreateManyInput[] = []
      const expenses: Prisma.ExpenseCreateManyInput[] = []
      const expenseParticipants: Prisma.ExpensePaidForCreateManyInput[] = []
      const participantIdsMapping: Record<number, string> = {}
      const expenseIdsMapping: Record<number, string> = {}

      if (existingGroups.includes(groupRow.id)) {
        console.log(`Group ${groupRow.id} already exists, skipping.`)
        continue
      }

      const group: Prisma.GroupCreateInput = {
        id: groupRow.id,
        name: groupRow.name,
        currency: groupRow.currency,
        createdAt: groupRow.created_at,
      }

      const { rows: participantRows } = await client.query<{
        id: number
        created_at: Date
        name: string
      }>(
        'select id, created_at, name from participants where group_id = $1::text',
        [groupRow.id],
      )
      for (const participantRow of participantRows) {
        const id = randomId()
        participantIdsMapping[participantRow.id] = id
        participants.push({
          id,
          groupId: groupRow.id,
          name: participantRow.name,
        })
      }

      const { rows: expenseRows } = await client.query<{
        id: number
        created_at: Date
        description: string
        amount: number
        paid_by_participant_id: number
        is_reimbursement: boolean
      }>(
        'select id, created_at, description, amount, paid_by_participant_id, is_reimbursement from expenses where group_id = $1::text and deleted_at is null',
        [groupRow.id],
      )
      for (const expenseRow of expenseRows) {
        const id = randomId()
        expenseIdsMapping[expenseRow.id] = id
        expenses.push({
          id,
          amount: Math.round(expenseRow.amount * 100),
          groupId: groupRow.id,
          title: expenseRow.description,
          categoryId: 1,
          expenseDate: new Date(expenseRow.created_at.toDateString()),
          createdAt: expenseRow.created_at,
          isReimbursement: expenseRow.is_reimbursement === true,
          paidById: participantIdsMapping[expenseRow.paid_by_participant_id],
        })
      }

      if (expenseRows.length > 0) {
        const { rows: expenseParticipantRows } = await client.query<{
          expense_id: number
          participant_id: number
        }>(
          'select expense_id, participant_id from expense_participants where expense_id = any($1::int[]);',
          [expenseRows.map((row) => row.id)],
        )
        for (const expenseParticipantRow of expenseParticipantRows) {
          expenseParticipants.push({
            expenseId: expenseIdsMapping[expenseParticipantRow.expense_id],
            participantId:
              participantIdsMapping[expenseParticipantRow.participant_id],
          })
        }
      }

      console.log('Creating group:', group)
      await prisma.group.create({ data: group })
      console.log('Creating participants:', participants)
      await prisma.participant.createMany({ data: participants })
      console.log('Creating expenses:', expenses)
      await prisma.expense.createMany({ data: expenses })
      console.log('Creating expenseParticipants:', expenseParticipants)
      await prisma.expensePaidFor.createMany({ data: expenseParticipants })
    }
  })
}

async function withClient(fn: (client: Client) => void | Promise<void>) {
  const client = new Client({
    connectionString: process.env.OLD_POSTGRES_URL,
    ssl: true,
  })
  await client.connect()
  console.log('Connected.')

  try {
    await fn(client)
  } finally {
    await client.end()
    console.log('Disconnected.')
  }
}

main().catch(console.error)