lib/og/store/mysql.rb in og-0.23.0 vs lib/og/store/mysql.rb in og-0.24.0

- old
+ new

@@ -1,10 +1,10 @@ begin require 'mysql' rescue Object => ex Logger.error 'Ruby-Mysql bindings are not installed!' - Logger.error 'Trying to uses the pure-Ruby binding included in Og' + Logger.error 'Trying to use the pure-Ruby binding included in Og' begin # Attempt to use the included pure ruby version. require 'vendor/mysql' require 'vendor/mysql411' rescue Object => ex @@ -85,12 +85,23 @@ end end end # A Store that persists objects into a MySQL database. -# To read documentation about the methods, consult the documentation -# for SqlStore and Store. +# To read documentation about the methods, consult +# the documentation for SqlStore and Store. +# +# Here is some useful code to initialize your MySQL +# RDBMS for development. You probably want to be +# more careful with provileges on your production +# environment. +# +# mysql> GRANT ALL PRIVELEGES +# ON keystone.* +# TO <$sys_dbuser name>@localhost +# IDENTIFIED BY '(password)' +# WITH GRANT OPTION; class MysqlStore < SqlStore extend MysqlUtils include MysqlUtils @@ -107,22 +118,34 @@ "--password=#{options[:password]}", 'drop', options[:name] super end + # Initialize the MySQL store. + # + # === Options + # + # * :address, the addres where the server is listening. + # * :socket, is useful when the pure ruby driver is used. + # this is the location of mysql.sock. For Ubuntu/Debian + # this is '/var/run/mysqld/mysqld.sock'. You can find + # the location for your system in my.cnf + def initialize(options) super @typemap.update(TrueClass => 'tinyint') @conn = Mysql.connect( options[:address] || 'localhost', options[:user], options[:password], - options[:name] + options[:name], + options[:port], + options[:socket] ) - + # You should set recconect to true to avoid MySQL has # gone away errors. if @conn.respond_to? :reconnect options[:reconnect] = true unless options.has_key?(:reconnect) @@ -141,13 +164,13 @@ def close @conn.close super end - def enchant(klass, manager) - if klass.metadata.primary_key.flatten.first == :oid - unless klass.properties.find { |p| p.symbol == :oid } + def enchant(klass, manager) + if klass.ann.this.primary_key.symbol == :oid + unless klass.properties.include? :oid klass.property :oid, Fixnum, :sql => 'integer AUTO_INCREMENT PRIMARY KEY' end end super end @@ -193,29 +216,38 @@ end private def create_table(klass) + # rp: fixes problems when user doesn't have + # write access to db. + # THINK, should a method more like this be + # used instead of catching database exceptions + # for 'table exists'? + + return if @conn.list_tables.include?(klass::OGTABLE) + + fields = fields_for_class(klass) sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}" - # Create table constrains. + # Create table constraints. - if klass.metadata and constrains = klass.metadata.sql_constrain - sql << ", #{constrains.join(', ')}" + if constraints = klass.ann.this[:sql_constraint] + sql << ", #{constraints.join(', ')}" end if table_type = @options[:table_type] sql << ") TYPE = #{table_type};" else sql << ");" end # Create indices. - if klass.__meta and indices = klass.__meta[:index] + if indices = klass.ann.this[:index] for data in indices idx, options = *data idx = idx.to_s pre_sql, post_sql = options[:pre], options[:post] idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "") @@ -238,20 +270,20 @@ end # Create join tables if needed. Join tables are used in # 'many_to_many' relations. - if klass.__meta and join_tables = klass.__meta[:join_tables] + if join_tables = klass.ann.this[:join_tables] for info in join_tables begin create_join_table_sql(info).each do |sql| @conn.query sql end Logger.debug "Created jointable '#{info[:table]}'." rescue => ex - if ex.respond_to?(:errno) and ex.errno == 1050 # table already exists. - Logger.debug 'Join table already exists' if $DBG + if ex.respond_to?(:errno) and ex.errno == 1050 # table already exists. + Logger.debug 'Join table already exists' if $DBG else raise end end end @@ -272,24 +304,24 @@ res.close if res end def write_prop(p) if p.klass.ancestors.include?(Integer) - return "#\{@#{p.symbol} || 'NULL'\}" + return "#\{@#{p} || 'NULL'\}" elsif p.klass.ancestors.include?(Float) - return "#\{@#{p.symbol} || 'NULL'\}" + return "#\{@#{p} || 'NULL'\}" elsif p.klass.ancestors.include?(String) - return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}| + return %|#\{@#{p} ? "'#\{#{self.class}.escape(@#{p})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(Time) - return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}| + return %|#\{@#{p} ? "'#\{#{self.class}.timestamp(@#{p})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(Date) - return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}| + return %|#\{@#{p} ? "'#\{#{self.class}.date(@#{p})\}'" : 'NULL'\}| elsif p.klass.ancestors.include?(TrueClass) - return "#\{@#{p.symbol} ? \"'1'\" : 'NULL' \}" + return "#\{@#{p} ? \"'1'\" : 'NULL' \}" else # gmosx: keep the '' for nil symbols. - return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}| + return %|#\{@#{p} ? "'#\{#{self.class}.escape(@#{p}.to_yaml)\}'" : "''"\}| end end def read_prop(p, col) if p.klass.ancestors.include?(Integer) @@ -301,30 +333,29 @@ elsif p.klass.ancestors.include?(Time) return "#{self.class}.parse_timestamp(res[#{col} + offset])" elsif p.klass.ancestors.include?(Date) return "#{self.class}.parse_date(res[#{col} + offset])" elsif p.klass.ancestors.include?(TrueClass) - return "('0' != res[#{col} + offset])" + return "('1' == res[#{col} + offset])" else return "YAML.load(res[#{col} + offset])" end end def eval_og_insert(klass) - props = klass.properties.dup + props = klass.properties.values values = props.collect { |p| write_prop(p) }.join(',') - if klass.metadata.superclass or klass.metadata.subclasses - props << Property.new(:ogtype, String) + if klass.schema_inheritance? + props << Property.new(:symbol => :ogtype, :klass => String) values << ", '#{klass}'" end sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| field_for_property(p)}.join(',')}) VALUES (#{values})" klass.class_eval %{ def og_insert(store) #{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)} - puts "#{sql}" store.conn.query_with_result = false store.conn.query "#{sql}" @#{klass.pk_symbol} = store.conn.insert_id #{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)} end