lib/og/backends/psql.rb in nitro-0.7.0 vs lib/og/backends/psql.rb in nitro-0.8.0

- old
+ new

@@ -2,22 +2,60 @@ # * George Moschovitis <gm@navel.gr> # # (c) 2004 Navel, all rights reserved. # $Id: psql.rb 194 2004-12-20 20:23:57Z gmosx $ -require "postgres" +require 'postgres' -require "og/backend" +require 'og/backend' -module Og +class Og -# = Utils +# = PsqlBackend # -# A collection of useful utilities. +# Implements a PostgreSQL powered backend. +# This backend is compatible with Michael Neumann's postgres-pr +# pure ruby driver. # -module Utils +class PsqlBackend < 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' + } + + # Intitialize the connection to the RDBMS. + # + def initialize(config) + begin + @conn = PGconn.connect(nil, nil, nil, nil, config[:database], + config[:user], config[:password]) + rescue => ex + # gmosx: any idea how to better test this? + if ex.to_s =~ /database .* does not exist/i + Logger.info "Database '#{config[:database]}' not found!" + PsqlBackend.create_db(config[:database], config[:user]) + retry + end + raise + end + end + + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + # Utilities + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + # Escape an SQL string # def self.escape(str) return nil unless str return PGconn.escape(str) @@ -65,19 +103,19 @@ if p.klass.ancestors.include?(Integer) return "#\{@#{p.symbol} || 'NULL'\}" elsif p.klass.ancestors.include?(Float) return "#\{@#{p.symbol} || 'NULL'\}" elsif p.klass.ancestors.include?(String) - return "'#\{Og::Utils.escape(@#{p.symbol})\}'" + return "'#\{Og::PsqlBackend.escape(@#{p.symbol})\}'" elsif p.klass.ancestors.include?(Time) - return %|#\{@#{p.symbol} ? "'#\{Og::Utils.timestamp(@#{p.symbol})\}'" : 'NULL'\}| + return %|#\{@#{p.symbol} ? "'#\{Og::PsqlBackend.timestamp(@#{p.symbol})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(Date) - return %|#\{@#{p.symbol} ? "'#\{Og::Utils.date(@#{p.symbol})\}'" : 'NULL'\}| + return %|#\{@#{p.symbol} ? "'#\{Og::PsqlBackend.date(@#{p.symbol})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(TrueClass) return "#\{@#{p.symbol} || 'NULL'\}" else - return %|#\{@#{p.symbol} ? "'#\{Og::Utils.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}| + return %|#\{@#{p.symbol} ? "'#\{Og::PsqlBackend.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}| end end # Return an evaluator for reading the property. # No need to optimize this, used only to precalculate code. @@ -88,13 +126,13 @@ elsif p.klass.ancestors.include?(Float) return "res.getvalue(tuple, #{idx}).to_f()" elsif p.klass.ancestors.include?(String) return "res.getvalue(tuple, #{idx})" elsif p.klass.ancestors.include?(Time) - return "Og::Utils.parse_timestamp(res.getvalue(tuple, #{idx}))" + return "Og::PsqlBackend.parse_timestamp(res.getvalue(tuple, #{idx}))" elsif p.klass.ancestors.include?(Date) - return "Og::Utils.parse_date(res.getvalue(tuple, #{idx}))" + return "Og::PsqlBackend.parse_date(res.getvalue(tuple, #{idx}))" elsif p.klass.ancestors.include?(TrueClass) return "('true' == res.getvalue(tuple, #{idx}))" else return "YAML::load(res.getvalue(tuple, #{idx}))" end @@ -130,106 +168,69 @@ def self.eval_og_oid(klass) klass.class_eval %{ prop_accessor :oid, Fixnum, :sql => "integer PRIMARY KEY" } end -end -# = PsqlBackend -# -# Implements a PostgreSQL powered backend. -# This backend is compatible with Michael Neumann's postgres-pr -# pure ruby driver. -# -class PsqlBackend < Og::Backend + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + # Connection methods. + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # 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" - } - - # Intitialize the connection to the RDBMS. - # - def initialize(config) - begin - @conn = PGconn.connect(nil, nil, nil, nil, config[:database], - config[:user], config[:password]) - rescue => ex - # gmosx: any idea how to better test this? - if ex.to_s =~ /database .* does not exist/i - $log.info "Database '#{config[:database]}' not found!" - PsqlBackend.create_db(config[:database], config[:user]) - retry - end - raise - end - end - # Create the database. # def self.create_db(database, user = nil, password = nil) - $log.info "Creating database '#{database}'." + Logger.info "Creating database '#{database}'." `createdb #{database} -U #{user}` end # Drop the database. # def self.drop_db(database, user = nil, password = nil) - $log.info "Dropping database '#{database}'." + Logger.info "Dropping database '#{database}'." `dropdb #{database} -U #{user}` end # Execute an SQL query and return the result # def query(sql) - $log.debug sql if $DBG + Logger.debug sql if $DBG return @conn.exec(sql) end # Execute an SQL query, no result returned. # def exec(sql) - $log.debug sql if $DBG + Logger.debug sql if $DBG res = @conn.exec(sql) res.clear() end # Execute an SQL query and return the result. Wrapped in a rescue # block. # def safe_query(sql) - $log.debug sql if $DBG + Logger.debug sql if $DBG begin return @conn.exec(sql) rescue => ex - $log.error "DB error #{ex}, [#{sql}]" - $log.error ex.backtrace + Logger.error "DB error #{ex}, [#{sql}]" + Logger.error ex.backtrace return nil end end # Execute an SQL query, no result returned. Wrapped in a rescue # block. # def safe_exec(sql) - $log.debug sql if $DBG + Logger.debug sql if $DBG begin res = @conn.exec(sql) res.clear() rescue => ex - $log.error "DB error #{ex}, [#{sql}]" - $log.error ex.backtrace + Logger.error "DB error #{ex}, [#{sql}]" + Logger.error ex.backtrace end end # Check if it is a valid resultset. # @@ -266,30 +267,30 @@ end end begin exec(sql) - $log.info "Created table '#{klass::DBTABLE}'." + Logger.info "Created table '#{klass::DBTABLE}'." rescue => ex # gmosx: any idea how to better test this? if ex.to_s =~ /relation .* already exists/i - $log.debug "Table already exists" if $DBG + Logger.debug "Table already exists" if $DBG else raise end end # create the sequence for this table. Even if the table # uses the oids_seq, attempt to create it. This makes # the system more fault tolerant. begin exec "CREATE SEQUENCE #{klass::DBSEQ}" - $log.info "Created sequence '#{klass::DBSEQ}'." + Logger.info "Created sequence '#{klass::DBSEQ}'." rescue => ex # gmosx: any idea how to better test this? if ex.to_s =~ /relation .* already exists/i - $log.debug "Sequence already exists" if $DBG + Logger.debug "Sequence already exists" if $DBG else raise end end @@ -301,34 +302,34 @@ # the class to join to and some options. join_class, options = *data # gmosx: dont use DBTABLE here, perhaps the join class # is not managed yet. - join_table = "#{Og::Utils.join_table(klass, join_class)}" - join_src = "#{Og::Utils.encode(klass)}_oid" - join_dst = "#{Og::Utils.encode(join_class)}_oid" + join_table = "#{self.class.join_table(klass, join_class)}" + join_src = "#{self.class.encode(klass)}_oid" + join_dst = "#{self.class.encode(join_class)}_oid" begin exec "CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )" exec "CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)" exec "CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)" rescue => ex # gmosx: any idea how to better test this? if ex.to_s =~ /relation .* already exists/i - $log.debug "Join table already exists" if $DBG + Logger.debug "Join table already exists" if $DBG else raise end end end end begin exec(sql) - $log.info "Created join table '#{join_table}'." + Logger.info "Created join table '#{join_table}'." rescue => ex # gmosx: any idea how to better test this? if ex.to_s =~ /relation .* already exists/i - $log.debug "Join table already exists" if $DBG + Logger.debug "Join table already exists" if $DBG else raise end end