Implementation
CreateTableSQL generateCreateTableSQL(
{EntityRepository? entityRepository,
Object? obj,
Type? type,
String? name,
String? tableName,
bool ifNotExists = true,
bool sortColumns = true}) {
entityRepository ??=
getEntityRepository(type: type, obj: obj, name: name, tableName: name);
if (entityRepository == null) {
throw ArgumentError(
"Can't resolve `EntityRepository`> obj: $obj ; type: $type ; name: $name ; tableName: $tableName");
}
var q = dialect.elementQuote;
var entityType = entityRepository.type;
var entityHandler = entityRepository.entityHandler;
var table = getTableForEntityRepository(entityRepository);
var idFieldName = entityHandler.idFieldName();
var idType = entityHandler.idType();
var idColumnName = normalizeColumnName(idFieldName);
var idAnnotations = entityHandler
.getFieldEntityAnnotations(null, idFieldName)
?.whereType<EntityField>()
.toList();
var idTypeSQL =
primaryKeyTypeToSQLType(idType, entityFieldAnnotations: idAnnotations);
var sqlEntries = <SQLEntry>[
SQLEntry('COLUMN', ' $q$idColumnName$q $idTypeSQL',
comment: '$idType $idFieldName',
columns: [SQLColumn(table, idColumnName)]),
];
var indexSQLs = <CreateIndexSQL>[];
var fieldsEntries = entityHandler
.fieldsTypes()
.entries
.where((e) => !e.value.isListEntityOrReference)
.toList();
if (sortColumns) {
fieldsEntries.sort((a, b) => a.key.compareTo(b.key));
}
var referenceFields =
<String, MapEntry<String, MapEntry<String, String>>>{};
for (var e in fieldsEntries) {
var fieldName = e.key;
var fieldType = e.value;
if (fieldName == idFieldName) continue;
var entityFieldAnnotations = entityHandler
.getFieldEntityAnnotations(null, fieldName)
?.whereType<EntityField>()
.toList();
if (entityFieldAnnotations != null && entityFieldAnnotations.hasHidden) {
continue;
}
var columnName = normalizeColumnName(fieldName);
var comment = '${fieldType.toString(withT: false)} $fieldName';
String? refTable;
String? refColumn;
var fieldSQLType = typeToSQLType(fieldType, columnName,
entityFieldAnnotations: entityFieldAnnotations);
if (fieldSQLType == null) {
var entityType = entityTypeToSQLType(fieldType, columnName,
entityFieldAnnotations: entityFieldAnnotations);
if (entityType != null) {
var fieldEntityType = fieldType.entityType;
if (fieldEntityType != null &&
isSiblingEntityType(entityRepository, fieldEntityType)) {
referenceFields[columnName] = entityType;
}
fieldSQLType = entityType.value.value;
refTable = entityType.key;
refColumn = entityType.value.key;
comment += ' @ $refTable.$refColumn';
}
}
if (fieldSQLType == null) {
var enumType = enumTypeToSQLType(fieldType.type, columnName,
entityFieldAnnotations: entityFieldAnnotations);
if (enumType != null) {
var type = enumType.key;
var values = enumType.value;
fieldSQLType =
_buildEnumSQLType(type, fieldSQLType, values, q, columnName);
comment += ' enum(${values.join(', ')})';
}
}
if (fieldSQLType == null) {
_log.warning("Can't define field SQL type: `$table`.`$fieldName`");
continue;
}
sqlEntries.add(SQLEntry('COLUMN', ' $q$columnName$q $fieldSQLType',
comment: comment,
columns: [
SQLColumn(table, columnName,
referenceTable: refTable, referenceColumn: refColumn)
]));
if (entityFieldAnnotations != null) {
if (entityFieldAnnotations.hasUnique) {
var constrainUniqueName = '${table}__${columnName}__unique';
sqlEntries.add(SQLEntry('CONSTRAINT',
' CONSTRAINT $q$constrainUniqueName$q UNIQUE ($q$columnName$q)',
columns: [
SQLColumn(table, columnName,
referenceTable: refTable, referenceColumn: refColumn)
]));
} else if (entityFieldAnnotations.hasIndexed) {
var indexName = '${table}__${columnName}__idx';
indexSQLs
.add(CreateIndexSQL(dialect, table, columnName, indexName, q: q));
}
}
}
for (var e in referenceFields.entries) {
var fieldName = e.key;
var ref = e.value;
var columnName = normalizeColumnName(fieldName);
var refTableName = ref.key;
var refField = ref.value.key.toLowerCase();
var constrainName = '${table}__${columnName}__fkey';
sqlEntries.add(SQLEntry('CONSTRAINT',
' CONSTRAINT $q$constrainName$q FOREIGN KEY ($q$columnName$q) REFERENCES $q$refTableName$q($q$refField$q)',
comment: '$fieldName @ $refTableName.$refField',
columns: [
SQLColumn(table, columnName,
referenceTable: refTableName, referenceColumn: refField)
]));
}
sqlEntries.sort((a, b) {
var c1 = a.type == 'CONSTRAINT';
var c2 = b.type == 'CONSTRAINT';
if (c1) {
return c2 ? 0 : 1;
} else {
return c2 ? -1 : 0;
}
});
var createSQL = CreateTableSQL(dialect, table, sqlEntries,
q: q, entityRepository: entityRepository, indexes: indexSQLs);
var relationshipSQLs = <CreateTableSQL>[];
var relationshipEntries = entityHandler
.fieldsTypes()
.entries
.where((e) => e.value.isListEntityOrReference)
.toList();
for (var e in relationshipEntries) {
var fieldName = e.key;
var fieldType = e.value.arguments0!;
var entityFieldAnnotations = entityHandler
.getFieldEntityAnnotations(null, fieldName)
?.whereType<EntityField>()
.toList();
var columnName = normalizeColumnName(fieldName);
var srcFieldName = normalizeColumnName(table);
var relSrcType = foreignKeyTypeToSQLType(
TypeInfo.fromType(idType), srcFieldName,
entityFieldAnnotations: entityFieldAnnotations);
var relDstType = entityTypeToSQLType(fieldType, null);
if (relDstType == null) continue;
var relDstTable = relDstType.key;
var relDstTableId = relDstType.value.key;
var relDstTypeSQL = relDstType.value.value;
var dstFieldName = normalizeColumnName(relDstTable);
var relName = '${table}__${columnName}__rel';
var constrainUniqueName = '${relName}__unique';
var constrainSrcName = '${relName}__${srcFieldName}__fkey';
var constrainDstName = '${relName}__${dstFieldName}__fkey';
var sqlRelEntries = <SQLEntry>[
SQLEntry('COLUMN', ' $q$srcFieldName$q $relSrcType NOT NULL',
comment: '$entityType.${e.key}',
columns: [
SQLColumn(relName, srcFieldName,
referenceTable: table, referenceColumn: idColumnName)
]),
SQLEntry('COLUMN', ' $q$dstFieldName$q $relDstTypeSQL NOT NULL',
comment:
'${e.value.toString(withT: false)} @ $relDstTable.$relDstTableId',
columns: [
SQLColumn(relName, dstFieldName,
referenceTable: relDstTable, referenceColumn: relDstTableId)
]),
SQLEntry('CONSTRAINT',
' CONSTRAINT $q$constrainUniqueName$q UNIQUE ($q$srcFieldName$q, $q$dstFieldName$q)',
columns: [
SQLColumn(relName, srcFieldName),
SQLColumn(relName, dstFieldName)
]),
SQLEntry('CONSTRAINT',
' CONSTRAINT $q$constrainSrcName$q FOREIGN KEY ($q$srcFieldName$q) REFERENCES $q$table$q($q$idColumnName$q) ON DELETE CASCADE',
comment: ' $srcFieldName @ $table.$idColumnName',
columns: [
SQLColumn(relName, srcFieldName,
referenceTable: table, referenceColumn: idColumnName)
]),
SQLEntry('CONSTRAINT',
' CONSTRAINT $q$constrainDstName$q FOREIGN KEY ($q$dstFieldName$q) REFERENCES $q$relDstTable$q($q$relDstTableId$q) ON DELETE CASCADE',
comment: ' $dstFieldName @ $relDstTable.$relDstTableId',
columns: [
SQLColumn(relName, dstFieldName,
referenceTable: relDstTable, referenceColumn: relDstTableId)
])
];
var relSQL = CreateTableSQL(dialect, relName, sqlRelEntries,
q: q, parentTable: table);
relationshipSQLs.add(relSQL);
}
createSQL.relationships = relationshipSQLs;
return createSQL;
}