sqlite_adapter.rb 3.8 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# sqlite_adapter.rb
# author:   Luke Holden <lholden@cablelan.net>

require 'active_record/connection_adapters/abstract_adapter'

module ActiveRecord
  class Base
    # Establishes a connection to the database that's used by all Active Record objects
    def self.sqlite_connection(config) # :nodoc:
      require_library_or_gem('sqlite') unless self.class.const_defined?(:SQLite)
      symbolize_strings_in_hash(config)
      unless config.has_key?(:dbfile)
        raise ArgumentError, "No database file specified. Missing argument: dbfile"
      end
15
      
16
      config[:dbfile] = File.expand_path(config[:dbfile], RAILS_ROOT) if Object.const_defined?(:RAILS_ROOT)
D
Initial  
David Heinemeier Hansson 已提交
17 18 19 20 21 22 23 24 25 26 27
      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

      ConnectionAdapters::SQLiteAdapter.new(db, logger)
    end
  end

  module ConnectionAdapters
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
    
    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
D
Initial  
David Heinemeier Hansson 已提交
50 51 52 53 54 55 56 57 58 59 60 61
    class SQLiteAdapter < AbstractAdapter # :nodoc:
      def select_all(sql, name = nil)
        select(sql, name)
      end

      def select_one(sql, name = nil)
        result = select(sql, name)
        result.nil? ? nil : result.first
      end

      def columns(table_name, name = nil)
        table_structure(table_name).inject([]) do |columns, field| 
62
          columns << SQLiteColumn.new(field['name'], field['dflt_value'], field['type'])
D
Initial  
David Heinemeier Hansson 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
          columns
        end
      end

      def insert(sql, name = nil, pk = nil, id_value = nil)
        execute(sql, name = nil)
        id_value || @connection.send( defined?( SQLite::Version ) ? :last_insert_row_id : :last_insert_rowid )
      end

      def execute(sql, name = nil)
        log(sql, name, @connection) do |connection|
          if defined?( SQLite::Version )
            case sql
              when "BEGIN" then connection.transaction
              when "COMMIT" then connection.commit
              when "ROLLBACK" then connection.rollback
              else connection.execute(sql)
            end
          else
            connection.execute( sql )
          end
        end
      end

87 88 89 90 91 92 93 94 95 96
      def update(sql, name = nil)
        execute(sql, name)
        @connection.changes
      end
      
      def delete(sql, name = nil)
        sql += " WHERE 1=1" unless sql =~ /WHERE/i
        execute(sql, name)
        @connection.changes
      end
D
Initial  
David Heinemeier Hansson 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

      def begin_db_transaction()    execute "BEGIN" end
      def commit_db_transaction()   execute "COMMIT" end
      def rollback_db_transaction() execute "ROLLBACK" end

      def quote_string(s)
        SQLite::Database.quote(s)
      end
        
      def quote_column_name(name)
        return "'#{name}'"
      end

      private
        def select(sql, name = nil)
          results = nil
          log(sql, name, @connection) { |connection| results = connection.execute(sql) }

          rows = []

          results.each do |row|
            hash_only_row = {}
            row.each_key do |key|
              hash_only_row[key.sub(/\w+\./, "")] = row[key] unless key.class == Fixnum
            end
            rows << hash_only_row
          end

          return rows
        end

        def table_structure(table_name)
          sql = "PRAGMA table_info(#{table_name});"
          results = nil
          log(sql, nil, @connection) { |connection| results = connection.execute(sql) }
          return results
        end
    end
  end
136
end