public
Rubygem
Description: An ActiveRecord to the DBSlayer lightweight proxy/pooling layer (http://code.nytimes.com/projects/dbslayer)
Clone URL: git://github.com/harrisj/activerecord-dbslayer-adapter.git
harrisj (author)
Thu May 08 11:16:27 -0700 2008
commit  102cec42ea8bbe59742e0525f67b3ee1489c4bbf
tree    d9bffc96ceb1f9985615c38f98b67fd7b77235db
parent  0ad288887d167265431c0cbbdce8257bd403af88
100644 154 lines (129 sloc) 3.573 kb
1
2
3
4
5
6
7
8
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
require 'rubygems'
require 'net/http'
require 'open-uri'
require 'json'
 
module ActiveRecord
  module ConnectionAdapters
 
    class DbslayerException < RuntimeError
    end
    
    class DbslayerResult
      def initialize(results_hash)
        @hash = results_hash
      end
 
      def rows
        @hash['ROWS']
      end
 
      def types
        @hash['TYPES']
      end
 
      def header
        @hash['HEADER']
      end
      
      ## Compatibility to the MySQL ones
      def num_rows
        return 0 if rows.nil?
        rows.size
      end
 
      def each
        return if rows.nil?
        rows.each {|r| yield r }
      end
      
      def hash_rows
        return [] if rows.nil?
        rows.map do |row|
          hash = {}
          header.each_with_index do |head, i|
            hash[head] = row[i]
          end
          
          hash
        end
      end
      
      def each_hash
        return if rows.nil?
        hash_rows.each do |row|
          yield row
        end
      end
    end
 
    class DbslayerConnection
      attr_reader :host, :port
      
      def initialize(host='localhost', port=9090)
        @host = host
        @port = port
      end
 
      ##
      # Executes a SQL query
      def sql_query(sql)
        dbslay_results = cmd_execute(:db, 'SQL' => sql)
                
        # check for an error
        if dbslay_results['MYSQL_ERROR']
          raise DbslayerException, "MySQL Error #{dbslay_results['MYSQL_ERRNO']}: #{dbslay_results['MYSQL_ERROR']}"
        elsif dbslay_results['RESULT']
          result = dbslay_results['RESULT']
          case result
          when Hash
            DbslayerResult.new(result)
          when Array
            result.map {|r| DbslayerResult.new(r) }
          else
            raise DbslayerException, "Unknown format for SQL results from DBSlayer"
          end
        elsif dbslay_results['SUCCESS']
          return dbslay_results['SUCCESS']
        else
          raise DbslayerException, "Unknown format for SQL results from DBSlayer"
        end
      end
 
      alias execute sql_query
      alias query sql_query
 
      def mysql_stats
        results = cmd_execute(:db, 'STAT' => true)
        results['STAT']
      end
 
      alias stat mysql_stats
 
      def client_info
        if @client_info.nil?
          @client_info = cmd_execute(:db, 'CLIENT_INFO' => true)["CLIENT_INFO"]
        end
        @client_info
      end
 
      alias server_info client_info
 
      def client_version_num
        if @client_version.nil?
          @client_version = Integer(cmd_execute(:db, 'CLIENT_VERSION' => true)["CLIENT_VERSION"])
        end
        @client_version
      end
 
      def server_version_num
        if @server_version.nil?
          @server_version = Integer(cmd_execute(:db, 'SERVER_VERSION' => true)["SERVER_VERSION"])
        end
        @server_version
      end
 
      def escape_string(str)
        str.gsub(/([\0\n\r\032\'\"\\])/) do
          case $1
          when "\0" then "\\0"
          when "\n" then "\\n"
          when "\r" then "\\r"
          when "\032" then "\\Z"
          else "\\"+$1
          end
        end
      end
      alias :quote :escape_string
      
      private
      def query_string(commands)
        URI.encode commands.to_json
      end
 
      ##
      # Returns a JSON date
      def cmd_execute(endpoint, commands)
        url = "http://#{host}:#{port}/#{endpoint.to_s}?#{query_string(commands)}"
        open(url) do |file|
          JSON.parse(file.read)
        end
      end
    end
  end
end