Skip to content

Commit

Permalink
Merge pull request #470 from tenderlove/remove-translator
Browse files Browse the repository at this point in the history
Remove type translation
  • Loading branch information
tenderlove authored Jan 10, 2024
2 parents 9cff42b + c92a473 commit d7f5f6b
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 246 deletions.
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,46 @@ This release drops support for Ruby 2.7. [#453] @flavorjones
### Removed

- Remove `SQLite3::VersionProxy` which has been deprecated since v1.3.2. [#453] @flavorjones
- Remove `SQLite3::Translator` and all related type translation methods.
If you need to do type translation on values returned from the statement object,
please wrap it with a delegate object. Here is an example of using a delegate
class to implement type translation:

```ruby
require "sqlite3"
require "delegate"

db = SQLite3::Database.new(":memory:")

return_value = db.execute_batch2 <<-EOSQL
CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, name string);
INSERT INTO items (name) VALUES ("foo");
INSERT INTO items (name) VALUES ("bar");
EOSQL

class MyTranslator < DelegateClass(SQLite3::Statement)
def step
row = super
return if done?

row.map.with_index do |item, i|
case types[i]
when "integer" # turn all integers to floats
item.to_f
when "string" # add "hello" to all strings
item + "hello"
end
end
end
end

db.prepare("SELECT * FROM items") do |stmt|
stmt = MyTranslator.new(stmt)
while row = stmt.step
p row
end
end
```


## 1.7.0 / 2023-12-27
Expand Down
43 changes: 0 additions & 43 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,49 +289,6 @@ by column name, even though they are still arrays!
end
```

## I'd like the values from a query to be the correct types, instead of String.

You can turn on "type translation" by setting `Database#type_translation` to
true:


```ruby
db.type_translation = true
db.execute( "select * from table" ) do |row|
p row
end
```


By doing this, each return value for each row will be translated to its
correct type, based on its declared column type.


You can even declare your own translation routines, if (for example) you are
using an SQL type that is not handled by default:


```ruby
# assume "objects" table has the following schema:
# create table objects (
# name varchar2(20),
# thing object
# )

db.type_translation = true
db.translator.add_translator( "object" ) do |type, value|
db.decode( value )
end

h = { :one=>:two, "three"=>"four", 5=>6 }
dump = db.encode( h )

db.execute( "insert into objects values ( ?, ? )", "bob", dump )

obj = db.get_first_value( "select thing from objects where name='bob'" )
p obj == h
```

## How do I insert binary data into the database?

Use blobs. Blobs are new features of SQLite3. You have to use bind
Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ group :development do
gem "rubocop", require: false
gem "standardrb", require: false
gem "rubocop-minitest", require: false

# FIXME: Remove after minitest removes dependency
gem "mutex_m"
end
44 changes: 0 additions & 44 deletions lib/sqlite3/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
require "sqlite3/errors"
require "sqlite3/pragmas"
require "sqlite3/statement"
require "sqlite3/translator"
require "sqlite3/value"

module SQLite3
Expand Down Expand Up @@ -82,7 +81,6 @@ def quote(string)
# Other supported +options+:
# - +:strict+: boolean (default false), disallow the use of double-quoted string literals (see https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted)
# - +:results_as_hash+: boolean (default false), return rows as hashes instead of arrays
# - +:type_translation+: boolean (default false), enable type translation
# - +:default_transaction_mode+: one of +:deferred+ (default), +:immediate+, or +:exclusive+. If a mode is not specified in a call to #transaction, this will be the default transaction mode.
#
def initialize file, options = {}, zvfs = nil
Expand Down Expand Up @@ -124,8 +122,6 @@ def initialize file, options = {}, zvfs = nil
@collations = {}
@functions = {}
@results_as_hash = options[:results_as_hash]
@type_translation = options[:type_translation]
@type_translator = make_type_translator @type_translation
@readonly = mode & Constants::Open::READONLY != 0
@default_transaction_mode = options[:default_transaction_mode] || :deferred

Expand All @@ -145,25 +141,6 @@ def encoding
@encoding ||= Encoding.find(execute("PRAGMA encoding").first.first)
end

def type_translation= value # :nodoc:
warn(<<~EOWARN) if $VERBOSE
#{caller(1..1).first} is calling `SQLite3::Database#type_translation=` which is deprecated and will be removed in version 2.0.0.
EOWARN
@type_translator = make_type_translator value
@type_translation = value
end
attr_reader :type_translation # :nodoc:

# Return the type translator employed by this database instance. Each
# database instance has its own type translator; this allows for different
# type handlers to be installed in each instance without affecting other
# instances. Furthermore, the translators are instantiated lazily, so that
# if a database does not use type translation, it will not be burdened by
# the overhead of a useless type translator. (See the Translator class.)
def translator
@translator ||= Translator.new
end

# Installs (or removes) a block that will be invoked for every access
# to the database. If the block returns 0 (or +nil+), the statement
# is allowed to proceed. Returning 1 causes an authorization error to
Expand Down Expand Up @@ -760,11 +737,6 @@ def []=(key, value)
end
end

# Translates a +row+ of data from the database with the given +types+
def translate_from_db types, row
@type_translator.call types, row
end

# Given a statement, return a result set.
# This is not intended for general consumption
# :nodoc:
Expand All @@ -775,21 +747,5 @@ def build_result_set stmt
ResultSet.new(self, stmt)
end
end

private

NULL_TRANSLATOR = lambda { |_, row| row }

def make_type_translator should_translate
if should_translate
lambda { |types, row|
types.zip(row).map do |type, value|
translator.translate(type, value)
end
}
else
NULL_TRANSLATOR
end
end
end
end
31 changes: 6 additions & 25 deletions lib/sqlite3/resultset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ module SQLite3
class ResultSet
include Enumerable

class ArrayWithTypes < Array # :nodoc:
attr_accessor :types
end

class ArrayWithTypesAndFields < Array # :nodoc:
attr_writer :types
attr_writer :fields
Expand Down Expand Up @@ -78,9 +74,7 @@ def eof?
end

# Obtain the next row from the cursor. If there are no more rows to be
# had, this will return +nil+. If type translation is active on the
# corresponding database, the values in the row will be translated
# according to their types.
# had, this will return +nil+.
#
# The returned value will be an array, unless Database#results_as_hash has
# been set to +true+, in which case the returned value will be a hash.
Expand All @@ -94,19 +88,10 @@ def next
row = @stmt.step
return nil if @stmt.done?

row = @db.translate_from_db @stmt.types, row

row = if row.respond_to?(:fields)
# FIXME: this can only happen if the translator returns something
# that responds to `fields`. Since we're removing the translator
# in 2.0, we can remove this branch in 2.0.
ArrayWithTypes.new(row)
else
# FIXME: the `fields` and `types` methods are deprecated on this
# object for version 2.0, so we can safely remove this branch
# as well.
ArrayWithTypesAndFields.new(row)
end
# FIXME: the `fields` and `types` methods are deprecated on this
# object for version 2.0, so we can safely remove this branch
# as well.
row = ArrayWithTypesAndFields.new(row)

row.fields = @stmt.columns
row.types = @stmt.types
Expand Down Expand Up @@ -156,10 +141,6 @@ def next_hash
row = @stmt.step
return nil if @stmt.done?

# FIXME: type translation is deprecated, so this can be removed
# in 2.0
row = @db.translate_from_db @stmt.types, row

# FIXME: this can be switched to a regular hash in 2.0
row = HashWithTypesAndFields[*@stmt.columns.zip(row).flatten]

Expand All @@ -172,6 +153,6 @@ def next_hash
end

class HashResultSet < ResultSet # :nodoc:
alias :next :next_hash
alias_method :next, :next_hash
end
end
113 changes: 0 additions & 113 deletions lib/sqlite3/translator.rb

This file was deleted.

1 change: 0 additions & 1 deletion sqlite3.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ Gem::Specification.new do |s|
"lib/sqlite3/pragmas.rb",
"lib/sqlite3/resultset.rb",
"lib/sqlite3/statement.rb",
"lib/sqlite3/translator.rb",
"lib/sqlite3/value.rb",
"lib/sqlite3/version.rb",
"test/helper.rb",
Expand Down
Loading

0 comments on commit d7f5f6b

Please sign in to comment.