Skip to content

Commit

Permalink
added SchemaField.Presentable field
Browse files Browse the repository at this point in the history
  • Loading branch information
ganigeorgiev committed Aug 21, 2023
1 parent 1e99555 commit 864bbe7
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 221 deletions.
87 changes: 2 additions & 85 deletions apis/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/list"
)
Expand Down Expand Up @@ -401,7 +400,7 @@ func TestCollectionCreate(t *testing.T) {
`"name":"new"`,
`"type":"base"`,
`"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":{}`,
},
ExpectedEvents: map[string]int{
Expand All @@ -425,7 +424,7 @@ func TestCollectionCreate(t *testing.T) {
`"name":"new"`,
`"type":"auth"`,
`"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}`,
},
ExpectedEvents: map[string]int{
Expand Down Expand Up @@ -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
// -----------------------------------------------------------
{
Expand Down
49 changes: 0 additions & 49 deletions daos/record_table_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tools/dbutils"
"github.com/pocketbase/pocketbase/tools/list"
"github.com/pocketbase/pocketbase/tools/security"
)

Expand Down Expand Up @@ -159,10 +158,6 @@ func (dao *Dao) SyncRecordTableSchema(newCollection *models.Collection, oldColle
return err
}

if err := txDao.syncRelationDisplayFieldsChanges(newCollection, renamedFieldNames, deletedFieldNames); err != nil {
return err
}

return txDao.createCollectionIndexes(newCollection)
})
}
Expand Down Expand Up @@ -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 {
if collection.IsView() {
return nil // views don't have indexes
Expand Down
22 changes: 0 additions & 22 deletions forms/collection_upsert.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,6 @@ func (form *CollectionUpsert) ensureNoFieldsTypeChange(value any) error {
func (form *CollectionUpsert) checkRelationFields(value any) error {
v, _ := value.(schema.Schema)

systemDisplayFields := schema.BaseModelFieldNames()
systemDisplayFields = append(systemDisplayFields,
schema.FieldNameUsername,
schema.FieldNameEmail,
schema.FieldNameEmailVisibility,
schema.FieldNameVerified,
)

for i, field := range v.Fields() {
if field.Type != schema.FieldTypeRelation {
continue
Expand Down Expand Up @@ -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
Expand Down
21 changes: 1 addition & 20 deletions forms/collection_upsert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,25 +171,6 @@ func TestCollectionUpsertValidateAndSubmit(t *testing.T) {
}`,
[]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",
"",
Expand Down Expand Up @@ -605,7 +586,7 @@ func TestCollectionUpsertValidateAndSubmit(t *testing.T) {
}

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 {
Expand Down
7 changes: 6 additions & 1 deletion models/schema/schema_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ type SchemaField struct {
Type string `form:"type" json:"type"`
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.
// Please use the collection.Indexes field to define a unique constraint.
Unique bool `form:"unique" json:"unique"`
Expand Down Expand Up @@ -645,7 +649,8 @@ type RelationOptions struct {
// If nil no limits are applied.
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"`
}

Expand Down

0 comments on commit 864bbe7

Please sign in to comment.