sqlite_adapter.rb 4.3 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
# sqlite_adapter.rb
2 3
# author: Luke Holden <lholden@cablelan.net>
# updated for SQLite3: Jamis Buck <jamis_buck@byu.edu>
D
Initial  
David Heinemeier Hansson 已提交
4 5 6 7 8

require 'active_record/connection_adapters/abstract_adapter'

module ActiveRecord
  class Base
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
    class << self
      # sqlite3 adapter reuses sqlite_connection.
      def sqlite3_connection(config) # :nodoc:
        parse_config!(config)

        unless self.class.const_defined?(:SQLite3)
          require_library_or_gem(config[:adapter])
        end

        db = SQLite3::Database.new(
          config[:dbfile],
          :results_as_hash => true,
          :type_translation => false
        )
        ConnectionAdapters::SQLiteAdapter.new(db, logger)
      end

      # Establishes a connection to the database that's used by all Active Record objects
      def sqlite_connection(config) # :nodoc:
        parse_config!(config)

        unless self.class.const_defined?(:SQLite)
          require_library_or_gem(config[:adapter])

          db = SQLite::Database.new(config[:dbfile], 0)
          db.show_datatypes   = "ON" if !defined? SQLite::Version
          db.results_as_hash  = true if defined? SQLite::Version
          db.type_translation = false

          # "Downgrade" deprecated sqlite API
          if SQLite.const_defined?(:Version)
            ConnectionAdapters::SQLiteAdapter.new(db, logger)
          else
            ConnectionAdapters::DeprecatedSQLiteAdapter.new(db, logger)
          end
        end
D
Initial  
David Heinemeier Hansson 已提交
45 46
      end

47 48 49 50 51 52
      private
        def parse_config!(config)
          # Require dbfile.
          unless config.has_key?(:dbfile)
            raise ArgumentError, "No database file specified. Missing argument: dbfile"
          end
D
Initial  
David Heinemeier Hansson 已提交
53

54 55 56 57 58
          # Allow database path relative to RAILS_ROOT.
          if Object.const_defined?(:RAILS_ROOT)
            config[:dbfile] = File.expand_path(config[:dbfile], RAILS_ROOT)
          end
        end
D
Initial  
David Heinemeier Hansson 已提交
59 60 61 62
    end
  end

  module ConnectionAdapters
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    
    class SQLiteColumn < Column
      def string_to_binary(value)
        value.gsub(/(\0|\%)/) do
          case $1
            when "\0" then "%00"
            when "%" then "%25"
          end
        end                
      end
      
      def binary_to_string(value)
        value.gsub(/(%00|%25)/) do
          case $1
            when "%00" then "\0"
            when "%25" then "%"
          end
        end                
      end
    end
83

D
Initial  
David Heinemeier Hansson 已提交
84
    class SQLiteAdapter < AbstractAdapter # :nodoc:
85 86
      def execute(sql, name = nil)
        log(sql, name) { @connection.execute(sql) }
D
Initial  
David Heinemeier Hansson 已提交
87 88
      end

89 90 91
      def update(sql, name = nil)
        execute(sql, name)
        @connection.changes
D
Initial  
David Heinemeier Hansson 已提交
92 93
      end

94 95 96 97
      def delete(sql, name = nil)
        sql += " WHERE 1=1" unless sql =~ /WHERE/i
        execute(sql, name)
        @connection.changes
D
Initial  
David Heinemeier Hansson 已提交
98 99 100 101
      end

      def insert(sql, name = nil, pk = nil, id_value = nil)
        execute(sql, name = nil)
102
        id_value || @connection.last_insert_row_id
D
Initial  
David Heinemeier Hansson 已提交
103 104
      end

105 106 107 108 109
      def select_all(sql, name = nil)
        execute(sql, name).map do |row|
          record = {}
          row.each_key do |key|
            record[key.sub(/\w+\./, '')] = row[key] unless key.is_a?(Fixnum)
D
Initial  
David Heinemeier Hansson 已提交
110
          end
111
          record
D
Initial  
David Heinemeier Hansson 已提交
112 113 114
        end
      end

115 116 117
      def select_one(sql, name = nil)
        result = select_all(sql, name)
        result.nil? ? nil : result.first
118
      end
119 120 121 122 123 124 125 126 127


      def begin_db_transaction()    @connection.transaction end
      def commit_db_transaction()   @connection.commit      end
      def rollback_db_transaction() @connection.rollback    end


      def tables
        execute('.table').map { |table| Table.new(table) }
128
      end
D
Initial  
David Heinemeier Hansson 已提交
129

130 131 132 133 134
      def columns(table_name, name = nil)
        table_structure(table_name).map { |field|
          SQLiteColumn.new(field['name'], field['dflt_value'], field['type'])
        }
      end
D
Initial  
David Heinemeier Hansson 已提交
135 136

      def quote_string(s)
137
        @connection.class.quote(s)
D
Initial  
David Heinemeier Hansson 已提交
138
      end
139

D
Initial  
David Heinemeier Hansson 已提交
140 141 142 143
      def quote_column_name(name)
        return "'#{name}'"
      end

144 145 146 147
      def adapter_name()
        'SQLite'
      end

148
      protected
D
Initial  
David Heinemeier Hansson 已提交
149
        def table_structure(table_name)
150
          execute "PRAGMA table_info(#{table_name})"
D
Initial  
David Heinemeier Hansson 已提交
151 152
        end
    end
153 154 155 156 157 158 159

    class DeprecatedSQLiteAdapter < SQLiteAdapter # :nodoc:
      def insert(sql, name = nil, pk = nil, id_value = nil)
        execute(sql, name = nil)
        id_value || @connection.last_insert_rowid
      end
    end
D
Initial  
David Heinemeier Hansson 已提交
160
  end
161
end