@adonisjs/lucid
Version:
SQL ORM built on top of Active Record pattern
104 lines (103 loc) • 3.16 kB
JavaScript
/*
* @adonisjs/lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { DateTime } from 'luxon';
import * as errors from '../../errors.js';
/**
* The method to prepare the datetime column before persisting it's
* value to the database
*/
function prepareDateTimeColumn(value, attributeName, modelInstance) {
/**
* Return string or missing values as it is. If `auto` is set to true on
* the column, then the hook will always initialize the date
*/
if (typeof value === 'string' || !value) {
return value;
}
const model = modelInstance.constructor;
const modelName = model.name;
/**
* Format luxon instances to SQL formatted date
*/
if (DateTime.isDateTime(value)) {
if (!value.isValid) {
throw new errors.E_INVALID_DATE_COLUMN_VALUE([
`${modelName}.${attributeName}`,
value.invalidReason,
]);
}
const dateTimeFormat = model.query(modelInstance.$options).client.dialect.dateTimeFormat;
return value.toFormat(dateTimeFormat);
}
/**
* Anything else if not an acceptable value for date column
*/
throw new errors.E_INVALID_DATE_COLUMN_VALUE([
`${modelName}.${attributeName}`,
'It must be an instance of "luxon.DateTime"',
]);
}
/**
* Consume database return value and convert it to an instance of luxon.DateTime
*/
function consumeDateTimeColumn(value, attributeName, modelInstance) {
/**
* Bypass null columns
*/
if (!value) {
return value;
}
/**
* Convert from string
*/
if (typeof value === 'string') {
return DateTime.fromSQL(value);
}
/**
* Convert from date
*/
if (value instanceof Date) {
return DateTime.fromJSDate(value);
}
/**
* Any another value cannot be formatted
*/
const modelName = modelInstance.constructor.name;
throw new errors.E_INVALID_DATE_COLUMN_VALUE([
`${modelName}.${attributeName}`,
`${typeof value} cannot be formatted`,
]);
}
/**
* Decorator to define a new date time column
*/
export const dateTimeColumn = (options) => {
return function decorateAsColumn(target, property) {
const Model = target.constructor;
Model.boot();
const normalizedOptions = Object.assign({
prepare: prepareDateTimeColumn,
consume: consumeDateTimeColumn,
serialize: (value) => {
if (DateTime.isDateTime(value)) {
return value.toISO();
}
return value;
},
meta: {},
}, options);
/**
* Type always has to be a datetime
*/
normalizedOptions.meta.type = 'datetime';
normalizedOptions.meta.autoCreate = normalizedOptions.autoCreate === true;
normalizedOptions.meta.autoUpdate = normalizedOptions.autoUpdate === true;
Model.$addColumn(property, normalizedOptions);
};
};