2021-06-02 15:53:22 +02:00
|
|
|
'use strict';
|
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
const types = require('../types');
|
|
|
|
|
|
|
|
const createColumn = (name, attribute) => {
|
|
|
|
const { type, args = [], ...opts } = getColumnType(attribute);
|
|
|
|
|
|
|
|
return {
|
|
|
|
name,
|
|
|
|
type,
|
|
|
|
args,
|
|
|
|
...opts,
|
|
|
|
...(attribute.column || {}),
|
|
|
|
// TODO: allow passing custom params to the DB from the model definition
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const shouldCreateColumn = attribute => {
|
|
|
|
return types.isScalar(attribute.type);
|
|
|
|
};
|
|
|
|
|
|
|
|
const createTable = meta => {
|
|
|
|
const table = {
|
|
|
|
// TODO: allow passing custom params to the DB from the model definition
|
|
|
|
name: meta.tableName,
|
|
|
|
indexes: meta.indexes || [],
|
|
|
|
foreignKeys: meta.foreignKeys || [],
|
|
|
|
columns: [],
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const key in meta.attributes) {
|
|
|
|
const attribute = meta.attributes[key];
|
|
|
|
|
|
|
|
if (types.isRelation(attribute.type)) {
|
2021-07-26 17:52:59 +02:00
|
|
|
if (attribute.morphColumn && attribute.owner) {
|
|
|
|
const { idColumn, typeColumn } = attribute.morphColumn;
|
|
|
|
|
|
|
|
table.columns.push(
|
|
|
|
createColumn(idColumn.name, {
|
|
|
|
type: 'integer',
|
2021-08-10 09:36:02 +02:00
|
|
|
column: {
|
|
|
|
unsigned: true,
|
|
|
|
},
|
2021-07-26 17:52:59 +02:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
2021-08-10 09:36:02 +02:00
|
|
|
table.columns.push(createColumn(typeColumn.name, { type: 'string' }));
|
2021-07-26 17:52:59 +02:00
|
|
|
} else if (attribute.joinColumn && attribute.owner) {
|
|
|
|
// NOTE: we could pass uniquness for oneToOne to avoid creating more than one to one
|
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
const { name: columnName, referencedColumn, referencedTable } = attribute.joinColumn;
|
2021-07-30 20:45:51 +02:00
|
|
|
|
2021-08-10 09:36:02 +02:00
|
|
|
const column = createColumn(columnName, {
|
|
|
|
type: 'integer',
|
|
|
|
column: {
|
2021-06-17 16:17:15 +02:00
|
|
|
unsigned: true,
|
2021-08-10 09:36:02 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
table.columns.push(column);
|
2021-06-17 16:17:15 +02:00
|
|
|
|
|
|
|
table.foreignKeys.push({
|
2021-08-10 09:36:02 +02:00
|
|
|
name: `${table.name}_${columnName}_fk`,
|
2021-06-17 16:17:15 +02:00
|
|
|
columns: [columnName],
|
|
|
|
referencedTable,
|
|
|
|
referencedColumns: [referencedColumn],
|
2021-08-10 09:36:02 +02:00
|
|
|
// NOTE: could allow configuration
|
|
|
|
onDelete: 'SET NULL',
|
2021-06-17 16:17:15 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if (shouldCreateColumn(attribute)) {
|
|
|
|
const column = createColumn(key, meta.attributes[key]);
|
|
|
|
|
|
|
|
if (column.unique) {
|
|
|
|
table.indexes.push({
|
2021-06-02 15:53:22 +02:00
|
|
|
type: 'unique',
|
2021-06-17 16:17:15 +02:00
|
|
|
name: `${table.name}_${column.name}_unique`,
|
|
|
|
columns: [column.name],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (column.primary) {
|
|
|
|
table.indexes.push({
|
2021-06-02 15:53:22 +02:00
|
|
|
type: 'primary',
|
2021-06-17 16:17:15 +02:00
|
|
|
name: `${table.name}_${column.name}_primary`,
|
|
|
|
columns: [column.name],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
table.columns.push(column);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return table;
|
2021-06-02 15:53:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const getColumnType = attribute => {
|
|
|
|
if (attribute.columnType) {
|
|
|
|
return attribute.columnType;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (attribute.type) {
|
2021-06-17 16:17:15 +02:00
|
|
|
case 'increments': {
|
|
|
|
return { type: 'increments', args: [{ primary: true }] };
|
|
|
|
}
|
|
|
|
// We might want to convert email/password to string types before going into the orm with specific validators & transformers
|
2021-06-02 15:53:22 +02:00
|
|
|
case 'password':
|
|
|
|
case 'email':
|
2021-06-17 16:17:15 +02:00
|
|
|
case 'string': {
|
|
|
|
return { type: 'string' };
|
|
|
|
}
|
|
|
|
case 'uid': {
|
|
|
|
return {
|
|
|
|
type: 'string',
|
|
|
|
unique: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
case 'richtext':
|
|
|
|
case 'text': {
|
|
|
|
return {
|
|
|
|
type: 'text',
|
|
|
|
args: ['longtext'],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
case 'json': {
|
2021-06-29 16:27:35 +02:00
|
|
|
return { type: 'jsonb' };
|
2021-06-17 16:17:15 +02:00
|
|
|
}
|
|
|
|
case 'enumeration': {
|
2021-06-17 19:51:35 +02:00
|
|
|
return {
|
|
|
|
type: 'enum',
|
|
|
|
args: [
|
|
|
|
attribute.enum /*,{ useNative: true, existingType: true, enumName: 'foo_type', schemaName: 'public' }*/,
|
|
|
|
],
|
|
|
|
};
|
2021-06-17 16:17:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'integer': {
|
|
|
|
return { type: 'integer' };
|
|
|
|
}
|
|
|
|
case 'biginteger': {
|
|
|
|
return { type: 'bigInteger' };
|
|
|
|
}
|
|
|
|
// TODO: verify usage of double vs float
|
|
|
|
case 'float': {
|
|
|
|
return { type: 'double', args: [] };
|
|
|
|
}
|
|
|
|
// TODO: define precision
|
|
|
|
case 'decimal': {
|
|
|
|
return { type: 'decimal', args: [10, 2] };
|
|
|
|
}
|
|
|
|
case 'date': {
|
|
|
|
return { type: 'date' };
|
|
|
|
}
|
|
|
|
// TODO: define precision
|
|
|
|
case 'time': {
|
|
|
|
return { type: 'time', args: [{ precision: 3 }] };
|
|
|
|
}
|
|
|
|
case 'datetime': {
|
|
|
|
return {
|
|
|
|
type: 'datetime',
|
|
|
|
args: [
|
|
|
|
{
|
|
|
|
useTz: false,
|
|
|
|
precision: 6, // TODO: to define
|
|
|
|
},
|
|
|
|
],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// TODO: handle defaults
|
|
|
|
case 'timestamp': {
|
|
|
|
return {
|
|
|
|
type: 'timestamp',
|
|
|
|
args: [
|
|
|
|
{
|
|
|
|
useTz: false,
|
|
|
|
precision: 6, // TODO: to define
|
|
|
|
},
|
|
|
|
],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
case 'boolean': {
|
|
|
|
return { type: 'boolean' };
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
throw new Error(`Unknow type ${attribute.type}`);
|
|
|
|
}
|
2021-06-02 15:53:22 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const metadataToSchema = metadata => {
|
2021-06-17 16:17:15 +02:00
|
|
|
const schema = {
|
|
|
|
tables: [],
|
|
|
|
addTable(table) {
|
|
|
|
this.tables.push(table);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
};
|
2021-06-02 15:53:22 +02:00
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
metadata.forEach(metadata => {
|
|
|
|
schema.addTable(createTable(metadata));
|
|
|
|
});
|
2021-06-02 15:53:22 +02:00
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
return schema;
|
2021-06-02 15:53:22 +02:00
|
|
|
};
|
|
|
|
|
2021-06-17 16:17:15 +02:00
|
|
|
module.exports = { metadataToSchema, createTable };
|