Skip to content

Saving Serialized JSON not work. #1956

@zw963

Description

@zw963

Describe the bug
Following the example in the doc to save serialized json.

You can set your operation up with virtual properties to map back to your serializable object when updating.

class UpdateUser < User::SaveOperation
  attribute allow_email : Bool
  before_save do
    if prefs = preferences.value
      prefs.receive_email = !!allow_email.value
    end
  end
end

To Reproduce

require "pg"
require "avram"

class AppDatabase < Avram::Database
end

AppDatabase.configure do |settings|
  settings.credentials = Avram::Credentials.new(database: "test_db", username: "postgres", hostname: "localhost")
end

Avram.configure do |settings|
  settings.database_to_migrate = AppDatabase
  settings.lazy_load_enabled = true
end

class CreateReply::V20240420041991 < Avram::Migrator::Migration::V1
  def migrate
    create table_for(Reply) do
      primary_key id : Int64
      add content : String
      add preferences : JSON::Any
      add_timestamps
    end
  end

  def rollback
    drop table_for(Reply)
  end
end

Avram::Migrator::Runner.drop_db(true)
Avram::Migrator::Runner.create_db(true)
Avram::Migrator::Runner.new.run_next_migration

abstract class BaseModel < Avram::Model
  def self.database : Avram::Database.class
    AppDatabase
  end
end

class Reply < BaseModel
  # skip_default_columns

  struct Preferences
    include JSON::Serializable

    property? path_for_doc : String?
    property floor : Int32?
  end

  table do
    column content : String
    column preferences : Reply::Preferences, serialize: true
  end
end

Reply::SaveOperation.create!(content: "foo", preferences: Reply::Preferences.from_json({"path_for_doc" => "/doc/index"}.to_json))

reply = Reply::BaseQuery.first

p! reply.preferences # => Reply::Preferences(@path_for_doc="/doc/index", @floor=nil)

class UpdateReply < Reply::SaveOperation
  attribute floor : Int32

  before_save do
    if prefs = preferences.value
      prefs.floor = floor.value.not_nil!
    end
  end
end

UpdateReply.update!(reply, floor: 1)

p! reply.reload.preferences  # => Reply::Preferences(@path_for_doc="/doc/index", @floor=nil)

Expected behavior
reply.reload.preferences should update floor serialize column to 1.

Screenshots/code
If applicable, add screenshots/code samples to help explain your problem.

Versions (please complete the following information):

  • Lucky version (check in shard.lock): 1.3.0
  • Crystal version (crystal --version): 1.16.3
  • OS: linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationThis just needs more/better documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions