207 lines
4.7 KiB
JavaScript
Raw Normal View History

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)) {
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-08-10 09:36:02 +02:00
table.columns.push(createColumn(typeColumn.name, { type: 'string' }));
} 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 };