We recently hit an issue doing a multi insert via a repository’s create
command where some columns are not written.
Specifically, the columns that are not represented in the first hash passed to create
are ignored. i.e. in the following call, the private
column of the posts table will not be set to true
for the second post.
post_repo.create([
{title: "First post"},
{title: "Second post", private: true}
])
The reason for that is this method in Sequel, which documents the fact that all hashes should have the same keys (the columns are determined by the first hash):
# This is a front end for import that allows you to submit an array of
# hashes instead of arrays of columns and values:
#
# DB[:table].multi_insert([{x: 1}, {x: 2}])
# # INSERT INTO table (x) VALUES (1)
# # INSERT INTO table (x) VALUES (2)
#
# Be aware that all hashes should have the same keys if you use this calling method,
# otherwise some columns could be missed or set to null instead of to default
# values.
#
# This respects the same options as #import.
def multi_insert(hashes, opts=OPTS)
return if hashes.empty?
columns = hashes.first.keys
import(columns, hashes.map{|h| columns.map{|c| h[c]}}, opts)
end
As this behaviour could be the cause of application bugs where columns are unexpectedly not written, I wanted to open a discussion about whether some behaviour should change here?
For example, should Sequel check all keys of all hashes being inserted? Should rom-sql do that instead? Or should rom-sql raise an error if it encounters a multi-insert where the hashes have different key sets, to prevent developers encountering this situation?