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
Public Instance
Classes and Modules
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.
# File lib/sequel/dataset/placeholder_literalizer.rb 147 def self.loader(dataset, &block) 148 Recorder.new.loader(self, dataset, &block) 149 end
# File lib/sequel/dataset/placeholder_literalizer.rb 152 def initialize(dataset, fragments, final_sql, arity) 153 @dataset = dataset 154 @fragments = fragments 155 @final_sql = final_sql 156 @arity = arity 157 freeze 158 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.
# File lib/sequel/dataset/placeholder_literalizer.rb 179 def all(*args, &block) 180 @dataset.with_sql_all(sql(*args), &block) 181 end
# File lib/sequel/dataset/placeholder_literalizer.rb 207 def append_sql(sql, *args) 208 ds = @dataset 209 @fragments.each do |s, i, transformer| 210 sql << s 211 if i.is_a?(Integer) 212 v = args.fetch(i) 213 v = transformer.call(v) if transformer 214 else 215 v = i.call 216 end 217 ds.literal_append(sql, v) 218 end 219 sql << @final_sql 220 sql 221 end
Run the SQL
query for the given arguments, yielding each returned row to the block.
# File lib/sequel/dataset/placeholder_literalizer.rb 184 def each(*args, &block) 185 @dataset.with_sql_each(sql(*args), &block) 186 end
Run the SQL
query for the given arguments, returning the first row.
# File lib/sequel/dataset/placeholder_literalizer.rb 189 def first(*args) 190 @dataset.with_sql_first(sql(*args)) 191 end
Freeze the fragments and final SQL
when freezing the literalizer.
# File lib/sequel/dataset/placeholder_literalizer.rb 161 def freeze 162 @fragments.freeze 163 @final_sql.freeze 164 super 165 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).
# File lib/sequel/dataset/placeholder_literalizer.rb 195 def get(*args) 196 @dataset.with_sql_single_value(sql(*args)) 197 end
Return the SQL
query to use for the given arguments.
# File lib/sequel/dataset/placeholder_literalizer.rb 200 def sql(*args) 201 raise Error, "wrong number of arguments (#{args.length} for #{@arity})" unless args.length == @arity 202 s = sql_origin 203 append_sql(s, *args) 204 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.
# File lib/sequel/dataset/placeholder_literalizer.rb 170 def with_dataset 171 dataset = yield @dataset 172 other = dup 173 other.instance_variable_set(:@dataset, dataset) 174 other.freeze 175 end