stackpress
Version:
Incept is a content management framework.
180 lines (179 loc) • 6.22 kB
JavaScript
import Exception from '../Exception.js';
export const stringable = ['String', 'Text', 'Json', 'Object', 'Hash'];
export const floatable = ['Number', 'Float'];
export const dateable = ['Date', 'Time', 'Datetime'];
export const boolable = ['Boolean'];
export const intable = ['Integer'];
export function toErrorResponse(e, code = 400) {
if (typeof e.toResponse !== 'function') {
e = Exception.upgrade(e, code);
}
const error = e;
return error.toResponse();
}
;
export function toResponse(results, total) {
if (typeof total === 'number') {
return { code: 200, status: 'OK', results, total: total };
}
return { code: 200, status: 'OK', results };
}
;
export function toSqlString(value, strict = false) {
if (typeof value === 'undefined') {
return (strict ? '' : undefined);
}
else if (value === null) {
return (strict ? '' : null);
}
else if (typeof value === 'object') {
return JSON.stringify(value);
}
return value.toString();
}
export function toSqlBoolean(value, strict = false) {
if (typeof value === 'undefined') {
return (strict ? false : undefined);
}
else if (value === null) {
return (strict ? false : null);
}
return Boolean(value);
}
export function toSqlDate(value, strict = false) {
if (!strict) {
if (typeof value === 'undefined') {
return undefined;
}
else if (value === null) {
return null;
}
}
let date = value instanceof Date ? value : new Date(value);
if (isNaN(date.getTime())) {
date = new Date(0);
}
return date;
}
export function toSqlInteger(value, strict = false) {
if (typeof value === 'undefined') {
return (strict ? 0 : undefined);
}
else if (value === null) {
return (strict ? 0 : null);
}
return (parseInt(value) || 0);
}
export function toSqlFloat(value, strict = false) {
if (typeof value === 'undefined') {
return (strict ? 0 : undefined);
}
else if (value === null) {
return (strict ? 0 : null);
}
return (parseFloat(value) || 0);
}
export function sequence(models) {
const sequence = [];
while (sequence.length < models.length) {
const floating = models.filter(model => !sequence.find(order => order.name === model.name));
for (const model of floating) {
const dependents = floating.filter(float => float.relations
.map(column => column.type)
.find(table => table === model.name));
if (!dependents.length) {
sequence.push(model);
}
}
}
return sequence;
}
export function getColumns(column, model, prefixes = []) {
if (column === '*') {
const columns = [];
model.columns.forEach(column => {
if (column.model) {
return;
}
const prefix = prefixes.length > 0 ? prefixes.join('.') + '.' : '';
columns.push(`${prefix}${column.name}`);
});
return columns;
}
const path = column.split('.');
if (path.length > 1) {
const column = model.columns.get(path[0]);
if (column && column.model) {
return getColumns(path.slice(1).join('.'), column.model, [...prefixes, path[0]]);
}
}
if (prefixes.length > 0) {
return [`${prefixes.join('.')}.${column}`];
}
return [column];
}
export function getColumnInfo(selector, model) {
const name = selector;
const table = getAlias(selector.substring(0, selector.lastIndexOf('.')));
const column = getAlias(selector.substring(selector.lastIndexOf('.') + 1));
const alias = getAlias(selector);
const path = getColumnPath(selector, model);
const last = path[path.length - 1];
const joins = getColumnJoins(selector, model);
return { name, table, column, alias, path, last, joins };
}
export function getColumnPath(selector, model, path = []) {
const selectors = selector.split('.');
const column = model.columns.get(selectors[0]);
if (!column) {
return [];
}
else if (selectors.length === 1) {
return path.concat([{ model, column }]);
}
if (!column.model) {
return [];
}
return getColumnPath(selectors.slice(1).join('.'), column.model, path.concat([{ model, column }]));
}
export function getColumnJoins(selector, model, index = 0, joins = {}) {
const selectors = selector.split('.');
if (selectors.length === (index + 1)) {
return joins;
}
const alias = {
parent: getAlias(selectors.slice(0, index).join('.')),
child: getAlias(selectors.slice(0, index + 1).join('.'))
};
if (alias.parent.length > 0) {
alias.parent += '.';
}
const column = model.columns.get(selectors[index]);
if (column?.relation) {
const relation = column.relation;
const table = relation.parent.model.snake;
const from = `${alias.parent}${relation.child.key.snake}`;
const to = `${alias.child}.${relation.parent.key.snake}`;
const key = `INNER JOIN ${table} AS ${alias.child} ON (${from} = ${to})`;
joins[key] = { table, from, to, alias: alias.child };
return getColumnJoins(selector, relation.parent.model, index + 1, joins);
}
else if (column?.related && !column?.related.parent.column.multiple) {
const related = column.related;
const table = related.child.model.snake;
const aliasParent = alias.parent || `${related.parent.model.snake}.`;
const from = `${aliasParent}${related.parent.key.snake}`;
const to = `${alias.child}.${related.child.key.snake}`;
const key = `INNER JOIN ${table} AS ${alias.child} ON (${from} = ${to})`;
joins[key] = { table, from, to, alias: alias.child };
return getColumnJoins(selector, related.child.model, index + 1, joins);
}
return {};
}
export function getAlias(selector) {
return selector.split('.').map(part => part.trim()
.replace(/([a-z])([A-Z0-9])/g, '$1_$2')
.replace(/-{2,}/g, '_')
.replace(/^_+|_+$/g, '')
.toLowerCase()).join('__');
}