diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ff10b0..8175ccd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ - Updatated to `modernc.org/sqlite` 1.36.0 (SQLite 3.49.0). +## v0.25.9 + +- Fixed `DynamicModel` object/array props reflect type caching ([#6563](https://github.com/pocketbase/pocketbase/discussions/6563)). + + ## v0.25.8 - Added a default leeway of 5 minutes for the Apple/OIDC `id_token` timestamp claims check to account for clock-skew ([#6529](https://github.com/pocketbase/pocketbase/issues/6529)). diff --git a/plugins/jsvm/binds.go b/plugins/jsvm/binds.go index f0275e88..d63a8e08 100644 --- a/plugins/jsvm/binds.go +++ b/plugins/jsvm/binds.go @@ -1020,8 +1020,6 @@ func structConstructorUnmarshal(vm *goja.Runtime, call goja.ConstructorCall, ins return instanceValue } -var cachedDynamicModels = store.New[string, *dynamicModelType](nil) - // newDynamicModel creates a new dynamic struct with fields based // on the specified "shape". // @@ -1032,16 +1030,7 @@ var cachedDynamicModels = store.New[string, *dynamicModelType](nil) // "total": 0, // }) func newDynamicModel(shape map[string]any) any { - var modelType *dynamicModelType - - shapeRaw, err := json.Marshal(shape) - if err != nil { - modelType = getDynamicModelStruct(shape) - } else { - modelType = cachedDynamicModels.GetOrSet(string(shapeRaw), func() *dynamicModelType { - return getDynamicModelStruct(shape) - }) - } + modelType := getDynamicModelStruct(shape) rvShapeValues := make([]reflect.Value, len(modelType.shapeValues)) for i, v := range modelType.shapeValues { diff --git a/plugins/jsvm/binds_test.go b/plugins/jsvm/binds_test.go index 13421be4..e4f23f69 100644 --- a/plugins/jsvm/binds_test.go +++ b/plugins/jsvm/binds_test.go @@ -1137,6 +1137,46 @@ func TestLoadingDynamicModel(t *testing.T) { } } +// @todo revert the reflect caching and check other types +func TestDynamicModelMapFieldCaching(t *testing.T) { + app, _ := tests.NewTestApp() + defer app.Cleanup() + + vm := goja.New() + baseBinds(vm) + dbxBinds(vm) + vm.Set("$app", app) + + _, err := vm.RunString(` + let m1 = new DynamicModel({ + obj: {}, + }) + + let m2 = new DynamicModel({ + obj: {}, + }) + + m1.obj.set("a", 1) + + m2.obj.set("b", 1) + + let m1Expected = '{"obj":{"a":1}}'; + let m1Serialized = JSON.stringify(m1); + if (m1Serialized != m1Expected) { + throw new Error("Expected m1 \n" + m1Expected + "\ngot\n" + m1Serialized); + } + + let m2Expected = '{"obj":{"b":1}}'; + let m2Serialized = JSON.stringify(m2); + if (m2Serialized != m2Expected) { + throw new Error("Expected m2 \n" + m2Expected + "\ngot\n" + m2Serialized); + } + `) + if err != nil { + t.Fatal(err) + } +} + func TestLoadingArrayOf(t *testing.T) { app, _ := tests.NewTestApp() defer app.Cleanup()