lib/og/backends/mysql.rb in og-0.8.0 vs lib/og/backends/mysql.rb in og-0.9.3

- old
+ new

@@ -1,41 +1,37 @@ -# code: # * George Moschovitis <gm@navel.gr> # * Elias Athanasopoulos <elathan@navel.gr> -# -# (c) 2004 Navel, all rights reserved. -# $Id: mysql.rb 194 2004-12-20 20:23:57Z gmosx $ +# (c) 2004-2005 Navel, all rights reserved. +# $Id: mysql.rb 248 2005-01-31 13:38:34Z gmosx $ -require "mysql" +require 'mysql' -require "og/backend" +require 'og/backend' class Og -# = MysqlBackend -# # Implements a MySQL powered backend. -# + class MysqlBackend < Og::Backend # A mapping between Ruby and SQL types. - # + TYPEMAP = { - Integer => "integer", - Fixnum => "integer", - Float => "float", - String => "text", - Time => "timestamp", - Date => "date", - TrueClass => "boolean", - Object => "text", - Array => "text", - Hash => "text" + Integer => 'integer', + Fixnum => 'integer', + Float => 'float', + String => 'text', + Time => 'timestamp', + Date => 'date', + TrueClass => 'tinyint', + Object => 'text', + Array => 'text', + Hash => 'text' } # Intitialize the connection to the RDBMS. - # + def initialize(config) begin @conn = Mysql.connect(config[:address], config[:user], config[:password], config[:database]) rescue => ex @@ -51,42 +47,42 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Utilities # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Escape an SQL string - # + def self.escape(str) return nil unless str return Mysql.quote(str) end # Convert a ruby time to an sql timestamp. # TODO: Optimize this - # + def self.timestamp(time = Time.now) return nil unless time return time.strftime("%Y%m%d%H%M%S") end # Output YYY-mm-dd # TODO: Optimize this - # + def self.date(date) return nil unless date return "#{date.year}-#{date.month}-#{date.mday}" end # Parse sql datetime # TODO: Optimize this - # + def self.parse_timestamp(str) return Time.parse(str) end # Input YYYY-mm-dd # TODO: Optimize this - # + def self.parse_date(str) return nil unless str return Date.strptime(str) end @@ -94,11 +90,11 @@ # No need to optimize this, used only to precalculate code. # YAML is used to store general Ruby objects to be more # portable. # # FIXME: add extra handling for float. - # + def self.write_prop(p) if p.klass.ancestors.include?(Integer) return "#\{@#{p.symbol} || 'NULL'\}" elsif p.klass.ancestors.include?(Float) return "#\{@#{p.symbol} || 'NULL'\}" @@ -107,19 +103,19 @@ elsif p.klass.ancestors.include?(Time) return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.timestamp(@#{p.symbol})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(Date) return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.date(@#{p.symbol})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(TrueClass) - return "#\{@#{p.symbol} || 'NULL'\}" + return "#\{@#{p.symbol} ? 1 : 0 \}" else return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}| end end # Return an evaluator for reading the property. # No need to optimize this, used only to precalculate code. - # + def self.read_prop(p, idx) if p.klass.ancestors.include?(Integer) return "res[#{idx}].to_i()" elsif p.klass.ancestors.include?(Float) return "res[#{idx}].to_f()" @@ -128,27 +124,27 @@ elsif p.klass.ancestors.include?(Time) return "Og::MysqlBackend.parse_timestamp(res[#{idx}])" elsif p.klass.ancestors.include?(Date) return "Og::MysqlBackend.parse_date(res[#{idx}])" elsif p.klass.ancestors.include?(TrueClass) - return "('true' == res[#{idx}])" + return "('0' != res[#{idx}])" else return "YAML::load(res[#{idx}])" end end # Returns the props that will be included in the insert query. # The oid property is rejected because it is mapped to an # AUTO_INCREMENT column. - # + def self.props_for_insert(klass) klass.__props.reject { |p| :oid == p.symbol } end - # Returns the code that actually inserts the object into the + # Returns the code that actually inserts the object into the # database. Returns the code as String. - # + def self.insert_code(klass, sql, pre_cb, post_cb) %{ #{pre_cb} conn.exec "#{sql}" @oid = conn.db.conn.insert_id() @@ -156,22 +152,22 @@ } end # generate the mapping of the database fields to the # object properties. - # + def self.calc_field_index(klass, og) res = og.query "SELECT * FROM #{klass::DBTABLE} LIMIT 1" meta = og.managed_classes[klass] for idx in (0...res.num_fields) meta.field_index[res.fetch_field.name] = idx end end - # Generate the property for oid - # + # Generate the property for oid. + def self.eval_og_oid(klass) klass.class_eval %{ prop_accessor :oid, Fixnum, :sql => "integer AUTO_INCREMENT PRIMARY KEY" } end @@ -179,40 +175,40 @@ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Connection methods. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Create the database. - # + def self.create_db(database, user = nil, password = nil) Logger.info "Creating database '#{database}'." `mysqladmin -f --user=#{user} --password=#{password} create #{database}` end # Drop the database. - # + def self.drop_db(database, user = nil, password = nil) Logger.info "Dropping database '#{database}'." `mysqladmin -f --user=#{user} --password=#{password} drop #{database}` end # Execute an SQL query and return the result - # + def query(sql) Logger.debug sql if $DBG return @conn.query(sql) end # Execute an SQL query, no result returned. - # + def exec(sql) Logger.debug sql if $DBG @conn.query(sql) end # Execute an SQL query and return the result. Wrapped in a rescue # block. - # + def safe_query(sql) Logger.debug sql if $DBG begin return @conn.query(sql) rescue => ex @@ -222,11 +218,11 @@ end end # Execute an SQL query, no result returned. Wrapped in a rescue # block. - # + def safe_exec(sql) Logger.debug sql if $DBG begin @conn.query(sql) rescue => ex @@ -234,37 +230,37 @@ Logger.error ex.backtrace end end # Check if it is a valid resultset. - # + def valid?(res) return !(res.nil? or 0 == res.num_rows) end # Start a new transaction. - # + def start # no transaction support end # Commit a transaction. - # + def commit # no transaction support end # Rollback transaction. - # + def rollback # no transaction support end # Create the managed object table. The properties of the # object are mapped to the table columns. Additional sql relations # and constrains are created (indicices, sequences, etc). - # + def create_table(klass) fields = create_fields(klass, TYPEMAP) sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}" @@ -326,11 +322,11 @@ end end end # Deserialize one row of the resultset. - # + def deserialize_one(res, klass) return nil unless valid?(res) # gmosx: Managed objects should have no params constructor. row = res.fetch_row() @@ -341,13 +337,13 @@ return entity end # Deserialize all rows of the resultset. - # + def deserialize_all(res, klass) - return nil unless valid?(res) + return [] unless valid?(res) entities = [] for tuple in (0...res.num_rows) row = res.fetch_row() @@ -362,13 +358,13 @@ return entities end # Return a single integer value from the resultset. - # + def get_int(res, idx = 0) return res.fetch_row[idx].to_i end end -end # module +end