Compare commits
2 Commits
705a99d415
...
features/c
| Author | SHA1 | Date | |
|---|---|---|---|
| eb2cb72ea4 | |||
| 2a0d231597 |
11
doc/prompts/12 csv import
Normal file
11
doc/prompts/12 csv import
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Please make script to import following csv to Customer model
|
||||||
|
|
||||||
|
City,Name,Website URL,Email
|
||||||
|
"Tokyo","teamLab Planets TOKYO","http://www.teamlab.art/e/planets/","null"
|
||||||
|
"Tokyo","Tokyo National Museum","http://www.tnm.jp/","null"
|
||||||
|
"Tokyo","Nezu Museum","http://www.nezu-muse.or.jp/","null"
|
||||||
|
|
||||||
|
- Name should be unique.
|
||||||
|
- Also if there are same email address skip the row.
|
||||||
|
|
||||||
|
Create new branch features/csvimport and commit when you finished
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
@ -19,6 +19,7 @@
|
|||||||
"@editorjs/paragraph": "^2.11.7",
|
"@editorjs/paragraph": "^2.11.7",
|
||||||
"@editorjs/quote": "^2.7.6",
|
"@editorjs/quote": "^2.7.6",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
|
"csv-parse": "^5.6.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"mysql2": "^3.13.0",
|
"mysql2": "^3.13.0",
|
||||||
"next": "15.2.2",
|
"next": "15.2.2",
|
||||||
@ -2764,6 +2765,11 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/csv-parse": {
|
||||||
|
"version": "5.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.6.0.tgz",
|
||||||
|
"integrity": "sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q=="
|
||||||
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||||
|
|||||||
@ -8,7 +8,8 @@
|
|||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"create-test-user": "npx ts-node -P tsconfig.scripts.json src/scripts/create-test-user.ts",
|
"create-test-user": "npx ts-node -P tsconfig.scripts.json src/scripts/create-test-user.ts",
|
||||||
"reset-database": "npx ts-node -P tsconfig.scripts.json src/scripts/reset-database.ts"
|
"reset-database": "npx ts-node -P tsconfig.scripts.json src/scripts/reset-database.ts",
|
||||||
|
"import-customers": "npx ts-node -P tsconfig.scripts.json src/scripts/import-customers.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@editorjs/code": "^2.9.3",
|
"@editorjs/code": "^2.9.3",
|
||||||
@ -22,6 +23,7 @@
|
|||||||
"@editorjs/paragraph": "^2.11.7",
|
"@editorjs/paragraph": "^2.11.7",
|
||||||
"@editorjs/quote": "^2.7.6",
|
"@editorjs/quote": "^2.7.6",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
|
"csv-parse": "^5.6.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"mysql2": "^3.13.0",
|
"mysql2": "^3.13.0",
|
||||||
"next": "15.2.2",
|
"next": "15.2.2",
|
||||||
|
|||||||
108
src/scripts/import-customers.ts
Normal file
108
src/scripts/import-customers.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import 'reflect-metadata';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { parse } from 'csv-parse/sync';
|
||||||
|
import { getDataSource } from '../lib/database';
|
||||||
|
import { Customer } from '../lib/database/entities/Customer';
|
||||||
|
|
||||||
|
interface CustomerCSVRow {
|
||||||
|
City: string;
|
||||||
|
Name: string;
|
||||||
|
'Website URL': string;
|
||||||
|
Email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function importCustomers(csvFilePath: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
// Initialize database connection
|
||||||
|
const dataSource = await getDataSource();
|
||||||
|
const customerRepository = dataSource.getRepository(Customer);
|
||||||
|
|
||||||
|
// Read and parse CSV file
|
||||||
|
const fileContent = fs.readFileSync(csvFilePath, 'utf-8');
|
||||||
|
const records = parse(fileContent, {
|
||||||
|
columns: true,
|
||||||
|
skip_empty_lines: true,
|
||||||
|
trim: true,
|
||||||
|
}) as CustomerCSVRow[];
|
||||||
|
|
||||||
|
console.log(`Found ${records.length} records in CSV file`);
|
||||||
|
|
||||||
|
// Track processed emails to skip duplicates
|
||||||
|
const processedEmails = new Set<string>();
|
||||||
|
// Track existing names to ensure uniqueness
|
||||||
|
const existingNames = new Set<string>(
|
||||||
|
(await customerRepository.find()).map(customer => customer.name)
|
||||||
|
);
|
||||||
|
|
||||||
|
let importedCount = 0;
|
||||||
|
let skippedDuplicateEmail = 0;
|
||||||
|
let skippedDuplicateName = 0;
|
||||||
|
|
||||||
|
for (const record of records) {
|
||||||
|
const email = record.Email === 'null' ? '' : record.Email;
|
||||||
|
const name = record.Name;
|
||||||
|
|
||||||
|
// Skip if email is already processed (not empty and already seen)
|
||||||
|
if (email && processedEmails.has(email)) {
|
||||||
|
console.log(`Skipping record with duplicate email: ${email}`);
|
||||||
|
skippedDuplicateEmail++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if name already exists in database
|
||||||
|
if (existingNames.has(name)) {
|
||||||
|
console.log(`Skipping record with duplicate name: ${name}`);
|
||||||
|
skippedDuplicateName++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to processed sets
|
||||||
|
if (email) {
|
||||||
|
processedEmails.add(email);
|
||||||
|
}
|
||||||
|
existingNames.add(name);
|
||||||
|
|
||||||
|
// Create new customer
|
||||||
|
const customer = new Customer();
|
||||||
|
customer.name = name;
|
||||||
|
customer.url = record['Website URL'] === 'null' ? '' : record['Website URL'];
|
||||||
|
customer.email = email;
|
||||||
|
|
||||||
|
// Save to database
|
||||||
|
await customerRepository.save(customer);
|
||||||
|
importedCount++;
|
||||||
|
|
||||||
|
console.log(`Imported customer: ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Import summary:');
|
||||||
|
console.log(`- Total records in CSV: ${records.length}`);
|
||||||
|
console.log(`- Successfully imported: ${importedCount}`);
|
||||||
|
console.log(`- Skipped (duplicate email): ${skippedDuplicateEmail}`);
|
||||||
|
console.log(`- Skipped (duplicate name): ${skippedDuplicateName}`);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error importing customers:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file path is provided as command line argument
|
||||||
|
const csvFilePath = process.argv[2];
|
||||||
|
if (!csvFilePath) {
|
||||||
|
console.error('Please provide the path to the CSV file as a command line argument');
|
||||||
|
console.error('Example: npm run import-customers -- ./data/customers.csv');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the import function
|
||||||
|
importCustomers(csvFilePath)
|
||||||
|
.then(() => {
|
||||||
|
console.log('Import completed successfully');
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Import failed:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user