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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


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

overrides:
- files:
Expand Down
4 changes: 4 additions & 0 deletions .prettierrc.json
@@ -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
Expand Up @@ -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"
Expand Down
262 changes: 143 additions & 119 deletions src/airtable-data.js
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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) => {
Expand Down
18 changes: 10 additions & 8 deletions src/enrichment.js
Expand Up @@ -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');
Expand All @@ -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')) {
Expand All @@ -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 = {
Expand Down
7 changes: 4 additions & 3 deletions src/replicate-incrementally.js
Expand Up @@ -38,7 +38,6 @@ async function run(configuration) {
name: table,
lastRecordIndex: lastRecordIndexTargetBeforeReplication,
});

}

logger.info('Start COPY FROM/TO through STDIN/OUT');
Expand All @@ -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);

Expand Down