Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TECH] Formater le code avec Prettier. #104

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintrc.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
extends: 'eslint:recommended'
extends:
- 'eslint:recommended'
- 'plugin:prettier/recommended'

overrides:
- files:
4 changes: 4 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"printWidth": 120,
"singleQuote": true
}
415 changes: 216 additions & 199 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -48,14 +48,17 @@
"devDependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^7.17.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-yaml": "^0.3.0",
"husky": "^4.3.7",
"mocha": "^8.2.1",
"nock": "^13.0.5",
"pg-connection-string": "^2.4.0",
"prettier": "^2.4.1",
"proxyquire": "^2.1.3",
"sinon": "^9.2.3",
"tmp-promise": "^3.0.2"
262 changes: 143 additions & 119 deletions src/airtable-data.js
Original file line number Diff line number Diff line change
@@ -5,121 +5,139 @@ const _ = require('lodash');
const format = require('pg-format');
const { runDBOperation } = require('./db-connection');

const tables = [{
name: 'areas',
airtableName: 'Domaines',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
],
airtableId: 'id persistant',
indices: [],
}, {
name: 'attachments',
airtableName: 'Attachments',
fields: [
{ name: 'type', type: 'text', airtableName: 'type' },
{ name: 'challengeId', type: 'text', airtableName: 'challengeId persistant' },
{ name: 'alt', type: 'text', airtableName: 'alt' },
{ name: 'url', type: 'text', airtableName: 'url' },
{ name: 'size', type: 'numeric', airtableName: 'size' },
],
airtableId: 'Record ID',
indices: [],
}, {
name: 'competences',
airtableName: 'Competences',
fields: [
{ name: 'name', type: 'text', airtableName: 'Référence' },
{ name: 'code', type: 'text', airtableName: 'Sous-domaine' },
{ name: 'title', type: 'text', airtableName: 'Titre fr-fr' },
{ name: 'origin', type: 'text', airtableName: 'Origine' },
{ name: 'areaId', type: 'text', airtableName: 'Domaine (id persistant)', isArray: false },
],
airtableId: 'id persistant',
indices: ['areaId'],
}, {
name: 'tubes',
airtableName: 'Tubes',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
{ name: 'title', type: 'text', airtableName: 'Titre' },
{ name: 'competenceId', type: 'text', airtableName: 'Competences (id persistant)', isArray: false },
],
airtableId: 'id persistant',
indices: ['competenceId'],
}, {
name: 'skills',
airtableName: 'Acquis',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
{ name: 'description', type: 'text', airtableName: 'Description' },
{ name: 'level', type: 'smallint', airtableName: 'Level' },
{ name: 'tubeId', type: 'text', airtableName: 'Tube (id persistant)', isArray: false },
{ name: 'status', type: 'text', airtableName: 'Status' },
{ name: 'pixValue', type: 'numeric(6,5)', airtableName: 'PixValue' },
{ name: 'hintStatus', type: 'text', airtableName: 'Statut de l\'indice' },
{ name: 'tutorialIds', type: 'text []', airtableName: 'Comprendre (id persistant)', isArray: true },
{ name: 'learningMoreTutorialIds', type: 'text []', airtableName: 'En savoir plus (id persistant)', isArray: true },
{ name: 'internationalization', type: 'text', airtableName: 'Internationalisation' },
],
airtableId: 'id persistant',
indices: ['tubeId'],
}, {
name: 'challenges',
airtableName: 'Epreuves',
fields: [
{ name: 'instructions', type: 'text', airtableName: 'Consigne' },
{ name: 'status', type: 'text', airtableName: 'Statut' },
{ name: 'type', type: 'text', airtableName: 'Type d\'épreuve' },
{ name: 'timer', type: 'smallint', airtableName: 'Timer' },
{ name: 'autoReply', type: 'boolean', airtableName: 'Réponse automatique' },
{ name: 'skillIds', type: 'text []', airtableName: 'Acquix (id persistant)', isArray: true },
{ name: 'skillCount', type: 'smallint', extractor: (record) => _.size(record.get('Acquix (id persistant)')) },
{ name: 'firstSkillId', type: 'text', extractor: (record) => _.get(record.get('Acquix (id persistant)'), 0) },
{ name: 'secondSkillId', type: 'text', extractor: (record) => _.get(record.get('Acquix (id persistant)'), 1) },
{ name: 'thirdSkillId', type: 'text', extractor: (record) => _.get(record.get('Acquix (id persistant)'), 2) },
{ name: 'languages', type: 'text []', airtableName: 'Langues', isArray: true },
{ name: 'embedUrl', type: 'text', airtableName: 'Embed URL' },
{ name: 'hasEmbedUrl', type: 'boolean', extractor: (record) => !!record.get('Embed URL') },
{ name: 'alternativeInstruction', type: 'text', airtableName: 'Consigne alternative' },
{ name: 'hasAlternativeInstruction', type: 'boolean', extractor: (record) => !!record.get('Consigne alternative') },
{ name: 'area', type: 'text', airtableName: 'Géographie' },
{ name: 'focus', type: 'boolean', airtableName: 'Focalisée' },
{ name: 'explicativeResponse', type: 'text', airtableName: 'Bonnes réponses à afficher' },
],
airtableId: 'id persistant',
indices: ['firstSkillId'],
}, {
name: 'courses',
airtableName: 'Tests',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
{ name: 'adaptive', type: 'boolean', airtableName: 'Adaptatif ?' },
{ name: 'competenceId', type: 'text', airtableName: 'Competence (id persistant)', isArray: false },
],
airtableId: 'id persistant',
indices: ['competenceId'],
}, {
name: 'tutorials',
airtableName: 'Tutoriels',
fields: [
{ name: 'title', type: 'text', airtableName: 'Titre' },
{ name: 'link', type: 'text', airtableName: 'Lien' },
{ name: 'tutorialForSkills', type: 'text []', airtableName: 'Solution à', isArray: true },
{ name: 'furtherInformation', type: 'text []', airtableName: 'En savoir plus', isArray: true },
{ name: 'locale', type: 'text', airtableName: 'Langue' },
],
airtableId: 'id persistant',
indices: ['title'],
}];
const tables = [
{
name: 'areas',
airtableName: 'Domaines',
fields: [{ name: 'name', type: 'text', airtableName: 'Nom' }],
airtableId: 'id persistant',
indices: [],
},
{
name: 'attachments',
airtableName: 'Attachments',
fields: [
{ name: 'type', type: 'text', airtableName: 'type' },
{ name: 'challengeId', type: 'text', airtableName: 'challengeId persistant' },
{ name: 'alt', type: 'text', airtableName: 'alt' },
{ name: 'url', type: 'text', airtableName: 'url' },
{ name: 'size', type: 'numeric', airtableName: 'size' },
],
airtableId: 'Record ID',
indices: [],
},
{
name: 'competences',
airtableName: 'Competences',
fields: [
{ name: 'name', type: 'text', airtableName: 'Référence' },
{ name: 'code', type: 'text', airtableName: 'Sous-domaine' },
{ name: 'title', type: 'text', airtableName: 'Titre fr-fr' },
{ name: 'origin', type: 'text', airtableName: 'Origine' },
{ name: 'areaId', type: 'text', airtableName: 'Domaine (id persistant)', isArray: false },
],
airtableId: 'id persistant',
indices: ['areaId'],
},
{
name: 'tubes',
airtableName: 'Tubes',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
{ name: 'title', type: 'text', airtableName: 'Titre' },
{ name: 'competenceId', type: 'text', airtableName: 'Competences (id persistant)', isArray: false },
],
airtableId: 'id persistant',
indices: ['competenceId'],
},
{
name: 'skills',
airtableName: 'Acquis',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
{ name: 'description', type: 'text', airtableName: 'Description' },
{ name: 'level', type: 'smallint', airtableName: 'Level' },
{ name: 'tubeId', type: 'text', airtableName: 'Tube (id persistant)', isArray: false },
{ name: 'status', type: 'text', airtableName: 'Status' },
{ name: 'pixValue', type: 'numeric(6,5)', airtableName: 'PixValue' },
{ name: 'hintStatus', type: 'text', airtableName: 'Statut de l\'indice' },
{ name: 'tutorialIds', type: 'text []', airtableName: 'Comprendre (id persistant)', isArray: true },
{
name: 'learningMoreTutorialIds',
type: 'text []',
airtableName: 'En savoir plus (id persistant)',
isArray: true,
},
{ name: 'internationalization', type: 'text', airtableName: 'Internationalisation' },
],
airtableId: 'id persistant',
indices: ['tubeId'],
},
{
name: 'challenges',
airtableName: 'Epreuves',
fields: [
{ name: 'instructions', type: 'text', airtableName: 'Consigne' },
{ name: 'status', type: 'text', airtableName: 'Statut' },
{ name: 'type', type: 'text', airtableName: 'Type d\'épreuve' },
{ name: 'timer', type: 'smallint', airtableName: 'Timer' },
{ name: 'autoReply', type: 'boolean', airtableName: 'Réponse automatique' },
{ name: 'skillIds', type: 'text []', airtableName: 'Acquix (id persistant)', isArray: true },
{ name: 'skillCount', type: 'smallint', extractor: (record) => _.size(record.get('Acquix (id persistant)')) },
{ name: 'firstSkillId', type: 'text', extractor: (record) => _.get(record.get('Acquix (id persistant)'), 0) },
{ name: 'secondSkillId', type: 'text', extractor: (record) => _.get(record.get('Acquix (id persistant)'), 1) },
{ name: 'thirdSkillId', type: 'text', extractor: (record) => _.get(record.get('Acquix (id persistant)'), 2) },
{ name: 'languages', type: 'text []', airtableName: 'Langues', isArray: true },
{ name: 'embedUrl', type: 'text', airtableName: 'Embed URL' },
{ name: 'hasEmbedUrl', type: 'boolean', extractor: (record) => !!record.get('Embed URL') },
{ name: 'alternativeInstruction', type: 'text', airtableName: 'Consigne alternative' },
{
name: 'hasAlternativeInstruction',
type: 'boolean',
extractor: (record) => !!record.get('Consigne alternative'),
},
{ name: 'area', type: 'text', airtableName: 'Géographie' },
{ name: 'focus', type: 'boolean', airtableName: 'Focalisée' },
{ name: 'explicativeResponse', type: 'text', airtableName: 'Bonnes réponses à afficher' },
],
airtableId: 'id persistant',
indices: ['firstSkillId'],
},
{
name: 'courses',
airtableName: 'Tests',
fields: [
{ name: 'name', type: 'text', airtableName: 'Nom' },
{ name: 'adaptive', type: 'boolean', airtableName: 'Adaptatif ?' },
{ name: 'competenceId', type: 'text', airtableName: 'Competence (id persistant)', isArray: false },
],
airtableId: 'id persistant',
indices: ['competenceId'],
},
{
name: 'tutorials',
airtableName: 'Tutoriels',
fields: [
{ name: 'title', type: 'text', airtableName: 'Titre' },
{ name: 'link', type: 'text', airtableName: 'Lien' },
{ name: 'tutorialForSkills', type: 'text []', airtableName: 'Solution à', isArray: true },
{ name: 'furtherInformation', type: 'text []', airtableName: 'En savoir plus', isArray: true },
{ name: 'locale', type: 'text', airtableName: 'Langue' },
],
airtableId: 'id persistant',
indices: ['title'],
},
];

async function fetchAndSaveData(configuration) {
await Promise.all(tables.map(async (table) => {
const data = await _getItems(table, configuration);
await _dropTable(table.name, configuration);
await _createTable(table, configuration);
await _saveItems(table, data, configuration);
}));
await Promise.all(
tables.map(async (table) => {
const data = await _getItems(table, configuration);
await _dropTable(table.name, configuration);
await _createTable(table, configuration);
await _saveItems(table, data, configuration);
}),
);
}

async function _dropTable(tableName, configuration) {
@@ -131,9 +149,13 @@ async function _dropTable(tableName, configuration) {

async function _createTable(table, configuration) {
await runDBOperation(async (client) => {
const fieldsText = ['"id" text PRIMARY KEY'].concat(table.fields.map((field) => {
return format('\t%I\t%s', field.name, field.type + (field.type === 'boolean' ? ' NOT NULL' : ''));
})).join(',\n');
const fieldsText = ['"id" text PRIMARY KEY']
.concat(
table.fields.map((field) => {
return format('\t%I\t%s', field.name, field.type + (field.type === 'boolean' ? ' NOT NULL' : ''));
}),
)
.join(',\n');
const createQuery = format('CREATE TABLE %I (%s)', table.name, fieldsText);
await client.query(createQuery);
for (const index of table.indices) {
@@ -165,9 +187,11 @@ async function _getItems(structure, configuration) {
if (structure.airtableId) {
airtableFields.push(structure.airtableId);
}
const records = await base(structure.airtableName).select({
fields: airtableFields,
}).all();
const records = await base(structure.airtableName)
.select({
fields: airtableFields,
})
.all();
return records.map((record) => {
const item = { id: record.get(structure.airtableId) || record.getId() };
fields.forEach((field) => {
18 changes: 10 additions & 8 deletions src/enrichment.js
Original file line number Diff line number Diff line change
@@ -9,15 +9,17 @@ async function add(configuration) {
const tablesToNotBeEnriched = _getTablesToNotBeEnriched(configuration);
if (!tablesToNotBeEnriched.includes('knowledge-elements')) {
logger.info('CREATE INDEX "knowledge-elements_createdAt_idx" - Started');
await client.query('CREATE INDEX "knowledge-elements_createdAt_idx" on "knowledge-elements" (cast("createdAt" AT TIME ZONE \'UTC+1\' as date) DESC)');
await client.query(
'CREATE INDEX "knowledge-elements_createdAt_idx" on "knowledge-elements" (cast("createdAt" AT TIME ZONE \'UTC+1\' as date) DESC)',
);
logger.info('CREATE INDEX "knowledge-elements_createdAt_idx" - Ended');

}
if (!tablesToNotBeEnriched.includes('knowledge-element-snapshots')) {
logger.info('CREATE INDEX "knowledge-element-snapshots_snappedAt_idx" - Started');
await client.query('CREATE INDEX "knowledge-element-snapshots_snappedAt_idx" on "knowledge-element-snapshots" (cast("snappedAt" AT TIME ZONE \'UTC+1\' as date) DESC)');
await client.query(
'CREATE INDEX "knowledge-element-snapshots_snappedAt_idx" on "knowledge-element-snapshots" (cast("snappedAt" AT TIME ZONE \'UTC+1\' as date) DESC)',
);
logger.info('CREATE INDEX "knowledge-element-snapshots_snappedAt_idx" - Ended');

}
if (!tablesToNotBeEnriched.includes('answers')) {
logger.info('CREATE INDEX "answers_challengeId_idx" - Started');
@@ -27,7 +29,9 @@ async function add(configuration) {

if (!tablesToNotBeEnriched.includes('users')) {
logger.info('CREATE INDEX "users_createdAt_idx" - Started');
await client.query('CREATE INDEX "users_createdAt_idx" on "users" (cast("createdAt" AT TIME ZONE \'UTC+1\' as date) DESC)');
await client.query(
'CREATE INDEX "users_createdAt_idx" on "users" (cast("createdAt" AT TIME ZONE \'UTC+1\' as date) DESC)',
);
logger.info('CREATE INDEX "users_createdAt_idx" - Ended');
}
if (!tablesToNotBeEnriched.includes('schooling-registrations')) {
@@ -40,9 +44,7 @@ async function add(configuration) {

function _getTablesToNotBeEnriched(configuration) {
const tablePairs = toPairs(configuration.BACKUP_MODE);
return tablePairs
.filter(([_, mode]) => mode === 'incremental' || mode === 'none')
.map(([tableName, _]) => tableName);
return tablePairs.filter(([_, mode]) => mode === 'incremental' || mode === 'none').map(([tableName, _]) => tableName);
}

module.exports = {
7 changes: 4 additions & 3 deletions src/replicate-incrementally.js
Original file line number Diff line number Diff line change
@@ -38,7 +38,6 @@ async function run(configuration) {
name: table,
lastRecordIndex: lastRecordIndexTargetBeforeReplication,
});

}

logger.info('Start COPY FROM/TO through STDIN/OUT');
@@ -55,15 +54,17 @@ async function run(configuration) {
`\\copy ${escapeSQLIdentifier(table.name)} from stdin`,
];
const copyToStdOutProcess = execa('psql', copyToStdOutArgs, {
stdin: 'ignore', stdout: 'pipe', stderr: 'inherit',
stdin: 'ignore',
stdout: 'pipe',
stderr: 'inherit',
buffer: false, // disable execa's buffering otherwise it interferes with the transfer
});
const copyFromStdInProcess = execa('psql', copyFromStdInArgs, {
stdin: copyToStdOutProcess.stdout,
all: true, // join stdout and stderr
});

const [ , copyFromStdInResult ] = await Promise.all([ copyToStdOutProcess, copyFromStdInProcess ]);
const [, copyFromStdInResult] = await Promise.all([copyToStdOutProcess, copyFromStdInProcess]);

logger.info(`${table.name} table copy returned: ` + copyFromStdInResult.all);

Loading