Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 0fbb3b38c2e59e80f397fcd83fcc50efbd050bd5 @lifo committed Dec 16, 2009
@@ -0,0 +1,14 @@
+require 'rubygems'
+
+$: << File.join(File.dirname(__FILE__), "lib")
+require 'cramp'
+require 'cramp/model'
+
+Arel::Table.engine = Cramp::Model::Engine.new(:username => 'root', :database => 'arel_test')
+
+EM.run do
+ users = Table(:users)
+ users.where(users[:name].eq('lifo')).each {|x| puts x.inspect }
+ EM.stop
+end
+
@@ -0,0 +1,2 @@
+module Cramp
+end
@@ -0,0 +1,18 @@
+require 'cramp/vendor/evented_mysql'
+require 'eventmachine'
+require 'mysqlplus'
+
+$: << File.join(File.dirname(__FILE__), 'vendor/arel/lib')
+require 'arel'
+
+module Cramp
+ module Model
+ autoload :Quoting, "cramp/model/quoting"
+ autoload :Engine, "cramp/model/engine"
+ autoload :Column, "cramp/model/column"
+ end
+end
+
+require 'cramp/model/monkey_patches'
+require 'cramp/model/emysql_ext'
+
@@ -0,0 +1,72 @@
+# Some of it yanked from Rails
+
+# Copyright (c) 2004-2009 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Cramp
+ module Model
+ class Column < Struct.new(:name, :default, :sql_type, :null)
+ attr_reader :type
+
+ def initialize(name, default, sql_type, null)
+ super
+ @type = simplified_type(sql_type)
+ end
+
+ private
+
+ def simplified_type(field_type)
+ case field_type
+ when /int/i
+ :integer
+ when /float|double/i
+ :float
+ when /decimal|numeric|number/i
+ extract_scale(field_type) == 0 ? :integer : :decimal
+ when /datetime/i
+ :datetime
+ when /timestamp/i
+ :timestamp
+ when /time/i
+ :time
+ when /date/i
+ :date
+ when /clob/i, /text/i
+ :text
+ when /blob/i, /binary/i
+ :binary
+ when /char/i, /string/i
+ :string
+ when /boolean/i
+ :boolean
+ end
+ end
+
+ def extract_scale(sql_type)
+ case sql_type
+ when /^(numeric|decimal|number)\((\d+)\)/i then 0
+ when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
+ end
+ end
+
+ end
+ end
+end
@@ -0,0 +1,21 @@
+class EventedMysql
+ def self.execute_now(query)
+ @n ||= 0
+ connection = connection_pool[@n]
+ @n = 0 if (@n+=1) >= connection_pool.size
+ connection.execute_now(query)
+ end
+
+ def execute_now(sql)
+ log 'mysql sending', sql
+ @mysql.query(sql)
+ rescue Mysql::Error => e
+ log 'mysql error', e.message
+ if DisconnectErrors.include? e.message
+ @@queue << [response, sql, cblk, eblk]
+ return close
+ else
+ raise e
+ end
+ end
+end
@@ -0,0 +1,45 @@
+module Cramp
+ module Model
+ class Engine
+ include Quoting
+
+ def initialize(settings)
+ @settings = settings
+ @quoted_column_names, @quoted_table_names = {}, {}
+
+ EventedMysql.settings.update(settings) {|r| yield(r) }
+ end
+
+ def create(relation)
+ EventedMysql.insert(relation.to_sql) {|r| yield(r) }
+ end
+
+ def read(relation, &block)
+ EventedMysql.select(relation.to_sql) {|rows| block.call(rows) }
+ end
+
+ def update(relation)
+ EventedMysql.update(relation.to_sql) {|r| yield(r) }
+ end
+
+ def delete(relation)
+ EventedMysql.delete(relation.to_sql) {|r| yield(r) }
+ end
+
+ def adapter_name
+ "Cramp MySQL Async Adapter"
+ end
+
+ def columns(table_name, name = nil)
+ sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
+ columns = []
+ result = EventedMysql.execute_now(sql)
+
+ result.each { |field| columns << Column.new(field[0], field[4], field[1], field[2] == "YES") }
+ result.free
+ columns
+ end
+
+ end
+ end
+end
@@ -0,0 +1,19 @@
+class Arel::Session
+ def read(select, &block)
+ select.call(&block)
+ end
+end
+
+class Arel::Relation
+ def call(&block)
+ engine.read(self, &block)
+ end
+
+ def each(&block)
+ session.read(self) {|rows| rows.each(&block)}
+ end
+
+ def each(&block)
+ session.read(self) {|rows| rows.each {|r| block.call(r) } }
+ end
+end
@@ -0,0 +1,114 @@
+# Yanked from Rails
+
+# Copyright (c) 2004-2009 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Cramp
+ module Model
+ module Quoting
+ def quote_column_name(name)
+ @quoted_column_names[name] ||= "`#{name}`"
+ end
+
+ def quote_table_name(name)
+ @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
+ end
+
+ def quote(value, column = nil)
+ if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
+ s = value.unpack("H*")[0]
+ "x'#{s}'"
+ elsif value.kind_of?(BigDecimal)
+ value.to_s("F")
+ else
+ super
+ end
+ end
+
+ def quote(value, column = nil)
+ # records are quoted as their primary key
+ return value.quoted_id if value.respond_to?(:quoted_id)
+
+ case value
+ when String, ActiveSupport::Multibyte::Chars
+ value = value.to_s
+ if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
+ "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
+ elsif column && [:integer, :float].include?(column.type)
+ value = column.type == :integer ? value.to_i : value.to_f
+ value.to_s
+ else
+ "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
+ end
+ when NilClass then "NULL"
+ when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
+ when FalseClass then (column && column.type == :integer ? '0' : quoted_false)
+ when Float, Fixnum, Bignum then value.to_s
+ # BigDecimals need to be output in a non-normalized form and quoted.
+ when BigDecimal then value.to_s('F')
+ else
+ if value.acts_like?(:date) || value.acts_like?(:time)
+ "'#{quoted_date(value)}'"
+ else
+ "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
+ end
+ end
+ end
+
+ # Quotes a string, escaping any ' (single quote) and \ (backslash)
+ # characters.
+ def quote_string(s)
+ s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
+ end
+
+ # Quotes the column name. Defaults to no quoting.
+ def quote_column_name(column_name)
+ column_name
+ end
+
+ # Quotes the table name. Defaults to column name quoting.
+ def quote_table_name(table_name)
+ quote_column_name(table_name)
+ end
+
+ def quoted_true
+ "'t'"
+ end
+
+ def quoted_false
+ "'f'"
+ end
+
+ def quoted_date(value)
+ if value.acts_like?(:time)
+ zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
+ value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
+ else
+ value
+ end.to_s(:db)
+ end
+
+ def quoted_string_prefix
+ ''
+ end
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 0fbb3b3

Please sign in to comment.