Skip to content

Commit

Permalink
Meta 6 US4: Importar CSV para a tabela students (#9)
Browse files Browse the repository at this point in the history
Meta 6 US4: Importar CSV para a tabela students
  • Loading branch information
lubien authored May 8, 2019
2 parents 332d734 + 398b0c0 commit 8a8c92d
Show file tree
Hide file tree
Showing 3 changed files with 407 additions and 1 deletion.
9 changes: 8 additions & 1 deletion migrations/20190506212942_students.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ exports.up = function(knex, Promise) {
return knex.schema.createTable('students', table => {
table.increments('id').primary()
table.string('name').notNullable()
table.string('registrationNumber').notNullable()
table
.string('registrationNumber')
.notNullable()
.unique()
table.float('crg').nullable()
table.string('course').notNullable()
table.string('email').nullable()
Expand All @@ -18,6 +21,10 @@ exports.up = function(knex, Promise) {
.boolean('isActive')
.notNullable()
.defaultTo(false)
table
.boolean('isForming')
.notNullable()
.defaultTo(false)
table
.boolean('isGraduating')
.notNullable()
Expand Down
163 changes: 163 additions & 0 deletions server/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
const { knex } = require('./db')
/**
* Given a CSV file with header make an Array of objects
*
* @param {string} str - CSV String
* @return {object[]} An object based on the CSV
*
* @example
*
* const csv = `a,b,c
* 1,2,3`
* parseCsv(csv) // [ { a: 1, b: 2, c: 3 } ]
*/
export function parseCsv(str) {
const lines = str.split('\n')
const [head, ...items] = lines

const headerItens = head.split(',')
return items.map(item =>
item.split(',').reduce((acc, value, i) => {
const prop = headerItens[i]
acc[prop] = value
return acc
}, {})
)
}

/**
* Convert an object from SIGAA's CSV (see parseCsv) into
* proper objects to insert in the table students.
*
* @param {object[]} data - Array of objects from SIGAA's CSV
* @return {object[]} Array of objects ready to insert in the database
*
* @example
*
* const csv = `Matrícula,AnoIngresso,Nome,CPF,DataNascimento,NomeMae,Municipio,Curso,Status
* 201704940001,2017,FELIPE SOUZA FERREIRA,111.111.111-11,1/29/1995,VITORIA DIAS ROCHA,Belém,CIENCIA DA COMPUTACAO,ATIVO`
* const data = parseCsv(csv)
* digestSigaaData(data)
* // [{
* // name: 'FELIPE SOUZA FERREIRA',
* // course: 'cbcc',
* // registrationNumber: '201704940001',
* // isFit: false,
* // isConcluding: false,
* // isActive: true,
* // evidence: false,
* // isForming: false,
* // isGraduating: false,
* // academicHighlight: false,
* // cancelled: false,
* // prescribed: false
* // }]
*/
export function digestSigaaData(data) {
function getCourse(student) {
return student.Curso === 'CIENCIA DA COMPUTACAO' ? 'cbcc' : 'cbsi'
}

function getName(student) {
return student.Nome
}

function getRegistrationNumber(student) {
return student['Matrícula']
}

function getFlags(student) {
const base = {
isFit: false,
isConcluding: false,
isActive: true,
evidence: false,
isForming: false,
isGraduating: false,
academicHighlight: false,
cancelled: false,
prescribed: false
}

const translateStatus = {
FORMANDO: 'isForming',
// We have no evidence GRADUANDO is the real string (Issue #8)
GRADUANDO: 'isGraduating',
CONCLUÍDO: 'isConcluding',
CANCELADO: 'cancelled'
}

const keyToOpen = translateStatus[student.Status]
if (keyToOpen) {
base[keyToOpen] = true
}

const inactive = base.isConcluding || base.cancelled
if (inactive) {
base.isActive = false
}

return base
}

return data.map(student => ({
name: getName(student),
course: getCourse(student),
registrationNumber: getRegistrationNumber(student),
...getFlags(student)
}))
}

/**
* Batch upsert (insert new, update old) student data
*
* @param {object[]} data - Valid objects of student rows
* @return {Promise} Knex promise
*
* @example
*
*
* const csv = `Matrícula,AnoIngresso,Nome,CPF,DataNascimento,NomeMae,Municipio,Curso,Status
* 201704940001,2017,FELIPE SOUZA FERREIRA,111.111.111-11,1/29/1995,VITORIA DIAS ROCHA,Belém,CIENCIA DA COMPUTACAO,ATIVO`
* const data = parseCsv(csv)
* const digested = digestSigaaData(data)
* await batchUpdateStudents(digested)
*/
export function batchUpdateStudents(data) {
const query = `
INSERT INTO
students (name, registrationNumber, course, isFit, isConcluding, isActive, isForming, isGraduating, academicHighlight, cancelled, prescribed)
VALUES
${data.map(() => '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').join(', ')}
ON CONFLICT
(registrationNumber)
DO UPDATE SET
course = excluded.course,
isFit = excluded.isFit,
isConcluding = excluded.isConcluding,
isActive = excluded.isActive,
isForming = excluded.isForming,
isGraduating = excluded.isGraduating,
academicHighlight = excluded.academicHighlight,
cancelled = excluded.cancelled,
prescribed = excluded.prescribed
`

const bindings = data
.map(student => [
student.name,
student.registrationNumber,
student.course,
student.isFit,
student.isConcluding,
student.isActive,
student.isForming,
student.isGraduating,
student.academicHighlight,
student.cancelled,
student.prescribed
])
.reduce((acc, x) => acc.concat(x), [])

return knex.raw(query, bindings)
}
Loading

0 comments on commit 8a8c92d

Please sign in to comment.