Class Sequel::Dataset::PlaceholderLiteralizer
In: lib/sequel/dataset/placeholder_literalizer.rb
Parent: 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

all   each   first   get   loader   new   sql   with_dataset  

Classes and Modules

Class Sequel::Dataset::PlaceholderLiteralizer::Argument
Class Sequel::Dataset::PlaceholderLiteralizer::Recorder

Public Class methods

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.

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 118
118:       def self.loader(dataset, &block)
119:         Recorder.new.loader(dataset, &block)
120:       end

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

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 123
123:       def initialize(dataset, fragments, final_sql, arity)
124:         @dataset = dataset
125:         @fragments = fragments
126:         @final_sql = final_sql
127:         @arity = arity
128:       end

Public Instance methods

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.

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 139
139:       def all(*args, &block)
140:         @dataset.with_sql_all(sql(*args), &block)
141:       end

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

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 144
144:       def each(*args, &block)
145:         @dataset.with_sql_each(sql(*args), &block)
146:       end

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

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 149
149:       def first(*args)
150:         @dataset.with_sql_first(sql(*args))
151:       end

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).

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 155
155:       def get(*args)
156:         @dataset.with_sql_single_value(sql(*args))
157:       end

Return the SQL query to use for the given arguments.

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 160
160:       def sql(*args)
161:         raise Error, "wrong number of arguments (#{args.length} for #{@arity})" unless args.length == @arity
162:         s = String.new
163:         ds = @dataset
164:         @fragments.each do |sql, i, transformer|
165:           s << sql
166:           if i.is_a?(Integer)
167:             v = args.fetch(i)
168:             v = transformer.call(v) if transformer
169:           else
170:             v = i.call
171:           end
172:           ds.literal_append(s, v)
173:         end
174:         if sql = @final_sql
175:           s << sql
176:         end
177:         s
178:       end

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.

[Source]

     # File lib/sequel/dataset/placeholder_literalizer.rb, line 133
133:       def with_dataset
134:         dup.instance_exec{@dataset = yield @dataset; self}
135:       end

[Validate]