extralite 1.25 → 1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -1
- data/.yardopts +8 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +2 -2
- data/README.md +1 -1
- data/ext/extralite/extconf.rb +1 -0
- data/ext/extralite/prepared_statement.c +6 -0
- data/lib/extralite/sqlite3_constants.rb +0 -1
- data/lib/extralite/version.rb +2 -1
- data/lib/extralite.rb +1 -0
- data/lib/sequel/adapters/extralite.rb +45 -26
- data/test/test_sequel.rb +27 -5
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a027328ec4af0d01bc81706f4f8e1ea08770a1341d8a36953882244b2d20ed88
         | 
| 4 | 
            +
              data.tar.gz: 916fabb4a5328e93bcdcb8121b54aa3e958b87915e9b1c9027cccb44941837b9
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: fc4cd60e38d6e229d5d28ab6e28db3a16f7ddf1ffde53e3f5a97cacebe607158604421016bab34fa5bf96659ab4d0074fffb0f51712e4429d5529f59bbcdec0d
         | 
| 7 | 
            +
              data.tar.gz: db9905c1c839a4135fe4c1156b3991f8cad5ac438b5c70091be34e8afee7563371e19afe45cd835cec2f83dd26fc92e5855bf7c53c6ee473728b80caabb3e5e1
         | 
    
        data/.github/FUNDING.yml
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            github:  | 
| 1 | 
            +
            github: noteflakes
         | 
    
        data/.yardopts
    ADDED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,12 @@ | |
| 1 | 
            +
            # 1.27 2023-06-12
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            - Fix execution of prepared statements in Sequel adapter (#23 @gschlager)
         | 
| 4 | 
            +
            - Update bundled sqlite code to version 3.42.0 (#22 @gschlager)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # 1.26 2023-05-17
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            - Improve documentation
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            # 1.25 2023-03-10
         | 
| 2 11 |  | 
| 3 12 | 
             
            - Remove bundled sqlite3 source files from extralite.gemspec
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -14,7 +14,7 @@ with an SQLite3 database, as well as prepared statements. | |
| 14 14 | 
             
            Extralite comes in two flavors: the `extralite` gem which uses the
         | 
| 15 15 | 
             
            system-installed sqlite3 library, and the `extralite-bundle` gem which bundles
         | 
| 16 16 | 
             
            the latest version of SQLite
         | 
| 17 | 
            -
            ([3. | 
| 17 | 
            +
            ([3.42.0](https://sqlite.org/releaselog/3_42_0.html)), offering access to the
         | 
| 18 18 | 
             
            latest features and enhancements.
         | 
| 19 19 |  | 
| 20 20 | 
             
            ## Features
         | 
    
        data/ext/extralite/extconf.rb
    CHANGED
    
    
    
        data/lib/extralite/version.rb
    CHANGED
    
    
    
        data/lib/extralite.rb
    CHANGED
    
    
| @@ -7,22 +7,28 @@ | |
| 7 7 | 
             
            require 'extralite'
         | 
| 8 8 | 
             
            require 'sequel/adapters/shared/sqlite'
         | 
| 9 9 |  | 
| 10 | 
            +
            # @!visibility private
         | 
| 10 11 | 
             
            module Sequel
         | 
| 12 | 
            +
              # Extralite Sequel adapter
         | 
| 11 13 | 
             
              module Extralite
         | 
| 14 | 
            +
                # @!visibility private
         | 
| 12 15 | 
             
                FALSE_VALUES = (%w'0 false f no n'.each(&:freeze) + [0]).freeze
         | 
| 13 16 |  | 
| 14 17 | 
             
                blob = Object.new
         | 
| 18 | 
            +
                # @!visibility private
         | 
| 15 19 | 
             
                def blob.call(s)
         | 
| 16 20 | 
             
                  Sequel::SQL::Blob.new(s.to_s)
         | 
| 17 21 | 
             
                end
         | 
| 18 22 |  | 
| 19 23 | 
             
                boolean = Object.new
         | 
| 24 | 
            +
                # @!visibility private
         | 
| 20 25 | 
             
                def boolean.call(s)
         | 
| 21 26 | 
             
                  s = s.downcase if s.is_a?(String)
         | 
| 22 27 | 
             
                  !FALSE_VALUES.include?(s)
         | 
| 23 28 | 
             
                end
         | 
| 24 29 |  | 
| 25 30 | 
             
                date = Object.new
         | 
| 31 | 
            +
                # @!visibility private
         | 
| 26 32 | 
             
                def date.call(s)
         | 
| 27 33 | 
             
                  case s
         | 
| 28 34 | 
             
                  when String
         | 
| @@ -37,22 +43,26 @@ module Sequel | |
| 37 43 | 
             
                end
         | 
| 38 44 |  | 
| 39 45 | 
             
                integer = Object.new
         | 
| 46 | 
            +
                # @!visibility private
         | 
| 40 47 | 
             
                def integer.call(s)
         | 
| 41 48 | 
             
                  s.to_i
         | 
| 42 49 | 
             
                end
         | 
| 43 50 |  | 
| 44 51 | 
             
                float = Object.new
         | 
| 52 | 
            +
                # @!visibility private
         | 
| 45 53 | 
             
                def float.call(s)
         | 
| 46 54 | 
             
                  s.to_f
         | 
| 47 55 | 
             
                end
         | 
| 48 56 |  | 
| 49 57 | 
             
                numeric = Object.new
         | 
| 58 | 
            +
                # @!visibility private
         | 
| 50 59 | 
             
                def numeric.call(s)
         | 
| 51 60 | 
             
                  s = s.to_s unless s.is_a?(String)
         | 
| 52 61 | 
             
                  BigDecimal(s) rescue s
         | 
| 53 62 | 
             
                end
         | 
| 54 63 |  | 
| 55 64 | 
             
                time = Object.new
         | 
| 65 | 
            +
                # @!visibility private
         | 
| 56 66 | 
             
                def time.call(s)
         | 
| 57 67 | 
             
                  case s
         | 
| 58 68 | 
             
                  when String
         | 
| @@ -82,19 +92,21 @@ module Sequel | |
| 82 92 | 
             
                end
         | 
| 83 93 | 
             
                SQLITE_TYPES.freeze
         | 
| 84 94 |  | 
| 95 | 
            +
                # @!visibility private
         | 
| 85 96 | 
             
                USE_EXTENDED_RESULT_CODES = false
         | 
| 86 | 
            -
             | 
| 97 | 
            +
             | 
| 98 | 
            +
                # Database adapter for Sequel
         | 
| 87 99 | 
             
                class Database < Sequel::Database
         | 
| 88 100 | 
             
                  include ::Sequel::SQLite::DatabaseMethods
         | 
| 89 | 
            -
             | 
| 101 | 
            +
             | 
| 90 102 | 
             
                  set_adapter_scheme :extralite
         | 
| 91 | 
            -
             | 
| 103 | 
            +
             | 
| 92 104 | 
             
                  # Mimic the file:// uri, by having 2 preceding slashes specify a relative
         | 
| 93 105 | 
             
                  # path, and 3 preceding slashes specify an absolute path.
         | 
| 94 106 | 
             
                  def self.uri_to_options(uri) # :nodoc:
         | 
| 95 107 | 
             
                    { :database => (uri.host.nil? && uri.path == '/') ? nil : "#{uri.host}#{uri.path}" }
         | 
| 96 108 | 
             
                  end
         | 
| 97 | 
            -
             | 
| 109 | 
            +
             | 
| 98 110 | 
             
                  private_class_method :uri_to_options
         | 
| 99 111 |  | 
| 100 112 | 
             
                  # The conversion procs to use for this database
         | 
| @@ -119,14 +131,14 @@ module Sequel | |
| 119 131 | 
             
                    # if USE_EXTENDED_RESULT_CODES
         | 
| 120 132 | 
             
                    #   db.extended_result_codes = true
         | 
| 121 133 | 
             
                    # end
         | 
| 122 | 
            -
             | 
| 134 | 
            +
             | 
| 123 135 | 
             
                    connection_pragmas.each{|s| log_connection_yield(s, db){db.query(s)}}
         | 
| 124 | 
            -
             | 
| 136 | 
            +
             | 
| 125 137 | 
             
                    class << db
         | 
| 126 138 | 
             
                      attr_reader :prepared_statements
         | 
| 127 139 | 
             
                    end
         | 
| 128 140 | 
             
                    db.instance_variable_set(:@prepared_statements, {})
         | 
| 129 | 
            -
             | 
| 141 | 
            +
             | 
| 130 142 | 
             
                    db
         | 
| 131 143 | 
             
                  end
         | 
| 132 144 |  | 
| @@ -135,7 +147,7 @@ module Sequel | |
| 135 147 | 
             
                    c.prepared_statements.each_value{|v| v.first.close }
         | 
| 136 148 | 
             
                    c.close
         | 
| 137 149 | 
             
                  end
         | 
| 138 | 
            -
             | 
| 150 | 
            +
             | 
| 139 151 | 
             
                  # Run the given SQL with the given arguments and yield each row.
         | 
| 140 152 | 
             
                  def execute(sql, opts=OPTS, &block)
         | 
| 141 153 | 
             
                    _execute(:select, sql, opts, &block)
         | 
| @@ -145,7 +157,7 @@ module Sequel | |
| 145 157 | 
             
                  def execute_dui(sql, opts=OPTS)
         | 
| 146 158 | 
             
                    _execute(:update, sql, opts)
         | 
| 147 159 | 
             
                  end
         | 
| 148 | 
            -
             | 
| 160 | 
            +
             | 
| 149 161 | 
             
                  # Drop any prepared statements on the connection when executing DDL.  This is because
         | 
| 150 162 | 
             
                  # prepared statements lock the table in such a way that you can't drop or alter the
         | 
| 151 163 | 
             
                  # table while a prepared statement that references it still exists.
         | 
| @@ -156,11 +168,13 @@ module Sequel | |
| 156 168 | 
             
                      super
         | 
| 157 169 | 
             
                    end
         | 
| 158 170 | 
             
                  end
         | 
| 159 | 
            -
             | 
| 171 | 
            +
             | 
| 172 | 
            +
                  # @!visibility private
         | 
| 160 173 | 
             
                  def execute_insert(sql, opts=OPTS)
         | 
| 161 174 | 
             
                    _execute(:insert, sql, opts)
         | 
| 162 175 | 
             
                  end
         | 
| 163 | 
            -
             | 
| 176 | 
            +
             | 
| 177 | 
            +
                  # @!visibility private
         | 
| 164 178 | 
             
                  def freeze
         | 
| 165 179 | 
             
                    @conversion_procs.freeze
         | 
| 166 180 | 
             
                    super
         | 
| @@ -181,13 +195,13 @@ module Sequel | |
| 181 195 | 
             
                  end
         | 
| 182 196 |  | 
| 183 197 | 
             
                  private
         | 
| 184 | 
            -
             | 
| 198 | 
            +
             | 
| 185 199 | 
             
                  def adapter_initialize
         | 
| 186 200 | 
             
                    @conversion_procs = SQLITE_TYPES.dup
         | 
| 187 201 | 
             
                    @conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp)
         | 
| 188 202 | 
             
                    set_integer_booleans
         | 
| 189 203 | 
             
                  end
         | 
| 190 | 
            -
             | 
| 204 | 
            +
             | 
| 191 205 | 
             
                  # Yield an available connection. Rescue any Extralite::Error and turn
         | 
| 192 206 | 
             
                  # them into DatabaseErrors.
         | 
| 193 207 | 
             
                  def _execute(type, sql, opts, &block)
         | 
| @@ -212,7 +226,7 @@ module Sequel | |
| 212 226 | 
             
                      raise_error(e)
         | 
| 213 227 | 
             
                    end
         | 
| 214 228 | 
             
                  end
         | 
| 215 | 
            -
             | 
| 229 | 
            +
             | 
| 216 230 | 
             
                  # The SQLite adapter does not need the pool to convert exceptions.
         | 
| 217 231 | 
             
                  # Also, force the max connections to 1 if a memory database is being
         | 
| 218 232 | 
             
                  # used, as otherwise each connection gets a separate database.
         | 
| @@ -223,7 +237,7 @@ module Sequel | |
| 223 237 | 
             
                    o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database])
         | 
| 224 238 | 
             
                    o
         | 
| 225 239 | 
             
                  end
         | 
| 226 | 
            -
             | 
| 240 | 
            +
             | 
| 227 241 | 
             
                  def prepared_statement_argument(arg)
         | 
| 228 242 | 
             
                    case arg
         | 
| 229 243 | 
             
                    when Date, DateTime, Time
         | 
| @@ -267,9 +281,9 @@ module Sequel | |
| 267 281 | 
             
                      log_sql << ")"
         | 
| 268 282 | 
             
                    end
         | 
| 269 283 | 
             
                    if block
         | 
| 270 | 
            -
                      log_connection_yield(log_sql, conn, args){cps. | 
| 284 | 
            +
                      log_connection_yield(log_sql, conn, args){cps.query(ps_args, &block)}
         | 
| 271 285 | 
             
                    else
         | 
| 272 | 
            -
                      log_connection_yield(log_sql, conn, args){cps. | 
| 286 | 
            +
                      log_connection_yield(log_sql, conn, args){cps.query(ps_args){|r|}}
         | 
| 273 287 | 
             
                      case type
         | 
| 274 288 | 
             
                      when :insert
         | 
| 275 289 | 
             
                        conn.last_insert_rowid
         | 
| @@ -278,7 +292,7 @@ module Sequel | |
| 278 292 | 
             
                      end
         | 
| 279 293 | 
             
                    end
         | 
| 280 294 | 
             
                  end
         | 
| 281 | 
            -
             | 
| 295 | 
            +
             | 
| 282 296 | 
             
                  # # SQLite3 raises ArgumentError in addition to SQLite3::Exception in
         | 
| 283 297 | 
             
                  # # some cases, such as operations on a closed database.
         | 
| 284 298 | 
             
                  def database_error_classes
         | 
| @@ -297,15 +311,17 @@ module Sequel | |
| 297 311 | 
             
                    end
         | 
| 298 312 | 
             
                  end
         | 
| 299 313 | 
             
                end
         | 
| 300 | 
            -
             | 
| 314 | 
            +
             | 
| 315 | 
            +
                # Dataset adapter for Sequel
         | 
| 301 316 | 
             
                class Dataset < Sequel::Dataset
         | 
| 302 317 | 
             
                  include ::Sequel::SQLite::DatasetMethods
         | 
| 303 318 |  | 
| 319 | 
            +
                  # @!visibility private
         | 
| 304 320 | 
             
                  module ArgumentMapper
         | 
| 305 321 | 
             
                    include Sequel::Dataset::ArgumentMapper
         | 
| 306 | 
            -
             | 
| 322 | 
            +
             | 
| 307 323 | 
             
                    protected
         | 
| 308 | 
            -
             | 
| 324 | 
            +
             | 
| 309 325 | 
             
                    # Return a hash with the same values as the given hash,
         | 
| 310 326 | 
             
                    # but with the keys converted to strings.
         | 
| 311 327 | 
             
                    def map_to_prepared_args(hash)
         | 
| @@ -313,19 +329,22 @@ module Sequel | |
| 313 329 | 
             
                      hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
         | 
| 314 330 | 
             
                      args
         | 
| 315 331 | 
             
                    end
         | 
| 316 | 
            -
             | 
| 332 | 
            +
             | 
| 317 333 | 
             
                    private
         | 
| 318 | 
            -
             | 
| 334 | 
            +
             | 
| 319 335 | 
             
                    # SQLite uses a : before the name of the argument for named
         | 
| 320 336 | 
             
                    # arguments.
         | 
| 321 337 | 
             
                    def prepared_arg(k)
         | 
| 322 338 | 
             
                      LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
         | 
| 323 339 | 
             
                    end
         | 
| 324 340 | 
             
                  end
         | 
| 325 | 
            -
             | 
| 341 | 
            +
             | 
| 342 | 
            +
                  # @!visibility private
         | 
| 326 343 | 
             
                  BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
         | 
| 344 | 
            +
                  # @!visibility private
         | 
| 327 345 | 
             
                  PreparedStatementMethods = prepared_statements_module(:prepare, BindArgumentMethods)
         | 
| 328 346 |  | 
| 347 | 
            +
                  # @!visibility private
         | 
| 329 348 | 
             
                  def fetch_rows(sql, &block)
         | 
| 330 349 | 
             
                    execute(sql, &block)
         | 
| 331 350 | 
             
                    # execute(sql) do |result|
         | 
| @@ -350,9 +369,9 @@ module Sequel | |
| 350 369 | 
             
                    #   end
         | 
| 351 370 | 
             
                    # end
         | 
| 352 371 | 
             
                  end
         | 
| 353 | 
            -
             | 
| 372 | 
            +
             | 
| 354 373 | 
             
                  private
         | 
| 355 | 
            -
             | 
| 374 | 
            +
             | 
| 356 375 | 
             
                  # The base type name for a given type, without any parenthetical part.
         | 
| 357 376 | 
             
                  def base_type_name(t)
         | 
| 358 377 | 
             
                    (t =~ /^(.*?)\(/ ? $1 : t).downcase if t
         | 
    
        data/test/test_sequel.rb
    CHANGED
    
    | @@ -4,21 +4,43 @@ require_relative 'helper' | |
| 4 4 | 
             
            require 'sequel'
         | 
| 5 5 |  | 
| 6 6 | 
             
            class SequelExtraliteTest < MiniTest::Test
         | 
| 7 | 
            -
              def  | 
| 8 | 
            -
                db = Sequel.connect('extralite::memory:')
         | 
| 9 | 
            -
                db.create_table :items do
         | 
| 7 | 
            +
              def setup
         | 
| 8 | 
            +
                @db = Sequel.connect('extralite::memory:')
         | 
| 9 | 
            +
                @db.create_table :items do
         | 
| 10 10 | 
             
                  primary_key :id
         | 
| 11 11 | 
             
                  String :name, unique: true, null: false
         | 
| 12 12 | 
             
                  Float :price, null: false
         | 
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 | 
            -
                items = db[:items]
         | 
| 16 | 
            -
             | 
| 15 | 
            +
                items = @db[:items]
         | 
| 17 16 | 
             
                items.insert(name: 'abc', price: 123)
         | 
| 18 17 | 
             
                items.insert(name: 'def', price: 456)
         | 
| 19 18 | 
             
                items.insert(name: 'ghi', price: 789)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def teardown
         | 
| 22 | 
            +
                @db.disconnect
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def test_sequel
         | 
| 26 | 
            +
                items = @db[:items]
         | 
| 20 27 |  | 
| 21 28 | 
             
                assert_equal 3, items.count
         | 
| 22 29 | 
             
                assert_equal (123+456+789) / 3, items.avg(:price)
         | 
| 23 30 | 
             
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def test_prepared_statement
         | 
| 33 | 
            +
                items = @db[:items]
         | 
| 34 | 
            +
                prepared_query = items.where(name: :$name).prepare(:select, :select_by_name)
         | 
| 35 | 
            +
                prepared_insert = items.prepare(:insert, :insert_with_name_and_price, name: :$name, price: :$price)
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                assert_equal prepared_query.call(name: 'def'), [{ id: 2, name: 'def', price: 456 }]
         | 
| 38 | 
            +
                assert_equal @db.call(:select_by_name, name: 'def'), [{ id: 2, name: 'def', price: 456 }]
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                id = prepared_insert.call(name: 'jkl', price: 444)
         | 
| 41 | 
            +
                assert_equal items[id: id], { id: id, name: 'jkl', price: 444 }
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                id = @db.call(:insert_with_name_and_price, name: 'mno', price: 555)
         | 
| 44 | 
            +
                assert_equal items[id: id], { id: id, name: 'mno', price: 555 }
         | 
| 45 | 
            +
              end
         | 
| 24 46 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: extralite
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: '1. | 
| 4 | 
            +
              version: '1.27'
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Sharon Rosner
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-06-12 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake-compiler
         | 
| @@ -91,6 +91,7 @@ files: | |
| 91 91 | 
             
            - ".github/FUNDING.yml"
         | 
| 92 92 | 
             
            - ".github/workflows/test.yml"
         | 
| 93 93 | 
             
            - ".gitignore"
         | 
| 94 | 
            +
            - ".yardopts"
         | 
| 94 95 | 
             
            - CHANGELOG.md
         | 
| 95 96 | 
             
            - Gemfile
         | 
| 96 97 | 
             
            - Gemfile.lock
         |