@gumin61/transfer-data-sdk 1.0.0
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.
- package/README.md +317 -0
- package/dist/transfer-data-sdk/index.d.ts +3 -0
- package/dist/transfer-data-sdk/index.d.ts.map +1 -0
- package/dist/transfer-data-sdk/index.js +7 -0
- package/dist/transfer-data-sdk/index.js.map +1 -0
- package/dist/transfer-data-sdk/script.d.ts +13 -0
- package/dist/transfer-data-sdk/script.d.ts.map +1 -0
- package/dist/transfer-data-sdk/script.js +449 -0
- package/dist/transfer-data-sdk/script.js.map +1 -0
- package/dist/transfer-data-sdk/types.d.ts +60 -0
- package/dist/transfer-data-sdk/types.d.ts.map +1 -0
- package/dist/transfer-data-sdk/types.js +3 -0
- package/dist/transfer-data-sdk/types.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# คู่มือการใช้งาน Script Transfer Data PDPA
|
|
2
|
+
|
|
3
|
+
สคริปต์นี้ใช้โอนย้ายข้อมูลจากฐานข้อมูลต้นทาง (source) ไปยังฐานข้อมูลปลายทาง (target) แบ่งเป็นส่วน (sections) ตามลำดับความสัมพันธ์ของตาราง (FK)
|
|
4
|
+
|
|
5
|
+
**หมายเหตุ:** ต้องมีไฟล์ `.env` กำหนดค่าเชื่อมต่อ DB ต้นทางและปลายทางก่อนรัน
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## การใช้งานแบบ SDK (สำหรับ npm package)
|
|
10
|
+
|
|
11
|
+
แพ็กเกจนี้ export ฟังก์ชันหลัก `copyDataTables` ที่ path หลักของแพ็กเกจ
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import mysql from "mysql2/promise";
|
|
15
|
+
import { copyDataTables } from "@gumin61/transfer-data-sdk";
|
|
16
|
+
|
|
17
|
+
const sourcePool = mysql.createPool({ /* source config */ });
|
|
18
|
+
const targetPool = mysql.createPool({ /* target config */ });
|
|
19
|
+
|
|
20
|
+
const result = await copyDataTables(
|
|
21
|
+
{ sourcePool, targetPool },
|
|
22
|
+
{
|
|
23
|
+
tableNames: ["permissions"],
|
|
24
|
+
restoreUserRefsOptions: [
|
|
25
|
+
{ tableName: "organizations", batchSize: 100 },
|
|
26
|
+
{ tableName: "systemlangaue", batchSize: 100 },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- build SDK: `npm run build:sdk`
|
|
33
|
+
- ทดสอบตัวอย่างการใช้งาน SDK: `npm run demo:test`
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. คำสั่ง npm ที่มีในโปรเจกต์
|
|
38
|
+
|
|
39
|
+
### 1.1 รันโอนข้อมูลทีละตาราง (ใช้กรณีที่ข้อมูลฐานนั้นไม่ครบหรือมีข้อมูลใหม่เข้ามา)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run table -- --name "<ชื่อตาราง>"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| คำสั่งตัวอย่าง | ความหมาย |
|
|
46
|
+
|---------------|----------|
|
|
47
|
+
| `npm run table -- --name "permissions"` | โอนเฉพาะตาราง permissions (sync จาก v3) |
|
|
48
|
+
| `npm run table -- --name "users"` | โอนเฉพาะตาราง users |
|
|
49
|
+
| `npm run table -- --name "pii_master"` | โอนเฉพาะตาราง pii_master |
|
|
50
|
+
| `npm run table -- --name "organizations"` | โอนเฉพาะตาราง organizations |
|
|
51
|
+
|
|
52
|
+
- ตารางต้องอยู่ใน config ของ section ใด section หนึ่ง (`sections.config.ts`) จึงจะรันได้
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### 1.2 รันโอนตาม Section
|
|
57
|
+
|
|
58
|
+
| คำสั่ง | ความหมาย |
|
|
59
|
+
|--------|----------|
|
|
60
|
+
| `npm run transfer:sections` | รันทุก section ตามลำดับ (section-1 → master-data → section-2 → … → section-6 → section-1 อีกครั้ง → section-7-1 → section-7-2) |
|
|
61
|
+
| `npm run transfer:section-1` | รันเฉพาะ Section 1 (Core Data) |
|
|
62
|
+
| `npm run transfer:section-2` | รันเฉพาะ Section 2 |
|
|
63
|
+
| `npm run transfer:section-3` | รันเฉพาะ Section 3 |
|
|
64
|
+
| `npm run transfer:section-4` | รันเฉพาะ Section 4 |
|
|
65
|
+
| `npm run transfer:section-5` | รันเฉพาะ Section 5 |
|
|
66
|
+
| `npm run transfer:section-6` | รันเฉพาะ Section 6 |
|
|
67
|
+
| `npm run transfer:master-data` | รันเฉพาะ Master Data |
|
|
68
|
+
| `npm run transfer:section-7` | รัน Section 7 ทั้งหมด (section-7-1 + section-7-2) |
|
|
69
|
+
| `npm run transfer:section-7-1` | รันเฉพาะ Section 7.1 |
|
|
70
|
+
| `npm run transfer:section-7-2` | รันเฉพาะ Section 7.2 (จำเป็นต้องรัน 7.1 ก่อน หากรันแล้วสามารถรันส่วนนี้ทันทีได้เลย) |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### 1.3 รันทดสอบและตรวจสอบข้อมูล (ส่วนนี้ต้องกำหนด Logic ที่จะตรวจสอบใน run-test.ts)
|
|
75
|
+
|
|
76
|
+
| คำสั่ง | ความหมาย |
|
|
77
|
+
|--------|----------|
|
|
78
|
+
| `npm run test -- --function "<function_name>"` | รันฟังก์ชันทดสอบที่กำหนด (เช่น `validate_permissions`, `validate_data`, `copy_tables`) |
|
|
79
|
+
| `npm run validate-data` | รันการตรวจสอบความถูกต้องของข้อมูล |
|
|
80
|
+
| `npm run seed:permissions` | seed/อัปเดตตาราง permissions จาก `src/assets/data/permissions.ts` (รันแยกหลัง section-1 ตามต้องการ) |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 2. ลำดับการรันเมื่อใช้ `transfer:sections` (ไม่ควรข้าม section ใด section หนึ่ง)
|
|
85
|
+
|
|
86
|
+
1. **section-1** (Core Data – company, org, users, roles, permissions ฯลฯ)
|
|
87
|
+
2. **master-data** (Master tables – chanel_dsar, data_type_master ฯลฯ)
|
|
88
|
+
3. **section-2** (Owner, Activity, ROP ฯลฯ)
|
|
89
|
+
4. **section-3** (Consent)
|
|
90
|
+
5. **section-4** (DSAR)
|
|
91
|
+
6. **section-5** (Incident)
|
|
92
|
+
7. **section-6** (PDPA message, file attach ฯลฯ)
|
|
93
|
+
8. **section-1** อีกครั้ง (ถ้าต้องการ sync ข้อมูล core ซ้ำ)
|
|
94
|
+
9. **`npm run seed:permissions`** (อัปเดต permissions จาก assets/data/permissions.ts — รันแยกเมื่อต้องการ)
|
|
95
|
+
10. **section-7-1** (CK, Consent CK ฯลฯ)
|
|
96
|
+
11. **section-7-2** (Access, DSAR เพิ่มเติม, Technical measures ฯลฯ)
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. ตารางที่แต่ละ Section Insert และเงื่อนไขเพิ่มเติม
|
|
101
|
+
|
|
102
|
+
### Master Data (`master-data`)
|
|
103
|
+
|
|
104
|
+
**วิธีโอน:** ใช้ `copyTableMaster` — อ่านจาก source แล้ว insert ลง target โดยรันซ้ำจะ **insert เฉพาะแถวที่ PK ยังไม่มีใน target** (ไม่ insert ซ้ำ)
|
|
105
|
+
|
|
106
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
107
|
+
|
|
108
|
+
| ลำดับ | ชื่อตาราง |
|
|
109
|
+
|-------|------------|
|
|
110
|
+
| 1 | chanel_dsar_master |
|
|
111
|
+
| 2 | data_backup_location_master |
|
|
112
|
+
| 3 | disposal_data_type_master |
|
|
113
|
+
| 4 | encryption_type_master |
|
|
114
|
+
| 5 | subject_type_master |
|
|
115
|
+
| 6 | subject_group_master |
|
|
116
|
+
| 7 | rop_gap_type_master |
|
|
117
|
+
| 8 | rop_gap_master |
|
|
118
|
+
| 9 | data_type_master |
|
|
119
|
+
| 10 | pii_master |
|
|
120
|
+
| 11 | legal_bases_master |
|
|
121
|
+
| 12 | tags |
|
|
122
|
+
| 13 | taggables |
|
|
123
|
+
| 14 | role_master |
|
|
124
|
+
| 15 | rop_type_master |
|
|
125
|
+
| 16 | question_master |
|
|
126
|
+
| 17 | channel_group_master |
|
|
127
|
+
| 18 | dsar_type_master |
|
|
128
|
+
|
|
129
|
+
**เงื่อนไขเพิ่มเติม:**
|
|
130
|
+
|
|
131
|
+
- ตาราง **data_type_master**: ถ้าไม่มีแถวจาก asset ใน target จะ insert ข้อมูลจาก asset ก่อน แล้วใช้ `data_type_id` ที่มีอยู่ทั้งหมดใน target ในการกรอง/อ้างอิง (เพราะมีข้อมูล FK ที่ไม่มีอยู่จริงในระบบ)
|
|
132
|
+
- ตาราง **rop_type_master**: ทำแบบเดียวกัน insert จาก asset ถ้ายังไม่มี, ใช้ `rop_type_id` ใน target ในการกรอง (เพราะมีข้อมูล FK ที่ไม่มีอยู่จริงในระบบ)
|
|
133
|
+
- หลังโอนครบทุกตารางจะมีการ **validate** จำนวนแถว source vs target
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Section 1 (`section-1`) — Core Data
|
|
138
|
+
|
|
139
|
+
**วิธีโอน:** ใช้ `copyDataTables` (โอนตาม PK, รันซ้ำ insert เฉพาะแถวใหม่) + จัดการ `created_by`/`updated_by`
|
|
140
|
+
- **permissions**: โอนจาก source ตามตารางอื่น; การ **เติม/อัปเดต permissions ให้ครบ** ทำแยกด้วย `npm run seed:permissions` (ใช้ข้อมูลจาก `src/assets/data/permissions.ts`)
|
|
141
|
+
|
|
142
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
143
|
+
|
|
144
|
+
| ลำดับ | ชื่อตาราง |
|
|
145
|
+
|-------|------------|
|
|
146
|
+
| 1 | company_master |
|
|
147
|
+
| 2 | organizations |
|
|
148
|
+
| 3 | systemlangaue |
|
|
149
|
+
| 4 | users |
|
|
150
|
+
| 5 | theme |
|
|
151
|
+
| 6 | roles |
|
|
152
|
+
| 7 | model_has_roles |
|
|
153
|
+
| 8 | permissions |
|
|
154
|
+
| 9 | role_has_permissions |
|
|
155
|
+
| 10 | oauth_clients |
|
|
156
|
+
|
|
157
|
+
**เงื่อนไขเพิ่มเติม:**
|
|
158
|
+
|
|
159
|
+
- **organizations**, **systemlangaue**: อยู่ก่อน `users` จึง insert ด้วย **created_by / updated_by = null** ก่อน แล้วหลัง copy `users` จะ **คืนค่า created_by / updated_by** จาก source ไปอัปเดตใน target (`restoreUserRefsInTable`)
|
|
160
|
+
- **permissions**: รัน `npm run seed:permissions` แยกเพื่อ seed/อัปเดตจาก `src/assets/data/permissions.ts` (unique key `name`; มีใน target แล้วจะ skip)
|
|
161
|
+
- หลังโอนครบจะ **validate** จำนวนแถวของตารางใน section นี้
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### Section 2 (`section-2`)
|
|
166
|
+
|
|
167
|
+
**วิธีโอน:** ใช้ `copyDataTables` (รันซ้ำ insert เฉพาะแถวใหม่)
|
|
168
|
+
|
|
169
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
170
|
+
|
|
171
|
+
| ลำดับ | ชื่อตาราง |
|
|
172
|
+
|-------|------------|
|
|
173
|
+
| 1 | owner_master |
|
|
174
|
+
| 2 | activity_master |
|
|
175
|
+
| 3 | activity_owner_ref_master |
|
|
176
|
+
| 4 | storage_asset_master |
|
|
177
|
+
| 5 | report_preferences |
|
|
178
|
+
| 6 | rop_header |
|
|
179
|
+
| 7 | rop_answer |
|
|
180
|
+
| 8 | rop_gap_results |
|
|
181
|
+
| 9 | rop_activity_advisory_topics |
|
|
182
|
+
| 10 | rop_activity_advisory_comments |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### Section 3 (`section-3`) — Consent
|
|
187
|
+
|
|
188
|
+
**วิธีโอน:** ใช้ `copyDataTables` พร้อม **columnMapping** บางตาราง
|
|
189
|
+
|
|
190
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
191
|
+
|
|
192
|
+
| ลำดับ | ชื่อตาราง |
|
|
193
|
+
|-------|------------|
|
|
194
|
+
| 1 | cs_consent_type |
|
|
195
|
+
| 2 | cs_consent_send_template |
|
|
196
|
+
| 3 | thank_consent_msg |
|
|
197
|
+
| 4 | cs_consent_send_template_form |
|
|
198
|
+
| 5 | cs_consent_form_client |
|
|
199
|
+
| 6 | cs_consent_form_result |
|
|
200
|
+
| 7 | cs_consent_form_personal |
|
|
201
|
+
|
|
202
|
+
**เงื่อนไขเพิ่มเติม:**
|
|
203
|
+
|
|
204
|
+
- **cs_consent_form_client**: ใช้ **columnMapping** — คอลัมน์ `updated_at` ใน target ใช้ค่าจากคอลัมน์ `created_at` ของ source เนื่องจากตารางใหม่ updated_at ถูกระบุว่าห้ามเป็นค่าว่าง
|
|
205
|
+
- หลังโอนครบจะ validate จำนวนแถว
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Section 4 (`section-4`) — DSAR
|
|
210
|
+
|
|
211
|
+
**วิธีโอน:** ใช้ `copyDataTables` (รันซ้ำ insert เฉพาะแถวใหม่)
|
|
212
|
+
|
|
213
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
214
|
+
|
|
215
|
+
| ลำดับ | ชื่อตาราง |
|
|
216
|
+
|-------|------------|
|
|
217
|
+
| 1 | dsar_setting |
|
|
218
|
+
| 2 | dsar_setting_users_pivot |
|
|
219
|
+
| 3 | dsar_form |
|
|
220
|
+
| 4 | dsar_req |
|
|
221
|
+
| 5 | dsar_req_log |
|
|
222
|
+
| 6 | dsar_req_case_access_data |
|
|
223
|
+
| 7 | dsar_req_case_access_data_dtl |
|
|
224
|
+
| 8 | dsar_req_case_del |
|
|
225
|
+
| 9 | dsar_req_case_del_dtl |
|
|
226
|
+
| 10 | dsar_managements |
|
|
227
|
+
| 11 | dsar_req_case_consent |
|
|
228
|
+
| 12 | dsar_req_case_consent_dtl |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### Section 5 (`section-5`) — Incident
|
|
233
|
+
|
|
234
|
+
**วิธีโอน:** ใช้ `copyDataTables` (รันซ้ำ insert เฉพาะแถวใหม่)
|
|
235
|
+
|
|
236
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
237
|
+
|
|
238
|
+
| ลำดับ | ชื่อตาราง |
|
|
239
|
+
|-------|------------|
|
|
240
|
+
| 1 | incident_form |
|
|
241
|
+
| 2 | incodent_req |
|
|
242
|
+
| 3 | incodent_req_log |
|
|
243
|
+
| 4 | incident_estimate |
|
|
244
|
+
| 5 | incident_estimate_log |
|
|
245
|
+
| 6 | incident_agency_personal |
|
|
246
|
+
| 7 | agency_users_pivot |
|
|
247
|
+
| 8 | incident_with_person |
|
|
248
|
+
| 9 | incident_with_person_log |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Section 6 (`section-6`)
|
|
253
|
+
|
|
254
|
+
**วิธีโอน:** ใช้ `copyDataTables` (รันซ้ำ insert เฉพาะแถวใหม่)
|
|
255
|
+
|
|
256
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
257
|
+
|
|
258
|
+
| ลำดับ | ชื่อตาราง |
|
|
259
|
+
|-------|------------|
|
|
260
|
+
| 1 | pdpa_message_history |
|
|
261
|
+
| 2 | pdpa_file_attach |
|
|
262
|
+
| 3 | cs_consent_form |
|
|
263
|
+
| 4 | cs_consent_form_content |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### Section 7.1 (`section-7-1`)
|
|
268
|
+
|
|
269
|
+
**วิธีโอน:** ใช้ `copyTableMaster` (insert เฉพาะแถวที่ PK ยังไม่มีใน target)
|
|
270
|
+
|
|
271
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
272
|
+
|
|
273
|
+
| ลำดับ | ชื่อตาราง |
|
|
274
|
+
|-------|------------|
|
|
275
|
+
| 1 | ck_type_master |
|
|
276
|
+
| 2 | consent_ck_scan |
|
|
277
|
+
| 3 | consent_ck_scan_dtl |
|
|
278
|
+
| 4 | ck_consent_form |
|
|
279
|
+
| 5 | cs_consent_form_dtl |
|
|
280
|
+
| 6 | ck_ref_master |
|
|
281
|
+
|
|
282
|
+
**หมายเหตุ:** ตาราง `ck_ref_master` มีข้อมูล FK ที่ไม่มีอยู่จริงในระบบต้นทาง จึงเข้าเงื่อนไขเดียวกันกับของ data_type_master ใน section-master-data
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### Section 7.2 (`section-7-2`)
|
|
287
|
+
|
|
288
|
+
**วิธีโอน:** ใช้ `copyDataTables` (รันซ้ำ insert เฉพาะแถวใหม่)
|
|
289
|
+
|
|
290
|
+
**ตารางที่ insert (ตามลำดับ):**
|
|
291
|
+
access_master, access_assign_group_user, dsar_type_master, dsar_req_case_del_dtl_log, technical_measures_master, storage_asset_technical_measures, telescope_entries, telescope_entries_tags, cs_consent_timeout, migrations, oauth_refresh_tokens, subscriptions, tbcookielog, failed_jobs, storage_asset_databackup_location, subscribables, user_assign_role, access_assign_user, incident_type_master, notifications, prog_group_master, versions, dsar_incident_doc_status_master, oauth_access_tokens, otp, storage_asset_location_master, user_preference, job_batches, organization_measures_master, dsar_req_case_consent_dtl_log, dsar_req_case_consent_log, incident_req_risk_management, prog_master, new_licenses, group_menu_authority, group_menu_master, chanel_master, risk_master, tbonchangecookielog, dsar_req_case_del_log, tbonfirstactioncookielog, agency_tr_master, source_asset_master, activity_log
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## 4. สรุปเงื่อนไขเฉพาะของแต่ละ Section
|
|
296
|
+
|
|
297
|
+
| Section | เงื่อนไขเพิ่มเติม |
|
|
298
|
+
|---------|-------------------|
|
|
299
|
+
| **master-data** | ใช้ `copyTableMaster`; data_type_master / rop_type_master มีการ insert จาก asset ถ้ายังไม่มีใน target |
|
|
300
|
+
| **section-1** | organizations, systemlangaue insert ด้วย created_by/updated_by = null แล้วคืนค่าหลัง copy users; permissions เติม/อัปเดตแยกด้วย `npm run seed:permissions` (จาก assets/data/permissions.ts) |
|
|
301
|
+
| **section-3** | cs_consent_form_client: columnMapping updated_at ← created_at (จาก source) |
|
|
302
|
+
| **section-6** | cs_consent_form และ cs_consent_form_content ย้ายมาจากรอบ section-3 |
|
|
303
|
+
| **section-7-1** | ใช้ copyTableMaster; ck_ref_master อาจมี FK ที่ไม่มีอยู่จริง |
|
|
304
|
+
| **section-7-2** | ใช้ copyDataTables |
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## 5. การตั้งค่าโอนข้อมูล
|
|
309
|
+
|
|
310
|
+
- **Batch size / Page size**: กำหนดใน `.env` หรือ `src/config/transfer.config.ts` (เช่น `TRANSFER_BATCH_SIZE`, `TRANSFER_PAGE_SIZE`)
|
|
311
|
+
- ตารางที่มีคอลัมน์ LONGTEXT หรือข้อมูลต่อแถวใหญ่ แนะนำให้ลดค่า (เช่น 50–100) เพื่อไม่ให้เกิน `max_allowed_packet` และลดโอกาสข้อมูลผิดพลาด
|
|
312
|
+
- **Database**: กำหนด connection ต้นทางและปลายทางใน `.env` และใช้ใน `src/config/db.source.js` / `src/config/db.target.js`
|
|
313
|
+
- **ลำดับ/รายการตารางต่อ section**: แก้ใน `src/config/sections.config.ts`
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
*เอกสารนี้อ้างอิงจากโครงสร้างและ config ในโปรเจกต์ ณ เวลาที่เขียน*
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { copyDataTables, restoreUserRefsInTable } from "./script.js";
|
|
2
|
+
export type { ConnectionPool, CopyDataTablesResult, RestoreUserRefsResult, RestoreUserRefsTableOption, TableTransferResult, TransferOptions, ValidateTableResult, } from "./types.js";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transfer-data-sdk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,eAAe,EACf,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.restoreUserRefsInTable = exports.copyDataTables = void 0;
|
|
4
|
+
var script_js_1 = require("./script.js");
|
|
5
|
+
Object.defineProperty(exports, "copyDataTables", { enumerable: true, get: function () { return script_js_1.copyDataTables; } });
|
|
6
|
+
Object.defineProperty(exports, "restoreUserRefsInTable", { enumerable: true, get: function () { return script_js_1.restoreUserRefsInTable; } });
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transfer-data-sdk/index.ts"],"names":[],"mappings":";;;AAAA,yCAAqE;AAA5D,2GAAA,cAAc,OAAA;AAAE,mHAAA,sBAAsB,OAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Pool, PoolConnection } from "mysql2/promise";
|
|
2
|
+
import type { ConnectionPool, CopyDataTablesResult, TransferOptions } from "./types.js";
|
|
3
|
+
export declare function toBindValue(v: unknown): string | number | boolean | null | Buffer;
|
|
4
|
+
export declare function getPrimaryKeyColumns(pool: Pool, tableName: string): Promise<string[]>;
|
|
5
|
+
export declare function fetchExistingPkSetInTarget(targetConn: Pool | PoolConnection, tableName: string, pkColumns: string[], rows: Record<string, unknown>[]): Promise<Set<string>>;
|
|
6
|
+
export declare function restoreUserRefsInTable(sourcePool: Pool, targetPool: Pool, tableName: string, options?: {
|
|
7
|
+
pkColumn?: string;
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
}): Promise<{
|
|
10
|
+
rowsUpdated: number;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function copyDataTables(connectionPool: ConnectionPool, params: TransferOptions): Promise<CopyDataTablesResult>;
|
|
13
|
+
//# sourceMappingURL=script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../src/transfer-data-sdk/script.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EAKpB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAmBpB,wBAAgB,WAAW,CACzB,CAAC,EAAE,OAAO,GACT,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAQ3C;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CAUnB;AAqDD,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,IAAI,GAAG,cAAc,EACjC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC9B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAsCtB;AAED,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,IAAI,EAChB,UAAU,EAAE,IAAI,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CA0ElC;AAgYD,wBAAsB,cAAc,CAClC,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,oBAAoB,CAAC,CAkC/B"}
|
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toBindValue = toBindValue;
|
|
4
|
+
exports.getPrimaryKeyColumns = getPrimaryKeyColumns;
|
|
5
|
+
exports.fetchExistingPkSetInTarget = fetchExistingPkSetInTarget;
|
|
6
|
+
exports.restoreUserRefsInTable = restoreUserRefsInTable;
|
|
7
|
+
exports.copyDataTables = copyDataTables;
|
|
8
|
+
const DEFAULT_PAGE_SIZE = 500;
|
|
9
|
+
const DEFAULT_BATCH_SIZE = 500;
|
|
10
|
+
function escapeId(name) {
|
|
11
|
+
return "`" + String(name).replace(/`/g, "``") + "`";
|
|
12
|
+
}
|
|
13
|
+
function formatDateForMysql(d) {
|
|
14
|
+
const y = d.getFullYear();
|
|
15
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
16
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
17
|
+
const h = String(d.getHours()).padStart(2, "0");
|
|
18
|
+
const min = String(d.getMinutes()).padStart(2, "0");
|
|
19
|
+
const s = String(d.getSeconds()).padStart(2, "0");
|
|
20
|
+
return `${y}-${m}-${day} ${h}:${min}:${s}`;
|
|
21
|
+
}
|
|
22
|
+
function toBindValue(v) {
|
|
23
|
+
if (v === undefined || v === null)
|
|
24
|
+
return null;
|
|
25
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
26
|
+
return v;
|
|
27
|
+
if (typeof v === "string")
|
|
28
|
+
return v;
|
|
29
|
+
if (Buffer.isBuffer(v))
|
|
30
|
+
return v;
|
|
31
|
+
if (v instanceof Date)
|
|
32
|
+
return formatDateForMysql(v);
|
|
33
|
+
if (typeof v === "object")
|
|
34
|
+
return JSON.stringify(v);
|
|
35
|
+
return String(v);
|
|
36
|
+
}
|
|
37
|
+
async function getPrimaryKeyColumns(pool, tableName) {
|
|
38
|
+
const [rows] = await pool.query(`SELECT COLUMN_NAME
|
|
39
|
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
40
|
+
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND CONSTRAINT_NAME = 'PRIMARY'
|
|
41
|
+
ORDER BY ORDINAL_POSITION`, [tableName]);
|
|
42
|
+
const list = (Array.isArray(rows) ? rows : []);
|
|
43
|
+
return list.map((r) => r.COLUMN_NAME);
|
|
44
|
+
}
|
|
45
|
+
function makePkKey(pkColumns, row) {
|
|
46
|
+
return pkColumns.map((c) => String(row[c] ?? "")).join("\x00");
|
|
47
|
+
}
|
|
48
|
+
function normalizeForCompare(v) {
|
|
49
|
+
if (v === null || v === undefined)
|
|
50
|
+
return "";
|
|
51
|
+
if (v instanceof Date)
|
|
52
|
+
return v.toISOString().slice(0, 19).replace("T", " ");
|
|
53
|
+
if (Buffer.isBuffer(v))
|
|
54
|
+
return v.toString("hex");
|
|
55
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
56
|
+
return String(v);
|
|
57
|
+
if (typeof v === "string")
|
|
58
|
+
return v;
|
|
59
|
+
if (typeof v === "object")
|
|
60
|
+
return JSON.stringify(v);
|
|
61
|
+
return String(v);
|
|
62
|
+
}
|
|
63
|
+
function formatPkForLog(pkColumns, row) {
|
|
64
|
+
return pkColumns.map((c) => `${c}=${row[c]}`).join(", ");
|
|
65
|
+
}
|
|
66
|
+
function normalizeTableNames(params) {
|
|
67
|
+
const rawTableNames = params.tableNames ?? params.tablesName;
|
|
68
|
+
if (!rawTableNames) {
|
|
69
|
+
throw new Error("tableNames is required");
|
|
70
|
+
}
|
|
71
|
+
const list = Array.isArray(rawTableNames) ? rawTableNames : [rawTableNames];
|
|
72
|
+
const normalized = list.map((name) => String(name).trim()).filter(Boolean);
|
|
73
|
+
if (normalized.length === 0) {
|
|
74
|
+
throw new Error("tableNames must include at least one table");
|
|
75
|
+
}
|
|
76
|
+
return normalized;
|
|
77
|
+
}
|
|
78
|
+
function applySetDataOptions(tableName, row, setDataOptions) {
|
|
79
|
+
const tableOverrides = setDataOptions.filter((option) => option.tableName === tableName);
|
|
80
|
+
if (tableOverrides.length === 0)
|
|
81
|
+
return row;
|
|
82
|
+
const next = { ...row };
|
|
83
|
+
for (const option of tableOverrides) {
|
|
84
|
+
next[option.columnName] = option.value;
|
|
85
|
+
}
|
|
86
|
+
return next;
|
|
87
|
+
}
|
|
88
|
+
async function fetchExistingPkSetInTarget(targetConn, tableName, pkColumns, rows) {
|
|
89
|
+
if (pkColumns.length === 0 || rows.length === 0)
|
|
90
|
+
return new Set();
|
|
91
|
+
const safeTable = escapeId(tableName);
|
|
92
|
+
if (pkColumns.length === 1) {
|
|
93
|
+
const pkCol = pkColumns[0];
|
|
94
|
+
const pkValues = rows.map((row) => row[pkCol]);
|
|
95
|
+
const placeholders = pkValues.map(() => "?").join(", ");
|
|
96
|
+
const [targetRows] = await targetConn.execute(`SELECT ${escapeId(pkCol)} FROM ${safeTable} WHERE ${escapeId(pkCol)} IN (${placeholders})`, pkValues);
|
|
97
|
+
const list = (Array.isArray(targetRows) ? targetRows : []);
|
|
98
|
+
return new Set(list.map((row) => makePkKey(pkColumns, row)));
|
|
99
|
+
}
|
|
100
|
+
const pkEscaped = pkColumns.map(escapeId).join(", ");
|
|
101
|
+
const tuplePlaceholders = rows
|
|
102
|
+
.map(() => "(" + pkColumns.map(() => "?").join(", ") + ")")
|
|
103
|
+
.join(", ");
|
|
104
|
+
const params = [];
|
|
105
|
+
for (const row of rows) {
|
|
106
|
+
for (const column of pkColumns)
|
|
107
|
+
params.push(row[column]);
|
|
108
|
+
}
|
|
109
|
+
const [targetRows] = await targetConn.execute(`SELECT ${pkEscaped} FROM ${safeTable} WHERE (${pkEscaped}) IN (${tuplePlaceholders})`, params);
|
|
110
|
+
const list = (Array.isArray(targetRows) ? targetRows : []);
|
|
111
|
+
return new Set(list.map((row) => makePkKey(pkColumns, row)));
|
|
112
|
+
}
|
|
113
|
+
async function restoreUserRefsInTable(sourcePool, targetPool, tableName, options) {
|
|
114
|
+
const safeTable = escapeId(tableName);
|
|
115
|
+
const [countResult] = await targetPool.query(`SELECT COUNT(*) AS cnt FROM ${safeTable} WHERE created_by IS NULL`);
|
|
116
|
+
const countRows = Array.isArray(countResult) ? countResult : [];
|
|
117
|
+
const first = countRows[0];
|
|
118
|
+
const count = Number(first?.cnt ?? 0);
|
|
119
|
+
if (count === 0)
|
|
120
|
+
return { rowsUpdated: 0 };
|
|
121
|
+
const pkColumns = options?.pkColumn != null
|
|
122
|
+
? [options.pkColumn]
|
|
123
|
+
: await getPrimaryKeyColumns(sourcePool, tableName);
|
|
124
|
+
if (pkColumns.length === 0) {
|
|
125
|
+
throw new Error(`No primary key found for table: ${tableName}`);
|
|
126
|
+
}
|
|
127
|
+
const pkSelect = pkColumns.map((column) => escapeId(column)).join(", ");
|
|
128
|
+
const [rows] = await sourcePool.query(`SELECT ${pkSelect}, created_by, updated_by FROM ${safeTable}`);
|
|
129
|
+
const list = (Array.isArray(rows) ? rows : []);
|
|
130
|
+
if (list.length === 0)
|
|
131
|
+
return { rowsUpdated: 0 };
|
|
132
|
+
const whereClause = pkColumns
|
|
133
|
+
.map((column) => `${escapeId(column)} = ?`)
|
|
134
|
+
.join(" AND ");
|
|
135
|
+
const updateSql = `UPDATE ${safeTable} SET created_by = ?, updated_by = ? WHERE ${whereClause}`;
|
|
136
|
+
const batch = Math.max(1, Number(options?.batchSize ?? 100));
|
|
137
|
+
const isSinglePk = pkColumns.length === 1;
|
|
138
|
+
const pkCol = pkColumns[0];
|
|
139
|
+
const conn = await targetPool.getConnection();
|
|
140
|
+
try {
|
|
141
|
+
await conn.beginTransaction();
|
|
142
|
+
let totalUpdated = 0;
|
|
143
|
+
if (isSinglePk) {
|
|
144
|
+
for (let i = 0; i < list.length; i += batch) {
|
|
145
|
+
const chunk = list.slice(i, i + batch);
|
|
146
|
+
const pkList = chunk.map((r) => r[pkCol]);
|
|
147
|
+
const createdByCases = chunk.map(() => "WHEN ? THEN ?").join(" ");
|
|
148
|
+
const updatedByCases = chunk.map(() => "WHEN ? THEN ?").join(" ");
|
|
149
|
+
const inList = chunk.map(() => "?").join(",");
|
|
150
|
+
const sql = `UPDATE ${safeTable} SET created_by = CASE ${escapeId(pkCol)} ${createdByCases} END, updated_by = CASE ${escapeId(pkCol)} ${updatedByCases} END WHERE ${escapeId(pkCol)} IN (${inList})`;
|
|
151
|
+
const params = [];
|
|
152
|
+
for (const r of chunk)
|
|
153
|
+
params.push(r[pkCol], r.created_by ?? null);
|
|
154
|
+
for (const r of chunk)
|
|
155
|
+
params.push(r[pkCol], r.updated_by ?? null);
|
|
156
|
+
params.push(...pkList);
|
|
157
|
+
await conn.execute(sql, params);
|
|
158
|
+
totalUpdated += chunk.length;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
for (const row of list) {
|
|
163
|
+
await conn.execute(updateSql, [
|
|
164
|
+
row.created_by ?? null,
|
|
165
|
+
row.updated_by ?? null,
|
|
166
|
+
...pkColumns.map((column) => row[column]),
|
|
167
|
+
]);
|
|
168
|
+
totalUpdated += 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
await conn.commit();
|
|
172
|
+
return { rowsUpdated: totalUpdated };
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
await conn.rollback();
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
conn.release();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function runRestoreUserRefs(sourcePool, targetPool, restoreOptions) {
|
|
183
|
+
const results = [];
|
|
184
|
+
for (const option of restoreOptions) {
|
|
185
|
+
const { rowsUpdated } = await restoreUserRefsInTable(sourcePool, targetPool, option.tableName, { pkColumn: option.pkColumn, batchSize: option.batchSize });
|
|
186
|
+
results.push({ tableName: option.tableName, rowsUpdated });
|
|
187
|
+
}
|
|
188
|
+
return results;
|
|
189
|
+
}
|
|
190
|
+
async function fetchTargetRowsByPk(targetPool, tableName, pkColumns, sourceRows) {
|
|
191
|
+
const safeTable = escapeId(tableName);
|
|
192
|
+
const result = new Map();
|
|
193
|
+
if (sourceRows.length === 0)
|
|
194
|
+
return result;
|
|
195
|
+
if (pkColumns.length === 1) {
|
|
196
|
+
const pkCol = pkColumns[0];
|
|
197
|
+
const pkValues = sourceRows.map((row) => row[pkCol]);
|
|
198
|
+
const placeholders = pkValues.map(() => "?").join(", ");
|
|
199
|
+
const [rows] = await targetPool.execute(`SELECT * FROM ${safeTable} WHERE ${escapeId(pkCol)} IN (${placeholders})`, pkValues);
|
|
200
|
+
const list = (Array.isArray(rows) ? rows : []);
|
|
201
|
+
for (const row of list) {
|
|
202
|
+
result.set(String(row[pkCol] ?? ""), row);
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
const pkEscaped = pkColumns.map(escapeId).join(", ");
|
|
207
|
+
const tuplePlaceholders = sourceRows
|
|
208
|
+
.map(() => "(" + pkColumns.map(() => "?").join(", ") + ")")
|
|
209
|
+
.join(", ");
|
|
210
|
+
const params = [];
|
|
211
|
+
for (const row of sourceRows) {
|
|
212
|
+
for (const column of pkColumns) {
|
|
213
|
+
params.push(row[column]);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const [rows] = await targetPool.execute(`SELECT * FROM ${safeTable} WHERE (${pkEscaped}) IN (${tuplePlaceholders})`, params);
|
|
217
|
+
const list = (Array.isArray(rows) ? rows : []);
|
|
218
|
+
for (const row of list) {
|
|
219
|
+
result.set(makePkKey(pkColumns, row), row);
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
async function validateOneTable(sourcePool, targetPool, tableName, pageSize, batchSize, mode) {
|
|
224
|
+
const safeTable = escapeId(tableName);
|
|
225
|
+
const pkColumns = await getPrimaryKeyColumns(sourcePool, tableName);
|
|
226
|
+
if (pkColumns.length === 0)
|
|
227
|
+
return null;
|
|
228
|
+
const pkOrderBy = pkColumns.map((c) => `${escapeId(c)} ASC`).join(", ");
|
|
229
|
+
const pkWhereCols = pkColumns.map((c) => escapeId(c)).join(", ");
|
|
230
|
+
let lastCursor = null;
|
|
231
|
+
let totalChecked = 0;
|
|
232
|
+
let mismatchCount = 0;
|
|
233
|
+
let insertedCount = 0;
|
|
234
|
+
let updatedCount = 0;
|
|
235
|
+
const toInsert = [];
|
|
236
|
+
const toUpdate = [];
|
|
237
|
+
while (true) {
|
|
238
|
+
let sourceRows;
|
|
239
|
+
if (lastCursor === null) {
|
|
240
|
+
const [raw] = await sourcePool.execute(`SELECT * FROM ${safeTable} ORDER BY ${pkOrderBy} LIMIT ?`, [pageSize]);
|
|
241
|
+
sourceRows = (Array.isArray(raw) ? raw : []);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
const placeholders = pkColumns.map(() => "?").join(", ");
|
|
245
|
+
const [raw] = await sourcePool.execute(`SELECT * FROM ${safeTable} WHERE (${pkWhereCols}) > (${placeholders}) ORDER BY ${pkOrderBy} LIMIT ?`, [...lastCursor, pageSize]);
|
|
246
|
+
sourceRows = (Array.isArray(raw) ? raw : []);
|
|
247
|
+
}
|
|
248
|
+
if (sourceRows.length === 0)
|
|
249
|
+
break;
|
|
250
|
+
const columns = Object.keys(sourceRows[0]);
|
|
251
|
+
const targetByPk = await fetchTargetRowsByPk(targetPool, tableName, pkColumns, sourceRows);
|
|
252
|
+
for (const sourceRow of sourceRows) {
|
|
253
|
+
const pkKey = makePkKey(pkColumns, sourceRow);
|
|
254
|
+
const targetRow = targetByPk.get(pkKey);
|
|
255
|
+
const pkLog = formatPkForLog(pkColumns, sourceRow);
|
|
256
|
+
if (!targetRow) {
|
|
257
|
+
mismatchCount += 1;
|
|
258
|
+
console.log(`[validation] ตาราง "${tableName}" ไอดี (${pkLog}) ไม่พบใน target`);
|
|
259
|
+
if (mode === "validate-and-update")
|
|
260
|
+
toInsert.push(sourceRow);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const diffColumns = [];
|
|
264
|
+
for (const col of columns) {
|
|
265
|
+
if (normalizeForCompare(sourceRow[col]) !== normalizeForCompare(targetRow[col])) {
|
|
266
|
+
diffColumns.push(col);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (diffColumns.length > 0) {
|
|
270
|
+
mismatchCount += 1;
|
|
271
|
+
console.log(`[validation] ตาราง "${tableName}" ไอดี (${pkLog}) ข้อมูลไม่ตรงกัน — คอลัมน์: ${diffColumns.join(", ")}`);
|
|
272
|
+
for (const col of diffColumns) {
|
|
273
|
+
console.log(` - ${col}: source=${JSON.stringify(sourceRow[col])} | target=${JSON.stringify(targetRow[col])}`);
|
|
274
|
+
}
|
|
275
|
+
if (mode === "validate-and-update") {
|
|
276
|
+
toUpdate.push({ sourceRow, diffColumns });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
totalChecked += sourceRows.length;
|
|
281
|
+
const lastRow = sourceRows[sourceRows.length - 1];
|
|
282
|
+
lastCursor = pkColumns.map((c) => lastRow[c]);
|
|
283
|
+
if (sourceRows.length < pageSize)
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
if (mode === "validate-and-update" && (toInsert.length > 0 || toUpdate.length > 0)) {
|
|
287
|
+
const conn = await targetPool.getConnection();
|
|
288
|
+
const columns = toInsert.length > 0
|
|
289
|
+
? Object.keys(toInsert[0])
|
|
290
|
+
: Object.keys(toUpdate[0].sourceRow);
|
|
291
|
+
try {
|
|
292
|
+
await conn.beginTransaction();
|
|
293
|
+
const colsEscaped = columns.map((c) => escapeId(c)).join(", ");
|
|
294
|
+
const placeholders = columns.map(() => "?").join(", ");
|
|
295
|
+
const insertSql = `INSERT INTO ${safeTable} (${colsEscaped}) VALUES (${placeholders})`;
|
|
296
|
+
for (let i = 0; i < toInsert.length; i += batchSize) {
|
|
297
|
+
const batch = toInsert.slice(i, i + batchSize);
|
|
298
|
+
for (const row of batch) {
|
|
299
|
+
const values = columns.map((column) => toBindValue(row[column]));
|
|
300
|
+
await conn.execute(insertSql, values);
|
|
301
|
+
insertedCount += 1;
|
|
302
|
+
console.log(`[update] ตาราง "${tableName}" INSERT แถว PK (${formatPkForLog(pkColumns, row)})`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const setClause = columns.map((column) => `${escapeId(column)} = ?`).join(", ");
|
|
306
|
+
const wherePk = pkColumns.map((column) => `${escapeId(column)} = ?`).join(" AND ");
|
|
307
|
+
const updateSql = `UPDATE ${safeTable} SET ${setClause} WHERE ${wherePk}`;
|
|
308
|
+
for (const { sourceRow } of toUpdate) {
|
|
309
|
+
const values = columns.map((column) => toBindValue(sourceRow[column]));
|
|
310
|
+
const whereValues = pkColumns.map((column) => toBindValue(sourceRow[column]));
|
|
311
|
+
await conn.execute(updateSql, [...values, ...whereValues]);
|
|
312
|
+
updatedCount += 1;
|
|
313
|
+
console.log(`[update] ตาราง "${tableName}" UPDATE แถว PK (${formatPkForLog(pkColumns, sourceRow)})`);
|
|
314
|
+
}
|
|
315
|
+
await conn.commit();
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
await conn.rollback();
|
|
319
|
+
throw err;
|
|
320
|
+
}
|
|
321
|
+
finally {
|
|
322
|
+
conn.release();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
console.log(`[validation] ตาราง "${tableName}" ตรวจแล้ว ${totalChecked} แถว, ไม่ตรงกัน ${mismatchCount} แถว`);
|
|
326
|
+
return { tableName, totalChecked, mismatchCount, insertedCount, updatedCount };
|
|
327
|
+
}
|
|
328
|
+
async function runValidation(sourcePool, targetPool, tableNames, params) {
|
|
329
|
+
const pageSize = Math.max(1, Number(params.options?.pageSize) || DEFAULT_PAGE_SIZE);
|
|
330
|
+
const batchSize = Math.max(1, Number(params.options?.batchSize) || DEFAULT_BATCH_SIZE);
|
|
331
|
+
const mode = params.validateAndUpdate ? "validate-and-update" : "validate";
|
|
332
|
+
const results = [];
|
|
333
|
+
for (const tableName of tableNames) {
|
|
334
|
+
const result = await validateOneTable(sourcePool, targetPool, tableName, pageSize, batchSize, mode);
|
|
335
|
+
if (result)
|
|
336
|
+
results.push(result);
|
|
337
|
+
}
|
|
338
|
+
return results;
|
|
339
|
+
}
|
|
340
|
+
async function transferSingleTable(sourcePool, targetPool, tableName, params) {
|
|
341
|
+
const safeTableName = escapeId(tableName);
|
|
342
|
+
const pageSizeVal = Math.max(1, Number(params.options?.pageSize) || DEFAULT_PAGE_SIZE);
|
|
343
|
+
const batchSizeVal = Math.max(1, Number(params.options?.batchSize) || DEFAULT_BATCH_SIZE);
|
|
344
|
+
let rowsTransferred = 0;
|
|
345
|
+
let columnList = [];
|
|
346
|
+
let lastCursor = null;
|
|
347
|
+
const setDataOptions = params.setDataOptions ?? [];
|
|
348
|
+
const pkColumns = await getPrimaryKeyColumns(sourcePool, tableName);
|
|
349
|
+
const queryRunner = await targetPool.getConnection();
|
|
350
|
+
try {
|
|
351
|
+
await queryRunner.beginTransaction();
|
|
352
|
+
if (pkColumns.length === 0) {
|
|
353
|
+
const [existing] = await queryRunner.execute(`SELECT 1 FROM ${safeTableName} LIMIT 1`);
|
|
354
|
+
if (Array.isArray(existing) && existing.length > 0) {
|
|
355
|
+
await queryRunner.execute(`DELETE FROM ${safeTableName}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
while (true) {
|
|
359
|
+
let dataRows;
|
|
360
|
+
if (pkColumns.length > 0) {
|
|
361
|
+
const pkOrderBy = pkColumns
|
|
362
|
+
.map((column) => `${escapeId(column)} ASC`)
|
|
363
|
+
.join(", ");
|
|
364
|
+
const pkWhereCols = pkColumns
|
|
365
|
+
.map((column) => escapeId(column))
|
|
366
|
+
.join(", ");
|
|
367
|
+
if (lastCursor === null) {
|
|
368
|
+
const [rawDataRows] = await sourcePool.execute(`SELECT * FROM ${safeTableName} ORDER BY ${pkOrderBy} LIMIT ?`, [pageSizeVal]);
|
|
369
|
+
dataRows = (Array.isArray(rawDataRows) ? rawDataRows : []);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
const placeholders = pkColumns.map(() => "?").join(", ");
|
|
373
|
+
const [rawDataRows] = await sourcePool.execute(`SELECT * FROM ${safeTableName} WHERE (${pkWhereCols}) > (${placeholders}) ORDER BY ${pkOrderBy} LIMIT ?`, [...lastCursor, pageSizeVal]);
|
|
374
|
+
dataRows = (Array.isArray(rawDataRows) ? rawDataRows : []);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
const [rawDataRows] = await sourcePool.execute(`SELECT * FROM ${safeTableName} LIMIT ? OFFSET ?`, [pageSizeVal, rowsTransferred]);
|
|
379
|
+
dataRows = (Array.isArray(rawDataRows) ? rawDataRows : []);
|
|
380
|
+
}
|
|
381
|
+
if (dataRows.length === 0)
|
|
382
|
+
break;
|
|
383
|
+
if (columnList.length === 0)
|
|
384
|
+
columnList = Object.keys(dataRows[0]);
|
|
385
|
+
if (pkColumns.length > 0) {
|
|
386
|
+
const lastRow = dataRows[dataRows.length - 1];
|
|
387
|
+
lastCursor = pkColumns.map((column) => lastRow[column]);
|
|
388
|
+
}
|
|
389
|
+
const existingPkSet = pkColumns.length > 0
|
|
390
|
+
? await fetchExistingPkSetInTarget(queryRunner, tableName, pkColumns, dataRows)
|
|
391
|
+
: new Set();
|
|
392
|
+
const newRows = pkColumns.length > 0
|
|
393
|
+
? dataRows.filter((row) => !existingPkSet.has(makePkKey(pkColumns, row)))
|
|
394
|
+
: dataRows;
|
|
395
|
+
for (let start = 0; start < newRows.length; start += batchSizeVal) {
|
|
396
|
+
const batch = newRows.slice(start, start + batchSizeVal);
|
|
397
|
+
if (batch.length === 0)
|
|
398
|
+
continue;
|
|
399
|
+
const values = [];
|
|
400
|
+
for (const row of batch) {
|
|
401
|
+
const data = applySetDataOptions(tableName, { ...row }, setDataOptions);
|
|
402
|
+
for (const column of columnList) {
|
|
403
|
+
values.push(toBindValue(data[column]));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const oneRowPl = "(" + columnList.map(() => "?").join(",") + ")";
|
|
407
|
+
const allPl = batch.map(() => oneRowPl).join(",");
|
|
408
|
+
const batchInsertSql = `INSERT INTO ${safeTableName} (${columnList.map(escapeId).join(", ")}) VALUES ${allPl}`;
|
|
409
|
+
await queryRunner.execute(batchInsertSql, values);
|
|
410
|
+
rowsTransferred += batch.length;
|
|
411
|
+
}
|
|
412
|
+
if (dataRows.length < pageSizeVal)
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
await queryRunner.commit();
|
|
416
|
+
return { tableName, rowsTransferred };
|
|
417
|
+
}
|
|
418
|
+
catch (err) {
|
|
419
|
+
await queryRunner.rollback();
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
finally {
|
|
423
|
+
queryRunner.release();
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function copyDataTables(connectionPool, params) {
|
|
427
|
+
const { sourcePool, targetPool } = connectionPool;
|
|
428
|
+
const tableNames = normalizeTableNames(params);
|
|
429
|
+
const tableResults = [];
|
|
430
|
+
const restoreUserRefsOptions = params.restoreUserRefsOptions ?? [];
|
|
431
|
+
const shouldValidate = typeof params.validateAndUpdate === "boolean";
|
|
432
|
+
for (const tableName of tableNames) {
|
|
433
|
+
const result = await transferSingleTable(sourcePool, targetPool, tableName, params);
|
|
434
|
+
tableResults.push(result);
|
|
435
|
+
}
|
|
436
|
+
const restoreUserRefsResults = restoreUserRefsOptions.length > 0
|
|
437
|
+
? await runRestoreUserRefs(sourcePool, targetPool, restoreUserRefsOptions)
|
|
438
|
+
: [];
|
|
439
|
+
const validateResults = shouldValidate
|
|
440
|
+
? await runValidation(sourcePool, targetPool, tableNames, params)
|
|
441
|
+
: [];
|
|
442
|
+
return {
|
|
443
|
+
totalRowsTransferred: tableResults.reduce((total, item) => total + item.rowsTransferred, 0),
|
|
444
|
+
tableResults,
|
|
445
|
+
restoreUserRefsResults,
|
|
446
|
+
validateResults,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.js","sourceRoot":"","sources":["../../src/transfer-data-sdk/script.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Pool } from "mysql2/promise";
|
|
2
|
+
export interface ConnectionPool {
|
|
3
|
+
sourcePool: Pool;
|
|
4
|
+
targetPool: Pool;
|
|
5
|
+
}
|
|
6
|
+
export interface LimitSizeOptions {
|
|
7
|
+
pageSize?: number;
|
|
8
|
+
batchSize?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SetDataOptions {
|
|
11
|
+
tableName: string;
|
|
12
|
+
columnName: string;
|
|
13
|
+
value: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface RestoreUserRefsTableOption {
|
|
16
|
+
tableName: string;
|
|
17
|
+
pkColumn?: string;
|
|
18
|
+
batchSize?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface RestoreUserRefsResult {
|
|
21
|
+
tableName: string;
|
|
22
|
+
rowsUpdated: number;
|
|
23
|
+
}
|
|
24
|
+
export interface ValidateTableResult {
|
|
25
|
+
tableName: string;
|
|
26
|
+
totalChecked: number;
|
|
27
|
+
mismatchCount: number;
|
|
28
|
+
insertedCount: number;
|
|
29
|
+
updatedCount: number;
|
|
30
|
+
}
|
|
31
|
+
export interface TransferOptions {
|
|
32
|
+
/**
|
|
33
|
+
* ชื่อฟิลด์ที่ต้องการ
|
|
34
|
+
* รองรับตารางเดียวหรือหลายตาราง
|
|
35
|
+
*/
|
|
36
|
+
tableNames?: string[] | string;
|
|
37
|
+
/**
|
|
38
|
+
* ชื่อเรียกแทน (alias) ที่เข้ากันได้กับเวอร์ชันก่อนหน้า
|
|
39
|
+
*/
|
|
40
|
+
tablesName?: string[] | string;
|
|
41
|
+
/**
|
|
42
|
+
* สงวนไว้สำหรับการปรับปรุงในอนาคต
|
|
43
|
+
* ขณะนี้ยังไม่มีการดำเนินการขั้นตอนการตรวจสอบ/อัปเดตเพิ่มเติม
|
|
44
|
+
*/
|
|
45
|
+
validateAndUpdate?: boolean;
|
|
46
|
+
options?: LimitSizeOptions;
|
|
47
|
+
setDataOptions?: SetDataOptions[];
|
|
48
|
+
restoreUserRefsOptions?: RestoreUserRefsTableOption[];
|
|
49
|
+
}
|
|
50
|
+
export interface TableTransferResult {
|
|
51
|
+
tableName: string;
|
|
52
|
+
rowsTransferred: number;
|
|
53
|
+
}
|
|
54
|
+
export interface CopyDataTablesResult {
|
|
55
|
+
totalRowsTransferred: number;
|
|
56
|
+
tableResults: TableTransferResult[];
|
|
57
|
+
restoreUserRefsResults: RestoreUserRefsResult[];
|
|
58
|
+
validateResults: ValidateTableResult[];
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transfer-data-sdk/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC/B;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC/B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;IAClC,sBAAsB,CAAC,EAAE,0BAA0B,EAAE,CAAC;CACvD;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACpC,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;IAChD,eAAe,EAAE,mBAAmB,EAAE,CAAC;CACxC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transfer-data-sdk/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gumin61/transfer-data-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"private": false,
|
|
8
|
+
"main": "dist/transfer-data-sdk/index.js",
|
|
9
|
+
"types": "dist/transfer-data-sdk/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/transfer-data-sdk/index.d.ts",
|
|
13
|
+
"default": "./dist/transfer-data-sdk/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/transfer-data-sdk",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"build:sdk": "tsc -p tsconfig.json",
|
|
23
|
+
"prepublishOnly": "npm run build:sdk",
|
|
24
|
+
"test": "tsx src/run-test.ts",
|
|
25
|
+
"table": "tsx src/run-test.ts",
|
|
26
|
+
"validate-data": "tsx src/transfer/validation-data.ts",
|
|
27
|
+
"validation": "tsx src/run-test.ts --validate",
|
|
28
|
+
"seed:permissions": "tsx src/seed-permissions.ts",
|
|
29
|
+
"transfer:sections": "tsx src/run.ts sections",
|
|
30
|
+
"transfer:master-data": "tsx src/run.ts master-data",
|
|
31
|
+
"transfer:section-1": "tsx src/run.ts section-1",
|
|
32
|
+
"transfer:section-2": "tsx src/run.ts section-2",
|
|
33
|
+
"transfer:section-3": "tsx src/run.ts section-3",
|
|
34
|
+
"transfer:section-4": "tsx src/run.ts section-4",
|
|
35
|
+
"transfer:section-5": "tsx src/run.ts section-5",
|
|
36
|
+
"transfer:section-6": "tsx src/run.ts section-6",
|
|
37
|
+
"transfer:section-7": "tsx src/run.ts section-7",
|
|
38
|
+
"transfer:section-7-1": "tsx src/run.ts section-7-1",
|
|
39
|
+
"transfer:section-7-2": "tsx src/run.ts section-7-2",
|
|
40
|
+
"demo:test": "npm --prefix demo run test"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"dotenv": "^16.4.5",
|
|
44
|
+
"drizzle-orm": "^0.36.0",
|
|
45
|
+
"mysql2": "^3.11.3"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.8.4",
|
|
49
|
+
"tsx": "^4.19.2",
|
|
50
|
+
"typescript": "^5.6.3"
|
|
51
|
+
}
|
|
52
|
+
}
|