diff --git a/CHANGELOG.md b/CHANGELOG.md index c3dae210..68662ee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ > [!CAUTION] > **This is a prerelease intended for test and experimental purposes only!** -- Fixed auto `www.` redirect due to missing schema. +- Fixed auto `www.` redirect due to missing URI schema. + +- Fixed collection and field renaming when reusing an old collection/field name ([#5741](https://github.com/pocketbase/pocketbase/issues/5741)). - Update the "API preview" section to include information about the batch api. diff --git a/apis/collection.go b/apis/collection.go index b25972b6..ea6e3bc5 100644 --- a/apis/collection.go +++ b/apis/collection.go @@ -182,9 +182,15 @@ func collectionTruncate(e *core.RequestEvent) error { } func collectionScaffolds(e *core.RequestEvent) error { - return e.JSON(http.StatusOK, map[string]*core.Collection{ + collections := map[string]*core.Collection{ core.CollectionTypeBase: core.NewBaseCollection(""), core.CollectionTypeAuth: core.NewAuthCollection(""), core.CollectionTypeView: core.NewViewCollection(""), - }) + } + + for _, c := range collections { + c.Id = "" // clear autogenerated id + } + + return e.JSON(http.StatusOK, collections) } diff --git a/apis/collection_test.go b/apis/collection_test.go index c8d2cdda..e4b93d6b 100644 --- a/apis/collection_test.go +++ b/apis/collection_test.go @@ -503,7 +503,7 @@ func TestCollectionCreate(t *testing.T) { "emailChangeToken":{"duration":123}, "fields":[ {"type":"text","id":"12345789","name":"test"}, - {"type":"text","name":"tokenKey","required":false,"min":10} + {"type":"text","name":"tokenKey","system":true,"required":false,"min":10} ] }`), Headers: map[string]string{ @@ -1409,6 +1409,8 @@ func TestCollectionScaffolds(t *testing.T) { }, ExpectedStatus: 200, ExpectedContent: []string{ + `"id":""`, + `"name":""`, `"auth":{`, `"base":{`, `"view":{`, diff --git a/core/collection_model.go b/core/collection_model.go index e952ccf4..0f27de26 100644 --- a/core/collection_model.go +++ b/core/collection_model.go @@ -660,8 +660,13 @@ func onCollectionDeleteExecute(e *CollectionEvent) error { // ------------------------------------------------------------------- func (c *Collection) initDefaultId() { - if c.Id == "" && c.Name != "" { - c.Id = "_pbc_" + crc32Checksum(c.Name) + if c.Id == "" { + if c.System && c.Name != "" { + // for system collections we use crc32 checksum for consistency because they cannot be renamed + c.Id = "_pbc_" + crc32Checksum(c.Name) + } else { + c.Id = "_pbc_" + security.RandomStringWithAlphabet(10, DefaultIdAlphabet) + } } } diff --git a/core/collection_model_test.go b/core/collection_model_test.go index 879f583a..2d76e66d 100644 --- a/core/collection_model_test.go +++ b/core/collection_model_test.go @@ -26,7 +26,7 @@ func TestNewCollection(t *testing.T) { "", "", []string{ - `"id":""`, + `"id":"_pbc_`, `"name":""`, `"type":"base"`, `"system":false`, @@ -45,7 +45,7 @@ func TestNewCollection(t *testing.T) { "unknown", "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"base"`, `"system":false`, @@ -64,7 +64,7 @@ func TestNewCollection(t *testing.T) { "base", "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"base"`, `"system":false`, @@ -83,7 +83,7 @@ func TestNewCollection(t *testing.T) { "view", "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"view"`, `"indexes":[]`, @@ -100,7 +100,7 @@ func TestNewCollection(t *testing.T) { "auth", "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"auth"`, `"fields":[{`, @@ -148,7 +148,7 @@ func TestNewBaseCollection(t *testing.T) { { "", []string{ - `"id":""`, + `"id":"_pbc_`, `"name":""`, `"type":"base"`, `"system":false`, @@ -166,7 +166,7 @@ func TestNewBaseCollection(t *testing.T) { { "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"base"`, `"system":false`, @@ -206,7 +206,7 @@ func TestNewViewCollection(t *testing.T) { { "", []string{ - `"id":""`, + `"id":"_pbc_`, `"name":""`, `"type":"view"`, `"indexes":[]`, @@ -222,7 +222,7 @@ func TestNewViewCollection(t *testing.T) { { "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"view"`, `"indexes":[]`, @@ -286,7 +286,7 @@ func TestNewAuthCollection(t *testing.T) { { "test", []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"auth"`, `"fields":[{`, @@ -498,10 +498,11 @@ func TestCollectionUnmarshalJSON(t *testing.T) { defer app.Cleanup() scenarios := []struct { - name string - raw string - collection func() *core.Collection - expectedCollection func() *core.Collection + name string + raw string + collection func() *core.Collection + expected []string + notExpected []string }{ { "base new empty", @@ -509,12 +510,18 @@ func TestCollectionUnmarshalJSON(t *testing.T) { func() *core.Collection { return &core.Collection{} }, - func() *core.Collection { - c := core.NewBaseCollection("test") - c.ListRule = types.Pointer("1=2") - c.AuthRule = types.Pointer("1=3") - c.ViewQuery = "abc" - return c + []string{ + `"type":"base"`, + `"id":"_pbc_`, + `"name":"test"`, + `"listRule":"1=2"`, + `"fields":[`, + `"name":"id"`, + `"indexes":[]`, + }, + []string{ + `"authRule":"1=3"`, + `"viewQuery":"abc"`, }, }, { @@ -523,12 +530,17 @@ func TestCollectionUnmarshalJSON(t *testing.T) { func() *core.Collection { return &core.Collection{} }, - func() *core.Collection { - c := core.NewViewCollection("test") - c.ListRule = types.Pointer("1=2") - c.AuthRule = types.Pointer("1=3") - c.ViewQuery = "abc" - return c + []string{ + `"type":"view"`, + `"id":"_pbc_`, + `"name":"test"`, + `"listRule":"1=2"`, + `"fields":[]`, + `"viewQuery":"abc"`, + `"indexes":[]`, + }, + []string{ + `"authRule":"1=3"`, }, }, { @@ -537,12 +549,18 @@ func TestCollectionUnmarshalJSON(t *testing.T) { func() *core.Collection { return &core.Collection{} }, - func() *core.Collection { - c := core.NewAuthCollection("test") - c.ListRule = types.Pointer("1=2") - c.AuthRule = types.Pointer("1=3") - c.ViewQuery = "abc" - return c + []string{ + `"type":"auth"`, + `"id":"_pbc_`, + `"name":"test"`, + `"listRule":"1=2"`, + `"authRule":"1=3"`, + `"fields":[`, + `"name":"id"`, + }, + []string{ + `"indexes":[]`, + `"viewQuery":"abc"`, }, }, { @@ -553,14 +571,16 @@ func TestCollectionUnmarshalJSON(t *testing.T) { c.Type = core.CollectionTypeBase return c }, - func() *core.Collection { - c := &core.Collection{} - c.Type = core.CollectionTypeBase - c.Name = "test" - c.ListRule = types.Pointer("1=2") - c.AuthRule = types.Pointer("1=3") - c.ViewQuery = "abc" - return c + []string{ + `"type":"base"`, + `"id":""`, + `"name":"test"`, + `"listRule":"1=2"`, + `"fields":[]`, + }, + []string{ + `"authRule":"1=3"`, + `"viewQuery":"abc"`, }, }, { @@ -570,14 +590,17 @@ func TestCollectionUnmarshalJSON(t *testing.T) { c, _ := app.FindCollectionByNameOrId("demo1") return c }, - func() *core.Collection { - c, _ := app.FindCollectionByNameOrId("demo1") - c.Type = core.CollectionTypeAuth - c.Name = "test" - c.ListRule = types.Pointer("1=2") - c.AuthRule = types.Pointer("1=3") - c.ViewQuery = "abc" - return c + []string{ + `"type":"auth"`, + `"name":"test"`, + `"listRule":"1=2"`, + `"authRule":"1=3"`, + `"fields":[`, + `"name":"id"`, + }, + []string{ + `"name":"tokenKey"`, + `"viewQuery":"abc"`, }, }, } @@ -597,14 +620,16 @@ func TestCollectionUnmarshalJSON(t *testing.T) { } rawResultStr := string(rawResult) - rawExpected, err := json.Marshal(s.expectedCollection()) - if err != nil { - t.Fatal(err) + for _, part := range s.expected { + if !strings.Contains(rawResultStr, part) { + t.Fatalf("Missing expected %q in\n%v", part, rawResultStr) + } } - rawExpectedStr := string(rawExpected) - if rawResultStr != rawExpectedStr { - t.Fatalf("Expected collection\n%s\ngot\n%s", rawExpectedStr, rawResultStr) + for _, part := range s.notExpected { + if strings.Contains(rawResultStr, part) { + t.Fatalf("Didn't expected %q in\n%v", part, rawResultStr) + } } }) } @@ -630,7 +655,7 @@ func TestCollectionSerialize(t *testing.T) { return c }, []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"base"`, }, @@ -658,7 +683,7 @@ func TestCollectionSerialize(t *testing.T) { return c }, []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"view"`, `"viewQuery":"1=1"`, @@ -686,7 +711,7 @@ func TestCollectionSerialize(t *testing.T) { return c }, []string{ - `"id":"_pbc_3632233996"`, + `"id":"_pbc_`, `"name":"test"`, `"type":"auth"`, `"oauth2":{`, @@ -748,19 +773,19 @@ func TestCollectionDBExport(t *testing.T) { }{ { "unknown", - `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"bool597745380","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"bool3131674462","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":"{}","system":true,"type":"unknown","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, + `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"f1_id","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"f2_id","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":"{}","system":true,"type":"unknown","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, }, { core.CollectionTypeBase, - `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"bool597745380","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"bool3131674462","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":"{}","system":true,"type":"base","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, + `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"f1_id","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"f2_id","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":"{}","system":true,"type":"base","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, }, { core.CollectionTypeView, - `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"bool597745380","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"bool3131674462","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":{"viewQuery":"select 1"},"system":true,"type":"view","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, + `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"f1_id","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"f2_id","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":{"viewQuery":"select 1"},"system":true,"type":"view","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, }, { core.CollectionTypeAuth, - `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"bool597745380","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"bool3131674462","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":{"authRule":null,"manageRule":"1=6","authAlert":{"enabled":false,"emailTemplate":{"subject":"","body":""}},"oauth2":{"providers":null,"mappedFields":{"id":"","name":"","username":"","avatarURL":""},"enabled":false},"passwordAuth":{"enabled":false,"identityFields":null},"mfa":{"enabled":false,"duration":0,"rule":""},"otp":{"enabled":false,"duration":0,"length":0,"emailTemplate":{"subject":"","body":""}},"authToken":{"duration":0},"passwordResetToken":{"duration":0},"emailChangeToken":{"duration":0},"verificationToken":{"duration":0},"fileToken":{"duration":0},"verificationTemplate":{"subject":"","body":""},"resetPasswordTemplate":{"subject":"","body":""},"confirmEmailChangeTemplate":{"subject":"","body":""}},"system":true,"type":"auth","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, + `{"createRule":"1=3","created":"2024-07-01 01:02:03.456Z","deleteRule":"1=5","fields":[{"hidden":false,"id":"f1_id","name":"f1","presentable":false,"required":false,"system":true,"type":"bool"},{"hidden":false,"id":"f2_id","name":"f2","presentable":false,"required":true,"system":false,"type":"bool"}],"id":"test_id","indexes":["CREATE INDEX idx1 on test_name(id)","CREATE INDEX idx2 on test_name(id)"],"listRule":"1=1","name":"test_name","options":{"authRule":null,"manageRule":"1=6","authAlert":{"enabled":false,"emailTemplate":{"subject":"","body":""}},"oauth2":{"providers":null,"mappedFields":{"id":"","name":"","username":"","avatarURL":""},"enabled":false},"passwordAuth":{"enabled":false,"identityFields":null},"mfa":{"enabled":false,"duration":0,"rule":""},"otp":{"enabled":false,"duration":0,"length":0,"emailTemplate":{"subject":"","body":""}},"authToken":{"duration":0},"passwordResetToken":{"duration":0},"emailChangeToken":{"duration":0},"verificationToken":{"duration":0},"fileToken":{"duration":0},"verificationTemplate":{"subject":"","body":""},"resetPasswordTemplate":{"subject":"","body":""},"confirmEmailChangeTemplate":{"subject":"","body":""}},"system":true,"type":"auth","updateRule":"1=4","updated":"2024-07-01 01:02:03.456Z","viewRule":"1=7"}`, }, } @@ -782,8 +807,8 @@ func TestCollectionDBExport(t *testing.T) { c.Updated = date c.Indexes = types.JSONArray[string]{"CREATE INDEX idx1 on test_name(id)", "CREATE INDEX idx2 on test_name(id)"} c.ViewQuery = "select 1" - c.Fields.Add(&core.BoolField{Name: "f1", System: true}) - c.Fields.Add(&core.BoolField{Name: "f2", Required: true}) + c.Fields.Add(&core.BoolField{Id: "f1_id", Name: "f1", System: true}) + c.Fields.Add(&core.BoolField{Id: "f2_id", Name: "f2", Required: true}) c.RawOptions = types.JSONRaw(`{"viewQuery": "select 2"}`) // should be ignored result, err := c.DBExport(app) diff --git a/core/collection_validate.go b/core/collection_validate.go index 9da95f69..34f0bf40 100644 --- a/core/collection_validate.go +++ b/core/collection_validate.go @@ -416,6 +416,10 @@ func (validator *collectionValidator) ensureNoSystemFieldsChange(value any) erro return validators.ErrUnsupportedValueType } + if validator.original.IsNew() { + return nil // not an update + } + for _, oldField := range validator.original.Fields { if !oldField.GetSystem() { continue diff --git a/core/fields_list.go b/core/fields_list.go index c3be1bd7..5e640d8f 100644 --- a/core/fields_list.go +++ b/core/fields_list.go @@ -108,13 +108,13 @@ func (l *FieldsList) RemoveByName(fieldName string) { // Add adds one or more fields to the current list. // -// If any of the new fields doesn't have an id it will try to set a -// default one based on its type and name. +// By default this method will try to REPLACE existing fields with +// the new ones by their id or by their name if the new field doesn't have an explicit id. // -// If the list already has a field with the same id, -// then the existing field is replaced with the new one. +// If no matching existing field is found, it will APPEND the field to the end of the list. // -// Otherwise the new field is appended after the other list fields. +// In all cases, if any of the new fields don't have an explicit id it will auto generate a default one for them +// (the id value doesn't really matter and it is mostly used as a stable identifier in case of a field rename). func (l *FieldsList) Add(fields ...Field) { for _, f := range fields { l.add(f) @@ -124,7 +124,9 @@ func (l *FieldsList) Add(fields ...Field) { // AddMarshaledJSON parses the provided raw json data and adds the // found fields into the current list (following the same rule as the Add method). // -// rawJSON could be either a serialized array of field objects or a single field object. +// The rawJSON argument could be one of: +// - serialized array of field objects +// - single field object. // // Example: // @@ -160,29 +162,41 @@ func (l *FieldsList) AddMarshaledJSON(rawJSON []byte) error { } func (l *FieldsList) add(newField Field) { + fields := *l + + var replaceByName bool + newFieldId := newField.GetId() // set default id if newFieldId == "" { - if newField.GetName() != "" { + replaceByName = true + if newField.GetSystem() && newField.GetName() != "" { + // for system fields we use crc32 checksum for consistency because they cannot be renamed newFieldId = newField.Type() + crc32Checksum(newField.GetName()) } else { - newFieldId = newField.Type() + security.RandomString(5) + newFieldId = newField.Type() + security.RandomString(7) } - newField.SetId(newFieldId) } - fields := *l - + // replace existing for i, field := range fields { - // replace existing - if newFieldId != "" && field.GetId() == newFieldId { - (*l)[i] = newField - return + if replaceByName { + if name := newField.GetName(); name != "" && field.GetName() == name { + newField.SetId(field.GetId()) + (*l)[i] = newField + return + } + } else { + if field.GetId() == newFieldId { + (*l)[i] = newField + return + } } } // add new field + newField.SetId(newFieldId) *l = append(fields, newField) } diff --git a/core/record_model_test.go b/core/record_model_test.go index 0f5e3ade..c8a6bfa2 100644 --- a/core/record_model_test.go +++ b/core/record_model_test.go @@ -414,6 +414,8 @@ func TestRecordMergeExpand(t *testing.T) { t.Parallel() collection := core.NewBaseCollection("test") + collection.Id = "_pbc_123" + m := core.NewRecord(collection) m.Id = "m" @@ -497,7 +499,7 @@ func TestRecordMergeExpand(t *testing.T) { } rawStr := string(raw) - expected := `{"a":{"collectionId":"_pbc_3632233996","collectionName":"test","expand":{"a1":{"collectionId":"_pbc_3632233996","collectionName":"test","id":"a1"},"a23":[{"collectionId":"_pbc_3632233996","collectionName":"test","id":"a2"},{"collectionId":"_pbc_3632233996","collectionName":"test","expand":{"a31":{"collectionId":"_pbc_3632233996","collectionName":"test","id":"a31"},"a32":[{"collectionId":"_pbc_3632233996","collectionName":"test","id":"a32"},{"collectionId":"_pbc_3632233996","collectionName":"test","id":"a32New"}],"a33New":{"collectionId":"_pbc_3632233996","collectionName":"test","id":"a33New"}},"id":"a3"}]},"id":"a"},"b":[{"collectionId":"_pbc_3632233996","collectionName":"test","expand":{"b1":{"collectionId":"_pbc_3632233996","collectionName":"test","id":"b1"}},"id":"b"},{"collectionId":"_pbc_3632233996","collectionName":"test","id":"bNew"}],"c":[{"collectionId":"_pbc_3632233996","collectionName":"test","id":"c"}],"dNew":{"collectionId":"_pbc_3632233996","collectionName":"test","id":"dNew"}}` + expected := `{"a":{"collectionId":"_pbc_123","collectionName":"test","expand":{"a1":{"collectionId":"_pbc_123","collectionName":"test","id":"a1"},"a23":[{"collectionId":"_pbc_123","collectionName":"test","id":"a2"},{"collectionId":"_pbc_123","collectionName":"test","expand":{"a31":{"collectionId":"_pbc_123","collectionName":"test","id":"a31"},"a32":[{"collectionId":"_pbc_123","collectionName":"test","id":"a32"},{"collectionId":"_pbc_123","collectionName":"test","id":"a32New"}],"a33New":{"collectionId":"_pbc_123","collectionName":"test","id":"a33New"}},"id":"a3"}]},"id":"a"},"b":[{"collectionId":"_pbc_123","collectionName":"test","expand":{"b1":{"collectionId":"_pbc_123","collectionName":"test","id":"b1"}},"id":"b"},{"collectionId":"_pbc_123","collectionName":"test","id":"bNew"}],"c":[{"collectionId":"_pbc_123","collectionName":"test","id":"c"}],"dNew":{"collectionId":"_pbc_123","collectionName":"test","id":"dNew"}}` if expected != rawStr { t.Fatalf("Expected \n%v, \ngot \n%v", expected, rawStr) @@ -508,6 +510,7 @@ func TestRecordMergeExpandNilCheck(t *testing.T) { t.Parallel() collection := core.NewBaseCollection("test") + collection.Id = "_pbc_123" scenarios := []struct { name string @@ -517,17 +520,17 @@ func TestRecordMergeExpandNilCheck(t *testing.T) { { "nil expand", nil, - `{"collectionId":"_pbc_3632233996","collectionName":"test","id":""}`, + `{"collectionId":"_pbc_123","collectionName":"test","id":""}`, }, { "empty expand", map[string]any{}, - `{"collectionId":"_pbc_3632233996","collectionName":"test","id":""}`, + `{"collectionId":"_pbc_123","collectionName":"test","id":""}`, }, { "non-empty expand", map[string]any{"test": core.NewRecord(collection)}, - `{"collectionId":"_pbc_3632233996","collectionName":"test","expand":{"test":{"collectionId":"_pbc_3632233996","collectionName":"test","id":""}},"id":""}`, + `{"collectionId":"_pbc_123","collectionName":"test","expand":{"test":{"collectionId":"_pbc_123","collectionName":"test","id":""}},"id":""}`, }, } @@ -1308,9 +1311,11 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { f5 := &core.TextField{Name: "field5", Hidden: true} colBase := core.NewBaseCollection("test_base") + colBase.Id = "_pbc_base_123" colBase.Fields.Add(f1, f2, f3, f4, f5) colAuth := core.NewAuthCollection("test_auth") + colAuth.Id = "_pbc_auth_123" colAuth.Fields.Add(f1, f2, f3, f4, f5) scenarios := []struct { @@ -1330,7 +1335,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { false, nil, nil, - `{"collectionId":"_pbc_3318600878","collectionName":"test_base","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id"}`, + `{"collectionId":"_pbc_base_123","collectionName":"test_base","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id"}`, }, { "[base] with email visibility", @@ -1339,7 +1344,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { false, nil, nil, - `{"collectionId":"_pbc_3318600878","collectionName":"test_base","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id"}`, + `{"collectionId":"_pbc_base_123","collectionName":"test_base","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id"}`, }, { "[base] with custom data", @@ -1348,7 +1353,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { true, nil, nil, - `{"collectionId":"_pbc_3318600878","collectionName":"test_base","email":"test_email","emailVisibility":"test_invalid","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","password":"test_passwordHash","tokenKey":"test_tokenKey","unknown":"test_unknown","verified":true}`, + `{"collectionId":"_pbc_base_123","collectionName":"test_base","email":"test_email","emailVisibility":"test_invalid","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","password":"test_passwordHash","tokenKey":"test_tokenKey","unknown":"test_unknown","verified":true}`, }, { "[base] with explicit hide and unhide fields", @@ -1366,7 +1371,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { true, nil, []string{"field5", "@pbInternalAbc", "email", "tokenKey", "unknown"}, - `{"collectionId":"_pbc_3318600878","collectionName":"test_base","email":"test_email","emailVisibility":"test_invalid","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"field5":"field_5","id":"test_id","password":"test_passwordHash","tokenKey":"test_tokenKey","unknown":"test_unknown","verified":true}`, + `{"collectionId":"_pbc_base_123","collectionName":"test_base","email":"test_email","emailVisibility":"test_invalid","expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"field5":"field_5","id":"test_id","password":"test_passwordHash","tokenKey":"test_tokenKey","unknown":"test_unknown","verified":true}`, }, // auth @@ -1377,7 +1382,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { false, nil, nil, - `{"collectionId":"_pbc_4255619734","collectionName":"test_auth","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","verified":true}`, + `{"collectionId":"_pbc_auth_123","collectionName":"test_auth","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","verified":true}`, }, { "[auth] with email visibility", @@ -1386,7 +1391,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { false, nil, nil, - `{"collectionId":"_pbc_4255619734","collectionName":"test_auth","email":"test_email","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","verified":true}`, + `{"collectionId":"_pbc_auth_123","collectionName":"test_auth","email":"test_email","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","verified":true}`, }, { "[auth] with custom data", @@ -1395,7 +1400,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { true, nil, nil, - `{"collectionId":"_pbc_4255619734","collectionName":"test_auth","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","unknown":"test_unknown","verified":true}`, + `{"collectionId":"_pbc_auth_123","collectionName":"test_auth","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"id":"test_id","unknown":"test_unknown","verified":true}`, }, { "[auth] with explicit hide and unhide fields", @@ -1413,7 +1418,7 @@ func TestRecordPublicExportAndMarshalJSON(t *testing.T) { true, nil, []string{"field5", "@pbInternalAbc", "tokenKey", "unknown", "email"}, // emailVisibility:false has higher priority - `{"collectionId":"_pbc_4255619734","collectionName":"test_auth","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"field5":"field_5","id":"test_id","unknown":"test_unknown","verified":true}`, + `{"collectionId":"_pbc_auth_123","collectionName":"test_auth","emailVisibility":false,"expand":{"test":123},"field1":"field_1","field2":"field_2.png","field3":["test1","test2"],"field5":"field_5","id":"test_id","unknown":"test_unknown","verified":true}`, }, } diff --git a/plugins/migratecmd/migratecmd_test.go b/plugins/migratecmd/migratecmd_test.go index 57412978..50465336 100644 --- a/plugins/migratecmd/migratecmd_test.go +++ b/plugins/migratecmd/migratecmd_test.go @@ -3,12 +3,14 @@ package migratecmd_test import ( "os" "path/filepath" + "regexp" "strings" "testing" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/plugins/migratecmd" "github.com/pocketbase/pocketbase/tests" + "github.com/pocketbase/pocketbase/tools/list" "github.com/pocketbase/pocketbase/tools/types" ) @@ -49,7 +51,7 @@ migrate((app) => { { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, - "id": "text3208210256", + "id": "text@TEST_RANDOM", "max": 15, "min": 15, "name": "id", @@ -63,7 +65,7 @@ migrate((app) => { { "cost": 0, "hidden": true, - "id": "password901924565", + "id": "password@TEST_RANDOM", "max": 0, "min": 8, "name": "password", @@ -76,7 +78,7 @@ migrate((app) => { { "autogeneratePattern": "[a-zA-Z0-9]{50}", "hidden": true, - "id": "text2504183744", + "id": "text@TEST_RANDOM", "max": 60, "min": 30, "name": "tokenKey", @@ -90,7 +92,7 @@ migrate((app) => { { "exceptDomains": null, "hidden": false, - "id": "email3885137012", + "id": "email@TEST_RANDOM", "name": "email", "onlyDomains": null, "presentable": false, @@ -100,7 +102,7 @@ migrate((app) => { }, { "hidden": false, - "id": "bool1547992806", + "id": "bool@TEST_RANDOM", "name": "emailVisibility", "presentable": false, "required": false, @@ -109,7 +111,7 @@ migrate((app) => { }, { "hidden": false, - "id": "bool256245529", + "id": "bool@TEST_RANDOM", "name": "verified", "presentable": false, "required": false, @@ -120,11 +122,11 @@ migrate((app) => { "fileToken": { "duration": 180 }, - "id": "_pbc_2865679067", + "id": "@TEST_RANDOM", "indexes": [ "create index test on new_name (id)", - "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey__pbc_2865679067` + "`" + ` ON ` + "`" + `new_name` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", - "CREATE UNIQUE INDEX ` + "`" + `idx_email__pbc_2865679067` + "`" + ` ON ` + "`" + `new_name` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" + "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey_@TEST_RANDOM` + "`" + ` ON ` + "`" + `new_name` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", + "CREATE UNIQUE INDEX ` + "`" + `idx_email_@TEST_RANDOM` + "`" + ` ON ` + "`" + `new_name` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" ], "listRule": "@request.auth.id != '' && 1 > 0 || 'backtick` + "`" + `test' = 0", "manageRule": "1 != 2", @@ -180,7 +182,7 @@ migrate((app) => { return app.save(collection); }, (app) => { - const collection = app.findCollectionByNameOrId("_pbc_2865679067"); + const collection = app.findCollectionByNameOrId("@TEST_RANDOM"); return app.delete(collection); }) @@ -225,7 +227,7 @@ func init() { { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, - "id": "text3208210256", + "id": "text@TEST_RANDOM", "max": 15, "min": 15, "name": "id", @@ -239,7 +241,7 @@ func init() { { "cost": 0, "hidden": true, - "id": "password901924565", + "id": "password@TEST_RANDOM", "max": 0, "min": 8, "name": "password", @@ -252,7 +254,7 @@ func init() { { "autogeneratePattern": "[a-zA-Z0-9]{50}", "hidden": true, - "id": "text2504183744", + "id": "text@TEST_RANDOM", "max": 60, "min": 30, "name": "tokenKey", @@ -266,7 +268,7 @@ func init() { { "exceptDomains": null, "hidden": false, - "id": "email3885137012", + "id": "email@TEST_RANDOM", "name": "email", "onlyDomains": null, "presentable": false, @@ -276,7 +278,7 @@ func init() { }, { "hidden": false, - "id": "bool1547992806", + "id": "bool@TEST_RANDOM", "name": "emailVisibility", "presentable": false, "required": false, @@ -285,7 +287,7 @@ func init() { }, { "hidden": false, - "id": "bool256245529", + "id": "bool@TEST_RANDOM", "name": "verified", "presentable": false, "required": false, @@ -296,11 +298,11 @@ func init() { "fileToken": { "duration": 180 }, - "id": "_pbc_2865679067", + "id": "@TEST_RANDOM", "indexes": [ "create index test on new_name (id)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey__pbc_2865679067` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `new_name` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email__pbc_2865679067` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `new_name` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `new_name` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `new_name` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" ], "listRule": "@request.auth.id != '' && 1 > 0 || 'backtick` + "` + \"`\" + `" + `test' = 0", "manageRule": "1 != 2", @@ -361,7 +363,7 @@ func init() { return app.Save(collection) }, func(app core.App) error { - collection, err := app.FindCollectionByNameOrId("_pbc_2865679067") + collection, err := app.FindCollectionByNameOrId("@TEST_RANDOM") if err != nil { return err } @@ -434,9 +436,16 @@ func init() { if err != nil { t.Fatalf("Failed to read the generated migration file: %v", err) } + contentStr := strings.TrimSpace(string(content)) - if v := strings.TrimSpace(string(content)); v != strings.TrimSpace(s.expectedTemplate) { - t.Fatalf("Expected template \n%v \ngot \n%v", s.expectedTemplate, v) + // replace @TEST_RANDOM placeholder with a regex pattern + expectedTemplate := strings.ReplaceAll( + "^"+regexp.QuoteMeta(strings.TrimSpace(s.expectedTemplate))+"$", + "@TEST_RANDOM", + `\w+`, + ) + if !list.ExistInSliceWithRegex(contentStr, []string{expectedTemplate}) { + t.Fatalf("Expected template \n%v \ngot \n%v", s.expectedTemplate, contentStr) } }) } @@ -454,7 +463,7 @@ func TestAutomigrateCollectionDelete(t *testing.T) { ` /// migrate((app) => { - const collection = app.findCollectionByNameOrId("_pbc_4032078523"); + const collection = app.findCollectionByNameOrId("@TEST_RANDOM"); return app.delete(collection); }, (app) => { @@ -483,7 +492,7 @@ migrate((app) => { { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, - "id": "text3208210256", + "id": "text@TEST_RANDOM", "max": 15, "min": 15, "name": "id", @@ -497,7 +506,7 @@ migrate((app) => { { "cost": 0, "hidden": true, - "id": "password901924565", + "id": "password@TEST_RANDOM", "max": 0, "min": 8, "name": "password", @@ -510,7 +519,7 @@ migrate((app) => { { "autogeneratePattern": "[a-zA-Z0-9]{50}", "hidden": true, - "id": "text2504183744", + "id": "text@TEST_RANDOM", "max": 60, "min": 30, "name": "tokenKey", @@ -534,7 +543,7 @@ migrate((app) => { }, { "hidden": false, - "id": "bool1547992806", + "id": "bool@TEST_RANDOM", "name": "emailVisibility", "presentable": false, "required": false, @@ -554,11 +563,11 @@ migrate((app) => { "fileToken": { "duration": 180 }, - "id": "_pbc_4032078523", + "id": "@TEST_RANDOM", "indexes": [ "create index test on test123 (id)", - "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey__pbc_4032078523` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", - "CREATE UNIQUE INDEX ` + "`" + `idx_email__pbc_4032078523` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" + "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey_@TEST_RANDOM` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", + "CREATE UNIQUE INDEX ` + "`" + `idx_email_@TEST_RANDOM` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" ], "listRule": "@request.auth.id != '' && 1 > 0 || 'backtick` + "`" + `test' = 0", "manageRule": "1 != 2", @@ -630,7 +639,7 @@ import ( func init() { m.Register(func(app core.App) error { - collection, err := app.FindCollectionByNameOrId("_pbc_4032078523") + collection, err := app.FindCollectionByNameOrId("@TEST_RANDOM") if err != nil { return err } @@ -662,7 +671,7 @@ func init() { { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, - "id": "text3208210256", + "id": "text@TEST_RANDOM", "max": 15, "min": 15, "name": "id", @@ -676,7 +685,7 @@ func init() { { "cost": 0, "hidden": true, - "id": "password901924565", + "id": "password@TEST_RANDOM", "max": 0, "min": 8, "name": "password", @@ -689,7 +698,7 @@ func init() { { "autogeneratePattern": "[a-zA-Z0-9]{50}", "hidden": true, - "id": "text2504183744", + "id": "text@TEST_RANDOM", "max": 60, "min": 30, "name": "tokenKey", @@ -713,7 +722,7 @@ func init() { }, { "hidden": false, - "id": "bool1547992806", + "id": "bool@TEST_RANDOM", "name": "emailVisibility", "presentable": false, "required": false, @@ -733,11 +742,11 @@ func init() { "fileToken": { "duration": 180 }, - "id": "_pbc_4032078523", + "id": "@TEST_RANDOM", "indexes": [ "create index test on test123 (id)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey__pbc_4032078523` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email__pbc_4032078523` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" ], "listRule": "@request.auth.id != '' && 1 > 0 || 'backtick` + "` + \"`\" + `" + `test' = 0", "manageRule": "1 != 2", @@ -859,9 +868,16 @@ func init() { if err != nil { t.Fatalf("Failed to read the generated migration file: %v", err) } + contentStr := strings.TrimSpace(string(content)) - if v := strings.TrimSpace(string(content)); v != strings.TrimSpace(s.expectedTemplate) { - t.Fatalf("Expected template \n%v \ngot \n%v", s.expectedTemplate, v) + // replace @TEST_RANDOM placeholder with a regex pattern + expectedTemplate := strings.ReplaceAll( + "^"+regexp.QuoteMeta(strings.TrimSpace(s.expectedTemplate))+"$", + "@TEST_RANDOM", + `\w+`, + ) + if !list.ExistInSliceWithRegex(contentStr, []string{expectedTemplate}) { + t.Fatalf("Expected template \n%v \ngot \n%v", s.expectedTemplate, contentStr) } }) } @@ -879,7 +895,7 @@ func TestAutomigrateCollectionUpdate(t *testing.T) { ` /// migrate((app) => { - const collection = app.findCollectionByNameOrId("_pbc_4032078523") + const collection = app.findCollectionByNameOrId("@TEST_RANDOM") // update collection data unmarshal({ @@ -890,8 +906,8 @@ migrate((app) => { }, "indexes": [ "create index test1 on test123_update (f1_name)", - "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey__pbc_4032078523` + "`" + ` ON ` + "`" + `test123_update` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", - "CREATE UNIQUE INDEX ` + "`" + `idx_email__pbc_4032078523` + "`" + ` ON ` + "`" + `test123_update` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" + "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey_@TEST_RANDOM` + "`" + ` ON ` + "`" + `test123_update` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", + "CREATE UNIQUE INDEX ` + "`" + `idx_email_@TEST_RANDOM` + "`" + ` ON ` + "`" + `test123_update` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" ], "listRule": "@request.auth.id != ''", "name": "test123_update", @@ -936,7 +952,7 @@ migrate((app) => { return app.save(collection) }, (app) => { - const collection = app.findCollectionByNameOrId("_pbc_4032078523") + const collection = app.findCollectionByNameOrId("@TEST_RANDOM") // update collection data unmarshal({ @@ -947,8 +963,8 @@ migrate((app) => { }, "indexes": [ "create index test1 on test123 (f1_name)", - "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey__pbc_4032078523` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", - "CREATE UNIQUE INDEX ` + "`" + `idx_email__pbc_4032078523` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" + "CREATE UNIQUE INDEX ` + "`" + `idx_tokenKey_@TEST_RANDOM` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `tokenKey` + "`" + `)", + "CREATE UNIQUE INDEX ` + "`" + `idx_email_@TEST_RANDOM` + "`" + ` ON ` + "`" + `test123` + "`" + ` (` + "`" + `email` + "`" + `) WHERE ` + "`" + `email` + "`" + ` != ''" ], "listRule": "@request.auth.id != '' && 1 != 2", "name": "test123", @@ -1005,7 +1021,7 @@ import ( func init() { m.Register(func(app core.App) error { - collection, err := app.FindCollectionByNameOrId("_pbc_4032078523") + collection, err := app.FindCollectionByNameOrId("@TEST_RANDOM") if err != nil { return err } @@ -1019,8 +1035,8 @@ func init() { }, "indexes": [ "create index test1 on test123_update (f1_name)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey__pbc_4032078523` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123_update` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email__pbc_4032078523` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123_update` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123_update` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123_update` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" ], "listRule": "@request.auth.id != ''", "name": "test123_update", @@ -1071,7 +1087,7 @@ func init() { return app.Save(collection) }, func(app core.App) error { - collection, err := app.FindCollectionByNameOrId("_pbc_4032078523") + collection, err := app.FindCollectionByNameOrId("@TEST_RANDOM") if err != nil { return err } @@ -1085,8 +1101,8 @@ func init() { }, "indexes": [ "create index test1 on test123 (f1_name)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey__pbc_4032078523` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", - "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email__pbc_4032078523` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_tokenKey_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `tokenKey` + "` + \"`\" + `" + `)", + "CREATE UNIQUE INDEX ` + "` + \"`\" + `" + `idx_email_@TEST_RANDOM` + "` + \"`\" + `" + ` ON ` + "` + \"`\" + `" + `test123` + "` + \"`\" + `" + ` (` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + `) WHERE ` + "` + \"`\" + `" + `email` + "` + \"`\" + `" + ` != ''" ], "listRule": "@request.auth.id != '' && 1 != 2", "name": "test123", @@ -1240,9 +1256,16 @@ func init() { if err != nil { t.Fatalf("Failed to read the generated migration file: %v", err) } + contentStr := strings.TrimSpace(string(content)) - if v := strings.TrimSpace(string(content)); v != strings.TrimSpace(s.expectedTemplate) { - t.Fatalf("Expected template \n%v \ngot \n%v", s.expectedTemplate, v) + // replace @TEST_RANDOM placeholder with a regex pattern + expectedTemplate := strings.ReplaceAll( + "^"+regexp.QuoteMeta(strings.TrimSpace(s.expectedTemplate))+"$", + "@TEST_RANDOM", + `\w+`, + ) + if !list.ExistInSliceWithRegex(contentStr, []string{expectedTemplate}) { + t.Fatalf("Expected template \n%v \ngot \n%v", s.expectedTemplate, contentStr) } }) }