diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f1e12b7dbd..c4c0b154a4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -115,6 +115,8 @@ "jest-environment-jsdom": "29.7.0", "lint-staged": "14.0.1", "madge": "8.0.0", + "ora": "8.1.1", + "postgres": "3.4.5", "prettier": "3.4.1", "puppeteer": "22.15.0", "strip-json-comments": "5.0.1", @@ -5844,7 +5846,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -6375,7 +6376,6 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8" } @@ -7216,7 +7216,6 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, - "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -9736,6 +9735,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -10898,13 +10909,15 @@ } }, "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-map": { @@ -13459,6 +13472,38 @@ "node": ">= 10" } }, + "node_modules/madge/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/madge/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -14107,6 +14152,18 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", @@ -14689,29 +14746,188 @@ } }, "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.1.1.tgz", + "integrity": "sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==", "dev": true, - "license": "MIT", "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", @@ -15299,6 +15515,19 @@ "postcss": "^8.2.9" } }, + "node_modules/postgres": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.5.tgz", + "integrity": "sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, "node_modules/precinct": { "version": "12.1.2", "resolved": "https://registry.npmjs.org/precinct/-/precinct-12.1.2.tgz", @@ -17274,6 +17503,18 @@ "node": ">=8" } }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stream-events": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", @@ -19204,7 +19445,6 @@ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, - "license": "MIT", "dependencies": { "defaults": "^1.0.3" } diff --git a/frontend/package.json b/frontend/package.json index 61560a902f..5a5a1b18c1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,7 @@ "dev-puppeteer": "FRONTEND_OIDC_ENABLED=false FRONTEND_MONITORENV_URL=//localhost:9880 import-meta-env-prepare -u -x ./.env.local.defaults && vite --port 3000", "bundle-sw": "esbuild src/workers/serviceWorker.ts --bundle --outfile=public/service-worker.js", "prepare": "cd .. && ./frontend/node_modules/.bin/husky ./frontend/config/husky", + "generate:perfdata": "node ./scripts/generate_perf_data.js", "generate:testdata": "node ./scripts/generate_test_data_seeds.js", "start": "import-meta-env-prepare -u -x ./.env.local.defaults && vite preview --port 3000", "start:emulate": "npm run clean && npm run build && import-meta-env -x ./.env.example -p ./build/index.html && import-meta-env-prepare -u -x ./.env.local.defaults && vite preview --port 3000", @@ -140,6 +141,8 @@ "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "lint-staged": "14.0.1", + "ora": "8.1.1", + "postgres": "3.4.5", "madge": "8.0.0", "prettier": "3.4.1", "puppeteer": "22.15.0", diff --git a/frontend/scripts/generate_perf_data.js b/frontend/scripts/generate_perf_data.js new file mode 100644 index 0000000000..d026426d2f --- /dev/null +++ b/frontend/scripts/generate_perf_data.js @@ -0,0 +1,280 @@ +/* eslint-disable no-await-in-loop */ + +import { faker } from '@faker-js/faker' +import dayjs from 'dayjs' +import ora from 'ora' +import postgres from 'postgres' + +const BATCH_SIZE = 1000 +const BATCH_SKELETON = new Array(BATCH_SIZE).fill(null) +const START_DATE = dayjs().subtract(6, 'months').toDate() +const END_DATE = dayjs().add(6, 'months').toDate() + +const FAKE_PNO_COUNT = 1000000 +const FAKE_PNO_BATCH_COUNT = FAKE_PNO_COUNT / BATCH_SIZE + +const FAKE_VESSEL_COUNT = 10000 +const FAKE_VESSEL_BATCH_COUNT = FAKE_VESSEL_COUNT / BATCH_SIZE + +const FAKE_REPORTING_COUNT = FAKE_VESSEL_COUNT * 3 +const FAKE_REPORTING_BATCH_COUNT = FAKE_REPORTING_COUNT / BATCH_SIZE + +function getFakePnoLogbookRawMessages(index) { + return [ + { + operation_number: `FAKE_OPERATION_${FAKE_PNO_COUNT + index}`, + xml_message: `Message FLUX xml` + }, + { + operation_number: `FAKE_OPERATION_${FAKE_PNO_COUNT + index}_RET`, + xml_message: `Message FLUX xml` + } + ] +} + +function getFakePnoLogbookReports(index) { + const vesselId = faker.number.int({ max: FAKE_VESSEL_COUNT * 2, min: FAKE_VESSEL_COUNT + 1 }) + const cfr = `FAKCFR_${vesselId}` + const vessel_name = `FAUX NAVIRE ${vesselId}` + + const tripStartDateAsDayjs = dayjs( + faker.date.between({ + from: START_DATE, + to: END_DATE + }) + ) + + const operation_datetime_utc = tripStartDateAsDayjs.add(26, 'hours').format('YYYY-MM-DD HH:mm:ss') + const report_id = `FAKE_OPERATION_${FAKE_PNO_COUNT + index}` + const transmission_format = 'ERS' + + return [ + { + cfr, + enriched: true, + flag_state: 'FRA', + id: FAKE_PNO_COUNT + index, + integration_datetime_utc: operation_datetime_utc, + log_type: 'PNO', + operation_datetime_utc, + operation_number: report_id, + operation_type: 'DAT', + referenced_report_id: null, + report_datetime_utc: operation_datetime_utc, + report_id, + transmission_format, + trip_gears: [ + { dimensions: '250;180', gear: 'TBN', mesh: 100 }, + { dimensions: '250;280', gear: 'OTT', mesh: 120.5 } + ], + trip_segments: [ + { segment: 'SWW04', segmentName: 'Chaluts pélagiques' }, + { segment: 'SWW06', segmentName: 'Sennes' } + ], + value: { + authorTrigram: null, + catchOnboard: [ + { + economicZone: 'FRA', + effortZone: 'C', + faoZone: '27.8.a', + nbFish: null, + species: 'ANF', + statisticalRectangle: '23E6', + weight: 150 + } + ], + pnoTypes: [ + { + hasDesignatedPorts: false, + minimumNotificationPeriod: 4, + pnoTypeName: 'Préavis type Z' + } + ], + port: 'BROIA', + predictedArrivalDatetimeUtc: tripStartDateAsDayjs.add(30, 'hours').format('YYYY-MM-DDTHH:mm:ss[Z]'), + predictedLandingDatetimeUtc: tripStartDateAsDayjs.add(31, 'hours').format('YYYY-MM-DDTHH:mm:ss[Z]'), + purpose: 'LAN', + riskFactor: 2.9, + tripStartDate: tripStartDateAsDayjs.format('YYYY-MM-DDTHH:mm:ss[Z]'), + updatedAt: null, + updatedBy: null + }, + vessel_name + }, + // We need to have the exact same props as the DAT report otherwise `sql()` batch insert will fail + { + cfr: null, + enriched: true, + flag_state: null, + id: 2 * FAKE_PNO_COUNT + index, + integration_datetime_utc: operation_datetime_utc, + log_type: null, + operation_datetime_utc, + operation_number: `${report_id}_RET`, + operation_type: 'RET', + referenced_report_id: report_id, + report_datetime_utc: null, + report_id: null, + transmission_format, + trip_gears: null, + trip_segments: null, + value: { + returnStatus: '000' + }, + vessel_name: null + } + ] +} + +function getFakeReporting(index) { + const vessel_id = faker.number.int({ max: FAKE_VESSEL_COUNT * 2, min: FAKE_VESSEL_COUNT + 1 }) + const internal_reference_number = `FAKCFR_${vessel_id}` + const vessel_name = `FAUX NAVIRE ${vessel_id}` + + const creationDate = dayjs( + faker.date.between({ + from: START_DATE, + to: END_DATE + }) + ) + + const type = faker.helpers.arrayElement(['ALERT', 'INFRACTION_SUSPICION', 'OBSERVATION']) + const value = + type === 'ALERT' + ? { + natinfCode: 7059, + riskFactor: faker.number.float({ max: 5, min: 0 }), + seaFront: faker.helpers.arrayElement(['MED', 'MEMN', 'NAMO', 'SA']), + type: 'THREE_MILES_TRAWLING_ALERT' + } + : { + authorContact: '', + authorTrigram: faker.string.alpha(3).toUpperCase(), + controlUnitId: null, + description: faker.lorem.sentence(), + dml: 'DML 29', + natinfCode: 23588, + reportingActor: faker.helpers.arrayElement(['OPS', 'UNIT']), + seaFront: faker.helpers.arrayElement(['MED', 'MEMN', 'NAMO', 'SA']), + title: faker.lorem.sentence(), + type + } + + return { + archived: false, + creation_date: creationDate.format('YYYY-MM-DD HH:mm:ss'), + deleted: false, + external_reference_number: null, + flag_state: 'FR', + id: FAKE_REPORTING_COUNT + index, + internal_reference_number, + ircs: null, + latitude: faker.location.latitude({ max: 51, min: 42, precision: 3 }), + longitude: faker.location.longitude({ max: 10, min: -7, precision: 3 }), + type, + validation_date: creationDate.add(2, 'hours').format('YYYY-MM-DD HH:mm:ss'), + value, + vessel_id, + vessel_identifier: 'INTERNAL_REFERENCE_NUMBER', + vessel_name + } +} + +function getFakeVessel(index) { + const id = FAKE_VESSEL_COUNT + index + + return { + cfr: `FAKCFR_${id}`, + flag_state: 'FR', + id, + length: 99, + vessel_name: `FAUX NAVIRE ${id}` + } +} + +const sql = postgres('postgres://postgres:postgres@localhost:5432/monitorfishdb') + +async function run() { + let batchIndex + const spinner = ora('Starting...').start() + + try { + // Ignore SQL notices + await sql`SET client_min_messages TO WARNING` + + spinner.text = 'Deleting fake vessels...' + await sql`DELETE FROM vessels WHERE id >= ${FAKE_VESSEL_COUNT + 1} AND id <= ${FAKE_VESSEL_COUNT * 2}` + spinner.succeed('Fake vessels successfully deleted.') + + spinner.start('Generating fake vessels...') + batchIndex = 1 + while (batchIndex <= FAKE_VESSEL_BATCH_COUNT) { + const startIndex = (batchIndex - 1) * BATCH_SIZE + 1 + const endIndex = batchIndex * BATCH_SIZE + spinner.text = `Generating fake vessels ${startIndex}->${endIndex} / ${FAKE_VESSEL_COUNT} (${Math.round((10000 * startIndex) / FAKE_VESSEL_COUNT) / 100}%)...` + + const fakeVessels = BATCH_SKELETON.map((_, index) => getFakeVessel(startIndex + index)) + await sql`INSERT INTO vessels ${sql(fakeVessels)}` + + batchIndex += 1 + } + spinner.succeed('Fake vessels successfully generated.') + + spinner.start('Deleting fake reportings...') + await sql`DELETE FROM reportings WHERE id >= ${FAKE_REPORTING_COUNT + 1} AND id <= ${FAKE_REPORTING_COUNT * 2}` + spinner.succeed('Fake reportings successfully deleted.') + + spinner.start('Generating fake reporting...') + batchIndex = 1 + while (batchIndex <= FAKE_REPORTING_BATCH_COUNT) { + const startIndex = (batchIndex - 1) * BATCH_SIZE + 1 + const endIndex = batchIndex * BATCH_SIZE + spinner.text = `Generating fake reportings ${startIndex}->${endIndex} / ${FAKE_REPORTING_COUNT} (${Math.round((10000 * startIndex) / FAKE_REPORTING_COUNT) / 100}%)...` + + const fakeReportings = BATCH_SKELETON.map((_, index) => getFakeReporting(startIndex + index)) + await sql`INSERT INTO reportings ${sql(fakeReportings)}` + + batchIndex += 1 + } + spinner.succeed('Fake reportings successfully generated.') + + spinner.start('Deleting fake PNO logbook reports...') + // Prevent TimescaleDB truncate cascade notices from spamming output (`truncate cascades to table "_hyper_2_135_chunk"`) + await sql`SET client_min_messages TO WARNING` + await sql`TRUNCATE TABLE logbook_raw_messages CASCADE` + await sql`TRUNCATE TABLE logbook_reports` + await sql`RESET client_min_messages` + spinner.succeed('Fake PNO logbook reports successfully deleted.') + + spinner.start('Generating fake PNO logbook report...') + batchIndex = 1 + while (batchIndex <= FAKE_PNO_BATCH_COUNT) { + const startIndex = (batchIndex - 1) * BATCH_SIZE + 1 + const endIndex = batchIndex * BATCH_SIZE + spinner.text = `Generating fake PNO logbook report ${startIndex}->${endIndex} / ${FAKE_PNO_COUNT} (${Math.round((10000 * startIndex) / FAKE_PNO_COUNT) / 100}%)...` + + const fakeLogbookRawMessages = BATCH_SKELETON.flatMap((_, index) => + getFakePnoLogbookRawMessages(startIndex + index) + ) + const fakeLogbookReports = BATCH_SKELETON.flatMap((_, index) => getFakePnoLogbookReports(startIndex + index)) + + spinner.text = `Generating fake PNO logbook report ${startIndex}->${endIndex} / ${FAKE_PNO_COUNT} (${Math.round((10000 * startIndex) / FAKE_PNO_COUNT) / 100}%) [RANDOMNESS CHECK: ${fakeLogbookReports[0].operation_datetime_utc}]...` + await sql`INSERT INTO logbook_raw_messages ${sql(fakeLogbookRawMessages)}` + await sql`INSERT INTO logbook_reports ${sql(fakeLogbookReports)}` + + batchIndex += 1 + } + spinner.succeed('Fake PNO logbook report successfully generated.') + } catch (error) { + spinner.fail('Failed to generate perf data.') + + console.error(error) + + process.exit(1) + } finally { + await sql.end() + } +} + +run()