Split parser and formatter in specific files

This commit is contained in:
Alexandre Bodin 2019-12-03 11:27:15 +01:00
parent 2dbad3fcde
commit 95c7a515d7
4 changed files with 145 additions and 82 deletions

View File

@ -0,0 +1,65 @@
'use strict';
const { isValid, format, formatISO } = require('date-fns');
const { has } = require('lodash');
const createFormatter = client => ({ type }, value) => {
if (value === null) return null;
const formatter = {
...defaultFormatter,
...formatters[client],
};
if (has(formatter, type)) {
return formatter[type](value);
}
return value;
};
const defaultFormatter = {
json: value => JSON.parse(value),
boolean: value => {
if (typeof value === 'boolean') {
return value;
}
const strVal = value.toString();
if (strVal === '1') {
return true;
} else if (strVal === '0') {
return false;
} else {
return null;
}
},
};
const formatters = {
sqlite3: {
date: value => {
const cast = new Date(value);
return isValid(cast) ? formatISO(cast, { representation: 'date' }) : null;
},
time: value => {
const cast = new Date(value);
return isValid(cast) ? formatISO(cast, { representation: 'time' }) : null;
},
datetime: value => {
const cast = new Date(value);
return isValid(cast) ? formatISO(cast) : null;
},
timestamp: value => {
const cast = new Date(value);
return isValid(cast) ? format(cast, 'T') : null;
},
biginteger: value => {
return value.toString();
},
},
};
module.exports = {
createFormatter,
};

View File

@ -1,7 +1,6 @@
'use strict';
const _ = require('lodash');
const { singular } = require('pluralize');
const dateFns = require('date-fns');
const utilsModels = require('strapi-utils').models;
const relations = require('./relations');
@ -10,6 +9,8 @@ const {
createComponentJoinTables,
createComponentModels,
} = require('./generate-component-relations');
const { createParser } = require('./parser');
const { createFormatter } = require('./formatter');
const populateFetch = require('./populate');
@ -457,12 +458,13 @@ module.exports = ({ models, target, plugin = false }, ctx) => {
// Call this callback function after we are done parsing
// all attributes for relationships-- see below.
const parseValue = createParser();
try {
// External function to map key that has been updated with `columnName`
const mapper = (params = {}) => {
Object.keys(params).map(key => {
const attr = definition.attributes[key] || {};
params[key] = castValueFromType(attr.type, params[key], definition);
params[key] = parseValue(attr.type, params[key], definition);
});
return _.mapKeys(params, (value, key) => {
@ -636,44 +638,11 @@ module.exports = ({ models, target, plugin = false }, ctx) => {
},
];
const formatValue = createFormatter(definition.client);
const formatter = attributes => {
Object.keys(attributes).forEach(key => {
const attr = definition.attributes[key] || {};
if (attributes[key] === null) return;
if (attr.type === 'json') {
attributes[key] = JSON.parse(attributes[key]);
}
if (attr.type === 'boolean') {
if (typeof attributes[key] === 'boolean') {
return;
}
const strVal = attributes[key].toString();
if (strVal === '1') {
attributes[key] = true;
} else if (strVal === '0') {
attributes[key] = false;
} else {
attributes[key] = null;
}
}
if (attr.type === 'date' && definition.client === 'sqlite3') {
const cast = dateFns.parseISO(attributes[key]);
attributes[key] = dateFns.isValid(cast)
? dateFns.format(cast, 'yyyy-MM-dd')
: null;
}
if (
attr.type === 'biginteger' &&
definition.client === 'sqlite3'
) {
attributes[key] = attributes[key].toString();
}
attributes[key] = formatValue(attr, attributes[key]);
});
};
@ -749,48 +718,3 @@ module.exports = ({ models, target, plugin = false }, ctx) => {
return Promise.all(updates);
};
const castValueFromType = (type, value /* definition */) => {
// do not cast null values
if (value === null) return null;
switch (type) {
case 'json':
return JSON.stringify(value);
case 'time': {
try {
dateFns.parse(value, 'HH:mm:ss', new Date());
} catch (error) {
throw new Error(`Invalid time format, expected a time HH:mm:ss`);
}
return value;
}
case 'date': {
try {
dateFns.parse(value, 'yyyy-MM-dd', new Date());
} catch (error) {
throw new Error(`Invalid date format, expected a date YYYY-MM-DD`);
}
return value;
}
case 'timestamp':
case 'datetime': {
const date = dateFns.parseISO(value);
if (dateFns.isValid(date)) return date;
date.setTime(value);
if (!dateFns.isValid(date)) {
throw new Error(
`Invalid ${type} format, expected a timestamp or an ISO date`
);
}
return date;
}
default:
return value;
}
};

View File

@ -0,0 +1,73 @@
'use strict';
const _ = require('lodash');
const { parse, isValid, parseISO } = require('date-fns');
const createParser = () => (type, value) => {
if (value === null) return null;
switch (type) {
case 'json':
return JSON.stringify(value);
case 'time':
return parseTime(value);
case 'date':
return parseDate(value);
case 'timestamp':
case 'datetime':
return parseDateTimeOrTimestamp(value);
default:
return value;
}
};
const parseDateOrThrow = format => value => {
try {
let date = parseISO(value);
if (isValid(date)) return date;
date = parse(value, format, new Date());
if (isValid(date)) {
return date;
} else {
throw new Error(`Invalid format, expected a ${format}`);
}
} catch (error) {
throw new Error(`Invalid format, expected a ${format}`);
}
};
const parseDateTimeOrTimestamp = value => {
const date = parseISO(value);
if (isValid(date)) return date;
date.setTime(value);
if (!isValid(date)) {
throw new Error(`Invalid format, expected a timestamp or an ISO date`);
}
return date;
};
const parseTime = value => {
const time = {
hours: 0,
minutes: 0,
seconds: 0,
secondsFraction: 0,
};
const padTime = t => _.padStart(t, 2, '0');
const hrs = padTime(time.hours);
const min = padeTime(time.minutes);
const seconds = padeTime(time.seconds);
return `${time}.${padFraction()}`;
};
const parseDate = parseDateOrThrow('yyyy-MM-dd');
module.exports = { createParser };

View File

@ -15,6 +15,7 @@ const typeToSize = type => {
case 'checkbox':
case 'boolean':
case 'date':
case 'time':
case 'biginteger':
case 'decimal':
case 'float':