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;
}