Module Sequel::Plugins::Finder::ClassMethods
In: lib/sequel/plugins/finder.rb

Methods

Public Instance methods

Create an optimized finder method using a dataset placeholder literalizer. This pre-computes the SQL to use for the query, except for given arguments.

There are two ways to use this. The recommended way is to pass a symbol that represents a model class method that returns a dataset:

  def Artist.by_name(name)
    where(name: name)
  end

  Artist.finder :by_name

This creates an optimized first_by_name method, which you can call normally:

  Artist.first_by_name("Joe")

The alternative way to use this to pass your own block:

  Artist.finder(name: :first_by_name){|pl, ds| ds.where(name: pl.arg).limit(1)}

Note that if you pass your own block, you are responsible for manually setting limits if necessary (as shown above).

Options:

:arity :When using a symbol method name, this specifies the arity of the method. This should be used if if the method accepts an arbitrary number of arguments, or the method has default argument values. Note that if the method is defined as a dataset method, the class method Sequel creates accepts an arbitrary number of arguments, so you should use this option in that case. If you want to handle multiple possible arities, you need to call the finder method multiple times with unique :arity and :name methods each time.
:name :The name of the method to create. This must be given if you pass a block. If you use a symbol, this defaults to the symbol prefixed by the type.
:mod :The module in which to create the finder method. Defaults to the singleton class of the model.
:type :The type of query to run. Can be :first, :each, :all, or :get, defaults to :first.

Caveats:

This doesn‘t handle all possible cases. For example, if you have a method such as:

  def Artist.by_name(name)
    name ? where(name: name) : exclude(name: nil)
  end

Then calling a finder without an argument will not work as you expect.

  Artist.finder :by_name
  Artist.by_name(nil).first
  # WHERE (name IS NOT NULL)
  Artist.first_by_name(nil)
  # WHERE (name IS NULL)

See Dataset::PlaceholderLiteralizer for additional caveats.

[Source]

     # File lib/sequel/plugins/finder.rb, line 101
101:         def finder(meth=OPTS, opts=OPTS, &block)
102:           if block
103:             raise Error, "cannot pass both a method name argument and a block of Model.finder" unless meth.is_a?(Hash)
104:             raise Error, "cannot pass two option hashes to Model.finder" unless opts.equal?(OPTS)
105:             opts = meth
106:             raise Error, "must provide method name via :name option when passing block to Model.finder" unless meth_name = opts[:name]
107:           end
108: 
109:           type = opts.fetch(:type, :first)
110:           unless prepare = opts[:prepare]
111:             raise Error, ":type option to Model.finder must be :first, :all, :each, or :get" unless FINDER_TYPES.include?(type)
112:           end
113:           limit1 = type == :first || type == :get
114:           meth_name ||= opts[:name] || "#{type}_#{meth}""#{type}_#{meth}"
115: 
116:           argn = lambda do |model|
117:             if arity = opts[:arity]
118:               arity
119:             else
120:               method = block || model.method(meth)
121:               (method.arity < 0 ? method.arity.abs - 1 : method.arity)
122:             end
123:           end
124: 
125:           loader_proc = if prepare
126:             proc do |model|
127:               args = prepare_method_args('$a', argn.call(model))
128:               ds = if block
129:                 model.instance_exec(*args, &block)
130:               else
131:                 model.public_send(meth, *args)
132:               end
133:               ds = ds.limit(1) if limit1
134:               model_name = model.name
135:               if model_name.to_s.empty?
136:                 model_name = model.object_id
137:               else
138:                 model_name = model_name.gsub(/\W/, '_')
139:               end
140:               ds.prepare(type, "#{model_name}_#{meth_name}""#{model_name}_#{meth_name}")
141:             end
142:           else
143:             proc do |model|
144:               n = argn.call(model)
145:               block ||= lambda do |pl, model2|
146:                 args = (0...n).map{pl.arg}
147:                 ds = model2.public_send(meth, *args)
148:                 ds = ds.limit(1) if limit1
149:                 ds
150:               end
151: 
152:               Sequel::Dataset::PlaceholderLiteralizer.loader(model, &block) 
153:             end
154:           end
155: 
156:           @finder_loaders[meth_name] = loader_proc
157:           mod = opts[:mod] || singleton_class
158:           if prepare
159:             def_prepare_method(mod, meth_name)
160:           else
161:             def_finder_method(mod, meth_name, type)
162:           end
163:         end

[Source]

     # File lib/sequel/plugins/finder.rb, line 165
165:         def freeze
166:           @finder_loaders.freeze
167:           @finder_loaders.each_key{|k| finder_for(k)} if @dataset
168:           @finders.freeze
169:           super
170:         end

Similar to finder, but uses a prepared statement instead of a placeholder literalizer. This makes the SQL used static (cannot vary per call), but allows binding argument values instead of literalizing them into the SQL query string.

If a block is used with this method, it is instance_execed by the model, and should accept the desired number of placeholder arguments.

The options are the same as the options for finder, with the following exception:

:type :Specifies the type of prepared statement to create

[Source]

     # File lib/sequel/plugins/finder.rb, line 183
183:         def prepared_finder(meth=OPTS, opts=OPTS, &block)
184:           if block
185:             raise Error, "cannot pass both a method name argument and a block of Model.finder" unless meth.is_a?(Hash)
186:             meth = meth.merge(:prepare=>true)
187:           else
188:             opts = opts.merge(:prepare=>true)
189:           end
190:           finder(meth, opts, &block)
191:         end

[Validate]