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