File: insert_conflict.rb

package info (click to toggle)
ruby-sequel 5.63.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 10,408 kB
  • sloc: ruby: 113,747; makefile: 3
file content (76 lines) | stat: -rw-r--r-- 2,552 bytes parent folder | download | duplicates (2)
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