|
| 1 | +import fastq from 'fastq'; |
1 | 2 | import '../src/config';
|
2 | 3 | import createOrGetConnection from '../src/db';
|
3 | 4 | import {
|
|
8 | 9 | import { User } from '../src/entity/user/User';
|
9 | 10 | import type { UserNotificationFlags } from '../src/entity/user/User';
|
10 | 11 |
|
| 12 | +const QUEUE_CONCURRENCY = 1; |
| 13 | + |
11 | 14 | interface UserData {
|
12 | 15 | id: string;
|
13 | 16 | notificationEmail: boolean;
|
@@ -73,50 +76,53 @@ function buildNotificationFlags(user: UserData): UserNotificationFlags {
|
73 | 76 | const con = await createOrGetConnection();
|
74 | 77 |
|
75 | 78 | try {
|
76 |
| - const userRepo = con.getRepository(User); |
77 |
| - |
78 |
| - const users = await userRepo |
79 |
| - .createQueryBuilder('user') |
80 |
| - .select([ |
81 |
| - 'user.id', |
82 |
| - 'user.notificationEmail', |
83 |
| - 'user.followingEmail', |
84 |
| - 'user.followNotifications', |
85 |
| - 'user.awardEmail', |
86 |
| - 'user.awardNotifications', |
87 |
| - 'user.notificationFlags', |
88 |
| - ]) |
89 |
| - .orderBy('user.id') |
90 |
| - .limit(limit) |
91 |
| - .offset(offset) |
92 |
| - .getMany(); |
93 |
| - |
94 | 79 | console.log(
|
95 |
| - `Processing ${users.length} users (offset ${offset} to ${offset + users.length - 1})...`, |
| 80 | + `Processing users starting from offset ${offset} (limit ${limit})...`, |
96 | 81 | );
|
97 | 82 |
|
| 83 | + let processedCount = 0; |
| 84 | + |
98 | 85 | await con.transaction(async (manager) => {
|
99 |
| - for (const user of users) { |
100 |
| - const userData: UserData = { |
101 |
| - id: user.id, |
102 |
| - notificationEmail: user.notificationEmail, |
103 |
| - followingEmail: user.followingEmail, |
104 |
| - followNotifications: user.followNotifications, |
105 |
| - awardEmail: user.awardEmail, |
106 |
| - awardNotifications: user.awardNotifications, |
107 |
| - notificationFlags: user.notificationFlags, |
108 |
| - }; |
109 |
| - |
110 |
| - const newFlags = buildNotificationFlags(userData); |
| 86 | + const userRepo = manager.getRepository(User); |
| 87 | + |
| 88 | + const builder = userRepo |
| 89 | + .createQueryBuilder('user') |
| 90 | + .select('user.id', 'id') |
| 91 | + .addSelect('user.notificationEmail', 'notificationEmail') |
| 92 | + .addSelect('user.followingEmail', 'followingEmail') |
| 93 | + .addSelect('user.followNotifications', 'followNotifications') |
| 94 | + .addSelect('user.awardEmail', 'awardEmail') |
| 95 | + .addSelect('user.awardNotifications', 'awardNotifications') |
| 96 | + .addSelect('user.notificationFlags', 'notificationFlags') |
| 97 | + .orderBy('user.id') |
| 98 | + .limit(limit) |
| 99 | + .offset(offset); |
| 100 | + |
| 101 | + const stream = await builder.stream(); |
| 102 | + |
| 103 | + const insertQueue = fastq.promise(async (user: UserData) => { |
| 104 | + const newFlags = buildNotificationFlags(user); |
111 | 105 |
|
112 | 106 | await manager
|
113 | 107 | .getRepository(User)
|
114 | 108 | .update({ id: user.id }, { notificationFlags: newFlags });
|
115 |
| - } |
| 109 | + |
| 110 | + processedCount++; |
| 111 | + }, QUEUE_CONCURRENCY); |
| 112 | + |
| 113 | + stream.on('data', (user: UserData) => { |
| 114 | + insertQueue.push(user); |
| 115 | + }); |
| 116 | + |
| 117 | + await new Promise((resolve, reject) => { |
| 118 | + stream.on('error', reject); |
| 119 | + stream.on('end', () => resolve(true)); |
| 120 | + }); |
| 121 | + await insertQueue.drained(); |
116 | 122 | });
|
117 | 123 |
|
118 | 124 | console.log(
|
119 |
| - `Migration completed successfully. Updated ${users.length} users (offset ${offset} to ${offset + users.length - 1}).`, |
| 125 | + `Migration completed successfully. Updated ${processedCount} users (offset ${offset} to ${offset + processedCount - 1}).`, |
120 | 126 | );
|
121 | 127 | } catch (error) {
|
122 | 128 | console.error('Migration failed:', error);
|
|
0 commit comments