tramp 0.1
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.
- data/MIT-LICENSE +20 -0
 - data/lib/tramp.rb +49 -0
 - data/lib/tramp/arel_monkey_patches.rb +66 -0
 - data/lib/tramp/attribute.rb +101 -0
 - data/lib/tramp/attribute_methods.rb +81 -0
 - data/lib/tramp/base.rb +117 -0
 - data/lib/tramp/callbacks.rb +39 -0
 - data/lib/tramp/column.rb +70 -0
 - data/lib/tramp/emysql_ext.rb +21 -0
 - data/lib/tramp/engine.rb +73 -0
 - data/lib/tramp/engine/connection.rb +30 -0
 - data/lib/tramp/evented_mysql.rb +298 -0
 - data/lib/tramp/finders.rb +25 -0
 - data/lib/tramp/quoting.rb +102 -0
 - data/lib/tramp/relation.rb +60 -0
 - data/lib/tramp/status.rb +16 -0
 - metadata +133 -0
 
    
        data/MIT-LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2009-2010 Pratik Naik
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 4 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 5 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 6 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 7 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 8 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 9 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 12 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 15 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 16 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 17 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 18 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 19 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 20 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/lib/tramp.rb
    ADDED
    
    | 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'eventmachine'
         
     | 
| 
      
 2 
     | 
    
         
            +
            EM.epoll
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'active_support/core_ext/class/inheritable_attributes'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'active_support/core_ext/class/attribute_accessors'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'active_support/core_ext/module/aliasing'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'active_support/core_ext/module/attribute_accessors'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'active_support/core_ext/kernel/reporting'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'active_support/core_ext/hash/indifferent_access'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'active_support/buffered_logger'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            require 'tramp/evented_mysql'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'tramp/emysql_ext'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require 'mysqlplus'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'arel'
         
     | 
| 
      
 18 
     | 
    
         
            +
            require 'tramp/arel_monkey_patches'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'active_model'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 22 
     | 
    
         
            +
              VERSION = '0.1'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              mattr_accessor :logger
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              autoload :Quoting, "tramp/quoting"
         
     | 
| 
      
 27 
     | 
    
         
            +
              autoload :Engine, "tramp/engine"
         
     | 
| 
      
 28 
     | 
    
         
            +
              autoload :Column, "tramp/column"
         
     | 
| 
      
 29 
     | 
    
         
            +
              autoload :Relation, "tramp/relation"
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              autoload :Base, "tramp/base"
         
     | 
| 
      
 32 
     | 
    
         
            +
              autoload :Finders, "tramp/finders"
         
     | 
| 
      
 33 
     | 
    
         
            +
              autoload :Attribute, "tramp/attribute"
         
     | 
| 
      
 34 
     | 
    
         
            +
              autoload :AttributeMethods, "tramp/attribute_methods"
         
     | 
| 
      
 35 
     | 
    
         
            +
              autoload :Status, "tramp/status"
         
     | 
| 
      
 36 
     | 
    
         
            +
              autoload :Callbacks, "tramp/callbacks"
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def self.init(settings)
         
     | 
| 
      
 39 
     | 
    
         
            +
                Arel::Table.engine = Tramp::Engine.new(settings)
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              def self.select(query, callback = nil, &block)
         
     | 
| 
      
 43 
     | 
    
         
            +
                callback ||= block
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                EventedMysql.select(query) do |rows|
         
     | 
| 
      
 46 
     | 
    
         
            +
                  callback.arity == 1 ? callback.call(rows) : callback.call if callback
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Arel::Session
         
     | 
| 
      
 2 
     | 
    
         
            +
              def create(insert, &block)
         
     | 
| 
      
 3 
     | 
    
         
            +
                insert.call(&block)
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def read(select, &block)
         
     | 
| 
      
 7 
     | 
    
         
            +
                select.call(&block)
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def update(update, &block)
         
     | 
| 
      
 11 
     | 
    
         
            +
                update.call(&block)
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def delete(delete, &block)
         
     | 
| 
      
 15 
     | 
    
         
            +
                delete.call(&block)
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            module Arel::Relation
         
     | 
| 
      
 21 
     | 
    
         
            +
              def call(&block)
         
     | 
| 
      
 22 
     | 
    
         
            +
                engine.read(self, &block)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              def all(&block)
         
     | 
| 
      
 26 
     | 
    
         
            +
                session.read(self) {|rows| block.call(rows) }
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              def first(&block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                session.read(self) {|rows| block.call(rows[0]) }
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def each(&block)
         
     | 
| 
      
 34 
     | 
    
         
            +
                session.read(self) {|rows| rows.each {|r| block.call(r) } }
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              def insert(record, &block)
         
     | 
| 
      
 38 
     | 
    
         
            +
                session.create(Arel::Insert.new(self, record), &block)
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def update(assignments, &block)
         
     | 
| 
      
 42 
     | 
    
         
            +
                session.update(Arel::Update.new(self, assignments), &block)
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def delete(&block)
         
     | 
| 
      
 46 
     | 
    
         
            +
                session.delete(Arel::Deletion.new(self), &block)
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            class Arel::Deletion
         
     | 
| 
      
 51 
     | 
    
         
            +
              def call(&block)
         
     | 
| 
      
 52 
     | 
    
         
            +
                engine.delete(self, &block)
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            class Arel::Insert
         
     | 
| 
      
 57 
     | 
    
         
            +
              def call(&block)
         
     | 
| 
      
 58 
     | 
    
         
            +
                engine.create(self, &block)
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            class Arel::Update
         
     | 
| 
      
 63 
     | 
    
         
            +
              def call(&block)
         
     | 
| 
      
 64 
     | 
    
         
            +
                engine.update(self, &block)
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright (c) 2009 Koziarski Software Ltd
         
     | 
| 
      
 2 
     | 
    
         
            +
            # 
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Permission to use, copy, modify, and/or distribute this software for any
         
     | 
| 
      
 4 
     | 
    
         
            +
            # purpose with or without fee is hereby granted, provided that the above
         
     | 
| 
      
 5 
     | 
    
         
            +
            # copyright notice and this permission notice appear in all copies.
         
     | 
| 
      
 6 
     | 
    
         
            +
            # 
         
     | 
| 
      
 7 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
         
     | 
| 
      
 8 
     | 
    
         
            +
            # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
         
     | 
| 
      
 9 
     | 
    
         
            +
            # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
         
     | 
| 
      
 10 
     | 
    
         
            +
            # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
         
     | 
| 
      
 11 
     | 
    
         
            +
            # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
         
     | 
| 
      
 12 
     | 
    
         
            +
            # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
         
     | 
| 
      
 13 
     | 
    
         
            +
            # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 16 
     | 
    
         
            +
              class Attribute
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                FORMATS = {}
         
     | 
| 
      
 19 
     | 
    
         
            +
                FORMATS[Date]    = /^\d{4}\/\d{2}\/\d{2}$/
         
     | 
| 
      
 20 
     | 
    
         
            +
                FORMATS[Integer] = /^-?\d+$/
         
     | 
| 
      
 21 
     | 
    
         
            +
                FORMATS[Float]   = /^-?\d*\.\d*$/
         
     | 
| 
      
 22 
     | 
    
         
            +
                FORMATS[Time]    = /\A\s*
         
     | 
| 
      
 23 
     | 
    
         
            +
                          -?\d+-\d\d-\d\d
         
     | 
| 
      
 24 
     | 
    
         
            +
                          T
         
     | 
| 
      
 25 
     | 
    
         
            +
                          \d\d:\d\d:\d\d
         
     | 
| 
      
 26 
     | 
    
         
            +
                          (\.\d*)?
         
     | 
| 
      
 27 
     | 
    
         
            +
                          (Z|[+-]\d\d:\d\d)?
         
     | 
| 
      
 28 
     | 
    
         
            +
                          \s*\z/ix # lifted from the implementation of Time.xmlschema
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                CONVERTERS = {}
         
     | 
| 
      
 31 
     | 
    
         
            +
                CONVERTERS[Date] = Proc.new do |str|
         
     | 
| 
      
 32 
     | 
    
         
            +
                  Date.strptime(str, "%Y/%m/%d")
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                CONVERTERS[Integer] = Proc.new do |str|
         
     | 
| 
      
 36 
     | 
    
         
            +
                  Integer(str)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                CONVERTERS[Float] = Proc.new do |str|
         
     | 
| 
      
 40 
     | 
    
         
            +
                  Float(str)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                CONVERTERS[Time] = Proc.new do |str|
         
     | 
| 
      
 44 
     | 
    
         
            +
                  Time.xmlschema(str)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                attr_reader :name
         
     | 
| 
      
 48 
     | 
    
         
            +
                def initialize(name, owner_class, options)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @name = name.to_s
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @owner_class = owner_class
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @options = options
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  # append_validations!
         
     | 
| 
      
 54 
     | 
    
         
            +
                  define_methods!
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                # I think this should live somewhere in Amo
         
     | 
| 
      
 58 
     | 
    
         
            +
                def check_value!(value)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # Allow nil and Strings to fall back on the validations for typecasting
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # Everything else gets checked with is_a?
         
     | 
| 
      
 61 
     | 
    
         
            +
                  if value.nil?
         
     | 
| 
      
 62 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 63 
     | 
    
         
            +
                  elsif value.is_a?(String)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    value
         
     | 
| 
      
 65 
     | 
    
         
            +
                  elsif value.is_a?(expected_type)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    value
         
     | 
| 
      
 67 
     | 
    
         
            +
                  else
         
     | 
| 
      
 68 
     | 
    
         
            +
                    raise TypeError, "Expected #{expected_type.inspect} but got #{value.inspect}"
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def expected_type
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @options[:type] || String
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def type_cast(value)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  if value.is_a?(expected_type)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    value
         
     | 
| 
      
 79 
     | 
    
         
            +
                  elsif (converter = CONVERTERS[expected_type]) && (value =~ FORMATS[expected_type])
         
     | 
| 
      
 80 
     | 
    
         
            +
                    converter.call(value)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  else
         
     | 
| 
      
 82 
     | 
    
         
            +
                    value
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def append_validations!
         
     | 
| 
      
 87 
     | 
    
         
            +
                  if f = FORMATS[expected_type]
         
     | 
| 
      
 88 
     | 
    
         
            +
                    @owner_class.validates_format_of @name, :with => f, :unless => lambda {|obj| obj.send(name).is_a? expected_type }, :allow_nil => @options[:allow_nil]
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def define_methods!
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @owner_class.define_attribute_methods(true)
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def primary_key?
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @options[:primary_key]
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,81 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright (c) 2009 Koziarski Software Ltd
         
     | 
| 
      
 2 
     | 
    
         
            +
            # 
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Permission to use, copy, modify, and/or distribute this software for any
         
     | 
| 
      
 4 
     | 
    
         
            +
            # purpose with or without fee is hereby granted, provided that the above
         
     | 
| 
      
 5 
     | 
    
         
            +
            # copyright notice and this permission notice appear in all copies.
         
     | 
| 
      
 6 
     | 
    
         
            +
            # 
         
     | 
| 
      
 7 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
         
     | 
| 
      
 8 
     | 
    
         
            +
            # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
         
     | 
| 
      
 9 
     | 
    
         
            +
            # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
         
     | 
| 
      
 10 
     | 
    
         
            +
            # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
         
     | 
| 
      
 11 
     | 
    
         
            +
            # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
         
     | 
| 
      
 12 
     | 
    
         
            +
            # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
         
     | 
| 
      
 13 
     | 
    
         
            +
            # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 16 
     | 
    
         
            +
                module AttributeMethods
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 19 
     | 
    
         
            +
                include ActiveModel::AttributeMethods
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def attribute(name, options = {})
         
     | 
| 
      
 23 
     | 
    
         
            +
                    write_inheritable_hash(:model_attributes, {name => Attribute.new(name, self, options)})
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def define_attribute_methods(force = false)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    return unless model_attributes
         
     | 
| 
      
 28 
     | 
    
         
            +
                    undefine_attribute_methods if force
         
     | 
| 
      
 29 
     | 
    
         
            +
                    super(model_attributes.keys)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                included do
         
     | 
| 
      
 34 
     | 
    
         
            +
                  class_inheritable_hash :model_attributes
         
     | 
| 
      
 35 
     | 
    
         
            +
                  undef_method(:id) if method_defined?(:id)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  attribute_method_suffix("", "=")
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def write_attribute(name, value)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  if ma = self.class.model_attributes[name.to_sym]
         
     | 
| 
      
 42 
     | 
    
         
            +
                    value = ma.check_value!(value)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  if(@attributes[name] != value)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    send "#{name}_will_change!".to_sym
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @attributes[name] = value
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def read_attribute(name)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  if ma = self.class.model_attributes[name]
         
     | 
| 
      
 52 
     | 
    
         
            +
                    ma.type_cast(@attributes[name])
         
     | 
| 
      
 53 
     | 
    
         
            +
                  else
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @attributes[name]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def attributes=(attributes)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  attributes.each do |(name, value)|
         
     | 
| 
      
 60 
     | 
    
         
            +
                    send("#{name}=", value)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                protected
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def attribute_method?(name)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @attributes.include?(name.to_sym) || model_attributes[name.to_sym]
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                private
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def attribute(name)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  read_attribute(name.to_sym)
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def attribute=(name, value)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  write_attribute(name.to_sym, value)
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tramp/base.rb
    ADDED
    
    | 
         @@ -0,0 +1,117 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                extend Finders
         
     | 
| 
      
 5 
     | 
    
         
            +
                include AttributeMethods
         
     | 
| 
      
 6 
     | 
    
         
            +
                include ActiveModel::Validations
         
     | 
| 
      
 7 
     | 
    
         
            +
                include ActiveModel::Dirty
         
     | 
| 
      
 8 
     | 
    
         
            +
                include Callbacks
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def columns
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @columns ||= arel_table.columns
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def column_names
         
     | 
| 
      
 16 
     | 
    
         
            +
                    columns.map(&:name)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def primary_key
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @primary_key ||= model_attributes.detect {|k, v| v.primary_key? }[0]
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def instantiate(record)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    object = allocate
         
     | 
| 
      
 25 
     | 
    
         
            +
                    object.instance_variable_set("@attributes", record.with_indifferent_access)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    object
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                attr_reader :attributes
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def initialize(attributes = {})
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @new_record = true
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @attributes = {}.with_indifferent_access
         
     | 
| 
      
 35 
     | 
    
         
            +
                  self.attributes = attributes
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def new_record?
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @new_record
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                def save(callback = nil, &block)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  if valid?
         
     | 
| 
      
 46 
     | 
    
         
            +
                    new_record? ? create_record(callback) : update_record(callback)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  else
         
     | 
| 
      
 48 
     | 
    
         
            +
                    callback.arity == 1 ? callback.call(Status.new(self, false)) : callback.call if callback
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def destroy(callback = nil, &block)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 54 
     | 
    
         
            +
                  
         
     | 
| 
      
 55 
     | 
    
         
            +
                  relation.delete do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    status = Status.new(self, true)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    after_destroy_callbacks status
         
     | 
| 
      
 58 
     | 
    
         
            +
                    callback.arity == 1 ? callback.call(status) : callback.call if callback
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                private
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def create_record(callback = nil, &block)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  self.class.arel_table.insert(arel_attributes(true)) do |new_id|
         
     | 
| 
      
 68 
     | 
    
         
            +
                    if new_id.present?
         
     | 
| 
      
 69 
     | 
    
         
            +
                      self.id = new_id
         
     | 
| 
      
 70 
     | 
    
         
            +
                      saved = true
         
     | 
| 
      
 71 
     | 
    
         
            +
                      @new_record = false
         
     | 
| 
      
 72 
     | 
    
         
            +
                    else
         
     | 
| 
      
 73 
     | 
    
         
            +
                      saved = false
         
     | 
| 
      
 74 
     | 
    
         
            +
                    end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    status = Status.new(self, saved)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    after_save status
         
     | 
| 
      
 78 
     | 
    
         
            +
                    callback.arity == 1 ? callback.call(status) : callback.call if callback
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                def update_record(callback = nil, &block)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  relation.update(arel_attributes) do |updated_rows|
         
     | 
| 
      
 86 
     | 
    
         
            +
                    status = Status.new(self, true)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    after_save status
         
     | 
| 
      
 88 
     | 
    
         
            +
                    callback.arity == 1 ? callback.call(status) : callback.call if callback
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def relation
         
     | 
| 
      
 93 
     | 
    
         
            +
                  self.class.arel_table.where(self.class[self.class.primary_key].eq(send(self.class.primary_key)))
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def after_save(status)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  if status.success?
         
     | 
| 
      
 98 
     | 
    
         
            +
                    @previously_changed = changes
         
     | 
| 
      
 99 
     | 
    
         
            +
                    changed_attributes.clear
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  
         
     | 
| 
      
 102 
     | 
    
         
            +
                  after_save_callbacks status
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                def arel_attributes(exclude_primary_key = true, attribute_names = @attributes.keys)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  attrs = {}
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                  attribute_names.each do |name|
         
     | 
| 
      
 109 
     | 
    
         
            +
                    value = read_attribute(name)
         
     | 
| 
      
 110 
     | 
    
         
            +
                    attrs[self.class.arel_table[name]] = value
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  attrs
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
              end
         
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Callbacks
         
     | 
| 
      
 3 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                included do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class_inheritable_accessor :after_save_callback_names
         
     | 
| 
      
 7 
     | 
    
         
            +
                  class_inheritable_accessor :after_destroy_callback_names
         
     | 
| 
      
 8 
     | 
    
         
            +
                  
         
     | 
| 
      
 9 
     | 
    
         
            +
                  self.after_save_callback_names = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                  self.after_destroy_callback_names = []
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def after_save(*method_names)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    self.after_save_callback_names += method_names
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  
         
     | 
| 
      
 18 
     | 
    
         
            +
                  def after_destroy(*method_names)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    self.after_destroy_callback_names += method_names
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                private
         
     | 
| 
      
 24 
     | 
    
         
            +
                def after_save_callbacks(result)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  after_save_callback_names.collect do |callback_name|
         
     | 
| 
      
 26 
     | 
    
         
            +
                    callback = method callback_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                    callback.arity == 1 ? callback.call(result) : callback.call if callback
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                def after_destroy_callbacks(result)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  after_destroy_callback_names.collect do |callback_name|
         
     | 
| 
      
 33 
     | 
    
         
            +
                    callback = method callback_name
         
     | 
| 
      
 34 
     | 
    
         
            +
                    callback.arity == 1 ? callback.call(result) : callback.call if callback
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tramp/column.rb
    ADDED
    
    | 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Some of it yanked from Rails
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright (c) 2004-2009 David Heinemeier Hansson
         
     | 
| 
      
 4 
     | 
    
         
            +
            # 
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            # a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            # "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            # without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            # distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            # permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            # the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
            # 
         
     | 
| 
      
 13 
     | 
    
         
            +
            # The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            # included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
            # 
         
     | 
| 
      
 16 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 25 
     | 
    
         
            +
              class Column < Struct.new(:name, :default, :sql_type, :null)
         
     | 
| 
      
 26 
     | 
    
         
            +
                attr_reader :type
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def initialize(name, default, sql_type, null)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  super
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @type = simplified_type(sql_type)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                private
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def simplified_type(field_type)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  case field_type
         
     | 
| 
      
 37 
     | 
    
         
            +
                    when /int/i
         
     | 
| 
      
 38 
     | 
    
         
            +
                      :integer
         
     | 
| 
      
 39 
     | 
    
         
            +
                    when /float|double/i
         
     | 
| 
      
 40 
     | 
    
         
            +
                      :float
         
     | 
| 
      
 41 
     | 
    
         
            +
                    when /decimal|numeric|number/i
         
     | 
| 
      
 42 
     | 
    
         
            +
                      extract_scale(field_type) == 0 ? :integer : :decimal
         
     | 
| 
      
 43 
     | 
    
         
            +
                    when /datetime/i
         
     | 
| 
      
 44 
     | 
    
         
            +
                      :datetime
         
     | 
| 
      
 45 
     | 
    
         
            +
                    when /timestamp/i
         
     | 
| 
      
 46 
     | 
    
         
            +
                      :timestamp
         
     | 
| 
      
 47 
     | 
    
         
            +
                    when /time/i
         
     | 
| 
      
 48 
     | 
    
         
            +
                      :time
         
     | 
| 
      
 49 
     | 
    
         
            +
                    when /date/i
         
     | 
| 
      
 50 
     | 
    
         
            +
                      :date
         
     | 
| 
      
 51 
     | 
    
         
            +
                    when /clob/i, /text/i
         
     | 
| 
      
 52 
     | 
    
         
            +
                      :text
         
     | 
| 
      
 53 
     | 
    
         
            +
                    when /blob/i, /binary/i
         
     | 
| 
      
 54 
     | 
    
         
            +
                      :binary
         
     | 
| 
      
 55 
     | 
    
         
            +
                    when /char/i, /string/i
         
     | 
| 
      
 56 
     | 
    
         
            +
                      :string
         
     | 
| 
      
 57 
     | 
    
         
            +
                    when /boolean/i
         
     | 
| 
      
 58 
     | 
    
         
            +
                      :boolean
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def extract_scale(sql_type)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  case sql_type
         
     | 
| 
      
 64 
     | 
    
         
            +
                    when /^(numeric|decimal|number)\((\d+)\)/i then 0
         
     | 
| 
      
 65 
     | 
    
         
            +
                    when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class EventedMysql
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.execute_now(query)
         
     | 
| 
      
 3 
     | 
    
         
            +
                @n ||= 0
         
     | 
| 
      
 4 
     | 
    
         
            +
                connection = connection_pool[@n]
         
     | 
| 
      
 5 
     | 
    
         
            +
                @n = 0 if (@n+=1) >= connection_pool.size
         
     | 
| 
      
 6 
     | 
    
         
            +
                connection.execute_now(query)
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              def execute_now(sql)
         
     | 
| 
      
 10 
     | 
    
         
            +
                log 'mysql sending', sql
         
     | 
| 
      
 11 
     | 
    
         
            +
                @mysql.query(sql)
         
     | 
| 
      
 12 
     | 
    
         
            +
              rescue Mysql::Error => e
         
     | 
| 
      
 13 
     | 
    
         
            +
                log 'mysql error', e.message
         
     | 
| 
      
 14 
     | 
    
         
            +
                if DisconnectErrors.include? e.message
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @@queue << [response, sql, cblk, eblk]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  return close
         
     | 
| 
      
 17 
     | 
    
         
            +
                else
         
     | 
| 
      
 18 
     | 
    
         
            +
                  raise e
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tramp/engine.rb
    ADDED
    
    | 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_support/core_ext/module/attribute_accessors'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Engine
         
     | 
| 
      
 5 
     | 
    
         
            +
                autoload :Connection, "tramp/engine/connection"
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                include Quoting
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def initialize(settings)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @connection = Connection.new settings
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @quoted_column_names, @quoted_table_names = {}, {}
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def create(relation, &block)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  query = relation.to_sql
         
     | 
| 
      
 16 
     | 
    
         
            +
                  log_query(query)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @connection.insert(query) {|rows| yield(rows) if block_given? }
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def read(relation, &block)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  query = relation.to_sql
         
     | 
| 
      
 22 
     | 
    
         
            +
                  log_query(query)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @connection.select(query) {|rows| yield(rows) }
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def update(relation)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  query = relation.to_sql
         
     | 
| 
      
 28 
     | 
    
         
            +
                  log_query(query)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @connection.update(query) {|rows| yield(rows) if block_given? }
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def delete(relation)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  query = relation.to_sql
         
     | 
| 
      
 34 
     | 
    
         
            +
                  log_query(query)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @connection.delete(relation.to_sql) {|rows| yield(rows) if block_given? }
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def adapter_name
         
     | 
| 
      
 39 
     | 
    
         
            +
                  "mysql"
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                def connection
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # Arel apparently uses this method to check whether the engine is connected or not
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @connection
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                def tables
         
     | 
| 
      
 48 
     | 
    
         
            +
                  sql = "SHOW TABLES"
         
     | 
| 
      
 49 
     | 
    
         
            +
                  tables = []
         
     | 
| 
      
 50 
     | 
    
         
            +
                  result = @connection.execute_now(sql)
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  result.each { |field| tables << field[0] }
         
     | 
| 
      
 53 
     | 
    
         
            +
                  result.free
         
     | 
| 
      
 54 
     | 
    
         
            +
                  tables
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def columns(table_name, name = nil)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
         
     | 
| 
      
 59 
     | 
    
         
            +
                  columns = []
         
     | 
| 
      
 60 
     | 
    
         
            +
                  result = @connection.execute_now(sql)
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  result.each { |field| columns << Column.new(field[0], field[4], field[1], field[2] == "YES") }
         
     | 
| 
      
 63 
     | 
    
         
            +
                  result.free
         
     | 
| 
      
 64 
     | 
    
         
            +
                  columns
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                protected
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                def log_query(sql)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  Tramp.logger.info("[QUERY] #{sql}") if Tramp.logger
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Engine
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Connection
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize(settings)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    EventedMysql.settings.update(settings)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
                  
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def execute_now(sql)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    EventedMysql.execute_now sql
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                  
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def insert(sql, &block)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    EventedMysql.insert sql, block
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  
         
     | 
| 
      
 16 
     | 
    
         
            +
                  def select(sql, &block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    EventedMysql.select sql, block
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def update(sql, &block)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    EventedMysql.update sql, block
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  
         
     | 
| 
      
 24 
     | 
    
         
            +
                  def delete(sql, &block)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    EventedMysql.delete sql, block
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,298 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Async MySQL driver for Ruby/EventMachine
         
     | 
| 
      
 2 
     | 
    
         
            +
            #   (c) 2008 Aman Gupta (tmm1)
         
     | 
| 
      
 3 
     | 
    
         
            +
            # http://github.com/tmm1/em-mysql
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'eventmachine'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'fcntl'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            class Mysql
         
     | 
| 
      
 9 
     | 
    
         
            +
              def result
         
     | 
| 
      
 10 
     | 
    
         
            +
                @cur_result
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            class EventedMysql < EM::Connection
         
     | 
| 
      
 15 
     | 
    
         
            +
              def initialize mysql, opts
         
     | 
| 
      
 16 
     | 
    
         
            +
                @mysql = mysql
         
     | 
| 
      
 17 
     | 
    
         
            +
                @fd = mysql.socket
         
     | 
| 
      
 18 
     | 
    
         
            +
                @opts = opts
         
     | 
| 
      
 19 
     | 
    
         
            +
                @current = nil
         
     | 
| 
      
 20 
     | 
    
         
            +
                @@queue ||= []
         
     | 
| 
      
 21 
     | 
    
         
            +
                @processing = false
         
     | 
| 
      
 22 
     | 
    
         
            +
                @connected = true
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                log 'mysql connected'
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                self.notify_readable = true
         
     | 
| 
      
 27 
     | 
    
         
            +
                EM.add_timer(0){ next_query }
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
              attr_reader :processing, :connected, :opts
         
     | 
| 
      
 30 
     | 
    
         
            +
              alias :settings :opts
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              DisconnectErrors = [
         
     | 
| 
      
 33 
     | 
    
         
            +
                'query: not connected',
         
     | 
| 
      
 34 
     | 
    
         
            +
                'MySQL server has gone away',
         
     | 
| 
      
 35 
     | 
    
         
            +
                'Lost connection to MySQL server during query'
         
     | 
| 
      
 36 
     | 
    
         
            +
              ] unless defined? DisconnectErrors
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def notify_readable
         
     | 
| 
      
 39 
     | 
    
         
            +
                log 'readable'
         
     | 
| 
      
 40 
     | 
    
         
            +
                if item = @current
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @current = nil
         
     | 
| 
      
 42 
     | 
    
         
            +
                  start, response, sql, cblk, eblk = item
         
     | 
| 
      
 43 
     | 
    
         
            +
                  log 'mysql response', Time.now-start, sql
         
     | 
| 
      
 44 
     | 
    
         
            +
                  arg = case response
         
     | 
| 
      
 45 
     | 
    
         
            +
                        when :raw
         
     | 
| 
      
 46 
     | 
    
         
            +
                          result = @mysql.get_result
         
     | 
| 
      
 47 
     | 
    
         
            +
                          @mysql.instance_variable_set('@cur_result', result)
         
     | 
| 
      
 48 
     | 
    
         
            +
                          @mysql
         
     | 
| 
      
 49 
     | 
    
         
            +
                        when :select
         
     | 
| 
      
 50 
     | 
    
         
            +
                          ret = []
         
     | 
| 
      
 51 
     | 
    
         
            +
                          result = @mysql.get_result
         
     | 
| 
      
 52 
     | 
    
         
            +
                          result.each_hash{|h| ret << h }
         
     | 
| 
      
 53 
     | 
    
         
            +
                          log 'mysql result', ret
         
     | 
| 
      
 54 
     | 
    
         
            +
                          ret
         
     | 
| 
      
 55 
     | 
    
         
            +
                        when :update
         
     | 
| 
      
 56 
     | 
    
         
            +
                          result = @mysql.get_result
         
     | 
| 
      
 57 
     | 
    
         
            +
                          @mysql.affected_rows
         
     | 
| 
      
 58 
     | 
    
         
            +
                        when :insert
         
     | 
| 
      
 59 
     | 
    
         
            +
                          result = @mysql.get_result
         
     | 
| 
      
 60 
     | 
    
         
            +
                          @mysql.insert_id
         
     | 
| 
      
 61 
     | 
    
         
            +
                        else
         
     | 
| 
      
 62 
     | 
    
         
            +
                          result = @mysql.get_result
         
     | 
| 
      
 63 
     | 
    
         
            +
                          log 'got a result??', result if result
         
     | 
| 
      
 64 
     | 
    
         
            +
                          nil
         
     | 
| 
      
 65 
     | 
    
         
            +
                        end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  @processing = false
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # result.free if result.is_a? Mysql::Result
         
     | 
| 
      
 69 
     | 
    
         
            +
                  next_query
         
     | 
| 
      
 70 
     | 
    
         
            +
                  cblk.call(arg) if cblk
         
     | 
| 
      
 71 
     | 
    
         
            +
                else
         
     | 
| 
      
 72 
     | 
    
         
            +
                  log 'readable, but nothing queued?! probably an ERROR state'
         
     | 
| 
      
 73 
     | 
    
         
            +
                  return close
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              rescue Mysql::Error => e
         
     | 
| 
      
 76 
     | 
    
         
            +
                log 'mysql error', e.message
         
     | 
| 
      
 77 
     | 
    
         
            +
                if e.message =~ /Deadlock/
         
     | 
| 
      
 78 
     | 
    
         
            +
                  @@queue << [response, sql, cblk, eblk]
         
     | 
| 
      
 79 
     | 
    
         
            +
                  @processing = false
         
     | 
| 
      
 80 
     | 
    
         
            +
                  next_query
         
     | 
| 
      
 81 
     | 
    
         
            +
                elsif DisconnectErrors.include? e.message
         
     | 
| 
      
 82 
     | 
    
         
            +
                  @@queue << [response, sql, cblk, eblk]
         
     | 
| 
      
 83 
     | 
    
         
            +
                  return close
         
     | 
| 
      
 84 
     | 
    
         
            +
                elsif cb = (eblk || @opts[:on_error])
         
     | 
| 
      
 85 
     | 
    
         
            +
                  cb.call(e)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @processing = false
         
     | 
| 
      
 87 
     | 
    
         
            +
                  next_query
         
     | 
| 
      
 88 
     | 
    
         
            +
                else
         
     | 
| 
      
 89 
     | 
    
         
            +
                  raise e
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
              # ensure
         
     | 
| 
      
 92 
     | 
    
         
            +
              #   res.free if res.is_a? Mysql::Result
         
     | 
| 
      
 93 
     | 
    
         
            +
              #   @processing = false
         
     | 
| 
      
 94 
     | 
    
         
            +
              #   next_query
         
     | 
| 
      
 95 
     | 
    
         
            +
              end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
              def unbind
         
     | 
| 
      
 98 
     | 
    
         
            +
                log 'mysql disconnect', $!
         
     | 
| 
      
 99 
     | 
    
         
            +
                # cp = EventedMysql.instance_variable_get('@connection_pool') and cp.delete(self)
         
     | 
| 
      
 100 
     | 
    
         
            +
                @connected = false
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                # XXX wait for the next tick until the current fd is removed completely from the reactor
         
     | 
| 
      
 103 
     | 
    
         
            +
                #
         
     | 
| 
      
 104 
     | 
    
         
            +
                # XXX in certain cases the new FD# (@mysql.socket) is the same as the old, since FDs are re-used
         
     | 
| 
      
 105 
     | 
    
         
            +
                # XXX without next_tick in these cases, unbind will get fired on the newly attached signature as well
         
     | 
| 
      
 106 
     | 
    
         
            +
                #
         
     | 
| 
      
 107 
     | 
    
         
            +
                # XXX do _NOT_ use EM.next_tick here. if a bunch of sockets disconnect at the same time, we want
         
     | 
| 
      
 108 
     | 
    
         
            +
                # XXX reconnects to happen after all the unbinds have been processed
         
     | 
| 
      
 109 
     | 
    
         
            +
                EM.add_timer(0) do
         
     | 
| 
      
 110 
     | 
    
         
            +
                  log 'mysql reconnecting'
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @processing = false
         
     | 
| 
      
 112 
     | 
    
         
            +
                  @mysql = EventedMysql._connect @opts
         
     | 
| 
      
 113 
     | 
    
         
            +
                  @fd = @mysql.socket
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  @signature = EM.attach_fd @mysql.socket, true
         
     | 
| 
      
 116 
     | 
    
         
            +
                  EM.set_notify_readable @signature, true
         
     | 
| 
      
 117 
     | 
    
         
            +
                  log 'mysql connected'
         
     | 
| 
      
 118 
     | 
    
         
            +
                  EM.instance_variable_get('@conns')[@signature] = self
         
     | 
| 
      
 119 
     | 
    
         
            +
                  @connected = true
         
     | 
| 
      
 120 
     | 
    
         
            +
                  make_socket_blocking
         
     | 
| 
      
 121 
     | 
    
         
            +
                  next_query
         
     | 
| 
      
 122 
     | 
    
         
            +
                end
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              def execute sql, response = nil, cblk = nil, eblk = nil, &blk
         
     | 
| 
      
 126 
     | 
    
         
            +
                cblk ||= blk
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                begin
         
     | 
| 
      
 129 
     | 
    
         
            +
                  unless @processing or !@connected
         
     | 
| 
      
 130 
     | 
    
         
            +
                    # begin
         
     | 
| 
      
 131 
     | 
    
         
            +
                    #   log 'mysql ping', @mysql.ping
         
     | 
| 
      
 132 
     | 
    
         
            +
                    #   # log 'mysql stat', @mysql.stat
         
     | 
| 
      
 133 
     | 
    
         
            +
                    #   # log 'mysql errno', @mysql.errno
         
     | 
| 
      
 134 
     | 
    
         
            +
                    # rescue
         
     | 
| 
      
 135 
     | 
    
         
            +
                    #   log 'mysql ping failed'
         
     | 
| 
      
 136 
     | 
    
         
            +
                    #   @@queue << [response, sql, blk]
         
     | 
| 
      
 137 
     | 
    
         
            +
                    #   return close
         
     | 
| 
      
 138 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                    @processing = true
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                    log 'mysql sending', sql
         
     | 
| 
      
 143 
     | 
    
         
            +
                    @mysql.send_query(sql)
         
     | 
| 
      
 144 
     | 
    
         
            +
                  else
         
     | 
| 
      
 145 
     | 
    
         
            +
                    @@queue << [response, sql, cblk, eblk]
         
     | 
| 
      
 146 
     | 
    
         
            +
                    return
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
                rescue Mysql::Error => e
         
     | 
| 
      
 149 
     | 
    
         
            +
                  log 'mysql error', e.message
         
     | 
| 
      
 150 
     | 
    
         
            +
                  if DisconnectErrors.include? e.message
         
     | 
| 
      
 151 
     | 
    
         
            +
                    @@queue << [response, sql, cblk, eblk]
         
     | 
| 
      
 152 
     | 
    
         
            +
                    return close
         
     | 
| 
      
 153 
     | 
    
         
            +
                  else
         
     | 
| 
      
 154 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
                end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                log 'queuing', response, sql
         
     | 
| 
      
 159 
     | 
    
         
            +
                @current = [Time.now, response, sql, cblk, eblk]
         
     | 
| 
      
 160 
     | 
    
         
            +
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
              def close
         
     | 
| 
      
 163 
     | 
    
         
            +
                @connected = false
         
     | 
| 
      
 164 
     | 
    
         
            +
                fd = detach
         
     | 
| 
      
 165 
     | 
    
         
            +
                log 'detached fd', fd
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
              private
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
              def next_query
         
     | 
| 
      
 171 
     | 
    
         
            +
                if @connected and !@processing and pending = @@queue.shift
         
     | 
| 
      
 172 
     | 
    
         
            +
                  response, sql, cblk, eblk = pending
         
     | 
| 
      
 173 
     | 
    
         
            +
                  execute(sql, response, cblk, eblk)
         
     | 
| 
      
 174 
     | 
    
         
            +
                end
         
     | 
| 
      
 175 
     | 
    
         
            +
              end
         
     | 
| 
      
 176 
     | 
    
         
            +
              
         
     | 
| 
      
 177 
     | 
    
         
            +
              def log *args
         
     | 
| 
      
 178 
     | 
    
         
            +
                return unless @opts[:logging]
         
     | 
| 
      
 179 
     | 
    
         
            +
                p [Time.now, @fd, (@signature[-4..-1] if @signature), *args]
         
     | 
| 
      
 180 
     | 
    
         
            +
              end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
              public
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
              def self.connect opts
         
     | 
| 
      
 185 
     | 
    
         
            +
                unless EM.respond_to?(:watch) and Mysql.method_defined?(:socket)
         
     | 
| 
      
 186 
     | 
    
         
            +
                  raise RuntimeError, 'mysqlplus and EM.watch are required for EventedMysql'
         
     | 
| 
      
 187 
     | 
    
         
            +
                end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                if conn = _connect(opts)
         
     | 
| 
      
 190 
     | 
    
         
            +
                  EM.watch conn.socket, self, conn, opts
         
     | 
| 
      
 191 
     | 
    
         
            +
                else
         
     | 
| 
      
 192 
     | 
    
         
            +
                  EM.add_timer(5){ connect opts }
         
     | 
| 
      
 193 
     | 
    
         
            +
                end
         
     | 
| 
      
 194 
     | 
    
         
            +
              end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
              self::Mysql = ::Mysql unless defined? self::Mysql
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
              # stolen from sequel
         
     | 
| 
      
 199 
     | 
    
         
            +
              def self._connect opts
         
     | 
| 
      
 200 
     | 
    
         
            +
                opts = settings.merge(opts)
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                conn = Mysql.init
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                # set encoding _before_ connecting
         
     | 
| 
      
 205 
     | 
    
         
            +
                if charset = opts[:charset] || opts[:encoding]
         
     | 
| 
      
 206 
     | 
    
         
            +
                  conn.options(Mysql::SET_CHARSET_NAME, charset)
         
     | 
| 
      
 207 
     | 
    
         
            +
                end
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                conn.options(Mysql::OPT_LOCAL_INFILE, 'client')
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                conn.real_connect(
         
     | 
| 
      
 212 
     | 
    
         
            +
                  opts[:host] || 'localhost',
         
     | 
| 
      
 213 
     | 
    
         
            +
                  opts[:user] || opts[:username] || 'root',
         
     | 
| 
      
 214 
     | 
    
         
            +
                  opts[:password],
         
     | 
| 
      
 215 
     | 
    
         
            +
                  opts[:database],
         
     | 
| 
      
 216 
     | 
    
         
            +
                  opts[:port],
         
     | 
| 
      
 217 
     | 
    
         
            +
                  opts[:socket],
         
     | 
| 
      
 218 
     | 
    
         
            +
                  0 +
         
     | 
| 
      
 219 
     | 
    
         
            +
                  # XXX multi results require multiple callbacks to parse
         
     | 
| 
      
 220 
     | 
    
         
            +
                  # Mysql::CLIENT_MULTI_RESULTS +
         
     | 
| 
      
 221 
     | 
    
         
            +
                  # Mysql::CLIENT_MULTI_STATEMENTS +
         
     | 
| 
      
 222 
     | 
    
         
            +
                  (opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
         
     | 
| 
      
 223 
     | 
    
         
            +
                )
         
     | 
| 
      
 224 
     | 
    
         
            +
                
         
     | 
| 
      
 225 
     | 
    
         
            +
                # increase timeout so mysql server doesn't disconnect us
         
     | 
| 
      
 226 
     | 
    
         
            +
                # this is especially bad if we're disconnected while EM.attach is
         
     | 
| 
      
 227 
     | 
    
         
            +
                # still in progress, because by the time it gets to EM, the FD is
         
     | 
| 
      
 228 
     | 
    
         
            +
                # no longer valid, and it throws a c++ 'bad file descriptor' error
         
     | 
| 
      
 229 
     | 
    
         
            +
                # (do not use a timeout of -1 for unlimited, it does not work on mysqld > 5.0.60)
         
     | 
| 
      
 230 
     | 
    
         
            +
                conn.query("set @@wait_timeout = #{opts[:timeout] || 2592000}")
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                # we handle reconnecting (and reattaching the new fd to EM)
         
     | 
| 
      
 233 
     | 
    
         
            +
                conn.reconnect = false
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                # By default, MySQL 'where id is null' selects the last inserted id
         
     | 
| 
      
 236 
     | 
    
         
            +
                # Turn this off. http://dev.rubyonrails.org/ticket/6778
         
     | 
| 
      
 237 
     | 
    
         
            +
                conn.query("set SQL_AUTO_IS_NULL=0")
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                # get results for queries
         
     | 
| 
      
 240 
     | 
    
         
            +
                conn.query_with_result = true
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
                conn
         
     | 
| 
      
 243 
     | 
    
         
            +
              rescue Mysql::Error => e
         
     | 
| 
      
 244 
     | 
    
         
            +
                if cb = opts[:on_error]
         
     | 
| 
      
 245 
     | 
    
         
            +
                  cb.call(e)
         
     | 
| 
      
 246 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 247 
     | 
    
         
            +
                else
         
     | 
| 
      
 248 
     | 
    
         
            +
                  raise e
         
     | 
| 
      
 249 
     | 
    
         
            +
                end
         
     | 
| 
      
 250 
     | 
    
         
            +
              end
         
     | 
| 
      
 251 
     | 
    
         
            +
            end
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
            class EventedMysql
         
     | 
| 
      
 254 
     | 
    
         
            +
              def self.settings
         
     | 
| 
      
 255 
     | 
    
         
            +
                @settings ||= { :connections => 4, :logging => false }
         
     | 
| 
      
 256 
     | 
    
         
            +
              end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
              def self.execute query, type = nil, cblk = nil, eblk = nil, &blk
         
     | 
| 
      
 259 
     | 
    
         
            +
                unless nil#connection = connection_pool.find{|c| not c.processing and c.connected }
         
     | 
| 
      
 260 
     | 
    
         
            +
                  @n ||= 0
         
     | 
| 
      
 261 
     | 
    
         
            +
                  connection = connection_pool[@n]
         
     | 
| 
      
 262 
     | 
    
         
            +
                  @n = 0 if (@n+=1) >= connection_pool.size
         
     | 
| 
      
 263 
     | 
    
         
            +
                end
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                connection.execute(query, type, cblk, eblk, &blk)
         
     | 
| 
      
 266 
     | 
    
         
            +
              end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
              %w[ select insert update delete raw ].each do |type| class_eval %[
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
                def self.#{type} query, cblk = nil, eblk = nil, &blk
         
     | 
| 
      
 271 
     | 
    
         
            +
                  execute query, :#{type}, cblk, eblk, &blk
         
     | 
| 
      
 272 
     | 
    
         
            +
                end
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
              ] end
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
              def self.all query, type = nil, &blk
         
     | 
| 
      
 277 
     | 
    
         
            +
                responses = 0
         
     | 
| 
      
 278 
     | 
    
         
            +
                connection_pool.each do |c|
         
     | 
| 
      
 279 
     | 
    
         
            +
                  c.execute(query, type) do
         
     | 
| 
      
 280 
     | 
    
         
            +
                    responses += 1
         
     | 
| 
      
 281 
     | 
    
         
            +
                    blk.call if blk and responses == @connection_pool.size
         
     | 
| 
      
 282 
     | 
    
         
            +
                  end
         
     | 
| 
      
 283 
     | 
    
         
            +
                end
         
     | 
| 
      
 284 
     | 
    
         
            +
              end
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
              def self.connection_pool
         
     | 
| 
      
 287 
     | 
    
         
            +
                @connection_pool ||= (1..settings[:connections]).map{ EventedMysql.connect(settings) }
         
     | 
| 
      
 288 
     | 
    
         
            +
                # p ['connpool', settings[:connections], @connection_pool.size]
         
     | 
| 
      
 289 
     | 
    
         
            +
                # (1..(settings[:connections]-@connection_pool.size)).each do
         
     | 
| 
      
 290 
     | 
    
         
            +
                #   @connection_pool << EventedMysql.connect(settings)
         
     | 
| 
      
 291 
     | 
    
         
            +
                # end unless settings[:connections] == @connection_pool.size
         
     | 
| 
      
 292 
     | 
    
         
            +
                # @connection_pool
         
     | 
| 
      
 293 
     | 
    
         
            +
              end
         
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
      
 295 
     | 
    
         
            +
              def self.reset_connection_pool!
         
     | 
| 
      
 296 
     | 
    
         
            +
                @connection_pool = nil
         
     | 
| 
      
 297 
     | 
    
         
            +
              end
         
     | 
| 
      
 298 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Finders
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                delegate :all, :first, :each, :where, :select, :group, :order, :limit, :offset, :to => :relation
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def [](attribute)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  arel_table[attribute]
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def arel_table
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @arel_table ||= Arel::Table.new(table_name)
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def relation
         
     | 
| 
      
 15 
     | 
    
         
            +
                  Relation.new(self, arel_table)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                private
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def table_name
         
     | 
| 
      
 21 
     | 
    
         
            +
                  self.to_s.demodulize.underscore.pluralize
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,102 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Yanked from Rails
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright (c) 2004-2009 David Heinemeier Hansson
         
     | 
| 
      
 4 
     | 
    
         
            +
            # 
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            # a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            # "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            # without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            # distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            # permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            # the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
            # 
         
     | 
| 
      
 13 
     | 
    
         
            +
            # The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            # included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
            # 
         
     | 
| 
      
 16 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 25 
     | 
    
         
            +
              module Quoting
         
     | 
| 
      
 26 
     | 
    
         
            +
                def quote_column_name(name)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @quoted_column_names[name] ||= "`#{name}`"
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def quote_table_name(name)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def quote(value, column = nil)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    s = value.unpack("H*")[0]
         
     | 
| 
      
 37 
     | 
    
         
            +
                    "x'#{s}'"
         
     | 
| 
      
 38 
     | 
    
         
            +
                  elsif value.kind_of?(BigDecimal)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    value.to_s("F")
         
     | 
| 
      
 40 
     | 
    
         
            +
                  else
         
     | 
| 
      
 41 
     | 
    
         
            +
                    super
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def quote(value, column = nil)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # records are quoted as their primary key
         
     | 
| 
      
 47 
     | 
    
         
            +
                  return value.quoted_id if value.respond_to?(:quoted_id)
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  case value
         
     | 
| 
      
 50 
     | 
    
         
            +
                    when String, ActiveSupport::Multibyte::Chars
         
     | 
| 
      
 51 
     | 
    
         
            +
                      value = value.to_s
         
     | 
| 
      
 52 
     | 
    
         
            +
                      if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      elsif column && [:integer, :float].include?(column.type)
         
     | 
| 
      
 55 
     | 
    
         
            +
                        value = column.type == :integer ? value.to_i : value.to_f
         
     | 
| 
      
 56 
     | 
    
         
            +
                        value.to_s
         
     | 
| 
      
 57 
     | 
    
         
            +
                      else
         
     | 
| 
      
 58 
     | 
    
         
            +
                        "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    when NilClass                 then "NULL"
         
     | 
| 
      
 61 
     | 
    
         
            +
                    when TrueClass                then (column && column.type == :integer ? '1' : quoted_true)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    when FalseClass               then (column && column.type == :integer ? '0' : quoted_false)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    when Float, Fixnum, Bignum    then value.to_s
         
     | 
| 
      
 64 
     | 
    
         
            +
                    # BigDecimals need to be output in a non-normalized form and quoted.
         
     | 
| 
      
 65 
     | 
    
         
            +
                    when BigDecimal               then value.to_s('F')
         
     | 
| 
      
 66 
     | 
    
         
            +
                    else
         
     | 
| 
      
 67 
     | 
    
         
            +
                      if value.acts_like?(:date) || value.acts_like?(:time)
         
     | 
| 
      
 68 
     | 
    
         
            +
                        "'#{quoted_date(value)}'"
         
     | 
| 
      
 69 
     | 
    
         
            +
                      else
         
     | 
| 
      
 70 
     | 
    
         
            +
                        "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
         
     | 
| 
      
 71 
     | 
    
         
            +
                      end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                # Quotes a string, escaping any ' (single quote) and \ (backslash)
         
     | 
| 
      
 76 
     | 
    
         
            +
                # characters.
         
     | 
| 
      
 77 
     | 
    
         
            +
                def quote_string(s)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  s.gsub(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def quoted_true
         
     | 
| 
      
 82 
     | 
    
         
            +
                  "'t'"
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def quoted_false
         
     | 
| 
      
 86 
     | 
    
         
            +
                  "'f'"
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def quoted_date(value)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  if value.acts_like?(:time)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
         
     | 
| 
      
 92 
     | 
    
         
            +
                    value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
         
     | 
| 
      
 93 
     | 
    
         
            +
                  else
         
     | 
| 
      
 94 
     | 
    
         
            +
                    value
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end.to_s(:db)
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                def quoted_string_prefix
         
     | 
| 
      
 99 
     | 
    
         
            +
                  ''
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
              end
         
     | 
| 
      
 102 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,60 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tramp
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Relation
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                def initialize(klass, relation)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @klass, @relation = klass, relation
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def each(callback = nil, &block)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  @relation.each do |row|
         
     | 
| 
      
 12 
     | 
    
         
            +
                    object = @klass.instantiate(row)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    callback.call(object)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def all(callback = nil, &block)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  @relation.all do |rows|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    objects = rows.map {|r| @klass.instantiate(r) }
         
     | 
| 
      
 22 
     | 
    
         
            +
                    callback.call(objects)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def first(callback = nil, &block)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  callback ||= block
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  @relation.first do |row|
         
     | 
| 
      
 30 
     | 
    
         
            +
                    object = row ? @klass.instantiate(row) : nil
         
     | 
| 
      
 31 
     | 
    
         
            +
                    callback.call(object)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def where(*conditions)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  Relation.new(@klass, @relation.where(*conditions))
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def select(*selects)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  Relation.new(@klass, @relation.project(*selects))
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def group(groups)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  Relation.new(@klass, @relation.group(groups))
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def order(orders)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  Relation.new(@klass, @relation.order(orders))
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def limit(limits)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  Relation.new(@klass, @relation.take(limits))
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def offset(offsets)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  Relation.new(@klass, @relation.skip(offsets))
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tramp/status.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,133 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: tramp
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 5 
     | 
    
         
            +
              segments: 
         
     | 
| 
      
 6 
     | 
    
         
            +
              - 0
         
     | 
| 
      
 7 
     | 
    
         
            +
              - 1
         
     | 
| 
      
 8 
     | 
    
         
            +
              version: "0.1"
         
     | 
| 
      
 9 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 10 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Pratik Naik
         
     | 
| 
      
 12 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 13 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 14 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            date: 2010-07-17 00:00:00 +01:00
         
     | 
| 
      
 17 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 18 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 19 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 20 
     | 
    
         
            +
              name: activesupport
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 26 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 27 
     | 
    
         
            +
                    - 3
         
     | 
| 
      
 28 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 29 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 30 
     | 
    
         
            +
                    - beta4
         
     | 
| 
      
 31 
     | 
    
         
            +
                    version: 3.0.0.beta4
         
     | 
| 
      
 32 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 33 
     | 
    
         
            +
              version_requirements: *id001
         
     | 
| 
      
 34 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 35 
     | 
    
         
            +
              name: activemodel
         
     | 
| 
      
 36 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 37 
     | 
    
         
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 38 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 39 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 40 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 41 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 42 
     | 
    
         
            +
                    - 3
         
     | 
| 
      
 43 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 44 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 45 
     | 
    
         
            +
                    - beta4
         
     | 
| 
      
 46 
     | 
    
         
            +
                    version: 3.0.0.beta4
         
     | 
| 
      
 47 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 48 
     | 
    
         
            +
              version_requirements: *id002
         
     | 
| 
      
 49 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 50 
     | 
    
         
            +
              name: arel
         
     | 
| 
      
 51 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 52 
     | 
    
         
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 53 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 54 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 55 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 56 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 57 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 58 
     | 
    
         
            +
                    - 4
         
     | 
| 
      
 59 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 60 
     | 
    
         
            +
                    version: 0.4.0
         
     | 
| 
      
 61 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 62 
     | 
    
         
            +
              version_requirements: *id003
         
     | 
| 
      
 63 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 64 
     | 
    
         
            +
              name: mysqlplus
         
     | 
| 
      
 65 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 66 
     | 
    
         
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 67 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 68 
     | 
    
         
            +
                - - ~>
         
     | 
| 
      
 69 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 70 
     | 
    
         
            +
                    segments: 
         
     | 
| 
      
 71 
     | 
    
         
            +
                    - 0
         
     | 
| 
      
 72 
     | 
    
         
            +
                    - 1
         
     | 
| 
      
 73 
     | 
    
         
            +
                    - 1
         
     | 
| 
      
 74 
     | 
    
         
            +
                    version: 0.1.1
         
     | 
| 
      
 75 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 76 
     | 
    
         
            +
              version_requirements: *id004
         
     | 
| 
      
 77 
     | 
    
         
            +
            description: "    Tramp provides asynchronous ORM layer.\n"
         
     | 
| 
      
 78 
     | 
    
         
            +
            email: pratiknaik@gmail.com
         
     | 
| 
      
 79 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 86 
     | 
    
         
            +
            - MIT-LICENSE
         
     | 
| 
      
 87 
     | 
    
         
            +
            - lib/tramp/arel_monkey_patches.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/tramp/attribute.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - lib/tramp/attribute_methods.rb
         
     | 
| 
      
 90 
     | 
    
         
            +
            - lib/tramp/base.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - lib/tramp/callbacks.rb
         
     | 
| 
      
 92 
     | 
    
         
            +
            - lib/tramp/column.rb
         
     | 
| 
      
 93 
     | 
    
         
            +
            - lib/tramp/emysql_ext.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - lib/tramp/engine/connection.rb
         
     | 
| 
      
 95 
     | 
    
         
            +
            - lib/tramp/engine.rb
         
     | 
| 
      
 96 
     | 
    
         
            +
            - lib/tramp/evented_mysql.rb
         
     | 
| 
      
 97 
     | 
    
         
            +
            - lib/tramp/finders.rb
         
     | 
| 
      
 98 
     | 
    
         
            +
            - lib/tramp/quoting.rb
         
     | 
| 
      
 99 
     | 
    
         
            +
            - lib/tramp/relation.rb
         
     | 
| 
      
 100 
     | 
    
         
            +
            - lib/tramp/status.rb
         
     | 
| 
      
 101 
     | 
    
         
            +
            - lib/tramp.rb
         
     | 
| 
      
 102 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 103 
     | 
    
         
            +
            homepage: http://m.onkey.org
         
     | 
| 
      
 104 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 107 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 110 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 111 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 112 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 113 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 114 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 115 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 116 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 117 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 118 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 119 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 120 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 121 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 122 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 123 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 124 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 125 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 128 
     | 
    
         
            +
            rubygems_version: 1.3.6
         
     | 
| 
      
 129 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 130 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 131 
     | 
    
         
            +
            summary: Async ORM layer.
         
     | 
| 
      
 132 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     |