fix: Require unique FK columns to be nullable (#95)
This commit is contained in:
parent
a9fa6b6b91
commit
c6a873d04c
2 changed files with 184 additions and 20 deletions
|
|
@ -58,6 +58,19 @@ class CrdtSchemaRegistry {
|
|||
);
|
||||
}
|
||||
|
||||
final requiredFKeyUniqueColumns = crdtRequiredForeignKeyOnlyUniqueColumnViolations(
|
||||
syncTables,
|
||||
tableDefinitionsByName,
|
||||
);
|
||||
if (requiredFKeyUniqueColumns.isNotEmpty) {
|
||||
throw StateError(
|
||||
'CRDT can only synchronize 1:1 relations when the foreign key column is '
|
||||
'nullable, but the following foreign keys are non-nullable: '
|
||||
'"${requiredFKeyUniqueColumns.join("', '")}". '
|
||||
'Make the relation optional/nullable.',
|
||||
);
|
||||
}
|
||||
|
||||
final nonReleasableUniqueIndexes = crdtNonReleasableUniqueIndexViolations(
|
||||
syncTables,
|
||||
tableDefinitionsByName,
|
||||
|
|
|
|||
|
|
@ -6,14 +6,27 @@ bool isCrdtAllowedForeignKeyOnlyUniqueIndex(
|
|||
TableDefinition tableDefinition,
|
||||
IndexDefinition index,
|
||||
Set<String> syncTableNames,
|
||||
) {
|
||||
return _foreignKeyOnlyUniqueIndexColumns(
|
||||
tableDefinition,
|
||||
index,
|
||||
syncTableNames,
|
||||
) !=
|
||||
null;
|
||||
}
|
||||
|
||||
List<String>? _foreignKeyOnlyUniqueIndexColumns(
|
||||
TableDefinition tableDefinition,
|
||||
IndexDefinition index,
|
||||
Set<String> syncTableNames,
|
||||
) {
|
||||
final indexColumns = <String>[];
|
||||
for (final element in index.elements) {
|
||||
if (element.type != IndexElementDefinitionType.column) return false;
|
||||
if (element.type != IndexElementDefinitionType.column) return null;
|
||||
indexColumns.add(element.definition);
|
||||
}
|
||||
if (indexColumns.isEmpty || indexColumns.length != indexColumns.toSet().length) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
final indexColumnSet = indexColumns.toSet();
|
||||
|
|
@ -27,7 +40,47 @@ bool isCrdtAllowedForeignKeyOnlyUniqueIndex(
|
|||
}
|
||||
}
|
||||
|
||||
return indexColumns.every(coveredForeignKeyColumns.contains);
|
||||
return indexColumns.every(coveredForeignKeyColumns.contains) ? indexColumns : null;
|
||||
}
|
||||
|
||||
@internal
|
||||
List<String> crdtRequiredForeignKeyOnlyUniqueColumnViolations(
|
||||
List<Table> syncTables,
|
||||
Map<String, TableDefinition> tableDefinitionsByName,
|
||||
) {
|
||||
final syncTableNames = {for (final table in syncTables) table.tableName};
|
||||
final violations = <String>{};
|
||||
|
||||
for (final tableName in syncTableNames) {
|
||||
final table = tableDefinitionsByName[tableName];
|
||||
if (table == null) continue;
|
||||
|
||||
final columnsByName = {for (final column in table.columns) column.name: column};
|
||||
for (final index in table.indexes) {
|
||||
if (!index.isUnique || index.isPrimary || isCrdtScopedUniqueIndex(index)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final foreignKeyOnlyColumns = _foreignKeyOnlyUniqueIndexColumns(
|
||||
table,
|
||||
index,
|
||||
syncTableNames,
|
||||
);
|
||||
if (foreignKeyOnlyColumns == null) continue;
|
||||
|
||||
for (final columnName in foreignKeyOnlyColumns) {
|
||||
final column = columnsByName[columnName];
|
||||
if (column == null) {
|
||||
throw StateError(
|
||||
'No column definition found for ${table.name}.$columnName.',
|
||||
);
|
||||
}
|
||||
if (!column.isNullable) violations.add('${table.name}.$columnName');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return violations.toList();
|
||||
}
|
||||
|
||||
@internal
|
||||
|
|
|
|||
Loading…
Reference in a new issue