2021-01-06 11:32:16 +01:00
|
|
|
package check
|
2020-11-11 12:02:23 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
2021-01-06 11:32:16 +01:00
|
|
|
|
|
|
|
models "github.com/OpenSlides/openslides-models-to-go"
|
2020-11-11 12:02:23 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Check runs some checks on the given models.
|
2021-01-06 11:32:16 +01:00
|
|
|
func Check(data map[string]models.Model) error {
|
|
|
|
validators := []func(map[string]models.Model) error{
|
2020-11-11 12:02:23 +01:00
|
|
|
validateTypes,
|
|
|
|
validateRelations,
|
|
|
|
validateTemplatePrefixes,
|
|
|
|
}
|
|
|
|
|
|
|
|
errors := new(ErrorList)
|
|
|
|
for _, v := range validators {
|
2021-01-06 11:32:16 +01:00
|
|
|
if err := v(data); err != nil {
|
2020-11-11 12:02:23 +01:00
|
|
|
errors.append(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !errors.empty() {
|
|
|
|
return errors
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-06 11:32:16 +01:00
|
|
|
func validateTypes(data map[string]models.Model) error {
|
2020-11-11 12:02:23 +01:00
|
|
|
scalar := scalarTypes()
|
|
|
|
relation := relationTypes()
|
|
|
|
errs := &ErrorList{
|
|
|
|
Name: "type validator",
|
|
|
|
intent: 1,
|
|
|
|
}
|
2021-01-06 11:32:16 +01:00
|
|
|
for modelName, model := range data {
|
2020-11-11 12:02:23 +01:00
|
|
|
for fieldName, field := range model.Fields {
|
|
|
|
if scalar[strings.TrimSuffix(field.Type, "[]")] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if relation[field.Type] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
errs.append(fmt.Errorf("Unknown type `%s` in %s/%s", field.Type, modelName, fieldName))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if errs.empty() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errs
|
|
|
|
}
|
|
|
|
|
2021-01-06 11:32:16 +01:00
|
|
|
func validateRelations(data map[string]models.Model) error {
|
2020-11-11 12:02:23 +01:00
|
|
|
errs := &ErrorList{
|
|
|
|
Name: "relation validator",
|
|
|
|
intent: 1,
|
|
|
|
}
|
|
|
|
relation := relationTypes()
|
2021-01-06 11:32:16 +01:00
|
|
|
for modelName, model := range data {
|
2020-11-11 12:02:23 +01:00
|
|
|
Next:
|
|
|
|
for fieldName, field := range model.Fields {
|
|
|
|
r := field.Relation()
|
|
|
|
if r == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range r.ToCollections() {
|
2021-01-06 11:32:16 +01:00
|
|
|
toModel, ok := data[c.Collection]
|
2020-11-11 12:02:23 +01:00
|
|
|
if !ok {
|
2021-01-06 11:32:16 +01:00
|
|
|
errs.append(fmt.Errorf("%s/%s directs to nonexisting model `%s`", modelName, fieldName, c))
|
2020-11-11 12:02:23 +01:00
|
|
|
continue Next
|
|
|
|
}
|
2021-01-06 11:32:16 +01:00
|
|
|
|
2020-11-11 12:02:23 +01:00
|
|
|
toField, ok := toModel.Fields[c.ToField.Name]
|
|
|
|
if !ok {
|
|
|
|
errs.append(fmt.Errorf("%s/%s directs to nonexisting collectionfield `%s/%s`", modelName, fieldName, c.Collection, c.ToField.Name))
|
|
|
|
continue Next
|
|
|
|
}
|
|
|
|
|
|
|
|
if !relation[toField.Type] {
|
|
|
|
errs.append(fmt.Errorf("%s/%s directs to `%s/%s`, but it is not a relation, but %s", modelName, fieldName, c.Collection, c.ToField.Name, toField.Type))
|
|
|
|
continue Next
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if errs.empty() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errs
|
|
|
|
}
|
|
|
|
|
2021-01-06 11:32:16 +01:00
|
|
|
func validateTemplatePrefixes(models map[string]models.Model) error {
|
2020-11-11 12:02:23 +01:00
|
|
|
errs := &ErrorList{
|
|
|
|
Name: "template prefixes validator",
|
|
|
|
intent: 1,
|
|
|
|
}
|
|
|
|
for modelName, model := range models {
|
|
|
|
prefixes := map[string]bool{}
|
|
|
|
for fieldName := range model.Fields {
|
|
|
|
i := strings.Index(fieldName, "$")
|
|
|
|
if i < 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
prefix := fieldName[0:i]
|
|
|
|
if prefixes[prefix] {
|
|
|
|
errs.append(fmt.Errorf("Duplicate template prefix %s in %s", prefix, modelName))
|
|
|
|
}
|
|
|
|
prefixes[prefix] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if errs.empty() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errs
|
|
|
|
}
|
|
|
|
|
|
|
|
// scalarTypes are the main types. All scalarTypes can be used as a list.
|
|
|
|
// JSON[], timestamp[] etc.
|
|
|
|
func scalarTypes() map[string]bool {
|
|
|
|
s := []string{
|
|
|
|
"string",
|
|
|
|
"number",
|
|
|
|
"boolean",
|
|
|
|
"JSON",
|
|
|
|
"HTMLPermissive",
|
|
|
|
"HTMLStrict",
|
|
|
|
"float",
|
|
|
|
"decimal(6)",
|
|
|
|
"timestamp",
|
|
|
|
}
|
|
|
|
out := make(map[string]bool)
|
|
|
|
for _, t := range s {
|
|
|
|
out[t] = true
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
// relationTypes are realtion types in realtion to other fields.
|
|
|
|
func relationTypes() map[string]bool {
|
|
|
|
s := []string{
|
|
|
|
"relation",
|
|
|
|
"relation-list",
|
|
|
|
"generic-relation",
|
|
|
|
"generic-relation-list",
|
|
|
|
"template",
|
|
|
|
}
|
|
|
|
out := make(map[string]bool)
|
|
|
|
for _, t := range s {
|
|
|
|
out[t] = true
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|