feat: many-to-one check, constrints check
This commit is contained in:
@@ -14,35 +14,37 @@ var RelationsAnalyzer = &analysis.Analyzer{
|
||||
Run: run,
|
||||
}
|
||||
|
||||
func CheckTypesOfM2M(pass *analysis.Pass, modelName string, relatedModelName string, relationName string, reference common.Field, backReference common.Field) {
|
||||
func CheckTypesOfM2M(pass *analysis.Pass, modelName string, relatedModelName string, relationName string, reference common.Field, backReference common.Field) bool {
|
||||
if !common.IsSlice(reference.Type) {
|
||||
pass.Reportf(reference.Pos, "M2M relation `%s` with bad type `%s` (should be a slice)", relationName, reference.Type)
|
||||
return
|
||||
return true
|
||||
}
|
||||
if !common.IsSlice(backReference.Type) {
|
||||
pass.Reportf(backReference.Pos, "M2M relation `%s` with bad type `%s` (should be a slice)", relationName, backReference.Type)
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
referenceBaseType := common.ResolveBaseType(reference.Type)
|
||||
if referenceBaseType == nil {
|
||||
pass.Reportf(reference.Pos, "Failed to resolve field type: `%s`", reference.Type)
|
||||
return
|
||||
return true
|
||||
}
|
||||
backReferenceBaseType := common.ResolveBaseType(backReference.Type)
|
||||
if backReferenceBaseType == nil {
|
||||
pass.Reportf(reference.Pos, "Failed to resolve type: `%s`", reference.Type)
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
if *backReferenceBaseType != modelName {
|
||||
pass.Reportf(backReference.Pos, "Invalid type `%s` in M2M relation (use []*%s or self-reference)", *backReferenceBaseType, modelName)
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
if *referenceBaseType != relatedModelName {
|
||||
pass.Reportf(reference.Pos, "Invalid type `%s` in M2M relation (use []*%s or self-reference)", *referenceBaseType, relatedModelName)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func CheckMany2Many(pass *analysis.Pass, models map[string]common.Model) {
|
||||
@@ -55,7 +57,7 @@ func CheckMany2Many(pass *analysis.Pass, models map[string]common.Model) {
|
||||
relatedModel := common.GetModelFromType(field.Type, models)
|
||||
if relatedModel == nil {
|
||||
pass.Reportf(field.Pos, "Failed to resolve related model type")
|
||||
return
|
||||
continue
|
||||
}
|
||||
|
||||
backReference := common.FindBackReferenceInM2M(m2mRelation.Value, *relatedModel)
|
||||
@@ -66,9 +68,14 @@ func CheckMany2Many(pass *analysis.Pass, models map[string]common.Model) {
|
||||
knownModels = append(knownModels, model.Name)
|
||||
knownModels = append(knownModels, relatedModel.Name)
|
||||
}
|
||||
CheckTypesOfM2M(pass, model.Name, relatedModel.Name, m2mRelation.Value, field, *backReference)
|
||||
if CheckTypesOfM2M(pass, model.Name, relatedModel.Name, m2mRelation.Value, field, *backReference) {
|
||||
continue
|
||||
}
|
||||
// TODO: check foreign key and references
|
||||
fmt.Printf("Found M2M relation between \"%s\" and \"%s\"\n", model.Name, relatedModel.Name)
|
||||
if CheckCascadeDelete(pass, field) {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// Check self-reference
|
||||
if model.Name == relatedModel.Name {
|
||||
@@ -77,13 +84,29 @@ func CheckMany2Many(pass *analysis.Pass, models map[string]common.Model) {
|
||||
if !relatedModel.HasPrimaryKey() {
|
||||
fmt.Printf("%#v\n", relatedModel)
|
||||
pass.Reportf(field.Pos, "Can't build M2M relation `%s`, primary key on `%s` model is absont", m2mRelation.Value, relatedModel.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Here you can forbid M2M relations without back-reference
|
||||
// TODO: process m2m without backref
|
||||
if CheckCascadeDelete(pass, field) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: check [] and process m:1
|
||||
if common.IsSlice(field.Type) {
|
||||
relatedModel := common.GetModelFromType(field.Type, models)
|
||||
if relatedModel == nil {
|
||||
pass.Reportf(field.Pos, "Failed to resolve related model type")
|
||||
continue
|
||||
}
|
||||
if checkManyToOne(pass, field, model, *relatedModel) {
|
||||
continue
|
||||
}
|
||||
if CheckCascadeDelete(pass, field) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user