Skip to content

Commit 69c7834

Browse files
louispt1noracato
andauthored
Msgpack metadata (#1553)
* Serialize metadata with MessagePack * Bump bootsnap to 1.18 --------- Co-authored-by: noracato <[email protected]>
1 parent e00f01b commit 69c7834

File tree

8 files changed

+54
-26
lines changed

8 files changed

+54
-26
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ GEM
180180
bindata (2.5.0)
181181
binding_of_caller (1.0.0)
182182
debug_inspector (>= 0.0.1)
183-
bootsnap (1.10.3)
183+
bootsnap (1.18.4)
184184
msgpack (~> 1.2)
185185
builder (3.3.0)
186186
byebug (11.1.3)

app/models/scenario.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class Scenario < ApplicationRecord
1515

1616
serialize :user_values, type: Hash, coder: MessagePack
1717
serialize :balanced_values, type: Hash, coder: MessagePack
18-
serialize :active_couplings, type: Array
19-
store :metadata, coder: JSON
18+
serialize :active_couplings, type: Array
19+
serialize :metadata, type: Hash, coder: MessagePack
2020

2121
has_many :scenario_users, dependent: :destroy
2222
has_many :users, through: :scenario_users

app/views/inspect/scenarios/index.html.haml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
%span.tag.gray Public
4040
%td
4141
= link_to s.id, inspect_scenario_path(:id => s.id)
42-
- if s.metadata[:title]
43-
%span{ style: 'margin: 0 0.25rem 0 0.5rem; font-weight: normal' }= s.metadata[:title]
42+
- if s.title
43+
%span{ style: 'margin: 0 0.25rem 0 0.5rem; font-weight: normal' }= s.title
4444
- if s.id.to_s == params[:api_scenario_id]
4545
%span.tag.green &#9733; Current Scenario
4646
%td

config/initializers/msgpack.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
module MessagePack
44
class << self
55
alias_method :load, :unpack
6-
alias_method :dump, :pack
6+
alias_method :dump, :pack
77
end
88
end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class SerializeMetadata < ActiveRecord::Migration[7.1]
2+
include ETEngine::ScenarioMigration
3+
4+
class ScenarioForMigration < ActiveRecord::Base
5+
self.table_name = 'scenarios'
6+
end
7+
8+
require 'msgpack'
9+
10+
def up
11+
change_column :scenarios, :metadata, :text, size: :medium
12+
add_column :scenarios, :metadata_binary, :binary, limit:64.kilobytes
13+
14+
migrate_scenarios(raise_if_no_changes: false) do |scenario|
15+
original = ScenarioForMigration.find(scenario.id)
16+
yaml_data = original.read_attribute_before_type_cast("metadata")
17+
next if yaml_data.blank? || !yaml_data.is_a?(String)
18+
19+
begin
20+
# Had to add other permitted_classes
21+
values = YAML.safe_load(yaml_data, permitted_classes: [Hash, Float, Integer, String, Symbol], aliases: true)
22+
next unless values.is_a?(Hash)
23+
msgpack_blob = values.to_h.to_msgpack
24+
25+
ScenarioForMigration.find(scenario.id).update!(metadata_binary: msgpack_blob)
26+
rescue => e
27+
Rails.logger.warn("Skipping scenario ##{scenario.id}: #{e.message}")
28+
end
29+
end
30+
31+
rename_column :scenarios, :metadata, :metadata_old
32+
rename_column :scenarios, :metadata_binary, :metadata
33+
end
34+
end

db/schema.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,11 @@
126126
t.string "area_code"
127127
t.string "source"
128128
t.text "balanced_values_old", size: :medium
129-
t.text "metadata"
129+
t.text "metadata_old", size: :medium
130130
t.text "active_couplings", size: :medium
131131
t.binary "user_values", size: :long
132132
t.binary "balanced_values", size: :medium
133+
t.binary "metadata", size: :medium
133134
t.index ["created_at"], name: "index_scenarios_on_created_at"
134135
end
135136

spec/controllers/api/v3/scenarios_controller_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@
145145

146146
it 'makes the ctm_scenario_id available' do
147147
scenario = Scenario.find(JSON.parse(response.body)['id'])
148-
expect(scenario.metadata[:ctm_scenario_id]).to eq('123')
148+
expect(scenario.metadata["ctm_scenario_id"]).to eq('123')
149149
end
150150

151151
context 'when metadata is huge' do

spec/models/scenario_spec.rb

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -737,38 +737,38 @@
737737

738738
context 'with no metadata' do
739739
it 'responds with nil when requesting a key' do
740-
expect(scenario.metadata[:ctm_scenario_id]).to be_nil
740+
expect(scenario.metadata["ctm_scenario_id"]).to be_nil
741741
end
742742
end
743743

744744
context 'with empty metadata' do
745745
before { scenario.metadata = {} }
746746

747747
it 'responds with nil when requesting a key' do
748-
expect(scenario.metadata[:ctm_scenario_id]).to be_nil
748+
expect(scenario.metadata["ctm_scenario_id"]).to be_nil
749749
end
750750
end
751751

752752
context 'with metadata present' do
753-
before { scenario.metadata = { ctm_scenario_id: 12_345, kittens: 'mew' } }
753+
before { scenario.metadata = { "ctm_scenario_id" => 12_345, "kittens" => "mew" } }
754754

755755
it 'stores numeric data' do
756-
expect(scenario.metadata[:ctm_scenario_id]).to eq(12_345)
756+
expect(scenario.metadata["ctm_scenario_id"]).to eq(12_345)
757757
end
758758

759759
it 'stores string data' do
760-
expect(scenario.metadata[:kittens]).to eq('mew')
760+
expect(scenario.metadata["kittens"]).to eq("mew")
761761
end
762762

763-
it 'does not have metadata accesible by accessor' do
763+
it 'does not have metadata accessible by accessor' do
764764
expect { scenario.kittens }.to raise_error(NoMethodError)
765765
end
766766
end
767767

768768
context 'when setting metadata' do
769-
it 'permits JSON object' do
770-
scenario.metadata = JSON.generate({})
771-
expect(scenario.metadata).to eq({})
769+
it 'permits a hash' do
770+
scenario.metadata = { "a" => 1 }
771+
expect(scenario.metadata).to eq({ "a" => 1 })
772772
end
773773

774774
it 'permits a hash' do
@@ -781,21 +781,14 @@
781781
expect(scenario.metadata).to eq({})
782782
end
783783

784-
it 'permits empty string' do
785-
scenario.metadata = ''
786-
expect(scenario.metadata).to eq({})
787-
end
788-
789784
it 'denies objects larger than 64Kb' do
790-
scenario.metadata = (0..15_000).to_h { |i| [i, i] }
791-
785+
scenario.metadata = (0..15_000).to_h { |i| [i.to_s, i] }
792786
expect(scenario).not_to be_valid
793787
end
794788
end
795789

796790
context 'when creating a clone of a scenario' do
797-
before { scenario.metadata = { ctm_scenario_id: 12_345, kittens: 'mew' } }
798-
791+
before { scenario.metadata = { "ctm_scenario_id" => 12_345, "kittens" => "mew" } }
799792
let(:scenario_clone) { described_class.new(scenario_id: scenario.id) }
800793

801794
it 'keeps the original metadata' do

0 commit comments

Comments
 (0)