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 150 def self.loader(dataset, &block) 151 Recorder.new.loader(self, dataset, &block) 152 end
# 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
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 182 def all(*args, &block) 183 @dataset.with_sql_all(sql(*args), &block) 184 end
# 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
Run the SQL query for the given arguments, yielding each returned row to the block.
# File lib/sequel/dataset/placeholder_literalizer.rb 187 def each(*args, &block) 188 @dataset.with_sql_each(sql(*args), &block) 189 end
Run the SQL query for the given arguments, returning the first row.
# File lib/sequel/dataset/placeholder_literalizer.rb 192 def first(*args) 193 @dataset.with_sql_first(sql(*args)) 194 end
Freeze the fragments and final SQL when freezing the literalizer.
# File lib/sequel/dataset/placeholder_literalizer.rb 164 def freeze 165 @fragments.freeze 166 @final_sql.freeze 167 super 168 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 198 def get(*args) 199 @dataset.with_sql_single_value(sql(*args)) 200 end
Return the SQL query to use for the given arguments.
# 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
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 173 def with_dataset 174 dataset = yield @dataset 175 other = dup 176 other.instance_variable_set(:@dataset, dataset) 177 other.freeze 178 end