-
Notifications
You must be signed in to change notification settings - Fork 81
Open
Description
In case of a JSON column, bulk_insert will incorrectly insert the default value. It inserts "{}" (ie. a string) instead of {} (ie. an object).
Here's a failing test:
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
gem "rails"
gem "sqlite3"
gem "bulk_insert"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :profiles, force: true do |t|
t.string :name
t.json :json_data, default: {}, null: false
end
end
class Profile < ActiveRecord::Base
end
class BugTest < Minitest::Test
def test_bulk_insert_json_default
worker = Profile.bulk_insert
worker.add(name: "Foo", json_data: {})
worker.add(name: "Bar")
worker.save!
profile1 = Profile.find_by!(name: "Foo")
profile2 = Profile.find_by!(name: "Bar")
assert_equal profile1.json_data, {}
assert_equal profile2.json_data, {}
end
endThe reason is the following code:
bulk_insert/lib/bulk_insert/worker.rb
Lines 51 to 64 in ab5db08
| mapped = @columns.map.with_index do |column, index| | |
| value_exists = values.is_a?(Hash) ? values.key?(column.name) : (index < values.length) | |
| if !value_exists | |
| if column.default.present? | |
| column.default | |
| elsif column.name == "created_at" || column.name == "updated_at" | |
| :__timestamp_placeholder | |
| else | |
| nil | |
| end | |
| else | |
| values.is_a?(Hash) ? values[column.name] : values[index] | |
| end | |
| end |
In case a value does not exist, the column default is used. The column default in rails is expressed as a string (ie. in the example above: Profile.columns_hash["json_data"].default == {}). This is problematic for JSON columns, as both "{}" and {} are valid JSON (one a string, the other an object).
jjinkxy, lemboywp, Jamie5 and nBollard
Metadata
Metadata
Assignees
Labels
No labels