class Sequel::Dataset::PlaceholderLiteralizer

  1. lib/sequel/dataset/placeholder_literalizer.rb
  2. lib/sequel/dataset/prepared_statements.rb
  3. lib/sequel/dataset/query.rb
  4. lib/sequel/sql.rb
  5. show all
Superclass: Object

PlaceholderLiteralizer allows you to record the application of arbitrary changes to a dataset with placeholder arguments, recording where those placeholder arguments are used in the query. When running the query, the literalization process is much faster as Sequel can skip most of the work it normally has to do when literalizing a dataset.

Basically, this enables optimizations that allow Sequel to cache the SQL produced for a given dataset, so that it doesn’t need to recompute that information every time.

Example:

loader = Sequel::Dataset::PlaceholderLiteralizer.loader(DB[:items]) do |pl, ds|
  ds.where(id: pl.arg).exclude(name: pl.arg).limit(1)
end
loader.first(1, "foo")
# SELECT * FROM items WHERE ((id = 1) AND (name != 'foo')) LIMIT 1
loader.first(2, "bar")
# SELECT * FROM items WHERE ((id = 2) AND (name != 'bar')) LIMIT 1

Caveats:

Note that this method does not handle all possible cases. For example:

loader = Sequel::Dataset::PlaceholderLiteralizer.loader(DB[:items]) do |pl, ds|
  ds.join(pl.arg, item_id: :id)
end
loader.all(:cart_items)

Will not qualify the item_id column with cart_items. In this type of situation it’s best to add a table alias when joining:

loader = Sequel::Dataset::PlaceholderLiteralizer.loader(DB[:items]) do |pl, ds|
  ds.join(Sequel.as(pl.arg, :t), item_id: :id)
end
loader.all(:cart_items)

There are other similar cases that are not handled, mainly when Sequel changes the SQL produced depending on the types of the arguments.

Methods

Public Class

  1. loader
  2. new

Public Instance

  1. all
  2. append_sql
  3. each
  4. first
  5. freeze
  6. get
  7. sql
  8. with_dataset

Public Class methods

loader(dataset, &block)

Create a PlaceholderLiteralizer by yielding a Recorder and dataset to the given block, recording the offsets at which the recorders arguments are used in the query.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
150 def self.loader(dataset, &block)
151   Recorder.new.loader(self, dataset, &block)
152 end
new(dataset, fragments, final_sql, arity)

Save the dataset, array of SQL fragments, and ending SQL string.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
155 def initialize(dataset, fragments, final_sql, arity)
156   @dataset = dataset
157   @fragments = fragments
158   @final_sql = final_sql
159   @arity = arity
160   freeze
161 end

Public Instance methods

all(*args, &block)

Return an array of all objects by running the SQL query for the given arguments. If a block is given, yields all objects to the block after loading them.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
182 def all(*args, &block)
183   @dataset.with_sql_all(sql(*args), &block)
184 end
append_sql(sql, *args)

Append the SQL query to use for the given arguments to the given SQL string.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
210 def append_sql(sql, *args)
211   ds = @dataset
212   @fragments.each do |s, i, transformer|
213     sql << s
214     if i.is_a?(Integer)
215       v = args.fetch(i)
216       v = transformer.call(v) if transformer
217     else
218       v = i.call
219     end
220     ds.literal_append(sql, v)
221   end
222   sql << @final_sql
223   sql
224 end
each(*args, &block)

Run the SQL query for the given arguments, yielding each returned row to the block.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
187 def each(*args, &block)
188   @dataset.with_sql_each(sql(*args), &block)
189 end
first(*args)

Run the SQL query for the given arguments, returning the first row.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
192 def first(*args)
193   @dataset.with_sql_first(sql(*args))
194 end
freeze()

Freeze the fragments and final SQL when freezing the literalizer.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
164 def freeze
165   @fragments.freeze
166   @final_sql.freeze
167   super
168 end
get(*args)

Run the SQL query for the given arguments, returning the first value. For this to make sense, the dataset should return a single row with a single value (or no rows).

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
198 def get(*args)
199   @dataset.with_sql_single_value(sql(*args))
200 end
sql(*args)

Return the SQL query to use for the given arguments.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
203 def sql(*args)
204   raise Error, "wrong number of arguments (#{args.length} for #{@arity})" unless args.length == @arity
205   s = sql_origin
206   append_sql(s, *args)
207 end
with_dataset()

Return a new PlaceholderLiteralizer with a modified dataset. This yields the receiver’s dataset to the block, and the block should return the new dataset to use.

[show source]
    # File lib/sequel/dataset/placeholder_literalizer.rb
173 def with_dataset
174   dataset = yield @dataset
175   other = dup
176   other.instance_variable_set(:@dataset, dataset)
177   other.freeze
178 end