lib/mosql/sql.rb in mosql-0.2.0 vs lib/mosql/sql.rb in mosql-0.3.0

- old
+ new

@@ -33,40 +33,41 @@ h end def upsert_ns(ns, obj) h = transform_one_ns(ns, obj) - upsert(table_for_ns(ns), @schema.primary_sql_key_for_ns(ns), h) + upsert!(table_for_ns(ns), @schema.primary_sql_key_for_ns(ns), h) end # obj must contain an _id field. All other fields will be ignored. def delete_ns(ns, obj) primary_sql_key = @schema.primary_sql_key_for_ns(ns) h = transform_one_ns(ns, obj) raise "No #{primary_sql_key} found in transform of #{obj.inspect}" if h[primary_sql_key].nil? table_for_ns(ns).where(primary_sql_key.to_sym => h[primary_sql_key]).delete end - def upsert(table, table_primary_key, item) - begin - upsert!(table, table_primary_key, item) - rescue Sequel::DatabaseError => e - wrapped = e.wrapped_exception - if wrapped.result - log.warn("Ignoring row (#{table_primary_key}=#{item[table_primary_key]}): #{e}") - else - raise e + def upsert!(table, table_primary_key, item) + rows = table.where(table_primary_key.to_sym => item[table_primary_key]).update(item) + if rows == 0 + begin + table.insert(item) + rescue Sequel::DatabaseError => e + raise e unless self.class.duplicate_key_error?(e) + log.info("RACE during upsert: Upserting #{item} into #{table}: #{e}") end + elsif rows > 1 + log.warn("Huh? Updated #{rows} > 1 rows: upsert(#{table}, #{item})") end end - def upsert!(table, table_primary_key, item) - begin - table.insert(item) - rescue Sequel::DatabaseError => e - raise e unless e.message =~ /duplicate key value violates unique constraint/ - table.where(table_primary_key.to_sym => item[table_primary_key]).update(item) - end + def self.duplicate_key_error?(e) + # c.f. http://www.postgresql.org/docs/9.2/static/errcodes-appendix.html + # for the list of error codes. + # + # No thanks to Sequel and pg for making it easy to figure out + # how to get at this error code.... + e.wrapped_exception.result.error_field(PG::Result::PG_DIAG_SQLSTATE) == "23505" end end end