diff --git a/lib/staging_table/bulk_inserter.rb b/lib/staging_table/bulk_inserter.rb index cb2d86f..b99932a 100644 --- a/lib/staging_table/bulk_inserter.rb +++ b/lib/staging_table/bulk_inserter.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "json" + module StagingTable class BulkInserter attr_reader :model, :batch_size @@ -37,7 +39,12 @@ def connection end def quote(value) - connection.quote(value) + case value + when Array, Hash + connection.quote(value.to_json) + else + connection.quote(value) + end end end end diff --git a/spec/staging_table/bulk_inserter_spec.rb b/spec/staging_table/bulk_inserter_spec.rb index 37e05aa..acc24cc 100644 --- a/spec/staging_table/bulk_inserter_spec.rb +++ b/spec/staging_table/bulk_inserter_spec.rb @@ -88,12 +88,40 @@ end end + shared_examples "bulk inserter with JSON support" do + describe "#insert with JSON" do + it "handles array values for JSON/JSONB columns" do + records = [ + {name: "John", email: "john@example.com", tags: %w[admin user]} + ] + + inserter.insert(records) + + user = staging_model.first + expect(user.tags).to eq(%w[admin user]) + end + + it "handles hash values for JSON/JSONB columns" do + records = [ + {name: "John", email: "john@example.com", metadata: {role: "admin", level: 5}} + ] + + inserter.insert(records) + + user = staging_model.first + expect(user.metadata).to eq({"role" => "admin", "level" => 5}) + end + end + end + context "with PostgreSQL", :postgresql do include_examples "bulk inserter" + include_examples "bulk inserter with JSON support" end context "with MySQL", :mysql do include_examples "bulk inserter" + include_examples "bulk inserter with JSON support" end context "with SQLite", :sqlite do diff --git a/spec/support/database_helper.rb b/spec/support/database_helper.rb index 1bb63b3..b89bfef 100644 --- a/spec/support/database_helper.rb +++ b/spec/support/database_helper.rb @@ -187,6 +187,8 @@ def create_test_tables DROP TABLE IF EXISTS test_users SQL + json_type = /postgresql/.match?(ActiveRecord::Base.connection.adapter_name.downcase) ? "JSONB" : "JSON" + ActiveRecord::Base.connection.execute(<<~SQL) CREATE TABLE test_users ( id SERIAL PRIMARY KEY, @@ -194,6 +196,8 @@ def create_test_tables email VARCHAR(255), age INTEGER, active BOOLEAN DEFAULT true, + tags #{json_type}, + metadata #{json_type}, created_at TIMESTAMP, updated_at TIMESTAMP ) @@ -219,6 +223,8 @@ def create_sqlite_test_tables email VARCHAR(255), age INTEGER, active BOOLEAN DEFAULT 1, + tags TEXT, + metadata TEXT, created_at DATETIME, updated_at DATETIME )