added SchemaField.Presentable field
This commit is contained in:
		
							parent
							
								
									1e995552c8
								
							
						
					
					
						commit
						864bbe7e12
					
				| 
						 | 
					@ -12,7 +12,6 @@ import (
 | 
				
			||||||
	"github.com/labstack/echo/v5"
 | 
						"github.com/labstack/echo/v5"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/core"
 | 
						"github.com/pocketbase/pocketbase/core"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/models"
 | 
						"github.com/pocketbase/pocketbase/models"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/models/schema"
 | 
					 | 
				
			||||||
	"github.com/pocketbase/pocketbase/tests"
 | 
						"github.com/pocketbase/pocketbase/tests"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/tools/list"
 | 
						"github.com/pocketbase/pocketbase/tools/list"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -401,7 +400,7 @@ func TestCollectionCreate(t *testing.T) {
 | 
				
			||||||
				`"name":"new"`,
 | 
									`"name":"new"`,
 | 
				
			||||||
				`"type":"base"`,
 | 
									`"type":"base"`,
 | 
				
			||||||
				`"system":false`,
 | 
									`"system":false`,
 | 
				
			||||||
				`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
 | 
									`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
 | 
				
			||||||
				`"options":{}`,
 | 
									`"options":{}`,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			ExpectedEvents: map[string]int{
 | 
								ExpectedEvents: map[string]int{
 | 
				
			||||||
| 
						 | 
					@ -425,7 +424,7 @@ func TestCollectionCreate(t *testing.T) {
 | 
				
			||||||
				`"name":"new"`,
 | 
									`"name":"new"`,
 | 
				
			||||||
				`"type":"auth"`,
 | 
									`"type":"auth"`,
 | 
				
			||||||
				`"system":false`,
 | 
									`"system":false`,
 | 
				
			||||||
				`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
 | 
									`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
 | 
				
			||||||
				`"options":{"allowEmailAuth":false,"allowOAuth2Auth":false,"allowUsernameAuth":false,"exceptEmailDomains":null,"manageRule":null,"minPasswordLength":0,"onlyEmailDomains":null,"requireEmail":false}`,
 | 
									`"options":{"allowEmailAuth":false,"allowOAuth2Auth":false,"allowUsernameAuth":false,"exceptEmailDomains":null,"manageRule":null,"minPasswordLength":0,"onlyEmailDomains":null,"requireEmail":false}`,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			ExpectedEvents: map[string]int{
 | 
								ExpectedEvents: map[string]int{
 | 
				
			||||||
| 
						 | 
					@ -960,88 +959,6 @@ func TestCollectionUpdate(t *testing.T) {
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// rel field change displayFields propagation
 | 
					 | 
				
			||||||
		// -----------------------------------------------------------
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Name:   "renaming a display field should also update the referenced displayFields value",
 | 
					 | 
				
			||||||
			Method: http.MethodPatch,
 | 
					 | 
				
			||||||
			Url:    "/api/collections/demo3",
 | 
					 | 
				
			||||||
			Body: strings.NewReader(`{
 | 
					 | 
				
			||||||
				"schema":[
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						"id": "w5z2x0nq",
 | 
					 | 
				
			||||||
						"type": "text",
 | 
					 | 
				
			||||||
						"name": "title_change"
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				]
 | 
					 | 
				
			||||||
			}`),
 | 
					 | 
				
			||||||
			RequestHeaders: map[string]string{
 | 
					 | 
				
			||||||
				"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			ExpectedStatus: 200,
 | 
					 | 
				
			||||||
			ExpectedContent: []string{
 | 
					 | 
				
			||||||
				`"name":"title_change"`,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			ExpectedEvents: map[string]int{
 | 
					 | 
				
			||||||
				"OnModelBeforeUpdate":             2,
 | 
					 | 
				
			||||||
				"OnModelAfterUpdate":              2,
 | 
					 | 
				
			||||||
				"OnCollectionBeforeUpdateRequest": 1,
 | 
					 | 
				
			||||||
				"OnCollectionAfterUpdateRequest":  1,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
 | 
					 | 
				
			||||||
				collection, err := app.Dao().FindCollectionByNameOrId("demo4")
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatal(err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				relField := collection.Schema.GetFieldByName("rel_many_no_cascade_required")
 | 
					 | 
				
			||||||
				options := relField.Options.(*schema.RelationOptions)
 | 
					 | 
				
			||||||
				expectedDisplayFields := []string{"title_change", "id"}
 | 
					 | 
				
			||||||
				if len(list.SubtractSlice(options.DisplayFields, expectedDisplayFields)) != 0 {
 | 
					 | 
				
			||||||
					t.Fatalf("Expected displayFields %v, got %v", expectedDisplayFields, options.DisplayFields)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Name:   "deleting a display field should also update the referenced displayFields value",
 | 
					 | 
				
			||||||
			Method: http.MethodPatch,
 | 
					 | 
				
			||||||
			Url:    "/api/collections/demo3",
 | 
					 | 
				
			||||||
			Body: strings.NewReader(`{
 | 
					 | 
				
			||||||
				"schema":[
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						"type": "text",
 | 
					 | 
				
			||||||
						"name": "new_field"
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				]
 | 
					 | 
				
			||||||
			}`),
 | 
					 | 
				
			||||||
			RequestHeaders: map[string]string{
 | 
					 | 
				
			||||||
				"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			ExpectedStatus: 200,
 | 
					 | 
				
			||||||
			ExpectedContent: []string{
 | 
					 | 
				
			||||||
				`"name":"new_field"`,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			ExpectedEvents: map[string]int{
 | 
					 | 
				
			||||||
				"OnModelBeforeUpdate":             2,
 | 
					 | 
				
			||||||
				"OnModelAfterUpdate":              2,
 | 
					 | 
				
			||||||
				"OnCollectionBeforeUpdateRequest": 1,
 | 
					 | 
				
			||||||
				"OnCollectionAfterUpdateRequest":  1,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
 | 
					 | 
				
			||||||
				collection, err := app.Dao().FindCollectionByNameOrId("demo4")
 | 
					 | 
				
			||||||
				if err != nil {
 | 
					 | 
				
			||||||
					t.Fatal(err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				relField := collection.Schema.GetFieldByName("rel_many_no_cascade_required")
 | 
					 | 
				
			||||||
				options := relField.Options.(*schema.RelationOptions)
 | 
					 | 
				
			||||||
				expectedDisplayFields := []string{"id"}
 | 
					 | 
				
			||||||
				if len(list.SubtractSlice(options.DisplayFields, expectedDisplayFields)) != 0 {
 | 
					 | 
				
			||||||
					t.Fatalf("Expected displayFields %v, got %v", expectedDisplayFields, options.DisplayFields)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// view
 | 
							// view
 | 
				
			||||||
		// -----------------------------------------------------------
 | 
							// -----------------------------------------------------------
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@ import (
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/models"
 | 
						"github.com/pocketbase/pocketbase/models"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/models/schema"
 | 
						"github.com/pocketbase/pocketbase/models/schema"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/tools/dbutils"
 | 
						"github.com/pocketbase/pocketbase/tools/dbutils"
 | 
				
			||||||
	"github.com/pocketbase/pocketbase/tools/list"
 | 
					 | 
				
			||||||
	"github.com/pocketbase/pocketbase/tools/security"
 | 
						"github.com/pocketbase/pocketbase/tools/security"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,10 +158,6 @@ func (dao *Dao) SyncRecordTableSchema(newCollection *models.Collection, oldColle
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := txDao.syncRelationDisplayFieldsChanges(newCollection, renamedFieldNames, deletedFieldNames); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return txDao.createCollectionIndexes(newCollection)
 | 
							return txDao.createCollectionIndexes(newCollection)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -294,50 +289,6 @@ func (dao *Dao) normalizeSingleVsMultipleFieldChanges(newCollection, oldCollecti
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (dao *Dao) syncRelationDisplayFieldsChanges(collection *models.Collection, renamedFieldNames map[string]string, deletedFieldNames []string) error {
 | 
					 | 
				
			||||||
	if len(renamedFieldNames) == 0 && len(deletedFieldNames) == 0 {
 | 
					 | 
				
			||||||
		return nil // nothing to sync
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	refs, err := dao.FindCollectionReferences(collection)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for refCollection, refFields := range refs {
 | 
					 | 
				
			||||||
		for _, refField := range refFields {
 | 
					 | 
				
			||||||
			options, _ := refField.Options.(*schema.RelationOptions)
 | 
					 | 
				
			||||||
			if options == nil {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// remove deleted (if any)
 | 
					 | 
				
			||||||
			newDisplayFields := list.SubtractSlice(options.DisplayFields, deletedFieldNames)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for old, new := range renamedFieldNames {
 | 
					 | 
				
			||||||
				for i, name := range newDisplayFields {
 | 
					 | 
				
			||||||
					if name == old {
 | 
					 | 
				
			||||||
						newDisplayFields[i] = new
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// has changes
 | 
					 | 
				
			||||||
			if len(list.SubtractSlice(options.DisplayFields, newDisplayFields)) > 0 {
 | 
					 | 
				
			||||||
				options.DisplayFields = newDisplayFields
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// direct collection save to prevent self-referencing
 | 
					 | 
				
			||||||
				// recursion and unnecessary records table sync checks
 | 
					 | 
				
			||||||
				if err := dao.Save(refCollection); err != nil {
 | 
					 | 
				
			||||||
					return err
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dao *Dao) dropCollectionIndex(collection *models.Collection) error {
 | 
					func (dao *Dao) dropCollectionIndex(collection *models.Collection) error {
 | 
				
			||||||
	if collection.IsView() {
 | 
						if collection.IsView() {
 | 
				
			||||||
		return nil // views don't have indexes
 | 
							return nil // views don't have indexes
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,14 +229,6 @@ func (form *CollectionUpsert) ensureNoFieldsTypeChange(value any) error {
 | 
				
			||||||
func (form *CollectionUpsert) checkRelationFields(value any) error {
 | 
					func (form *CollectionUpsert) checkRelationFields(value any) error {
 | 
				
			||||||
	v, _ := value.(schema.Schema)
 | 
						v, _ := value.(schema.Schema)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	systemDisplayFields := schema.BaseModelFieldNames()
 | 
					 | 
				
			||||||
	systemDisplayFields = append(systemDisplayFields,
 | 
					 | 
				
			||||||
		schema.FieldNameUsername,
 | 
					 | 
				
			||||||
		schema.FieldNameEmail,
 | 
					 | 
				
			||||||
		schema.FieldNameEmailVisibility,
 | 
					 | 
				
			||||||
		schema.FieldNameVerified,
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for i, field := range v.Fields() {
 | 
						for i, field := range v.Fields() {
 | 
				
			||||||
		if field.Type != schema.FieldTypeRelation {
 | 
							if field.Type != schema.FieldTypeRelation {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
| 
						 | 
					@ -294,20 +286,6 @@ func (form *CollectionUpsert) checkRelationFields(value any) error {
 | 
				
			||||||
				}},
 | 
									}},
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// validate displayFields (if any)
 | 
					 | 
				
			||||||
		for _, name := range options.DisplayFields {
 | 
					 | 
				
			||||||
			if relCollection.Schema.GetFieldByName(name) == nil && !list.ExistInSlice(name, systemDisplayFields) {
 | 
					 | 
				
			||||||
				return validation.Errors{fmt.Sprint(i): validation.Errors{
 | 
					 | 
				
			||||||
					"options": validation.Errors{
 | 
					 | 
				
			||||||
						"displayFields": validation.NewError(
 | 
					 | 
				
			||||||
							"validation_field_invalid_relation_displayFields",
 | 
					 | 
				
			||||||
							fmt.Sprintf("%q does not exist in the related %q collection.", name, relCollection.Name),
 | 
					 | 
				
			||||||
						),
 | 
					 | 
				
			||||||
					}},
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,25 +171,6 @@ func TestCollectionUpsertValidateAndSubmit(t *testing.T) {
 | 
				
			||||||
			}`,
 | 
								}`,
 | 
				
			||||||
			[]string{"schema"},
 | 
								[]string{"schema"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			"create failure - missing relation display field",
 | 
					 | 
				
			||||||
			"",
 | 
					 | 
				
			||||||
			`{
 | 
					 | 
				
			||||||
				"name": "test_new",
 | 
					 | 
				
			||||||
				"type": "base",
 | 
					 | 
				
			||||||
				"schema": [
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						"name":"test",
 | 
					 | 
				
			||||||
						"type":"relation",
 | 
					 | 
				
			||||||
						"options":{
 | 
					 | 
				
			||||||
							"collectionId":"wsmn24bux7wo113",
 | 
					 | 
				
			||||||
							"displayFields":["text", "missing"]
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				]
 | 
					 | 
				
			||||||
			}`,
 | 
					 | 
				
			||||||
			[]string{"schema"},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"create failure - check auth options validators",
 | 
								"create failure - check auth options validators",
 | 
				
			||||||
			"",
 | 
								"",
 | 
				
			||||||
| 
						 | 
					@ -605,7 +586,7 @@ func TestCollectionUpsertValidateAndSubmit(t *testing.T) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if form.Name != collection.Name {
 | 
								if form.Name != collection.Name {
 | 
				
			||||||
				t.Errorf("Expected Name %q, got %q", collection.Name, form.Name)
 | 
									t.Fatalf("Expected Name %q, got %q", collection.Name, form.Name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if form.Type != collection.Type {
 | 
								if form.Type != collection.Type {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,6 +132,10 @@ type SchemaField struct {
 | 
				
			||||||
	Type     string `form:"type" json:"type"`
 | 
						Type     string `form:"type" json:"type"`
 | 
				
			||||||
	Required bool   `form:"required" json:"required"`
 | 
						Required bool   `form:"required" json:"required"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Presentable indicates whether the field is suitable for
 | 
				
			||||||
 | 
						// visualization purposes (eg. in the Admin UI relation views).
 | 
				
			||||||
 | 
						Presentable bool `form:"presentable" json:"presentable"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Deprecated: This field is no-op and will be removed in future versions.
 | 
						// Deprecated: This field is no-op and will be removed in future versions.
 | 
				
			||||||
	// Please use the collection.Indexes field to define a unique constraint.
 | 
						// Please use the collection.Indexes field to define a unique constraint.
 | 
				
			||||||
	Unique bool `form:"unique" json:"unique"`
 | 
						Unique bool `form:"unique" json:"unique"`
 | 
				
			||||||
| 
						 | 
					@ -645,7 +649,8 @@ type RelationOptions struct {
 | 
				
			||||||
	// If nil no limits are applied.
 | 
						// If nil no limits are applied.
 | 
				
			||||||
	MaxSelect *int `form:"maxSelect" json:"maxSelect"`
 | 
						MaxSelect *int `form:"maxSelect" json:"maxSelect"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DisplayFields is optional slice of collection field names used for UI purposes.
 | 
						// Deprecated: This field is no-op and will be removed in future versions.
 | 
				
			||||||
 | 
						// Instead use the individula SchemaField.Presentable option for each field in the relation collection.
 | 
				
			||||||
	DisplayFields []string `form:"displayFields" json:"displayFields"`
 | 
						DisplayFields []string `form:"displayFields" json:"displayFields"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -133,7 +133,7 @@ func TestSchemaFieldString(t *testing.T) {
 | 
				
			||||||
		Name:        "test",
 | 
							Name:        "test",
 | 
				
			||||||
		Type:        schema.FieldTypeText,
 | 
							Type:        schema.FieldTypeText,
 | 
				
			||||||
		Required:    true,
 | 
							Required:    true,
 | 
				
			||||||
		Unique:   false,
 | 
							Presentable: true,
 | 
				
			||||||
		System:      true,
 | 
							System:      true,
 | 
				
			||||||
		Options: &schema.TextOptions{
 | 
							Options: &schema.TextOptions{
 | 
				
			||||||
			Pattern: "test",
 | 
								Pattern: "test",
 | 
				
			||||||
| 
						 | 
					@ -141,7 +141,7 @@ func TestSchemaFieldString(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result := f.String()
 | 
						result := f.String()
 | 
				
			||||||
	expected := `{"system":true,"id":"abc","name":"test","type":"text","required":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`
 | 
						expected := `{"system":true,"id":"abc","name":"test","type":"text","required":true,"presentable":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if result != expected {
 | 
						if result != expected {
 | 
				
			||||||
		t.Errorf("Expected \n%v, got \n%v", expected, result)
 | 
							t.Errorf("Expected \n%v, got \n%v", expected, result)
 | 
				
			||||||
| 
						 | 
					@ -156,7 +156,7 @@ func TestSchemaFieldMarshalJSON(t *testing.T) {
 | 
				
			||||||
		// empty
 | 
							// empty
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{},
 | 
								schema.SchemaField{},
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
 | 
								`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		// without defined options
 | 
							// without defined options
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -165,10 +165,10 @@ func TestSchemaFieldMarshalJSON(t *testing.T) {
 | 
				
			||||||
				Name:        "test",
 | 
									Name:        "test",
 | 
				
			||||||
				Type:        schema.FieldTypeText,
 | 
									Type:        schema.FieldTypeText,
 | 
				
			||||||
				Required:    true,
 | 
									Required:    true,
 | 
				
			||||||
				Unique:   false,
 | 
									Presentable: true,
 | 
				
			||||||
				System:      true,
 | 
									System:      true,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			`{"system":true,"id":"abc","name":"test","type":"text","required":true,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
 | 
								`{"system":true,"id":"abc","name":"test","type":"text","required":true,"presentable":true,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		// with defined options
 | 
							// with defined options
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -182,7 +182,7 @@ func TestSchemaFieldMarshalJSON(t *testing.T) {
 | 
				
			||||||
					Pattern: "test",
 | 
										Pattern: "test",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			`{"system":true,"id":"","name":"test","type":"text","required":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
 | 
								`{"system":true,"id":"","name":"test","type":"text","required":true,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,32 +207,32 @@ func TestSchemaFieldUnmarshalJSON(t *testing.T) {
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			nil,
 | 
								nil,
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
 | 
								`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]byte{},
 | 
								[]byte{},
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
 | 
								`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]byte(`{"system": true}`),
 | 
								[]byte(`{"system": true}`),
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`{"system":true,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
 | 
								`{"system":true,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]byte(`{"invalid"`),
 | 
								[]byte(`{"invalid"`),
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
 | 
								`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]byte(`{"type":"text","system":true}`),
 | 
								[]byte(`{"type":"text","system":true}`),
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":true,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
 | 
								`{"system":true,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]byte(`{"type":"text","options":{"pattern":"test"}}`),
 | 
								[]byte(`{"type":"text","options":{"pattern":"test"}}`),
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
 | 
								`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -470,72 +470,72 @@ func TestSchemaFieldInitOptions(t *testing.T) {
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{},
 | 
								schema.SchemaField{},
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
 | 
								`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: "unknown"},
 | 
								schema.SchemaField{Type: "unknown"},
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"unknown","required":false,"unique":false,"options":null}`,
 | 
								`{"system":false,"id":"","name":"","type":"unknown","required":false,"presentable":false,"unique":false,"options":null}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeText},
 | 
								schema.SchemaField{Type: schema.FieldTypeText},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
 | 
								`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeNumber},
 | 
								schema.SchemaField{Type: schema.FieldTypeNumber},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"number","required":false,"unique":false,"options":{"min":null,"max":null}}`,
 | 
								`{"system":false,"id":"","name":"","type":"number","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeBool},
 | 
								schema.SchemaField{Type: schema.FieldTypeBool},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"bool","required":false,"unique":false,"options":{}}`,
 | 
								`{"system":false,"id":"","name":"","type":"bool","required":false,"presentable":false,"unique":false,"options":{}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeEmail},
 | 
								schema.SchemaField{Type: schema.FieldTypeEmail},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"email","required":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
 | 
								`{"system":false,"id":"","name":"","type":"email","required":false,"presentable":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeUrl},
 | 
								schema.SchemaField{Type: schema.FieldTypeUrl},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"url","required":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
 | 
								`{"system":false,"id":"","name":"","type":"url","required":false,"presentable":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeEditor},
 | 
								schema.SchemaField{Type: schema.FieldTypeEditor},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"editor","required":false,"unique":false,"options":{}}`,
 | 
								`{"system":false,"id":"","name":"","type":"editor","required":false,"presentable":false,"unique":false,"options":{}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeDate},
 | 
								schema.SchemaField{Type: schema.FieldTypeDate},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"date","required":false,"unique":false,"options":{"min":"","max":""}}`,
 | 
								`{"system":false,"id":"","name":"","type":"date","required":false,"presentable":false,"unique":false,"options":{"min":"","max":""}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeSelect},
 | 
								schema.SchemaField{Type: schema.FieldTypeSelect},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"select","required":false,"unique":false,"options":{"maxSelect":0,"values":null}}`,
 | 
								`{"system":false,"id":"","name":"","type":"select","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"values":null}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeJson},
 | 
								schema.SchemaField{Type: schema.FieldTypeJson},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"json","required":false,"unique":false,"options":{}}`,
 | 
								`{"system":false,"id":"","name":"","type":"json","required":false,"presentable":false,"unique":false,"options":{}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeFile},
 | 
								schema.SchemaField{Type: schema.FieldTypeFile},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"file","required":false,"unique":false,"options":{"maxSelect":0,"maxSize":0,"mimeTypes":null,"thumbs":null,"protected":false}}`,
 | 
								`{"system":false,"id":"","name":"","type":"file","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"maxSize":0,"mimeTypes":null,"thumbs":null,"protected":false}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeRelation},
 | 
								schema.SchemaField{Type: schema.FieldTypeRelation},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"relation","required":false,"unique":false,"options":{"collectionId":"","cascadeDelete":false,"minSelect":null,"maxSelect":null,"displayFields":null}}`,
 | 
								`{"system":false,"id":"","name":"","type":"relation","required":false,"presentable":false,"unique":false,"options":{"collectionId":"","cascadeDelete":false,"minSelect":null,"maxSelect":null,"displayFields":null}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{Type: schema.FieldTypeUser},
 | 
								schema.SchemaField{Type: schema.FieldTypeUser},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"user","required":false,"unique":false,"options":{"maxSelect":0,"cascadeDelete":false}}`,
 | 
								`{"system":false,"id":"","name":"","type":"user","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"cascadeDelete":false}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			schema.SchemaField{
 | 
								schema.SchemaField{
 | 
				
			||||||
| 
						 | 
					@ -543,7 +543,7 @@ func TestSchemaFieldInitOptions(t *testing.T) {
 | 
				
			||||||
				Options: &schema.TextOptions{Pattern: "test"},
 | 
									Options: &schema.TextOptions{Pattern: "test"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`{"system":false,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
 | 
								`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,7 +286,7 @@ func TestSchemaMarshalJSON(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}},{"system":false,"id":"f2id","name":"test2","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`
 | 
						expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}},{"system":false,"id":"f2id","name":"test2","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if string(result) != expected {
 | 
						if string(result) != expected {
 | 
				
			||||||
		t.Fatalf("Expected %s, got %s", expected, string(result))
 | 
							t.Fatalf("Expected %s, got %s", expected, string(result))
 | 
				
			||||||
| 
						 | 
					@ -354,7 +354,7 @@ func TestSchemaValue(t *testing.T) {
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`
 | 
						expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if v2 != expected {
 | 
						if v2 != expected {
 | 
				
			||||||
		t.Fatalf("Expected %v, got %v", expected, v2)
 | 
							t.Fatalf("Expected %v, got %v", expected, v2)
 | 
				
			||||||
| 
						 | 
					@ -377,21 +377,21 @@ func TestSchemaScan(t *testing.T) {
 | 
				
			||||||
		{`[{}]`, true, `[]`},
 | 
							{`[{}]`, true, `[]`},
 | 
				
			||||||
		// unknown field type
 | 
							// unknown field type
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			`[{"system":false,"id":"123","name":"test1","type":"unknown","required":false,"unique":false}]`,
 | 
								`[{"system":false,"id":"123","name":"test1","type":"unknown","required":false,"presentable":false,"unique":false}]`,
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			`[]`,
 | 
								`[]`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		// without options
 | 
							// without options
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false}]`,
 | 
								`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false}]`,
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
 | 
								`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		// with options
 | 
							// with options
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
 | 
								`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
 | 
				
			||||||
			false,
 | 
								false,
 | 
				
			||||||
			`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
 | 
								`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -398,6 +398,7 @@ migrate((db) => {
 | 
				
			||||||
    "name": "f4_name",
 | 
					    "name": "f4_name",
 | 
				
			||||||
    "type": "text",
 | 
					    "type": "text",
 | 
				
			||||||
    "required": false,
 | 
					    "required": false,
 | 
				
			||||||
 | 
					    "presentable": false,
 | 
				
			||||||
    "unique": false,
 | 
					    "unique": false,
 | 
				
			||||||
    "options": {
 | 
					    "options": {
 | 
				
			||||||
      "min": null,
 | 
					      "min": null,
 | 
				
			||||||
| 
						 | 
					@ -413,6 +414,7 @@ migrate((db) => {
 | 
				
			||||||
    "name": "f2_name_new",
 | 
					    "name": "f2_name_new",
 | 
				
			||||||
    "type": "number",
 | 
					    "type": "number",
 | 
				
			||||||
    "required": false,
 | 
					    "required": false,
 | 
				
			||||||
 | 
					    "presentable": false,
 | 
				
			||||||
    "unique": true,
 | 
					    "unique": true,
 | 
				
			||||||
    "options": {
 | 
					    "options": {
 | 
				
			||||||
      "min": 10,
 | 
					      "min": 10,
 | 
				
			||||||
| 
						 | 
					@ -450,6 +452,7 @@ migrate((db) => {
 | 
				
			||||||
    "name": "f3_name",
 | 
					    "name": "f3_name",
 | 
				
			||||||
    "type": "bool",
 | 
					    "type": "bool",
 | 
				
			||||||
    "required": false,
 | 
					    "required": false,
 | 
				
			||||||
 | 
					    "presentable": false,
 | 
				
			||||||
    "unique": false,
 | 
					    "unique": false,
 | 
				
			||||||
    "options": {}
 | 
					    "options": {}
 | 
				
			||||||
  }))
 | 
					  }))
 | 
				
			||||||
| 
						 | 
					@ -464,6 +467,7 @@ migrate((db) => {
 | 
				
			||||||
    "name": "f2_name",
 | 
					    "name": "f2_name",
 | 
				
			||||||
    "type": "number",
 | 
					    "type": "number",
 | 
				
			||||||
    "required": false,
 | 
					    "required": false,
 | 
				
			||||||
 | 
					    "presentable": false,
 | 
				
			||||||
    "unique": true,
 | 
					    "unique": true,
 | 
				
			||||||
    "options": {
 | 
					    "options": {
 | 
				
			||||||
      "min": 10,
 | 
					      "min": 10,
 | 
				
			||||||
| 
						 | 
					@ -526,6 +530,7 @@ func init() {
 | 
				
			||||||
			"name": "f4_name",
 | 
								"name": "f4_name",
 | 
				
			||||||
			"type": "text",
 | 
								"type": "text",
 | 
				
			||||||
			"required": false,
 | 
								"required": false,
 | 
				
			||||||
 | 
								"presentable": false,
 | 
				
			||||||
			"unique": false,
 | 
								"unique": false,
 | 
				
			||||||
			"options": {
 | 
								"options": {
 | 
				
			||||||
				"min": null,
 | 
									"min": null,
 | 
				
			||||||
| 
						 | 
					@ -543,6 +548,7 @@ func init() {
 | 
				
			||||||
			"name": "f2_name_new",
 | 
								"name": "f2_name_new",
 | 
				
			||||||
			"type": "number",
 | 
								"type": "number",
 | 
				
			||||||
			"required": false,
 | 
								"required": false,
 | 
				
			||||||
 | 
								"presentable": false,
 | 
				
			||||||
			"unique": true,
 | 
								"unique": true,
 | 
				
			||||||
			"options": {
 | 
								"options": {
 | 
				
			||||||
				"min": 10,
 | 
									"min": 10,
 | 
				
			||||||
| 
						 | 
					@ -593,6 +599,7 @@ func init() {
 | 
				
			||||||
			"name": "f3_name",
 | 
								"name": "f3_name",
 | 
				
			||||||
			"type": "bool",
 | 
								"type": "bool",
 | 
				
			||||||
			"required": false,
 | 
								"required": false,
 | 
				
			||||||
 | 
								"presentable": false,
 | 
				
			||||||
			"unique": false,
 | 
								"unique": false,
 | 
				
			||||||
			"options": {}
 | 
								"options": {}
 | 
				
			||||||
		}` + "`" + `), del_f3_name)
 | 
							}` + "`" + `), del_f3_name)
 | 
				
			||||||
| 
						 | 
					@ -609,6 +616,7 @@ func init() {
 | 
				
			||||||
			"name": "f2_name",
 | 
								"name": "f2_name",
 | 
				
			||||||
			"type": "number",
 | 
								"type": "number",
 | 
				
			||||||
			"required": false,
 | 
								"required": false,
 | 
				
			||||||
 | 
								"presentable": false,
 | 
				
			||||||
			"unique": true,
 | 
								"unique": true,
 | 
				
			||||||
			"options": {
 | 
								"options": {
 | 
				
			||||||
				"min": 10,
 | 
									"min": 10,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue