populate.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { INestApplication } from '@nestjs/common';
  2. import fs from 'fs-extra';
  3. import path from 'path';
  4. import { logColored } from './cli-utils';
  5. // tslint:disable:no-var-requires
  6. let Populator: any;
  7. let Importer: any;
  8. try {
  9. Populator = require('@vendure/core').Populator;
  10. Importer = require('@vendure/core').Importer;
  11. } catch (e) {
  12. Populator = require('../src/data-import/providers/populator/populator').Populator;
  13. Importer = require('../src/data-import/providers/importer/importer').Importer;
  14. }
  15. // tslint:disable:no-console
  16. export async function populateFromCli() {
  17. logColored('\nPopulating... (this may take a minute or two)\n');
  18. const initialDataPath = './assets/initial-data.json';
  19. const sampleProductsFile = path.join(__dirname, 'assets', 'products.csv');
  20. const imageSourcePath = path.join(__dirname, 'assets', 'images');
  21. const app = await populate(getApplicationRef, initialDataPath, sampleProductsFile, imageSourcePath);
  22. await app.close();
  23. process.exit(0);
  24. }
  25. export async function populate(bootstrapFn: () => Promise<INestApplication | undefined>,
  26. initialDataPath: string,
  27. productsCsvPath: string,
  28. imageSourcePath: string): Promise<INestApplication> {
  29. const app = await bootstrapFn();
  30. if (!app) {
  31. throw new Error('Could not bootstrap the Vendure app');
  32. }
  33. const initialData = require(initialDataPath);
  34. await populateInitialData(app, initialData);
  35. await populateProducts(app, initialData, productsCsvPath, imageSourcePath);
  36. await populateCollections(app, initialData);
  37. logColored('\nDone!');
  38. return app;
  39. }
  40. export async function importProducts(csvPath: string, languageCode: string) {
  41. logColored(`\nImporting from "${csvPath}"...\n`);
  42. const app = await getApplicationRef();
  43. if (app) {
  44. await importProductsFromFile(app, csvPath, languageCode);
  45. logColored('\nDone!');
  46. await app.close();
  47. process.exit(0);
  48. }
  49. }
  50. async function getApplicationRef(): Promise<INestApplication | undefined> {
  51. const tsConfigFile = path.join(process.cwd(), 'vendure-config.ts');
  52. const jsConfigFile = path.join(process.cwd(), 'vendure-config.js');
  53. let isTs = false;
  54. let configFile: string | undefined;
  55. if (fs.existsSync(tsConfigFile)) {
  56. configFile = tsConfigFile;
  57. isTs = true;
  58. } else if (fs.existsSync(jsConfigFile)) {
  59. configFile = jsConfigFile;
  60. }
  61. if (!configFile) {
  62. console.error(`Could not find a config file`);
  63. console.error(`Checked "${tsConfigFile}", "${jsConfigFile}"`);
  64. process.exit(1);
  65. return;
  66. }
  67. if (isTs) {
  68. // we expect ts-node to be available
  69. const tsNode = require('ts-node');
  70. if (!tsNode) {
  71. console.error(`For "populate" to work with TypeScript projects, you must have ts-node installed`);
  72. process.exit(1);
  73. return;
  74. }
  75. require('ts-node').register();
  76. }
  77. const index = require(configFile);
  78. if (!index) {
  79. console.error(`Could not read the contents of "${configFile}"`);
  80. process.exit(1);
  81. return;
  82. }
  83. if (!index.config) {
  84. console.error(`The file "${configFile}" does not export a "config" object`);
  85. process.exit(1);
  86. return;
  87. }
  88. const config = index.config;
  89. config.silent = true;
  90. // Force the sync mode on, so that all the tables are created
  91. // on this initial run.
  92. config.dbConnectionOptions.synchronize = true;
  93. const { bootstrap } = require('@vendure/core');
  94. console.log('Bootstrapping Vendure server...');
  95. const app = await bootstrap(config);
  96. return app;
  97. }
  98. async function populateInitialData(app: INestApplication, initialData: any) {
  99. const populator = app.get(Populator);
  100. try {
  101. await populator.populateInitialData(initialData);
  102. } catch (err) {
  103. console.error(err.message);
  104. }
  105. }
  106. async function populateCollections(app: INestApplication, initialData: any) {
  107. const populator = app.get(Populator);
  108. try {
  109. await populator.populateCollections(initialData);
  110. } catch (err) {
  111. console.error(err.message);
  112. }
  113. }
  114. async function populateProducts(app: INestApplication, initialData: any, csvPath: string, imageSourcePath: string) {
  115. // copy the images to the import folder
  116. const destination = path.join(process.cwd(), 'vendure', 'import-assets');
  117. await fs.copy(imageSourcePath, destination);
  118. await importProductsFromFile(app, csvPath, initialData.defaultLanguage);
  119. }
  120. async function importProductsFromFile(app: INestApplication, csvPath: string, languageCode: string) {
  121. // import the csv of same product data
  122. const importer = app.get(Importer);
  123. const productData = await fs.readFile(csvPath, 'utf-8');
  124. const importResult = await importer.parseAndImport(productData, languageCode, true).toPromise();
  125. if (importResult.errors.length) {
  126. const errorFile = path.join(process.cwd(), 'vendure-import-error.log');
  127. console.log(
  128. `${importResult.errors.length} errors encountered when importing product data. See: ${errorFile}`,
  129. );
  130. await fs.writeFile(errorFile, importResult.errors.join('\n'));
  131. }
  132. logColored(`\nImported ${importResult.imported} products`);
  133. }