1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
# frozen-string-literal: true
module Sequel
module Plugins
# The insert_conflict plugin allows handling conflicts due to unique
# constraints when saving new model instance, using the INSERT ON CONFLICT
# support in PostgreSQL 9.5+ and SQLite 3.24.0+. Example:
#
# class Album < Sequel::Model
# plugin :insert_conflict
# end
#
# Album.new(name: 'Foo', copies_sold: 1000).
# insert_conflict(
# target: :name,
# update: {copies_sold: Sequel[:excluded][:b]}
# ).
# save
#
# This example will try to insert the album, but if there is an existing
# album with the name 'Foo', this will update the copies_sold attribute
# for that album. See the PostgreSQL and SQLite adapter documention for
# the options you can pass to the insert_conflict method.
#
# You should not attempt to use this plugin to ignore conflicts when
# inserting, you should only use it to turn insert conflicts into updates.
# Any usage to ignore conflicts is not recommended or supported.
#
# Usage:
#
# # Make all model subclasses support insert_conflict
# Sequel::Model.plugin :insert_conflict
#
# # Make the Album class support insert_conflict
# Album.plugin :insert_conflict
module InsertConflict
def self.configure(model)
model.instance_exec do
if @dataset && !@dataset.respond_to?(:insert_conflict)
raise Error, "#{self}'s dataset does not support insert_conflict"
end
end
end
module InstanceMethods
# Set the insert_conflict options to pass to the dataset when inserting.
def insert_conflict(opts=OPTS)
raise Error, "Model#insert_conflict is only supported on new model instances" unless new?
@insert_conflict_opts = opts
self
end
private
# Set the dataset used for inserting to use INSERT ON CONFLICT
# Model#insert_conflict has been called on the instance previously.
def _insert_dataset
ds = super
if @insert_conflict_opts
ds = ds.insert_conflict(@insert_conflict_opts)
end
ds
end
# Disable the use of prepared insert statements, as they are not compatible
# with this plugin.
def use_prepared_statements_for?(type)
return false if type == :insert || type == :insert_select
super if defined?(super)
end
end
end
end
end
|