@nkhang1902/strapi-plugin-export-import-clsx 1.0.5 → 1.1.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.
@@ -1,55 +1,59 @@
1
- const XLSX = require('xlsx');
2
- const fs = require('fs');
1
+ const XLSX = require("xlsx");
2
+ const fs = require("fs");
3
3
 
4
4
  function toCamel(str) {
5
5
  return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
6
6
  }
7
7
 
8
8
  const SHORTCUT_FIELDS = [
9
- 'email','businessEmail','name','title','tickerCode',
10
- ]
11
- async function importData(file) {
12
- let result;
13
- try {
14
- let importData;
15
- // Check file extension
16
- const fileName = file.name || file.originalFilename || 'unknown.json';
17
- const fileExtension = fileName.split('.').pop().toLowerCase();
18
- const filePath = file.path || file.filepath;
19
- if (!filePath) {
20
- throw new Error('File path not found');
21
- }
9
+ "email",
10
+ "businessEmail",
11
+ "name",
12
+ "title",
13
+ "tickerCode",
14
+ ];
15
+ module.exports = ({ strapi }) => ({
16
+ async importData(file, targetContentType = null) {
17
+ let result;
18
+ try {
19
+ let importData;
20
+ // Check file extension
21
+ const fileName = file.name || file.originalFilename || "unknown.json";
22
+ const fileExtension = fileName.split(".").pop().toLowerCase();
23
+ const filePath = file.path || file.filepath;
24
+ if (!filePath) {
25
+ throw new Error("File path not found");
26
+ }
22
27
 
23
- if (fileExtension === 'json') {
24
- const fileContent = fs.readFileSync(filePath, 'utf8');
25
- importData = JSON.parse(fileContent);
26
- strapi.log.info('Parsed JSON data:', Object.keys(importData));
27
- } else if (fileExtension === 'xlsx' || fileExtension === 'xls') {
28
- importData = transformExcelData(filePath);
29
- }
30
- result = await bulkInsertData(importData);
31
- return result;
32
- } catch (error) {
33
- // Clean up uploaded file on error
34
- const filePath = file && (file.path || file.filepath);
35
- if (filePath && fs.existsSync(filePath)) {
36
- fs.unlinkSync(filePath);
28
+ if (fileExtension === "json") {
29
+ const fileContent = fs.readFileSync(filePath, "utf8");
30
+ importData = JSON.parse(fileContent);
31
+ strapi.log.info("Parsed JSON data:", Object.keys(importData));
32
+ } else if (fileExtension === "xlsx" || fileExtension === "xls") {
33
+ importData = this.transformExcelData(filePath, targetContentType);
34
+ }
35
+ result = await this.bulkInsertData(importData);
36
+ return result;
37
+ } catch (error) {
38
+ // Clean up uploaded file on error
39
+ const filePath = file && (file.path || file.filepath);
40
+ if (filePath && fs.existsSync(filePath)) {
41
+ fs.unlinkSync(filePath);
42
+ }
43
+ throw error;
37
44
  }
38
- throw error;
39
- }
40
- }
41
-
45
+ },
42
46
 
43
- function transformExcelData(filePath) {
47
+ transformExcelData(filePath, targetContentType = null) {
44
48
  const workbook = XLSX.readFile(filePath);
45
49
  const importData = {};
46
50
 
47
51
  const isComponentField = (key) => {
48
- const parts = key.split('_');
49
- return parts.length === 2; // exactly one underscore
52
+ const parts = key.split("_");
53
+ return parts.length === 2; // exactly one underscore
50
54
  };
51
55
 
52
- function unflattenRow(rows, targetContentType) {
56
+ const unflattenRow = (rows, targetContentType) => {
53
57
  const result = [];
54
58
  const attr = strapi.contentTypes[targetContentType].attributes;
55
59
  for (const row of rows) {
@@ -75,369 +79,373 @@ function transformExcelData(filePath) {
75
79
  };
76
80
 
77
81
  const mapSheetNameToContentType = (sheetName) => {
78
- return "api::" + sheetName + "." + sheetName;
82
+ // If targetContentType is provided, use it instead of guessing from sheet name
83
+ if (targetContentType) {
84
+ return targetContentType;
85
+ }
86
+ return "api::" + sheetName + "." + sheetName;
79
87
  };
80
88
 
81
- workbook.SheetNames.forEach(sheetName => {
82
- const worksheet = workbook.Sheets[sheetName];
83
- const rows = XLSX.utils.sheet_to_json(worksheet);
89
+ workbook.SheetNames.forEach((sheetName) => {
90
+ const worksheet = workbook.Sheets[sheetName];
91
+ const rows = XLSX.utils.sheet_to_json(worksheet);
84
92
 
85
- if (!rows.length) return;
93
+ if (!rows.length) return;
86
94
 
87
- const contentTypeName = mapSheetNameToContentType(sheetName);
95
+ const contentTypeName = mapSheetNameToContentType(sheetName);
88
96
 
89
- strapi.log.info(`Reading sheet "${sheetName}" -> ${rows.length} rows`);
90
- strapi.log.info(`Mapped sheet to content-type: ${contentTypeName}`);
97
+ strapi.log.info(`Reading sheet "${sheetName}" -> ${rows.length} rows`);
98
+ strapi.log.info(`Mapped sheet to content-type: ${contentTypeName}`);
91
99
 
92
- if (contentTypeName.startsWith('api::')) {
93
- importData[contentTypeName] = unflattenRow(rows, contentTypeName);
94
- } else {
95
- strapi.log.error(`Unknown content-type: ${contentTypeName}`);
100
+ if (contentTypeName.startsWith("api::")) {
101
+ // Validate that the content type exists
102
+ if (!strapi.contentTypes[contentTypeName]) {
103
+ strapi.log.error(
104
+ `Content type ${contentTypeName} not found. Available types:`,
105
+ Object.keys(strapi.contentTypes)
106
+ );
96
107
  return;
97
108
  }
109
+ importData[contentTypeName] = unflattenRow(rows, contentTypeName);
110
+ } else {
111
+ strapi.log.error(`Unknown content-type: ${contentTypeName}`);
112
+ return;
113
+ }
98
114
  });
99
115
 
100
- strapi.log.info('Final import data keys:', Object.keys(importData));
116
+ strapi.log.info("Final import data keys:", Object.keys(importData));
101
117
  return importData;
102
- }
118
+ },
103
119
 
104
- function getRelationFields(contentType) {
105
- const schema = strapi.contentTypes[contentType];
106
-
107
- if (!schema) {
108
- strapi.log.warn(`Content type ${contentType} not found`);
109
- return [];
110
- }
111
-
112
- return Object.entries(schema.attributes)
113
- .filter(([_, attr]) => attr.type === "relation")
114
- .map(([fieldName, attr]) => ({
115
- field: toCamel(fieldName),
116
- target: attr.target, // e.g. "api::category.category"
117
- relation: attr.relation,
118
- }));
119
- }
120
+ getRelationFields(contentType) {
121
+ const schema = strapi.contentTypes[contentType];
120
122
 
121
- function getComponentFields(contentType) {
122
- const schema = strapi.contentTypes[contentType];
123
+ if (!schema) {
124
+ strapi.log.warn(`Content type ${contentType} not found`);
125
+ return [];
126
+ }
123
127
 
124
- if (!schema) {
125
- strapi.log.warn(`Content type ${contentType} not found`);
126
- return [];
127
- }
128
+ return Object.entries(schema.attributes)
129
+ .filter(([_, attr]) => attr.type === "relation")
130
+ .map(([fieldName, attr]) => ({
131
+ field: toCamel(fieldName),
132
+ target: attr.target, // e.g. "api::category.category"
133
+ relation: attr.relation,
134
+ }));
135
+ },
136
+
137
+ getComponentFields(contentType) {
138
+ const schema = strapi.contentTypes[contentType];
139
+
140
+ if (!schema) {
141
+ strapi.log.warn(`Content type ${contentType} not found`);
142
+ return [];
143
+ }
128
144
 
129
- return Object.entries(schema.attributes)
130
- .filter(([_, attr]) => attr.type === "component")
131
- .map(([fieldName, attr]) => toCamel(fieldName));
132
- }
145
+ return Object.entries(schema.attributes)
146
+ .filter(([_, attr]) => attr.type === "component")
147
+ .map(([fieldName, attr]) => toCamel(fieldName));
148
+ },
149
+
150
+ async handleRelations(entry, contentType) {
151
+ const resolveRelationValue = async (field, value, target) => {
152
+ const targetAttr = strapi.contentTypes[target].attributes;
153
+ for (const field of SHORTCUT_FIELDS) {
154
+ if (!targetAttr[field]) continue;
155
+ const existing = await strapi.documents(target).findFirst({
156
+ filters: { [field]: { $eq: value } },
157
+ });
158
+ if (existing) return { id: existing.id };
159
+ throw new Error(`Data with ${field} ${value} not found`);
160
+ }
161
+ return null;
162
+ };
133
163
 
134
- async function handleRelations(entry, contentType) {
135
- async function resolveRelationValue(field, value, target) {
136
- const targetAttr = strapi.contentTypes[target].attributes;
137
- for (const field of SHORTCUT_FIELDS) {
138
- if (!targetAttr[field]) continue;
139
- const existing = await strapi.documents(target).findFirst({
140
- filters: { [field]: { $eq: value } },
141
- });
142
- if (existing) return {id: existing.id};
143
- throw new Error(`Data with ${field} ${value} not found`);
144
- }
145
- return null;
146
- }
164
+ const relationFields = this.getRelationFields(contentType);
165
+ if (relationFields.length === 0) return entry;
147
166
 
148
- const relationFields = getRelationFields(contentType);
149
- if (relationFields.length === 0) return entry;
167
+ const updatedEntry = { ...entry };
150
168
 
151
- const updatedEntry = { ...entry };
169
+ for (const rel of relationFields) {
170
+ const { field, target, relation } = rel;
152
171
 
153
- for (const rel of relationFields) {
154
- const { field, target, relation } = rel;
172
+ let value = entry[field];
173
+ if (!value || value === "") {
174
+ if (relation === "manyToMany" || relation === "oneToMany") {
175
+ updatedEntry[field] = [];
176
+ } else {
177
+ updatedEntry[field] = null;
178
+ }
179
+ continue;
180
+ }
155
181
 
156
- let value = entry[field];
157
- if (!value || value === "") {
158
- if (relation === "manyToMany" || relation === "oneToMany") {
159
- updatedEntry[field] = [];
160
- } else {
161
- updatedEntry[field] = null;
182
+ // Convert CSV to array
183
+ if (
184
+ typeof value === "string" &&
185
+ (relation === "manyToMany" || relation === "oneToMany")
186
+ ) {
187
+ value = value.split("|");
188
+ } else if (typeof value === "string" && value.includes("|")) {
189
+ throw new Error(
190
+ `Invalid value for field ${field}: ${value}, ${field} is not an array`
191
+ );
162
192
  }
163
- continue;
164
- };
165
193
 
166
- // Convert CSV to array
167
- if (typeof value === "string" && (relation === "manyToMany" || relation === "oneToMany")) {
168
- value = value.split("|");
169
- } else if (typeof value === "string" && value.includes("|")) {
170
- throw new Error(`Invalid value for field ${field}: ${value}, ${field} is not an array`);
171
- }
194
+ const values = Array.isArray(value) ? value : [value];
195
+ try {
196
+ const processed = [];
172
197
 
173
- const values = Array.isArray(value) ? value : [value];
174
- try {
175
- const processed = [];
198
+ for (const v of values) {
199
+ if (!v || v === "") continue;
200
+ const resolved = await resolveRelationValue(field, v, target);
201
+ if (resolved) processed.push(resolved);
202
+ }
176
203
 
177
- for (const v of values) {
178
- if (!v || v === "") continue;
179
- const resolved = await resolveRelationValue(field, v, target);
180
- if (resolved) processed.push(resolved);
204
+ updatedEntry[field] = Array.isArray(value) ? processed : processed[0];
205
+ } catch (err) {
206
+ throw new Error(
207
+ `Failed processing field ${field} with value ${JSON.stringify(value)}: ${err.message}`
208
+ );
181
209
  }
182
-
183
- updatedEntry[field] = Array.isArray(value) ? processed : processed[0];
184
- } catch (err) {
185
- throw new Error(
186
- `Failed processing field ${field} with value ${JSON.stringify(value)}: ${err.message}`
187
- );
188
210
  }
189
- }
190
-
191
- return updatedEntry;
192
- }
193
211
 
194
- function handleComponents(data, existing, contentType) {
195
- // Get the component fields for this content type
196
- const compFields = getComponentFields(contentType);
212
+ return updatedEntry;
213
+ },
197
214
 
198
- for (const field of compFields) {
199
- const newValue = data[field];
200
- const oldValue = existing?.[field];
215
+ handleComponents(data, existing, contentType) {
216
+ // Get the component fields for this content type
217
+ const compFields = this.getComponentFields(contentType);
201
218
 
202
- if (!newValue || !oldValue) continue;
219
+ for (const field of compFields) {
220
+ const newValue = data[field];
221
+ const oldValue = existing?.[field];
203
222
 
204
- //single component
205
- if (!Array.isArray(newValue)) {
206
- if (oldValue?.id) {
207
- data[field].id = oldValue.id;
208
- }
209
- for (const key of Object.keys(data[field])) {
210
- if (Array.isArray(oldValue[key])) {
211
- data[field][key] = data[field][key].split("|");
212
- }
213
- }
214
- continue;
215
- }
223
+ if (!newValue || !oldValue) continue;
216
224
 
217
- //multiple components
218
- if (Array.isArray(newValue) && Array.isArray(oldValue)) {
219
- data[field] = newValue.map((block, i) => {
220
- const oldBlock = oldValue[i];
221
- if (oldBlock?.id) {
222
- return { id: oldBlock.id, ...block };
225
+ //single component
226
+ if (!Array.isArray(newValue)) {
227
+ if (oldValue?.id) {
228
+ data[field].id = oldValue.id;
223
229
  }
224
- for (const key of Object.keys(block)) {
225
- if (Array.isArray(oldBlock[key])) {
226
- block[key] = block[key].split("|");
230
+ for (const key of Object.keys(data[field])) {
231
+ if (Array.isArray(oldValue[key])) {
232
+ data[field][key] = data[field][key].split("|");
227
233
  }
228
234
  }
229
- return block;
230
- });
231
- }
232
- }
233
-
234
- return data;
235
- }
236
-
237
- function sanitizeEntryBeforeWrite(data, uid, path = '', errors = []) {
238
- const schema = strapi.contentTypes[uid];
239
- const cleaned = {};
240
-
241
- for (const [key, attr] of Object.entries(schema.attributes)) {
242
- const value = data[key];
243
- const fieldPath = path ? `${path}.${key}` : key;
244
-
245
- if (value === undefined) continue;
246
-
247
- if (attr.type === 'component') {
248
- if (!value) {
249
- cleaned[key] = attr.repeatable ? [] : null;
250
235
  continue;
251
236
  }
252
237
 
253
- cleaned[key] = attr.repeatable
254
- ? value.map((v, i) =>
255
- sanitizeComponent(v, attr.component, `${fieldPath}[${i}]`, errors)
256
- )
257
- : sanitizeComponent(value, attr.component, fieldPath, errors);
258
- continue;
259
- }
260
-
261
- if (attr.type === 'relation') {
262
- cleaned[key] = value;
263
- } else {
264
- cleaned[key] = sanitizePrimitive(value, attr, fieldPath, errors);
265
- }
266
- }
267
-
268
- return cleaned;
269
- }
270
-
271
- function sanitizeComponent(data, uid, path, errors) {
272
- const schema = strapi.components[uid];
273
- if (!schema) return data;
274
-
275
- const cleaned = {};
276
-
277
- for (const [key, attr] of Object.entries(schema.attributes)) {
278
- const value = data?.[key];
279
- const fieldPath = `${path}.${key}`;
280
-
281
- if (attr.type === 'component') {
282
- cleaned[key] = attr.repeatable
283
- ? (value || []).map((v, i) =>
284
- sanitizeComponent(v, attr.component, `${fieldPath}[${i}]`, errors)
285
- )
286
- : sanitizeComponent(value, attr.component, fieldPath, errors);
287
- } else {
288
- cleaned[key] = sanitizePrimitive(value, attr, fieldPath, errors);
238
+ //multiple components
239
+ if (Array.isArray(newValue) && Array.isArray(oldValue)) {
240
+ data[field] = newValue.map((block, i) => {
241
+ const oldBlock = oldValue[i];
242
+ if (oldBlock?.id) {
243
+ return { id: oldBlock.id, ...block };
244
+ }
245
+ for (const key of Object.keys(block)) {
246
+ if (Array.isArray(oldBlock[key])) {
247
+ block[key] = block[key].split("|");
248
+ }
249
+ }
250
+ return block;
251
+ });
252
+ }
289
253
  }
290
- }
291
-
292
- return cleaned;
293
- }
294
254
 
295
- function sanitizePrimitive(value, attr, path, errors) {
296
- if (value === null || value === undefined || value === '') return null;
297
-
298
- switch (attr.type) {
299
- case 'string':
300
- case 'text':
301
- case 'richtext':
302
- case 'email':
303
- return String(value).trim();
304
-
305
- case 'boolean':
306
- if ([true, 'true', 1, '1', 'yes', 'y'].includes(value)) return true;
307
- if ([false, 'false', 0, '0', 'no', 'n'].includes(value)) return false;
308
- return false;
309
-
310
- case 'integer':
311
- case 'biginteger': {
312
- const i = parseInt(value, 10);
313
- return Number.isNaN(i) ? 0 : i;
255
+ return data;
256
+ },
257
+
258
+ sanitizeComponent(data, uid, rowIndex, errors, path) {
259
+ const schema = strapi.components[uid];
260
+ if (!schema) return data;
261
+
262
+ const cleaned = {};
263
+
264
+ for (const [key, attr] of Object.entries(schema.attributes)) {
265
+ const value = data?.[key];
266
+ const fieldPath = `${path}.${key}`;
267
+
268
+ if (attr.type === 'component') {
269
+ cleaned[key] = attr.repeatable
270
+ ? (value || []).map((v, i) =>
271
+ sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
272
+ )
273
+ : sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
274
+ } else {
275
+ cleaned[key] = sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
276
+ }
314
277
  }
315
-
316
- case 'float':
317
- case 'decimal': {
318
- const f = parseFloat(value);
319
- return Number.isNaN(f) ? 0 : f;
278
+
279
+ return cleaned;
280
+ },
281
+
282
+ sanitizeEntryBeforeWrite(data, uid, rowIndex, errors, path = '') {
283
+ const schema = strapi.contentTypes[uid];
284
+ const cleaned = {};
285
+
286
+ for (const [key, attr] of Object.entries(schema.attributes)) {
287
+ const value = data[key];
288
+ const fieldPath = path ? `${path}.${key}` : key;
289
+
290
+ if (value === undefined) continue;
291
+
292
+ if (attr.type === 'component') {
293
+ if (!value) {
294
+ cleaned[key] = attr.repeatable ? [] : null;
295
+ continue;
296
+ }
297
+
298
+ cleaned[key] = attr.repeatable
299
+ ? value.map((v, i) =>
300
+ sanitizeComponent(v, attr.component, rowIndex, errors, `${fieldPath}[${i}]`)
301
+ )
302
+ : sanitizeComponent(value, attr.component, rowIndex, errors, fieldPath);
303
+ continue;
304
+ }
305
+
306
+ cleaned[key] = sanitizePrimitive(value, attr, rowIndex, errors, fieldPath);
320
307
  }
321
-
322
- case 'date':
323
- case 'datetime': {
324
- const d = new Date(value);
325
- return isNaN(d.getTime()) ? null : d.toISOString();
308
+
309
+ return cleaned;
310
+ },
311
+
312
+ sanitizePrimitive(value, attr) {
313
+ if (value === null || value === undefined || value === '') return null;
314
+ switch (attr.type) {
315
+ case 'string':
316
+ case 'text':
317
+ case 'richtext':
318
+ case 'email':
319
+ return String(value).trim();
320
+ case 'boolean':
321
+ if ([true, 'true', 1, '1', 'yes', 'y'].includes(value)) return true;
322
+ if ([false, 'false', 0, '0', 'no', 'n'].includes(value)) return false;
323
+ return false; // fallback
324
+ case 'integer':
325
+ case 'biginteger': {
326
+ const i = parseInt(value, 10);
327
+ return Number.isNaN(i) ? 0 : i;
328
+ }
329
+ case 'float':
330
+ case 'decimal': {
331
+ const f = parseFloat(value);
332
+ return Number.isNaN(f) ? 0 : f;
333
+ }
334
+ case 'date':
335
+ case 'datetime': {
336
+ const d = new Date(value);
337
+ return isNaN(d.getTime()) ? null : d.toISOString();
338
+ }
339
+ default:
340
+ return value;
326
341
  }
342
+ },
327
343
 
328
- default:
329
- return value;
330
- }
331
- }
344
+ async bulkInsertData(importData) {
345
+ const results = {
346
+ created: 0,
347
+ updated: 0,
348
+ errors: [],
349
+ };
332
350
 
333
- async function bulkInsertData(importData) {
334
- const results = {
335
- created: 0,
336
- updated: 0,
337
- errors: [],
338
- };
339
-
340
- for (const [contentType, entries] of Object.entries(importData)) {
341
- // Validate entries
342
- if (!strapi.contentTypes[contentType]) {
343
- results.errors.push(`Content type ${contentType} not found`);
344
- continue;
345
- }
346
- if (!Array.isArray(entries)) {
347
- results.errors.push(`Invalid data format for ${contentType}`);
348
- continue;
349
- }
351
+ for (const [contentType, entries] of Object.entries(importData)) {
352
+ // Validate entries
353
+ if (!strapi.contentTypes[contentType]) {
354
+ results.errors.push(`Content type ${contentType} not found`);
355
+ continue;
356
+ }
357
+ if (!Array.isArray(entries)) {
358
+ results.errors.push(`Invalid data format for ${contentType}`);
359
+ continue;
360
+ }
350
361
 
351
- try {
352
- const { created, updated, errors } = await importEntries(entries, contentType);
353
- results.created += created;
354
- results.updated += updated;
355
- results.errors = results.errors.concat(errors);
356
- } catch (err) {
357
- results.errors.push(err.message);
362
+ try {
363
+ const { created, updated, errors } = await this.importEntries(
364
+ entries,
365
+ contentType
366
+ );
367
+ results.created += created;
368
+ results.updated += updated;
369
+ results.errors = results.errors.concat(errors);
370
+ } catch (err) {
371
+ results.errors.push(err.message);
372
+ }
358
373
  }
359
- }
360
-
361
- return results;
362
- }
363
374
 
364
- async function importEntries(entries, contentType) {
365
- const results = { created: 0, updated: 0, errors: [] };
375
+ return results;
376
+ },
366
377
 
367
- await strapi.db.transaction(async ({ trx, rollback, onRollback }) => {
368
- onRollback(() => {
369
- strapi.log.error("Transaction rolled back due to an error!");
370
- strapi.log.error(results.errors);
371
- });
378
+ async importEntries(entries, contentType) {
379
+ const results = { created: 0, updated: 0, errors: [] };
372
380
 
373
- for (let i = 0; i < entries.length; i++) {
374
- const entry = entries[i];
375
- let existing = null;
381
+ await strapi.db.transaction(async ({ trx, rollback, onRollback }) => {
382
+ onRollback(() => {
383
+ strapi.log.error("Transaction rolled back due to an error!");
384
+ strapi.log.error(results.errors);
385
+ });
376
386
 
377
- try {
378
- let { id, ...data } = entry;
379
-
380
- // Check if document exists
381
- if (id && id !== "null" && id !== "undefined") {
382
- existing = await strapi.documents(contentType).findFirst(
383
- {
384
- filters: { id },
385
- populate: "*",
386
- },
387
- { transaction: trx }
388
- );
389
- }
387
+ for (let i = 0; i < entries.length; i++) {
388
+ const entry = entries[i];
389
+ let existing = null;
390
+
391
+ try {
392
+ let { id, ...data } = entry;
393
+
394
+ // Check if document exists
395
+ if (id && id !== "null" && id !== "undefined") {
396
+ existing = await strapi.documents(contentType).findFirst(
397
+ {
398
+ filters: { id },
399
+ populate: "*",
400
+ },
401
+ { transaction: trx }
402
+ );
403
+ }
390
404
 
391
- // Handle relations & components
392
- data = await handleRelations(data, contentType);
393
- data = await handleComponents(data, existing, contentType);
405
+ // Handle relations & components
406
+ data = await this.handleRelations(data, contentType, trx);
407
+ data = await this.handleComponents(data, existing, contentType);
408
+ const sanitizeErrors = [];
409
+ data = sanitizeEntryBeforeWrite(data, contentType, '', sanitizeErrors);
394
410
 
395
- const sanitizeErrors = [];
396
- data = sanitizeEntryBeforeWrite(data, contentType, '', sanitizeErrors);
411
+ if (sanitizeErrors.length) {
412
+ throw new Error(`Data validation failed:\n${sanitizeErrors.join('\n')}`);
413
+ }
397
414
 
398
- if (sanitizeErrors.length) {
399
- throw new Error(`Data validation failed:\n${sanitizeErrors.join('\n')}`);
400
- }
415
+ // Update
416
+ if (existing) {
417
+ await strapi.documents(contentType).update(
418
+ {
419
+ documentId: existing.documentId,
420
+ data,
421
+ },
422
+ { transaction: trx }
423
+ );
424
+ results.updated++;
425
+ }
401
426
 
402
- // Update
403
- if (existing) {
404
- await strapi.documents(contentType).update(
405
- {
406
- documentId: existing.documentId,
407
- data,
408
- },
409
- { transaction: trx }
427
+ // Create
428
+ else {
429
+ await strapi
430
+ .documents(contentType)
431
+ .create({ data }, { transaction: trx });
432
+ results.created++;
433
+ }
434
+ } catch (err) {
435
+ results.errors.push(
436
+ `Failed ${existing ? "updating" : "creating"} on row ${
437
+ i + 2
438
+ }: ${err.message}`
410
439
  );
411
- results.updated++;
412
- }
440
+ results.created = 0;
441
+ results.updated = 0;
413
442
 
414
- // Create
415
- else {
416
- await strapi.documents(contentType).create(
417
- { data },
418
- { transaction: trx }
419
- );
420
- results.created++;
443
+ // IMPORTANT: force rollback
444
+ throw err;
421
445
  }
422
- } catch (err) {
423
- results.errors.push(
424
- `Failed ${existing ? "updating" : "creating"} on row ${
425
- i + 2
426
- }: ${err.message}`
427
- );
428
- results.created = 0;
429
- results.updated = 0;
430
-
431
- // IMPORTANT: force rollback
432
- throw err;
433
446
  }
434
- }
435
- });
436
-
437
- return results;
438
- }
439
-
447
+ });
440
448
 
441
- module.exports = {
442
- importData,
443
- };
449
+ return results;
450
+ },
451
+ });