From 8d240499526333d71a2ed978cbaa3eb1955ceb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pere=20Gim=C3=A9nez?= Date: Wed, 11 Dec 2024 20:17:47 +0100 Subject: [PATCH] Added functions for exporting and importing model field values from Dict (#306) * added functions for exporting and importing model field values from Dict * remove reactive warning --- src/ModelStorage.jl | 66 ++++++++++++++++++++++++++++++++++++++++++++- src/Stipple.jl | 3 +-- test/runtests.jl | 34 ++++++++++++++++++++++- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/ModelStorage.jl b/src/ModelStorage.jl index eb38fd34..0f5f032e 100644 --- a/src/ModelStorage.jl +++ b/src/ModelStorage.jl @@ -1,4 +1,68 @@ module ModelStorage +using JSON3 +using Stipple +import Stipple: INTERNALFIELDS, AUTOFIELDS, Reactive + +const DEFAULT_EXCLUDE = vcat(INTERNALFIELDS, AUTOFIELDS) + +""" + model_values(model::M; fields::Vector{Symbol} = Symbol[], exclude::Vector{Symbol} = Symbol[], json::Bool = false) where M + +Exports the values of reactive fields from a Stipple model. Returns either a Dict of field-value pairs or a JSON string +if json=true. + +### Example + + @app TestApp2 begin + @in i = 100 + @out s = "Hello" + @private x = 4 + end + + model = @init TestApp2 + exported_values = Stipple.ModelStorage.model_values(model) +""" +function model_values(model::M; fields::Vector{Symbol} = Symbol[], exclude::Vector{Symbol} = Symbol[], json::Bool = false) where M + field_list = isempty(fields) ? fieldnames(M) : fields + excluded_fields = vcat(DEFAULT_EXCLUDE, exclude) + + field_dict = Dict(field => getfield(model, field)[] for field in field_list + if field ∉ excluded_fields && getfield(model, field) isa Stipple.Reactive) + + json ? JSON3.write(field_dict) : field_dict +end + +""" + load_model_values!(model::M, values::Dict{Symbol, Any}) where M + load_model_values!(model::M, values::String) where M + +Loads values into the fields of a ReactiveModel. Accepts either a Dict of field-value pairs or a JSON string. + +### Example + + values_dict = Dict(:i => 20, :s => "world", :x => 5) + Stipple.ModelStorage.load_model_values!(model, values_dict) +""" +function load_model_values!(model::M, values::Dict{Symbol, Any}) where M + model_field_list = fieldnames(M) + excluded_fields = DEFAULT_EXCLUDE + + for (field, value) in values + if field ∉ excluded_fields && field ∈ model_field_list + model_field = getfield(model, field) + + if model_field isa Reactive + model_field[] = value + end + end + end + + return model +end + +function load_model_values!(model::M, values::String) where M + load_model_values!(model, Dict(JSON3.read(values))) +end module Sessions @@ -61,4 +125,4 @@ end end # module Sessions -end # module ModelStorage \ No newline at end of file +end # module ModelStorage diff --git a/src/Stipple.jl b/src/Stipple.jl index 45c9c5d8..0a0d7619 100644 --- a/src/Stipple.jl +++ b/src/Stipple.jl @@ -100,10 +100,9 @@ export setchannel, getchannel isempty(methods(notify, Observables)) && (Base.notify(observable::AbstractObservable) = Observables.notify!(observable)) include("ParsingTools.jl") -use_model_storage() && include("ModelStorage.jl") include("NamedTuples.jl") - include("stipple/reactivity.jl") +use_model_storage() && include("ModelStorage.jl") include("stipple/json.jl") include("stipple/undefined.jl") include("stipple/assets.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 61ff58c9..fc0bd72b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -559,4 +559,36 @@ end @test Stipple.Layout.THEMES[][end] == my_css remove_css(my_css, byname = true) @test findfirst(==(my_css), Stipple.Layout.THEMES[]) === nothing -end \ No newline at end of file +end + +@testset "Exporting and loading model field values" begin + @app TestApp2 begin + @in i = 100 + @out s = "Hello" + @private x = 4 + end + + model = @init TestApp2 + + exported_values = Stipple.ModelStorage.model_values(model) + @test exported_values[:i] == 100 + @test exported_values[:s] == "Hello" + @test exported_values[:x] == 4 + + values_json = JSON3.write(exported_values) + exported_values_json = Stipple.ModelStorage.model_values(model, json = true) + @test values_json == exported_values_json + + values_dict = Dict(:i => 20, :s => "world", :x => 5) + Stipple.ModelStorage.load_model_values!(model, values_dict) + @test model.i[] == 20 + @test model.s[] == "world" + @test model.x[] == 5 + + values_json = Dict(:i => 30, :s => "zero", :x => 50) |> JSON3.write |> string + Stipple.ModelStorage.load_model_values!(model, values_json) + @test model.i[] == 30 + @test model.s[] == "zero" + @test model.x[] == 50 + +end